mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 20:23:11 +01:00
11a667f122
This lets external consumers customize the output, similar to how AssemblyAnnotationWriter lets the caller define callbacks when printing IR. The array of handlers already existed, this just cleans up the code so that it can be exposed publically. Replaces https://reviews.llvm.org/D74158 Differential Revision: https://reviews.llvm.org/D89613
430 lines
14 KiB
C++
430 lines
14 KiB
C++
//===- llvm/unittest/CodeGen/AsmPrinterDwarfTest.cpp ----------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "TestAsmPrinter.h"
|
|
#include "llvm/CodeGen/AsmPrinter.h"
|
|
#include "llvm/CodeGen/MachineModuleInfo.h"
|
|
#include "llvm/IR/LegacyPassManager.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/IR/PassManager.h"
|
|
#include "llvm/MC/MCContext.h"
|
|
#include "llvm/MC/MCSectionELF.h"
|
|
#include "llvm/Target/TargetMachine.h"
|
|
#include "llvm/Testing/Support/Error.h"
|
|
|
|
using namespace llvm;
|
|
using testing::_;
|
|
using testing::InSequence;
|
|
using testing::SaveArg;
|
|
|
|
namespace {
|
|
|
|
class AsmPrinterFixtureBase : public testing::Test {
|
|
void setupTestPrinter(const std::string &TripleStr, unsigned DwarfVersion,
|
|
dwarf::DwarfFormat DwarfFormat) {
|
|
auto ExpectedTestPrinter =
|
|
TestAsmPrinter::create(TripleStr, DwarfVersion, DwarfFormat);
|
|
ASSERT_THAT_EXPECTED(ExpectedTestPrinter, Succeeded());
|
|
TestPrinter = std::move(ExpectedTestPrinter.get());
|
|
}
|
|
|
|
protected:
|
|
bool init(const std::string &TripleStr, unsigned DwarfVersion,
|
|
dwarf::DwarfFormat DwarfFormat) {
|
|
setupTestPrinter(TripleStr, DwarfVersion, DwarfFormat);
|
|
return TestPrinter != nullptr;
|
|
}
|
|
|
|
std::unique_ptr<TestAsmPrinter> TestPrinter;
|
|
};
|
|
|
|
class AsmPrinterEmitDwarfSymbolReferenceTest : public AsmPrinterFixtureBase {
|
|
protected:
|
|
bool init(const std::string &TripleStr, unsigned DwarfVersion,
|
|
dwarf::DwarfFormat DwarfFormat) {
|
|
if (!AsmPrinterFixtureBase::init(TripleStr, DwarfVersion, DwarfFormat))
|
|
return false;
|
|
|
|
// Create a symbol which will be emitted in the tests and associate it
|
|
// with a section because that is required in some code paths.
|
|
|
|
Val = TestPrinter->getCtx().createTempSymbol();
|
|
Sec = TestPrinter->getCtx().getELFSection(".tst", ELF::SHT_PROGBITS, 0);
|
|
SecBeginSymbol = Sec->getBeginSymbol();
|
|
TestPrinter->getMS().SwitchSection(Sec);
|
|
TestPrinter->getMS().emitLabel(Val);
|
|
return true;
|
|
}
|
|
|
|
MCSymbol *Val = nullptr;
|
|
MCSection *Sec = nullptr;
|
|
MCSymbol *SecBeginSymbol = nullptr;
|
|
};
|
|
|
|
TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, COFF) {
|
|
if (!init("x86_64-pc-windows", /*DwarfVersion=*/4, dwarf::DWARF32))
|
|
return;
|
|
|
|
EXPECT_CALL(TestPrinter->getMS(), EmitCOFFSecRel32(Val, 0));
|
|
TestPrinter->getAP()->emitDwarfSymbolReference(Val, false);
|
|
}
|
|
|
|
TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, COFFForceOffset) {
|
|
if (!init("x86_64-pc-windows", /*DwarfVersion=*/4, dwarf::DWARF32))
|
|
return;
|
|
|
|
EXPECT_CALL(TestPrinter->getMS(),
|
|
emitAbsoluteSymbolDiff(Val, SecBeginSymbol, 4));
|
|
TestPrinter->getAP()->emitDwarfSymbolReference(Val, true);
|
|
}
|
|
|
|
TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, ELFDWARF32) {
|
|
if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
|
|
return;
|
|
|
|
const MCExpr *Arg0 = nullptr;
|
|
EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 4, _))
|
|
.WillOnce(SaveArg<0>(&Arg0));
|
|
TestPrinter->getAP()->emitDwarfSymbolReference(Val, false);
|
|
|
|
const MCSymbolRefExpr *ActualArg0 = dyn_cast_or_null<MCSymbolRefExpr>(Arg0);
|
|
ASSERT_NE(ActualArg0, nullptr);
|
|
EXPECT_EQ(&(ActualArg0->getSymbol()), Val);
|
|
}
|
|
|
|
TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, ELFDWARF32ForceOffset) {
|
|
if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
|
|
return;
|
|
|
|
EXPECT_CALL(TestPrinter->getMS(),
|
|
emitAbsoluteSymbolDiff(Val, SecBeginSymbol, 4));
|
|
TestPrinter->getAP()->emitDwarfSymbolReference(Val, true);
|
|
}
|
|
|
|
TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, ELFDWARF64) {
|
|
if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
|
|
return;
|
|
|
|
const MCExpr *Arg0 = nullptr;
|
|
EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 8, _))
|
|
.WillOnce(SaveArg<0>(&Arg0));
|
|
TestPrinter->getAP()->emitDwarfSymbolReference(Val, false);
|
|
|
|
const MCSymbolRefExpr *ActualArg0 = dyn_cast_or_null<MCSymbolRefExpr>(Arg0);
|
|
ASSERT_NE(ActualArg0, nullptr);
|
|
EXPECT_EQ(&(ActualArg0->getSymbol()), Val);
|
|
}
|
|
|
|
TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, ELFDWARF64ForceOffset) {
|
|
if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
|
|
return;
|
|
|
|
EXPECT_CALL(TestPrinter->getMS(),
|
|
emitAbsoluteSymbolDiff(Val, SecBeginSymbol, 8));
|
|
TestPrinter->getAP()->emitDwarfSymbolReference(Val, true);
|
|
}
|
|
|
|
class AsmPrinterEmitDwarfStringOffsetTest : public AsmPrinterFixtureBase {
|
|
protected:
|
|
bool init(const std::string &TripleStr, unsigned DwarfVersion,
|
|
dwarf::DwarfFormat DwarfFormat) {
|
|
if (!AsmPrinterFixtureBase::init(TripleStr, DwarfVersion, DwarfFormat))
|
|
return false;
|
|
|
|
Val.Index = DwarfStringPoolEntry::NotIndexed;
|
|
Val.Symbol = TestPrinter->getCtx().createTempSymbol();
|
|
Val.Offset = 42;
|
|
return true;
|
|
}
|
|
|
|
DwarfStringPoolEntry Val;
|
|
};
|
|
|
|
TEST_F(AsmPrinterEmitDwarfStringOffsetTest, DWARF32) {
|
|
if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
|
|
return;
|
|
|
|
const MCExpr *Arg0 = nullptr;
|
|
EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 4, _))
|
|
.WillOnce(SaveArg<0>(&Arg0));
|
|
TestPrinter->getAP()->emitDwarfStringOffset(Val);
|
|
|
|
const MCSymbolRefExpr *ActualArg0 = dyn_cast_or_null<MCSymbolRefExpr>(Arg0);
|
|
ASSERT_NE(ActualArg0, nullptr);
|
|
EXPECT_EQ(&(ActualArg0->getSymbol()), Val.Symbol);
|
|
}
|
|
|
|
TEST_F(AsmPrinterEmitDwarfStringOffsetTest,
|
|
DWARF32NoRelocationsAcrossSections) {
|
|
if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
|
|
return;
|
|
|
|
TestPrinter->setDwarfUsesRelocationsAcrossSections(false);
|
|
EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val.Offset, 4));
|
|
TestPrinter->getAP()->emitDwarfStringOffset(Val);
|
|
}
|
|
|
|
TEST_F(AsmPrinterEmitDwarfStringOffsetTest, DWARF64) {
|
|
if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
|
|
return;
|
|
|
|
const MCExpr *Arg0 = nullptr;
|
|
EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 8, _))
|
|
.WillOnce(SaveArg<0>(&Arg0));
|
|
TestPrinter->getAP()->emitDwarfStringOffset(Val);
|
|
|
|
const MCSymbolRefExpr *ActualArg0 = dyn_cast_or_null<MCSymbolRefExpr>(Arg0);
|
|
ASSERT_NE(ActualArg0, nullptr);
|
|
EXPECT_EQ(&(ActualArg0->getSymbol()), Val.Symbol);
|
|
}
|
|
|
|
TEST_F(AsmPrinterEmitDwarfStringOffsetTest,
|
|
DWARF64NoRelocationsAcrossSections) {
|
|
if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
|
|
return;
|
|
|
|
TestPrinter->setDwarfUsesRelocationsAcrossSections(false);
|
|
EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val.Offset, 8));
|
|
TestPrinter->getAP()->emitDwarfStringOffset(Val);
|
|
}
|
|
|
|
class AsmPrinterEmitDwarfOffsetTest : public AsmPrinterFixtureBase {
|
|
protected:
|
|
bool init(const std::string &TripleStr, unsigned DwarfVersion,
|
|
dwarf::DwarfFormat DwarfFormat) {
|
|
if (!AsmPrinterFixtureBase::init(TripleStr, DwarfVersion, DwarfFormat))
|
|
return false;
|
|
|
|
Label = TestPrinter->getCtx().createTempSymbol();
|
|
return true;
|
|
}
|
|
|
|
MCSymbol *Label = nullptr;
|
|
uint64_t Offset = 42;
|
|
};
|
|
|
|
TEST_F(AsmPrinterEmitDwarfOffsetTest, DWARF32) {
|
|
if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
|
|
return;
|
|
|
|
const MCExpr *Arg0 = nullptr;
|
|
EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 4, _))
|
|
.WillOnce(SaveArg<0>(&Arg0));
|
|
TestPrinter->getAP()->emitDwarfOffset(Label, Offset);
|
|
|
|
const MCBinaryExpr *ActualArg0 = dyn_cast_or_null<MCBinaryExpr>(Arg0);
|
|
ASSERT_NE(ActualArg0, nullptr);
|
|
EXPECT_EQ(ActualArg0->getOpcode(), MCBinaryExpr::Add);
|
|
|
|
const MCSymbolRefExpr *ActualLHS =
|
|
dyn_cast_or_null<MCSymbolRefExpr>(ActualArg0->getLHS());
|
|
ASSERT_NE(ActualLHS, nullptr);
|
|
EXPECT_EQ(&(ActualLHS->getSymbol()), Label);
|
|
|
|
const MCConstantExpr *ActualRHS =
|
|
dyn_cast_or_null<MCConstantExpr>(ActualArg0->getRHS());
|
|
ASSERT_NE(ActualRHS, nullptr);
|
|
EXPECT_EQ(static_cast<uint64_t>(ActualRHS->getValue()), Offset);
|
|
}
|
|
|
|
TEST_F(AsmPrinterEmitDwarfOffsetTest, DWARF64) {
|
|
if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
|
|
return;
|
|
|
|
const MCExpr *Arg0 = nullptr;
|
|
EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 8, _))
|
|
.WillOnce(SaveArg<0>(&Arg0));
|
|
TestPrinter->getAP()->emitDwarfOffset(Label, Offset);
|
|
|
|
const MCBinaryExpr *ActualArg0 = dyn_cast_or_null<MCBinaryExpr>(Arg0);
|
|
ASSERT_NE(ActualArg0, nullptr);
|
|
EXPECT_EQ(ActualArg0->getOpcode(), MCBinaryExpr::Add);
|
|
|
|
const MCSymbolRefExpr *ActualLHS =
|
|
dyn_cast_or_null<MCSymbolRefExpr>(ActualArg0->getLHS());
|
|
ASSERT_NE(ActualLHS, nullptr);
|
|
EXPECT_EQ(&(ActualLHS->getSymbol()), Label);
|
|
|
|
const MCConstantExpr *ActualRHS =
|
|
dyn_cast_or_null<MCConstantExpr>(ActualArg0->getRHS());
|
|
ASSERT_NE(ActualRHS, nullptr);
|
|
EXPECT_EQ(static_cast<uint64_t>(ActualRHS->getValue()), Offset);
|
|
}
|
|
|
|
class AsmPrinterEmitDwarfLengthOrOffsetTest : public AsmPrinterFixtureBase {
|
|
protected:
|
|
uint64_t Val = 42;
|
|
};
|
|
|
|
TEST_F(AsmPrinterEmitDwarfLengthOrOffsetTest, DWARF32) {
|
|
if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
|
|
return;
|
|
|
|
EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val, 4));
|
|
TestPrinter->getAP()->emitDwarfLengthOrOffset(Val);
|
|
}
|
|
|
|
TEST_F(AsmPrinterEmitDwarfLengthOrOffsetTest, DWARF64) {
|
|
if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
|
|
return;
|
|
|
|
EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val, 8));
|
|
TestPrinter->getAP()->emitDwarfLengthOrOffset(Val);
|
|
}
|
|
|
|
class AsmPrinterGetUnitLengthFieldByteSizeTest : public AsmPrinterFixtureBase {
|
|
};
|
|
|
|
TEST_F(AsmPrinterGetUnitLengthFieldByteSizeTest, DWARF32) {
|
|
if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
|
|
return;
|
|
|
|
EXPECT_EQ(TestPrinter->getAP()->getUnitLengthFieldByteSize(), 4u);
|
|
}
|
|
|
|
TEST_F(AsmPrinterGetUnitLengthFieldByteSizeTest, DWARF64) {
|
|
if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
|
|
return;
|
|
|
|
EXPECT_EQ(TestPrinter->getAP()->getUnitLengthFieldByteSize(), 12u);
|
|
}
|
|
|
|
class AsmPrinterMaybeEmitDwarf64MarkTest : public AsmPrinterFixtureBase {};
|
|
|
|
TEST_F(AsmPrinterMaybeEmitDwarf64MarkTest, DWARF32) {
|
|
if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
|
|
return;
|
|
|
|
EXPECT_CALL(TestPrinter->getMS(), emitIntValue(_, _)).Times(0);
|
|
TestPrinter->getAP()->maybeEmitDwarf64Mark();
|
|
}
|
|
|
|
TEST_F(AsmPrinterMaybeEmitDwarf64MarkTest, DWARF64) {
|
|
if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
|
|
return;
|
|
|
|
EXPECT_CALL(TestPrinter->getMS(), emitIntValue(dwarf::DW_LENGTH_DWARF64, 4));
|
|
TestPrinter->getAP()->maybeEmitDwarf64Mark();
|
|
}
|
|
|
|
class AsmPrinterEmitDwarfUnitLengthAsIntTest : public AsmPrinterFixtureBase {
|
|
protected:
|
|
uint64_t Val = 42;
|
|
};
|
|
|
|
TEST_F(AsmPrinterEmitDwarfUnitLengthAsIntTest, DWARF32) {
|
|
if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
|
|
return;
|
|
|
|
EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val, 4));
|
|
TestPrinter->getAP()->emitDwarfUnitLength(Val, "");
|
|
}
|
|
|
|
TEST_F(AsmPrinterEmitDwarfUnitLengthAsIntTest, DWARF64) {
|
|
if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
|
|
return;
|
|
|
|
InSequence S;
|
|
EXPECT_CALL(TestPrinter->getMS(), emitIntValue(dwarf::DW_LENGTH_DWARF64, 4));
|
|
EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val, 8));
|
|
|
|
TestPrinter->getAP()->emitDwarfUnitLength(Val, "");
|
|
}
|
|
|
|
class AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest
|
|
: public AsmPrinterFixtureBase {
|
|
protected:
|
|
bool init(const std::string &TripleStr, unsigned DwarfVersion,
|
|
dwarf::DwarfFormat DwarfFormat) {
|
|
if (!AsmPrinterFixtureBase::init(TripleStr, DwarfVersion, DwarfFormat))
|
|
return false;
|
|
|
|
Hi = TestPrinter->getCtx().createTempSymbol();
|
|
Lo = TestPrinter->getCtx().createTempSymbol();
|
|
return true;
|
|
}
|
|
|
|
MCSymbol *Hi = nullptr;
|
|
MCSymbol *Lo = nullptr;
|
|
};
|
|
|
|
TEST_F(AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest, DWARF32) {
|
|
if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
|
|
return;
|
|
|
|
EXPECT_CALL(TestPrinter->getMS(), emitAbsoluteSymbolDiff(Hi, Lo, 4));
|
|
TestPrinter->getAP()->emitDwarfUnitLength(Hi, Lo, "");
|
|
}
|
|
|
|
TEST_F(AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest, DWARF64) {
|
|
if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
|
|
return;
|
|
|
|
InSequence S;
|
|
EXPECT_CALL(TestPrinter->getMS(), emitIntValue(dwarf::DW_LENGTH_DWARF64, 4));
|
|
EXPECT_CALL(TestPrinter->getMS(), emitAbsoluteSymbolDiff(Hi, Lo, 8));
|
|
|
|
TestPrinter->getAP()->emitDwarfUnitLength(Hi, Lo, "");
|
|
}
|
|
|
|
class AsmPrinterHandlerTest : public AsmPrinterFixtureBase {
|
|
class TestHandler : public AsmPrinterHandler {
|
|
AsmPrinterHandlerTest &Test;
|
|
|
|
public:
|
|
TestHandler(AsmPrinterHandlerTest &Test) : Test(Test) {}
|
|
virtual ~TestHandler() {}
|
|
virtual void setSymbolSize(const MCSymbol *Sym, uint64_t Size) override {}
|
|
virtual void beginModule(Module *M) override { Test.BeginCount++; }
|
|
virtual void endModule() override { Test.EndCount++; }
|
|
virtual void beginFunction(const MachineFunction *MF) override {}
|
|
virtual void endFunction(const MachineFunction *MF) override {}
|
|
virtual void beginInstruction(const MachineInstr *MI) override {}
|
|
virtual void endInstruction() override {}
|
|
};
|
|
|
|
protected:
|
|
bool init(const std::string &TripleStr, unsigned DwarfVersion,
|
|
dwarf::DwarfFormat DwarfFormat) {
|
|
if (!AsmPrinterFixtureBase::init(TripleStr, DwarfVersion, DwarfFormat))
|
|
return false;
|
|
|
|
auto *AP = TestPrinter->getAP();
|
|
AP->addAsmPrinterHandler(AsmPrinter::HandlerInfo(
|
|
std::unique_ptr<AsmPrinterHandler>(new TestHandler(*this)),
|
|
"TestTimerName", "TestTimerDesc", "TestGroupName", "TestGroupDesc"));
|
|
LLVMTargetMachine *LLVMTM = static_cast<LLVMTargetMachine *>(&AP->TM);
|
|
legacy::PassManager PM;
|
|
PM.add(new MachineModuleInfoWrapperPass(LLVMTM));
|
|
PM.add(TestPrinter->releaseAP()); // Takes ownership of destroying AP
|
|
LLVMContext Context;
|
|
std::unique_ptr<Module> M(new Module("TestModule", Context));
|
|
M->setDataLayout(LLVMTM->createDataLayout());
|
|
PM.run(*M);
|
|
// Now check that we can run it twice.
|
|
AP->addAsmPrinterHandler(AsmPrinter::HandlerInfo(
|
|
std::unique_ptr<AsmPrinterHandler>(new TestHandler(*this)),
|
|
"TestTimerName", "TestTimerDesc", "TestGroupName", "TestGroupDesc"));
|
|
PM.run(*M);
|
|
return true;
|
|
}
|
|
|
|
int BeginCount = 0;
|
|
int EndCount = 0;
|
|
};
|
|
|
|
TEST_F(AsmPrinterHandlerTest, Basic) {
|
|
if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
|
|
return;
|
|
|
|
ASSERT_EQ(BeginCount, 3);
|
|
ASSERT_EQ(EndCount, 3);
|
|
}
|
|
|
|
} // end namespace
|