[llvm] 380e746 - [DebugInfo] Fix methods of AsmPrinter to emit values corresponding to the DWARF format (1/19).

Igor Kudrin via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 14 22:24:17 PDT 2020


Author: Igor Kudrin
Date: 2020-09-15T11:29:48+07:00
New Revision: 380e746bcca87baa5c746854b44d6a5cea6f7bde

URL: https://github.com/llvm/llvm-project/commit/380e746bcca87baa5c746854b44d6a5cea6f7bde
DIFF: https://github.com/llvm/llvm-project/commit/380e746bcca87baa5c746854b44d6a5cea6f7bde.diff

LOG: [DebugInfo] Fix methods of AsmPrinter to emit values corresponding to the DWARF format (1/19).

These methods are used to emit values which are 32-bit in DWARF32 and
64-bit in DWARF64. The patch fixes them so that they choose the length
automatically, depending on the DWARF format set in the Context.

Differential Revision: https://reviews.llvm.org/D87008

Added: 
    llvm/unittests/CodeGen/AsmPrinterDwarfTest.cpp
    llvm/unittests/CodeGen/TestAsmPrinter.cpp
    llvm/unittests/CodeGen/TestAsmPrinter.h

Modified: 
    llvm/include/llvm/CodeGen/AsmPrinter.h
    llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
    llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
    llvm/unittests/CodeGen/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h
