1 | //===- FunctionTest.cpp - Function unit tests -----------------------------===// |
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/IR/Function.h" |
10 | #include "llvm/AsmParser/Parser.h" |
11 | #include "llvm/IR/Module.h" |
12 | #include "llvm/Support/SourceMgr.h" |
13 | #include "gtest/gtest.h" |
14 | using namespace llvm; |
15 | |
16 | namespace { |
17 | |
18 | static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) { |
19 | SMDiagnostic Err; |
20 | std::unique_ptr<Module> Mod = parseAssemblyString(AsmString: IR, Err, Context&: C); |
21 | if (!Mod) |
22 | Err.print(ProgName: "InstructionsTests" , S&: errs()); |
23 | return Mod; |
24 | } |
25 | |
26 | static BasicBlock *getBBWithName(Function *F, StringRef Name) { |
27 | auto It = find_if( |
28 | Range&: *F, P: [&Name](const BasicBlock &BB) { return BB.getName() == Name; }); |
29 | assert(It != F->end() && "Not found!" ); |
30 | return &*It; |
31 | } |
32 | |
33 | TEST(FunctionTest, hasLazyArguments) { |
34 | LLVMContext C; |
35 | |
36 | Type *ArgTypes[] = {Type::getInt8Ty(C), Type::getInt32Ty(C)}; |
37 | FunctionType *FTy = FunctionType::get(Result: Type::getVoidTy(C), Params: ArgTypes, isVarArg: false); |
38 | |
39 | // Functions start out with lazy arguments. |
40 | std::unique_ptr<Function> F( |
41 | Function::Create(Ty: FTy, Linkage: GlobalValue::ExternalLinkage, N: "F" )); |
42 | EXPECT_TRUE(F->hasLazyArguments()); |
43 | |
44 | // Checking for empty or size shouldn't force arguments to be instantiated. |
45 | EXPECT_FALSE(F->arg_empty()); |
46 | EXPECT_TRUE(F->hasLazyArguments()); |
47 | EXPECT_EQ(2u, F->arg_size()); |
48 | EXPECT_TRUE(F->hasLazyArguments()); |
49 | |
50 | // The argument list should be populated at first access. |
51 | (void)F->arg_begin(); |
52 | EXPECT_FALSE(F->hasLazyArguments()); |
53 | |
54 | // Checking that getArg gets the arguments from F1 in the correct order. |
55 | unsigned i = 0; |
56 | for (Argument &A : F->args()) { |
57 | EXPECT_EQ(&A, F->getArg(i)); |
58 | ++i; |
59 | } |
60 | EXPECT_FALSE(F->hasLazyArguments()); |
61 | } |
62 | |
63 | TEST(FunctionTest, stealArgumentListFrom) { |
64 | LLVMContext C; |
65 | |
66 | Type *ArgTypes[] = {Type::getInt8Ty(C), Type::getInt32Ty(C)}; |
67 | FunctionType *FTy = FunctionType::get(Result: Type::getVoidTy(C), Params: ArgTypes, isVarArg: false); |
68 | std::unique_ptr<Function> F1( |
69 | Function::Create(Ty: FTy, Linkage: GlobalValue::ExternalLinkage, N: "F1" )); |
70 | std::unique_ptr<Function> F2( |
71 | Function::Create(Ty: FTy, Linkage: GlobalValue::ExternalLinkage, N: "F1" )); |
72 | EXPECT_TRUE(F1->hasLazyArguments()); |
73 | EXPECT_TRUE(F2->hasLazyArguments()); |
74 | |
75 | // Steal arguments before they've been accessed. Nothing should change; both |
76 | // functions should still have lazy arguments. |
77 | // |
78 | // steal(empty); drop (empty) |
79 | F1->stealArgumentListFrom(Src&: *F2); |
80 | EXPECT_TRUE(F1->hasLazyArguments()); |
81 | EXPECT_TRUE(F2->hasLazyArguments()); |
82 | |
83 | // Save arguments from F1 for later assertions. F1 won't have lazy arguments |
84 | // anymore. |
85 | SmallVector<Argument *, 4> Args; |
86 | for (Argument &A : F1->args()) |
87 | Args.push_back(Elt: &A); |
88 | EXPECT_EQ(2u, Args.size()); |
89 | EXPECT_FALSE(F1->hasLazyArguments()); |
90 | |
91 | // Steal arguments from F1 to F2. F1's arguments should be lazy again. |
92 | // |
93 | // steal(real); drop (empty) |
94 | F2->stealArgumentListFrom(Src&: *F1); |
95 | EXPECT_TRUE(F1->hasLazyArguments()); |
96 | EXPECT_FALSE(F2->hasLazyArguments()); |
97 | unsigned I = 0; |
98 | for (Argument &A : F2->args()) { |
99 | EXPECT_EQ(Args[I], &A); |
100 | I++; |
101 | } |
102 | EXPECT_EQ(2u, I); |
103 | |
104 | // Check that arguments in F1 don't have pointer equality with the saved ones. |
105 | // This also instantiates F1's arguments. |
106 | I = 0; |
107 | for (Argument &A : F1->args()) { |
108 | EXPECT_NE(Args[I], &A); |
109 | I++; |
110 | } |
111 | EXPECT_EQ(2u, I); |
112 | EXPECT_FALSE(F1->hasLazyArguments()); |
113 | EXPECT_FALSE(F2->hasLazyArguments()); |
114 | |
115 | // Steal back from F2. F2's arguments should be lazy again. |
116 | // |
117 | // steal(real); drop (real) |
118 | F1->stealArgumentListFrom(Src&: *F2); |
119 | EXPECT_FALSE(F1->hasLazyArguments()); |
120 | EXPECT_TRUE(F2->hasLazyArguments()); |
121 | I = 0; |
122 | for (Argument &A : F1->args()) { |
123 | EXPECT_EQ(Args[I], &A); |
124 | I++; |
125 | } |
126 | EXPECT_EQ(2u, I); |
127 | |
128 | // Steal from F2 a second time. Now both functions should have lazy |
129 | // arguments. |
130 | // |
131 | // steal(empty); drop (real) |
132 | F1->stealArgumentListFrom(Src&: *F2); |
133 | EXPECT_TRUE(F1->hasLazyArguments()); |
134 | EXPECT_TRUE(F2->hasLazyArguments()); |
135 | } |
136 | |
137 | // Test setting and removing section information |
138 | TEST(FunctionTest, setSection) { |
139 | LLVMContext C; |
140 | Module M("test" , C); |
141 | |
142 | llvm::Function *F = |
143 | Function::Create(Ty: llvm::FunctionType::get(Result: llvm::Type::getVoidTy(C), isVarArg: false), |
144 | Linkage: llvm::GlobalValue::ExternalLinkage, N: "F" , M: &M); |
145 | |
146 | F->setSection(".text.test" ); |
147 | EXPECT_TRUE(F->getSection() == ".text.test" ); |
148 | EXPECT_TRUE(F->hasSection()); |
149 | F->setSection("" ); |
150 | EXPECT_FALSE(F->hasSection()); |
151 | F->setSection(".text.test" ); |
152 | F->setSection(".text.test2" ); |
153 | EXPECT_TRUE(F->getSection() == ".text.test2" ); |
154 | EXPECT_TRUE(F->hasSection()); |
155 | } |
156 | |
157 | TEST(FunctionTest, GetPointerAlignment) { |
158 | LLVMContext Context; |
159 | Type *VoidType(Type::getVoidTy(C&: Context)); |
160 | FunctionType *FuncType(FunctionType::get(Result: VoidType, isVarArg: false)); |
161 | std::unique_ptr<Function> Func(Function::Create( |
162 | Ty: FuncType, Linkage: GlobalValue::ExternalLinkage)); |
163 | EXPECT_EQ(Align(1), Func->getPointerAlignment(DataLayout("" ))); |
164 | EXPECT_EQ(Align(1), Func->getPointerAlignment(DataLayout("Fi8" ))); |
165 | EXPECT_EQ(Align(1), Func->getPointerAlignment(DataLayout("Fn8" ))); |
166 | EXPECT_EQ(Align(2), Func->getPointerAlignment(DataLayout("Fi16" ))); |
167 | EXPECT_EQ(Align(2), Func->getPointerAlignment(DataLayout("Fn16" ))); |
168 | EXPECT_EQ(Align(4), Func->getPointerAlignment(DataLayout("Fi32" ))); |
169 | EXPECT_EQ(Align(4), Func->getPointerAlignment(DataLayout("Fn32" ))); |
170 | |
171 | Func->setAlignment(Align(4)); |
172 | |
173 | EXPECT_EQ(Align(1), Func->getPointerAlignment(DataLayout("" ))); |
174 | EXPECT_EQ(Align(1), Func->getPointerAlignment(DataLayout("Fi8" ))); |
175 | EXPECT_EQ(Align(4), Func->getPointerAlignment(DataLayout("Fn8" ))); |
176 | EXPECT_EQ(Align(2), Func->getPointerAlignment(DataLayout("Fi16" ))); |
177 | EXPECT_EQ(Align(4), Func->getPointerAlignment(DataLayout("Fn16" ))); |
178 | EXPECT_EQ(Align(4), Func->getPointerAlignment(DataLayout("Fi32" ))); |
179 | EXPECT_EQ(Align(4), Func->getPointerAlignment(DataLayout("Fn32" ))); |
180 | } |
181 | |
182 | TEST(FunctionTest, InsertBasicBlockAt) { |
183 | LLVMContext C; |
184 | std::unique_ptr<Module> M = parseIR(C, IR: R"( |
185 | define void @foo(i32 %a, i32 %b) { |
186 | foo_bb0: |
187 | ret void |
188 | } |
189 | |
190 | define void @bar() { |
191 | bar_bb0: |
192 | br label %bar_bb1 |
193 | bar_bb1: |
194 | br label %bar_bb2 |
195 | bar_bb2: |
196 | ret void |
197 | } |
198 | )" ); |
199 | Function *FooF = M->getFunction(Name: "foo" ); |
200 | BasicBlock *FooBB0 = getBBWithName(F: FooF, Name: "foo_bb0" ); |
201 | |
202 | Function *BarF = M->getFunction(Name: "bar" ); |
203 | BasicBlock *BarBB0 = getBBWithName(F: BarF, Name: "bar_bb0" ); |
204 | BasicBlock *BarBB1 = getBBWithName(F: BarF, Name: "bar_bb1" ); |
205 | BasicBlock *BarBB2 = getBBWithName(F: BarF, Name: "bar_bb2" ); |
206 | |
207 | // Insert foo_bb0 into bar() at the very top. |
208 | FooBB0->removeFromParent(); |
209 | auto It = BarF->insert(Position: BarF->begin(), BB: FooBB0); |
210 | EXPECT_EQ(BarBB0->getPrevNode(), FooBB0); |
211 | EXPECT_EQ(It, FooBB0->getIterator()); |
212 | |
213 | // Insert foo_bb0 into bar() at the very end. |
214 | FooBB0->removeFromParent(); |
215 | It = BarF->insert(Position: BarF->end(), BB: FooBB0); |
216 | EXPECT_EQ(FooBB0->getPrevNode(), BarBB2); |
217 | EXPECT_EQ(FooBB0->getNextNode(), nullptr); |
218 | EXPECT_EQ(It, FooBB0->getIterator()); |
219 | |
220 | // Insert foo_bb0 into bar() just before bar_bb0. |
221 | FooBB0->removeFromParent(); |
222 | It = BarF->insert(Position: BarBB0->getIterator(), BB: FooBB0); |
223 | EXPECT_EQ(FooBB0->getPrevNode(), nullptr); |
224 | EXPECT_EQ(FooBB0->getNextNode(), BarBB0); |
225 | EXPECT_EQ(It, FooBB0->getIterator()); |
226 | |
227 | // Insert foo_bb0 into bar() just before bar_bb1. |
228 | FooBB0->removeFromParent(); |
229 | It = BarF->insert(Position: BarBB1->getIterator(), BB: FooBB0); |
230 | EXPECT_EQ(FooBB0->getPrevNode(), BarBB0); |
231 | EXPECT_EQ(FooBB0->getNextNode(), BarBB1); |
232 | EXPECT_EQ(It, FooBB0->getIterator()); |
233 | |
234 | // Insert foo_bb0 into bar() just before bar_bb2. |
235 | FooBB0->removeFromParent(); |
236 | It = BarF->insert(Position: BarBB2->getIterator(), BB: FooBB0); |
237 | EXPECT_EQ(FooBB0->getPrevNode(), BarBB1); |
238 | EXPECT_EQ(FooBB0->getNextNode(), BarBB2); |
239 | EXPECT_EQ(It, FooBB0->getIterator()); |
240 | } |
241 | |
242 | TEST(FunctionTest, SpliceOneBB) { |
243 | LLVMContext Ctx; |
244 | std::unique_ptr<Module> M = parseIR(C&: Ctx, IR: R"( |
245 | define void @from() { |
246 | from_bb1: |
247 | br label %from_bb2 |
248 | from_bb2: |
249 | br label %from_bb3 |
250 | from_bb3: |
251 | ret void |
252 | } |
253 | define void @to() { |
254 | to_bb1: |
255 | br label %to_bb2 |
256 | to_bb2: |
257 | br label %to_bb3 |
258 | to_bb3: |
259 | ret void |
260 | } |
261 | )" ); |
262 | Function *FromF = M->getFunction(Name: "from" ); |
263 | BasicBlock *FromBB1 = getBBWithName(F: FromF, Name: "from_bb1" ); |
264 | BasicBlock *FromBB2 = getBBWithName(F: FromF, Name: "from_bb2" ); |
265 | BasicBlock *FromBB3 = getBBWithName(F: FromF, Name: "from_bb3" ); |
266 | |
267 | Function *ToF = M->getFunction(Name: "to" ); |
268 | BasicBlock *ToBB1 = getBBWithName(F: ToF, Name: "to_bb1" ); |
269 | BasicBlock *ToBB2 = getBBWithName(F: ToF, Name: "to_bb2" ); |
270 | BasicBlock *ToBB3 = getBBWithName(F: ToF, Name: "to_bb3" ); |
271 | |
272 | // Move from_bb2 before to_bb1. |
273 | ToF->splice(ToIt: ToBB1->getIterator(), FromF, FromIt: FromBB2->getIterator()); |
274 | EXPECT_EQ(FromF->size(), 2u); |
275 | EXPECT_EQ(ToF->size(), 4u); |
276 | |
277 | auto It = FromF->begin(); |
278 | EXPECT_EQ(&*It++, FromBB1); |
279 | EXPECT_EQ(&*It++, FromBB3); |
280 | |
281 | It = ToF->begin(); |
282 | EXPECT_EQ(&*It++, FromBB2); |
283 | EXPECT_EQ(&*It++, ToBB1); |
284 | EXPECT_EQ(&*It++, ToBB2); |
285 | EXPECT_EQ(&*It++, ToBB3); |
286 | |
287 | // Cleanup to avoid "Uses remain when a value is destroyed!". |
288 | FromF->splice(ToIt: FromBB3->getIterator(), FromF: ToF, FromIt: FromBB2->getIterator()); |
289 | } |
290 | |
291 | TEST(FunctionTest, SpliceOneBBWhenFromIsSameAsTo) { |
292 | LLVMContext Ctx; |
293 | std::unique_ptr<Module> M = parseIR(C&: Ctx, IR: R"( |
294 | define void @fromto() { |
295 | bb1: |
296 | br label %bb2 |
297 | bb2: |
298 | ret void |
299 | } |
300 | )" ); |
301 | Function *F = M->getFunction(Name: "fromto" ); |
302 | BasicBlock *BB1 = getBBWithName(F, Name: "bb1" ); |
303 | BasicBlock *BB2 = getBBWithName(F, Name: "bb2" ); |
304 | |
305 | // According to ilist's splice() a single-element splice where dst == src |
306 | // should be a noop. |
307 | F->splice(ToIt: BB1->getIterator(), FromF: F, FromIt: BB1->getIterator()); |
308 | |
309 | auto It = F->begin(); |
310 | EXPECT_EQ(&*It++, BB1); |
311 | EXPECT_EQ(&*It++, BB2); |
312 | EXPECT_EQ(F->size(), 2u); |
313 | } |
314 | |
315 | TEST(FunctionTest, SpliceLastBB) { |
316 | LLVMContext Ctx; |
317 | std::unique_ptr<Module> M = parseIR(C&: Ctx, IR: R"( |
318 | define void @from() { |
319 | from_bb1: |
320 | br label %from_bb2 |
321 | from_bb2: |
322 | br label %from_bb3 |
323 | from_bb3: |
324 | ret void |
325 | } |
326 | define void @to() { |
327 | to_bb1: |
328 | br label %to_bb2 |
329 | to_bb2: |
330 | br label %to_bb3 |
331 | to_bb3: |
332 | ret void |
333 | } |
334 | )" ); |
335 | |
336 | Function *FromF = M->getFunction(Name: "from" ); |
337 | BasicBlock *FromBB1 = getBBWithName(F: FromF, Name: "from_bb1" ); |
338 | BasicBlock *FromBB2 = getBBWithName(F: FromF, Name: "from_bb2" ); |
339 | BasicBlock *FromBB3 = getBBWithName(F: FromF, Name: "from_bb3" ); |
340 | |
341 | Function *ToF = M->getFunction(Name: "to" ); |
342 | BasicBlock *ToBB1 = getBBWithName(F: ToF, Name: "to_bb1" ); |
343 | BasicBlock *ToBB2 = getBBWithName(F: ToF, Name: "to_bb2" ); |
344 | BasicBlock *ToBB3 = getBBWithName(F: ToF, Name: "to_bb3" ); |
345 | |
346 | // Move from_bb2 before to_bb1. |
347 | auto ToMove = FromBB2->getIterator(); |
348 | ToF->splice(ToIt: ToBB1->getIterator(), FromF, FromBeginIt: ToMove, FromEndIt: std::next(x: ToMove)); |
349 | |
350 | EXPECT_EQ(FromF->size(), 2u); |
351 | auto It = FromF->begin(); |
352 | EXPECT_EQ(&*It++, FromBB1); |
353 | EXPECT_EQ(&*It++, FromBB3); |
354 | |
355 | EXPECT_EQ(ToF->size(), 4u); |
356 | It = ToF->begin(); |
357 | EXPECT_EQ(&*It++, FromBB2); |
358 | EXPECT_EQ(&*It++, ToBB1); |
359 | EXPECT_EQ(&*It++, ToBB2); |
360 | EXPECT_EQ(&*It++, ToBB3); |
361 | |
362 | // Cleanup to avoid "Uses remain when a value is destroyed!". |
363 | FromF->splice(ToIt: FromBB3->getIterator(), FromF: ToF, FromIt: ToMove); |
364 | } |
365 | |
366 | TEST(FunctionTest, SpliceBBRange) { |
367 | LLVMContext Ctx; |
368 | std::unique_ptr<Module> M = parseIR(C&: Ctx, IR: R"( |
369 | define void @from() { |
370 | from_bb1: |
371 | br label %from_bb2 |
372 | from_bb2: |
373 | br label %from_bb3 |
374 | from_bb3: |
375 | ret void |
376 | } |
377 | define void @to() { |
378 | to_bb1: |
379 | br label %to_bb2 |
380 | to_bb2: |
381 | br label %to_bb3 |
382 | to_bb3: |
383 | ret void |
384 | } |
385 | )" ); |
386 | |
387 | Function *FromF = M->getFunction(Name: "from" ); |
388 | BasicBlock *FromBB1 = getBBWithName(F: FromF, Name: "from_bb1" ); |
389 | BasicBlock *FromBB2 = getBBWithName(F: FromF, Name: "from_bb2" ); |
390 | BasicBlock *FromBB3 = getBBWithName(F: FromF, Name: "from_bb3" ); |
391 | |
392 | Function *ToF = M->getFunction(Name: "to" ); |
393 | BasicBlock *ToBB1 = getBBWithName(F: ToF, Name: "to_bb1" ); |
394 | BasicBlock *ToBB2 = getBBWithName(F: ToF, Name: "to_bb2" ); |
395 | BasicBlock *ToBB3 = getBBWithName(F: ToF, Name: "to_bb3" ); |
396 | |
397 | // Move all BBs from @from to @to. |
398 | ToF->splice(ToIt: ToBB2->getIterator(), FromF, FromBeginIt: FromF->begin(), FromEndIt: FromF->end()); |
399 | |
400 | EXPECT_EQ(FromF->size(), 0u); |
401 | |
402 | EXPECT_EQ(ToF->size(), 6u); |
403 | auto It = ToF->begin(); |
404 | EXPECT_EQ(&*It++, ToBB1); |
405 | EXPECT_EQ(&*It++, FromBB1); |
406 | EXPECT_EQ(&*It++, FromBB2); |
407 | EXPECT_EQ(&*It++, FromBB3); |
408 | EXPECT_EQ(&*It++, ToBB2); |
409 | EXPECT_EQ(&*It++, ToBB3); |
410 | } |
411 | |
412 | #ifdef EXPENSIVE_CHECKS |
413 | TEST(FunctionTest, SpliceEndBeforeBegin) { |
414 | LLVMContext Ctx; |
415 | std::unique_ptr<Module> M = parseIR(Ctx, R"( |
416 | define void @from() { |
417 | from_bb1: |
418 | br label %from_bb2 |
419 | from_bb2: |
420 | br label %from_bb3 |
421 | from_bb3: |
422 | ret void |
423 | } |
424 | define void @to() { |
425 | to_bb1: |
426 | br label %to_bb2 |
427 | to_bb2: |
428 | br label %to_bb3 |
429 | to_bb3: |
430 | ret void |
431 | } |
432 | )" ); |
433 | |
434 | Function *FromF = M->getFunction("from" ); |
435 | BasicBlock *FromBB1 = getBBWithName(FromF, "from_bb1" ); |
436 | BasicBlock *FromBB2 = getBBWithName(FromF, "from_bb2" ); |
437 | |
438 | Function *ToF = M->getFunction("to" ); |
439 | BasicBlock *ToBB2 = getBBWithName(ToF, "to_bb2" ); |
440 | |
441 | EXPECT_DEATH(ToF->splice(ToBB2->getIterator(), FromF, FromBB2->getIterator(), |
442 | FromBB1->getIterator()), |
443 | "FromBeginIt not before FromEndIt!" ); |
444 | } |
445 | #endif //EXPENSIVE_CHECKS |
446 | |
447 | TEST(FunctionTest, EraseBBs) { |
448 | LLVMContext Ctx; |
449 | std::unique_ptr<Module> M = parseIR(C&: Ctx, IR: R"( |
450 | define void @foo() { |
451 | bb1: |
452 | br label %bb2 |
453 | bb2: |
454 | br label %bb3 |
455 | bb3: |
456 | br label %bb4 |
457 | bb4: |
458 | br label %bb5 |
459 | bb5: |
460 | ret void |
461 | } |
462 | )" ); |
463 | |
464 | Function *F = M->getFunction(Name: "foo" ); |
465 | BasicBlock *BB1 = getBBWithName(F, Name: "bb1" ); |
466 | BasicBlock *BB2 = getBBWithName(F, Name: "bb2" ); |
467 | BasicBlock *BB3 = getBBWithName(F, Name: "bb3" ); |
468 | BasicBlock *BB4 = getBBWithName(F, Name: "bb4" ); |
469 | BasicBlock *BB5 = getBBWithName(F, Name: "bb5" ); |
470 | EXPECT_EQ(F->size(), 5u); |
471 | |
472 | // Erase BB2. |
473 | BB1->getTerminator()->eraseFromParent(); |
474 | auto It = F->erase(FromIt: BB2->getIterator(), ToIt: std::next(x: BB2->getIterator())); |
475 | EXPECT_EQ(F->size(), 4u); |
476 | // Check that the iterator returned matches the node after the erased one. |
477 | EXPECT_EQ(It, BB3->getIterator()); |
478 | |
479 | It = F->begin(); |
480 | EXPECT_EQ(&*It++, BB1); |
481 | EXPECT_EQ(&*It++, BB3); |
482 | EXPECT_EQ(&*It++, BB4); |
483 | EXPECT_EQ(&*It++, BB5); |
484 | |
485 | // Erase all BBs. |
486 | It = F->erase(FromIt: F->begin(), ToIt: F->end()); |
487 | EXPECT_EQ(F->size(), 0u); |
488 | } |
489 | } // end namespace |
490 | |