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"
24 using testing::InSequence
;
25 using testing::SaveArg
;
29 class AsmPrinterFixtureBase
: public testing::Test
{
30 void setupTestPrinter(const std::string
&TripleStr
, unsigned DwarfVersion
,
31 dwarf::DwarfFormat DwarfFormat
) {
32 auto ExpectedTestPrinter
=
33 TestAsmPrinter::create(TripleStr
, DwarfVersion
, DwarfFormat
);
34 ASSERT_THAT_EXPECTED(ExpectedTestPrinter
, Succeeded());
35 TestPrinter
= std::move(ExpectedTestPrinter
.get());
39 bool init(const std::string
&TripleStr
, unsigned DwarfVersion
,
40 dwarf::DwarfFormat DwarfFormat
) {
41 setupTestPrinter(TripleStr
, DwarfVersion
, DwarfFormat
);
42 return TestPrinter
!= nullptr;
45 std::unique_ptr
<TestAsmPrinter
> TestPrinter
;
48 class AsmPrinterEmitDwarfSymbolReferenceTest
: public AsmPrinterFixtureBase
{
50 bool init(const std::string
&TripleStr
, unsigned DwarfVersion
,
51 dwarf::DwarfFormat DwarfFormat
) {
52 if (!AsmPrinterFixtureBase::init(TripleStr
, DwarfVersion
, DwarfFormat
))
55 // AsmPrinter::emitDwarfSymbolReference(Label, true) gets the associated
56 // section from `Label` to find its BeginSymbol.
57 // Prepare the test symbol `Val` accordingly.
59 Val
= TestPrinter
->getCtx().createTempSymbol();
61 TestPrinter
->getCtx().getELFSection(".tst", ELF::SHT_PROGBITS
, 0);
62 SecBeginSymbol
= Sec
->getBeginSymbol();
63 TestPrinter
->getMS().switchSection(Sec
);
64 Val
->setFragment(&Sec
->getDummyFragment());
69 MCSymbol
*Val
= nullptr;
70 MCSymbol
*SecBeginSymbol
= nullptr;
73 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest
, COFF
) {
74 if (!init("x86_64-pc-windows", /*DwarfVersion=*/4, dwarf::DWARF32
))
77 EXPECT_CALL(TestPrinter
->getMS(), emitCOFFSecRel32(Val
, 0));
78 TestPrinter
->getAP()->emitDwarfSymbolReference(Val
, false);
81 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest
, COFFForceOffset
) {
82 if (!init("x86_64-pc-windows", /*DwarfVersion=*/4, dwarf::DWARF32
))
85 EXPECT_CALL(TestPrinter
->getMS(),
86 emitAbsoluteSymbolDiff(Val
, SecBeginSymbol
, 4));
87 TestPrinter
->getAP()->emitDwarfSymbolReference(Val
, true);
90 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest
, ELFDWARF32
) {
91 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
94 const MCExpr
*Arg0
= nullptr;
95 EXPECT_CALL(TestPrinter
->getMS(), emitValueImpl(_
, 4, _
))
96 .WillOnce(SaveArg
<0>(&Arg0
));
97 TestPrinter
->getAP()->emitDwarfSymbolReference(Val
, false);
99 const MCSymbolRefExpr
*ActualArg0
= dyn_cast_or_null
<MCSymbolRefExpr
>(Arg0
);
100 ASSERT_NE(ActualArg0
, nullptr);
101 EXPECT_EQ(&(ActualArg0
->getSymbol()), Val
);
104 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest
, ELFDWARF32ForceOffset
) {
105 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
108 EXPECT_CALL(TestPrinter
->getMS(),
109 emitAbsoluteSymbolDiff(Val
, SecBeginSymbol
, 4));
110 TestPrinter
->getAP()->emitDwarfSymbolReference(Val
, true);
113 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest
, ELFDWARF64
) {
114 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64
))
117 const MCExpr
*Arg0
= nullptr;
118 EXPECT_CALL(TestPrinter
->getMS(), emitValueImpl(_
, 8, _
))
119 .WillOnce(SaveArg
<0>(&Arg0
));
120 TestPrinter
->getAP()->emitDwarfSymbolReference(Val
, false);
122 const MCSymbolRefExpr
*ActualArg0
= dyn_cast_or_null
<MCSymbolRefExpr
>(Arg0
);
123 ASSERT_NE(ActualArg0
, nullptr);
124 EXPECT_EQ(&(ActualArg0
->getSymbol()), Val
);
127 TEST_F(AsmPrinterEmitDwarfSymbolReferenceTest
, ELFDWARF64ForceOffset
) {
128 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64
))
131 EXPECT_CALL(TestPrinter
->getMS(),
132 emitAbsoluteSymbolDiff(Val
, SecBeginSymbol
, 8));
133 TestPrinter
->getAP()->emitDwarfSymbolReference(Val
, true);
136 class AsmPrinterEmitDwarfStringOffsetTest
: public AsmPrinterFixtureBase
{
138 bool init(const std::string
&TripleStr
, unsigned DwarfVersion
,
139 dwarf::DwarfFormat DwarfFormat
) {
140 if (!AsmPrinterFixtureBase::init(TripleStr
, DwarfVersion
, DwarfFormat
))
143 Val
.Index
= DwarfStringPoolEntry::NotIndexed
;
144 Val
.Symbol
= TestPrinter
->getCtx().createTempSymbol();
149 DwarfStringPoolEntry Val
;
152 TEST_F(AsmPrinterEmitDwarfStringOffsetTest
, DWARF32
) {
153 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
156 const MCExpr
*Arg0
= nullptr;
157 EXPECT_CALL(TestPrinter
->getMS(), emitValueImpl(_
, 4, _
))
158 .WillOnce(SaveArg
<0>(&Arg0
));
159 TestPrinter
->getAP()->emitDwarfStringOffset(Val
);
161 const MCSymbolRefExpr
*ActualArg0
= dyn_cast_or_null
<MCSymbolRefExpr
>(Arg0
);
162 ASSERT_NE(ActualArg0
, nullptr);
163 EXPECT_EQ(&(ActualArg0
->getSymbol()), Val
.Symbol
);
166 TEST_F(AsmPrinterEmitDwarfStringOffsetTest
,
167 DWARF32NoRelocationsAcrossSections
) {
168 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
171 TestPrinter
->setDwarfUsesRelocationsAcrossSections(false);
172 EXPECT_CALL(TestPrinter
->getMS(), emitIntValue(Val
.Offset
, 4));
173 TestPrinter
->getAP()->emitDwarfStringOffset(Val
);
176 TEST_F(AsmPrinterEmitDwarfStringOffsetTest
, DWARF64
) {
177 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64
))
180 const MCExpr
*Arg0
= nullptr;
181 EXPECT_CALL(TestPrinter
->getMS(), emitValueImpl(_
, 8, _
))
182 .WillOnce(SaveArg
<0>(&Arg0
));
183 TestPrinter
->getAP()->emitDwarfStringOffset(Val
);
185 const MCSymbolRefExpr
*ActualArg0
= dyn_cast_or_null
<MCSymbolRefExpr
>(Arg0
);
186 ASSERT_NE(ActualArg0
, nullptr);
187 EXPECT_EQ(&(ActualArg0
->getSymbol()), Val
.Symbol
);
190 TEST_F(AsmPrinterEmitDwarfStringOffsetTest
,
191 DWARF64NoRelocationsAcrossSections
) {
192 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64
))
195 TestPrinter
->setDwarfUsesRelocationsAcrossSections(false);
196 EXPECT_CALL(TestPrinter
->getMS(), emitIntValue(Val
.Offset
, 8));
197 TestPrinter
->getAP()->emitDwarfStringOffset(Val
);
200 class AsmPrinterEmitDwarfOffsetTest
: public AsmPrinterFixtureBase
{
202 bool init(const std::string
&TripleStr
, unsigned DwarfVersion
,
203 dwarf::DwarfFormat DwarfFormat
) {
204 if (!AsmPrinterFixtureBase::init(TripleStr
, DwarfVersion
, DwarfFormat
))
207 Label
= TestPrinter
->getCtx().createTempSymbol();
211 MCSymbol
*Label
= nullptr;
212 uint64_t Offset
= 42;
215 TEST_F(AsmPrinterEmitDwarfOffsetTest
, DWARF32
) {
216 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
219 const MCExpr
*Arg0
= nullptr;
220 EXPECT_CALL(TestPrinter
->getMS(), emitValueImpl(_
, 4, _
))
221 .WillOnce(SaveArg
<0>(&Arg0
));
222 TestPrinter
->getAP()->emitDwarfOffset(Label
, Offset
);
224 const MCBinaryExpr
*ActualArg0
= dyn_cast_or_null
<MCBinaryExpr
>(Arg0
);
225 ASSERT_NE(ActualArg0
, nullptr);
226 EXPECT_EQ(ActualArg0
->getOpcode(), MCBinaryExpr::Add
);
228 const MCSymbolRefExpr
*ActualLHS
=
229 dyn_cast_or_null
<MCSymbolRefExpr
>(ActualArg0
->getLHS());
230 ASSERT_NE(ActualLHS
, nullptr);
231 EXPECT_EQ(&(ActualLHS
->getSymbol()), Label
);
233 const MCConstantExpr
*ActualRHS
=
234 dyn_cast_or_null
<MCConstantExpr
>(ActualArg0
->getRHS());
235 ASSERT_NE(ActualRHS
, nullptr);
236 EXPECT_EQ(static_cast<uint64_t>(ActualRHS
->getValue()), Offset
);
239 TEST_F(AsmPrinterEmitDwarfOffsetTest
, DWARF64
) {
240 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64
))
243 const MCExpr
*Arg0
= nullptr;
244 EXPECT_CALL(TestPrinter
->getMS(), emitValueImpl(_
, 8, _
))
245 .WillOnce(SaveArg
<0>(&Arg0
));
246 TestPrinter
->getAP()->emitDwarfOffset(Label
, Offset
);
248 const MCBinaryExpr
*ActualArg0
= dyn_cast_or_null
<MCBinaryExpr
>(Arg0
);
249 ASSERT_NE(ActualArg0
, nullptr);
250 EXPECT_EQ(ActualArg0
->getOpcode(), MCBinaryExpr::Add
);
252 const MCSymbolRefExpr
*ActualLHS
=
253 dyn_cast_or_null
<MCSymbolRefExpr
>(ActualArg0
->getLHS());
254 ASSERT_NE(ActualLHS
, nullptr);
255 EXPECT_EQ(&(ActualLHS
->getSymbol()), Label
);
257 const MCConstantExpr
*ActualRHS
=
258 dyn_cast_or_null
<MCConstantExpr
>(ActualArg0
->getRHS());
259 ASSERT_NE(ActualRHS
, nullptr);
260 EXPECT_EQ(static_cast<uint64_t>(ActualRHS
->getValue()), Offset
);
263 class AsmPrinterEmitDwarfLengthOrOffsetTest
: public AsmPrinterFixtureBase
{
268 TEST_F(AsmPrinterEmitDwarfLengthOrOffsetTest
, DWARF32
) {
269 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
272 EXPECT_CALL(TestPrinter
->getMS(), emitIntValue(Val
, 4));
273 TestPrinter
->getAP()->emitDwarfLengthOrOffset(Val
);
276 TEST_F(AsmPrinterEmitDwarfLengthOrOffsetTest
, DWARF64
) {
277 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64
))
280 EXPECT_CALL(TestPrinter
->getMS(), emitIntValue(Val
, 8));
281 TestPrinter
->getAP()->emitDwarfLengthOrOffset(Val
);
284 class AsmPrinterGetUnitLengthFieldByteSizeTest
: public AsmPrinterFixtureBase
{
287 TEST_F(AsmPrinterGetUnitLengthFieldByteSizeTest
, DWARF32
) {
288 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
291 EXPECT_EQ(TestPrinter
->getAP()->getUnitLengthFieldByteSize(), 4u);
294 TEST_F(AsmPrinterGetUnitLengthFieldByteSizeTest
, DWARF64
) {
295 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64
))
298 EXPECT_EQ(TestPrinter
->getAP()->getUnitLengthFieldByteSize(), 12u);
301 class AsmPrinterEmitDwarfUnitLengthAsIntTest
: public AsmPrinterFixtureBase
{
306 TEST_F(AsmPrinterEmitDwarfUnitLengthAsIntTest
, DWARF32
) {
307 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
310 EXPECT_CALL(TestPrinter
->getMS(), emitIntValue(Val
, 4));
311 TestPrinter
->getAP()->emitDwarfUnitLength(Val
, "");
314 TEST_F(AsmPrinterEmitDwarfUnitLengthAsIntTest
, DWARF64
) {
315 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64
))
319 EXPECT_CALL(TestPrinter
->getMS(), emitIntValue(dwarf::DW_LENGTH_DWARF64
, 4));
320 EXPECT_CALL(TestPrinter
->getMS(), emitIntValue(Val
, 8));
322 TestPrinter
->getAP()->emitDwarfUnitLength(Val
, "");
325 class AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest
326 : public AsmPrinterFixtureBase
{
328 bool init(const std::string
&TripleStr
, unsigned DwarfVersion
,
329 dwarf::DwarfFormat DwarfFormat
) {
330 if (!AsmPrinterFixtureBase::init(TripleStr
, DwarfVersion
, DwarfFormat
))
337 TEST_F(AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest
, DWARF32
) {
338 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
342 const MCSymbol
*Hi
= nullptr;
343 const MCSymbol
*Lo
= nullptr;
344 EXPECT_CALL(TestPrinter
->getMS(), emitAbsoluteSymbolDiff(_
, _
, 4))
345 .WillOnce(DoAll(SaveArg
<0>(&Hi
), SaveArg
<1>(&Lo
)));
346 MCSymbol
*LTmp
= nullptr;
347 EXPECT_CALL(TestPrinter
->getMS(), emitLabel(_
, _
))
348 .WillOnce(SaveArg
<0>(<mp
));
350 MCSymbol
*HTmp
= TestPrinter
->getAP()->emitDwarfUnitLength("", "");
351 EXPECT_NE(Lo
, nullptr);
353 EXPECT_NE(Hi
, nullptr);
357 TEST_F(AsmPrinterEmitDwarfUnitLengthAsHiLoDiffTest
, DWARF64
) {
358 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF64
))
362 const MCSymbol
*Hi
= nullptr;
363 const MCSymbol
*Lo
= nullptr;
364 EXPECT_CALL(TestPrinter
->getMS(), emitIntValue(dwarf::DW_LENGTH_DWARF64
, 4));
365 EXPECT_CALL(TestPrinter
->getMS(), emitAbsoluteSymbolDiff(_
, _
, 8))
366 .WillOnce(DoAll(SaveArg
<0>(&Hi
), SaveArg
<1>(&Lo
)));
367 MCSymbol
*LTmp
= nullptr;
368 EXPECT_CALL(TestPrinter
->getMS(), emitLabel(_
, _
))
369 .WillOnce(SaveArg
<0>(<mp
));
371 MCSymbol
*HTmp
= TestPrinter
->getAP()->emitDwarfUnitLength("", "");
372 EXPECT_NE(Lo
, nullptr);
374 EXPECT_NE(Hi
, nullptr);
378 class AsmPrinterHandlerTest
: public AsmPrinterFixtureBase
{
379 class TestHandler
: public AsmPrinterHandler
{
380 AsmPrinterHandlerTest
&Test
;
383 TestHandler(AsmPrinterHandlerTest
&Test
) : Test(Test
) {}
384 virtual ~TestHandler() {}
385 virtual void setSymbolSize(const MCSymbol
*Sym
, uint64_t Size
) override
{}
386 virtual void beginModule(Module
*M
) override
{ Test
.BeginCount
++; }
387 virtual void endModule() override
{ Test
.EndCount
++; }
388 virtual void beginFunction(const MachineFunction
*MF
) override
{}
389 virtual void endFunction(const MachineFunction
*MF
) override
{}
390 virtual void beginInstruction(const MachineInstr
*MI
) override
{}
391 virtual void endInstruction() override
{}
395 bool init(const std::string
&TripleStr
, unsigned DwarfVersion
,
396 dwarf::DwarfFormat DwarfFormat
) {
397 if (!AsmPrinterFixtureBase::init(TripleStr
, DwarfVersion
, DwarfFormat
))
400 auto *AP
= TestPrinter
->getAP();
401 AP
->addAsmPrinterHandler(AsmPrinter::HandlerInfo(
402 std::unique_ptr
<AsmPrinterHandler
>(new TestHandler(*this)),
403 "TestTimerName", "TestTimerDesc", "TestGroupName", "TestGroupDesc"));
404 LLVMTargetMachine
*LLVMTM
= static_cast<LLVMTargetMachine
*>(&AP
->TM
);
405 legacy::PassManager PM
;
406 PM
.add(new MachineModuleInfoWrapperPass(LLVMTM
));
407 PM
.add(TestPrinter
->releaseAP()); // Takes ownership of destroying AP
409 std::unique_ptr
<Module
> M(new Module("TestModule", Context
));
410 M
->setDataLayout(LLVMTM
->createDataLayout());
412 // Now check that we can run it twice.
413 AP
->addAsmPrinterHandler(AsmPrinter::HandlerInfo(
414 std::unique_ptr
<AsmPrinterHandler
>(new TestHandler(*this)),
415 "TestTimerName", "TestTimerDesc", "TestGroupName", "TestGroupDesc"));
424 TEST_F(AsmPrinterHandlerTest
, Basic
) {
425 if (!init("x86_64-pc-linux", /*DwarfVersion=*/4, dwarf::DWARF32
))
428 ASSERT_EQ(BeginCount
, 3);
429 ASSERT_EQ(EndCount
, 3);