index c157bb0672ba..89d266b4286b 100644
--- a/llvm/include/llvm/CodeGen/AsmPrinter.h
+++ b/llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -216,6 +216,11 @@ class AsmPrinter : public MachineFunctionPass {
   uint16_t getDwarfVersion() const;
   void setDwarfVersion(uint16_t Version);
 
+  bool isDwarf64() const;
+
+  /// Returns 4 for DWARF32 and 8 for DWARF64.
+  unsigned int getDwarfOffsetByteSize() const;
+
   bool isPositionIndependent() const;
 
   /// Return true if assembly output should contain comments.
@@ -562,9 +567,6 @@ class AsmPrinter : public MachineFunctionPass {
     emitLabelPlusOffset(Label, 0, Size, IsSectionRelative);
   }
 
-  /// Emit something like ".long Label + Offset".
-  void emitDwarfOffset(const MCSymbol *Label, uint64_t Offset) const;
-
   //===------------------------------------------------------------------===//
   // Dwarf Emission Helper Routines
   //===------------------------------------------------------------------===//
@@ -593,18 +595,24 @@ class AsmPrinter : public MachineFunctionPass {
   void emitDwarfSymbolReference(const MCSymbol *Label,
                                 bool ForceOffset = false) const;
 
-  /// Emit the 4-byte offset of a string from the start of its section.
+  /// Emit the 4- or 8-byte offset of a string from the start of its section.
   ///
   /// When possible, emit a DwarfStringPool section offset without any
   /// relocations, and without using the symbol.  Otherwise, defers to \a
   /// emitDwarfSymbolReference().
+  ///
+  /// The length of the emitted value depends on the DWARF format.
   void emitDwarfStringOffset(DwarfStringPoolEntry S) const;
 
-  /// Emit the 4-byte offset of a string from the start of its section.
+  /// Emit the 4-or 8-byte offset of a string from the start of its section.
   void emitDwarfStringOffset(DwarfStringPoolEntryRef S) const {
     emitDwarfStringOffset(S.getEntry());
   }
 
+  /// Emit something like ".long Label + Offset" or ".quad Label + Offset"
+  /// depending on the DWARF format.
+  void emitDwarfOffset(const MCSymbol *Label, uint64_t Offset) 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 01370baa4fd1..35a40bb277b9 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -3432,3 +3432,12 @@ uint16_t AsmPrinter::getDwarfVersion() const {
 void AsmPrinter::setDwarfVersion(uint16_t Version) {
   OutStreamer->getContext().setDwarfVersion(Version);
 }
+
+bool AsmPrinter::isDwarf64() const {
+  return OutStreamer->getContext().getDwarfFormat() == dwarf::DWARF64;
+}
+
+unsigned int AsmPrinter::getDwarfOffsetByteSize() const {
+  return dwarf::getDwarfOffsetByteSize(
+      OutStreamer->getContext().getDwarfFormat());
+}

diff  --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
index b6a9a9568360..7f8f6c646925 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
@@ -154,19 +154,22 @@ void AsmPrinter::emitDwarfSymbolReference(const MCSymbol *Label,
   if (!ForceOffset) {
     // On COFF targets, we have to emit the special .secrel32 directive.
     if (MAI->needsDwarfSectionOffsetDirective()) {
+      assert(!isDwarf64() &&
+             "emitting DWARF64 is not implemented for COFF targets");
       OutStreamer->EmitCOFFSecRel32(Label, /*Offset=*/0);
       return;
     }
 
     // If the format uses relocations with dwarf, refer to the symbol directly.
     if (MAI->doesDwarfUseRelocationsAcrossSections()) {
-      OutStreamer->emitSymbolValue(Label, 4);
+      OutStreamer->emitSymbolValue(Label, getDwarfOffsetByteSize());
       return;
     }
   }
 
   // Otherwise, emit it as a label 
diff erence from the start of the section.
-  emitLabelDifference(Label, Label->getSection().getBeginSymbol(), 4);
+  emitLabelDifference(Label, Label->getSection().getBeginSymbol(),
+                      getDwarfOffsetByteSize());
 }
 
 void AsmPrinter::emitDwarfStringOffset(DwarfStringPoolEntry S) const {
@@ -177,12 +180,11 @@ void AsmPrinter::emitDwarfStringOffset(DwarfStringPoolEntry S) const {
   }
 
   // Just emit the offset directly; no need for symbol math.
-  emitInt32(S.Offset);
+  OutStreamer->emitIntValue(S.Offset, getDwarfOffsetByteSize());
 }
 
 void AsmPrinter::emitDwarfOffset(const MCSymbol *Label, uint64_t Offset) const {
-  // TODO: Support DWARF64
-  emitLabelPlusOffset(Label, Offset, 4);
+  emitLabelPlusOffset(Label, Offset, getDwarfOffsetByteSize());
 }
 
 void AsmPrinter::emitCallSiteOffset(const MCSymbol *Hi, const MCSymbol *Lo,

diff  --git a/llvm/unittests/CodeGen/AsmPrinterDwarfTest.cpp b/llvm/unittests/CodeGen/AsmPrinterDwarfTest.cpp
new file mode 100644
index 000000000000..948b8851149d
--- /dev/null
+++ b/llvm/unittests/CodeGen/AsmPrinterDwarfTest.cpp
@@ -0,0 +1,253 @@
+//===- 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/MC/MCContext.h"
+#include "llvm/MC/MCSectionELF.h"
+#include "llvm/Testing/Support/Error.h"
+
+using namespace llvm;
+using testing::_;
+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);
+}
+
+} // end namespace

diff  --git a/llvm/unittests/CodeGen/CMakeLists.txt b/llvm/unittests/CodeGen/CMakeLists.txt
index 831eb66e82cf..3af8b7f74297 100644
--- a/llvm/unittests/CodeGen/CMakeLists.txt
+++ b/llvm/unittests/CodeGen/CMakeLists.txt
@@ -15,6 +15,7 @@ set(LLVM_LINK_COMPONENTS
 
 add_llvm_unittest(CodeGenTests
   AArch64SelectionDAGTest.cpp
+  AsmPrinterDwarfTest.cpp
   DIEHashTest.cpp
   LowLevelTypeTest.cpp
   LexicalScopesTest.cpp
@@ -25,6 +26,9 @@ add_llvm_unittest(CodeGenTests
   ScalableVectorMVTsTest.cpp
   TypeTraitsTest.cpp
   TargetOptionsTest.cpp
+  TestAsmPrinter.cpp
   )
 
 add_subdirectory(GlobalISel)
+
+target_link_libraries(CodeGenTests PRIVATE LLVMTestingSupport)

diff  --git a/llvm/unittests/CodeGen/TestAsmPrinter.cpp b/llvm/unittests/CodeGen/TestAsmPrinter.cpp
new file mode 100644
index 000000000000..7d0420206768
--- /dev/null
+++ b/llvm/unittests/CodeGen/TestAsmPrinter.cpp
@@ -0,0 +1,88 @@
+//===--- unittests/CodeGen/TestAsmPrinter.cpp -------------------*- C++ -*-===//
+//
+// 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/ADT/Triple.h"
+#include "llvm/CodeGen/AsmPrinter.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Target/TargetLoweringObjectFile.h"
+#include "llvm/Target/TargetMachine.h"
+
+using namespace llvm;
+using ::testing::StrictMock;
+
+// Note: a non-const reference argument cannot be passed through
+// testing::StrictMock, thus, we pass a pointer and dereference it here.
+MockMCStreamer::MockMCStreamer(MCContext *Ctx) : MCStreamer(*Ctx) {}
+
+MockMCStreamer::~MockMCStreamer() = default;
+
+TestAsmPrinter::TestAsmPrinter() = default;
+
+TestAsmPrinter::~TestAsmPrinter() = default;
+
+llvm::Expected<std::unique_ptr<TestAsmPrinter>>
+TestAsmPrinter::create(const std::string &TripleStr, uint16_t DwarfVersion,
+                       dwarf::DwarfFormat DwarfFormat) {
+  std::string ErrorStr;
+  const Target *TheTarget = TargetRegistry::lookupTarget(TripleStr, ErrorStr);
+  if (!TheTarget)
+    return std::unique_ptr<TestAsmPrinter>();
+
+  std::unique_ptr<TestAsmPrinter> TestPrinter(new TestAsmPrinter);
+  if (llvm::Error E =
+          TestPrinter->init(TheTarget, TripleStr, DwarfVersion, DwarfFormat))
+    return std::move(E);
+
+  return std::move(TestPrinter);
+}
+
+// Note:: based on dwarfgen::Generator::init() from
+// llvm/unittests/DebugInfo/DWARF/DwarfGenerator.cpp
+llvm::Error TestAsmPrinter::init(const Target *TheTarget, StringRef TripleName,
+                                 uint16_t DwarfVersion,
+                                 dwarf::DwarfFormat DwarfFormat) {
+  TM.reset(TheTarget->createTargetMachine(TripleName, "", "", TargetOptions(),
+                                          None));
+  if (!TM)
+    return make_error<StringError>("no target machine for target " + TripleName,
+                                   inconvertibleErrorCode());
+
+  MC.reset(new MCContext(TM->getMCAsmInfo(), TM->getMCRegisterInfo(),
+                         TM->getObjFileLowering()));
+  TM->getObjFileLowering()->Initialize(*MC, *TM);
+
+  MS = new StrictMock<MockMCStreamer>(MC.get());
+
+  Asm.reset(
+      TheTarget->createAsmPrinter(*TM, std::unique_ptr<MockMCStreamer>(MS)));
+  if (!Asm)
+    return make_error<StringError>("no asm printer for target " + TripleName,
+                                   inconvertibleErrorCode());
+
+  // Set the DWARF version correctly on all classes that we use.
+  MC->setDwarfVersion(DwarfVersion);
+  Asm->setDwarfVersion(DwarfVersion);
+
+  // Set the DWARF format.
+  MC->setDwarfFormat(DwarfFormat);
+
+  return Error::success();
+}
+
+void TestAsmPrinter::setDwarfUsesRelocationsAcrossSections(bool Enable) {
+  struct HackMCAsmInfo : MCAsmInfo {
+    void setDwarfUsesRelocationsAcrossSections(bool Enable) {
+      DwarfUsesRelocationsAcrossSections = Enable;
+    }
+  };
+  static_cast<HackMCAsmInfo *>(const_cast<MCAsmInfo *>(TM->getMCAsmInfo()))
+      ->setDwarfUsesRelocationsAcrossSections(Enable);
+}

diff  --git a/llvm/unittests/CodeGen/TestAsmPrinter.h b/llvm/unittests/CodeGen/TestAsmPrinter.h
new file mode 100644
index 000000000000..65e557b9b4a6
--- /dev/null
+++ b/llvm/unittests/CodeGen/TestAsmPrinter.h
@@ -0,0 +1,82 @@
+//===--- unittests/CodeGen/TestAsmPrinter.h ---------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_UNITTESTS_CODEGEN_TESTASMPRINTER_H
+#define LLVM_UNITTESTS_CODEGEN_TESTASMPRINTER_H
+
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/MC/MCStreamer.h"
+#include "gmock/gmock.h"
+
+#include <memory>
+
+namespace llvm {
+class AsmPrinter;
+class MCContext;
+class Target;
+class TargetMachine;
+
+class MockMCStreamer : public MCStreamer {
+public:
+  explicit MockMCStreamer(MCContext *Ctx);
+  ~MockMCStreamer();
+
+  // These methods are pure virtual in MCStreamer, thus, have to be overridden:
+
+  MOCK_METHOD2(emitSymbolAttribute,
+               bool(MCSymbol *Symbol, MCSymbolAttr Attribute));
+  MOCK_METHOD3(emitCommonSymbol,
+               void(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment));
+  MOCK_METHOD5(emitZerofill,
+               void(MCSection *Section, MCSymbol *Symbol, uint64_t Size,
+                    unsigned ByteAlignment, SMLoc Loc));
+
+  // The following are mock methods to be used in tests.
+
+  MOCK_METHOD2(emitIntValue, void(uint64_t Value, unsigned Size));
+  MOCK_METHOD3(emitValueImpl,
+               void(const MCExpr *Value, unsigned Size, SMLoc Loc));
+  MOCK_METHOD3(emitAbsoluteSymbolDiff,
+               void(const MCSymbol *Hi, const MCSymbol *Lo, unsigned Size));
+  MOCK_METHOD2(EmitCOFFSecRel32, void(MCSymbol const *Symbol, uint64_t Offset));
+};
+
+class TestAsmPrinter {
+  std::unique_ptr<MCContext> MC;
+  MockMCStreamer *MS = nullptr; // Owned by AsmPrinter
+  std::unique_ptr<TargetMachine> TM;
+  std::unique_ptr<AsmPrinter> Asm;
+
+  /// Private constructor; call TestAsmPrinter::create(...)
+  /// to create an instance.
+  TestAsmPrinter();
+
+  /// Initialize an AsmPrinter instance with a mocked MCStreamer.
+  llvm::Error init(const Target *TheTarget, StringRef TripleStr,
+                   uint16_t DwarfVersion, dwarf::DwarfFormat DwarfFormat);
+
+public:
+  /// Create an AsmPrinter and accompanied objects.
+  /// Returns ErrorSuccess() with an empty value if the requested target is not
+  /// supported so that the corresponding test can be gracefully skipped.
+  static llvm::Expected<std::unique_ptr<TestAsmPrinter>>
+  create(const std::string &TripleStr, uint16_t DwarfVersion,
+         dwarf::DwarfFormat DwarfFormat);
+
+  ~TestAsmPrinter();
+
+  void setDwarfUsesRelocationsAcrossSections(bool Enable);
+
+  AsmPrinter *getAP() const { return Asm.get(); }
+  MCContext &getCtx() const { return *MC; }
+  MockMCStreamer &getMS() const { return *MS; }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_UNITTESTS_CODEGEN_TESTASMPRINTER_H


        


More information about the llvm-commits mailing list