diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h index 89d266b4286b9e..11ba36aee5a80a 100644 --- a/llvm/include/llvm/CodeGen/AsmPrinter.h +++ b/llvm/include/llvm/CodeGen/AsmPrinter.h @@ -221,6 +221,9 @@ class AsmPrinter : public MachineFunctionPass { /// Returns 4 for DWARF32 and 8 for DWARF64. unsigned int getDwarfOffsetByteSize() const; + /// Returns 4 for DWARF32 and 12 for DWARF64. + unsigned int getUnitLengthFieldByteSize() const; + bool isPositionIndependent() const; /// Return true if assembly output should contain comments. @@ -613,6 +616,21 @@ class AsmPrinter : public MachineFunctionPass { /// depending on the DWARF format. void emitDwarfOffset(const MCSymbol *Label, uint64_t Offset) const; + /// Emit 32- or 64-bit value depending on the DWARF format. + void emitDwarfLengthOrOffset(uint64_t Value) const; + + /// Emit a special value of 0xffffffff if producing 64-bit debugging info. + void maybeEmitDwarf64Mark() const; + + /// Emit a unit length field. The actual format, DWARF32 or DWARF64, is chosen + /// according to the settings. + void emitDwarfUnitLength(uint64_t Length, const Twine &Comment) const; + + /// Emit a unit length field. The actual format, DWARF32 or DWARF64, is chosen + /// according to the settings. + void emitDwarfUnitLength(const MCSymbol *Hi, const MCSymbol *Lo, + const Twine &Comment) const; + /// Emit reference to a call site with a specified encoding void emitCallSiteOffset(const MCSymbol *Hi, const MCSymbol *Lo, unsigned Encoding) const; diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 35a40bb277b934..7d8355c0496935 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -3441,3 +3441,8 @@ unsigned int AsmPrinter::getDwarfOffsetByteSize() const { return dwarf::getDwarfOffsetByteSize( OutStreamer->getContext().getDwarfFormat()); } + +unsigned int AsmPrinter::getUnitLengthFieldByteSize() const { + return dwarf::getUnitLengthFieldByteSize( + OutStreamer->getContext().getDwarfFormat()); +} diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp index 7f8f6c646925a9..594b41bcea53f1 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp @@ -27,6 +27,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetMachine.h" +#include using namespace llvm; #define DEBUG_TYPE "asm-printer" @@ -187,6 +188,33 @@ void AsmPrinter::emitDwarfOffset(const MCSymbol *Label, uint64_t Offset) const { emitLabelPlusOffset(Label, Offset, getDwarfOffsetByteSize()); } +void AsmPrinter::emitDwarfLengthOrOffset(uint64_t Value) const { + assert(isDwarf64() || Value <= UINT32_MAX); + OutStreamer->emitIntValue(Value, getDwarfOffsetByteSize()); +} + +void AsmPrinter::maybeEmitDwarf64Mark() const { + if (!isDwarf64()) + return; + OutStreamer->AddComment("DWARF64 Mark"); + OutStreamer->emitInt32(dwarf::DW_LENGTH_DWARF64); +} + +void AsmPrinter::emitDwarfUnitLength(uint64_t Length, + const Twine &Comment) const { + assert(isDwarf64() || Length <= dwarf::DW_LENGTH_lo_reserved); + maybeEmitDwarf64Mark(); + OutStreamer->AddComment(Comment); + OutStreamer->emitIntValue(Length, getDwarfOffsetByteSize()); +} + +void AsmPrinter::emitDwarfUnitLength(const MCSymbol *Hi, const MCSymbol *Lo, + const Twine &Comment) const { + maybeEmitDwarf64Mark(); + OutStreamer->AddComment(Comment); + OutStreamer->emitAbsoluteSymbolDiff(Hi, Lo, getDwarfOffsetByteSize()); +} + void AsmPrinter::emitCallSiteOffset(const MCSymbol *Hi, const MCSymbol *Lo, unsigned Encoding) const { // The least significant 3 bits specify the width of the encoding diff --git a/llvm/unittests/CodeGen/AsmPrinterDwarfTest.cpp b/llvm/unittests/CodeGen/AsmPrinterDwarfTest.cpp index 948b8851149d92..5c53f39fd9a3ec 100644 --- a/llvm/unittests/CodeGen/AsmPrinterDwarfTest.cpp +++ b/llvm/unittests/CodeGen/AsmPrinterDwarfTest.cpp @@ -14,6 +14,7 @@ using namespace llvm; using testing::_; +using testing::InSequence; using testing::SaveArg; namespace { @@ -250,4 +251,120 @@ TEST_F(AsmPrinterEmitDwarfOffsetTest, DWARF64) { EXPECT_EQ(static_cast(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, ""); +} + } // end namespace