1 | //===----------- llvm/unittest/CodeGen/LexicalScopesTest.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 "llvm/CodeGen/LexicalScopes.h" |
10 | #include "llvm/CodeGen/MachineBasicBlock.h" |
11 | #include "llvm/CodeGen/MachineFunction.h" |
12 | #include "llvm/CodeGen/MachineInstr.h" |
13 | #include "llvm/CodeGen/MachineMemOperand.h" |
14 | #include "llvm/CodeGen/MachineModuleInfo.h" |
15 | #include "llvm/CodeGen/TargetFrameLowering.h" |
16 | #include "llvm/CodeGen/TargetInstrInfo.h" |
17 | #include "llvm/CodeGen/TargetLowering.h" |
18 | #include "llvm/CodeGen/TargetSubtargetInfo.h" |
19 | #include "llvm/IR/DIBuilder.h" |
20 | #include "llvm/IR/DebugInfoMetadata.h" |
21 | #include "llvm/IR/IRBuilder.h" |
22 | #include "llvm/IR/ModuleSlotTracker.h" |
23 | #include "llvm/MC/MCAsmInfo.h" |
24 | #include "llvm/MC/MCSymbol.h" |
25 | #include "llvm/MC/TargetRegistry.h" |
26 | #include "llvm/Support/TargetSelect.h" |
27 | #include "llvm/Target/TargetMachine.h" |
28 | #include "llvm/Target/TargetOptions.h" |
29 | |
30 | #include "gtest/gtest.h" |
31 | |
32 | using namespace llvm; |
33 | |
34 | namespace { |
35 | // Include helper functions to ease the manipulation of MachineFunctions |
36 | #include "MFCommon.inc" |
37 | |
38 | class LexicalScopesTest : public testing::Test { |
39 | public: |
40 | // Boilerplate, |
41 | LLVMContext Ctx; |
42 | Module Mod; |
43 | std::unique_ptr<MachineFunction> MF; |
44 | DICompileUnit *OurCU; |
45 | DIFile *OurFile; |
46 | DISubprogram *OurFunc; |
47 | DILexicalBlock *OurBlock, *AnotherBlock; |
48 | DISubprogram *ToInlineFunc; |
49 | DILexicalBlock *ToInlineBlock; |
50 | // DebugLocs that we'll used to create test environments. |
51 | DebugLoc OutermostLoc, InBlockLoc, NotNestedBlockLoc, InlinedLoc; |
52 | |
53 | // Test environment blocks -- these form a diamond control flow pattern, |
54 | // MBB1 being the entry block, blocks two and three being the branches, and |
55 | // block four joining the branches and being an exit block. |
56 | MachineBasicBlock *MBB1, *MBB2, *MBB3, *MBB4; |
57 | |
58 | // Some meaningless instructions -- the first is fully meaningless, |
59 | // while the second is supposed to impersonate DBG_VALUEs through its |
60 | // opcode. |
61 | MCInstrDesc BeanInst{}; |
62 | MCInstrDesc DbgValueInst{}; |
63 | |
64 | LexicalScopesTest() : Ctx(), Mod("beehives" , Ctx) { |
65 | memset(s: &BeanInst, c: 0, n: sizeof(BeanInst)); |
66 | BeanInst.Opcode = 1; |
67 | BeanInst.Size = 1; |
68 | |
69 | memset(s: &DbgValueInst, c: 0, n: sizeof(DbgValueInst)); |
70 | DbgValueInst.Opcode = TargetOpcode::DBG_VALUE; |
71 | DbgValueInst.Size = 1; |
72 | DbgValueInst.Flags = 1U << MCID::Meta; |
73 | |
74 | // Boilerplate that creates a MachineFunction and associated blocks. |
75 | MF = createMachineFunction(Ctx, M&: Mod); |
76 | llvm::Function &F = const_cast<llvm::Function &>(MF->getFunction()); |
77 | auto BB1 = BasicBlock::Create(Context&: Ctx, Name: "a" , Parent: &F); |
78 | auto BB2 = BasicBlock::Create(Context&: Ctx, Name: "b" , Parent: &F); |
79 | auto BB3 = BasicBlock::Create(Context&: Ctx, Name: "c" , Parent: &F); |
80 | auto BB4 = BasicBlock::Create(Context&: Ctx, Name: "d" , Parent: &F); |
81 | IRBuilder<> IRB1(BB1), IRB2(BB2), IRB3(BB3), IRB4(BB4); |
82 | IRB1.CreateBr(Dest: BB2); |
83 | IRB2.CreateBr(Dest: BB3); |
84 | IRB3.CreateBr(Dest: BB4); |
85 | IRB4.CreateRetVoid(); |
86 | MBB1 = MF->CreateMachineBasicBlock(BB: BB1); |
87 | MF->insert(MBBI: MF->end(), MBB: MBB1); |
88 | MBB2 = MF->CreateMachineBasicBlock(BB: BB2); |
89 | MF->insert(MBBI: MF->end(), MBB: MBB2); |
90 | MBB3 = MF->CreateMachineBasicBlock(BB: BB3); |
91 | MF->insert(MBBI: MF->end(), MBB: MBB3); |
92 | MBB4 = MF->CreateMachineBasicBlock(BB: BB4); |
93 | MF->insert(MBBI: MF->end(), MBB: MBB4); |
94 | MBB1->addSuccessor(Succ: MBB2); |
95 | MBB1->addSuccessor(Succ: MBB3); |
96 | MBB2->addSuccessor(Succ: MBB4); |
97 | MBB3->addSuccessor(Succ: MBB4); |
98 | |
99 | // Create metadata: CU, subprogram, some blocks and an inline function |
100 | // scope. |
101 | DIBuilder DIB(Mod); |
102 | OurFile = DIB.createFile(Filename: "xyzzy.c" , Directory: "/cave" ); |
103 | OurCU = |
104 | DIB.createCompileUnit(Lang: dwarf::DW_LANG_C99, File: OurFile, Producer: "nou" , isOptimized: false, Flags: "" , RV: 0); |
105 | auto OurSubT = |
106 | DIB.createSubroutineType(ParameterTypes: DIB.getOrCreateTypeArray(Elements: std::nullopt)); |
107 | OurFunc = |
108 | DIB.createFunction(Scope: OurCU, Name: "bees" , LinkageName: "" , File: OurFile, LineNo: 1, Ty: OurSubT, ScopeLine: 1, |
109 | Flags: DINode::FlagZero, SPFlags: DISubprogram::SPFlagDefinition); |
110 | F.setSubprogram(OurFunc); |
111 | OurBlock = DIB.createLexicalBlock(Scope: OurFunc, File: OurFile, Line: 2, Col: 3); |
112 | AnotherBlock = DIB.createLexicalBlock(Scope: OurFunc, File: OurFile, Line: 2, Col: 6); |
113 | ToInlineFunc = |
114 | DIB.createFunction(Scope: OurFile, Name: "shoes" , LinkageName: "" , File: OurFile, LineNo: 10, Ty: OurSubT, ScopeLine: 10, |
115 | Flags: DINode::FlagZero, SPFlags: DISubprogram::SPFlagDefinition); |
116 | |
117 | // Make some nested scopes. |
118 | OutermostLoc = DILocation::get(Context&: Ctx, Line: 3, Column: 1, Scope: OurFunc); |
119 | InBlockLoc = DILocation::get(Context&: Ctx, Line: 4, Column: 1, Scope: OurBlock); |
120 | InlinedLoc = DILocation::get(Context&: Ctx, Line: 10, Column: 1, Scope: ToInlineFunc, InlinedAt: InBlockLoc.get()); |
121 | |
122 | // Make a scope that isn't nested within the others. |
123 | NotNestedBlockLoc = DILocation::get(Context&: Ctx, Line: 4, Column: 1, Scope: AnotherBlock); |
124 | |
125 | DIB.finalize(); |
126 | } |
127 | }; |
128 | |
129 | // Fill blocks with dummy instructions, test some base lexical scope |
130 | // functionaliy. |
131 | TEST_F(LexicalScopesTest, FlatLayout) { |
132 | BuildMI(BB&: *MBB1, I: MBB1->end(), MIMD: OutermostLoc, MCID: BeanInst); |
133 | BuildMI(BB&: *MBB2, I: MBB2->end(), MIMD: OutermostLoc, MCID: BeanInst); |
134 | BuildMI(BB&: *MBB3, I: MBB3->end(), MIMD: OutermostLoc, MCID: BeanInst); |
135 | BuildMI(BB&: *MBB4, I: MBB4->end(), MIMD: OutermostLoc, MCID: BeanInst); |
136 | |
137 | LexicalScopes LS; |
138 | EXPECT_TRUE(LS.empty()); |
139 | LS.reset(); |
140 | EXPECT_EQ(LS.getCurrentFunctionScope(), nullptr); |
141 | |
142 | LS.initialize(*MF); |
143 | EXPECT_FALSE(LS.empty()); |
144 | LexicalScope *FuncScope = LS.getCurrentFunctionScope(); |
145 | EXPECT_EQ(FuncScope->getParent(), nullptr); |
146 | EXPECT_EQ(FuncScope->getDesc(), OurFunc); |
147 | EXPECT_EQ(FuncScope->getInlinedAt(), nullptr); |
148 | EXPECT_EQ(FuncScope->getScopeNode(), OurFunc); |
149 | EXPECT_FALSE(FuncScope->isAbstractScope()); |
150 | EXPECT_EQ(FuncScope->getChildren().size(), 0u); |
151 | |
152 | // There should be one range, covering the whole function. Test that it |
153 | // points at the correct instructions. |
154 | auto &Ranges = FuncScope->getRanges(); |
155 | ASSERT_EQ(Ranges.size(), 1u); |
156 | EXPECT_EQ(Ranges.front().first, &*MF->begin()->begin()); |
157 | auto BBIt = MF->end(); |
158 | BBIt = std::prev(x: BBIt); |
159 | EXPECT_EQ(Ranges.front().second, &*BBIt->begin()); |
160 | |
161 | EXPECT_TRUE(FuncScope->dominates(FuncScope)); |
162 | SmallPtrSet<const MachineBasicBlock *, 4> MBBVec; |
163 | LS.getMachineBasicBlocks(DL: OutermostLoc.get(), MBBs&: MBBVec); |
164 | |
165 | EXPECT_EQ(MBBVec.size(), 4u); |
166 | // All the blocks should be in that set; the outermost loc should dominate |
167 | // them; and no other scope should. |
168 | for (auto &MBB : *MF) { |
169 | EXPECT_EQ(MBBVec.count(&MBB), 1u); |
170 | EXPECT_TRUE(LS.dominates(OutermostLoc.get(), &MBB)); |
171 | EXPECT_FALSE(LS.dominates(InBlockLoc.get(), &MBB)); |
172 | EXPECT_FALSE(LS.dominates(InlinedLoc.get(), &MBB)); |
173 | } |
174 | } |
175 | |
176 | // Examine relationship between two nested scopes inside the function, the |
177 | // outer function and the lexical block within it. |
178 | TEST_F(LexicalScopesTest, BlockScopes) { |
179 | BuildMI(BB&: *MBB1, I: MBB1->end(), MIMD: InBlockLoc, MCID: BeanInst); |
180 | BuildMI(BB&: *MBB2, I: MBB2->end(), MIMD: InBlockLoc, MCID: BeanInst); |
181 | BuildMI(BB&: *MBB3, I: MBB3->end(), MIMD: InBlockLoc, MCID: BeanInst); |
182 | BuildMI(BB&: *MBB4, I: MBB4->end(), MIMD: InBlockLoc, MCID: BeanInst); |
183 | |
184 | LexicalScopes LS; |
185 | LS.initialize(*MF); |
186 | LexicalScope *FuncScope = LS.getCurrentFunctionScope(); |
187 | EXPECT_EQ(FuncScope->getDesc(), OurFunc); |
188 | auto &Children = FuncScope->getChildren(); |
189 | ASSERT_EQ(Children.size(), 1u); |
190 | auto *BlockScope = Children[0]; |
191 | EXPECT_EQ(LS.findLexicalScope(InBlockLoc.get()), BlockScope); |
192 | EXPECT_EQ(BlockScope->getDesc(), InBlockLoc->getScope()); |
193 | EXPECT_FALSE(BlockScope->isAbstractScope()); |
194 | |
195 | EXPECT_TRUE(FuncScope->dominates(BlockScope)); |
196 | EXPECT_FALSE(BlockScope->dominates(FuncScope)); |
197 | EXPECT_EQ(FuncScope->getParent(), nullptr); |
198 | EXPECT_EQ(BlockScope->getParent(), FuncScope); |
199 | |
200 | SmallPtrSet<const MachineBasicBlock *, 4> MBBVec; |
201 | LS.getMachineBasicBlocks(DL: OutermostLoc.get(), MBBs&: MBBVec); |
202 | |
203 | EXPECT_EQ(MBBVec.size(), 4u); |
204 | for (auto &MBB : *MF) { |
205 | EXPECT_EQ(MBBVec.count(&MBB), 1u); |
206 | EXPECT_TRUE(LS.dominates(OutermostLoc.get(), &MBB)); |
207 | EXPECT_TRUE(LS.dominates(InBlockLoc.get(), &MBB)); |
208 | EXPECT_FALSE(LS.dominates(InlinedLoc.get(), &MBB)); |
209 | } |
210 | } |
211 | |
212 | // Test inlined scopes functionality and relationship with the outer scopes. |
213 | TEST_F(LexicalScopesTest, InlinedScopes) { |
214 | BuildMI(BB&: *MBB1, I: MBB1->end(), MIMD: InlinedLoc, MCID: BeanInst); |
215 | BuildMI(BB&: *MBB2, I: MBB2->end(), MIMD: InlinedLoc, MCID: BeanInst); |
216 | BuildMI(BB&: *MBB3, I: MBB3->end(), MIMD: InlinedLoc, MCID: BeanInst); |
217 | BuildMI(BB&: *MBB4, I: MBB4->end(), MIMD: InlinedLoc, MCID: BeanInst); |
218 | |
219 | LexicalScopes LS; |
220 | LS.initialize(*MF); |
221 | LexicalScope *FuncScope = LS.getCurrentFunctionScope(); |
222 | auto &Children = FuncScope->getChildren(); |
223 | ASSERT_EQ(Children.size(), 1u); |
224 | auto *BlockScope = Children[0]; |
225 | auto &BlockChildren = BlockScope->getChildren(); |
226 | ASSERT_EQ(BlockChildren.size(), 1u); |
227 | auto *InlinedScope = BlockChildren[0]; |
228 | |
229 | EXPECT_FALSE(InlinedScope->isAbstractScope()); |
230 | EXPECT_EQ(InlinedScope->getInlinedAt(), InlinedLoc.getInlinedAt()); |
231 | EXPECT_EQ(InlinedScope->getDesc(), InlinedLoc.getScope()); |
232 | EXPECT_EQ(InlinedScope->getChildren().size(), 0u); |
233 | |
234 | EXPECT_EQ(FuncScope->getParent(), nullptr); |
235 | EXPECT_EQ(BlockScope->getParent(), FuncScope); |
236 | EXPECT_EQ(InlinedScope->getParent(), BlockScope); |
237 | |
238 | const auto &AbstractScopes = LS.getAbstractScopesList(); |
239 | ASSERT_EQ(AbstractScopes.size(), 1u); |
240 | const auto &AbstractScope = *AbstractScopes[0]; |
241 | EXPECT_TRUE(AbstractScope.isAbstractScope()); |
242 | EXPECT_EQ(AbstractScope.getDesc(), InlinedLoc.getScope()); |
243 | EXPECT_EQ(AbstractScope.getInlinedAt(), nullptr); |
244 | EXPECT_EQ(AbstractScope.getParent(), nullptr); |
245 | } |
246 | |
247 | // Test behaviour in a function that has empty DebugLocs. |
248 | TEST_F(LexicalScopesTest, FuncWithEmptyGap) { |
249 | BuildMI(BB&: *MBB1, I: MBB1->end(), MIMD: OutermostLoc, MCID: BeanInst); |
250 | BuildMI(BB&: *MBB2, I: MBB2->end(), MIMD: DebugLoc(), MCID: BeanInst); |
251 | BuildMI(BB&: *MBB3, I: MBB3->end(), MIMD: DebugLoc(), MCID: BeanInst); |
252 | BuildMI(BB&: *MBB4, I: MBB4->end(), MIMD: OutermostLoc, MCID: BeanInst); |
253 | |
254 | LexicalScopes LS; |
255 | LS.initialize(*MF); |
256 | LexicalScope *FuncScope = LS.getCurrentFunctionScope(); |
257 | |
258 | // A gap in a range that contains no other location, is not actually a |
259 | // gap as far as lexical scopes are concerned. |
260 | auto &Ranges = FuncScope->getRanges(); |
261 | ASSERT_EQ(Ranges.size(), 1u); |
262 | EXPECT_EQ(Ranges[0].first, &*MF->begin()->begin()); |
263 | auto BBIt = MF->end(); |
264 | BBIt = std::prev(x: BBIt); |
265 | EXPECT_EQ(Ranges[0].second, &*BBIt->begin()); |
266 | } |
267 | |
268 | // Now a function with intervening not-in-scope instructions. |
269 | TEST_F(LexicalScopesTest, FuncWithRealGap) { |
270 | MachineInstr *FirstI = BuildMI(BB&: *MBB1, I: MBB1->end(), MIMD: InBlockLoc, MCID: BeanInst); |
271 | BuildMI(BB&: *MBB2, I: MBB2->end(), MIMD: OutermostLoc, MCID: BeanInst); |
272 | BuildMI(BB&: *MBB3, I: MBB3->end(), MIMD: OutermostLoc, MCID: BeanInst); |
273 | MachineInstr *LastI = BuildMI(BB&: *MBB4, I: MBB4->end(), MIMD: InBlockLoc, MCID: BeanInst); |
274 | |
275 | LexicalScopes LS; |
276 | LS.initialize(*MF); |
277 | LexicalScope *BlockScope = LS.findLexicalScope(DL: InBlockLoc.get()); |
278 | ASSERT_NE(BlockScope, nullptr); |
279 | |
280 | // Within the block scope, there's a gap between the first and last |
281 | // block / instruction, where it's only the outermost scope. |
282 | auto &Ranges = BlockScope->getRanges(); |
283 | ASSERT_EQ(Ranges.size(), 2u); |
284 | EXPECT_EQ(Ranges[0].first, FirstI); |
285 | EXPECT_EQ(Ranges[0].second, FirstI); |
286 | EXPECT_EQ(Ranges[1].first, LastI); |
287 | EXPECT_EQ(Ranges[1].second, LastI); |
288 | |
289 | // The outer function scope should cover the whole function, including |
290 | // blocks the lexicalblock covers. |
291 | LexicalScope *FuncScope = LS.getCurrentFunctionScope(); |
292 | auto &FuncRanges = FuncScope->getRanges(); |
293 | ASSERT_EQ(FuncRanges.size(), 1u); |
294 | EXPECT_NE(FuncRanges[0].first, FuncRanges[0].second); |
295 | EXPECT_EQ(FuncRanges[0].first, FirstI); |
296 | EXPECT_EQ(FuncRanges[0].second, LastI); |
297 | } |
298 | |
299 | // Examine the relationship between two scopes that don't nest (are siblings). |
300 | TEST_F(LexicalScopesTest, NotNested) { |
301 | MachineInstr *FirstI = BuildMI(BB&: *MBB1, I: MBB1->end(), MIMD: InBlockLoc, MCID: BeanInst); |
302 | MachineInstr *SecondI = |
303 | BuildMI(BB&: *MBB2, I: MBB2->end(), MIMD: NotNestedBlockLoc, MCID: BeanInst); |
304 | MachineInstr *ThirdI = |
305 | BuildMI(BB&: *MBB3, I: MBB3->end(), MIMD: NotNestedBlockLoc, MCID: BeanInst); |
306 | MachineInstr *FourthI = BuildMI(BB&: *MBB4, I: MBB4->end(), MIMD: InBlockLoc, MCID: BeanInst); |
307 | |
308 | LexicalScopes LS; |
309 | LS.initialize(*MF); |
310 | LexicalScope *FuncScope = LS.getCurrentFunctionScope(); |
311 | LexicalScope *BlockScope = LS.findLexicalScope(DL: InBlockLoc.get()); |
312 | LexicalScope *OtherBlockScope = LS.findLexicalScope(DL: NotNestedBlockLoc.get()); |
313 | ASSERT_NE(FuncScope, nullptr); |
314 | ASSERT_NE(BlockScope, nullptr); |
315 | ASSERT_NE(OtherBlockScope, nullptr); |
316 | |
317 | // The function should cover everything; the two blocks are distinct and |
318 | // should not. |
319 | auto &FuncRanges = FuncScope->getRanges(); |
320 | ASSERT_EQ(FuncRanges.size(), 1u); |
321 | EXPECT_EQ(FuncRanges[0].first, FirstI); |
322 | EXPECT_EQ(FuncRanges[0].second, FourthI); |
323 | |
324 | // Two ranges, start and end instructions. |
325 | auto &BlockRanges = BlockScope->getRanges(); |
326 | ASSERT_EQ(BlockRanges.size(), 2u); |
327 | EXPECT_EQ(BlockRanges[0].first, FirstI); |
328 | EXPECT_EQ(BlockRanges[0].second, FirstI); |
329 | EXPECT_EQ(BlockRanges[1].first, FourthI); |
330 | EXPECT_EQ(BlockRanges[1].second, FourthI); |
331 | |
332 | // One inner range, covering the two inner blocks. |
333 | auto &OtherBlockRanges = OtherBlockScope->getRanges(); |
334 | ASSERT_EQ(OtherBlockRanges.size(), 1u); |
335 | EXPECT_EQ(OtherBlockRanges[0].first, SecondI); |
336 | EXPECT_EQ(OtherBlockRanges[0].second, ThirdI); |
337 | } |
338 | |
339 | // Test the scope-specific and block-specific dominates methods. |
340 | TEST_F(LexicalScopesTest, TestDominates) { |
341 | BuildMI(BB&: *MBB1, I: MBB1->end(), MIMD: InBlockLoc, MCID: BeanInst); |
342 | BuildMI(BB&: *MBB2, I: MBB2->end(), MIMD: NotNestedBlockLoc, MCID: BeanInst); |
343 | BuildMI(BB&: *MBB3, I: MBB3->end(), MIMD: NotNestedBlockLoc, MCID: BeanInst); |
344 | BuildMI(BB&: *MBB4, I: MBB4->end(), MIMD: InBlockLoc, MCID: BeanInst); |
345 | |
346 | LexicalScopes LS; |
347 | LS.initialize(*MF); |
348 | LexicalScope *FuncScope = LS.getCurrentFunctionScope(); |
349 | LexicalScope *BlockScope = LS.findLexicalScope(DL: InBlockLoc.get()); |
350 | LexicalScope *OtherBlockScope = LS.findLexicalScope(DL: NotNestedBlockLoc.get()); |
351 | ASSERT_NE(FuncScope, nullptr); |
352 | ASSERT_NE(BlockScope, nullptr); |
353 | ASSERT_NE(OtherBlockScope, nullptr); |
354 | |
355 | EXPECT_TRUE(FuncScope->dominates(BlockScope)); |
356 | EXPECT_TRUE(FuncScope->dominates(OtherBlockScope)); |
357 | EXPECT_FALSE(BlockScope->dominates(FuncScope)); |
358 | EXPECT_FALSE(BlockScope->dominates(OtherBlockScope)); |
359 | EXPECT_FALSE(OtherBlockScope->dominates(FuncScope)); |
360 | EXPECT_FALSE(OtherBlockScope->dominates(BlockScope)); |
361 | |
362 | // Outermost scope dominates everything, as all insts are within it. |
363 | EXPECT_TRUE(LS.dominates(OutermostLoc.get(), MBB1)); |
364 | EXPECT_TRUE(LS.dominates(OutermostLoc.get(), MBB2)); |
365 | EXPECT_TRUE(LS.dominates(OutermostLoc.get(), MBB3)); |
366 | EXPECT_TRUE(LS.dominates(OutermostLoc.get(), MBB4)); |
367 | |
368 | // One inner block dominates the outer pair of blocks, |
369 | EXPECT_TRUE(LS.dominates(InBlockLoc.get(), MBB1)); |
370 | EXPECT_FALSE(LS.dominates(InBlockLoc.get(), MBB2)); |
371 | EXPECT_FALSE(LS.dominates(InBlockLoc.get(), MBB3)); |
372 | EXPECT_TRUE(LS.dominates(InBlockLoc.get(), MBB4)); |
373 | |
374 | // While the other dominates the inner two blocks. |
375 | EXPECT_FALSE(LS.dominates(NotNestedBlockLoc.get(), MBB1)); |
376 | EXPECT_TRUE(LS.dominates(NotNestedBlockLoc.get(), MBB2)); |
377 | EXPECT_TRUE(LS.dominates(NotNestedBlockLoc.get(), MBB3)); |
378 | EXPECT_FALSE(LS.dominates(NotNestedBlockLoc.get(), MBB4)); |
379 | } |
380 | |
381 | // Test getMachineBasicBlocks returns all dominated blocks. |
382 | TEST_F(LexicalScopesTest, TestGetBlocks) { |
383 | BuildMI(BB&: *MBB1, I: MBB1->end(), MIMD: InBlockLoc, MCID: BeanInst); |
384 | BuildMI(BB&: *MBB2, I: MBB2->end(), MIMD: NotNestedBlockLoc, MCID: BeanInst); |
385 | BuildMI(BB&: *MBB3, I: MBB3->end(), MIMD: NotNestedBlockLoc, MCID: BeanInst); |
386 | BuildMI(BB&: *MBB4, I: MBB4->end(), MIMD: InBlockLoc, MCID: BeanInst); |
387 | |
388 | LexicalScopes LS; |
389 | LS.initialize(*MF); |
390 | LexicalScope *FuncScope = LS.getCurrentFunctionScope(); |
391 | LexicalScope *BlockScope = LS.findLexicalScope(DL: InBlockLoc.get()); |
392 | LexicalScope *OtherBlockScope = LS.findLexicalScope(DL: NotNestedBlockLoc.get()); |
393 | ASSERT_NE(FuncScope, nullptr); |
394 | ASSERT_NE(BlockScope, nullptr); |
395 | ASSERT_NE(OtherBlockScope, nullptr); |
396 | |
397 | SmallPtrSet<const MachineBasicBlock *, 4> OutermostBlocks, InBlockBlocks, |
398 | NotNestedBlockBlocks; |
399 | LS.getMachineBasicBlocks(DL: OutermostLoc.get(), MBBs&: OutermostBlocks); |
400 | LS.getMachineBasicBlocks(DL: InBlockLoc.get(), MBBs&: InBlockBlocks); |
401 | LS.getMachineBasicBlocks(DL: NotNestedBlockLoc.get(), MBBs&: NotNestedBlockBlocks); |
402 | |
403 | EXPECT_EQ(OutermostBlocks.count(MBB1), 1u); |
404 | EXPECT_EQ(OutermostBlocks.count(MBB2), 1u); |
405 | EXPECT_EQ(OutermostBlocks.count(MBB3), 1u); |
406 | EXPECT_EQ(OutermostBlocks.count(MBB4), 1u); |
407 | |
408 | EXPECT_EQ(InBlockBlocks.count(MBB1), 1u); |
409 | EXPECT_EQ(InBlockBlocks.count(MBB2), 0u); |
410 | EXPECT_EQ(InBlockBlocks.count(MBB3), 0u); |
411 | EXPECT_EQ(InBlockBlocks.count(MBB4), 1u); |
412 | |
413 | EXPECT_EQ(NotNestedBlockBlocks.count(MBB1), 0u); |
414 | EXPECT_EQ(NotNestedBlockBlocks.count(MBB2), 1u); |
415 | EXPECT_EQ(NotNestedBlockBlocks.count(MBB3), 1u); |
416 | EXPECT_EQ(NotNestedBlockBlocks.count(MBB4), 0u); |
417 | } |
418 | |
419 | TEST_F(LexicalScopesTest, TestMetaInst) { |
420 | // Instruction Layout looks like this, where 'F' means funcscope, and |
421 | // 'B' blockscope: |
422 | // bb1: |
423 | // F: bean |
424 | // B: bean |
425 | // bb2: |
426 | // F: bean |
427 | // B: DBG_VALUE |
428 | // bb3: |
429 | // F: bean |
430 | // B: DBG_VALUE |
431 | // bb4: |
432 | // F: bean |
433 | // B: bean |
434 | // The block / 'B' should only dominate bb1 and bb4. DBG_VALUE is a meta |
435 | // instruction, and shouldn't contribute to scopes. |
436 | BuildMI(BB&: *MBB1, I: MBB1->end(), MIMD: OutermostLoc, MCID: BeanInst); |
437 | BuildMI(BB&: *MBB1, I: MBB1->end(), MIMD: InBlockLoc, MCID: BeanInst); |
438 | BuildMI(BB&: *MBB2, I: MBB2->end(), MIMD: OutermostLoc, MCID: BeanInst); |
439 | BuildMI(BB&: *MBB2, I: MBB2->end(), MIMD: InBlockLoc, MCID: DbgValueInst); |
440 | BuildMI(BB&: *MBB3, I: MBB3->end(), MIMD: OutermostLoc, MCID: BeanInst); |
441 | BuildMI(BB&: *MBB3, I: MBB3->end(), MIMD: InBlockLoc, MCID: DbgValueInst); |
442 | BuildMI(BB&: *MBB4, I: MBB4->end(), MIMD: OutermostLoc, MCID: BeanInst); |
443 | BuildMI(BB&: *MBB4, I: MBB4->end(), MIMD: InBlockLoc, MCID: BeanInst); |
444 | |
445 | LexicalScopes LS; |
446 | LS.initialize(*MF); |
447 | LexicalScope *FuncScope = LS.getCurrentFunctionScope(); |
448 | LexicalScope *BlockScope = LS.findLexicalScope(DL: InBlockLoc.get()); |
449 | ASSERT_NE(FuncScope, nullptr); |
450 | ASSERT_NE(BlockScope, nullptr); |
451 | |
452 | EXPECT_TRUE(LS.dominates(OutermostLoc.get(), MBB1)); |
453 | EXPECT_TRUE(LS.dominates(OutermostLoc.get(), MBB2)); |
454 | EXPECT_TRUE(LS.dominates(OutermostLoc.get(), MBB3)); |
455 | EXPECT_TRUE(LS.dominates(OutermostLoc.get(), MBB4)); |
456 | EXPECT_TRUE(LS.dominates(InBlockLoc.get(), MBB1)); |
457 | EXPECT_FALSE(LS.dominates(InBlockLoc.get(), MBB2)); |
458 | EXPECT_FALSE(LS.dominates(InBlockLoc.get(), MBB3)); |
459 | EXPECT_TRUE(LS.dominates(InBlockLoc.get(), MBB4)); |
460 | } |
461 | |
462 | } // anonymous namespace |
463 | |