blob: 4bbd9667c4c1a767c3c401041382c6d4795ab0af [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();
Johannes Doerfert70cac412020-02-12 20:52:23 -060099 EXPECT_FALSE(verifyModule(*M, &errs()));
Johannes Doerfertd23c6142019-11-05 18:57:44 -0600100}
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();
Johannes Doerfert70cac412020-02-12 20:52:23 -0600154 EXPECT_FALSE(verifyModule(*M, &errs()));
Johannes Doerfert000c6a52019-12-27 15:53:37 -0600155}
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();
Johannes Doerfert70cac412020-02-12 20:52:23 -0600215 EXPECT_FALSE(verifyModule(*M, &errs()));
Johannes Doerfert000c6a52019-12-27 15:53:37 -0600216}
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();
Johannes Doerfert70cac412020-02-12 20:52:23 -0600270 EXPECT_FALSE(verifyModule(*M, &errs()));
Johannes Doerfertd23c6142019-11-05 18:57:44 -0600271}
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
Johannes Doerfert70cac412020-02-12 20:52:23 -0600365 IRBuilder<>::InsertPoint AfterIP =
366 OMPBuilder.CreateParallel(Loc, BodyGenCB, PrivCB, FiniCB, nullptr,
367 nullptr, OMP_PROC_BIND_default, false);
Johannes Doerferte4add9722019-12-25 16:59:38 -0600368 EXPECT_EQ(NumBodiesGenerated, 1U);
369 EXPECT_EQ(NumPrivatizedVars, 1U);
370 EXPECT_EQ(NumFinalizationPoints, 1U);
371
372 Builder.restoreIP(AfterIP);
373 Builder.CreateRetVoid();
374
Johannes Doerfert70cac412020-02-12 20:52:23 -0600375 OMPBuilder.finalize();
376
Johannes Doerferte4add9722019-12-25 16:59:38 -0600377 EXPECT_NE(PrivAI, nullptr);
378 Function *OutlinedFn = PrivAI->getFunction();
379 EXPECT_NE(F, OutlinedFn);
Johannes Doerfert70cac412020-02-12 20:52:23 -0600380 EXPECT_FALSE(verifyModule(*M, &errs()));
Johannes Doerfert10fedd92019-12-26 11:23:38 -0600381 EXPECT_TRUE(OutlinedFn->hasFnAttribute(Attribute::NoUnwind));
382 EXPECT_TRUE(OutlinedFn->hasFnAttribute(Attribute::NoRecurse));
383 EXPECT_TRUE(OutlinedFn->hasParamAttribute(0, Attribute::NoAlias));
384 EXPECT_TRUE(OutlinedFn->hasParamAttribute(1, Attribute::NoAlias));
Johannes Doerferte4add9722019-12-25 16:59:38 -0600385
386 EXPECT_TRUE(OutlinedFn->hasInternalLinkage());
387 EXPECT_EQ(OutlinedFn->arg_size(), 3U);
388
389 EXPECT_EQ(&OutlinedFn->getEntryBlock(), PrivAI->getParent());
390 EXPECT_EQ(OutlinedFn->getNumUses(), 1U);
391 User *Usr = OutlinedFn->user_back();
392 ASSERT_TRUE(isa<ConstantExpr>(Usr));
393 CallInst *ForkCI = dyn_cast<CallInst>(Usr->user_back());
394 ASSERT_NE(ForkCI, nullptr);
395
396 EXPECT_EQ(ForkCI->getCalledFunction()->getName(), "__kmpc_fork_call");
397 EXPECT_EQ(ForkCI->getNumArgOperands(), 4U);
398 EXPECT_TRUE(isa<GlobalVariable>(ForkCI->getArgOperand(0)));
399 EXPECT_EQ(ForkCI->getArgOperand(1),
400 ConstantInt::get(Type::getInt32Ty(Ctx), 1U));
401 EXPECT_EQ(ForkCI->getArgOperand(2), Usr);
402 EXPECT_EQ(ForkCI->getArgOperand(3), F->arg_begin());
403}
404
405TEST_F(OpenMPIRBuilderTest, ParallelIfCond) {
406 using InsertPointTy = OpenMPIRBuilder::InsertPointTy;
407 OpenMPIRBuilder OMPBuilder(*M);
408 OMPBuilder.initialize();
409 F->setName("func");
410 IRBuilder<> Builder(BB);
411
412 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});
413
414 AllocaInst *PrivAI = nullptr;
415
416 unsigned NumBodiesGenerated = 0;
417 unsigned NumPrivatizedVars = 0;
418 unsigned NumFinalizationPoints = 0;
419
420 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
421 BasicBlock &ContinuationIP) {
422 ++NumBodiesGenerated;
423
424 Builder.restoreIP(AllocaIP);
425 PrivAI = Builder.CreateAlloca(F->arg_begin()->getType());
426 Builder.CreateStore(F->arg_begin(), PrivAI);
427
428 Builder.restoreIP(CodeGenIP);
429 Value *PrivLoad = Builder.CreateLoad(PrivAI, "local.use");
430 Value *Cmp = Builder.CreateICmpNE(F->arg_begin(), PrivLoad);
431 Instruction *ThenTerm, *ElseTerm;
432 SplitBlockAndInsertIfThenElse(Cmp, CodeGenIP.getBlock()->getTerminator(),
433 &ThenTerm, &ElseTerm);
434
435 Builder.SetInsertPoint(ThenTerm);
436 Builder.CreateBr(&ContinuationIP);
437 ThenTerm->eraseFromParent();
438 };
439
440 auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
441 Value &VPtr, Value *&ReplacementValue) -> InsertPointTy {
442 ++NumPrivatizedVars;
443
444 if (!isa<AllocaInst>(VPtr)) {
445 EXPECT_EQ(&VPtr, F->arg_begin());
446 ReplacementValue = &VPtr;
447 return CodeGenIP;
448 }
449
450 // Trivial copy (=firstprivate).
451 Builder.restoreIP(AllocaIP);
452 Type *VTy = VPtr.getType()->getPointerElementType();
453 Value *V = Builder.CreateLoad(VTy, &VPtr, VPtr.getName() + ".reload");
454 ReplacementValue = Builder.CreateAlloca(VTy, 0, VPtr.getName() + ".copy");
455 Builder.restoreIP(CodeGenIP);
456 Builder.CreateStore(V, ReplacementValue);
457 return CodeGenIP;
458 };
459
460 auto FiniCB = [&](InsertPointTy CodeGenIP) {
461 ++NumFinalizationPoints;
462 // No destructors.
463 };
464
465 IRBuilder<>::InsertPoint AfterIP = OMPBuilder.CreateParallel(
466 Loc, BodyGenCB, PrivCB, FiniCB, Builder.CreateIsNotNull(F->arg_begin()),
Johannes Doerfert6c5d1f402019-12-25 18:15:36 -0600467 nullptr, OMP_PROC_BIND_default, false);
Johannes Doerferte4add9722019-12-25 16:59:38 -0600468
469 EXPECT_EQ(NumBodiesGenerated, 1U);
470 EXPECT_EQ(NumPrivatizedVars, 1U);
471 EXPECT_EQ(NumFinalizationPoints, 1U);
472
473 Builder.restoreIP(AfterIP);
474 Builder.CreateRetVoid();
Johannes Doerfert70cac412020-02-12 20:52:23 -0600475 OMPBuilder.finalize();
Johannes Doerferte4add9722019-12-25 16:59:38 -0600476
477 EXPECT_NE(PrivAI, nullptr);
478 Function *OutlinedFn = PrivAI->getFunction();
479 EXPECT_NE(F, OutlinedFn);
480 EXPECT_FALSE(verifyModule(*M, &errs()));
481
482 EXPECT_TRUE(OutlinedFn->hasInternalLinkage());
483 EXPECT_EQ(OutlinedFn->arg_size(), 3U);
484
485 EXPECT_EQ(&OutlinedFn->getEntryBlock(), PrivAI->getParent());
486 ASSERT_EQ(OutlinedFn->getNumUses(), 2U);
487
488 CallInst *DirectCI = nullptr;
489 CallInst *ForkCI = nullptr;
490 for (User *Usr : OutlinedFn->users()) {
491 if (isa<CallInst>(Usr)) {
492 ASSERT_EQ(DirectCI, nullptr);
493 DirectCI = cast<CallInst>(Usr);
494 } else {
495 ASSERT_TRUE(isa<ConstantExpr>(Usr));
496 ASSERT_EQ(Usr->getNumUses(), 1U);
497 ASSERT_TRUE(isa<CallInst>(Usr->user_back()));
498 ForkCI = cast<CallInst>(Usr->user_back());
499 }
500 }
501
502 EXPECT_EQ(ForkCI->getCalledFunction()->getName(), "__kmpc_fork_call");
503 EXPECT_EQ(ForkCI->getNumArgOperands(), 4U);
504 EXPECT_TRUE(isa<GlobalVariable>(ForkCI->getArgOperand(0)));
505 EXPECT_EQ(ForkCI->getArgOperand(1),
506 ConstantInt::get(Type::getInt32Ty(Ctx), 1));
507 EXPECT_EQ(ForkCI->getArgOperand(3), F->arg_begin());
508
509 EXPECT_EQ(DirectCI->getCalledFunction(), OutlinedFn);
510 EXPECT_EQ(DirectCI->getNumArgOperands(), 3U);
511 EXPECT_TRUE(isa<AllocaInst>(DirectCI->getArgOperand(0)));
512 EXPECT_TRUE(isa<AllocaInst>(DirectCI->getArgOperand(1)));
513 EXPECT_EQ(DirectCI->getArgOperand(2), F->arg_begin());
514}
515
516TEST_F(OpenMPIRBuilderTest, ParallelCancelBarrier) {
517 using InsertPointTy = OpenMPIRBuilder::InsertPointTy;
518 OpenMPIRBuilder OMPBuilder(*M);
519 OMPBuilder.initialize();
520 F->setName("func");
521 IRBuilder<> Builder(BB);
522
523 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});
524
525 unsigned NumBodiesGenerated = 0;
526 unsigned NumPrivatizedVars = 0;
527 unsigned NumFinalizationPoints = 0;
528
529 CallInst *CheckedBarrier = nullptr;
530 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
531 BasicBlock &ContinuationIP) {
532 ++NumBodiesGenerated;
533
534 Builder.restoreIP(CodeGenIP);
535
536 // Create three barriers, two cancel barriers but only one checked.
537 Function *CBFn, *BFn;
538
539 Builder.restoreIP(
540 OMPBuilder.CreateBarrier(Builder.saveIP(), OMPD_parallel));
541
542 CBFn = M->getFunction("__kmpc_cancel_barrier");
543 BFn = M->getFunction("__kmpc_barrier");
544 ASSERT_NE(CBFn, nullptr);
545 ASSERT_EQ(BFn, nullptr);
546 ASSERT_EQ(CBFn->getNumUses(), 1U);
547 ASSERT_TRUE(isa<CallInst>(CBFn->user_back()));
548 ASSERT_EQ(CBFn->user_back()->getNumUses(), 1U);
549 CheckedBarrier = cast<CallInst>(CBFn->user_back());
550
551 Builder.restoreIP(
552 OMPBuilder.CreateBarrier(Builder.saveIP(), OMPD_parallel, true));
553 CBFn = M->getFunction("__kmpc_cancel_barrier");
554 BFn = M->getFunction("__kmpc_barrier");
555 ASSERT_NE(CBFn, nullptr);
556 ASSERT_NE(BFn, nullptr);
557 ASSERT_EQ(CBFn->getNumUses(), 1U);
558 ASSERT_EQ(BFn->getNumUses(), 1U);
559 ASSERT_TRUE(isa<CallInst>(BFn->user_back()));
560 ASSERT_EQ(BFn->user_back()->getNumUses(), 0U);
561
562 Builder.restoreIP(OMPBuilder.CreateBarrier(Builder.saveIP(), OMPD_parallel,
563 false, false));
564 ASSERT_EQ(CBFn->getNumUses(), 2U);
565 ASSERT_EQ(BFn->getNumUses(), 1U);
566 ASSERT_TRUE(CBFn->user_back() != CheckedBarrier);
567 ASSERT_TRUE(isa<CallInst>(CBFn->user_back()));
568 ASSERT_EQ(CBFn->user_back()->getNumUses(), 0U);
569 };
570
571 auto PrivCB = [&](InsertPointTy, InsertPointTy, Value &V,
572 Value *&) -> InsertPointTy {
573 ++NumPrivatizedVars;
574 llvm_unreachable("No privatization callback call expected!");
575 };
576
577 FunctionType *FakeDestructorTy =
578 FunctionType::get(Type::getVoidTy(Ctx), {Type::getInt32Ty(Ctx)},
579 /*isVarArg=*/false);
580 auto *FakeDestructor = Function::Create(
581 FakeDestructorTy, Function::ExternalLinkage, "fakeDestructor", M.get());
582
583 auto FiniCB = [&](InsertPointTy IP) {
584 ++NumFinalizationPoints;
585 Builder.restoreIP(IP);
586 Builder.CreateCall(FakeDestructor,
587 {Builder.getInt32(NumFinalizationPoints)});
588 };
589
590 IRBuilder<>::InsertPoint AfterIP = OMPBuilder.CreateParallel(
591 Loc, BodyGenCB, PrivCB, FiniCB, Builder.CreateIsNotNull(F->arg_begin()),
Johannes Doerfert6c5d1f402019-12-25 18:15:36 -0600592 nullptr, OMP_PROC_BIND_default, true);
Johannes Doerferte4add9722019-12-25 16:59:38 -0600593
594 EXPECT_EQ(NumBodiesGenerated, 1U);
595 EXPECT_EQ(NumPrivatizedVars, 0U);
596 EXPECT_EQ(NumFinalizationPoints, 2U);
597 EXPECT_EQ(FakeDestructor->getNumUses(), 2U);
598
599 Builder.restoreIP(AfterIP);
600 Builder.CreateRetVoid();
Johannes Doerfert70cac412020-02-12 20:52:23 -0600601 OMPBuilder.finalize();
Johannes Doerferte4add9722019-12-25 16:59:38 -0600602
603 EXPECT_FALSE(verifyModule(*M, &errs()));
604
605 BasicBlock *ExitBB = nullptr;
606 for (const User *Usr : FakeDestructor->users()) {
607 const CallInst *CI = dyn_cast<CallInst>(Usr);
608 ASSERT_EQ(CI->getCalledFunction(), FakeDestructor);
609 ASSERT_TRUE(isa<BranchInst>(CI->getNextNode()));
610 ASSERT_EQ(CI->getNextNode()->getNumSuccessors(), 1U);
611 if (ExitBB)
612 ASSERT_EQ(CI->getNextNode()->getSuccessor(0), ExitBB);
613 else
614 ExitBB = CI->getNextNode()->getSuccessor(0);
615 ASSERT_EQ(ExitBB->size(), 1U);
616 ASSERT_TRUE(isa<ReturnInst>(ExitBB->front()));
617 }
618}
619
Johannes Doerfertd23c6142019-11-05 18:57:44 -0600620} // namespace