1 //===- llvm/unittest/IR/OpenMPIRBuilderTest.cpp - OpenMPIRBuilder 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/Frontend/OpenMP/OMPIRBuilder.h"
10 #include "llvm/IR/BasicBlock.h"
11 #include "llvm/IR/DIBuilder.h"
12 #include "llvm/IR/Function.h"
13 #include "llvm/IR/LLVMContext.h"
14 #include "llvm/IR/Module.h"
15 #include "llvm/Frontend/OpenMP/OMPConstants.h"
16 #include "llvm/IR/Verifier.h"
17 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
18 #include "gtest/gtest.h"
19
20 using namespace llvm;
21 using namespace omp;
22
23 namespace {
24
25 class OpenMPIRBuilderTest : public testing::Test {
26 protected:
SetUp()27 void SetUp() override {
28 M.reset(new Module("MyModule", Ctx));
29 FunctionType *FTy =
30 FunctionType::get(Type::getVoidTy(Ctx), {Type::getInt32Ty(Ctx)},
31 /*isVarArg=*/false);
32 F = Function::Create(FTy, Function::ExternalLinkage, "", M.get());
33 BB = BasicBlock::Create(Ctx, "", F);
34
35 DIBuilder DIB(*M);
36 auto File = DIB.createFile("test.dbg", "/");
37 auto CU =
38 DIB.createCompileUnit(dwarf::DW_LANG_C, File, "llvm-C", true, "", 0);
39 auto Type = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None));
40 auto SP = DIB.createFunction(
41 CU, "foo", "", File, 1, Type, 1, DINode::FlagZero,
42 DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized);
43 F->setSubprogram(SP);
44 auto Scope = DIB.createLexicalBlockFile(SP, File, 0);
45 DIB.finalize();
46 DL = DebugLoc::get(3, 7, Scope);
47 }
48
TearDown()49 void TearDown() override {
50 BB = nullptr;
51 M.reset();
52 }
53
54 LLVMContext Ctx;
55 std::unique_ptr<Module> M;
56 Function *F;
57 BasicBlock *BB;
58 DebugLoc DL;
59 };
60
TEST_F(OpenMPIRBuilderTest,CreateBarrier)61 TEST_F(OpenMPIRBuilderTest, CreateBarrier) {
62 OpenMPIRBuilder OMPBuilder(*M);
63 OMPBuilder.initialize();
64
65 IRBuilder<> Builder(BB);
66
67 OMPBuilder.CreateBarrier({IRBuilder<>::InsertPoint()}, OMPD_for);
68 EXPECT_TRUE(M->global_empty());
69 EXPECT_EQ(M->size(), 1U);
70 EXPECT_EQ(F->size(), 1U);
71 EXPECT_EQ(BB->size(), 0U);
72
73 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP()});
74 OMPBuilder.CreateBarrier(Loc, OMPD_for);
75 EXPECT_FALSE(M->global_empty());
76 EXPECT_EQ(M->size(), 3U);
77 EXPECT_EQ(F->size(), 1U);
78 EXPECT_EQ(BB->size(), 2U);
79
80 CallInst *GTID = dyn_cast<CallInst>(&BB->front());
81 EXPECT_NE(GTID, nullptr);
82 EXPECT_EQ(GTID->getNumArgOperands(), 1U);
83 EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num");
84 EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory());
85 EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory());
86
87 CallInst *Barrier = dyn_cast<CallInst>(GTID->getNextNode());
88 EXPECT_NE(Barrier, nullptr);
89 EXPECT_EQ(Barrier->getNumArgOperands(), 2U);
90 EXPECT_EQ(Barrier->getCalledFunction()->getName(), "__kmpc_barrier");
91 EXPECT_FALSE(Barrier->getCalledFunction()->doesNotAccessMemory());
92 EXPECT_FALSE(Barrier->getCalledFunction()->doesNotFreeMemory());
93
94 EXPECT_EQ(cast<CallInst>(Barrier)->getArgOperand(1), GTID);
95
96 Builder.CreateUnreachable();
97 EXPECT_FALSE(verifyModule(*M, &errs()));
98 }
99
TEST_F(OpenMPIRBuilderTest,CreateCancel)100 TEST_F(OpenMPIRBuilderTest, CreateCancel) {
101 using InsertPointTy = OpenMPIRBuilder::InsertPointTy;
102 OpenMPIRBuilder OMPBuilder(*M);
103 OMPBuilder.initialize();
104
105 BasicBlock *CBB = BasicBlock::Create(Ctx, "", F);
106 new UnreachableInst(Ctx, CBB);
107 auto FiniCB = [&](InsertPointTy IP) {
108 ASSERT_NE(IP.getBlock(), nullptr);
109 ASSERT_EQ(IP.getBlock()->end(), IP.getPoint());
110 BranchInst::Create(CBB, IP.getBlock());
111 };
112 OMPBuilder.pushFinalizationCB({FiniCB, OMPD_parallel, true});
113
114 IRBuilder<> Builder(BB);
115
116 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP()});
117 auto NewIP = OMPBuilder.CreateCancel(Loc, nullptr, OMPD_parallel);
118 Builder.restoreIP(NewIP);
119 EXPECT_FALSE(M->global_empty());
120 EXPECT_EQ(M->size(), 3U);
121 EXPECT_EQ(F->size(), 4U);
122 EXPECT_EQ(BB->size(), 4U);
123
124 CallInst *GTID = dyn_cast<CallInst>(&BB->front());
125 EXPECT_NE(GTID, nullptr);
126 EXPECT_EQ(GTID->getNumArgOperands(), 1U);
127 EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num");
128 EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory());
129 EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory());
130
131 CallInst *Cancel = dyn_cast<CallInst>(GTID->getNextNode());
132 EXPECT_NE(Cancel, nullptr);
133 EXPECT_EQ(Cancel->getNumArgOperands(), 3U);
134 EXPECT_EQ(Cancel->getCalledFunction()->getName(), "__kmpc_cancel");
135 EXPECT_FALSE(Cancel->getCalledFunction()->doesNotAccessMemory());
136 EXPECT_FALSE(Cancel->getCalledFunction()->doesNotFreeMemory());
137 EXPECT_EQ(Cancel->getNumUses(), 1U);
138 Instruction *CancelBBTI = Cancel->getParent()->getTerminator();
139 EXPECT_EQ(CancelBBTI->getNumSuccessors(), 2U);
140 EXPECT_EQ(CancelBBTI->getSuccessor(0), NewIP.getBlock());
141 EXPECT_EQ(CancelBBTI->getSuccessor(1)->size(), 1U);
142 EXPECT_EQ(CancelBBTI->getSuccessor(1)->getTerminator()->getNumSuccessors(),
143 1U);
144 EXPECT_EQ(CancelBBTI->getSuccessor(1)->getTerminator()->getSuccessor(0),
145 CBB);
146
147 EXPECT_EQ(cast<CallInst>(Cancel)->getArgOperand(1), GTID);
148
149 OMPBuilder.popFinalizationCB();
150
151 Builder.CreateUnreachable();
152 EXPECT_FALSE(verifyModule(*M, &errs()));
153 }
154
TEST_F(OpenMPIRBuilderTest,CreateCancelIfCond)155 TEST_F(OpenMPIRBuilderTest, CreateCancelIfCond) {
156 using InsertPointTy = OpenMPIRBuilder::InsertPointTy;
157 OpenMPIRBuilder OMPBuilder(*M);
158 OMPBuilder.initialize();
159
160 BasicBlock *CBB = BasicBlock::Create(Ctx, "", F);
161 new UnreachableInst(Ctx, CBB);
162 auto FiniCB = [&](InsertPointTy IP) {
163 ASSERT_NE(IP.getBlock(), nullptr);
164 ASSERT_EQ(IP.getBlock()->end(), IP.getPoint());
165 BranchInst::Create(CBB, IP.getBlock());
166 };
167 OMPBuilder.pushFinalizationCB({FiniCB, OMPD_parallel, true});
168
169 IRBuilder<> Builder(BB);
170
171 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP()});
172 auto NewIP = OMPBuilder.CreateCancel(Loc, Builder.getTrue(), OMPD_parallel);
173 Builder.restoreIP(NewIP);
174 EXPECT_FALSE(M->global_empty());
175 EXPECT_EQ(M->size(), 3U);
176 EXPECT_EQ(F->size(), 7U);
177 EXPECT_EQ(BB->size(), 1U);
178 ASSERT_TRUE(isa<BranchInst>(BB->getTerminator()));
179 ASSERT_EQ(BB->getTerminator()->getNumSuccessors(), 2U);
180 BB = BB->getTerminator()->getSuccessor(0);
181 EXPECT_EQ(BB->size(), 4U);
182
183
184 CallInst *GTID = dyn_cast<CallInst>(&BB->front());
185 EXPECT_NE(GTID, nullptr);
186 EXPECT_EQ(GTID->getNumArgOperands(), 1U);
187 EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num");
188 EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory());
189 EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory());
190
191 CallInst *Cancel = dyn_cast<CallInst>(GTID->getNextNode());
192 EXPECT_NE(Cancel, nullptr);
193 EXPECT_EQ(Cancel->getNumArgOperands(), 3U);
194 EXPECT_EQ(Cancel->getCalledFunction()->getName(), "__kmpc_cancel");
195 EXPECT_FALSE(Cancel->getCalledFunction()->doesNotAccessMemory());
196 EXPECT_FALSE(Cancel->getCalledFunction()->doesNotFreeMemory());
197 EXPECT_EQ(Cancel->getNumUses(), 1U);
198 Instruction *CancelBBTI = Cancel->getParent()->getTerminator();
199 EXPECT_EQ(CancelBBTI->getNumSuccessors(), 2U);
200 EXPECT_EQ(CancelBBTI->getSuccessor(0)->size(), 1U);
201 EXPECT_EQ(CancelBBTI->getSuccessor(0)->getUniqueSuccessor(), NewIP.getBlock());
202 EXPECT_EQ(CancelBBTI->getSuccessor(1)->size(), 1U);
203 EXPECT_EQ(CancelBBTI->getSuccessor(1)->getTerminator()->getNumSuccessors(),
204 1U);
205 EXPECT_EQ(CancelBBTI->getSuccessor(1)->getTerminator()->getSuccessor(0),
206 CBB);
207
208 EXPECT_EQ(cast<CallInst>(Cancel)->getArgOperand(1), GTID);
209
210 OMPBuilder.popFinalizationCB();
211
212 Builder.CreateUnreachable();
213 EXPECT_FALSE(verifyModule(*M, &errs()));
214 }
215
TEST_F(OpenMPIRBuilderTest,CreateCancelBarrier)216 TEST_F(OpenMPIRBuilderTest, CreateCancelBarrier) {
217 using InsertPointTy = OpenMPIRBuilder::InsertPointTy;
218 OpenMPIRBuilder OMPBuilder(*M);
219 OMPBuilder.initialize();
220
221 BasicBlock *CBB = BasicBlock::Create(Ctx, "", F);
222 new UnreachableInst(Ctx, CBB);
223 auto FiniCB = [&](InsertPointTy IP) {
224 ASSERT_NE(IP.getBlock(), nullptr);
225 ASSERT_EQ(IP.getBlock()->end(), IP.getPoint());
226 BranchInst::Create(CBB, IP.getBlock());
227 };
228 OMPBuilder.pushFinalizationCB({FiniCB, OMPD_parallel, true});
229
230 IRBuilder<> Builder(BB);
231
232 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP()});
233 auto NewIP = OMPBuilder.CreateBarrier(Loc, OMPD_for);
234 Builder.restoreIP(NewIP);
235 EXPECT_FALSE(M->global_empty());
236 EXPECT_EQ(M->size(), 3U);
237 EXPECT_EQ(F->size(), 4U);
238 EXPECT_EQ(BB->size(), 4U);
239
240 CallInst *GTID = dyn_cast<CallInst>(&BB->front());
241 EXPECT_NE(GTID, nullptr);
242 EXPECT_EQ(GTID->getNumArgOperands(), 1U);
243 EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num");
244 EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory());
245 EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory());
246
247 CallInst *Barrier = dyn_cast<CallInst>(GTID->getNextNode());
248 EXPECT_NE(Barrier, nullptr);
249 EXPECT_EQ(Barrier->getNumArgOperands(), 2U);
250 EXPECT_EQ(Barrier->getCalledFunction()->getName(), "__kmpc_cancel_barrier");
251 EXPECT_FALSE(Barrier->getCalledFunction()->doesNotAccessMemory());
252 EXPECT_FALSE(Barrier->getCalledFunction()->doesNotFreeMemory());
253 EXPECT_EQ(Barrier->getNumUses(), 1U);
254 Instruction *BarrierBBTI = Barrier->getParent()->getTerminator();
255 EXPECT_EQ(BarrierBBTI->getNumSuccessors(), 2U);
256 EXPECT_EQ(BarrierBBTI->getSuccessor(0), NewIP.getBlock());
257 EXPECT_EQ(BarrierBBTI->getSuccessor(1)->size(), 1U);
258 EXPECT_EQ(BarrierBBTI->getSuccessor(1)->getTerminator()->getNumSuccessors(),
259 1U);
260 EXPECT_EQ(BarrierBBTI->getSuccessor(1)->getTerminator()->getSuccessor(0),
261 CBB);
262
263 EXPECT_EQ(cast<CallInst>(Barrier)->getArgOperand(1), GTID);
264
265 OMPBuilder.popFinalizationCB();
266
267 Builder.CreateUnreachable();
268 EXPECT_FALSE(verifyModule(*M, &errs()));
269 }
270
TEST_F(OpenMPIRBuilderTest,DbgLoc)271 TEST_F(OpenMPIRBuilderTest, DbgLoc) {
272 OpenMPIRBuilder OMPBuilder(*M);
273 OMPBuilder.initialize();
274 F->setName("func");
275
276 IRBuilder<> Builder(BB);
277
278 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});
279 OMPBuilder.CreateBarrier(Loc, OMPD_for);
280 CallInst *GTID = dyn_cast<CallInst>(&BB->front());
281 CallInst *Barrier = dyn_cast<CallInst>(GTID->getNextNode());
282 EXPECT_EQ(GTID->getDebugLoc(), DL);
283 EXPECT_EQ(Barrier->getDebugLoc(), DL);
284 EXPECT_TRUE(isa<GlobalVariable>(Barrier->getOperand(0)));
285 if (!isa<GlobalVariable>(Barrier->getOperand(0)))
286 return;
287 GlobalVariable *Ident = cast<GlobalVariable>(Barrier->getOperand(0));
288 EXPECT_TRUE(Ident->hasInitializer());
289 if (!Ident->hasInitializer())
290 return;
291 Constant *Initializer = Ident->getInitializer();
292 EXPECT_TRUE(
293 isa<GlobalVariable>(Initializer->getOperand(4)->stripPointerCasts()));
294 GlobalVariable *SrcStrGlob =
295 cast<GlobalVariable>(Initializer->getOperand(4)->stripPointerCasts());
296 if (!SrcStrGlob)
297 return;
298 EXPECT_TRUE(isa<ConstantDataArray>(SrcStrGlob->getInitializer()));
299 ConstantDataArray *SrcSrc =
300 dyn_cast<ConstantDataArray>(SrcStrGlob->getInitializer());
301 if (!SrcSrc)
302 return;
303 EXPECT_EQ(SrcSrc->getAsCString(), ";test.dbg;foo;3;7;;");
304 }
305
TEST_F(OpenMPIRBuilderTest,ParallelSimple)306 TEST_F(OpenMPIRBuilderTest, ParallelSimple) {
307 using InsertPointTy = OpenMPIRBuilder::InsertPointTy;
308 OpenMPIRBuilder OMPBuilder(*M);
309 OMPBuilder.initialize();
310 F->setName("func");
311 IRBuilder<> Builder(BB);
312
313 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});
314
315 AllocaInst *PrivAI = nullptr;
316
317 unsigned NumBodiesGenerated = 0;
318 unsigned NumPrivatizedVars = 0;
319 unsigned NumFinalizationPoints = 0;
320
321 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
322 BasicBlock &ContinuationIP) {
323 ++NumBodiesGenerated;
324
325 Builder.restoreIP(AllocaIP);
326 PrivAI = Builder.CreateAlloca(F->arg_begin()->getType());
327 Builder.CreateStore(F->arg_begin(), PrivAI);
328
329 Builder.restoreIP(CodeGenIP);
330 Value *PrivLoad = Builder.CreateLoad(PrivAI, "local.use");
331 Value *Cmp = Builder.CreateICmpNE(F->arg_begin(), PrivLoad);
332 Instruction *ThenTerm, *ElseTerm;
333 SplitBlockAndInsertIfThenElse(Cmp, CodeGenIP.getBlock()->getTerminator(),
334 &ThenTerm, &ElseTerm);
335
336 Builder.SetInsertPoint(ThenTerm);
337 Builder.CreateBr(&ContinuationIP);
338 ThenTerm->eraseFromParent();
339 };
340
341 auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
342 Value &VPtr, Value *&ReplacementValue) -> InsertPointTy {
343 ++NumPrivatizedVars;
344
345 if (!isa<AllocaInst>(VPtr)) {
346 EXPECT_EQ(&VPtr, F->arg_begin());
347 ReplacementValue = &VPtr;
348 return CodeGenIP;
349 }
350
351 // Trivial copy (=firstprivate).
352 Builder.restoreIP(AllocaIP);
353 Type *VTy = VPtr.getType()->getPointerElementType();
354 Value *V = Builder.CreateLoad(VTy, &VPtr, VPtr.getName() + ".reload");
355 ReplacementValue = Builder.CreateAlloca(VTy, 0, VPtr.getName() + ".copy");
356 Builder.restoreIP(CodeGenIP);
357 Builder.CreateStore(V, ReplacementValue);
358 return CodeGenIP;
359 };
360
361 auto FiniCB = [&](InsertPointTy CodeGenIP) { ++NumFinalizationPoints; };
362
363 IRBuilder<>::InsertPoint AfterIP =
364 OMPBuilder.CreateParallel(Loc, BodyGenCB, PrivCB, FiniCB, nullptr,
365 nullptr, OMP_PROC_BIND_default, false);
366 EXPECT_EQ(NumBodiesGenerated, 1U);
367 EXPECT_EQ(NumPrivatizedVars, 1U);
368 EXPECT_EQ(NumFinalizationPoints, 1U);
369
370 Builder.restoreIP(AfterIP);
371 Builder.CreateRetVoid();
372
373 OMPBuilder.finalize();
374
375 EXPECT_NE(PrivAI, nullptr);
376 Function *OutlinedFn = PrivAI->getFunction();
377 EXPECT_NE(F, OutlinedFn);
378 EXPECT_FALSE(verifyModule(*M, &errs()));
379 EXPECT_TRUE(OutlinedFn->hasFnAttribute(Attribute::NoUnwind));
380 EXPECT_TRUE(OutlinedFn->hasFnAttribute(Attribute::NoRecurse));
381 EXPECT_TRUE(OutlinedFn->hasParamAttribute(0, Attribute::NoAlias));
382 EXPECT_TRUE(OutlinedFn->hasParamAttribute(1, Attribute::NoAlias));
383
384 EXPECT_TRUE(OutlinedFn->hasInternalLinkage());
385 EXPECT_EQ(OutlinedFn->arg_size(), 3U);
386
387 EXPECT_EQ(&OutlinedFn->getEntryBlock(), PrivAI->getParent());
388 EXPECT_EQ(OutlinedFn->getNumUses(), 1U);
389 User *Usr = OutlinedFn->user_back();
390 ASSERT_TRUE(isa<ConstantExpr>(Usr));
391 CallInst *ForkCI = dyn_cast<CallInst>(Usr->user_back());
392 ASSERT_NE(ForkCI, nullptr);
393
394 EXPECT_EQ(ForkCI->getCalledFunction()->getName(), "__kmpc_fork_call");
395 EXPECT_EQ(ForkCI->getNumArgOperands(), 4U);
396 EXPECT_TRUE(isa<GlobalVariable>(ForkCI->getArgOperand(0)));
397 EXPECT_EQ(ForkCI->getArgOperand(1),
398 ConstantInt::get(Type::getInt32Ty(Ctx), 1U));
399 EXPECT_EQ(ForkCI->getArgOperand(2), Usr);
400 EXPECT_EQ(ForkCI->getArgOperand(3), F->arg_begin());
401 }
402
TEST_F(OpenMPIRBuilderTest,ParallelIfCond)403 TEST_F(OpenMPIRBuilderTest, ParallelIfCond) {
404 using InsertPointTy = OpenMPIRBuilder::InsertPointTy;
405 OpenMPIRBuilder OMPBuilder(*M);
406 OMPBuilder.initialize();
407 F->setName("func");
408 IRBuilder<> Builder(BB);
409
410 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});
411
412 AllocaInst *PrivAI = nullptr;
413
414 unsigned NumBodiesGenerated = 0;
415 unsigned NumPrivatizedVars = 0;
416 unsigned NumFinalizationPoints = 0;
417
418 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
419 BasicBlock &ContinuationIP) {
420 ++NumBodiesGenerated;
421
422 Builder.restoreIP(AllocaIP);
423 PrivAI = Builder.CreateAlloca(F->arg_begin()->getType());
424 Builder.CreateStore(F->arg_begin(), PrivAI);
425
426 Builder.restoreIP(CodeGenIP);
427 Value *PrivLoad = Builder.CreateLoad(PrivAI, "local.use");
428 Value *Cmp = Builder.CreateICmpNE(F->arg_begin(), PrivLoad);
429 Instruction *ThenTerm, *ElseTerm;
430 SplitBlockAndInsertIfThenElse(Cmp, CodeGenIP.getBlock()->getTerminator(),
431 &ThenTerm, &ElseTerm);
432
433 Builder.SetInsertPoint(ThenTerm);
434 Builder.CreateBr(&ContinuationIP);
435 ThenTerm->eraseFromParent();
436 };
437
438 auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
439 Value &VPtr, Value *&ReplacementValue) -> InsertPointTy {
440 ++NumPrivatizedVars;
441
442 if (!isa<AllocaInst>(VPtr)) {
443 EXPECT_EQ(&VPtr, F->arg_begin());
444 ReplacementValue = &VPtr;
445 return CodeGenIP;
446 }
447
448 // Trivial copy (=firstprivate).
449 Builder.restoreIP(AllocaIP);
450 Type *VTy = VPtr.getType()->getPointerElementType();
451 Value *V = Builder.CreateLoad(VTy, &VPtr, VPtr.getName() + ".reload");
452 ReplacementValue = Builder.CreateAlloca(VTy, 0, VPtr.getName() + ".copy");
453 Builder.restoreIP(CodeGenIP);
454 Builder.CreateStore(V, ReplacementValue);
455 return CodeGenIP;
456 };
457
458 auto FiniCB = [&](InsertPointTy CodeGenIP) {
459 ++NumFinalizationPoints;
460 // No destructors.
461 };
462
463 IRBuilder<>::InsertPoint AfterIP = OMPBuilder.CreateParallel(
464 Loc, BodyGenCB, PrivCB, FiniCB, Builder.CreateIsNotNull(F->arg_begin()),
465 nullptr, OMP_PROC_BIND_default, false);
466
467 EXPECT_EQ(NumBodiesGenerated, 1U);
468 EXPECT_EQ(NumPrivatizedVars, 1U);
469 EXPECT_EQ(NumFinalizationPoints, 1U);
470
471 Builder.restoreIP(AfterIP);
472 Builder.CreateRetVoid();
473 OMPBuilder.finalize();
474
475 EXPECT_NE(PrivAI, nullptr);
476 Function *OutlinedFn = PrivAI->getFunction();
477 EXPECT_NE(F, OutlinedFn);
478 EXPECT_FALSE(verifyModule(*M, &errs()));
479
480 EXPECT_TRUE(OutlinedFn->hasInternalLinkage());
481 EXPECT_EQ(OutlinedFn->arg_size(), 3U);
482
483 EXPECT_EQ(&OutlinedFn->getEntryBlock(), PrivAI->getParent());
484 ASSERT_EQ(OutlinedFn->getNumUses(), 2U);
485
486 CallInst *DirectCI = nullptr;
487 CallInst *ForkCI = nullptr;
488 for (User *Usr : OutlinedFn->users()) {
489 if (isa<CallInst>(Usr)) {
490 ASSERT_EQ(DirectCI, nullptr);
491 DirectCI = cast<CallInst>(Usr);
492 } else {
493 ASSERT_TRUE(isa<ConstantExpr>(Usr));
494 ASSERT_EQ(Usr->getNumUses(), 1U);
495 ASSERT_TRUE(isa<CallInst>(Usr->user_back()));
496 ForkCI = cast<CallInst>(Usr->user_back());
497 }
498 }
499
500 EXPECT_EQ(ForkCI->getCalledFunction()->getName(), "__kmpc_fork_call");
501 EXPECT_EQ(ForkCI->getNumArgOperands(), 4U);
502 EXPECT_TRUE(isa<GlobalVariable>(ForkCI->getArgOperand(0)));
503 EXPECT_EQ(ForkCI->getArgOperand(1),
504 ConstantInt::get(Type::getInt32Ty(Ctx), 1));
505 EXPECT_EQ(ForkCI->getArgOperand(3), F->arg_begin());
506
507 EXPECT_EQ(DirectCI->getCalledFunction(), OutlinedFn);
508 EXPECT_EQ(DirectCI->getNumArgOperands(), 3U);
509 EXPECT_TRUE(isa<AllocaInst>(DirectCI->getArgOperand(0)));
510 EXPECT_TRUE(isa<AllocaInst>(DirectCI->getArgOperand(1)));
511 EXPECT_EQ(DirectCI->getArgOperand(2), F->arg_begin());
512 }
513
TEST_F(OpenMPIRBuilderTest,ParallelCancelBarrier)514 TEST_F(OpenMPIRBuilderTest, ParallelCancelBarrier) {
515 using InsertPointTy = OpenMPIRBuilder::InsertPointTy;
516 OpenMPIRBuilder OMPBuilder(*M);
517 OMPBuilder.initialize();
518 F->setName("func");
519 IRBuilder<> Builder(BB);
520
521 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});
522
523 unsigned NumBodiesGenerated = 0;
524 unsigned NumPrivatizedVars = 0;
525 unsigned NumFinalizationPoints = 0;
526
527 CallInst *CheckedBarrier = nullptr;
528 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
529 BasicBlock &ContinuationIP) {
530 ++NumBodiesGenerated;
531
532 Builder.restoreIP(CodeGenIP);
533
534 // Create three barriers, two cancel barriers but only one checked.
535 Function *CBFn, *BFn;
536
537 Builder.restoreIP(
538 OMPBuilder.CreateBarrier(Builder.saveIP(), OMPD_parallel));
539
540 CBFn = M->getFunction("__kmpc_cancel_barrier");
541 BFn = M->getFunction("__kmpc_barrier");
542 ASSERT_NE(CBFn, nullptr);
543 ASSERT_EQ(BFn, nullptr);
544 ASSERT_EQ(CBFn->getNumUses(), 1U);
545 ASSERT_TRUE(isa<CallInst>(CBFn->user_back()));
546 ASSERT_EQ(CBFn->user_back()->getNumUses(), 1U);
547 CheckedBarrier = cast<CallInst>(CBFn->user_back());
548
549 Builder.restoreIP(
550 OMPBuilder.CreateBarrier(Builder.saveIP(), OMPD_parallel, true));
551 CBFn = M->getFunction("__kmpc_cancel_barrier");
552 BFn = M->getFunction("__kmpc_barrier");
553 ASSERT_NE(CBFn, nullptr);
554 ASSERT_NE(BFn, nullptr);
555 ASSERT_EQ(CBFn->getNumUses(), 1U);
556 ASSERT_EQ(BFn->getNumUses(), 1U);
557 ASSERT_TRUE(isa<CallInst>(BFn->user_back()));
558 ASSERT_EQ(BFn->user_back()->getNumUses(), 0U);
559
560 Builder.restoreIP(OMPBuilder.CreateBarrier(Builder.saveIP(), OMPD_parallel,
561 false, false));
562 ASSERT_EQ(CBFn->getNumUses(), 2U);
563 ASSERT_EQ(BFn->getNumUses(), 1U);
564 ASSERT_TRUE(CBFn->user_back() != CheckedBarrier);
565 ASSERT_TRUE(isa<CallInst>(CBFn->user_back()));
566 ASSERT_EQ(CBFn->user_back()->getNumUses(), 0U);
567 };
568
569 auto PrivCB = [&](InsertPointTy, InsertPointTy, Value &V,
570 Value *&) -> InsertPointTy {
571 ++NumPrivatizedVars;
572 llvm_unreachable("No privatization callback call expected!");
573 };
574
575 FunctionType *FakeDestructorTy =
576 FunctionType::get(Type::getVoidTy(Ctx), {Type::getInt32Ty(Ctx)},
577 /*isVarArg=*/false);
578 auto *FakeDestructor = Function::Create(
579 FakeDestructorTy, Function::ExternalLinkage, "fakeDestructor", M.get());
580
581 auto FiniCB = [&](InsertPointTy IP) {
582 ++NumFinalizationPoints;
583 Builder.restoreIP(IP);
584 Builder.CreateCall(FakeDestructor,
585 {Builder.getInt32(NumFinalizationPoints)});
586 };
587
588 IRBuilder<>::InsertPoint AfterIP = OMPBuilder.CreateParallel(
589 Loc, BodyGenCB, PrivCB, FiniCB, Builder.CreateIsNotNull(F->arg_begin()),
590 nullptr, OMP_PROC_BIND_default, true);
591
592 EXPECT_EQ(NumBodiesGenerated, 1U);
593 EXPECT_EQ(NumPrivatizedVars, 0U);
594 EXPECT_EQ(NumFinalizationPoints, 2U);
595 EXPECT_EQ(FakeDestructor->getNumUses(), 2U);
596
597 Builder.restoreIP(AfterIP);
598 Builder.CreateRetVoid();
599 OMPBuilder.finalize();
600
601 EXPECT_FALSE(verifyModule(*M, &errs()));
602
603 BasicBlock *ExitBB = nullptr;
604 for (const User *Usr : FakeDestructor->users()) {
605 const CallInst *CI = dyn_cast<CallInst>(Usr);
606 ASSERT_EQ(CI->getCalledFunction(), FakeDestructor);
607 ASSERT_TRUE(isa<BranchInst>(CI->getNextNode()));
608 ASSERT_EQ(CI->getNextNode()->getNumSuccessors(), 1U);
609 if (ExitBB)
610 ASSERT_EQ(CI->getNextNode()->getSuccessor(0), ExitBB);
611 else
612 ExitBB = CI->getNextNode()->getSuccessor(0);
613 ASSERT_EQ(ExitBB->size(), 1U);
614 if (!isa<ReturnInst>(ExitBB->front())) {
615 ASSERT_TRUE(isa<BranchInst>(ExitBB->front()));
616 ASSERT_EQ(cast<BranchInst>(ExitBB->front()).getNumSuccessors(), 1U);
617 ASSERT_TRUE(isa<ReturnInst>(
618 cast<BranchInst>(ExitBB->front()).getSuccessor(0)->front()));
619 }
620 }
621 }
622
TEST_F(OpenMPIRBuilderTest,MasterDirective)623 TEST_F(OpenMPIRBuilderTest, MasterDirective) {
624 using InsertPointTy = OpenMPIRBuilder::InsertPointTy;
625 OpenMPIRBuilder OMPBuilder(*M);
626 OMPBuilder.initialize();
627 F->setName("func");
628 IRBuilder<> Builder(BB);
629
630 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});
631
632 AllocaInst *PrivAI = nullptr;
633
634 BasicBlock *EntryBB = nullptr;
635 BasicBlock *ExitBB = nullptr;
636 BasicBlock *ThenBB = nullptr;
637
638 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
639 BasicBlock &FiniBB) {
640 if (AllocaIP.isSet())
641 Builder.restoreIP(AllocaIP);
642 else
643 Builder.SetInsertPoint(&*(F->getEntryBlock().getFirstInsertionPt()));
644 PrivAI = Builder.CreateAlloca(F->arg_begin()->getType());
645 Builder.CreateStore(F->arg_begin(), PrivAI);
646
647 llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock();
648 llvm::Instruction *CodeGenIPInst = &*CodeGenIP.getPoint();
649 EXPECT_EQ(CodeGenIPBB->getTerminator(), CodeGenIPInst);
650
651 Builder.restoreIP(CodeGenIP);
652
653 // collect some info for checks later
654 ExitBB = FiniBB.getUniqueSuccessor();
655 ThenBB = Builder.GetInsertBlock();
656 EntryBB = ThenBB->getUniquePredecessor();
657
658 // simple instructions for body
659 Value *PrivLoad = Builder.CreateLoad(PrivAI, "local.use");
660 Builder.CreateICmpNE(F->arg_begin(), PrivLoad);
661 };
662
663 auto FiniCB = [&](InsertPointTy IP) {
664 BasicBlock *IPBB = IP.getBlock();
665 EXPECT_NE(IPBB->end(), IP.getPoint());
666 };
667
668 Builder.restoreIP(OMPBuilder.CreateMaster(Builder, BodyGenCB, FiniCB));
669 Value *EntryBBTI = EntryBB->getTerminator();
670 EXPECT_NE(EntryBBTI, nullptr);
671 EXPECT_TRUE(isa<BranchInst>(EntryBBTI));
672 BranchInst *EntryBr = cast<BranchInst>(EntryBB->getTerminator());
673 EXPECT_TRUE(EntryBr->isConditional());
674 EXPECT_EQ(EntryBr->getSuccessor(0), ThenBB);
675 EXPECT_EQ(ThenBB->getUniqueSuccessor(), ExitBB);
676 EXPECT_EQ(EntryBr->getSuccessor(1), ExitBB);
677
678 CmpInst *CondInst = cast<CmpInst>(EntryBr->getCondition());
679 EXPECT_TRUE(isa<CallInst>(CondInst->getOperand(0)));
680
681 CallInst *MasterEntryCI = cast<CallInst>(CondInst->getOperand(0));
682 EXPECT_EQ(MasterEntryCI->getNumArgOperands(), 2U);
683 EXPECT_EQ(MasterEntryCI->getCalledFunction()->getName(), "__kmpc_master");
684 EXPECT_TRUE(isa<GlobalVariable>(MasterEntryCI->getArgOperand(0)));
685
686 CallInst *MasterEndCI = nullptr;
687 for (auto &FI : *ThenBB) {
688 Instruction *cur = &FI;
689 if (isa<CallInst>(cur)) {
690 MasterEndCI = cast<CallInst>(cur);
691 if (MasterEndCI->getCalledFunction()->getName() == "__kmpc_end_master")
692 break;
693 MasterEndCI = nullptr;
694 }
695 }
696 EXPECT_NE(MasterEndCI, nullptr);
697 EXPECT_EQ(MasterEndCI->getNumArgOperands(), 2U);
698 EXPECT_TRUE(isa<GlobalVariable>(MasterEndCI->getArgOperand(0)));
699 EXPECT_EQ(MasterEndCI->getArgOperand(1), MasterEntryCI->getArgOperand(1));
700 }
701
TEST_F(OpenMPIRBuilderTest,CriticalDirective)702 TEST_F(OpenMPIRBuilderTest, CriticalDirective) {
703 using InsertPointTy = OpenMPIRBuilder::InsertPointTy;
704 OpenMPIRBuilder OMPBuilder(*M);
705 OMPBuilder.initialize();
706 F->setName("func");
707 IRBuilder<> Builder(BB);
708
709 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});
710
711 AllocaInst *PrivAI = Builder.CreateAlloca(F->arg_begin()->getType());
712
713 BasicBlock *EntryBB = nullptr;
714
715 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
716 BasicBlock &FiniBB) {
717 // collect some info for checks later
718 EntryBB = FiniBB.getUniquePredecessor();
719
720 // actual start for bodyCB
721 llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock();
722 llvm::Instruction *CodeGenIPInst = &*CodeGenIP.getPoint();
723 EXPECT_EQ(CodeGenIPBB->getTerminator(), CodeGenIPInst);
724 EXPECT_EQ(EntryBB, CodeGenIPBB);
725
726 // body begin
727 Builder.restoreIP(CodeGenIP);
728 Builder.CreateStore(F->arg_begin(), PrivAI);
729 Value *PrivLoad = Builder.CreateLoad(PrivAI, "local.use");
730 Builder.CreateICmpNE(F->arg_begin(), PrivLoad);
731 };
732
733 auto FiniCB = [&](InsertPointTy IP) {
734 BasicBlock *IPBB = IP.getBlock();
735 EXPECT_NE(IPBB->end(), IP.getPoint());
736 };
737
738 Builder.restoreIP(OMPBuilder.CreateCritical(Builder, BodyGenCB, FiniCB,
739 "testCRT", nullptr));
740
741 Value *EntryBBTI = EntryBB->getTerminator();
742 EXPECT_EQ(EntryBBTI, nullptr);
743
744 CallInst *CriticalEntryCI = nullptr;
745 for (auto &EI : *EntryBB) {
746 Instruction *cur = &EI;
747 if (isa<CallInst>(cur)) {
748 CriticalEntryCI = cast<CallInst>(cur);
749 if (CriticalEntryCI->getCalledFunction()->getName() == "__kmpc_critical")
750 break;
751 CriticalEntryCI = nullptr;
752 }
753 }
754 EXPECT_NE(CriticalEntryCI, nullptr);
755 EXPECT_EQ(CriticalEntryCI->getNumArgOperands(), 3U);
756 EXPECT_EQ(CriticalEntryCI->getCalledFunction()->getName(), "__kmpc_critical");
757 EXPECT_TRUE(isa<GlobalVariable>(CriticalEntryCI->getArgOperand(0)));
758
759 CallInst *CriticalEndCI = nullptr;
760 for (auto &FI : *EntryBB) {
761 Instruction *cur = &FI;
762 if (isa<CallInst>(cur)) {
763 CriticalEndCI = cast<CallInst>(cur);
764 if (CriticalEndCI->getCalledFunction()->getName() ==
765 "__kmpc_end_critical")
766 break;
767 CriticalEndCI = nullptr;
768 }
769 }
770 EXPECT_NE(CriticalEndCI, nullptr);
771 EXPECT_EQ(CriticalEndCI->getNumArgOperands(), 3U);
772 EXPECT_TRUE(isa<GlobalVariable>(CriticalEndCI->getArgOperand(0)));
773 EXPECT_EQ(CriticalEndCI->getArgOperand(1), CriticalEntryCI->getArgOperand(1));
774 PointerType *CriticalNamePtrTy =
775 PointerType::getUnqual(ArrayType::get(Type::getInt32Ty(Ctx), 8));
776 EXPECT_EQ(CriticalEndCI->getArgOperand(2), CriticalEntryCI->getArgOperand(2));
777 EXPECT_EQ(CriticalEndCI->getArgOperand(2)->getType(), CriticalNamePtrTy);
778 }
779
TEST_F(OpenMPIRBuilderTest,CopyinBlocks)780 TEST_F(OpenMPIRBuilderTest, CopyinBlocks) {
781 OpenMPIRBuilder OMPBuilder(*M);
782 OMPBuilder.initialize();
783 F->setName("func");
784 IRBuilder<> Builder(BB);
785
786 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});
787
788 IntegerType* Int32 = Type::getInt32Ty(M->getContext());
789 AllocaInst* MasterAddress = Builder.CreateAlloca(Int32->getPointerTo());
790 AllocaInst* PrivAddress = Builder.CreateAlloca(Int32->getPointerTo());
791
792 BasicBlock *EntryBB = BB;
793
794 OMPBuilder.CreateCopyinClauseBlocks(Builder.saveIP(), MasterAddress, PrivAddress, Int32, /*BranchtoEnd*/true);
795
796 BranchInst* EntryBr = dyn_cast_or_null<BranchInst>(EntryBB->getTerminator());
797
798 EXPECT_NE(EntryBr, nullptr);
799 EXPECT_TRUE(EntryBr->isConditional());
800
801 BasicBlock* NotMasterBB = EntryBr->getSuccessor(0);
802 BasicBlock* CopyinEnd = EntryBr->getSuccessor(1);
803 CmpInst* CMP = dyn_cast_or_null<CmpInst>(EntryBr->getCondition());
804
805 EXPECT_NE(CMP, nullptr);
806 EXPECT_NE(NotMasterBB, nullptr);
807 EXPECT_NE(CopyinEnd, nullptr);
808
809 BranchInst* NotMasterBr = dyn_cast_or_null<BranchInst>(NotMasterBB->getTerminator());
810 EXPECT_NE(NotMasterBr, nullptr);
811 EXPECT_FALSE(NotMasterBr->isConditional());
812 EXPECT_EQ(CopyinEnd,NotMasterBr->getSuccessor(0));
813 }
814
815 } // namespace
816