blob: c6a51f6b1af2aa3d0ae60306815ff9a136a705f6 [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));
Johannes Doerfert10fedd92019-12-26 11:23:38 -0600379 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));
Johannes Doerferte4add9722019-12-25 16:59:38 -0600383
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
403TEST_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()),
Johannes Doerfert6c5d1f402019-12-25 18:15:36 -0600465 nullptr, OMP_PROC_BIND_default, false);
Johannes Doerferte4add9722019-12-25 16:59:38 -0600466
467 EXPECT_EQ(NumBodiesGenerated, 1U);
468 EXPECT_EQ(NumPrivatizedVars, 1U);
469 EXPECT_EQ(NumFinalizationPoints, 1U);
470
471 Builder.restoreIP(AfterIP);
472 Builder.CreateRetVoid();
473
474 EXPECT_NE(PrivAI, nullptr);
475 Function *OutlinedFn = PrivAI->getFunction();
476 EXPECT_NE(F, OutlinedFn);
477 EXPECT_FALSE(verifyModule(*M, &errs()));
478
479 EXPECT_TRUE(OutlinedFn->hasInternalLinkage());
480 EXPECT_EQ(OutlinedFn->arg_size(), 3U);
481
482 EXPECT_EQ(&OutlinedFn->getEntryBlock(), PrivAI->getParent());
483 ASSERT_EQ(OutlinedFn->getNumUses(), 2U);
484
485 CallInst *DirectCI = nullptr;
486 CallInst *ForkCI = nullptr;
487 for (User *Usr : OutlinedFn->users()) {
488 if (isa<CallInst>(Usr)) {
489 ASSERT_EQ(DirectCI, nullptr);
490 DirectCI = cast<CallInst>(Usr);
491 } else {
492 ASSERT_TRUE(isa<ConstantExpr>(Usr));
493 ASSERT_EQ(Usr->getNumUses(), 1U);
494 ASSERT_TRUE(isa<CallInst>(Usr->user_back()));
495 ForkCI = cast<CallInst>(Usr->user_back());
496 }
497 }
498
499 EXPECT_EQ(ForkCI->getCalledFunction()->getName(), "__kmpc_fork_call");
500 EXPECT_EQ(ForkCI->getNumArgOperands(), 4U);
501 EXPECT_TRUE(isa<GlobalVariable>(ForkCI->getArgOperand(0)));
502 EXPECT_EQ(ForkCI->getArgOperand(1),
503 ConstantInt::get(Type::getInt32Ty(Ctx), 1));
504 EXPECT_EQ(ForkCI->getArgOperand(3), F->arg_begin());
505
506 EXPECT_EQ(DirectCI->getCalledFunction(), OutlinedFn);
507 EXPECT_EQ(DirectCI->getNumArgOperands(), 3U);
508 EXPECT_TRUE(isa<AllocaInst>(DirectCI->getArgOperand(0)));
509 EXPECT_TRUE(isa<AllocaInst>(DirectCI->getArgOperand(1)));
510 EXPECT_EQ(DirectCI->getArgOperand(2), F->arg_begin());
511}
512
513TEST_F(OpenMPIRBuilderTest, ParallelCancelBarrier) {
514 using InsertPointTy = OpenMPIRBuilder::InsertPointTy;
515 OpenMPIRBuilder OMPBuilder(*M);
516 OMPBuilder.initialize();
517 F->setName("func");
518 IRBuilder<> Builder(BB);
519
520 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});
521
522 unsigned NumBodiesGenerated = 0;
523 unsigned NumPrivatizedVars = 0;
524 unsigned NumFinalizationPoints = 0;
525
526 CallInst *CheckedBarrier = nullptr;
527 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
528 BasicBlock &ContinuationIP) {
529 ++NumBodiesGenerated;
530
531 Builder.restoreIP(CodeGenIP);
532
533 // Create three barriers, two cancel barriers but only one checked.
534 Function *CBFn, *BFn;
535
536 Builder.restoreIP(
537 OMPBuilder.CreateBarrier(Builder.saveIP(), OMPD_parallel));
538
539 CBFn = M->getFunction("__kmpc_cancel_barrier");
540 BFn = M->getFunction("__kmpc_barrier");
541 ASSERT_NE(CBFn, nullptr);
542 ASSERT_EQ(BFn, nullptr);
543 ASSERT_EQ(CBFn->getNumUses(), 1U);
544 ASSERT_TRUE(isa<CallInst>(CBFn->user_back()));
545 ASSERT_EQ(CBFn->user_back()->getNumUses(), 1U);
546 CheckedBarrier = cast<CallInst>(CBFn->user_back());
547
548 Builder.restoreIP(
549 OMPBuilder.CreateBarrier(Builder.saveIP(), OMPD_parallel, true));
550 CBFn = M->getFunction("__kmpc_cancel_barrier");
551 BFn = M->getFunction("__kmpc_barrier");
552 ASSERT_NE(CBFn, nullptr);
553 ASSERT_NE(BFn, nullptr);
554 ASSERT_EQ(CBFn->getNumUses(), 1U);
555 ASSERT_EQ(BFn->getNumUses(), 1U);
556 ASSERT_TRUE(isa<CallInst>(BFn->user_back()));
557 ASSERT_EQ(BFn->user_back()->getNumUses(), 0U);
558
559 Builder.restoreIP(OMPBuilder.CreateBarrier(Builder.saveIP(), OMPD_parallel,
560 false, false));
561 ASSERT_EQ(CBFn->getNumUses(), 2U);
562 ASSERT_EQ(BFn->getNumUses(), 1U);
563 ASSERT_TRUE(CBFn->user_back() != CheckedBarrier);
564 ASSERT_TRUE(isa<CallInst>(CBFn->user_back()));
565 ASSERT_EQ(CBFn->user_back()->getNumUses(), 0U);
566 };
567
568 auto PrivCB = [&](InsertPointTy, InsertPointTy, Value &V,
569 Value *&) -> InsertPointTy {
570 ++NumPrivatizedVars;
571 llvm_unreachable("No privatization callback call expected!");
572 };
573
574 FunctionType *FakeDestructorTy =
575 FunctionType::get(Type::getVoidTy(Ctx), {Type::getInt32Ty(Ctx)},
576 /*isVarArg=*/false);
577 auto *FakeDestructor = Function::Create(
578 FakeDestructorTy, Function::ExternalLinkage, "fakeDestructor", M.get());
579
580 auto FiniCB = [&](InsertPointTy IP) {
581 ++NumFinalizationPoints;
582 Builder.restoreIP(IP);
583 Builder.CreateCall(FakeDestructor,
584 {Builder.getInt32(NumFinalizationPoints)});
585 };
586
587 IRBuilder<>::InsertPoint AfterIP = OMPBuilder.CreateParallel(
588 Loc, BodyGenCB, PrivCB, FiniCB, Builder.CreateIsNotNull(F->arg_begin()),
Johannes Doerfert6c5d1f402019-12-25 18:15:36 -0600589 nullptr, OMP_PROC_BIND_default, true);
Johannes Doerferte4add9722019-12-25 16:59:38 -0600590
591 EXPECT_EQ(NumBodiesGenerated, 1U);
592 EXPECT_EQ(NumPrivatizedVars, 0U);
593 EXPECT_EQ(NumFinalizationPoints, 2U);
594 EXPECT_EQ(FakeDestructor->getNumUses(), 2U);
595
596 Builder.restoreIP(AfterIP);
597 Builder.CreateRetVoid();
598
599 EXPECT_FALSE(verifyModule(*M, &errs()));
600
601 BasicBlock *ExitBB = nullptr;
602 for (const User *Usr : FakeDestructor->users()) {
603 const CallInst *CI = dyn_cast<CallInst>(Usr);
604 ASSERT_EQ(CI->getCalledFunction(), FakeDestructor);
605 ASSERT_TRUE(isa<BranchInst>(CI->getNextNode()));
606 ASSERT_EQ(CI->getNextNode()->getNumSuccessors(), 1U);
607 if (ExitBB)
608 ASSERT_EQ(CI->getNextNode()->getSuccessor(0), ExitBB);
609 else
610 ExitBB = CI->getNextNode()->getSuccessor(0);
611 ASSERT_EQ(ExitBB->size(), 1U);
612 ASSERT_TRUE(isa<ReturnInst>(ExitBB->front()));
613 }
614}
615
Johannes Doerfertd23c6142019-11-05 18:57:44 -0600616} // namespace