| //===- 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 |