1 //===- llvm/unittest/CodeGen/AsmPrinterDwarfTest.cpp ----------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "TestAsmPrinter.h"
10 #include "llvm/BinaryFormat/ELF.h"
11 #include "llvm/CodeGen/AsmPrinter.h"
12 #include "llvm/CodeGen/AsmPrinterHandler.h"
13 #include "llvm/CodeGen/DebugHandlerBase.h"
14 #include "llvm/CodeGen/MachineModuleInfo.h"
15 #include "llvm/IR/LegacyPassManager.h"
16 #include "llvm/IR/Module.h"
17 #include "llvm/IR/PassManager.h"
18 #include "llvm/MC/MCContext.h"
19 #include "llvm/MC/MCSectionELF.h"
20 #include "llvm/Target/TargetMachine.h"
21 #include "llvm/Testing/Support/Error.h"
26 using testing::InSequence
;
27 using testing::SaveArg
;
31 class AsmPrinterFixtureBase
: public testing::Test
{
32 void setupTestPrinter(const std::string
&TripleStr
, unsigned DwarfVersion
,
33 dwarf::DwarfFormat DwarfFormat
) {
34 auto ExpectedTestPrinter
=
35 TestAsmPrinter::create(TripleStr
, DwarfVersion
, DwarfFormat
);
36 ASSERT_THAT_EXPECTED(ExpectedTestPrinter
, Succeeded());
37 TestPrinter
= std::move(ExpectedTestPrinter
.get());
41 bool init(const std::string
&TripleStr
, unsigned DwarfVersion
,
42 dwarf::DwarfFormat DwarfFormat
) {
43 setupTestPrinter(TripleStr
, DwarfVersion
, DwarfFormat
);
44 return TestPrinter
!= nullptr;
47 std::unique_ptr
<TestAsmPrinter
> TestPrinter
;
50 class AsmPrinterEmitDwarfSymbolReferenceTest
: public AsmPrinterFixtureBase
{
52 bool init(const std::string
&TripleStr
, unsigned DwarfVersion
,
53 dwarf::DwarfFormat DwarfFormat
) {
54 if (!AsmPrinterFixtureBase::init(TripleStr
, DwarfVersion
, DwarfFormat
))
57 // AsmPrinter::emitDwarfSymbolReference(Label, true) gets the associated
58 // section from `Label` to find its BeginSymbol.
59 // Prepare the test symbol `Val` accordingly.
61 Val
= TestPrinter
->getCtx().createTempSymbol();
63 TestPrinter
->getCtx().getELFSection(".tst", ELF::SHT_PROGBITS
, 0);
64 SecBeginSymbol
= Sec
->getBeginSymbol();
65 TestPrinter
->getMS().switchSection(Sec
);
66 Val
->setFragment(&Sec
->getDummyFragment());
71 MCSymbol
*Val
= nullptr;
72 MCSymbol
*SecBeginSymbol
= nullptr;
75 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest
, COFF
) {
76 if (!init("x86_64-pc-windows", /*DwarfVersion=*/4, dwarf::DWARF32
))
79 EXPECT_CALL(TestPrinter
->getMS(), emitCOFFSecRel32(Val
, 0));
80 TestPrinter
->getAP()->emitDwarfSymbolReference(Val
, false);
83 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest
, COFFForceOffset
) {
84 if (!init("x86_64-pc-windows", /*DwarfVersion=*/4, dwarf::DWARF32
))
87 EXPECT_CALL(TestPrinter
->getMS(),
88 emitAbsoluteSymbolDiff(Val
, SecBeginSymbol
, 4));
89 TestPrinter
->getAP()->emitDwarfSymbolReference(Val
, true);
92 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest
, ELFDWARF32
) {
93 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
96 const MCExpr
*Arg0
= nullptr;
97 EXPECT_CALL(TestPrinter
->getMS(), emitValueImpl(_
, 4, _
))
98 .WillOnce(SaveArg
<0>(&Arg0
));
99 TestPrinter
->getAP()->emitDwarfSymbolReference(Val
, false);
101 const MCSymbolRefExpr
*ActualArg0
= dyn_cast_or_null
<MCSymbolRefExpr
>(Arg0
);
102 ASSERT_NE(ActualArg0
, nullptr);
103 EXPECT_EQ(&(ActualArg0
->getSymbol()), Val
);
106 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest
, ELFDWARF32ForceOffset
) {
107 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
110 EXPECT_CALL(TestPrinter
->getMS(),
111 emitAbsoluteSymbolDiff(Val
, SecBeginSymbol
, 4));
112 TestPrinter
->getAP()->emitDwarfSymbolReference(Val
, true);
115 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest
, ELFDWARF64
) {
116 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64
))
119 const MCExpr
*Arg0
= nullptr;
120 EXPECT_CALL(TestPrinter
->getMS(), emitValueImpl(_
, 8, _
))
121 .WillOnce(SaveArg
<0>(&Arg0
));
122 TestPrinter
->getAP()->emitDwarfSymbolReference(Val
, false);
124 const MCSymbolRefExpr
*ActualArg0
= dyn_cast_or_null
<MCSymbolRefExpr
>(Arg0
);
125 ASSERT_NE(ActualArg0
, nullptr);
126 EXPECT_EQ(&(ActualArg0
->getSymbol()), Val
);
129 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest
, ELFDWARF64ForceOffset
) {
130 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64
))
133 EXPECT_CALL(TestPrinter
->getMS(),
134 emitAbsoluteSymbolDiff(Val
, SecBeginSymbol
, 8));
135 TestPrinter
->getAP()->emitDwarfSymbolReference(Val
, true);
138 class AsmPrinterEmitDwarfStringOffsetTest
: public AsmPrinterFixtureBase
{
140 bool init(const std::string
&TripleStr
, unsigned DwarfVersion
,
141 dwarf::DwarfFormat DwarfFormat
) {
142 if (!AsmPrinterFixtureBase::init(TripleStr
, DwarfVersion
, DwarfFormat
))
145 Val
.Index
= DwarfStringPoolEntry::NotIndexed
;
146 Val
.Symbol
= TestPrinter
->getCtx().createTempSymbol();
151 DwarfStringPoolEntry Val
;
154 TEST_F(AsmPrinterEmitDwarfStringOffsetTest
, DWARF32
) {
155 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
158 const MCExpr
*Arg0
= nullptr;
159 EXPECT_CALL(TestPrinter
->getMS(), emitValueImpl(_
, 4, _
))
160 .WillOnce(SaveArg
<0>(&Arg0
));
161 TestPrinter
->getAP()->emitDwarfStringOffset(Val
);
163 const MCSymbolRefExpr
*ActualArg0
= dyn_cast_or_null
<MCSymbolRefExpr
>(Arg0
);
164 ASSERT_NE(ActualArg0
, nullptr);
165 EXPECT_EQ(&(ActualArg0
->getSymbol()), Val
.Symbol
);
168 TEST_F(AsmPrinterEmitDwarfStringOffsetTest
,
169 DWARF32NoRelocationsAcrossSections
) {
170 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
173 TestPrinter
->setDwarfUsesRelocationsAcrossSections(false);
174 EXPECT_CALL(TestPrinter
->getMS(), emitIntValue(Val
.Offset
, 4));
175 TestPrinter
->getAP()->emitDwarfStringOffset(Val
);
178 TEST_F(AsmPrinterEmitDwarfStringOffsetTest
, DWARF64
) {
179 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64
))
182 const MCExpr
*Arg0
= nullptr;
183 EXPECT_CALL(TestPrinter
->getMS(), emitValueImpl(_
, 8, _
))
184 .WillOnce(SaveArg
<0>(&Arg0
));
185 TestPrinter
->getAP()->emitDwarfStringOffset(Val
);
187 const MCSymbolRefExpr
*ActualArg0
= dyn_cast_or_null
<MCSymbolRefExpr
>(Arg0
);
188 ASSERT_NE(ActualArg0
, nullptr);
189 EXPECT_EQ(&(ActualArg0
->getSymbol()), Val
.Symbol
);
192 TEST_F(AsmPrinterEmitDwarfStringOffsetTest
,
193 DWARF64NoRelocationsAcrossSections
) {
194 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64
))
197 TestPrinter
->setDwarfUsesRelocationsAcrossSections(false);
198 EXPECT_CALL(TestPrinter
->getMS(), emitIntValue(Val
.Offset
, 8));
199 TestPrinter
->getAP()->emitDwarfStringOffset(Val
);
202 class AsmPrinterEmitDwarfOffsetTest
: public AsmPrinterFixtureBase
{
204 bool init(const std::string
&TripleStr
, unsigned DwarfVersion
,
205 dwarf::DwarfFormat DwarfFormat
) {
206 if (!AsmPrinterFixtureBase::init(TripleStr
, DwarfVersion
, DwarfFormat
))
209 Label
= TestPrinter
->getCtx().createTempSymbol();
213 MCSymbol
*Label
= nullptr;
214 uint64_t Offset
= 42;
217 TEST_F(AsmPrinterEmitDwarfOffsetTest
, DWARF32
) {
218 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
221 const MCExpr
*Arg0
= nullptr;
222 EXPECT_CALL(TestPrinter
->getMS(), emitValueImpl(_
, 4, _
))
223 .WillOnce(SaveArg
<0>(&Arg0
));
224 TestPrinter
->getAP()->emitDwarfOffset(Label
, Offset
);
226 const MCBinaryExpr
*ActualArg0
= dyn_cast_or_null
<MCBinaryExpr
>(Arg0
);
227 ASSERT_NE(ActualArg0
, nullptr);
228 EXPECT_EQ(ActualArg0
->getOpcode(), MCBinaryExpr::Add
);
230 const MCSymbolRefExpr
*ActualLHS
=
231 dyn_cast_or_null
<MCSymbolRefExpr
>(ActualArg0
->getLHS());
232 ASSERT_NE(ActualLHS
, nullptr);
233 EXPECT_EQ(&(ActualLHS
->getSymbol()), Label
);
235 const MCConstantExpr
*ActualRHS
=
236 dyn_cast_or_null
<MCConstantExpr
>(ActualArg0
->getRHS());
237 ASSERT_NE(ActualRHS
, nullptr);
238 EXPECT_EQ(static_cast<uint64_t>(ActualRHS
->getValue()), Offset
);
241 TEST_F(AsmPrinterEmitDwarfOffsetTest
, DWARF64
) {
242 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64
))
245 const MCExpr
*Arg0
= nullptr;
246 EXPECT_CALL(TestPrinter
->getMS(), emitValueImpl(_
, 8, _
))
247 .WillOnce(SaveArg
<0>(&Arg0
));
248 TestPrinter
->getAP()->emitDwarfOffset(Label
, Offset
);
250 const MCBinaryExpr
*ActualArg0
= dyn_cast_or_null
<MCBinaryExpr
>(Arg0
);
251 ASSERT_NE(ActualArg0
, nullptr);
252 EXPECT_EQ(ActualArg0
->getOpcode(), MCBinaryExpr::Add
);
254 const MCSymbolRefExpr
*ActualLHS
=
255 dyn_cast_or_null
<MCSymbolRefExpr
>(ActualArg0
->getLHS());
256 ASSERT_NE(ActualLHS
, nullptr);
257 EXPECT_EQ(&(ActualLHS
->getSymbol()), Label
);
259 const MCConstantExpr
*ActualRHS
=
260 dyn_cast_or_null
<MCConstantExpr
>(ActualArg0
->getRHS());
261 ASSERT_NE(ActualRHS
, nullptr);
262 EXPECT_EQ(static_cast<uint64_t>(ActualRHS
->getValue()), Offset
);
265 class AsmPrinterEmitDwarfLengthOrOffsetTest
: public AsmPrinterFixtureBase
{
270 TEST_F(AsmPrinterEmitDwarfLengthOrOffsetTest
, DWARF32
) {
271 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
274 EXPECT_CALL(TestPrinter
->getMS(), emitIntValue(Val
, 4));
275 TestPrinter
->getAP()->emitDwarfLengthOrOffset(Val
);
278 TEST_F(AsmPrinterEmitDwarfLengthOrOffsetTest
, DWARF64
) {
279 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64
))
282 EXPECT_CALL(TestPrinter
->getMS(), emitIntValue(Val
, 8));
283 TestPrinter
->getAP()->emitDwarfLengthOrOffset(Val
);
286 class AsmPrinterGetUnitLengthFieldByteSizeTest
: public AsmPrinterFixtureBase
{
289 TEST_F(AsmPrinterGetUnitLengthFieldByteSizeTest
, DWARF32
) {
290 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
293 EXPECT_EQ(TestPrinter
->getAP()->getUnitLengthFieldByteSize(), 4u);
296 TEST_F(AsmPrinterGetUnitLengthFieldByteSizeTest
, DWARF64
) {
297 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64
))
300 EXPECT_EQ(TestPrinter
->getAP()->getUnitLengthFieldByteSize(), 12u);
303 class AsmPrinterEmitDwarfUnitLengthAsIntTest
: public AsmPrinterFixtureBase
{
308 TEST_F(AsmPrinterEmitDwarfUnitLengthAsIntTest
, DWARF32
) {
309 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
312 EXPECT_CALL(TestPrinter
->getMS(), emitIntValue(Val
, 4));
313 TestPrinter
->getAP()->emitDwarfUnitLength(Val
, "");
316 TEST_F(AsmPrinterEmitDwarfUnitLengthAsIntTest
, DWARF64
) {
317 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64
))
321 EXPECT_CALL(TestPrinter
->getMS(), emitIntValue(dwarf::DW_LENGTH_DWARF64
, 4));
322 EXPECT_CALL(TestPrinter
->getMS(), emitIntValue(Val
, 8));
324 TestPrinter
->getAP()->emitDwarfUnitLength(Val
, "");
327 class AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest
328 : public AsmPrinterFixtureBase
{
330 bool init(const std::string
&TripleStr
, unsigned DwarfVersion
,
331 dwarf::DwarfFormat DwarfFormat
) {
332 if (!AsmPrinterFixtureBase::init(TripleStr
, DwarfVersion
, DwarfFormat
))
339 TEST_F(AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest
, DWARF32
) {
340 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
344 const MCSymbol
*Hi
= nullptr;
345 const MCSymbol
*Lo
= nullptr;
346 EXPECT_CALL(TestPrinter
->getMS(), emitAbsoluteSymbolDiff(_
, _
, 4))
347 .WillOnce(DoAll(SaveArg
<0>(&Hi
), SaveArg
<1>(&Lo
)));
348 MCSymbol
*LTmp
= nullptr;
349 EXPECT_CALL(TestPrinter
->getMS(), emitLabel(_
, _
))
350 .WillOnce(SaveArg
<0>(<mp
));
352 MCSymbol
*HTmp
= TestPrinter
->getAP()->emitDwarfUnitLength("", "");
353 EXPECT_NE(Lo
, nullptr);
355 EXPECT_NE(Hi
, nullptr);
359 TEST_F(AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest
, DWARF64
) {
360 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64
))
364 const MCSymbol
*Hi
= nullptr;
365 const MCSymbol
*Lo
= nullptr;
366 EXPECT_CALL(TestPrinter
->getMS(), emitIntValue(dwarf::DW_LENGTH_DWARF64
, 4));
367 EXPECT_CALL(TestPrinter
->getMS(), emitAbsoluteSymbolDiff(_
, _
, 8))
368 .WillOnce(DoAll(SaveArg
<0>(&Hi
), SaveArg
<1>(&Lo
)));
369 MCSymbol
*LTmp
= nullptr;
370 EXPECT_CALL(TestPrinter
->getMS(), emitLabel(_
, _
))
371 .WillOnce(SaveArg
<0>(<mp
));
373 MCSymbol
*HTmp
= TestPrinter
->getAP()->emitDwarfUnitLength("", "");
374 EXPECT_NE(Lo
, nullptr);
376 EXPECT_NE(Hi
, nullptr);
380 class AsmPrinterHandlerTest
: public AsmPrinterFixtureBase
{
381 class TestHandler
: public AsmPrinterHandler
{
382 AsmPrinterHandlerTest
&Test
;
385 TestHandler(AsmPrinterHandlerTest
&Test
) : Test(Test
) {}
386 virtual ~TestHandler() {}
387 virtual void beginModule(Module
*M
) override
{ Test
.BeginCount
++; }
388 virtual void endModule() override
{ Test
.EndCount
++; }
389 virtual void beginFunction(const MachineFunction
*MF
) override
{}
390 virtual void endFunction(const MachineFunction
*MF
) override
{}
394 bool init(const std::string
&TripleStr
, unsigned DwarfVersion
,
395 dwarf::DwarfFormat DwarfFormat
) {
396 if (!AsmPrinterFixtureBase::init(TripleStr
, DwarfVersion
, DwarfFormat
))
399 auto *AP
= TestPrinter
->getAP();
400 AP
->addAsmPrinterHandler(std::make_unique
<TestHandler
>(*this));
401 TargetMachine
*TM
= &AP
->TM
;
402 legacy::PassManager PM
;
403 PM
.add(new MachineModuleInfoWrapperPass(TM
));
404 PM
.add(TestPrinter
->releaseAP()); // Takes ownership of destroying AP
406 std::unique_ptr
<Module
> M(new Module("TestModule", Context
));
407 M
->setDataLayout(TM
->createDataLayout());
409 // Now check that we can run it twice.
410 AP
->addAsmPrinterHandler(std::make_unique
<TestHandler
>(*this));
419 TEST_F(AsmPrinterHandlerTest
, Basic
) {
420 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
423 ASSERT_EQ(BeginCount
, 3);
424 ASSERT_EQ(EndCount
, 3);
427 class AsmPrinterDebugHandlerTest
: public AsmPrinterFixtureBase
{
428 class TestDebugHandler
: public DebugHandlerBase
{
429 AsmPrinterDebugHandlerTest
&Test
;
432 TestDebugHandler(AsmPrinterDebugHandlerTest
&Test
, AsmPrinter
*AP
)
433 : DebugHandlerBase(AP
), Test(Test
) {}
434 virtual ~TestDebugHandler() {}
435 virtual void beginModule(Module
*M
) override
{ Test
.BeginCount
++; }
436 virtual void endModule() override
{ Test
.EndCount
++; }
437 virtual void beginFunctionImpl(const MachineFunction
*MF
) override
{}
438 virtual void endFunctionImpl(const MachineFunction
*MF
) override
{}
439 virtual void beginInstruction(const MachineInstr
*MI
) override
{}
440 virtual void endInstruction() override
{}
444 bool init(const std::string
&TripleStr
, unsigned DwarfVersion
,
445 dwarf::DwarfFormat DwarfFormat
) {
446 if (!AsmPrinterFixtureBase::init(TripleStr
, DwarfVersion
, DwarfFormat
))
449 auto *AP
= TestPrinter
->getAP();
450 AP
->addDebugHandler(std::make_unique
<TestDebugHandler
>(*this, AP
));
451 TargetMachine
*TM
= &AP
->TM
;
452 legacy::PassManager PM
;
453 PM
.add(new MachineModuleInfoWrapperPass(TM
));
454 PM
.add(TestPrinter
->releaseAP()); // Takes ownership of destroying AP
456 std::unique_ptr
<Module
> M(new Module("TestModule", Context
));
457 M
->setDataLayout(TM
->createDataLayout());
459 // Now check that we can run it twice.
460 AP
->addDebugHandler(std::make_unique
<TestDebugHandler
>(*this, AP
));
469 TEST_F(AsmPrinterDebugHandlerTest
, Basic
) {
470 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
473 ASSERT_EQ(BeginCount
, 3);
474 ASSERT_EQ(EndCount
, 3);