xref: /llvm-project/llvm/unittests/CodeGen/AsmPrinterDwarfTest.cpp (revision be5d92e37e4fe0b7ba2f5658fa828c1c39988374)
1 //===- llvm/unittest/CodeGen/AsmPrinterDwarfTest.cpp ----------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "TestAsmPrinter.h"
10 #include "llvm/CodeGen/AsmPrinter.h"
11 #include "llvm/CodeGen/MachineModuleInfo.h"
12 #include "llvm/IR/LegacyPassManager.h"
13 #include "llvm/IR/Module.h"
14 #include "llvm/IR/PassManager.h"
15 #include "llvm/MC/MCContext.h"
16 #include "llvm/MC/MCSectionELF.h"
17 #include "llvm/Target/TargetMachine.h"
18 #include "llvm/Testing/Support/Error.h"
19 
20 using namespace llvm;
21 using testing::_;
22 using testing::InSequence;
23 using testing::SaveArg;
24 
25 namespace {
26 
27 class AsmPrinterFixtureBase : public testing::Test {
28   void setupTestPrinter(const std::string &TripleStr, unsigned DwarfVersion,
29                         dwarf::DwarfFormat DwarfFormat) {
30     auto ExpectedTestPrinter =
31         TestAsmPrinter::create(TripleStr, DwarfVersion, DwarfFormat);
32     ASSERT_THAT_EXPECTED(ExpectedTestPrinter, Succeeded());
33     TestPrinter = std::move(ExpectedTestPrinter.get());
34   }
35 
36 protected:
37   bool init(const std::string &TripleStr, unsigned DwarfVersion,
38             dwarf::DwarfFormat DwarfFormat) {
39     setupTestPrinter(TripleStr, DwarfVersion, DwarfFormat);
40     return TestPrinter != nullptr;
41   }
42 
43   std::unique_ptr<TestAsmPrinter> TestPrinter;
44 };
45 
46 class AsmPrinterEmitDwarfSymbolReferenceTest : public AsmPrinterFixtureBase {
47 protected:
48   bool init(const std::string &TripleStr, unsigned DwarfVersion,
49             dwarf::DwarfFormat DwarfFormat) {
50     if (!AsmPrinterFixtureBase::init(TripleStr, DwarfVersion, DwarfFormat))
51       return false;
52 
53     // Create a symbol which will be emitted in the tests and associate it
54     // with a section because that is required in some code paths.
55 
56     Val = TestPrinter->getCtx().createTempSymbol();
57     Sec = TestPrinter->getCtx().getELFSection(".tst", ELF::SHT_PROGBITS, 0);
58     SecBeginSymbol = Sec->getBeginSymbol();
59     TestPrinter->getMS().SwitchSection(Sec);
60     TestPrinter->getMS().emitLabel(Val);
61     return true;
62   }
63 
64   MCSymbol *Val = nullptr;
65   MCSection *Sec = nullptr;
66   MCSymbol *SecBeginSymbol = nullptr;
67 };
68 
69 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, COFF) {
70   if (!init("x86_64-pc-windows", /*DwarfVersion=*/4, dwarf::DWARF32))
71     return;
72 
73   EXPECT_CALL(TestPrinter->getMS(), EmitCOFFSecRel32(Val, 0));
74   TestPrinter->getAP()->emitDwarfSymbolReference(Val, false);
75 }
76 
77 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, COFFForceOffset) {
78   if (!init("x86_64-pc-windows", /*DwarfVersion=*/4, dwarf::DWARF32))
79     return;
80 
81   EXPECT_CALL(TestPrinter->getMS(),
82               emitAbsoluteSymbolDiff(Val, SecBeginSymbol, 4));
83   TestPrinter->getAP()->emitDwarfSymbolReference(Val, true);
84 }
85 
86 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, ELFDWARF32) {
87   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
88     return;
89 
90   const MCExpr *Arg0 = nullptr;
91   EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 4, _))
92       .WillOnce(SaveArg<0>(&Arg0));
93   TestPrinter->getAP()->emitDwarfSymbolReference(Val, false);
94 
95   const MCSymbolRefExpr *ActualArg0 = dyn_cast_or_null<MCSymbolRefExpr>(Arg0);
96   ASSERT_NE(ActualArg0, nullptr);
97   EXPECT_EQ(&(ActualArg0->getSymbol()), Val);
98 }
99 
100 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, ELFDWARF32ForceOffset) {
101   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
102     return;
103 
104   EXPECT_CALL(TestPrinter->getMS(),
105               emitAbsoluteSymbolDiff(Val, SecBeginSymbol, 4));
106   TestPrinter->getAP()->emitDwarfSymbolReference(Val, true);
107 }
108 
109 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, ELFDWARF64) {
110   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
111     return;
112 
113   const MCExpr *Arg0 = nullptr;
114   EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 8, _))
115       .WillOnce(SaveArg<0>(&Arg0));
116   TestPrinter->getAP()->emitDwarfSymbolReference(Val, false);
117 
118   const MCSymbolRefExpr *ActualArg0 = dyn_cast_or_null<MCSymbolRefExpr>(Arg0);
119   ASSERT_NE(ActualArg0, nullptr);
120   EXPECT_EQ(&(ActualArg0->getSymbol()), Val);
121 }
122 
123 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, ELFDWARF64ForceOffset) {
124   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
125     return;
126 
127   EXPECT_CALL(TestPrinter->getMS(),
128               emitAbsoluteSymbolDiff(Val, SecBeginSymbol, 8));
129   TestPrinter->getAP()->emitDwarfSymbolReference(Val, true);
130 }
131 
132 class AsmPrinterEmitDwarfStringOffsetTest : public AsmPrinterFixtureBase {
133 protected:
134   bool init(const std::string &TripleStr, unsigned DwarfVersion,
135             dwarf::DwarfFormat DwarfFormat) {
136     if (!AsmPrinterFixtureBase::init(TripleStr, DwarfVersion, DwarfFormat))
137       return false;
138 
139     Val.Index = DwarfStringPoolEntry::NotIndexed;
140     Val.Symbol = TestPrinter->getCtx().createTempSymbol();
141     Val.Offset = 42;
142     return true;
143   }
144 
145   DwarfStringPoolEntry Val;
146 };
147 
148 TEST_F(AsmPrinterEmitDwarfStringOffsetTest, DWARF32) {
149   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
150     return;
151 
152   const MCExpr *Arg0 = nullptr;
153   EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 4, _))
154       .WillOnce(SaveArg<0>(&Arg0));
155   TestPrinter->getAP()->emitDwarfStringOffset(Val);
156 
157   const MCSymbolRefExpr *ActualArg0 = dyn_cast_or_null<MCSymbolRefExpr>(Arg0);
158   ASSERT_NE(ActualArg0, nullptr);
159   EXPECT_EQ(&(ActualArg0->getSymbol()), Val.Symbol);
160 }
161 
162 TEST_F(AsmPrinterEmitDwarfStringOffsetTest,
163        DWARF32NoRelocationsAcrossSections) {
164   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
165     return;
166 
167   TestPrinter->setDwarfUsesRelocationsAcrossSections(false);
168   EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val.Offset, 4));
169   TestPrinter->getAP()->emitDwarfStringOffset(Val);
170 }
171 
172 TEST_F(AsmPrinterEmitDwarfStringOffsetTest, DWARF64) {
173   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
174     return;
175 
176   const MCExpr *Arg0 = nullptr;
177   EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 8, _))
178       .WillOnce(SaveArg<0>(&Arg0));
179   TestPrinter->getAP()->emitDwarfStringOffset(Val);
180 
181   const MCSymbolRefExpr *ActualArg0 = dyn_cast_or_null<MCSymbolRefExpr>(Arg0);
182   ASSERT_NE(ActualArg0, nullptr);
183   EXPECT_EQ(&(ActualArg0->getSymbol()), Val.Symbol);
184 }
185 
186 TEST_F(AsmPrinterEmitDwarfStringOffsetTest,
187        DWARF64NoRelocationsAcrossSections) {
188   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
189     return;
190 
191   TestPrinter->setDwarfUsesRelocationsAcrossSections(false);
192   EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val.Offset, 8));
193   TestPrinter->getAP()->emitDwarfStringOffset(Val);
194 }
195 
196 class AsmPrinterEmitDwarfOffsetTest : public AsmPrinterFixtureBase {
197 protected:
198   bool init(const std::string &TripleStr, unsigned DwarfVersion,
199             dwarf::DwarfFormat DwarfFormat) {
200     if (!AsmPrinterFixtureBase::init(TripleStr, DwarfVersion, DwarfFormat))
201       return false;
202 
203     Label = TestPrinter->getCtx().createTempSymbol();
204     return true;
205   }
206 
207   MCSymbol *Label = nullptr;
208   uint64_t Offset = 42;
209 };
210 
211 TEST_F(AsmPrinterEmitDwarfOffsetTest, DWARF32) {
212   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
213     return;
214 
215   const MCExpr *Arg0 = nullptr;
216   EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 4, _))
217       .WillOnce(SaveArg<0>(&Arg0));
218   TestPrinter->getAP()->emitDwarfOffset(Label, Offset);
219 
220   const MCBinaryExpr *ActualArg0 = dyn_cast_or_null<MCBinaryExpr>(Arg0);
221   ASSERT_NE(ActualArg0, nullptr);
222   EXPECT_EQ(ActualArg0->getOpcode(), MCBinaryExpr::Add);
223 
224   const MCSymbolRefExpr *ActualLHS =
225       dyn_cast_or_null<MCSymbolRefExpr>(ActualArg0->getLHS());
226   ASSERT_NE(ActualLHS, nullptr);
227   EXPECT_EQ(&(ActualLHS->getSymbol()), Label);
228 
229   const MCConstantExpr *ActualRHS =
230       dyn_cast_or_null<MCConstantExpr>(ActualArg0->getRHS());
231   ASSERT_NE(ActualRHS, nullptr);
232   EXPECT_EQ(static_cast<uint64_t>(ActualRHS->getValue()), Offset);
233 }
234 
235 TEST_F(AsmPrinterEmitDwarfOffsetTest, DWARF64) {
236   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
237     return;
238 
239   const MCExpr *Arg0 = nullptr;
240   EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 8, _))
241       .WillOnce(SaveArg<0>(&Arg0));
242   TestPrinter->getAP()->emitDwarfOffset(Label, Offset);
243 
244   const MCBinaryExpr *ActualArg0 = dyn_cast_or_null<MCBinaryExpr>(Arg0);
245   ASSERT_NE(ActualArg0, nullptr);
246   EXPECT_EQ(ActualArg0->getOpcode(), MCBinaryExpr::Add);
247 
248   const MCSymbolRefExpr *ActualLHS =
249       dyn_cast_or_null<MCSymbolRefExpr>(ActualArg0->getLHS());
250   ASSERT_NE(ActualLHS, nullptr);
251   EXPECT_EQ(&(ActualLHS->getSymbol()), Label);
252 
253   const MCConstantExpr *ActualRHS =
254       dyn_cast_or_null<MCConstantExpr>(ActualArg0->getRHS());
255   ASSERT_NE(ActualRHS, nullptr);
256   EXPECT_EQ(static_cast<uint64_t>(ActualRHS->getValue()), Offset);
257 }
258 
259 class AsmPrinterEmitDwarfLengthOrOffsetTest : public AsmPrinterFixtureBase {
260 protected:
261   uint64_t Val = 42;
262 };
263 
264 TEST_F(AsmPrinterEmitDwarfLengthOrOffsetTest, DWARF32) {
265   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
266     return;
267 
268   EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val, 4));
269   TestPrinter->getAP()->emitDwarfLengthOrOffset(Val);
270 }
271 
272 TEST_F(AsmPrinterEmitDwarfLengthOrOffsetTest, DWARF64) {
273   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
274     return;
275 
276   EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val, 8));
277   TestPrinter->getAP()->emitDwarfLengthOrOffset(Val);
278 }
279 
280 class AsmPrinterGetUnitLengthFieldByteSizeTest : public AsmPrinterFixtureBase {
281 };
282 
283 TEST_F(AsmPrinterGetUnitLengthFieldByteSizeTest, DWARF32) {
284   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
285     return;
286 
287   EXPECT_EQ(TestPrinter->getAP()->getUnitLengthFieldByteSize(), 4u);
288 }
289 
290 TEST_F(AsmPrinterGetUnitLengthFieldByteSizeTest, DWARF64) {
291   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
292     return;
293 
294   EXPECT_EQ(TestPrinter->getAP()->getUnitLengthFieldByteSize(), 12u);
295 }
296 
297 class AsmPrinterEmitDwarfUnitLengthAsIntTest : public AsmPrinterFixtureBase {
298 protected:
299   uint64_t Val = 42;
300 };
301 
302 TEST_F(AsmPrinterEmitDwarfUnitLengthAsIntTest, DWARF32) {
303   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
304     return;
305 
306   EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val, 4));
307   TestPrinter->getAP()->emitDwarfUnitLength(Val, "");
308 }
309 
310 TEST_F(AsmPrinterEmitDwarfUnitLengthAsIntTest, DWARF64) {
311   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
312     return;
313 
314   InSequence S;
315   EXPECT_CALL(TestPrinter->getMS(), emitIntValue(dwarf::DW_LENGTH_DWARF64, 4));
316   EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val, 8));
317 
318   TestPrinter->getAP()->emitDwarfUnitLength(Val, "");
319 }
320 
321 class AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest
322     : public AsmPrinterFixtureBase {
323 protected:
324   bool init(const std::string &TripleStr, unsigned DwarfVersion,
325             dwarf::DwarfFormat DwarfFormat) {
326     if (!AsmPrinterFixtureBase::init(TripleStr, DwarfVersion, DwarfFormat))
327       return false;
328 
329     Hi = TestPrinter->getCtx().createTempSymbol();
330     Lo = TestPrinter->getCtx().createTempSymbol();
331     return true;
332   }
333 
334   MCSymbol *Hi = nullptr;
335   MCSymbol *Lo = nullptr;
336 };
337 
338 TEST_F(AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest, DWARF32) {
339   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
340     return;
341 
342   EXPECT_CALL(TestPrinter->getMS(), emitAbsoluteSymbolDiff(Hi, Lo, 4));
343   TestPrinter->getAP()->emitDwarfUnitLength(Hi, Lo, "");
344 }
345 
346 TEST_F(AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest, DWARF64) {
347   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
348     return;
349 
350   InSequence S;
351   EXPECT_CALL(TestPrinter->getMS(), emitIntValue(dwarf::DW_LENGTH_DWARF64, 4));
352   EXPECT_CALL(TestPrinter->getMS(), emitAbsoluteSymbolDiff(Hi, Lo, 8));
353 
354   TestPrinter->getAP()->emitDwarfUnitLength(Hi, Lo, "");
355 }
356 
357 class AsmPrinterHandlerTest : public AsmPrinterFixtureBase {
358   class TestHandler : public AsmPrinterHandler {
359     AsmPrinterHandlerTest &Test;
360 
361   public:
362     TestHandler(AsmPrinterHandlerTest &Test) : Test(Test) {}
363     virtual ~TestHandler() {}
364     virtual void setSymbolSize(const MCSymbol *Sym, uint64_t Size) override {}
365     virtual void beginModule(Module *M) override { Test.BeginCount++; }
366     virtual void endModule() override { Test.EndCount++; }
367     virtual void beginFunction(const MachineFunction *MF) override {}
368     virtual void endFunction(const MachineFunction *MF) override {}
369     virtual void beginInstruction(const MachineInstr *MI) override {}
370     virtual void endInstruction() override {}
371   };
372 
373 protected:
374   bool init(const std::string &TripleStr, unsigned DwarfVersion,
375             dwarf::DwarfFormat DwarfFormat) {
376     if (!AsmPrinterFixtureBase::init(TripleStr, DwarfVersion, DwarfFormat))
377       return false;
378 
379     auto *AP = TestPrinter->getAP();
380     AP->addAsmPrinterHandler(AsmPrinter::HandlerInfo(
381         std::unique_ptr<AsmPrinterHandler>(new TestHandler(*this)),
382         "TestTimerName", "TestTimerDesc", "TestGroupName", "TestGroupDesc"));
383     LLVMTargetMachine *LLVMTM = static_cast<LLVMTargetMachine *>(&AP->TM);
384     legacy::PassManager PM;
385     PM.add(new MachineModuleInfoWrapperPass(LLVMTM));
386     PM.add(TestPrinter->releaseAP()); // Takes ownership of destroying AP
387     LLVMContext Context;
388     std::unique_ptr<Module> M(new Module("TestModule", Context));
389     M->setDataLayout(LLVMTM->createDataLayout());
390     PM.run(*M);
391     // Now check that we can run it twice.
392     AP->addAsmPrinterHandler(AsmPrinter::HandlerInfo(
393         std::unique_ptr<AsmPrinterHandler>(new TestHandler(*this)),
394         "TestTimerName", "TestTimerDesc", "TestGroupName", "TestGroupDesc"));
395     PM.run(*M);
396     return true;
397   }
398 
399   int BeginCount = 0;
400   int EndCount = 0;
401 };
402 
403 TEST_F(AsmPrinterHandlerTest, Basic) {
404   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
405     return;
406 
407   ASSERT_EQ(BeginCount, 3);
408   ASSERT_EQ(EndCount, 3);
409 }
410 
411 } // end namespace
412