blob: e777149b30eefa9ee26736ae1e19ccd829df8b26 [file] [log] [blame]
Johannes Doerfertd23c6142019-11-05 18:57:44 -06001//===- 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"
Johannes Doerferte4add9722019-12-25 16:59:38 -060017#include "llvm/Transforms/Utils/BasicBlockUtils.h"
Johannes Doerfertd23c6142019-11-05 18:57:44 -060018#include "gtest/gtest.h"
19
20using namespace llvm;
21using namespace omp;
22using namespace types;
23
24namespace {
25
26class OpenMPIRBuilderTest : public testing::Test {
27protected:
28 void SetUp() override {
29 M.reset(new Module("MyModule", Ctx));
30 FunctionType *FTy =
31 FunctionType::get(Type::getVoidTy(Ctx), {Type::getInt32Ty(Ctx)},
32 /*isVarArg=*/false);
33 F = Function::Create(FTy, Function::ExternalLinkage, "", M.get());
34 BB = BasicBlock::Create(Ctx, "", F);
35
36 DIBuilder DIB(*M);
37 auto File = DIB.createFile("test.dbg", "/");
38 auto CU =
39 DIB.createCompileUnit(dwarf::DW_LANG_C, File, "llvm-C", true, "", 0);
40 auto Type = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None));
41 auto SP = DIB.createFunction(
42 CU, "foo", "", File, 1, Type, 1, DINode::FlagZero,
43 DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized);
44 F->setSubprogram(SP);
45 auto Scope = DIB.createLexicalBlockFile(SP, File, 0);
46 DIB.finalize();
47 DL = DebugLoc::get(3, 7, Scope);
48 }
49
50 void TearDown() override {
51 BB = nullptr;
52 M.reset();
53 uninitializeTypes();
54 }
55
56 LLVMContext Ctx;
57 std::unique_ptr<Module> M;
58 Function *F;
59 BasicBlock *BB;
60 DebugLoc DL;
61};
62
63TEST_F(OpenMPIRBuilderTest, CreateBarrier) {
64 OpenMPIRBuilder OMPBuilder(*M);
65 OMPBuilder.initialize();
66
67 IRBuilder<> Builder(BB);
68
69 OMPBuilder.CreateBarrier({IRBuilder<>::InsertPoint()}, OMPD_for);
70 EXPECT_TRUE(M->global_empty());
71 EXPECT_EQ(M->size(), 1U);
72 EXPECT_EQ(F->size(), 1U);
73 EXPECT_EQ(BB->size(), 0U);
74
75 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP()});
76 OMPBuilder.CreateBarrier(Loc, OMPD_for);
77 EXPECT_FALSE(M->global_empty());
78 EXPECT_EQ(M->size(), 3U);
79 EXPECT_EQ(F->size(), 1U);
80 EXPECT_EQ(BB->size(), 2U);
81
82 CallInst *GTID = dyn_cast<CallInst>(&BB->front());
83 EXPECT_NE(GTID, nullptr);
84 EXPECT_EQ(GTID->getNumArgOperands(), 1U);
85 EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num");
86 EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory());
87 EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory());
88
89 CallInst *Barrier = dyn_cast<CallInst>(GTID->getNextNode());
90 EXPECT_NE(Barrier, nullptr);
91 EXPECT_EQ(Barrier->getNumArgOperands(), 2U);
92 EXPECT_EQ(Barrier->getCalledFunction()->getName(), "__kmpc_barrier");
93 EXPECT_FALSE(Barrier->getCalledFunction()->doesNotAccessMemory());
94 EXPECT_FALSE(Barrier->getCalledFunction()->doesNotFreeMemory());
95
96 EXPECT_EQ(cast<CallInst>(Barrier)->getArgOperand(1), GTID);
97
98 Builder.CreateUnreachable();
99 EXPECT_FALSE(verifyModule(*M));
100}
101
Johannes Doerfert000c6a52019-12-27 15:53:37 -0600102TEST_F(OpenMPIRBuilderTest, CreateCancel) {
103 using InsertPointTy = OpenMPIRBuilder::InsertPointTy;
104 OpenMPIRBuilder OMPBuilder(*M);
105 OMPBuilder.initialize();
106
107 BasicBlock *CBB = BasicBlock::Create(Ctx, "", F);
108 new UnreachableInst(Ctx, CBB);
109 auto FiniCB = [&](InsertPointTy IP) {
110 ASSERT_NE(IP.getBlock(), nullptr);
111 ASSERT_EQ(IP.getBlock()->end(), IP.getPoint());
112 BranchInst::Create(CBB, IP.getBlock());
113 };
114 OMPBuilder.pushFinalizationCB({FiniCB, OMPD_parallel, true});
115
116 IRBuilder<> Builder(BB);
117
118 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP()});
119 auto NewIP = OMPBuilder.CreateCancel(Loc, nullptr, OMPD_parallel);
120 Builder.restoreIP(NewIP);
121 EXPECT_FALSE(M->global_empty());
122 EXPECT_EQ(M->size(), 3U);
123 EXPECT_EQ(F->size(), 4U);
124 EXPECT_EQ(BB->size(), 4U);
125
126 CallInst *GTID = dyn_cast<CallInst>(&BB->front());
127 EXPECT_NE(GTID, nullptr);
128 EXPECT_EQ(GTID->getNumArgOperands(), 1U);
129 EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num");
130 EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory());
131 EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory());
132
133 CallInst *Cancel = dyn_cast<CallInst>(GTID->getNextNode());
134 EXPECT_NE(Cancel, nullptr);
135 EXPECT_EQ(Cancel->getNumArgOperands(), 3U);
136 EXPECT_EQ(Cancel->getCalledFunction()->getName(), "__kmpc_cancel");
137 EXPECT_FALSE(Cancel->getCalledFunction()->doesNotAccessMemory());
138 EXPECT_FALSE(Cancel->getCalledFunction()->doesNotFreeMemory());
139 EXPECT_EQ(Cancel->getNumUses(), 1U);
140 Instruction *CancelBBTI = Cancel->getParent()->getTerminator();
141 EXPECT_EQ(CancelBBTI->getNumSuccessors(), 2U);
142 EXPECT_EQ(CancelBBTI->getSuccessor(0), NewIP.getBlock());
143 EXPECT_EQ(CancelBBTI->getSuccessor(1)->size(), 1U);
144 EXPECT_EQ(CancelBBTI->getSuccessor(1)->getTerminator()->getNumSuccessors(),
145 1U);
146 EXPECT_EQ(CancelBBTI->getSuccessor(1)->getTerminator()->getSuccessor(0),
147 CBB);
148
149 EXPECT_EQ(cast<CallInst>(Cancel)->getArgOperand(1), GTID);
150
151 OMPBuilder.popFinalizationCB();
152
153 Builder.CreateUnreachable();
154 EXPECT_FALSE(verifyModule(*M));
155}
156
157TEST_F(OpenMPIRBuilderTest, CreateCancelIfCond) {
158 using InsertPointTy = OpenMPIRBuilder::InsertPointTy;
159 OpenMPIRBuilder OMPBuilder(*M);
160 OMPBuilder.initialize();
161
162 BasicBlock *CBB = BasicBlock::Create(Ctx, "", F);
163 new UnreachableInst(Ctx, CBB);
164 auto FiniCB = [&](InsertPointTy IP) {
165 ASSERT_NE(IP.getBlock(), nullptr);
166 ASSERT_EQ(IP.getBlock()->end(), IP.getPoint());
167 BranchInst::Create(CBB, IP.getBlock());
168 };
169 OMPBuilder.pushFinalizationCB({FiniCB, OMPD_parallel, true});
170
171 IRBuilder<> Builder(BB);
172
173 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP()});
174 auto NewIP = OMPBuilder.CreateCancel(Loc, Builder.getTrue(), OMPD_parallel);
175 Builder.restoreIP(NewIP);
176 EXPECT_FALSE(M->global_empty());
177 EXPECT_EQ(M->size(), 3U);
178 EXPECT_EQ(F->size(), 7U);
179 EXPECT_EQ(BB->size(), 1U);
180 ASSERT_TRUE(isa<BranchInst>(BB->getTerminator()));
181 ASSERT_EQ(BB->getTerminator()->getNumSuccessors(), 2U);
182 BB = BB->getTerminator()->getSuccessor(0);
183 EXPECT_EQ(BB->size(), 4U);
184
185
186 CallInst *GTID = dyn_cast<CallInst>(&BB->front());
187 EXPECT_NE(GTID, nullptr);
188 EXPECT_EQ(GTID->getNumArgOperands(), 1U);
189 EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num");
190 EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory());
191 EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory());
192
193 CallInst *Cancel = dyn_cast<CallInst>(GTID->getNextNode());
194 EXPECT_NE(Cancel, nullptr);
195 EXPECT_EQ(Cancel->getNumArgOperands(), 3U);
196 EXPECT_EQ(Cancel->getCalledFunction()->getName(), "__kmpc_cancel");
197 EXPECT_FALSE(Cancel->getCalledFunction()->doesNotAccessMemory());
198 EXPECT_FALSE(Cancel->getCalledFunction()->doesNotFreeMemory());
199 EXPECT_EQ(Cancel->getNumUses(), 1U);
200 Instruction *CancelBBTI = Cancel->getParent()->getTerminator();
201 EXPECT_EQ(CancelBBTI->getNumSuccessors(), 2U);
202 EXPECT_EQ(CancelBBTI->getSuccessor(0)->size(), 1U);
203 EXPECT_EQ(CancelBBTI->getSuccessor(0)->getUniqueSuccessor(), NewIP.getBlock());
204 EXPECT_EQ(CancelBBTI->getSuccessor(1)->size(), 1U);
205 EXPECT_EQ(CancelBBTI->getSuccessor(1)->getTerminator()->getNumSuccessors(),
206 1U);
207 EXPECT_EQ(CancelBBTI->getSuccessor(1)->getTerminator()->getSuccessor(0),
208 CBB);
209
210 EXPECT_EQ(cast<CallInst>(Cancel)->getArgOperand(1), GTID);
211
212 OMPBuilder.popFinalizationCB();
213
214 Builder.CreateUnreachable();
215 EXPECT_FALSE(verifyModule(*M));
216}
217
Johannes Doerfertd23c6142019-11-05 18:57:44 -0600218TEST_F(OpenMPIRBuilderTest, CreateCancelBarrier) {
Johannes Doerferte4add9722019-12-25 16:59:38 -0600219 using InsertPointTy = OpenMPIRBuilder::InsertPointTy;
Johannes Doerfertd23c6142019-11-05 18:57:44 -0600220 OpenMPIRBuilder OMPBuilder(*M);
221 OMPBuilder.initialize();
222
223 BasicBlock *CBB = BasicBlock::Create(Ctx, "", F);
224 new UnreachableInst(Ctx, CBB);
Johannes Doerferte4add9722019-12-25 16:59:38 -0600225 auto FiniCB = [&](InsertPointTy IP) {
226 ASSERT_NE(IP.getBlock(), nullptr);
227 ASSERT_EQ(IP.getBlock()->end(), IP.getPoint());
Johannes Doerfertf9c3c5da2019-12-25 10:33:56 -0600228 BranchInst::Create(CBB, IP.getBlock());
229 };
Johannes Doerferte4add9722019-12-25 16:59:38 -0600230 OMPBuilder.pushFinalizationCB({FiniCB, OMPD_parallel, true});
Johannes Doerfertd23c6142019-11-05 18:57:44 -0600231
232 IRBuilder<> Builder(BB);
233
234 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP()});
235 auto NewIP = OMPBuilder.CreateBarrier(Loc, OMPD_for);
236 Builder.restoreIP(NewIP);
237 EXPECT_FALSE(M->global_empty());
238 EXPECT_EQ(M->size(), 3U);
Johannes Doerfertf9c3c5da2019-12-25 10:33:56 -0600239 EXPECT_EQ(F->size(), 4U);
Johannes Doerfertd23c6142019-11-05 18:57:44 -0600240 EXPECT_EQ(BB->size(), 4U);
241
242 CallInst *GTID = dyn_cast<CallInst>(&BB->front());
243 EXPECT_NE(GTID, nullptr);
244 EXPECT_EQ(GTID->getNumArgOperands(), 1U);
245 EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num");
246 EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory());
247 EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory());
248
249 CallInst *Barrier = dyn_cast<CallInst>(GTID->getNextNode());
250 EXPECT_NE(Barrier, nullptr);
251 EXPECT_EQ(Barrier->getNumArgOperands(), 2U);
252 EXPECT_EQ(Barrier->getCalledFunction()->getName(), "__kmpc_cancel_barrier");
253 EXPECT_FALSE(Barrier->getCalledFunction()->doesNotAccessMemory());
254 EXPECT_FALSE(Barrier->getCalledFunction()->doesNotFreeMemory());
255 EXPECT_EQ(Barrier->getNumUses(), 1U);
256 Instruction *BarrierBBTI = Barrier->getParent()->getTerminator();
257 EXPECT_EQ(BarrierBBTI->getNumSuccessors(), 2U);
258 EXPECT_EQ(BarrierBBTI->getSuccessor(0), NewIP.getBlock());
Johannes Doerferte4add9722019-12-25 16:59:38 -0600259 EXPECT_EQ(BarrierBBTI->getSuccessor(1)->size(), 1U);
Johannes Doerfertf9c3c5da2019-12-25 10:33:56 -0600260 EXPECT_EQ(BarrierBBTI->getSuccessor(1)->getTerminator()->getNumSuccessors(),
261 1U);
262 EXPECT_EQ(BarrierBBTI->getSuccessor(1)->getTerminator()->getSuccessor(0),
263 CBB);
Johannes Doerfertd23c6142019-11-05 18:57:44 -0600264
265 EXPECT_EQ(cast<CallInst>(Barrier)->getArgOperand(1), GTID);
266
Johannes Doerfertf9c3c5da2019-12-25 10:33:56 -0600267 OMPBuilder.popFinalizationCB();
268
Johannes Doerfertd23c6142019-11-05 18:57:44 -0600269 Builder.CreateUnreachable();
270 EXPECT_FALSE(verifyModule(*M));
271}
272
273TEST_F(OpenMPIRBuilderTest, DbgLoc) {
274 OpenMPIRBuilder OMPBuilder(*M);
275 OMPBuilder.initialize();
276 F->setName("func");
277
278 IRBuilder<> Builder(BB);
279
280 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});
281 OMPBuilder.CreateBarrier(Loc, OMPD_for);
282 CallInst *GTID = dyn_cast<CallInst>(&BB->front());
283 CallInst *Barrier = dyn_cast<CallInst>(GTID->getNextNode());
284 EXPECT_EQ(GTID->getDebugLoc(), DL);
285 EXPECT_EQ(Barrier->getDebugLoc(), DL);
286 EXPECT_TRUE(isa<GlobalVariable>(Barrier->getOperand(0)));
287 if (!isa<GlobalVariable>(Barrier->getOperand(0)))
288 return;
289 GlobalVariable *Ident = cast<GlobalVariable>(Barrier->getOperand(0));
290 EXPECT_TRUE(Ident->hasInitializer());
291 if (!Ident->hasInitializer())
292 return;
293 Constant *Initializer = Ident->getInitializer();
294 EXPECT_TRUE(
295 isa<GlobalVariable>(Initializer->getOperand(4)->stripPointerCasts()));
296 GlobalVariable *SrcStrGlob =
297 cast<GlobalVariable>(Initializer->getOperand(4)->stripPointerCasts());
298 if (!SrcStrGlob)
299 return;
300 EXPECT_TRUE(isa<ConstantDataArray>(SrcStrGlob->getInitializer()));
301 ConstantDataArray *SrcSrc =
302 dyn_cast<ConstantDataArray>(SrcStrGlob->getInitializer());
303 if (!SrcSrc)
304 return;
305 EXPECT_EQ(SrcSrc->getAsCString(), ";test.dbg;foo;3;7;;");
306}
Johannes Doerferte4add9722019-12-25 16:59:38 -0600307
308TEST_F(OpenMPIRBuilderTest, ParallelSimple) {
309 using InsertPointTy = OpenMPIRBuilder::InsertPointTy;
310 OpenMPIRBuilder OMPBuilder(*M);
311 OMPBuilder.initialize();
312 F->setName("func");
313 IRBuilder<> Builder(BB);
314
315 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});
316
317 AllocaInst *PrivAI = nullptr;
318
319 unsigned NumBodiesGenerated = 0;
320 unsigned NumPrivatizedVars = 0;
321 unsigned NumFinalizationPoints = 0;
322
323 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
324 BasicBlock &ContinuationIP) {
325 ++NumBodiesGenerated;
326
327 Builder.restoreIP(AllocaIP);
328 PrivAI = Builder.CreateAlloca(F->arg_begin()->getType());
329 Builder.CreateStore(F->arg_begin(), PrivAI);
330
331 Builder.restoreIP(CodeGenIP);
332 Value *PrivLoad = Builder.CreateLoad(PrivAI, "local.use");
333 Value *Cmp = Builder.CreateICmpNE(F->arg_begin(), PrivLoad);
334 Instruction *ThenTerm, *ElseTerm;
335 SplitBlockAndInsertIfThenElse(Cmp, CodeGenIP.getBlock()->getTerminator(),
336 &ThenTerm, &ElseTerm);
337
338 Builder.SetInsertPoint(ThenTerm);
339 Builder.CreateBr(&ContinuationIP);
340 ThenTerm->eraseFromParent();
341 };
342
343 auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
344 Value &VPtr, Value *&ReplacementValue) -> InsertPointTy {
345 ++NumPrivatizedVars;
346
347 if (!isa<AllocaInst>(VPtr)) {
348 EXPECT_EQ(&VPtr, F->arg_begin());
349 ReplacementValue = &VPtr;
350 return CodeGenIP;
351 }
352
353 // Trivial copy (=firstprivate).
354 Builder.restoreIP(AllocaIP);
355 Type *VTy = VPtr.getType()->getPointerElementType();
356 Value *V = Builder.CreateLoad(VTy, &VPtr, VPtr.getName() + ".reload");
357 ReplacementValue = Builder.CreateAlloca(VTy, 0, VPtr.getName() + ".copy");
358 Builder.restoreIP(CodeGenIP);
359 Builder.CreateStore(V, ReplacementValue);
360 return CodeGenIP;
361 };
362
363 auto FiniCB = [&](InsertPointTy CodeGenIP) { ++NumFinalizationPoints; };
364
365 IRBuilder<>::InsertPoint AfterIP = OMPBuilder.CreateParallel(
Johannes Doerfert6c5d1f402019-12-25 18:15:36 -0600366 Loc, BodyGenCB, PrivCB, FiniCB, nullptr, nullptr, OMP_PROC_BIND_default, false);
Johannes Doerferte4add9722019-12-25 16:59:38 -0600367
368 EXPECT_EQ(NumBodiesGenerated, 1U);
369 EXPECT_EQ(NumPrivatizedVars, 1U);
370 EXPECT_EQ(NumFinalizationPoints, 1U);
371
372 Builder.restoreIP(AfterIP);
373 Builder.CreateRetVoid();
374
375 EXPECT_NE(PrivAI, nullptr);
376 Function *OutlinedFn = PrivAI->getFunction();
377 EXPECT_NE(F, OutlinedFn);
378 EXPECT_FALSE(verifyModule(*M));
379
380 EXPECT_TRUE(OutlinedFn->hasInternalLinkage());
381 EXPECT_EQ(OutlinedFn->arg_size(), 3U);
382
383 EXPECT_EQ(&OutlinedFn->getEntryBlock(), PrivAI->getParent());
384 EXPECT_EQ(OutlinedFn->getNumUses(), 1U);
385 User *Usr = OutlinedFn->user_back();
386 ASSERT_TRUE(isa<ConstantExpr>(Usr));
387 CallInst *ForkCI = dyn_cast<CallInst>(Usr->user_back());
388 ASSERT_NE(ForkCI, nullptr);
389
390 EXPECT_EQ(ForkCI->getCalledFunction()->getName(), "__kmpc_fork_call");
391 EXPECT_EQ(ForkCI->getNumArgOperands(), 4U);
392 EXPECT_TRUE(isa<GlobalVariable>(ForkCI->getArgOperand(0)));
393 EXPECT_EQ(ForkCI->getArgOperand(1),
394 ConstantInt::get(Type::getInt32Ty(Ctx), 1U));
395 EXPECT_EQ(ForkCI->getArgOperand(2), Usr);
396 EXPECT_EQ(ForkCI->getArgOperand(3), F->arg_begin());
397}
398
399TEST_F(OpenMPIRBuilderTest, ParallelIfCond) {
400 using InsertPointTy = OpenMPIRBuilder::InsertPointTy;
401 OpenMPIRBuilder OMPBuilder(*M);
402 OMPBuilder.initialize();
403 F->setName("func");
404 IRBuilder<> Builder(BB);
405
406 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});
407
408 AllocaInst *PrivAI = nullptr;
409
410 unsigned NumBodiesGenerated = 0;
411 unsigned NumPrivatizedVars = 0;
412 unsigned NumFinalizationPoints = 0;
413
414 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
415 BasicBlock &ContinuationIP) {
416 ++NumBodiesGenerated;
417
418 Builder.restoreIP(AllocaIP);
419 PrivAI = Builder.CreateAlloca(F->arg_begin()->getType());
420 Builder.CreateStore(F->arg_begin(), PrivAI);
421
422 Builder.restoreIP(CodeGenIP);
423 Value *PrivLoad = Builder.CreateLoad(PrivAI, "local.use");
424 Value *Cmp = Builder.CreateICmpNE(F->arg_begin(), PrivLoad);
425 Instruction *ThenTerm, *ElseTerm;
426 SplitBlockAndInsertIfThenElse(Cmp, CodeGenIP.getBlock()->getTerminator(),
427 &ThenTerm, &ElseTerm);
428
429 Builder.SetInsertPoint(ThenTerm);
430 Builder.CreateBr(&ContinuationIP);
431 ThenTerm->eraseFromParent();
432 };
433
434 auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
435 Value &VPtr, Value *&ReplacementValue) -> InsertPointTy {
436 ++NumPrivatizedVars;
437
438 if (!isa<AllocaInst>(VPtr)) {
439 EXPECT_EQ(&VPtr, F->arg_begin());
440 ReplacementValue = &VPtr;
441 return CodeGenIP;
442 }
443
444 // Trivial copy (=firstprivate).
445 Builder.restoreIP(AllocaIP);
446 Type *VTy = VPtr.getType()->getPointerElementType();
447 Value *V = Builder.CreateLoad(VTy, &VPtr, VPtr.getName() + ".reload");
448 ReplacementValue = Builder.CreateAlloca(VTy, 0, VPtr.getName() + ".copy");
449 Builder.restoreIP(CodeGenIP);
450 Builder.CreateStore(V, ReplacementValue);
451 return CodeGenIP;
452 };
453
454 auto FiniCB = [&](InsertPointTy CodeGenIP) {
455 ++NumFinalizationPoints;
456 // No destructors.
457 };
458
459 IRBuilder<>::InsertPoint AfterIP = OMPBuilder.CreateParallel(
460 Loc, BodyGenCB, PrivCB, FiniCB, Builder.CreateIsNotNull(F->arg_begin()),
Johannes Doerfert6c5d1f402019-12-25 18:15:36 -0600461 nullptr, OMP_PROC_BIND_default, false);
Johannes Doerferte4add9722019-12-25 16:59:38 -0600462
463 EXPECT_EQ(NumBodiesGenerated, 1U);
464 EXPECT_EQ(NumPrivatizedVars, 1U);
465 EXPECT_EQ(NumFinalizationPoints, 1U);
466
467 Builder.restoreIP(AfterIP);
468 Builder.CreateRetVoid();
469
470 EXPECT_NE(PrivAI, nullptr);
471 Function *OutlinedFn = PrivAI->getFunction();
472 EXPECT_NE(F, OutlinedFn);
473 EXPECT_FALSE(verifyModule(*M, &errs()));
474
475 EXPECT_TRUE(OutlinedFn->hasInternalLinkage());
476 EXPECT_EQ(OutlinedFn->arg_size(), 3U);
477
478 EXPECT_EQ(&OutlinedFn->getEntryBlock(), PrivAI->getParent());
479 ASSERT_EQ(OutlinedFn->getNumUses(), 2U);
480
481 CallInst *DirectCI = nullptr;
482 CallInst *ForkCI = nullptr;
483 for (User *Usr : OutlinedFn->users()) {
484 if (isa<CallInst>(Usr)) {
485 ASSERT_EQ(DirectCI, nullptr);
486 DirectCI = cast<CallInst>(Usr);
487 } else {
488 ASSERT_TRUE(isa<ConstantExpr>(Usr));
489 ASSERT_EQ(Usr->getNumUses(), 1U);
490 ASSERT_TRUE(isa<CallInst>(Usr->user_back()));
491 ForkCI = cast<CallInst>(Usr->user_back());
492 }
493 }
494
495 EXPECT_EQ(ForkCI->getCalledFunction()->getName(), "__kmpc_fork_call");
496 EXPECT_EQ(ForkCI->getNumArgOperands(), 4U);
497 EXPECT_TRUE(isa<GlobalVariable>(ForkCI->getArgOperand(0)));
498 EXPECT_EQ(ForkCI->getArgOperand(1),
499 ConstantInt::get(Type::getInt32Ty(Ctx), 1));
500 EXPECT_EQ(ForkCI->getArgOperand(3), F->arg_begin());
501
502 EXPECT_EQ(DirectCI->getCalledFunction(), OutlinedFn);
503 EXPECT_EQ(DirectCI->getNumArgOperands(), 3U);
504 EXPECT_TRUE(isa<AllocaInst>(DirectCI->getArgOperand(0)));
505 EXPECT_TRUE(isa<AllocaInst>(DirectCI->getArgOperand(1)));
506 EXPECT_EQ(DirectCI->getArgOperand(2), F->arg_begin());
507}
508
509TEST_F(OpenMPIRBuilderTest, ParallelCancelBarrier) {
510 using InsertPointTy = OpenMPIRBuilder::InsertPointTy;
511 OpenMPIRBuilder OMPBuilder(*M);
512 OMPBuilder.initialize();
513 F->setName("func");
514 IRBuilder<> Builder(BB);
515
516 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});
517
518 unsigned NumBodiesGenerated = 0;
519 unsigned NumPrivatizedVars = 0;
520 unsigned NumFinalizationPoints = 0;
521
522 CallInst *CheckedBarrier = nullptr;
523 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
524 BasicBlock &ContinuationIP) {
525 ++NumBodiesGenerated;
526
527 Builder.restoreIP(CodeGenIP);
528
529 // Create three barriers, two cancel barriers but only one checked.
530 Function *CBFn, *BFn;
531
532 Builder.restoreIP(
533 OMPBuilder.CreateBarrier(Builder.saveIP(), OMPD_parallel));
534
535 CBFn = M->getFunction("__kmpc_cancel_barrier");
536 BFn = M->getFunction("__kmpc_barrier");
537 ASSERT_NE(CBFn, nullptr);
538 ASSERT_EQ(BFn, nullptr);
539 ASSERT_EQ(CBFn->getNumUses(), 1U);
540 ASSERT_TRUE(isa<CallInst>(CBFn->user_back()));
541 ASSERT_EQ(CBFn->user_back()->getNumUses(), 1U);
542 CheckedBarrier = cast<CallInst>(CBFn->user_back());
543
544 Builder.restoreIP(
545 OMPBuilder.CreateBarrier(Builder.saveIP(), OMPD_parallel, true));
546 CBFn = M->getFunction("__kmpc_cancel_barrier");
547 BFn = M->getFunction("__kmpc_barrier");
548 ASSERT_NE(CBFn, nullptr);
549 ASSERT_NE(BFn, nullptr);
550 ASSERT_EQ(CBFn->getNumUses(), 1U);
551 ASSERT_EQ(BFn->getNumUses(), 1U);
552 ASSERT_TRUE(isa<CallInst>(BFn->user_back()));
553 ASSERT_EQ(BFn->user_back()->getNumUses(), 0U);
554
555 Builder.restoreIP(OMPBuilder.CreateBarrier(Builder.saveIP(), OMPD_parallel,
556 false, false));
557 ASSERT_EQ(CBFn->getNumUses(), 2U);
558 ASSERT_EQ(BFn->getNumUses(), 1U);
559 ASSERT_TRUE(CBFn->user_back() != CheckedBarrier);
560 ASSERT_TRUE(isa<CallInst>(CBFn->user_back()));
561 ASSERT_EQ(CBFn->user_back()->getNumUses(), 0U);
562 };
563
564 auto PrivCB = [&](InsertPointTy, InsertPointTy, Value &V,
565 Value *&) -> InsertPointTy {
566 ++NumPrivatizedVars;
567 llvm_unreachable("No privatization callback call expected!");
568 };
569
570 FunctionType *FakeDestructorTy =
571 FunctionType::get(Type::getVoidTy(Ctx), {Type::getInt32Ty(Ctx)},
572 /*isVarArg=*/false);
573 auto *FakeDestructor = Function::Create(
574 FakeDestructorTy, Function::ExternalLinkage, "fakeDestructor", M.get());
575
576 auto FiniCB = [&](InsertPointTy IP) {
577 ++NumFinalizationPoints;
578 Builder.restoreIP(IP);
579 Builder.CreateCall(FakeDestructor,
580 {Builder.getInt32(NumFinalizationPoints)});
581 };
582
583 IRBuilder<>::InsertPoint AfterIP = OMPBuilder.CreateParallel(
584 Loc, BodyGenCB, PrivCB, FiniCB, Builder.CreateIsNotNull(F->arg_begin()),
Johannes Doerfert6c5d1f402019-12-25 18:15:36 -0600585 nullptr, OMP_PROC_BIND_default, true);
Johannes Doerferte4add9722019-12-25 16:59:38 -0600586
587 EXPECT_EQ(NumBodiesGenerated, 1U);
588 EXPECT_EQ(NumPrivatizedVars, 0U);
589 EXPECT_EQ(NumFinalizationPoints, 2U);
590 EXPECT_EQ(FakeDestructor->getNumUses(), 2U);
591
592 Builder.restoreIP(AfterIP);
593 Builder.CreateRetVoid();
594
595 EXPECT_FALSE(verifyModule(*M, &errs()));
596
597 BasicBlock *ExitBB = nullptr;
598 for (const User *Usr : FakeDestructor->users()) {
599 const CallInst *CI = dyn_cast<CallInst>(Usr);
600 ASSERT_EQ(CI->getCalledFunction(), FakeDestructor);
601 ASSERT_TRUE(isa<BranchInst>(CI->getNextNode()));
602 ASSERT_EQ(CI->getNextNode()->getNumSuccessors(), 1U);
603 if (ExitBB)
604 ASSERT_EQ(CI->getNextNode()->getSuccessor(0), ExitBB);
605 else
606 ExitBB = CI->getNextNode()->getSuccessor(0);
607 ASSERT_EQ(ExitBB->size(), 1U);
608 ASSERT_TRUE(isa<ReturnInst>(ExitBB->front()));
609 }
610}
611
Johannes Doerfertd23c6142019-11-05 18:57:44 -0600612} // namespace