blob: b356f6d66e17ea67a084ded9bfa3c2f4f367582a [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);
Johannes Doerfert3f3ec9c2020-02-13 00:39:55 -0600616 if (!isa<ReturnInst>(ExitBB->front())) {
617 ASSERT_TRUE(isa<BranchInst>(ExitBB->front()));
618 ASSERT_EQ(cast<BranchInst>(ExitBB->front()).getNumSuccessors(), 1U);
619 ASSERT_TRUE(isa<ReturnInst>(
620 cast<BranchInst>(ExitBB->front()).getSuccessor(0)->front()));
621 }
Johannes Doerferte4add9722019-12-25 16:59:38 -0600622 }
623}
624
Fady Ghanim7438059a2020-02-15 00:42:23 -0600625TEST_F(OpenMPIRBuilderTest, MasterDirective) {
626 using InsertPointTy = OpenMPIRBuilder::InsertPointTy;
627 OpenMPIRBuilder OMPBuilder(*M);
628 OMPBuilder.initialize();
629 F->setName("func");
630 IRBuilder<> Builder(BB);
631
632 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});
633
634 AllocaInst *PrivAI = nullptr;
635
636 BasicBlock *EntryBB = nullptr;
637 BasicBlock *ExitBB = nullptr;
638 BasicBlock *ThenBB = nullptr;
639
640 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
641 BasicBlock &FiniBB) {
642 if (AllocaIP.isSet())
643 Builder.restoreIP(AllocaIP);
644 else
645 Builder.SetInsertPoint(&*(F->getEntryBlock().getFirstInsertionPt()));
646 PrivAI = Builder.CreateAlloca(F->arg_begin()->getType());
647 Builder.CreateStore(F->arg_begin(), PrivAI);
648
649 llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock();
650 llvm::Instruction *CodeGenIPInst = &*CodeGenIP.getPoint();
651 EXPECT_EQ(CodeGenIPBB->getTerminator(), CodeGenIPInst);
652
653 Builder.restoreIP(CodeGenIP);
654
655 // collect some info for checks later
656 ExitBB = FiniBB.getUniqueSuccessor();
657 ThenBB = Builder.GetInsertBlock();
658 EntryBB = ThenBB->getUniquePredecessor();
659
660 // simple instructions for body
661 Value *PrivLoad = Builder.CreateLoad(PrivAI, "local.use");
662 Builder.CreateICmpNE(F->arg_begin(), PrivLoad);
663 };
664
665 auto FiniCB = [&](InsertPointTy IP) {
666 BasicBlock *IPBB = IP.getBlock();
667 EXPECT_NE(IPBB->end(), IP.getPoint());
668 };
669
670 Builder.restoreIP(OMPBuilder.CreateMaster(Builder, BodyGenCB, FiniCB));
671 Value *EntryBBTI = EntryBB->getTerminator();
672 EXPECT_NE(EntryBBTI, nullptr);
673 EXPECT_TRUE(isa<BranchInst>(EntryBBTI));
674 BranchInst *EntryBr = cast<BranchInst>(EntryBB->getTerminator());
675 EXPECT_TRUE(EntryBr->isConditional());
676 EXPECT_EQ(EntryBr->getSuccessor(0), ThenBB);
677 EXPECT_EQ(ThenBB->getUniqueSuccessor(), ExitBB);
678 EXPECT_EQ(EntryBr->getSuccessor(1), ExitBB);
679
680 CmpInst *CondInst = cast<CmpInst>(EntryBr->getCondition());
681 EXPECT_TRUE(isa<CallInst>(CondInst->getOperand(0)));
682
683 CallInst *MasterEntryCI = cast<CallInst>(CondInst->getOperand(0));
684 EXPECT_EQ(MasterEntryCI->getNumArgOperands(), 2U);
685 EXPECT_EQ(MasterEntryCI->getCalledFunction()->getName(), "__kmpc_master");
686 EXPECT_TRUE(isa<GlobalVariable>(MasterEntryCI->getArgOperand(0)));
687
688 CallInst *MasterEndCI = nullptr;
689 for (auto &FI : *ThenBB) {
690 Instruction *cur = &FI;
691 if (isa<CallInst>(cur)) {
692 MasterEndCI = cast<CallInst>(cur);
693 if (MasterEndCI->getCalledFunction()->getName() == "__kmpc_end_master")
694 break;
695 MasterEndCI = nullptr;
696 }
697 }
698 EXPECT_NE(MasterEndCI, nullptr);
699 EXPECT_EQ(MasterEndCI->getNumArgOperands(), 2U);
700 EXPECT_TRUE(isa<GlobalVariable>(MasterEndCI->getArgOperand(0)));
701 EXPECT_EQ(MasterEndCI->getArgOperand(1), MasterEntryCI->getArgOperand(1));
702}
703
704TEST_F(OpenMPIRBuilderTest, CriticalDirective) {
705 using InsertPointTy = OpenMPIRBuilder::InsertPointTy;
706 OpenMPIRBuilder OMPBuilder(*M);
707 OMPBuilder.initialize();
708 F->setName("func");
709 IRBuilder<> Builder(BB);
710
711 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});
712
713 AllocaInst *PrivAI = Builder.CreateAlloca(F->arg_begin()->getType());
714
715 BasicBlock *EntryBB = nullptr;
716
717 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
718 BasicBlock &FiniBB) {
719 // collect some info for checks later
720 EntryBB = FiniBB.getUniquePredecessor();
721
722 // actual start for bodyCB
723 llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock();
724 llvm::Instruction *CodeGenIPInst = &*CodeGenIP.getPoint();
725 EXPECT_EQ(CodeGenIPBB->getTerminator(), CodeGenIPInst);
726 EXPECT_EQ(EntryBB, CodeGenIPBB);
727
728 // body begin
729 Builder.restoreIP(CodeGenIP);
730 Builder.CreateStore(F->arg_begin(), PrivAI);
731 Value *PrivLoad = Builder.CreateLoad(PrivAI, "local.use");
732 Builder.CreateICmpNE(F->arg_begin(), PrivLoad);
733 };
734
735 auto FiniCB = [&](InsertPointTy IP) {
736 BasicBlock *IPBB = IP.getBlock();
737 EXPECT_NE(IPBB->end(), IP.getPoint());
738 };
739
740 Builder.restoreIP(OMPBuilder.CreateCritical(Builder, BodyGenCB, FiniCB,
741 "testCRT", nullptr));
742
743 Value *EntryBBTI = EntryBB->getTerminator();
744 EXPECT_EQ(EntryBBTI, nullptr);
745
746 CallInst *CriticalEntryCI = nullptr;
747 for (auto &EI : *EntryBB) {
748 Instruction *cur = &EI;
749 if (isa<CallInst>(cur)) {
750 CriticalEntryCI = cast<CallInst>(cur);
751 if (CriticalEntryCI->getCalledFunction()->getName() == "__kmpc_critical")
752 break;
753 CriticalEntryCI = nullptr;
754 }
755 }
756 EXPECT_NE(CriticalEntryCI, nullptr);
757 EXPECT_EQ(CriticalEntryCI->getNumArgOperands(), 3U);
758 EXPECT_EQ(CriticalEntryCI->getCalledFunction()->getName(), "__kmpc_critical");
759 EXPECT_TRUE(isa<GlobalVariable>(CriticalEntryCI->getArgOperand(0)));
760
761 CallInst *CriticalEndCI = nullptr;
762 for (auto &FI : *EntryBB) {
763 Instruction *cur = &FI;
764 if (isa<CallInst>(cur)) {
765 CriticalEndCI = cast<CallInst>(cur);
766 if (CriticalEndCI->getCalledFunction()->getName() ==
767 "__kmpc_end_critical")
768 break;
769 CriticalEndCI = nullptr;
770 }
771 }
772 EXPECT_NE(CriticalEndCI, nullptr);
773 EXPECT_EQ(CriticalEndCI->getNumArgOperands(), 3U);
774 EXPECT_TRUE(isa<GlobalVariable>(CriticalEndCI->getArgOperand(0)));
775 EXPECT_EQ(CriticalEndCI->getArgOperand(1), CriticalEntryCI->getArgOperand(1));
776 PointerType *CriticalNamePtrTy =
777 PointerType::getUnqual(ArrayType::get(Type::getInt32Ty(Ctx), 8));
778 EXPECT_EQ(CriticalEndCI->getArgOperand(2), CriticalEntryCI->getArgOperand(2));
779 EXPECT_EQ(CriticalEndCI->getArgOperand(2)->getType(), CriticalNamePtrTy);
780}
781
Johannes Doerfertd23c6142019-11-05 18:57:44 -0600782} // namespace