xref: /llvm-project/llvm/unittests/CodeGen/AsmPrinterDwarfTest.cpp (revision d39bc36b1be72a16dcc4087dce547714ded324a9)
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     // AsmPrinter::emitDwarfSymbolReference(Label, true) gets the associated
54     // section from `Label` to find its BeginSymbol.
55     // Prepare the test symbol `Val` accordingly.
56 
57     Val = TestPrinter->getCtx().createTempSymbol();
58     MCSection *Sec =
59         TestPrinter->getCtx().getELFSection(".tst", ELF::SHT_PROGBITS, 0);
60     SecBeginSymbol = Sec->getBeginSymbol();
61     TestPrinter->getMS().SwitchSection(Sec);
62     Val->setFragment(&Sec->getDummyFragment());
63 
64     return true;
65   }
66 
67   MCSymbol *Val = nullptr;
68   MCSymbol *SecBeginSymbol = nullptr;
69 };
70 
71 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, COFF) {
72   if (!init("x86_64-pc-windows", /*DwarfVersion=*/4, dwarf::DWARF32))
73     return;
74 
75   EXPECT_CALL(TestPrinter->getMS(), EmitCOFFSecRel32(Val, 0));
76   TestPrinter->getAP()->emitDwarfSymbolReference(Val, false);
77 }
78 
79 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, COFFForceOffset) {
80   if (!init("x86_64-pc-windows", /*DwarfVersion=*/4, dwarf::DWARF32))
81     return;
82 
83   EXPECT_CALL(TestPrinter->getMS(),
84               emitAbsoluteSymbolDiff(Val, SecBeginSymbol, 4));
85   TestPrinter->getAP()->emitDwarfSymbolReference(Val, true);
86 }
87 
88 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, ELFDWARF32) {
89   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
90     return;
91 
92   const MCExpr *Arg0 = nullptr;
93   EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 4, _))
94       .WillOnce(SaveArg<0>(&Arg0));
95   TestPrinter->getAP()->emitDwarfSymbolReference(Val, false);
96 
97   const MCSymbolRefExpr *ActualArg0 = dyn_cast_or_null<MCSymbolRefExpr>(Arg0);
98   ASSERT_NE(ActualArg0, nullptr);
99   EXPECT_EQ(&(ActualArg0->getSymbol()), Val);
100 }
101 
102 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, ELFDWARF32ForceOffset) {
103   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
104     return;
105 
106   EXPECT_CALL(TestPrinter->getMS(),
107               emitAbsoluteSymbolDiff(Val, SecBeginSymbol, 4));
108   TestPrinter->getAP()->emitDwarfSymbolReference(Val, true);
109 }
110 
111 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, ELFDWARF64) {
112   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
113     return;
114 
115   const MCExpr *Arg0 = nullptr;
116   EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 8, _))
117       .WillOnce(SaveArg<0>(&Arg0));
118   TestPrinter->getAP()->emitDwarfSymbolReference(Val, false);
119 
120   const MCSymbolRefExpr *ActualArg0 = dyn_cast_or_null<MCSymbolRefExpr>(Arg0);
121   ASSERT_NE(ActualArg0, nullptr);
122   EXPECT_EQ(&(ActualArg0->getSymbol()), Val);
123 }
124 
125 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest, ELFDWARF64ForceOffset) {
126   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
127     return;
128 
129   EXPECT_CALL(TestPrinter->getMS(),
130               emitAbsoluteSymbolDiff(Val, SecBeginSymbol, 8));
131   TestPrinter->getAP()->emitDwarfSymbolReference(Val, true);
132 }
133 
134 class AsmPrinterEmitDwarfStringOffsetTest : public AsmPrinterFixtureBase {
135 protected:
136   bool init(const std::string &TripleStr, unsigned DwarfVersion,
137             dwarf::DwarfFormat DwarfFormat) {
138     if (!AsmPrinterFixtureBase::init(TripleStr, DwarfVersion, DwarfFormat))
139       return false;
140 
141     Val.Index = DwarfStringPoolEntry::NotIndexed;
142     Val.Symbol = TestPrinter->getCtx().createTempSymbol();
143     Val.Offset = 42;
144     return true;
145   }
146 
147   DwarfStringPoolEntry Val;
148 };
149 
150 TEST_F(AsmPrinterEmitDwarfStringOffsetTest, DWARF32) {
151   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
152     return;
153 
154   const MCExpr *Arg0 = nullptr;
155   EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 4, _))
156       .WillOnce(SaveArg<0>(&Arg0));
157   TestPrinter->getAP()->emitDwarfStringOffset(Val);
158 
159   const MCSymbolRefExpr *ActualArg0 = dyn_cast_or_null<MCSymbolRefExpr>(Arg0);
160   ASSERT_NE(ActualArg0, nullptr);
161   EXPECT_EQ(&(ActualArg0->getSymbol()), Val.Symbol);
162 }
163 
164 TEST_F(AsmPrinterEmitDwarfStringOffsetTest,
165        DWARF32NoRelocationsAcrossSections) {
166   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
167     return;
168 
169   TestPrinter->setDwarfUsesRelocationsAcrossSections(false);
170   EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val.Offset, 4));
171   TestPrinter->getAP()->emitDwarfStringOffset(Val);
172 }
173 
174 TEST_F(AsmPrinterEmitDwarfStringOffsetTest, DWARF64) {
175   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
176     return;
177 
178   const MCExpr *Arg0 = nullptr;
179   EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 8, _))
180       .WillOnce(SaveArg<0>(&Arg0));
181   TestPrinter->getAP()->emitDwarfStringOffset(Val);
182 
183   const MCSymbolRefExpr *ActualArg0 = dyn_cast_or_null<MCSymbolRefExpr>(Arg0);
184   ASSERT_NE(ActualArg0, nullptr);
185   EXPECT_EQ(&(ActualArg0->getSymbol()), Val.Symbol);
186 }
187 
188 TEST_F(AsmPrinterEmitDwarfStringOffsetTest,
189        DWARF64NoRelocationsAcrossSections) {
190   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
191     return;
192 
193   TestPrinter->setDwarfUsesRelocationsAcrossSections(false);
194   EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val.Offset, 8));
195   TestPrinter->getAP()->emitDwarfStringOffset(Val);
196 }
197 
198 class AsmPrinterEmitDwarfOffsetTest : public AsmPrinterFixtureBase {
199 protected:
200   bool init(const std::string &TripleStr, unsigned DwarfVersion,
201             dwarf::DwarfFormat DwarfFormat) {
202     if (!AsmPrinterFixtureBase::init(TripleStr, DwarfVersion, DwarfFormat))
203       return false;
204 
205     Label = TestPrinter->getCtx().createTempSymbol();
206     return true;
207   }
208 
209   MCSymbol *Label = nullptr;
210   uint64_t Offset = 42;
211 };
212 
213 TEST_F(AsmPrinterEmitDwarfOffsetTest, DWARF32) {
214   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
215     return;
216 
217   const MCExpr *Arg0 = nullptr;
218   EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 4, _))
219       .WillOnce(SaveArg<0>(&Arg0));
220   TestPrinter->getAP()->emitDwarfOffset(Label, Offset);
221 
222   const MCBinaryExpr *ActualArg0 = dyn_cast_or_null<MCBinaryExpr>(Arg0);
223   ASSERT_NE(ActualArg0, nullptr);
224   EXPECT_EQ(ActualArg0->getOpcode(), MCBinaryExpr::Add);
225 
226   const MCSymbolRefExpr *ActualLHS =
227       dyn_cast_or_null<MCSymbolRefExpr>(ActualArg0->getLHS());
228   ASSERT_NE(ActualLHS, nullptr);
229   EXPECT_EQ(&(ActualLHS->getSymbol()), Label);
230 
231   const MCConstantExpr *ActualRHS =
232       dyn_cast_or_null<MCConstantExpr>(ActualArg0->getRHS());
233   ASSERT_NE(ActualRHS, nullptr);
234   EXPECT_EQ(static_cast<uint64_t>(ActualRHS->getValue()), Offset);
235 }
236 
237 TEST_F(AsmPrinterEmitDwarfOffsetTest, DWARF64) {
238   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
239     return;
240 
241   const MCExpr *Arg0 = nullptr;
242   EXPECT_CALL(TestPrinter->getMS(), emitValueImpl(_, 8, _))
243       .WillOnce(SaveArg<0>(&Arg0));
244   TestPrinter->getAP()->emitDwarfOffset(Label, Offset);
245 
246   const MCBinaryExpr *ActualArg0 = dyn_cast_or_null<MCBinaryExpr>(Arg0);
247   ASSERT_NE(ActualArg0, nullptr);
248   EXPECT_EQ(ActualArg0->getOpcode(), MCBinaryExpr::Add);
249 
250   const MCSymbolRefExpr *ActualLHS =
251       dyn_cast_or_null<MCSymbolRefExpr>(ActualArg0->getLHS());
252   ASSERT_NE(ActualLHS, nullptr);
253   EXPECT_EQ(&(ActualLHS->getSymbol()), Label);
254 
255   const MCConstantExpr *ActualRHS =
256       dyn_cast_or_null<MCConstantExpr>(ActualArg0->getRHS());
257   ASSERT_NE(ActualRHS, nullptr);
258   EXPECT_EQ(static_cast<uint64_t>(ActualRHS->getValue()), Offset);
259 }
260 
261 class AsmPrinterEmitDwarfLengthOrOffsetTest : public AsmPrinterFixtureBase {
262 protected:
263   uint64_t Val = 42;
264 };
265 
266 TEST_F(AsmPrinterEmitDwarfLengthOrOffsetTest, DWARF32) {
267   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
268     return;
269 
270   EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val, 4));
271   TestPrinter->getAP()->emitDwarfLengthOrOffset(Val);
272 }
273 
274 TEST_F(AsmPrinterEmitDwarfLengthOrOffsetTest, DWARF64) {
275   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
276     return;
277 
278   EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val, 8));
279   TestPrinter->getAP()->emitDwarfLengthOrOffset(Val);
280 }
281 
282 class AsmPrinterGetUnitLengthFieldByteSizeTest : public AsmPrinterFixtureBase {
283 };
284 
285 TEST_F(AsmPrinterGetUnitLengthFieldByteSizeTest, DWARF32) {
286   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
287     return;
288 
289   EXPECT_EQ(TestPrinter->getAP()->getUnitLengthFieldByteSize(), 4u);
290 }
291 
292 TEST_F(AsmPrinterGetUnitLengthFieldByteSizeTest, DWARF64) {
293   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
294     return;
295 
296   EXPECT_EQ(TestPrinter->getAP()->getUnitLengthFieldByteSize(), 12u);
297 }
298 
299 class AsmPrinterEmitDwarfUnitLengthAsIntTest : public AsmPrinterFixtureBase {
300 protected:
301   uint64_t Val = 42;
302 };
303 
304 TEST_F(AsmPrinterEmitDwarfUnitLengthAsIntTest, DWARF32) {
305   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
306     return;
307 
308   EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val, 4));
309   TestPrinter->getAP()->emitDwarfUnitLength(Val, "");
310 }
311 
312 TEST_F(AsmPrinterEmitDwarfUnitLengthAsIntTest, DWARF64) {
313   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
314     return;
315 
316   InSequence S;
317   EXPECT_CALL(TestPrinter->getMS(), emitIntValue(dwarf::DW_LENGTH_DWARF64, 4));
318   EXPECT_CALL(TestPrinter->getMS(), emitIntValue(Val, 8));
319 
320   TestPrinter->getAP()->emitDwarfUnitLength(Val, "");
321 }
322 
323 class AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest
324     : public AsmPrinterFixtureBase {
325 protected:
326   bool init(const std::string &TripleStr, unsigned DwarfVersion,
327             dwarf::DwarfFormat DwarfFormat) {
328     if (!AsmPrinterFixtureBase::init(TripleStr, DwarfVersion, DwarfFormat))
329       return false;
330 
331     return true;
332   }
333 };
334 
335 TEST_F(AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest, DWARF32) {
336   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
337     return;
338 
339   InSequence S;
340   const MCSymbol *Hi = nullptr;
341   const MCSymbol *Lo = nullptr;
342   EXPECT_CALL(TestPrinter->getMS(), emitAbsoluteSymbolDiff(_, _, 4))
343       .WillOnce(DoAll(SaveArg<0>(&Hi), SaveArg<1>(&Lo)));
344   MCSymbol *LTmp = nullptr;
345   EXPECT_CALL(TestPrinter->getMS(), emitLabel(_, _))
346       .WillOnce(SaveArg<0>(&LTmp));
347 
348   MCSymbol *HTmp = TestPrinter->getAP()->emitDwarfUnitLength("", "");
349   EXPECT_NE(Lo, nullptr);
350   EXPECT_EQ(Lo, LTmp);
351   EXPECT_NE(Hi, nullptr);
352   EXPECT_EQ(Hi, HTmp);
353 }
354 
355 TEST_F(AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest, DWARF64) {
356   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64))
357     return;
358 
359   InSequence S;
360   const MCSymbol *Hi = nullptr;
361   const MCSymbol *Lo = nullptr;
362   EXPECT_CALL(TestPrinter->getMS(), emitIntValue(dwarf::DW_LENGTH_DWARF64, 4));
363   EXPECT_CALL(TestPrinter->getMS(), emitAbsoluteSymbolDiff(_, _, 8))
364       .WillOnce(DoAll(SaveArg<0>(&Hi), SaveArg<1>(&Lo)));
365   MCSymbol *LTmp = nullptr;
366   EXPECT_CALL(TestPrinter->getMS(), emitLabel(_, _))
367       .WillOnce(SaveArg<0>(&LTmp));
368 
369   MCSymbol *HTmp = TestPrinter->getAP()->emitDwarfUnitLength("", "");
370   EXPECT_NE(Lo, nullptr);
371   EXPECT_EQ(Lo, LTmp);
372   EXPECT_NE(Hi, nullptr);
373   EXPECT_EQ(Hi, HTmp);
374 }
375 
376 class AsmPrinterHandlerTest : public AsmPrinterFixtureBase {
377   class TestHandler : public AsmPrinterHandler {
378     AsmPrinterHandlerTest &Test;
379 
380   public:
381     TestHandler(AsmPrinterHandlerTest &Test) : Test(Test) {}
382     virtual ~TestHandler() {}
383     virtual void setSymbolSize(const MCSymbol *Sym, uint64_t Size) override {}
384     virtual void beginModule(Module *M) override { Test.BeginCount++; }
385     virtual void endModule() override { Test.EndCount++; }
386     virtual void beginFunction(const MachineFunction *MF) override {}
387     virtual void endFunction(const MachineFunction *MF) override {}
388     virtual void beginInstruction(const MachineInstr *MI) override {}
389     virtual void endInstruction() override {}
390   };
391 
392 protected:
393   bool init(const std::string &TripleStr, unsigned DwarfVersion,
394             dwarf::DwarfFormat DwarfFormat) {
395     if (!AsmPrinterFixtureBase::init(TripleStr, DwarfVersion, DwarfFormat))
396       return false;
397 
398     auto *AP = TestPrinter->getAP();
399     AP->addAsmPrinterHandler(AsmPrinter::HandlerInfo(
400         std::unique_ptr<AsmPrinterHandler>(new TestHandler(*this)),
401         "TestTimerName", "TestTimerDesc", "TestGroupName", "TestGroupDesc"));
402     LLVMTargetMachine *LLVMTM = static_cast<LLVMTargetMachine *>(&AP->TM);
403     legacy::PassManager PM;
404     PM.add(new MachineModuleInfoWrapperPass(LLVMTM));
405     PM.add(TestPrinter->releaseAP()); // Takes ownership of destroying AP
406     LLVMContext Context;
407     std::unique_ptr<Module> M(new Module("TestModule", Context));
408     M->setDataLayout(LLVMTM->createDataLayout());
409     PM.run(*M);
410     // Now check that we can run it twice.
411     AP->addAsmPrinterHandler(AsmPrinter::HandlerInfo(
412         std::unique_ptr<AsmPrinterHandler>(new TestHandler(*this)),
413         "TestTimerName", "TestTimerDesc", "TestGroupName", "TestGroupDesc"));
414     PM.run(*M);
415     return true;
416   }
417 
418   int BeginCount = 0;
419   int EndCount = 0;
420 };
421 
422 TEST_F(AsmPrinterHandlerTest, Basic) {
423   if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32))
424     return;
425 
426   ASSERT_EQ(BeginCount, 3);
427   ASSERT_EQ(EndCount, 3);
428 }
429 
430 } // end namespace
431