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/MachineModuleInfo.h"
13 #include "llvm/IR/LegacyPassManager.h"
14 #include "llvm/IR/Module.h"
15 #include "llvm/IR/PassManager.h"
16 #include "llvm/MC/MCContext.h"
17 #include "llvm/MC/MCSectionELF.h"
18 #include "llvm/Target/TargetMachine.h"
19 #include "llvm/Testing/Support/Error.h"
23 using testing::InSequence
;
24 using testing::SaveArg
;
28 class AsmPrinterFixtureBase
: public testing::Test
{
29 void setupTestPrinter(const std::string
&TripleStr
, unsigned DwarfVersion
,
30 dwarf::DwarfFormat DwarfFormat
) {
31 auto ExpectedTestPrinter
=
32 TestAsmPrinter::create(TripleStr
, DwarfVersion
, DwarfFormat
);
33 ASSERT_THAT_EXPECTED(ExpectedTestPrinter
, Succeeded());
34 TestPrinter
= std::move(ExpectedTestPrinter
.get());
38 bool init(const std::string
&TripleStr
, unsigned DwarfVersion
,
39 dwarf::DwarfFormat DwarfFormat
) {
40 setupTestPrinter(TripleStr
, DwarfVersion
, DwarfFormat
);
41 return TestPrinter
!= nullptr;
44 std::unique_ptr
<TestAsmPrinter
> TestPrinter
;
47 class AsmPrinterEmitDwarfSymbolReferenceTest
: public AsmPrinterFixtureBase
{
49 bool init(const std::string
&TripleStr
, unsigned DwarfVersion
,
50 dwarf::DwarfFormat DwarfFormat
) {
51 if (!AsmPrinterFixtureBase::init(TripleStr
, DwarfVersion
, DwarfFormat
))
54 // AsmPrinter::emitDwarfSymbolReference(Label, true) gets the associated
55 // section from `Label` to find its BeginSymbol.
56 // Prepare the test symbol `Val` accordingly.
58 Val
= TestPrinter
->getCtx().createTempSymbol();
60 TestPrinter
->getCtx().getELFSection(".tst", ELF::SHT_PROGBITS
, 0);
61 SecBeginSymbol
= Sec
->getBeginSymbol();
62 TestPrinter
->getMS().switchSection(Sec
);
63 Val
->setFragment(&Sec
->getDummyFragment());
68 MCSymbol
*Val
= nullptr;
69 MCSymbol
*SecBeginSymbol
= nullptr;
72 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest
, COFF
) {
73 if (!init("x86_64-pc-windows", /*DwarfVersion=*/4, dwarf::DWARF32
))
76 EXPECT_CALL(TestPrinter
->getMS(), emitCOFFSecRel32(Val
, 0));
77 TestPrinter
->getAP()->emitDwarfSymbolReference(Val
, false);
80 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest
, COFFForceOffset
) {
81 if (!init("x86_64-pc-windows", /*DwarfVersion=*/4, dwarf::DWARF32
))
84 EXPECT_CALL(TestPrinter
->getMS(),
85 emitAbsoluteSymbolDiff(Val
, SecBeginSymbol
, 4));
86 TestPrinter
->getAP()->emitDwarfSymbolReference(Val
, true);
89 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest
, ELFDWARF32
) {
90 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
93 const MCExpr
*Arg0
= nullptr;
94 EXPECT_CALL(TestPrinter
->getMS(), emitValueImpl(_
, 4, _
))
95 .WillOnce(SaveArg
<0>(&Arg0
));
96 TestPrinter
->getAP()->emitDwarfSymbolReference(Val
, false);
98 const MCSymbolRefExpr
*ActualArg0
= dyn_cast_or_null
<MCSymbolRefExpr
>(Arg0
);
99 ASSERT_NE(ActualArg0
, nullptr);
100 EXPECT_EQ(&(ActualArg0
->getSymbol()), Val
);
103 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest
, ELFDWARF32ForceOffset
) {
104 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
107 EXPECT_CALL(TestPrinter
->getMS(),
108 emitAbsoluteSymbolDiff(Val
, SecBeginSymbol
, 4));
109 TestPrinter
->getAP()->emitDwarfSymbolReference(Val
, true);
112 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest
, ELFDWARF64
) {
113 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64
))
116 const MCExpr
*Arg0
= nullptr;
117 EXPECT_CALL(TestPrinter
->getMS(), emitValueImpl(_
, 8, _
))
118 .WillOnce(SaveArg
<0>(&Arg0
));
119 TestPrinter
->getAP()->emitDwarfSymbolReference(Val
, false);
121 const MCSymbolRefExpr
*ActualArg0
= dyn_cast_or_null
<MCSymbolRefExpr
>(Arg0
);
122 ASSERT_NE(ActualArg0
, nullptr);
123 EXPECT_EQ(&(ActualArg0
->getSymbol()), Val
);
126 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest
, ELFDWARF64ForceOffset
) {
127 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64
))
130 EXPECT_CALL(TestPrinter
->getMS(),
131 emitAbsoluteSymbolDiff(Val
, SecBeginSymbol
, 8));
132 TestPrinter
->getAP()->emitDwarfSymbolReference(Val
, true);
135 class AsmPrinterEmitDwarfStringOffsetTest
: public AsmPrinterFixtureBase
{
137 bool init(const std::string
&TripleStr
, unsigned DwarfVersion
,
138 dwarf::DwarfFormat DwarfFormat
) {
139 if (!AsmPrinterFixtureBase::init(TripleStr
, DwarfVersion
, DwarfFormat
))
142 Val
.Index
= DwarfStringPoolEntry::NotIndexed
;
143 Val
.Symbol
= TestPrinter
->getCtx().createTempSymbol();
148 DwarfStringPoolEntry Val
;
151 TEST_F(AsmPrinterEmitDwarfStringOffsetTest
, DWARF32
) {
152 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
155 const MCExpr
*Arg0
= nullptr;
156 EXPECT_CALL(TestPrinter
->getMS(), emitValueImpl(_
, 4, _
))
157 .WillOnce(SaveArg
<0>(&Arg0
));
158 TestPrinter
->getAP()->emitDwarfStringOffset(Val
);
160 const MCSymbolRefExpr
*ActualArg0
= dyn_cast_or_null
<MCSymbolRefExpr
>(Arg0
);
161 ASSERT_NE(ActualArg0
, nullptr);
162 EXPECT_EQ(&(ActualArg0
->getSymbol()), Val
.Symbol
);
165 TEST_F(AsmPrinterEmitDwarfStringOffsetTest
,
166 DWARF32NoRelocationsAcrossSections
) {
167 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
170 TestPrinter
->setDwarfUsesRelocationsAcrossSections(false);
171 EXPECT_CALL(TestPrinter
->getMS(), emitIntValue(Val
.Offset
, 4));
172 TestPrinter
->getAP()->emitDwarfStringOffset(Val
);
175 TEST_F(AsmPrinterEmitDwarfStringOffsetTest
, DWARF64
) {
176 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64
))
179 const MCExpr
*Arg0
= nullptr;
180 EXPECT_CALL(TestPrinter
->getMS(), emitValueImpl(_
, 8, _
))
181 .WillOnce(SaveArg
<0>(&Arg0
));
182 TestPrinter
->getAP()->emitDwarfStringOffset(Val
);
184 const MCSymbolRefExpr
*ActualArg0
= dyn_cast_or_null
<MCSymbolRefExpr
>(Arg0
);
185 ASSERT_NE(ActualArg0
, nullptr);
186 EXPECT_EQ(&(ActualArg0
->getSymbol()), Val
.Symbol
);
189 TEST_F(AsmPrinterEmitDwarfStringOffsetTest
,
190 DWARF64NoRelocationsAcrossSections
) {
191 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64
))
194 TestPrinter
->setDwarfUsesRelocationsAcrossSections(false);
195 EXPECT_CALL(TestPrinter
->getMS(), emitIntValue(Val
.Offset
, 8));
196 TestPrinter
->getAP()->emitDwarfStringOffset(Val
);
199 class AsmPrinterEmitDwarfOffsetTest
: public AsmPrinterFixtureBase
{
201 bool init(const std::string
&TripleStr
, unsigned DwarfVersion
,
202 dwarf::DwarfFormat DwarfFormat
) {
203 if (!AsmPrinterFixtureBase::init(TripleStr
, DwarfVersion
, DwarfFormat
))
206 Label
= TestPrinter
->getCtx().createTempSymbol();
210 MCSymbol
*Label
= nullptr;
211 uint64_t Offset
= 42;
214 TEST_F(AsmPrinterEmitDwarfOffsetTest
, DWARF32
) {
215 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
218 const MCExpr
*Arg0
= nullptr;
219 EXPECT_CALL(TestPrinter
->getMS(), emitValueImpl(_
, 4, _
))
220 .WillOnce(SaveArg
<0>(&Arg0
));
221 TestPrinter
->getAP()->emitDwarfOffset(Label
, Offset
);
223 const MCBinaryExpr
*ActualArg0
= dyn_cast_or_null
<MCBinaryExpr
>(Arg0
);
224 ASSERT_NE(ActualArg0
, nullptr);
225 EXPECT_EQ(ActualArg0
->getOpcode(), MCBinaryExpr::Add
);
227 const MCSymbolRefExpr
*ActualLHS
=
228 dyn_cast_or_null
<MCSymbolRefExpr
>(ActualArg0
->getLHS());
229 ASSERT_NE(ActualLHS
, nullptr);
230 EXPECT_EQ(&(ActualLHS
->getSymbol()), Label
);
232 const MCConstantExpr
*ActualRHS
=
233 dyn_cast_or_null
<MCConstantExpr
>(ActualArg0
->getRHS());
234 ASSERT_NE(ActualRHS
, nullptr);
235 EXPECT_EQ(static_cast<uint64_t>(ActualRHS
->getValue()), Offset
);
238 TEST_F(AsmPrinterEmitDwarfOffsetTest
, DWARF64
) {
239 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64
))
242 const MCExpr
*Arg0
= nullptr;
243 EXPECT_CALL(TestPrinter
->getMS(), emitValueImpl(_
, 8, _
))
244 .WillOnce(SaveArg
<0>(&Arg0
));
245 TestPrinter
->getAP()->emitDwarfOffset(Label
, Offset
);
247 const MCBinaryExpr
*ActualArg0
= dyn_cast_or_null
<MCBinaryExpr
>(Arg0
);
248 ASSERT_NE(ActualArg0
, nullptr);
249 EXPECT_EQ(ActualArg0
->getOpcode(), MCBinaryExpr::Add
);
251 const MCSymbolRefExpr
*ActualLHS
=
252 dyn_cast_or_null
<MCSymbolRefExpr
>(ActualArg0
->getLHS());
253 ASSERT_NE(ActualLHS
, nullptr);
254 EXPECT_EQ(&(ActualLHS
->getSymbol()), Label
);
256 const MCConstantExpr
*ActualRHS
=
257 dyn_cast_or_null
<MCConstantExpr
>(ActualArg0
->getRHS());
258 ASSERT_NE(ActualRHS
, nullptr);
259 EXPECT_EQ(static_cast<uint64_t>(ActualRHS
->getValue()), Offset
);
262 class AsmPrinterEmitDwarfLengthOrOffsetTest
: public AsmPrinterFixtureBase
{
267 TEST_F(AsmPrinterEmitDwarfLengthOrOffsetTest
, DWARF32
) {
268 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
271 EXPECT_CALL(TestPrinter
->getMS(), emitIntValue(Val
, 4));
272 TestPrinter
->getAP()->emitDwarfLengthOrOffset(Val
);
275 TEST_F(AsmPrinterEmitDwarfLengthOrOffsetTest
, DWARF64
) {
276 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64
))
279 EXPECT_CALL(TestPrinter
->getMS(), emitIntValue(Val
, 8));
280 TestPrinter
->getAP()->emitDwarfLengthOrOffset(Val
);
283 class AsmPrinterGetUnitLengthFieldByteSizeTest
: public AsmPrinterFixtureBase
{
286 TEST_F(AsmPrinterGetUnitLengthFieldByteSizeTest
, DWARF32
) {
287 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
290 EXPECT_EQ(TestPrinter
->getAP()->getUnitLengthFieldByteSize(), 4u);
293 TEST_F(AsmPrinterGetUnitLengthFieldByteSizeTest
, DWARF64
) {
294 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64
))
297 EXPECT_EQ(TestPrinter
->getAP()->getUnitLengthFieldByteSize(), 12u);
300 class AsmPrinterEmitDwarfUnitLengthAsIntTest
: public AsmPrinterFixtureBase
{
305 TEST_F(AsmPrinterEmitDwarfUnitLengthAsIntTest
, DWARF32
) {
306 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
309 EXPECT_CALL(TestPrinter
->getMS(), emitIntValue(Val
, 4));
310 TestPrinter
->getAP()->emitDwarfUnitLength(Val
, "");
313 TEST_F(AsmPrinterEmitDwarfUnitLengthAsIntTest
, DWARF64
) {
314 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64
))
318 EXPECT_CALL(TestPrinter
->getMS(), emitIntValue(dwarf::DW_LENGTH_DWARF64
, 4));
319 EXPECT_CALL(TestPrinter
->getMS(), emitIntValue(Val
, 8));
321 TestPrinter
->getAP()->emitDwarfUnitLength(Val
, "");
324 class AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest
325 : public AsmPrinterFixtureBase
{
327 bool init(const std::string
&TripleStr
, unsigned DwarfVersion
,
328 dwarf::DwarfFormat DwarfFormat
) {
329 if (!AsmPrinterFixtureBase::init(TripleStr
, DwarfVersion
, DwarfFormat
))
336 TEST_F(AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest
, DWARF32
) {
337 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
341 const MCSymbol
*Hi
= nullptr;
342 const MCSymbol
*Lo
= nullptr;
343 EXPECT_CALL(TestPrinter
->getMS(), emitAbsoluteSymbolDiff(_
, _
, 4))
344 .WillOnce(DoAll(SaveArg
<0>(&Hi
), SaveArg
<1>(&Lo
)));
345 MCSymbol
*LTmp
= nullptr;
346 EXPECT_CALL(TestPrinter
->getMS(), emitLabel(_
, _
))
347 .WillOnce(SaveArg
<0>(<mp
));
349 MCSymbol
*HTmp
= TestPrinter
->getAP()->emitDwarfUnitLength("", "");
350 EXPECT_NE(Lo
, nullptr);
352 EXPECT_NE(Hi
, nullptr);
356 TEST_F(AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest
, DWARF64
) {
357 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64
))
361 const MCSymbol
*Hi
= nullptr;
362 const MCSymbol
*Lo
= nullptr;
363 EXPECT_CALL(TestPrinter
->getMS(), emitIntValue(dwarf::DW_LENGTH_DWARF64
, 4));
364 EXPECT_CALL(TestPrinter
->getMS(), emitAbsoluteSymbolDiff(_
, _
, 8))
365 .WillOnce(DoAll(SaveArg
<0>(&Hi
), SaveArg
<1>(&Lo
)));
366 MCSymbol
*LTmp
= nullptr;
367 EXPECT_CALL(TestPrinter
->getMS(), emitLabel(_
, _
))
368 .WillOnce(SaveArg
<0>(<mp
));
370 MCSymbol
*HTmp
= TestPrinter
->getAP()->emitDwarfUnitLength("", "");
371 EXPECT_NE(Lo
, nullptr);
373 EXPECT_NE(Hi
, nullptr);
377 class AsmPrinterHandlerTest
: public AsmPrinterFixtureBase
{
378 class TestHandler
: public AsmPrinterHandler
{
379 AsmPrinterHandlerTest
&Test
;
382 TestHandler(AsmPrinterHandlerTest
&Test
) : Test(Test
) {}
383 virtual ~TestHandler() {}
384 virtual void setSymbolSize(const MCSymbol
*Sym
, uint64_t Size
) override
{}
385 virtual void beginModule(Module
*M
) override
{ Test
.BeginCount
++; }
386 virtual void endModule() override
{ Test
.EndCount
++; }
387 virtual void beginFunction(const MachineFunction
*MF
) override
{}
388 virtual void endFunction(const MachineFunction
*MF
) override
{}
389 virtual void beginInstruction(const MachineInstr
*MI
) override
{}
390 virtual void endInstruction() 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(AsmPrinter::HandlerInfo(
401 std::unique_ptr
<AsmPrinterHandler
>(new TestHandler(*this)),
402 "TestTimerName", "TestTimerDesc", "TestGroupName", "TestGroupDesc"));
403 LLVMTargetMachine
*LLVMTM
= static_cast<LLVMTargetMachine
*>(&AP
->TM
);
404 legacy::PassManager PM
;
405 PM
.add(new MachineModuleInfoWrapperPass(LLVMTM
));
406 PM
.add(TestPrinter
->releaseAP()); // Takes ownership of destroying AP
408 std::unique_ptr
<Module
> M(new Module("TestModule", Context
));
409 M
->setDataLayout(LLVMTM
->createDataLayout());
411 // Now check that we can run it twice.
412 AP
->addAsmPrinterHandler(AsmPrinter::HandlerInfo(
413 std::unique_ptr
<AsmPrinterHandler
>(new TestHandler(*this)),
414 "TestTimerName", "TestTimerDesc", "TestGroupName", "TestGroupDesc"));
423 TEST_F(AsmPrinterHandlerTest
, Basic
) {
424 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
427 ASSERT_EQ(BeginCount
, 3);
428 ASSERT_EQ(EndCount
, 3);