1 //===- llvm/unittest/IR/OpenMPIRBuilderTest.cpp - OpenMPIRBuilder tests ---===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/Frontend/OpenMP/OMPConstants.h"
10 #include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
11 #include "llvm/IR/BasicBlock.h"
12 #include "llvm/IR/DIBuilder.h"
13 #include "llvm/IR/Function.h"
14 #include "llvm/IR/InstIterator.h"
15 #include "llvm/IR/LLVMContext.h"
16 #include "llvm/IR/Module.h"
17 #include "llvm/IR/Verifier.h"
18 #include "llvm/Passes/PassBuilder.h"
19 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
20 #include "gtest/gtest.h"
27 /// Create an instruction that uses the values in \p Values. We use "printf"
28 /// just because it is often used for this purpose in test code, but it is never
30 static CallInst
*createPrintfCall(IRBuilder
<> &Builder
, StringRef FormatStr
,
31 ArrayRef
<Value
*> Values
) {
32 Module
*M
= Builder
.GetInsertBlock()->getParent()->getParent();
34 GlobalVariable
*GV
= Builder
.CreateGlobalString(FormatStr
, "", 0, M
);
35 Constant
*Zero
= ConstantInt::get(Type::getInt32Ty(M
->getContext()), 0);
36 Constant
*Indices
[] = {Zero
, Zero
};
37 Constant
*FormatStrConst
=
38 ConstantExpr::getInBoundsGetElementPtr(GV
->getValueType(), GV
, Indices
);
40 Function
*PrintfDecl
= M
->getFunction("printf");
42 GlobalValue::LinkageTypes Linkage
= Function::ExternalLinkage
;
43 FunctionType
*Ty
= FunctionType::get(Builder
.getInt32Ty(), true);
44 PrintfDecl
= Function::Create(Ty
, Linkage
, "printf", M
);
47 SmallVector
<Value
*, 4> Args
;
48 Args
.push_back(FormatStrConst
);
49 Args
.append(Values
.begin(), Values
.end());
50 return Builder
.CreateCall(PrintfDecl
, Args
);
53 /// Verify that blocks in \p RefOrder are corresponds to the depth-first visit
54 /// order the control flow of \p F.
56 /// This is an easy way to verify the branching structure of the CFG without
57 /// checking every branch instruction individually. For the CFG of a
58 /// CanonicalLoopInfo, the Cond BB's terminating branch's first edge is entering
59 /// the body, i.e. the DFS order corresponds to the execution order with one
61 static testing::AssertionResult
62 verifyDFSOrder(Function
*F
, ArrayRef
<BasicBlock
*> RefOrder
) {
63 ArrayRef
<BasicBlock
*>::iterator It
= RefOrder
.begin();
64 ArrayRef
<BasicBlock
*>::iterator E
= RefOrder
.end();
66 df_iterator_default_set
<BasicBlock
*, 16> Visited
;
67 auto DFS
= llvm::depth_first_ext(&F
->getEntryBlock(), Visited
);
69 BasicBlock
*Prev
= nullptr;
70 for (BasicBlock
*BB
: DFS
) {
71 if (It
!= E
&& BB
== *It
) {
78 return testing::AssertionSuccess();
80 return testing::AssertionFailure()
81 << "Did not find " << (*It
)->getName() << " in control flow";
82 return testing::AssertionFailure()
83 << "Expected " << Prev
->getName() << " before " << (*It
)->getName()
84 << " in control flow";
87 /// Verify that blocks in \p RefOrder are in the same relative order in the
88 /// linked lists of blocks in \p F. The linked list may contain additional
89 /// blocks in-between.
91 /// While the order in the linked list is not relevant for semantics, keeping
92 /// the order roughly in execution order makes its printout easier to read.
93 static testing::AssertionResult
94 verifyListOrder(Function
*F
, ArrayRef
<BasicBlock
*> RefOrder
) {
95 ArrayRef
<BasicBlock
*>::iterator It
= RefOrder
.begin();
96 ArrayRef
<BasicBlock
*>::iterator E
= RefOrder
.end();
98 BasicBlock
*Prev
= nullptr;
99 for (BasicBlock
&BB
: *F
) {
100 if (It
!= E
&& &BB
== *It
) {
107 return testing::AssertionSuccess();
109 return testing::AssertionFailure() << "Did not find " << (*It
)->getName()
110 << " in function " << F
->getName();
111 return testing::AssertionFailure()
112 << "Expected " << Prev
->getName() << " before " << (*It
)->getName()
113 << " in function " << F
->getName();
116 /// Populate Calls with call instructions calling the function with the given
117 /// FnID from the given function F.
118 static void findCalls(Function
*F
, omp::RuntimeFunction FnID
,
119 OpenMPIRBuilder
&OMPBuilder
,
120 SmallVectorImpl
<CallInst
*> &Calls
) {
121 Function
*Fn
= OMPBuilder
.getOrCreateRuntimeFunctionPtr(FnID
);
122 for (BasicBlock
&BB
: *F
) {
123 for (Instruction
&I
: BB
) {
124 auto *Call
= dyn_cast
<CallInst
>(&I
);
125 if (Call
&& Call
->getCalledFunction() == Fn
)
126 Calls
.push_back(Call
);
131 /// Assuming \p F contains only one call to the function with the given \p FnID,
132 /// return that call.
133 static CallInst
*findSingleCall(Function
*F
, omp::RuntimeFunction FnID
,
134 OpenMPIRBuilder
&OMPBuilder
) {
135 SmallVector
<CallInst
*, 1> Calls
;
136 findCalls(F
, FnID
, OMPBuilder
, Calls
);
137 EXPECT_EQ(1u, Calls
.size());
138 if (Calls
.size() != 1)
140 return Calls
.front();
143 static omp::ScheduleKind
getSchedKind(omp::OMPScheduleType SchedType
) {
144 switch (SchedType
& ~omp::OMPScheduleType::ModifierMask
) {
145 case omp::OMPScheduleType::BaseDynamicChunked
:
146 return omp::OMP_SCHEDULE_Dynamic
;
147 case omp::OMPScheduleType::BaseGuidedChunked
:
148 return omp::OMP_SCHEDULE_Guided
;
149 case omp::OMPScheduleType::BaseAuto
:
150 return omp::OMP_SCHEDULE_Auto
;
151 case omp::OMPScheduleType::BaseRuntime
:
152 return omp::OMP_SCHEDULE_Runtime
;
154 llvm_unreachable("unknown type for this test");
158 class OpenMPIRBuilderTest
: public testing::Test
{
160 void SetUp() override
{
161 Ctx
.setOpaquePointers(false); // TODO: Update tests for opaque pointers.
162 M
.reset(new Module("MyModule", Ctx
));
164 FunctionType::get(Type::getVoidTy(Ctx
), {Type::getInt32Ty(Ctx
)},
166 F
= Function::Create(FTy
, Function::ExternalLinkage
, "", M
.get());
167 BB
= BasicBlock::Create(Ctx
, "", F
);
170 auto File
= DIB
.createFile("test.dbg", "/src", llvm::None
,
171 Optional
<StringRef
>("/src/test.dbg"));
173 DIB
.createCompileUnit(dwarf::DW_LANG_C
, File
, "llvm-C", true, "", 0);
174 auto Type
= DIB
.createSubroutineType(DIB
.getOrCreateTypeArray(None
));
175 auto SP
= DIB
.createFunction(
176 CU
, "foo", "", File
, 1, Type
, 1, DINode::FlagZero
,
177 DISubprogram::SPFlagDefinition
| DISubprogram::SPFlagOptimized
);
178 F
->setSubprogram(SP
);
179 auto Scope
= DIB
.createLexicalBlockFile(SP
, File
, 0);
181 DL
= DILocation::get(Ctx
, 3, 7, Scope
);
184 void TearDown() override
{
189 /// Create a function with a simple loop that calls printf using the logical
190 /// loop counter for use with tests that need a CanonicalLoopInfo object.
191 CanonicalLoopInfo
*buildSingleLoopFunction(DebugLoc DL
,
192 OpenMPIRBuilder
&OMPBuilder
,
194 CallInst
**Call
= nullptr,
195 BasicBlock
**BodyCode
= nullptr) {
196 OMPBuilder
.initialize();
199 IRBuilder
<> Builder(BB
);
200 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
201 Value
*TripCount
= F
->getArg(0);
203 Type
*IVType
= Type::getIntNTy(Builder
.getContext(), UseIVBits
);
204 Value
*CastedTripCount
=
205 Builder
.CreateZExtOrTrunc(TripCount
, IVType
, "tripcount");
207 auto LoopBodyGenCB
= [&](OpenMPIRBuilder::InsertPointTy CodeGenIP
,
209 Builder
.restoreIP(CodeGenIP
);
211 *BodyCode
= Builder
.GetInsertBlock();
213 // Add something that consumes the induction variable to the body.
214 CallInst
*CallInst
= createPrintfCall(Builder
, "%d\\n", {LC
});
218 CanonicalLoopInfo
*Loop
=
219 OMPBuilder
.createCanonicalLoop(Loc
, LoopBodyGenCB
, CastedTripCount
);
221 // Finalize the function.
222 Builder
.restoreIP(Loop
->getAfterIP());
223 Builder
.CreateRetVoid();
229 std::unique_ptr
<Module
> M
;
235 class OpenMPIRBuilderTestWithParams
236 : public OpenMPIRBuilderTest
,
237 public ::testing::WithParamInterface
<omp::OMPScheduleType
> {};
239 class OpenMPIRBuilderTestWithIVBits
240 : public OpenMPIRBuilderTest
,
241 public ::testing::WithParamInterface
<int> {};
243 // Returns the value stored in the given allocation. Returns null if the given
244 // value is not a result of an InstTy instruction, if no value is stored or if
245 // there is more than one store.
246 template <typename InstTy
> static Value
*findStoredValue(Value
*AllocaValue
) {
247 Instruction
*Inst
= dyn_cast
<InstTy
>(AllocaValue
);
250 StoreInst
*Store
= nullptr;
251 for (Use
&U
: Inst
->uses()) {
252 if (auto *CandidateStore
= dyn_cast
<StoreInst
>(U
.getUser())) {
253 EXPECT_EQ(Store
, nullptr);
254 Store
= CandidateStore
;
259 return Store
->getValueOperand();
262 // Returns the value stored in the aggregate argument of an outlined function,
263 // or nullptr if it is not found.
264 static Value
*findStoredValueInAggregateAt(LLVMContext
&Ctx
, Value
*Aggregate
,
266 GetElementPtrInst
*GEPAtIdx
= nullptr;
267 // Find GEP instruction at that index.
268 for (User
*Usr
: Aggregate
->users()) {
269 GetElementPtrInst
*GEP
= dyn_cast
<GetElementPtrInst
>(Usr
);
273 if (GEP
->getOperand(2) != ConstantInt::get(Type::getInt32Ty(Ctx
), Idx
))
276 EXPECT_EQ(GEPAtIdx
, nullptr);
280 EXPECT_NE(GEPAtIdx
, nullptr);
281 EXPECT_EQ(GEPAtIdx
->getNumUses(), 1U);
283 // Find the value stored to the aggregate.
284 StoreInst
*StoreToAgg
= dyn_cast
<StoreInst
>(*GEPAtIdx
->user_begin());
285 Value
*StoredAggValue
= StoreToAgg
->getValueOperand();
287 Value
*StoredValue
= nullptr;
289 // Find the value stored to the value stored in the aggregate.
290 for (User
*Usr
: StoredAggValue
->users()) {
291 StoreInst
*Store
= dyn_cast
<StoreInst
>(Usr
);
295 if (Store
->getPointerOperand() != StoredAggValue
)
298 EXPECT_EQ(StoredValue
, nullptr);
299 StoredValue
= Store
->getValueOperand();
305 // Returns the aggregate that the value is originating from.
306 static Value
*findAggregateFromValue(Value
*V
) {
307 // Expects a load instruction that loads from the aggregate.
308 LoadInst
*Load
= dyn_cast
<LoadInst
>(V
);
309 EXPECT_NE(Load
, nullptr);
310 // Find the GEP instruction used in the load instruction.
311 GetElementPtrInst
*GEP
=
312 dyn_cast
<GetElementPtrInst
>(Load
->getPointerOperand());
313 EXPECT_NE(GEP
, nullptr);
314 // Find the aggregate used in the GEP instruction.
315 Value
*Aggregate
= GEP
->getPointerOperand();
320 TEST_F(OpenMPIRBuilderTest
, CreateBarrier
) {
321 OpenMPIRBuilder
OMPBuilder(*M
);
322 OMPBuilder
.initialize();
324 IRBuilder
<> Builder(BB
);
326 OMPBuilder
.createBarrier({IRBuilder
<>::InsertPoint()}, OMPD_for
);
327 EXPECT_TRUE(M
->global_empty());
328 EXPECT_EQ(M
->size(), 1U);
329 EXPECT_EQ(F
->size(), 1U);
330 EXPECT_EQ(BB
->size(), 0U);
332 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP()});
333 OMPBuilder
.createBarrier(Loc
, OMPD_for
);
334 EXPECT_FALSE(M
->global_empty());
335 EXPECT_EQ(M
->size(), 3U);
336 EXPECT_EQ(F
->size(), 1U);
337 EXPECT_EQ(BB
->size(), 2U);
339 CallInst
*GTID
= dyn_cast
<CallInst
>(&BB
->front());
340 EXPECT_NE(GTID
, nullptr);
341 EXPECT_EQ(GTID
->arg_size(), 1U);
342 EXPECT_EQ(GTID
->getCalledFunction()->getName(), "__kmpc_global_thread_num");
343 EXPECT_FALSE(GTID
->getCalledFunction()->doesNotAccessMemory());
344 EXPECT_FALSE(GTID
->getCalledFunction()->doesNotFreeMemory());
346 CallInst
*Barrier
= dyn_cast
<CallInst
>(GTID
->getNextNode());
347 EXPECT_NE(Barrier
, nullptr);
348 EXPECT_EQ(Barrier
->arg_size(), 2U);
349 EXPECT_EQ(Barrier
->getCalledFunction()->getName(), "__kmpc_barrier");
350 EXPECT_FALSE(Barrier
->getCalledFunction()->doesNotAccessMemory());
351 EXPECT_FALSE(Barrier
->getCalledFunction()->doesNotFreeMemory());
353 EXPECT_EQ(cast
<CallInst
>(Barrier
)->getArgOperand(1), GTID
);
355 Builder
.CreateUnreachable();
356 EXPECT_FALSE(verifyModule(*M
, &errs()));
359 TEST_F(OpenMPIRBuilderTest
, CreateCancel
) {
360 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
361 OpenMPIRBuilder
OMPBuilder(*M
);
362 OMPBuilder
.initialize();
364 BasicBlock
*CBB
= BasicBlock::Create(Ctx
, "", F
);
365 new UnreachableInst(Ctx
, CBB
);
366 auto FiniCB
= [&](InsertPointTy IP
) {
367 ASSERT_NE(IP
.getBlock(), nullptr);
368 ASSERT_EQ(IP
.getBlock()->end(), IP
.getPoint());
369 BranchInst::Create(CBB
, IP
.getBlock());
371 OMPBuilder
.pushFinalizationCB({FiniCB
, OMPD_parallel
, true});
373 IRBuilder
<> Builder(BB
);
375 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP()});
376 auto NewIP
= OMPBuilder
.createCancel(Loc
, nullptr, OMPD_parallel
);
377 Builder
.restoreIP(NewIP
);
378 EXPECT_FALSE(M
->global_empty());
379 EXPECT_EQ(M
->size(), 4U);
380 EXPECT_EQ(F
->size(), 4U);
381 EXPECT_EQ(BB
->size(), 4U);
383 CallInst
*GTID
= dyn_cast
<CallInst
>(&BB
->front());
384 EXPECT_NE(GTID
, nullptr);
385 EXPECT_EQ(GTID
->arg_size(), 1U);
386 EXPECT_EQ(GTID
->getCalledFunction()->getName(), "__kmpc_global_thread_num");
387 EXPECT_FALSE(GTID
->getCalledFunction()->doesNotAccessMemory());
388 EXPECT_FALSE(GTID
->getCalledFunction()->doesNotFreeMemory());
390 CallInst
*Cancel
= dyn_cast
<CallInst
>(GTID
->getNextNode());
391 EXPECT_NE(Cancel
, nullptr);
392 EXPECT_EQ(Cancel
->arg_size(), 3U);
393 EXPECT_EQ(Cancel
->getCalledFunction()->getName(), "__kmpc_cancel");
394 EXPECT_FALSE(Cancel
->getCalledFunction()->doesNotAccessMemory());
395 EXPECT_FALSE(Cancel
->getCalledFunction()->doesNotFreeMemory());
396 EXPECT_EQ(Cancel
->getNumUses(), 1U);
397 Instruction
*CancelBBTI
= Cancel
->getParent()->getTerminator();
398 EXPECT_EQ(CancelBBTI
->getNumSuccessors(), 2U);
399 EXPECT_EQ(CancelBBTI
->getSuccessor(0), NewIP
.getBlock());
400 EXPECT_EQ(CancelBBTI
->getSuccessor(1)->size(), 3U);
401 CallInst
*GTID1
= dyn_cast
<CallInst
>(&CancelBBTI
->getSuccessor(1)->front());
402 EXPECT_NE(GTID1
, nullptr);
403 EXPECT_EQ(GTID1
->arg_size(), 1U);
404 EXPECT_EQ(GTID1
->getCalledFunction()->getName(), "__kmpc_global_thread_num");
405 EXPECT_FALSE(GTID1
->getCalledFunction()->doesNotAccessMemory());
406 EXPECT_FALSE(GTID1
->getCalledFunction()->doesNotFreeMemory());
407 CallInst
*Barrier
= dyn_cast
<CallInst
>(GTID1
->getNextNode());
408 EXPECT_NE(Barrier
, nullptr);
409 EXPECT_EQ(Barrier
->arg_size(), 2U);
410 EXPECT_EQ(Barrier
->getCalledFunction()->getName(), "__kmpc_cancel_barrier");
411 EXPECT_FALSE(Barrier
->getCalledFunction()->doesNotAccessMemory());
412 EXPECT_FALSE(Barrier
->getCalledFunction()->doesNotFreeMemory());
413 EXPECT_EQ(Barrier
->getNumUses(), 0U);
414 EXPECT_EQ(CancelBBTI
->getSuccessor(1)->getTerminator()->getNumSuccessors(),
416 EXPECT_EQ(CancelBBTI
->getSuccessor(1)->getTerminator()->getSuccessor(0), CBB
);
418 EXPECT_EQ(cast
<CallInst
>(Cancel
)->getArgOperand(1), GTID
);
420 OMPBuilder
.popFinalizationCB();
422 Builder
.CreateUnreachable();
423 EXPECT_FALSE(verifyModule(*M
, &errs()));
426 TEST_F(OpenMPIRBuilderTest
, CreateCancelIfCond
) {
427 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
428 OpenMPIRBuilder
OMPBuilder(*M
);
429 OMPBuilder
.initialize();
431 BasicBlock
*CBB
= BasicBlock::Create(Ctx
, "", F
);
432 new UnreachableInst(Ctx
, CBB
);
433 auto FiniCB
= [&](InsertPointTy IP
) {
434 ASSERT_NE(IP
.getBlock(), nullptr);
435 ASSERT_EQ(IP
.getBlock()->end(), IP
.getPoint());
436 BranchInst::Create(CBB
, IP
.getBlock());
438 OMPBuilder
.pushFinalizationCB({FiniCB
, OMPD_parallel
, true});
440 IRBuilder
<> Builder(BB
);
442 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP()});
443 auto NewIP
= OMPBuilder
.createCancel(Loc
, Builder
.getTrue(), OMPD_parallel
);
444 Builder
.restoreIP(NewIP
);
445 EXPECT_FALSE(M
->global_empty());
446 EXPECT_EQ(M
->size(), 4U);
447 EXPECT_EQ(F
->size(), 7U);
448 EXPECT_EQ(BB
->size(), 1U);
449 ASSERT_TRUE(isa
<BranchInst
>(BB
->getTerminator()));
450 ASSERT_EQ(BB
->getTerminator()->getNumSuccessors(), 2U);
451 BB
= BB
->getTerminator()->getSuccessor(0);
452 EXPECT_EQ(BB
->size(), 4U);
454 CallInst
*GTID
= dyn_cast
<CallInst
>(&BB
->front());
455 EXPECT_NE(GTID
, nullptr);
456 EXPECT_EQ(GTID
->arg_size(), 1U);
457 EXPECT_EQ(GTID
->getCalledFunction()->getName(), "__kmpc_global_thread_num");
458 EXPECT_FALSE(GTID
->getCalledFunction()->doesNotAccessMemory());
459 EXPECT_FALSE(GTID
->getCalledFunction()->doesNotFreeMemory());
461 CallInst
*Cancel
= dyn_cast
<CallInst
>(GTID
->getNextNode());
462 EXPECT_NE(Cancel
, nullptr);
463 EXPECT_EQ(Cancel
->arg_size(), 3U);
464 EXPECT_EQ(Cancel
->getCalledFunction()->getName(), "__kmpc_cancel");
465 EXPECT_FALSE(Cancel
->getCalledFunction()->doesNotAccessMemory());
466 EXPECT_FALSE(Cancel
->getCalledFunction()->doesNotFreeMemory());
467 EXPECT_EQ(Cancel
->getNumUses(), 1U);
468 Instruction
*CancelBBTI
= Cancel
->getParent()->getTerminator();
469 EXPECT_EQ(CancelBBTI
->getNumSuccessors(), 2U);
470 EXPECT_EQ(CancelBBTI
->getSuccessor(0)->size(), 1U);
471 EXPECT_EQ(CancelBBTI
->getSuccessor(0)->getUniqueSuccessor(),
473 EXPECT_EQ(CancelBBTI
->getSuccessor(1)->size(), 3U);
474 CallInst
*GTID1
= dyn_cast
<CallInst
>(&CancelBBTI
->getSuccessor(1)->front());
475 EXPECT_NE(GTID1
, nullptr);
476 EXPECT_EQ(GTID1
->arg_size(), 1U);
477 EXPECT_EQ(GTID1
->getCalledFunction()->getName(), "__kmpc_global_thread_num");
478 EXPECT_FALSE(GTID1
->getCalledFunction()->doesNotAccessMemory());
479 EXPECT_FALSE(GTID1
->getCalledFunction()->doesNotFreeMemory());
480 CallInst
*Barrier
= dyn_cast
<CallInst
>(GTID1
->getNextNode());
481 EXPECT_NE(Barrier
, nullptr);
482 EXPECT_EQ(Barrier
->arg_size(), 2U);
483 EXPECT_EQ(Barrier
->getCalledFunction()->getName(), "__kmpc_cancel_barrier");
484 EXPECT_FALSE(Barrier
->getCalledFunction()->doesNotAccessMemory());
485 EXPECT_FALSE(Barrier
->getCalledFunction()->doesNotFreeMemory());
486 EXPECT_EQ(Barrier
->getNumUses(), 0U);
487 EXPECT_EQ(CancelBBTI
->getSuccessor(1)->getTerminator()->getNumSuccessors(),
489 EXPECT_EQ(CancelBBTI
->getSuccessor(1)->getTerminator()->getSuccessor(0), CBB
);
491 EXPECT_EQ(cast
<CallInst
>(Cancel
)->getArgOperand(1), GTID
);
493 OMPBuilder
.popFinalizationCB();
495 Builder
.CreateUnreachable();
496 EXPECT_FALSE(verifyModule(*M
, &errs()));
499 TEST_F(OpenMPIRBuilderTest
, CreateCancelBarrier
) {
500 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
501 OpenMPIRBuilder
OMPBuilder(*M
);
502 OMPBuilder
.initialize();
504 BasicBlock
*CBB
= BasicBlock::Create(Ctx
, "", F
);
505 new UnreachableInst(Ctx
, CBB
);
506 auto FiniCB
= [&](InsertPointTy IP
) {
507 ASSERT_NE(IP
.getBlock(), nullptr);
508 ASSERT_EQ(IP
.getBlock()->end(), IP
.getPoint());
509 BranchInst::Create(CBB
, IP
.getBlock());
511 OMPBuilder
.pushFinalizationCB({FiniCB
, OMPD_parallel
, true});
513 IRBuilder
<> Builder(BB
);
515 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP()});
516 auto NewIP
= OMPBuilder
.createBarrier(Loc
, OMPD_for
);
517 Builder
.restoreIP(NewIP
);
518 EXPECT_FALSE(M
->global_empty());
519 EXPECT_EQ(M
->size(), 3U);
520 EXPECT_EQ(F
->size(), 4U);
521 EXPECT_EQ(BB
->size(), 4U);
523 CallInst
*GTID
= dyn_cast
<CallInst
>(&BB
->front());
524 EXPECT_NE(GTID
, nullptr);
525 EXPECT_EQ(GTID
->arg_size(), 1U);
526 EXPECT_EQ(GTID
->getCalledFunction()->getName(), "__kmpc_global_thread_num");
527 EXPECT_FALSE(GTID
->getCalledFunction()->doesNotAccessMemory());
528 EXPECT_FALSE(GTID
->getCalledFunction()->doesNotFreeMemory());
530 CallInst
*Barrier
= dyn_cast
<CallInst
>(GTID
->getNextNode());
531 EXPECT_NE(Barrier
, nullptr);
532 EXPECT_EQ(Barrier
->arg_size(), 2U);
533 EXPECT_EQ(Barrier
->getCalledFunction()->getName(), "__kmpc_cancel_barrier");
534 EXPECT_FALSE(Barrier
->getCalledFunction()->doesNotAccessMemory());
535 EXPECT_FALSE(Barrier
->getCalledFunction()->doesNotFreeMemory());
536 EXPECT_EQ(Barrier
->getNumUses(), 1U);
537 Instruction
*BarrierBBTI
= Barrier
->getParent()->getTerminator();
538 EXPECT_EQ(BarrierBBTI
->getNumSuccessors(), 2U);
539 EXPECT_EQ(BarrierBBTI
->getSuccessor(0), NewIP
.getBlock());
540 EXPECT_EQ(BarrierBBTI
->getSuccessor(1)->size(), 1U);
541 EXPECT_EQ(BarrierBBTI
->getSuccessor(1)->getTerminator()->getNumSuccessors(),
543 EXPECT_EQ(BarrierBBTI
->getSuccessor(1)->getTerminator()->getSuccessor(0),
546 EXPECT_EQ(cast
<CallInst
>(Barrier
)->getArgOperand(1), GTID
);
548 OMPBuilder
.popFinalizationCB();
550 Builder
.CreateUnreachable();
551 EXPECT_FALSE(verifyModule(*M
, &errs()));
554 TEST_F(OpenMPIRBuilderTest
, DbgLoc
) {
555 OpenMPIRBuilder
OMPBuilder(*M
);
556 OMPBuilder
.initialize();
559 IRBuilder
<> Builder(BB
);
561 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
562 OMPBuilder
.createBarrier(Loc
, OMPD_for
);
563 CallInst
*GTID
= dyn_cast
<CallInst
>(&BB
->front());
564 CallInst
*Barrier
= dyn_cast
<CallInst
>(GTID
->getNextNode());
565 EXPECT_EQ(GTID
->getDebugLoc(), DL
);
566 EXPECT_EQ(Barrier
->getDebugLoc(), DL
);
567 EXPECT_TRUE(isa
<GlobalVariable
>(Barrier
->getOperand(0)));
568 if (!isa
<GlobalVariable
>(Barrier
->getOperand(0)))
570 GlobalVariable
*Ident
= cast
<GlobalVariable
>(Barrier
->getOperand(0));
571 EXPECT_TRUE(Ident
->hasInitializer());
572 if (!Ident
->hasInitializer())
574 Constant
*Initializer
= Ident
->getInitializer();
576 isa
<GlobalVariable
>(Initializer
->getOperand(4)->stripPointerCasts()));
577 GlobalVariable
*SrcStrGlob
=
578 cast
<GlobalVariable
>(Initializer
->getOperand(4)->stripPointerCasts());
581 EXPECT_TRUE(isa
<ConstantDataArray
>(SrcStrGlob
->getInitializer()));
582 ConstantDataArray
*SrcSrc
=
583 dyn_cast
<ConstantDataArray
>(SrcStrGlob
->getInitializer());
586 EXPECT_EQ(SrcSrc
->getAsCString(), ";/src/test.dbg;foo;3;7;;");
589 TEST_F(OpenMPIRBuilderTest
, ParallelSimple
) {
590 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
591 OpenMPIRBuilder
OMPBuilder(*M
);
592 OMPBuilder
.initialize();
594 IRBuilder
<> Builder(BB
);
596 BasicBlock
*EnterBB
= BasicBlock::Create(Ctx
, "parallel.enter", F
);
597 Builder
.CreateBr(EnterBB
);
598 Builder
.SetInsertPoint(EnterBB
);
599 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
601 AllocaInst
*PrivAI
= nullptr;
603 unsigned NumBodiesGenerated
= 0;
604 unsigned NumPrivatizedVars
= 0;
605 unsigned NumFinalizationPoints
= 0;
607 auto BodyGenCB
= [&](InsertPointTy AllocaIP
, InsertPointTy CodeGenIP
) {
608 ++NumBodiesGenerated
;
610 Builder
.restoreIP(AllocaIP
);
611 PrivAI
= Builder
.CreateAlloca(F
->arg_begin()->getType());
612 Builder
.CreateStore(F
->arg_begin(), PrivAI
);
614 Builder
.restoreIP(CodeGenIP
);
616 Builder
.CreateLoad(PrivAI
->getAllocatedType(), PrivAI
, "local.use");
617 Value
*Cmp
= Builder
.CreateICmpNE(F
->arg_begin(), PrivLoad
);
618 Instruction
*ThenTerm
, *ElseTerm
;
619 SplitBlockAndInsertIfThenElse(Cmp
, CodeGenIP
.getBlock()->getTerminator(),
620 &ThenTerm
, &ElseTerm
);
623 auto PrivCB
= [&](InsertPointTy AllocaIP
, InsertPointTy CodeGenIP
,
624 Value
&Orig
, Value
&Inner
,
625 Value
*&ReplacementValue
) -> InsertPointTy
{
628 if (!isa
<AllocaInst
>(Orig
)) {
629 EXPECT_EQ(&Orig
, F
->arg_begin());
630 ReplacementValue
= &Inner
;
634 // Since the original value is an allocation, it has a pointer type and
635 // therefore no additional wrapping should happen.
636 EXPECT_EQ(&Orig
, &Inner
);
638 // Trivial copy (=firstprivate).
639 Builder
.restoreIP(AllocaIP
);
640 Type
*VTy
= ReplacementValue
->getType();
641 Value
*V
= Builder
.CreateLoad(VTy
, &Inner
, Orig
.getName() + ".reload");
642 ReplacementValue
= Builder
.CreateAlloca(VTy
, 0, Orig
.getName() + ".copy");
643 Builder
.restoreIP(CodeGenIP
);
644 Builder
.CreateStore(V
, ReplacementValue
);
648 auto FiniCB
= [&](InsertPointTy CodeGenIP
) { ++NumFinalizationPoints
; };
650 IRBuilder
<>::InsertPoint
AllocaIP(&F
->getEntryBlock(),
651 F
->getEntryBlock().getFirstInsertionPt());
652 IRBuilder
<>::InsertPoint AfterIP
=
653 OMPBuilder
.createParallel(Loc
, AllocaIP
, BodyGenCB
, PrivCB
, FiniCB
,
654 nullptr, nullptr, OMP_PROC_BIND_default
, false);
655 EXPECT_EQ(NumBodiesGenerated
, 1U);
656 EXPECT_EQ(NumPrivatizedVars
, 1U);
657 EXPECT_EQ(NumFinalizationPoints
, 1U);
659 Builder
.restoreIP(AfterIP
);
660 Builder
.CreateRetVoid();
662 OMPBuilder
.finalize();
664 EXPECT_NE(PrivAI
, nullptr);
665 Function
*OutlinedFn
= PrivAI
->getFunction();
666 EXPECT_NE(F
, OutlinedFn
);
667 EXPECT_FALSE(verifyModule(*M
, &errs()));
668 EXPECT_TRUE(OutlinedFn
->hasFnAttribute(Attribute::NoUnwind
));
669 EXPECT_TRUE(OutlinedFn
->hasFnAttribute(Attribute::NoRecurse
));
670 EXPECT_TRUE(OutlinedFn
->hasParamAttribute(0, Attribute::NoAlias
));
671 EXPECT_TRUE(OutlinedFn
->hasParamAttribute(1, Attribute::NoAlias
));
673 EXPECT_TRUE(OutlinedFn
->hasInternalLinkage());
674 EXPECT_EQ(OutlinedFn
->arg_size(), 3U);
676 EXPECT_EQ(&OutlinedFn
->getEntryBlock(), PrivAI
->getParent());
677 EXPECT_EQ(OutlinedFn
->getNumUses(), 1U);
678 User
*Usr
= OutlinedFn
->user_back();
679 ASSERT_TRUE(isa
<ConstantExpr
>(Usr
));
680 CallInst
*ForkCI
= dyn_cast
<CallInst
>(Usr
->user_back());
681 ASSERT_NE(ForkCI
, nullptr);
683 EXPECT_EQ(ForkCI
->getCalledFunction()->getName(), "__kmpc_fork_call");
684 EXPECT_EQ(ForkCI
->arg_size(), 4U);
685 EXPECT_TRUE(isa
<GlobalVariable
>(ForkCI
->getArgOperand(0)));
686 EXPECT_EQ(ForkCI
->getArgOperand(1),
687 ConstantInt::get(Type::getInt32Ty(Ctx
), 1U));
688 EXPECT_EQ(ForkCI
->getArgOperand(2), Usr
);
690 findStoredValueInAggregateAt(Ctx
, ForkCI
->getArgOperand(3), 0);
691 EXPECT_EQ(StoredValue
, F
->arg_begin());
694 TEST_F(OpenMPIRBuilderTest
, ParallelNested
) {
695 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
696 OpenMPIRBuilder
OMPBuilder(*M
);
697 OMPBuilder
.initialize();
699 IRBuilder
<> Builder(BB
);
701 BasicBlock
*EnterBB
= BasicBlock::Create(Ctx
, "parallel.enter", F
);
702 Builder
.CreateBr(EnterBB
);
703 Builder
.SetInsertPoint(EnterBB
);
704 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
706 unsigned NumInnerBodiesGenerated
= 0;
707 unsigned NumOuterBodiesGenerated
= 0;
708 unsigned NumFinalizationPoints
= 0;
710 auto InnerBodyGenCB
= [&](InsertPointTy AllocaIP
, InsertPointTy CodeGenIP
) {
711 ++NumInnerBodiesGenerated
;
714 auto PrivCB
= [&](InsertPointTy AllocaIP
, InsertPointTy CodeGenIP
,
715 Value
&Orig
, Value
&Inner
,
716 Value
*&ReplacementValue
) -> InsertPointTy
{
717 // Trivial copy (=firstprivate).
718 Builder
.restoreIP(AllocaIP
);
719 Type
*VTy
= ReplacementValue
->getType();
720 Value
*V
= Builder
.CreateLoad(VTy
, &Inner
, Orig
.getName() + ".reload");
721 ReplacementValue
= Builder
.CreateAlloca(VTy
, 0, Orig
.getName() + ".copy");
722 Builder
.restoreIP(CodeGenIP
);
723 Builder
.CreateStore(V
, ReplacementValue
);
727 auto FiniCB
= [&](InsertPointTy CodeGenIP
) { ++NumFinalizationPoints
; };
729 auto OuterBodyGenCB
= [&](InsertPointTy AllocaIP
, InsertPointTy CodeGenIP
) {
730 ++NumOuterBodiesGenerated
;
731 Builder
.restoreIP(CodeGenIP
);
732 BasicBlock
*CGBB
= CodeGenIP
.getBlock();
733 BasicBlock
*NewBB
= SplitBlock(CGBB
, &*CodeGenIP
.getPoint());
734 CGBB
->getTerminator()->eraseFromParent();
737 IRBuilder
<>::InsertPoint AfterIP
= OMPBuilder
.createParallel(
738 InsertPointTy(CGBB
, CGBB
->end()), AllocaIP
, InnerBodyGenCB
, PrivCB
,
739 FiniCB
, nullptr, nullptr, OMP_PROC_BIND_default
, false);
741 Builder
.restoreIP(AfterIP
);
742 Builder
.CreateBr(NewBB
);
745 IRBuilder
<>::InsertPoint
AllocaIP(&F
->getEntryBlock(),
746 F
->getEntryBlock().getFirstInsertionPt());
747 IRBuilder
<>::InsertPoint AfterIP
=
748 OMPBuilder
.createParallel(Loc
, AllocaIP
, OuterBodyGenCB
, PrivCB
, FiniCB
,
749 nullptr, nullptr, OMP_PROC_BIND_default
, false);
751 EXPECT_EQ(NumInnerBodiesGenerated
, 1U);
752 EXPECT_EQ(NumOuterBodiesGenerated
, 1U);
753 EXPECT_EQ(NumFinalizationPoints
, 2U);
755 Builder
.restoreIP(AfterIP
);
756 Builder
.CreateRetVoid();
758 OMPBuilder
.finalize();
760 EXPECT_EQ(M
->size(), 5U);
761 for (Function
&OutlinedFn
: *M
) {
762 if (F
== &OutlinedFn
|| OutlinedFn
.isDeclaration())
764 EXPECT_FALSE(verifyModule(*M
, &errs()));
765 EXPECT_TRUE(OutlinedFn
.hasFnAttribute(Attribute::NoUnwind
));
766 EXPECT_TRUE(OutlinedFn
.hasFnAttribute(Attribute::NoRecurse
));
767 EXPECT_TRUE(OutlinedFn
.hasParamAttribute(0, Attribute::NoAlias
));
768 EXPECT_TRUE(OutlinedFn
.hasParamAttribute(1, Attribute::NoAlias
));
770 EXPECT_TRUE(OutlinedFn
.hasInternalLinkage());
771 EXPECT_EQ(OutlinedFn
.arg_size(), 2U);
773 EXPECT_EQ(OutlinedFn
.getNumUses(), 1U);
774 User
*Usr
= OutlinedFn
.user_back();
775 ASSERT_TRUE(isa
<ConstantExpr
>(Usr
));
776 CallInst
*ForkCI
= dyn_cast
<CallInst
>(Usr
->user_back());
777 ASSERT_NE(ForkCI
, nullptr);
779 EXPECT_EQ(ForkCI
->getCalledFunction()->getName(), "__kmpc_fork_call");
780 EXPECT_EQ(ForkCI
->arg_size(), 3U);
781 EXPECT_TRUE(isa
<GlobalVariable
>(ForkCI
->getArgOperand(0)));
782 EXPECT_EQ(ForkCI
->getArgOperand(1),
783 ConstantInt::get(Type::getInt32Ty(Ctx
), 0U));
784 EXPECT_EQ(ForkCI
->getArgOperand(2), Usr
);
788 TEST_F(OpenMPIRBuilderTest
, ParallelNested2Inner
) {
789 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
790 OpenMPIRBuilder
OMPBuilder(*M
);
791 OMPBuilder
.initialize();
793 IRBuilder
<> Builder(BB
);
795 BasicBlock
*EnterBB
= BasicBlock::Create(Ctx
, "parallel.enter", F
);
796 Builder
.CreateBr(EnterBB
);
797 Builder
.SetInsertPoint(EnterBB
);
798 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
800 unsigned NumInnerBodiesGenerated
= 0;
801 unsigned NumOuterBodiesGenerated
= 0;
802 unsigned NumFinalizationPoints
= 0;
804 auto InnerBodyGenCB
= [&](InsertPointTy AllocaIP
, InsertPointTy CodeGenIP
) {
805 ++NumInnerBodiesGenerated
;
808 auto PrivCB
= [&](InsertPointTy AllocaIP
, InsertPointTy CodeGenIP
,
809 Value
&Orig
, Value
&Inner
,
810 Value
*&ReplacementValue
) -> InsertPointTy
{
811 // Trivial copy (=firstprivate).
812 Builder
.restoreIP(AllocaIP
);
813 Type
*VTy
= ReplacementValue
->getType();
814 Value
*V
= Builder
.CreateLoad(VTy
, &Inner
, Orig
.getName() + ".reload");
815 ReplacementValue
= Builder
.CreateAlloca(VTy
, 0, Orig
.getName() + ".copy");
816 Builder
.restoreIP(CodeGenIP
);
817 Builder
.CreateStore(V
, ReplacementValue
);
821 auto FiniCB
= [&](InsertPointTy CodeGenIP
) { ++NumFinalizationPoints
; };
823 auto OuterBodyGenCB
= [&](InsertPointTy AllocaIP
, InsertPointTy CodeGenIP
) {
824 ++NumOuterBodiesGenerated
;
825 Builder
.restoreIP(CodeGenIP
);
826 BasicBlock
*CGBB
= CodeGenIP
.getBlock();
827 BasicBlock
*NewBB1
= SplitBlock(CGBB
, &*CodeGenIP
.getPoint());
828 BasicBlock
*NewBB2
= SplitBlock(NewBB1
, &*NewBB1
->getFirstInsertionPt());
829 CGBB
->getTerminator()->eraseFromParent();
831 NewBB1
->getTerminator()->eraseFromParent();
834 IRBuilder
<>::InsertPoint AfterIP1
= OMPBuilder
.createParallel(
835 InsertPointTy(CGBB
, CGBB
->end()), AllocaIP
, InnerBodyGenCB
, PrivCB
,
836 FiniCB
, nullptr, nullptr, OMP_PROC_BIND_default
, false);
838 Builder
.restoreIP(AfterIP1
);
839 Builder
.CreateBr(NewBB1
);
841 IRBuilder
<>::InsertPoint AfterIP2
= OMPBuilder
.createParallel(
842 InsertPointTy(NewBB1
, NewBB1
->end()), AllocaIP
, InnerBodyGenCB
, PrivCB
,
843 FiniCB
, nullptr, nullptr, OMP_PROC_BIND_default
, false);
845 Builder
.restoreIP(AfterIP2
);
846 Builder
.CreateBr(NewBB2
);
849 IRBuilder
<>::InsertPoint
AllocaIP(&F
->getEntryBlock(),
850 F
->getEntryBlock().getFirstInsertionPt());
851 IRBuilder
<>::InsertPoint AfterIP
=
852 OMPBuilder
.createParallel(Loc
, AllocaIP
, OuterBodyGenCB
, PrivCB
, FiniCB
,
853 nullptr, nullptr, OMP_PROC_BIND_default
, false);
855 EXPECT_EQ(NumInnerBodiesGenerated
, 2U);
856 EXPECT_EQ(NumOuterBodiesGenerated
, 1U);
857 EXPECT_EQ(NumFinalizationPoints
, 3U);
859 Builder
.restoreIP(AfterIP
);
860 Builder
.CreateRetVoid();
862 OMPBuilder
.finalize();
864 EXPECT_EQ(M
->size(), 6U);
865 for (Function
&OutlinedFn
: *M
) {
866 if (F
== &OutlinedFn
|| OutlinedFn
.isDeclaration())
868 EXPECT_FALSE(verifyModule(*M
, &errs()));
869 EXPECT_TRUE(OutlinedFn
.hasFnAttribute(Attribute::NoUnwind
));
870 EXPECT_TRUE(OutlinedFn
.hasFnAttribute(Attribute::NoRecurse
));
871 EXPECT_TRUE(OutlinedFn
.hasParamAttribute(0, Attribute::NoAlias
));
872 EXPECT_TRUE(OutlinedFn
.hasParamAttribute(1, Attribute::NoAlias
));
874 EXPECT_TRUE(OutlinedFn
.hasInternalLinkage());
875 EXPECT_EQ(OutlinedFn
.arg_size(), 2U);
877 unsigned NumAllocas
= 0;
878 for (Instruction
&I
: instructions(OutlinedFn
))
879 NumAllocas
+= isa
<AllocaInst
>(I
);
880 EXPECT_EQ(NumAllocas
, 1U);
882 EXPECT_EQ(OutlinedFn
.getNumUses(), 1U);
883 User
*Usr
= OutlinedFn
.user_back();
884 ASSERT_TRUE(isa
<ConstantExpr
>(Usr
));
885 CallInst
*ForkCI
= dyn_cast
<CallInst
>(Usr
->user_back());
886 ASSERT_NE(ForkCI
, nullptr);
888 EXPECT_EQ(ForkCI
->getCalledFunction()->getName(), "__kmpc_fork_call");
889 EXPECT_EQ(ForkCI
->arg_size(), 3U);
890 EXPECT_TRUE(isa
<GlobalVariable
>(ForkCI
->getArgOperand(0)));
891 EXPECT_EQ(ForkCI
->getArgOperand(1),
892 ConstantInt::get(Type::getInt32Ty(Ctx
), 0U));
893 EXPECT_EQ(ForkCI
->getArgOperand(2), Usr
);
897 TEST_F(OpenMPIRBuilderTest
, ParallelIfCond
) {
898 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
899 OpenMPIRBuilder
OMPBuilder(*M
);
900 OMPBuilder
.initialize();
902 IRBuilder
<> Builder(BB
);
904 BasicBlock
*EnterBB
= BasicBlock::Create(Ctx
, "parallel.enter", F
);
905 Builder
.CreateBr(EnterBB
);
906 Builder
.SetInsertPoint(EnterBB
);
907 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
909 AllocaInst
*PrivAI
= nullptr;
911 unsigned NumBodiesGenerated
= 0;
912 unsigned NumPrivatizedVars
= 0;
913 unsigned NumFinalizationPoints
= 0;
915 auto BodyGenCB
= [&](InsertPointTy AllocaIP
, InsertPointTy CodeGenIP
) {
916 ++NumBodiesGenerated
;
918 Builder
.restoreIP(AllocaIP
);
919 PrivAI
= Builder
.CreateAlloca(F
->arg_begin()->getType());
920 Builder
.CreateStore(F
->arg_begin(), PrivAI
);
922 Builder
.restoreIP(CodeGenIP
);
924 Builder
.CreateLoad(PrivAI
->getAllocatedType(), PrivAI
, "local.use");
925 Value
*Cmp
= Builder
.CreateICmpNE(F
->arg_begin(), PrivLoad
);
926 Instruction
*ThenTerm
, *ElseTerm
;
927 SplitBlockAndInsertIfThenElse(Cmp
, &*Builder
.GetInsertPoint(), &ThenTerm
,
931 auto PrivCB
= [&](InsertPointTy AllocaIP
, InsertPointTy CodeGenIP
,
932 Value
&Orig
, Value
&Inner
,
933 Value
*&ReplacementValue
) -> InsertPointTy
{
936 if (!isa
<AllocaInst
>(Orig
)) {
937 EXPECT_EQ(&Orig
, F
->arg_begin());
938 ReplacementValue
= &Inner
;
942 // Since the original value is an allocation, it has a pointer type and
943 // therefore no additional wrapping should happen.
944 EXPECT_EQ(&Orig
, &Inner
);
946 // Trivial copy (=firstprivate).
947 Builder
.restoreIP(AllocaIP
);
948 Type
*VTy
= ReplacementValue
->getType();
949 Value
*V
= Builder
.CreateLoad(VTy
, &Inner
, Orig
.getName() + ".reload");
950 ReplacementValue
= Builder
.CreateAlloca(VTy
, 0, Orig
.getName() + ".copy");
951 Builder
.restoreIP(CodeGenIP
);
952 Builder
.CreateStore(V
, ReplacementValue
);
956 auto FiniCB
= [&](InsertPointTy CodeGenIP
) {
957 ++NumFinalizationPoints
;
961 IRBuilder
<>::InsertPoint
AllocaIP(&F
->getEntryBlock(),
962 F
->getEntryBlock().getFirstInsertionPt());
963 IRBuilder
<>::InsertPoint AfterIP
=
964 OMPBuilder
.createParallel(Loc
, AllocaIP
, BodyGenCB
, PrivCB
, FiniCB
,
965 Builder
.CreateIsNotNull(F
->arg_begin()),
966 nullptr, OMP_PROC_BIND_default
, false);
968 EXPECT_EQ(NumBodiesGenerated
, 1U);
969 EXPECT_EQ(NumPrivatizedVars
, 1U);
970 EXPECT_EQ(NumFinalizationPoints
, 1U);
972 Builder
.restoreIP(AfterIP
);
973 Builder
.CreateRetVoid();
974 OMPBuilder
.finalize();
976 EXPECT_NE(PrivAI
, nullptr);
977 Function
*OutlinedFn
= PrivAI
->getFunction();
978 EXPECT_NE(F
, OutlinedFn
);
979 EXPECT_FALSE(verifyModule(*M
, &errs()));
981 EXPECT_TRUE(OutlinedFn
->hasInternalLinkage());
982 EXPECT_EQ(OutlinedFn
->arg_size(), 3U);
984 EXPECT_EQ(&OutlinedFn
->getEntryBlock(), PrivAI
->getParent());
985 ASSERT_EQ(OutlinedFn
->getNumUses(), 2U);
987 CallInst
*DirectCI
= nullptr;
988 CallInst
*ForkCI
= nullptr;
989 for (User
*Usr
: OutlinedFn
->users()) {
990 if (isa
<CallInst
>(Usr
)) {
991 ASSERT_EQ(DirectCI
, nullptr);
992 DirectCI
= cast
<CallInst
>(Usr
);
994 ASSERT_TRUE(isa
<ConstantExpr
>(Usr
));
995 ASSERT_EQ(Usr
->getNumUses(), 1U);
996 ASSERT_TRUE(isa
<CallInst
>(Usr
->user_back()));
997 ForkCI
= cast
<CallInst
>(Usr
->user_back());
1001 EXPECT_EQ(ForkCI
->getCalledFunction()->getName(), "__kmpc_fork_call");
1002 EXPECT_EQ(ForkCI
->arg_size(), 4U);
1003 EXPECT_TRUE(isa
<GlobalVariable
>(ForkCI
->getArgOperand(0)));
1004 EXPECT_EQ(ForkCI
->getArgOperand(1),
1005 ConstantInt::get(Type::getInt32Ty(Ctx
), 1));
1006 Value
*StoredForkArg
=
1007 findStoredValueInAggregateAt(Ctx
, ForkCI
->getArgOperand(3), 0);
1008 EXPECT_EQ(StoredForkArg
, F
->arg_begin());
1010 EXPECT_EQ(DirectCI
->getCalledFunction(), OutlinedFn
);
1011 EXPECT_EQ(DirectCI
->arg_size(), 3U);
1012 EXPECT_TRUE(isa
<AllocaInst
>(DirectCI
->getArgOperand(0)));
1013 EXPECT_TRUE(isa
<AllocaInst
>(DirectCI
->getArgOperand(1)));
1014 Value
*StoredDirectArg
=
1015 findStoredValueInAggregateAt(Ctx
, DirectCI
->getArgOperand(2), 0);
1016 EXPECT_EQ(StoredDirectArg
, F
->arg_begin());
1019 TEST_F(OpenMPIRBuilderTest
, ParallelCancelBarrier
) {
1020 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
1021 OpenMPIRBuilder
OMPBuilder(*M
);
1022 OMPBuilder
.initialize();
1024 IRBuilder
<> Builder(BB
);
1026 BasicBlock
*EnterBB
= BasicBlock::Create(Ctx
, "parallel.enter", F
);
1027 Builder
.CreateBr(EnterBB
);
1028 Builder
.SetInsertPoint(EnterBB
);
1029 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
1031 unsigned NumBodiesGenerated
= 0;
1032 unsigned NumPrivatizedVars
= 0;
1033 unsigned NumFinalizationPoints
= 0;
1035 CallInst
*CheckedBarrier
= nullptr;
1036 auto BodyGenCB
= [&](InsertPointTy AllocaIP
, InsertPointTy CodeGenIP
) {
1037 ++NumBodiesGenerated
;
1039 Builder
.restoreIP(CodeGenIP
);
1041 // Create three barriers, two cancel barriers but only one checked.
1042 Function
*CBFn
, *BFn
;
1045 OMPBuilder
.createBarrier(Builder
.saveIP(), OMPD_parallel
));
1047 CBFn
= M
->getFunction("__kmpc_cancel_barrier");
1048 BFn
= M
->getFunction("__kmpc_barrier");
1049 ASSERT_NE(CBFn
, nullptr);
1050 ASSERT_EQ(BFn
, nullptr);
1051 ASSERT_EQ(CBFn
->getNumUses(), 1U);
1052 ASSERT_TRUE(isa
<CallInst
>(CBFn
->user_back()));
1053 ASSERT_EQ(CBFn
->user_back()->getNumUses(), 1U);
1054 CheckedBarrier
= cast
<CallInst
>(CBFn
->user_back());
1057 OMPBuilder
.createBarrier(Builder
.saveIP(), OMPD_parallel
, true));
1058 CBFn
= M
->getFunction("__kmpc_cancel_barrier");
1059 BFn
= M
->getFunction("__kmpc_barrier");
1060 ASSERT_NE(CBFn
, nullptr);
1061 ASSERT_NE(BFn
, nullptr);
1062 ASSERT_EQ(CBFn
->getNumUses(), 1U);
1063 ASSERT_EQ(BFn
->getNumUses(), 1U);
1064 ASSERT_TRUE(isa
<CallInst
>(BFn
->user_back()));
1065 ASSERT_EQ(BFn
->user_back()->getNumUses(), 0U);
1067 Builder
.restoreIP(OMPBuilder
.createBarrier(Builder
.saveIP(), OMPD_parallel
,
1069 ASSERT_EQ(CBFn
->getNumUses(), 2U);
1070 ASSERT_EQ(BFn
->getNumUses(), 1U);
1071 ASSERT_TRUE(CBFn
->user_back() != CheckedBarrier
);
1072 ASSERT_TRUE(isa
<CallInst
>(CBFn
->user_back()));
1073 ASSERT_EQ(CBFn
->user_back()->getNumUses(), 0U);
1076 auto PrivCB
= [&](InsertPointTy
, InsertPointTy
, Value
&V
, Value
&,
1077 Value
*&) -> InsertPointTy
{
1078 ++NumPrivatizedVars
;
1079 llvm_unreachable("No privatization callback call expected!");
1082 FunctionType
*FakeDestructorTy
=
1083 FunctionType::get(Type::getVoidTy(Ctx
), {Type::getInt32Ty(Ctx
)},
1084 /*isVarArg=*/false);
1085 auto *FakeDestructor
= Function::Create(
1086 FakeDestructorTy
, Function::ExternalLinkage
, "fakeDestructor", M
.get());
1088 auto FiniCB
= [&](InsertPointTy IP
) {
1089 ++NumFinalizationPoints
;
1090 Builder
.restoreIP(IP
);
1091 Builder
.CreateCall(FakeDestructor
,
1092 {Builder
.getInt32(NumFinalizationPoints
)});
1095 IRBuilder
<>::InsertPoint
AllocaIP(&F
->getEntryBlock(),
1096 F
->getEntryBlock().getFirstInsertionPt());
1097 IRBuilder
<>::InsertPoint AfterIP
=
1098 OMPBuilder
.createParallel(Loc
, AllocaIP
, BodyGenCB
, PrivCB
, FiniCB
,
1099 Builder
.CreateIsNotNull(F
->arg_begin()),
1100 nullptr, OMP_PROC_BIND_default
, true);
1102 EXPECT_EQ(NumBodiesGenerated
, 1U);
1103 EXPECT_EQ(NumPrivatizedVars
, 0U);
1104 EXPECT_EQ(NumFinalizationPoints
, 2U);
1105 EXPECT_EQ(FakeDestructor
->getNumUses(), 2U);
1107 Builder
.restoreIP(AfterIP
);
1108 Builder
.CreateRetVoid();
1109 OMPBuilder
.finalize();
1111 EXPECT_FALSE(verifyModule(*M
, &errs()));
1113 BasicBlock
*ExitBB
= nullptr;
1114 for (const User
*Usr
: FakeDestructor
->users()) {
1115 const CallInst
*CI
= dyn_cast
<CallInst
>(Usr
);
1116 ASSERT_EQ(CI
->getCalledFunction(), FakeDestructor
);
1117 ASSERT_TRUE(isa
<BranchInst
>(CI
->getNextNode()));
1118 ASSERT_EQ(CI
->getNextNode()->getNumSuccessors(), 1U);
1120 ASSERT_EQ(CI
->getNextNode()->getSuccessor(0), ExitBB
);
1122 ExitBB
= CI
->getNextNode()->getSuccessor(0);
1123 ASSERT_EQ(ExitBB
->size(), 1U);
1124 if (!isa
<ReturnInst
>(ExitBB
->front())) {
1125 ASSERT_TRUE(isa
<BranchInst
>(ExitBB
->front()));
1126 ASSERT_EQ(cast
<BranchInst
>(ExitBB
->front()).getNumSuccessors(), 1U);
1127 ASSERT_TRUE(isa
<ReturnInst
>(
1128 cast
<BranchInst
>(ExitBB
->front()).getSuccessor(0)->front()));
1133 TEST_F(OpenMPIRBuilderTest
, ParallelForwardAsPointers
) {
1134 OpenMPIRBuilder
OMPBuilder(*M
);
1135 OMPBuilder
.initialize();
1137 IRBuilder
<> Builder(BB
);
1138 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
1139 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
1141 Type
*I32Ty
= Type::getInt32Ty(M
->getContext());
1142 Type
*I32PtrTy
= Type::getInt32PtrTy(M
->getContext());
1143 Type
*StructTy
= StructType::get(I32Ty
, I32PtrTy
);
1144 Type
*StructPtrTy
= StructTy
->getPointerTo();
1145 StructType
*ArgStructTy
=
1146 StructType::get(I32PtrTy
, StructPtrTy
, I32PtrTy
, StructPtrTy
);
1147 Type
*VoidTy
= Type::getVoidTy(M
->getContext());
1148 FunctionCallee RetI32Func
= M
->getOrInsertFunction("ret_i32", I32Ty
);
1149 FunctionCallee TakeI32Func
=
1150 M
->getOrInsertFunction("take_i32", VoidTy
, I32Ty
);
1151 FunctionCallee RetI32PtrFunc
= M
->getOrInsertFunction("ret_i32ptr", I32PtrTy
);
1152 FunctionCallee TakeI32PtrFunc
=
1153 M
->getOrInsertFunction("take_i32ptr", VoidTy
, I32PtrTy
);
1154 FunctionCallee RetStructFunc
= M
->getOrInsertFunction("ret_struct", StructTy
);
1155 FunctionCallee TakeStructFunc
=
1156 M
->getOrInsertFunction("take_struct", VoidTy
, StructTy
);
1157 FunctionCallee RetStructPtrFunc
=
1158 M
->getOrInsertFunction("ret_structptr", StructPtrTy
);
1159 FunctionCallee TakeStructPtrFunc
=
1160 M
->getOrInsertFunction("take_structPtr", VoidTy
, StructPtrTy
);
1161 Value
*I32Val
= Builder
.CreateCall(RetI32Func
);
1162 Value
*I32PtrVal
= Builder
.CreateCall(RetI32PtrFunc
);
1163 Value
*StructVal
= Builder
.CreateCall(RetStructFunc
);
1164 Value
*StructPtrVal
= Builder
.CreateCall(RetStructPtrFunc
);
1166 Instruction
*Internal
;
1167 auto BodyGenCB
= [&](InsertPointTy AllocaIP
, InsertPointTy CodeGenIP
) {
1168 IRBuilder
<>::InsertPointGuard
Guard(Builder
);
1169 Builder
.restoreIP(CodeGenIP
);
1170 Internal
= Builder
.CreateCall(TakeI32Func
, I32Val
);
1171 Builder
.CreateCall(TakeI32PtrFunc
, I32PtrVal
);
1172 Builder
.CreateCall(TakeStructFunc
, StructVal
);
1173 Builder
.CreateCall(TakeStructPtrFunc
, StructPtrVal
);
1175 auto PrivCB
= [&](InsertPointTy AllocaIP
, InsertPointTy CodeGenIP
, Value
&,
1176 Value
&Inner
, Value
*&ReplacementValue
) {
1177 ReplacementValue
= &Inner
;
1180 auto FiniCB
= [](InsertPointTy
) {};
1182 IRBuilder
<>::InsertPoint
AllocaIP(&F
->getEntryBlock(),
1183 F
->getEntryBlock().getFirstInsertionPt());
1184 IRBuilder
<>::InsertPoint AfterIP
=
1185 OMPBuilder
.createParallel(Loc
, AllocaIP
, BodyGenCB
, PrivCB
, FiniCB
,
1186 nullptr, nullptr, OMP_PROC_BIND_default
, false);
1187 Builder
.restoreIP(AfterIP
);
1188 Builder
.CreateRetVoid();
1190 OMPBuilder
.finalize();
1192 EXPECT_FALSE(verifyModule(*M
, &errs()));
1193 Function
*OutlinedFn
= Internal
->getFunction();
1195 Type
*Arg2Type
= OutlinedFn
->getArg(2)->getType();
1196 EXPECT_TRUE(Arg2Type
->isPointerTy());
1198 cast
<PointerType
>(Arg2Type
)->isOpaqueOrPointeeTypeMatches(ArgStructTy
));
1201 TEST_F(OpenMPIRBuilderTest
, CanonicalLoopSimple
) {
1202 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
1203 OpenMPIRBuilder
OMPBuilder(*M
);
1204 OMPBuilder
.initialize();
1205 IRBuilder
<> Builder(BB
);
1206 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
1207 Value
*TripCount
= F
->getArg(0);
1209 unsigned NumBodiesGenerated
= 0;
1210 auto LoopBodyGenCB
= [&](InsertPointTy CodeGenIP
, llvm::Value
*LC
) {
1211 NumBodiesGenerated
+= 1;
1213 Builder
.restoreIP(CodeGenIP
);
1215 Value
*Cmp
= Builder
.CreateICmpEQ(LC
, TripCount
);
1216 Instruction
*ThenTerm
, *ElseTerm
;
1217 SplitBlockAndInsertIfThenElse(Cmp
, CodeGenIP
.getBlock()->getTerminator(),
1218 &ThenTerm
, &ElseTerm
);
1221 CanonicalLoopInfo
*Loop
=
1222 OMPBuilder
.createCanonicalLoop(Loc
, LoopBodyGenCB
, TripCount
);
1224 Builder
.restoreIP(Loop
->getAfterIP());
1225 ReturnInst
*RetInst
= Builder
.CreateRetVoid();
1226 OMPBuilder
.finalize();
1229 EXPECT_FALSE(verifyModule(*M
, &errs()));
1231 EXPECT_EQ(NumBodiesGenerated
, 1U);
1233 // Verify control flow structure (in addition to Loop->assertOK()).
1234 EXPECT_EQ(Loop
->getPreheader()->getSinglePredecessor(), &F
->getEntryBlock());
1235 EXPECT_EQ(Loop
->getAfter(), Builder
.GetInsertBlock());
1237 Instruction
*IndVar
= Loop
->getIndVar();
1238 EXPECT_TRUE(isa
<PHINode
>(IndVar
));
1239 EXPECT_EQ(IndVar
->getType(), TripCount
->getType());
1240 EXPECT_EQ(IndVar
->getParent(), Loop
->getHeader());
1242 EXPECT_EQ(Loop
->getTripCount(), TripCount
);
1244 BasicBlock
*Body
= Loop
->getBody();
1245 Instruction
*CmpInst
= &Body
->getInstList().front();
1246 EXPECT_TRUE(isa
<ICmpInst
>(CmpInst
));
1247 EXPECT_EQ(CmpInst
->getOperand(0), IndVar
);
1249 BasicBlock
*LatchPred
= Loop
->getLatch()->getSinglePredecessor();
1250 EXPECT_TRUE(llvm::all_of(successors(Body
), [=](BasicBlock
*SuccBB
) {
1251 return SuccBB
->getSingleSuccessor() == LatchPred
;
1254 EXPECT_EQ(&Loop
->getAfter()->front(), RetInst
);
1257 TEST_F(OpenMPIRBuilderTest
, CanonicalLoopBounds
) {
1258 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
1259 OpenMPIRBuilder
OMPBuilder(*M
);
1260 OMPBuilder
.initialize();
1261 IRBuilder
<> Builder(BB
);
1263 // Check the trip count is computed correctly. We generate the canonical loop
1264 // but rely on the IRBuilder's constant folder to compute the final result
1265 // since all inputs are constant. To verify overflow situations, limit the
1266 // trip count / loop counter widths to 16 bits.
1267 auto EvalTripCount
= [&](int64_t Start
, int64_t Stop
, int64_t Step
,
1268 bool IsSigned
, bool InclusiveStop
) -> int64_t {
1269 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
1270 Type
*LCTy
= Type::getInt16Ty(Ctx
);
1271 Value
*StartVal
= ConstantInt::get(LCTy
, Start
);
1272 Value
*StopVal
= ConstantInt::get(LCTy
, Stop
);
1273 Value
*StepVal
= ConstantInt::get(LCTy
, Step
);
1274 auto LoopBodyGenCB
= [&](InsertPointTy CodeGenIP
, llvm::Value
*LC
) {};
1275 CanonicalLoopInfo
*Loop
=
1276 OMPBuilder
.createCanonicalLoop(Loc
, LoopBodyGenCB
, StartVal
, StopVal
,
1277 StepVal
, IsSigned
, InclusiveStop
);
1279 Builder
.restoreIP(Loop
->getAfterIP());
1280 Value
*TripCount
= Loop
->getTripCount();
1281 return cast
<ConstantInt
>(TripCount
)->getValue().getZExtValue();
1284 EXPECT_EQ(EvalTripCount(0, 0, 1, false, false), 0);
1285 EXPECT_EQ(EvalTripCount(0, 1, 2, false, false), 1);
1286 EXPECT_EQ(EvalTripCount(0, 42, 1, false, false), 42);
1287 EXPECT_EQ(EvalTripCount(0, 42, 2, false, false), 21);
1288 EXPECT_EQ(EvalTripCount(21, 42, 1, false, false), 21);
1289 EXPECT_EQ(EvalTripCount(0, 5, 5, false, false), 1);
1290 EXPECT_EQ(EvalTripCount(0, 9, 5, false, false), 2);
1291 EXPECT_EQ(EvalTripCount(0, 11, 5, false, false), 3);
1292 EXPECT_EQ(EvalTripCount(0, 0xFFFF, 1, false, false), 0xFFFF);
1293 EXPECT_EQ(EvalTripCount(0xFFFF, 0, 1, false, false), 0);
1294 EXPECT_EQ(EvalTripCount(0xFFFE, 0xFFFF, 1, false, false), 1);
1295 EXPECT_EQ(EvalTripCount(0, 0xFFFF, 0x100, false, false), 0x100);
1296 EXPECT_EQ(EvalTripCount(0, 0xFFFF, 0xFFFF, false, false), 1);
1298 EXPECT_EQ(EvalTripCount(0, 6, 5, false, false), 2);
1299 EXPECT_EQ(EvalTripCount(0, 0xFFFF, 0xFFFE, false, false), 2);
1300 EXPECT_EQ(EvalTripCount(0, 0, 1, false, true), 1);
1301 EXPECT_EQ(EvalTripCount(0, 0, 0xFFFF, false, true), 1);
1302 EXPECT_EQ(EvalTripCount(0, 0xFFFE, 1, false, true), 0xFFFF);
1303 EXPECT_EQ(EvalTripCount(0, 0xFFFE, 2, false, true), 0x8000);
1305 EXPECT_EQ(EvalTripCount(0, 0, -1, true, false), 0);
1306 EXPECT_EQ(EvalTripCount(0, 1, -1, true, true), 0);
1307 EXPECT_EQ(EvalTripCount(20, 5, -5, true, false), 3);
1308 EXPECT_EQ(EvalTripCount(20, 5, -5, true, true), 4);
1309 EXPECT_EQ(EvalTripCount(-4, -2, 2, true, false), 1);
1310 EXPECT_EQ(EvalTripCount(-4, -3, 2, true, false), 1);
1311 EXPECT_EQ(EvalTripCount(-4, -2, 2, true, true), 2);
1313 EXPECT_EQ(EvalTripCount(INT16_MIN
, 0, 1, true, false), 0x8000);
1314 EXPECT_EQ(EvalTripCount(INT16_MIN
, 0, 1, true, true), 0x8001);
1315 EXPECT_EQ(EvalTripCount(INT16_MIN
, 0x7FFF, 1, true, false), 0xFFFF);
1316 EXPECT_EQ(EvalTripCount(INT16_MIN
+ 1, 0x7FFF, 1, true, true), 0xFFFF);
1317 EXPECT_EQ(EvalTripCount(INT16_MIN
, 0, 0x7FFF, true, false), 2);
1318 EXPECT_EQ(EvalTripCount(0x7FFF, 0, -1, true, false), 0x7FFF);
1319 EXPECT_EQ(EvalTripCount(0, INT16_MIN
, -1, true, false), 0x8000);
1320 EXPECT_EQ(EvalTripCount(0, INT16_MIN
, -16, true, false), 0x800);
1321 EXPECT_EQ(EvalTripCount(0x7FFF, INT16_MIN
, -1, true, false), 0xFFFF);
1322 EXPECT_EQ(EvalTripCount(0x7FFF, 1, INT16_MIN
, true, false), 1);
1323 EXPECT_EQ(EvalTripCount(0x7FFF, -1, INT16_MIN
, true, true), 2);
1325 // Finalize the function and verify it.
1326 Builder
.CreateRetVoid();
1327 OMPBuilder
.finalize();
1328 EXPECT_FALSE(verifyModule(*M
, &errs()));
1331 TEST_F(OpenMPIRBuilderTest
, CollapseNestedLoops
) {
1332 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
1333 OpenMPIRBuilder
OMPBuilder(*M
);
1334 OMPBuilder
.initialize();
1337 IRBuilder
<> Builder(BB
);
1339 Type
*LCTy
= F
->getArg(0)->getType();
1340 Constant
*One
= ConstantInt::get(LCTy
, 1);
1341 Constant
*Two
= ConstantInt::get(LCTy
, 2);
1342 Value
*OuterTripCount
=
1343 Builder
.CreateAdd(F
->getArg(0), Two
, "tripcount.outer");
1344 Value
*InnerTripCount
=
1345 Builder
.CreateAdd(F
->getArg(0), One
, "tripcount.inner");
1347 // Fix an insertion point for ComputeIP.
1348 BasicBlock
*LoopNextEnter
=
1349 BasicBlock::Create(M
->getContext(), "loopnest.enter", F
,
1350 Builder
.GetInsertBlock()->getNextNode());
1351 BranchInst
*EnterBr
= Builder
.CreateBr(LoopNextEnter
);
1352 InsertPointTy ComputeIP
{EnterBr
->getParent(), EnterBr
->getIterator()};
1354 Builder
.SetInsertPoint(LoopNextEnter
);
1355 OpenMPIRBuilder::LocationDescription
OuterLoc(Builder
.saveIP(), DL
);
1357 CanonicalLoopInfo
*InnerLoop
= nullptr;
1358 CallInst
*InbetweenLead
= nullptr;
1359 CallInst
*InbetweenTrail
= nullptr;
1360 CallInst
*Call
= nullptr;
1361 auto OuterLoopBodyGenCB
= [&](InsertPointTy OuterCodeGenIP
, Value
*OuterLC
) {
1362 Builder
.restoreIP(OuterCodeGenIP
);
1364 createPrintfCall(Builder
, "In-between lead i=%d\\n", {OuterLC
});
1366 auto InnerLoopBodyGenCB
= [&](InsertPointTy InnerCodeGenIP
,
1368 Builder
.restoreIP(InnerCodeGenIP
);
1369 Call
= createPrintfCall(Builder
, "body i=%d j=%d\\n", {OuterLC
, InnerLC
});
1371 InnerLoop
= OMPBuilder
.createCanonicalLoop(
1372 Builder
.saveIP(), InnerLoopBodyGenCB
, InnerTripCount
, "inner");
1374 Builder
.restoreIP(InnerLoop
->getAfterIP());
1376 createPrintfCall(Builder
, "In-between trail i=%d\\n", {OuterLC
});
1378 CanonicalLoopInfo
*OuterLoop
= OMPBuilder
.createCanonicalLoop(
1379 OuterLoc
, OuterLoopBodyGenCB
, OuterTripCount
, "outer");
1381 // Finish the function.
1382 Builder
.restoreIP(OuterLoop
->getAfterIP());
1383 Builder
.CreateRetVoid();
1385 CanonicalLoopInfo
*Collapsed
=
1386 OMPBuilder
.collapseLoops(DL
, {OuterLoop
, InnerLoop
}, ComputeIP
);
1388 OMPBuilder
.finalize();
1389 EXPECT_FALSE(verifyModule(*M
, &errs()));
1391 // Verify control flow and BB order.
1392 BasicBlock
*RefOrder
[] = {
1393 Collapsed
->getPreheader(), Collapsed
->getHeader(),
1394 Collapsed
->getCond(), Collapsed
->getBody(),
1395 InbetweenLead
->getParent(), Call
->getParent(),
1396 InbetweenTrail
->getParent(), Collapsed
->getLatch(),
1397 Collapsed
->getExit(), Collapsed
->getAfter(),
1399 EXPECT_TRUE(verifyDFSOrder(F
, RefOrder
));
1400 EXPECT_TRUE(verifyListOrder(F
, RefOrder
));
1402 // Verify the total trip count.
1403 auto *TripCount
= cast
<MulOperator
>(Collapsed
->getTripCount());
1404 EXPECT_EQ(TripCount
->getOperand(0), OuterTripCount
);
1405 EXPECT_EQ(TripCount
->getOperand(1), InnerTripCount
);
1407 // Verify the changed indvar.
1408 auto *OuterIV
= cast
<BinaryOperator
>(Call
->getOperand(1));
1409 EXPECT_EQ(OuterIV
->getOpcode(), Instruction::UDiv
);
1410 EXPECT_EQ(OuterIV
->getParent(), Collapsed
->getBody());
1411 EXPECT_EQ(OuterIV
->getOperand(1), InnerTripCount
);
1412 EXPECT_EQ(OuterIV
->getOperand(0), Collapsed
->getIndVar());
1414 auto *InnerIV
= cast
<BinaryOperator
>(Call
->getOperand(2));
1415 EXPECT_EQ(InnerIV
->getOpcode(), Instruction::URem
);
1416 EXPECT_EQ(InnerIV
->getParent(), Collapsed
->getBody());
1417 EXPECT_EQ(InnerIV
->getOperand(0), Collapsed
->getIndVar());
1418 EXPECT_EQ(InnerIV
->getOperand(1), InnerTripCount
);
1420 EXPECT_EQ(InbetweenLead
->getOperand(1), OuterIV
);
1421 EXPECT_EQ(InbetweenTrail
->getOperand(1), OuterIV
);
1424 TEST_F(OpenMPIRBuilderTest
, TileSingleLoop
) {
1425 OpenMPIRBuilder
OMPBuilder(*M
);
1427 BasicBlock
*BodyCode
;
1428 CanonicalLoopInfo
*Loop
=
1429 buildSingleLoopFunction(DL
, OMPBuilder
, 32, &Call
, &BodyCode
);
1431 Instruction
*OrigIndVar
= Loop
->getIndVar();
1432 EXPECT_EQ(Call
->getOperand(1), OrigIndVar
);
1435 Constant
*TileSize
= ConstantInt::get(Loop
->getIndVarType(), APInt(32, 7));
1436 std::vector
<CanonicalLoopInfo
*> GenLoops
=
1437 OMPBuilder
.tileLoops(DL
, {Loop
}, {TileSize
});
1439 OMPBuilder
.finalize();
1440 EXPECT_FALSE(verifyModule(*M
, &errs()));
1442 EXPECT_EQ(GenLoops
.size(), 2u);
1443 CanonicalLoopInfo
*Floor
= GenLoops
[0];
1444 CanonicalLoopInfo
*Tile
= GenLoops
[1];
1446 BasicBlock
*RefOrder
[] = {
1447 Floor
->getPreheader(), Floor
->getHeader(), Floor
->getCond(),
1448 Floor
->getBody(), Tile
->getPreheader(), Tile
->getHeader(),
1449 Tile
->getCond(), Tile
->getBody(), BodyCode
,
1450 Tile
->getLatch(), Tile
->getExit(), Tile
->getAfter(),
1451 Floor
->getLatch(), Floor
->getExit(), Floor
->getAfter(),
1453 EXPECT_TRUE(verifyDFSOrder(F
, RefOrder
));
1454 EXPECT_TRUE(verifyListOrder(F
, RefOrder
));
1456 // Check the induction variable.
1457 EXPECT_EQ(Call
->getParent(), BodyCode
);
1458 auto *Shift
= cast
<AddOperator
>(Call
->getOperand(1));
1459 EXPECT_EQ(cast
<Instruction
>(Shift
)->getParent(), Tile
->getBody());
1460 EXPECT_EQ(Shift
->getOperand(1), Tile
->getIndVar());
1461 auto *Scale
= cast
<MulOperator
>(Shift
->getOperand(0));
1462 EXPECT_EQ(cast
<Instruction
>(Scale
)->getParent(), Tile
->getBody());
1463 EXPECT_EQ(Scale
->getOperand(0), TileSize
);
1464 EXPECT_EQ(Scale
->getOperand(1), Floor
->getIndVar());
1467 TEST_F(OpenMPIRBuilderTest
, TileNestedLoops
) {
1468 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
1469 OpenMPIRBuilder
OMPBuilder(*M
);
1470 OMPBuilder
.initialize();
1473 IRBuilder
<> Builder(BB
);
1474 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
1475 Value
*TripCount
= F
->getArg(0);
1476 Type
*LCTy
= TripCount
->getType();
1478 BasicBlock
*BodyCode
= nullptr;
1479 CanonicalLoopInfo
*InnerLoop
= nullptr;
1480 auto OuterLoopBodyGenCB
= [&](InsertPointTy OuterCodeGenIP
,
1481 llvm::Value
*OuterLC
) {
1482 auto InnerLoopBodyGenCB
= [&](InsertPointTy InnerCodeGenIP
,
1483 llvm::Value
*InnerLC
) {
1484 Builder
.restoreIP(InnerCodeGenIP
);
1485 BodyCode
= Builder
.GetInsertBlock();
1487 // Add something that consumes the induction variables to the body.
1488 createPrintfCall(Builder
, "i=%d j=%d\\n", {OuterLC
, InnerLC
});
1490 InnerLoop
= OMPBuilder
.createCanonicalLoop(
1491 OuterCodeGenIP
, InnerLoopBodyGenCB
, TripCount
, "inner");
1493 CanonicalLoopInfo
*OuterLoop
= OMPBuilder
.createCanonicalLoop(
1494 Loc
, OuterLoopBodyGenCB
, TripCount
, "outer");
1496 // Finalize the function.
1497 Builder
.restoreIP(OuterLoop
->getAfterIP());
1498 Builder
.CreateRetVoid();
1500 // Tile to loop nest.
1501 Constant
*OuterTileSize
= ConstantInt::get(LCTy
, APInt(32, 11));
1502 Constant
*InnerTileSize
= ConstantInt::get(LCTy
, APInt(32, 7));
1503 std::vector
<CanonicalLoopInfo
*> GenLoops
= OMPBuilder
.tileLoops(
1504 DL
, {OuterLoop
, InnerLoop
}, {OuterTileSize
, InnerTileSize
});
1506 OMPBuilder
.finalize();
1507 EXPECT_FALSE(verifyModule(*M
, &errs()));
1509 EXPECT_EQ(GenLoops
.size(), 4u);
1510 CanonicalLoopInfo
*Floor1
= GenLoops
[0];
1511 CanonicalLoopInfo
*Floor2
= GenLoops
[1];
1512 CanonicalLoopInfo
*Tile1
= GenLoops
[2];
1513 CanonicalLoopInfo
*Tile2
= GenLoops
[3];
1515 BasicBlock
*RefOrder
[] = {
1516 Floor1
->getPreheader(),
1517 Floor1
->getHeader(),
1520 Floor2
->getPreheader(),
1521 Floor2
->getHeader(),
1524 Tile1
->getPreheader(),
1528 Tile2
->getPreheader(),
1546 EXPECT_TRUE(verifyDFSOrder(F
, RefOrder
));
1547 EXPECT_TRUE(verifyListOrder(F
, RefOrder
));
1550 TEST_F(OpenMPIRBuilderTest
, TileNestedLoopsWithBounds
) {
1551 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
1552 OpenMPIRBuilder
OMPBuilder(*M
);
1553 OMPBuilder
.initialize();
1556 IRBuilder
<> Builder(BB
);
1557 Value
*TripCount
= F
->getArg(0);
1558 Type
*LCTy
= TripCount
->getType();
1560 Value
*OuterStartVal
= ConstantInt::get(LCTy
, 2);
1561 Value
*OuterStopVal
= TripCount
;
1562 Value
*OuterStep
= ConstantInt::get(LCTy
, 5);
1563 Value
*InnerStartVal
= ConstantInt::get(LCTy
, 13);
1564 Value
*InnerStopVal
= TripCount
;
1565 Value
*InnerStep
= ConstantInt::get(LCTy
, 3);
1567 // Fix an insertion point for ComputeIP.
1568 BasicBlock
*LoopNextEnter
=
1569 BasicBlock::Create(M
->getContext(), "loopnest.enter", F
,
1570 Builder
.GetInsertBlock()->getNextNode());
1571 BranchInst
*EnterBr
= Builder
.CreateBr(LoopNextEnter
);
1572 InsertPointTy ComputeIP
{EnterBr
->getParent(), EnterBr
->getIterator()};
1574 InsertPointTy LoopIP
{LoopNextEnter
, LoopNextEnter
->begin()};
1575 OpenMPIRBuilder::LocationDescription
Loc({LoopIP
, DL
});
1577 BasicBlock
*BodyCode
= nullptr;
1578 CanonicalLoopInfo
*InnerLoop
= nullptr;
1579 CallInst
*Call
= nullptr;
1580 auto OuterLoopBodyGenCB
= [&](InsertPointTy OuterCodeGenIP
,
1581 llvm::Value
*OuterLC
) {
1582 auto InnerLoopBodyGenCB
= [&](InsertPointTy InnerCodeGenIP
,
1583 llvm::Value
*InnerLC
) {
1584 Builder
.restoreIP(InnerCodeGenIP
);
1585 BodyCode
= Builder
.GetInsertBlock();
1587 // Add something that consumes the induction variable to the body.
1588 Call
= createPrintfCall(Builder
, "i=%d j=%d\\n", {OuterLC
, InnerLC
});
1590 InnerLoop
= OMPBuilder
.createCanonicalLoop(
1591 OuterCodeGenIP
, InnerLoopBodyGenCB
, InnerStartVal
, InnerStopVal
,
1592 InnerStep
, false, false, ComputeIP
, "inner");
1594 CanonicalLoopInfo
*OuterLoop
= OMPBuilder
.createCanonicalLoop(
1595 Loc
, OuterLoopBodyGenCB
, OuterStartVal
, OuterStopVal
, OuterStep
, false,
1596 false, ComputeIP
, "outer");
1598 // Finalize the function
1599 Builder
.restoreIP(OuterLoop
->getAfterIP());
1600 Builder
.CreateRetVoid();
1602 // Tile the loop nest.
1603 Constant
*TileSize0
= ConstantInt::get(LCTy
, APInt(32, 11));
1604 Constant
*TileSize1
= ConstantInt::get(LCTy
, APInt(32, 7));
1605 std::vector
<CanonicalLoopInfo
*> GenLoops
=
1606 OMPBuilder
.tileLoops(DL
, {OuterLoop
, InnerLoop
}, {TileSize0
, TileSize1
});
1608 OMPBuilder
.finalize();
1609 EXPECT_FALSE(verifyModule(*M
, &errs()));
1611 EXPECT_EQ(GenLoops
.size(), 4u);
1612 CanonicalLoopInfo
*Floor0
= GenLoops
[0];
1613 CanonicalLoopInfo
*Floor1
= GenLoops
[1];
1614 CanonicalLoopInfo
*Tile0
= GenLoops
[2];
1615 CanonicalLoopInfo
*Tile1
= GenLoops
[3];
1617 BasicBlock
*RefOrder
[] = {
1618 Floor0
->getPreheader(),
1619 Floor0
->getHeader(),
1622 Floor1
->getPreheader(),
1623 Floor1
->getHeader(),
1626 Tile0
->getPreheader(),
1630 Tile1
->getPreheader(),
1648 EXPECT_TRUE(verifyDFSOrder(F
, RefOrder
));
1649 EXPECT_TRUE(verifyListOrder(F
, RefOrder
));
1651 EXPECT_EQ(Call
->getParent(), BodyCode
);
1653 auto *RangeShift0
= cast
<AddOperator
>(Call
->getOperand(1));
1654 EXPECT_EQ(RangeShift0
->getOperand(1), OuterStartVal
);
1655 auto *RangeScale0
= cast
<MulOperator
>(RangeShift0
->getOperand(0));
1656 EXPECT_EQ(RangeScale0
->getOperand(1), OuterStep
);
1657 auto *TileShift0
= cast
<AddOperator
>(RangeScale0
->getOperand(0));
1658 EXPECT_EQ(cast
<Instruction
>(TileShift0
)->getParent(), Tile1
->getBody());
1659 EXPECT_EQ(TileShift0
->getOperand(1), Tile0
->getIndVar());
1660 auto *TileScale0
= cast
<MulOperator
>(TileShift0
->getOperand(0));
1661 EXPECT_EQ(cast
<Instruction
>(TileScale0
)->getParent(), Tile1
->getBody());
1662 EXPECT_EQ(TileScale0
->getOperand(0), TileSize0
);
1663 EXPECT_EQ(TileScale0
->getOperand(1), Floor0
->getIndVar());
1665 auto *RangeShift1
= cast
<AddOperator
>(Call
->getOperand(2));
1666 EXPECT_EQ(cast
<Instruction
>(RangeShift1
)->getParent(), BodyCode
);
1667 EXPECT_EQ(RangeShift1
->getOperand(1), InnerStartVal
);
1668 auto *RangeScale1
= cast
<MulOperator
>(RangeShift1
->getOperand(0));
1669 EXPECT_EQ(cast
<Instruction
>(RangeScale1
)->getParent(), BodyCode
);
1670 EXPECT_EQ(RangeScale1
->getOperand(1), InnerStep
);
1671 auto *TileShift1
= cast
<AddOperator
>(RangeScale1
->getOperand(0));
1672 EXPECT_EQ(cast
<Instruction
>(TileShift1
)->getParent(), Tile1
->getBody());
1673 EXPECT_EQ(TileShift1
->getOperand(1), Tile1
->getIndVar());
1674 auto *TileScale1
= cast
<MulOperator
>(TileShift1
->getOperand(0));
1675 EXPECT_EQ(cast
<Instruction
>(TileScale1
)->getParent(), Tile1
->getBody());
1676 EXPECT_EQ(TileScale1
->getOperand(0), TileSize1
);
1677 EXPECT_EQ(TileScale1
->getOperand(1), Floor1
->getIndVar());
1680 TEST_F(OpenMPIRBuilderTest
, TileSingleLoopCounts
) {
1681 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
1682 OpenMPIRBuilder
OMPBuilder(*M
);
1683 OMPBuilder
.initialize();
1684 IRBuilder
<> Builder(BB
);
1686 // Create a loop, tile it, and extract its trip count. All input values are
1687 // constant and IRBuilder evaluates all-constant arithmetic inplace, such that
1688 // the floor trip count itself will be a ConstantInt. Unfortunately we cannot
1689 // do the same for the tile loop.
1690 auto GetFloorCount
= [&](int64_t Start
, int64_t Stop
, int64_t Step
,
1691 bool IsSigned
, bool InclusiveStop
,
1692 int64_t TileSize
) -> uint64_t {
1693 OpenMPIRBuilder::LocationDescription
Loc(Builder
.saveIP(), DL
);
1694 Type
*LCTy
= Type::getInt16Ty(Ctx
);
1695 Value
*StartVal
= ConstantInt::get(LCTy
, Start
);
1696 Value
*StopVal
= ConstantInt::get(LCTy
, Stop
);
1697 Value
*StepVal
= ConstantInt::get(LCTy
, Step
);
1700 auto LoopBodyGenCB
= [&](InsertPointTy CodeGenIP
, llvm::Value
*LC
) {};
1701 CanonicalLoopInfo
*Loop
=
1702 OMPBuilder
.createCanonicalLoop(Loc
, LoopBodyGenCB
, StartVal
, StopVal
,
1703 StepVal
, IsSigned
, InclusiveStop
);
1704 InsertPointTy AfterIP
= Loop
->getAfterIP();
1707 Value
*TileSizeVal
= ConstantInt::get(LCTy
, TileSize
);
1708 std::vector
<CanonicalLoopInfo
*> GenLoops
=
1709 OMPBuilder
.tileLoops(Loc
.DL
, {Loop
}, {TileSizeVal
});
1711 // Set the insertion pointer to after loop, where the next loop will be
1713 Builder
.restoreIP(AfterIP
);
1715 // Extract the trip count.
1716 CanonicalLoopInfo
*FloorLoop
= GenLoops
[0];
1717 Value
*FloorTripCount
= FloorLoop
->getTripCount();
1718 return cast
<ConstantInt
>(FloorTripCount
)->getValue().getZExtValue();
1721 // Empty iteration domain.
1722 EXPECT_EQ(GetFloorCount(0, 0, 1, false, false, 7), 0u);
1723 EXPECT_EQ(GetFloorCount(0, -1, 1, false, true, 7), 0u);
1724 EXPECT_EQ(GetFloorCount(-1, -1, -1, true, false, 7), 0u);
1725 EXPECT_EQ(GetFloorCount(-1, 0, -1, true, true, 7), 0u);
1726 EXPECT_EQ(GetFloorCount(-1, -1, 3, true, false, 7), 0u);
1728 // Only complete tiles.
1729 EXPECT_EQ(GetFloorCount(0, 14, 1, false, false, 7), 2u);
1730 EXPECT_EQ(GetFloorCount(0, 14, 1, false, false, 7), 2u);
1731 EXPECT_EQ(GetFloorCount(1, 15, 1, false, false, 7), 2u);
1732 EXPECT_EQ(GetFloorCount(0, -14, -1, true, false, 7), 2u);
1733 EXPECT_EQ(GetFloorCount(-1, -14, -1, true, true, 7), 2u);
1734 EXPECT_EQ(GetFloorCount(0, 3 * 7 * 2, 3, false, false, 7), 2u);
1736 // Only a partial tile.
1737 EXPECT_EQ(GetFloorCount(0, 1, 1, false, false, 7), 1u);
1738 EXPECT_EQ(GetFloorCount(0, 6, 1, false, false, 7), 1u);
1739 EXPECT_EQ(GetFloorCount(-1, 1, 3, true, false, 7), 1u);
1740 EXPECT_EQ(GetFloorCount(-1, -2, -1, true, false, 7), 1u);
1741 EXPECT_EQ(GetFloorCount(0, 2, 3, false, false, 7), 1u);
1743 // Complete and partial tiles.
1744 EXPECT_EQ(GetFloorCount(0, 13, 1, false, false, 7), 2u);
1745 EXPECT_EQ(GetFloorCount(0, 15, 1, false, false, 7), 3u);
1746 EXPECT_EQ(GetFloorCount(-1, -14, -1, true, false, 7), 2u);
1747 EXPECT_EQ(GetFloorCount(0, 3 * 7 * 5 - 1, 3, false, false, 7), 5u);
1748 EXPECT_EQ(GetFloorCount(-1, -3 * 7 * 5, -3, true, false, 7), 5u);
1750 // Close to 16-bit integer range.
1751 EXPECT_EQ(GetFloorCount(0, 0xFFFF, 1, false, false, 1), 0xFFFFu
);
1752 EXPECT_EQ(GetFloorCount(0, 0xFFFF, 1, false, false, 7), 0xFFFFu
/ 7 + 1);
1753 EXPECT_EQ(GetFloorCount(0, 0xFFFE, 1, false, true, 7), 0xFFFFu
/ 7 + 1);
1754 EXPECT_EQ(GetFloorCount(-0x8000, 0x7FFF, 1, true, false, 7), 0xFFFFu
/ 7 + 1);
1755 EXPECT_EQ(GetFloorCount(-0x7FFF, 0x7FFF, 1, true, true, 7), 0xFFFFu
/ 7 + 1);
1756 EXPECT_EQ(GetFloorCount(0, 0xFFFE, 1, false, false, 0xFFFF), 1u);
1757 EXPECT_EQ(GetFloorCount(-0x8000, 0x7FFF, 1, true, false, 0xFFFF), 1u);
1759 // Finalize the function.
1760 Builder
.CreateRetVoid();
1761 OMPBuilder
.finalize();
1763 EXPECT_FALSE(verifyModule(*M
, &errs()));
1766 TEST_F(OpenMPIRBuilderTest
, ApplySimd
) {
1767 OpenMPIRBuilder
OMPBuilder(*M
);
1769 CanonicalLoopInfo
*CLI
= buildSingleLoopFunction(DL
, OMPBuilder
, 32);
1771 // Simd-ize the loop.
1772 OMPBuilder
.applySimd(DL
, CLI
);
1774 OMPBuilder
.finalize();
1775 EXPECT_FALSE(verifyModule(*M
, &errs()));
1778 FunctionAnalysisManager FAM
;
1779 PB
.registerFunctionAnalyses(FAM
);
1780 LoopInfo
&LI
= FAM
.getResult
<LoopAnalysis
>(*F
);
1782 const std::vector
<Loop
*> &TopLvl
= LI
.getTopLevelLoops();
1783 EXPECT_EQ(TopLvl
.size(), 1u);
1785 Loop
*L
= TopLvl
.front();
1786 EXPECT_TRUE(findStringMetadataForLoop(L
, "llvm.loop.parallel_accesses"));
1787 EXPECT_TRUE(getBooleanLoopAttribute(L
, "llvm.loop.vectorize.enable"));
1789 // Check for llvm.access.group metadata attached to the printf
1790 // function in the loop body.
1791 BasicBlock
*LoopBody
= CLI
->getBody();
1792 EXPECT_TRUE(any_of(*LoopBody
, [](Instruction
&I
) {
1793 return I
.getMetadata("llvm.access.group") != nullptr;
1797 TEST_F(OpenMPIRBuilderTest
, UnrollLoopFull
) {
1798 OpenMPIRBuilder
OMPBuilder(*M
);
1800 CanonicalLoopInfo
*CLI
= buildSingleLoopFunction(DL
, OMPBuilder
, 32);
1803 OMPBuilder
.unrollLoopFull(DL
, CLI
);
1805 OMPBuilder
.finalize();
1806 EXPECT_FALSE(verifyModule(*M
, &errs()));
1809 FunctionAnalysisManager FAM
;
1810 PB
.registerFunctionAnalyses(FAM
);
1811 LoopInfo
&LI
= FAM
.getResult
<LoopAnalysis
>(*F
);
1813 const std::vector
<Loop
*> &TopLvl
= LI
.getTopLevelLoops();
1814 EXPECT_EQ(TopLvl
.size(), 1u);
1816 Loop
*L
= TopLvl
.front();
1817 EXPECT_TRUE(getBooleanLoopAttribute(L
, "llvm.loop.unroll.enable"));
1818 EXPECT_TRUE(getBooleanLoopAttribute(L
, "llvm.loop.unroll.full"));
1821 TEST_F(OpenMPIRBuilderTest
, UnrollLoopPartial
) {
1822 OpenMPIRBuilder
OMPBuilder(*M
);
1823 CanonicalLoopInfo
*CLI
= buildSingleLoopFunction(DL
, OMPBuilder
, 32);
1826 CanonicalLoopInfo
*UnrolledLoop
= nullptr;
1827 OMPBuilder
.unrollLoopPartial(DL
, CLI
, 5, &UnrolledLoop
);
1828 ASSERT_NE(UnrolledLoop
, nullptr);
1830 OMPBuilder
.finalize();
1831 EXPECT_FALSE(verifyModule(*M
, &errs()));
1832 UnrolledLoop
->assertOK();
1835 FunctionAnalysisManager FAM
;
1836 PB
.registerFunctionAnalyses(FAM
);
1837 LoopInfo
&LI
= FAM
.getResult
<LoopAnalysis
>(*F
);
1839 const std::vector
<Loop
*> &TopLvl
= LI
.getTopLevelLoops();
1840 EXPECT_EQ(TopLvl
.size(), 1u);
1841 Loop
*Outer
= TopLvl
.front();
1842 EXPECT_EQ(Outer
->getHeader(), UnrolledLoop
->getHeader());
1843 EXPECT_EQ(Outer
->getLoopLatch(), UnrolledLoop
->getLatch());
1844 EXPECT_EQ(Outer
->getExitingBlock(), UnrolledLoop
->getCond());
1845 EXPECT_EQ(Outer
->getExitBlock(), UnrolledLoop
->getExit());
1847 EXPECT_EQ(Outer
->getSubLoops().size(), 1u);
1848 Loop
*Inner
= Outer
->getSubLoops().front();
1850 EXPECT_TRUE(getBooleanLoopAttribute(Inner
, "llvm.loop.unroll.enable"));
1851 EXPECT_EQ(getIntLoopAttribute(Inner
, "llvm.loop.unroll.count"), 5);
1854 TEST_F(OpenMPIRBuilderTest
, UnrollLoopHeuristic
) {
1855 OpenMPIRBuilder
OMPBuilder(*M
);
1857 CanonicalLoopInfo
*CLI
= buildSingleLoopFunction(DL
, OMPBuilder
, 32);
1860 OMPBuilder
.unrollLoopHeuristic(DL
, CLI
);
1862 OMPBuilder
.finalize();
1863 EXPECT_FALSE(verifyModule(*M
, &errs()));
1866 FunctionAnalysisManager FAM
;
1867 PB
.registerFunctionAnalyses(FAM
);
1868 LoopInfo
&LI
= FAM
.getResult
<LoopAnalysis
>(*F
);
1870 const std::vector
<Loop
*> &TopLvl
= LI
.getTopLevelLoops();
1871 EXPECT_EQ(TopLvl
.size(), 1u);
1873 Loop
*L
= TopLvl
.front();
1874 EXPECT_TRUE(getBooleanLoopAttribute(L
, "llvm.loop.unroll.enable"));
1877 TEST_F(OpenMPIRBuilderTest
, StaticWorkShareLoop
) {
1878 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
1879 OpenMPIRBuilder
OMPBuilder(*M
);
1880 OMPBuilder
.initialize();
1881 IRBuilder
<> Builder(BB
);
1882 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
1884 Type
*LCTy
= Type::getInt32Ty(Ctx
);
1885 Value
*StartVal
= ConstantInt::get(LCTy
, 10);
1886 Value
*StopVal
= ConstantInt::get(LCTy
, 52);
1887 Value
*StepVal
= ConstantInt::get(LCTy
, 2);
1888 auto LoopBodyGen
= [&](InsertPointTy
, llvm::Value
*) {};
1890 CanonicalLoopInfo
*CLI
= OMPBuilder
.createCanonicalLoop(
1891 Loc
, LoopBodyGen
, StartVal
, StopVal
, StepVal
,
1892 /*IsSigned=*/false, /*InclusiveStop=*/false);
1893 BasicBlock
*Preheader
= CLI
->getPreheader();
1894 BasicBlock
*Body
= CLI
->getBody();
1895 Value
*IV
= CLI
->getIndVar();
1896 BasicBlock
*ExitBlock
= CLI
->getExit();
1898 Builder
.SetInsertPoint(BB
, BB
->getFirstInsertionPt());
1899 InsertPointTy AllocaIP
= Builder
.saveIP();
1901 OMPBuilder
.applyWorkshareLoop(DL
, CLI
, AllocaIP
, /*NeedsBarrier=*/true,
1902 OMP_SCHEDULE_Static
);
1904 BasicBlock
*Cond
= Body
->getSinglePredecessor();
1905 Instruction
*Cmp
= &*Cond
->begin();
1906 Value
*TripCount
= Cmp
->getOperand(1);
1908 auto AllocaIter
= BB
->begin();
1909 ASSERT_GE(std::distance(BB
->begin(), BB
->end()), 4);
1910 AllocaInst
*PLastIter
= dyn_cast
<AllocaInst
>(&*(AllocaIter
++));
1911 AllocaInst
*PLowerBound
= dyn_cast
<AllocaInst
>(&*(AllocaIter
++));
1912 AllocaInst
*PUpperBound
= dyn_cast
<AllocaInst
>(&*(AllocaIter
++));
1913 AllocaInst
*PStride
= dyn_cast
<AllocaInst
>(&*(AllocaIter
++));
1914 EXPECT_NE(PLastIter
, nullptr);
1915 EXPECT_NE(PLowerBound
, nullptr);
1916 EXPECT_NE(PUpperBound
, nullptr);
1917 EXPECT_NE(PStride
, nullptr);
1919 auto PreheaderIter
= Preheader
->begin();
1920 ASSERT_GE(std::distance(Preheader
->begin(), Preheader
->end()), 7);
1921 StoreInst
*LowerBoundStore
= dyn_cast
<StoreInst
>(&*(PreheaderIter
++));
1922 StoreInst
*UpperBoundStore
= dyn_cast
<StoreInst
>(&*(PreheaderIter
++));
1923 StoreInst
*StrideStore
= dyn_cast
<StoreInst
>(&*(PreheaderIter
++));
1924 ASSERT_NE(LowerBoundStore
, nullptr);
1925 ASSERT_NE(UpperBoundStore
, nullptr);
1926 ASSERT_NE(StrideStore
, nullptr);
1928 auto *OrigLowerBound
=
1929 dyn_cast
<ConstantInt
>(LowerBoundStore
->getValueOperand());
1930 auto *OrigUpperBound
=
1931 dyn_cast
<ConstantInt
>(UpperBoundStore
->getValueOperand());
1932 auto *OrigStride
= dyn_cast
<ConstantInt
>(StrideStore
->getValueOperand());
1933 ASSERT_NE(OrigLowerBound
, nullptr);
1934 ASSERT_NE(OrigUpperBound
, nullptr);
1935 ASSERT_NE(OrigStride
, nullptr);
1936 EXPECT_EQ(OrigLowerBound
->getValue(), 0);
1937 EXPECT_EQ(OrigUpperBound
->getValue(), 20);
1938 EXPECT_EQ(OrigStride
->getValue(), 1);
1940 // Check that the loop IV is updated to account for the lower bound returned
1941 // by the OpenMP runtime call.
1942 BinaryOperator
*Add
= dyn_cast
<BinaryOperator
>(&Body
->front());
1943 EXPECT_EQ(Add
->getOperand(0), IV
);
1944 auto *LoadedLowerBound
= dyn_cast
<LoadInst
>(Add
->getOperand(1));
1945 ASSERT_NE(LoadedLowerBound
, nullptr);
1946 EXPECT_EQ(LoadedLowerBound
->getPointerOperand(), PLowerBound
);
1948 // Check that the trip count is updated to account for the lower and upper
1949 // bounds return by the OpenMP runtime call.
1950 auto *AddOne
= dyn_cast
<Instruction
>(TripCount
);
1951 ASSERT_NE(AddOne
, nullptr);
1952 ASSERT_TRUE(AddOne
->isBinaryOp());
1953 auto *One
= dyn_cast
<ConstantInt
>(AddOne
->getOperand(1));
1954 ASSERT_NE(One
, nullptr);
1955 EXPECT_EQ(One
->getValue(), 1);
1956 auto *Difference
= dyn_cast
<Instruction
>(AddOne
->getOperand(0));
1957 ASSERT_NE(Difference
, nullptr);
1958 ASSERT_TRUE(Difference
->isBinaryOp());
1959 EXPECT_EQ(Difference
->getOperand(1), LoadedLowerBound
);
1960 auto *LoadedUpperBound
= dyn_cast
<LoadInst
>(Difference
->getOperand(0));
1961 ASSERT_NE(LoadedUpperBound
, nullptr);
1962 EXPECT_EQ(LoadedUpperBound
->getPointerOperand(), PUpperBound
);
1964 // The original loop iterator should only be used in the condition, in the
1965 // increment and in the statement that adds the lower bound to it.
1966 EXPECT_EQ(std::distance(IV
->use_begin(), IV
->use_end()), 3);
1968 // The exit block should contain the "fini" call and the barrier call,
1969 // plus the call to obtain the thread ID.
1970 size_t NumCallsInExitBlock
=
1971 count_if(*ExitBlock
, [](Instruction
&I
) { return isa
<CallInst
>(I
); });
1972 EXPECT_EQ(NumCallsInExitBlock
, 3u);
1975 TEST_P(OpenMPIRBuilderTestWithIVBits
, StaticChunkedWorkshareLoop
) {
1976 unsigned IVBits
= GetParam();
1978 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
1979 OpenMPIRBuilder
OMPBuilder(*M
);
1983 CanonicalLoopInfo
*CLI
=
1984 buildSingleLoopFunction(DL
, OMPBuilder
, IVBits
, &Call
, &Body
);
1986 Instruction
*OrigIndVar
= CLI
->getIndVar();
1987 EXPECT_EQ(Call
->getOperand(1), OrigIndVar
);
1989 Type
*LCTy
= Type::getInt32Ty(Ctx
);
1990 Value
*ChunkSize
= ConstantInt::get(LCTy
, 5);
1991 InsertPointTy AllocaIP
{&F
->getEntryBlock(),
1992 F
->getEntryBlock().getFirstInsertionPt()};
1993 OMPBuilder
.applyWorkshareLoop(DL
, CLI
, AllocaIP
, /*NeedsBarrier=*/true,
1994 OMP_SCHEDULE_Static
, ChunkSize
);
1996 OMPBuilder
.finalize();
1997 EXPECT_FALSE(verifyModule(*M
, &errs()));
1999 BasicBlock
*Entry
= &F
->getEntryBlock();
2000 BasicBlock
*Preheader
= Entry
->getSingleSuccessor();
2002 BasicBlock
*DispatchPreheader
= Preheader
->getSingleSuccessor();
2003 BasicBlock
*DispatchHeader
= DispatchPreheader
->getSingleSuccessor();
2004 BasicBlock
*DispatchCond
= DispatchHeader
->getSingleSuccessor();
2005 BasicBlock
*DispatchBody
= succ_begin(DispatchCond
)[0];
2006 BasicBlock
*DispatchExit
= succ_begin(DispatchCond
)[1];
2007 BasicBlock
*DispatchAfter
= DispatchExit
->getSingleSuccessor();
2008 BasicBlock
*Return
= DispatchAfter
->getSingleSuccessor();
2010 BasicBlock
*ChunkPreheader
= DispatchBody
->getSingleSuccessor();
2011 BasicBlock
*ChunkHeader
= ChunkPreheader
->getSingleSuccessor();
2012 BasicBlock
*ChunkCond
= ChunkHeader
->getSingleSuccessor();
2013 BasicBlock
*ChunkBody
= succ_begin(ChunkCond
)[0];
2014 BasicBlock
*ChunkExit
= succ_begin(ChunkCond
)[1];
2015 BasicBlock
*ChunkInc
= ChunkBody
->getSingleSuccessor();
2016 BasicBlock
*ChunkAfter
= ChunkExit
->getSingleSuccessor();
2018 BasicBlock
*DispatchInc
= ChunkAfter
;
2020 EXPECT_EQ(ChunkBody
, Body
);
2021 EXPECT_EQ(ChunkInc
->getSingleSuccessor(), ChunkHeader
);
2022 EXPECT_EQ(DispatchInc
->getSingleSuccessor(), DispatchHeader
);
2024 EXPECT_TRUE(isa
<ReturnInst
>(Return
->front()));
2026 Value
*NewIV
= Call
->getOperand(1);
2027 EXPECT_EQ(NewIV
->getType()->getScalarSizeInBits(), IVBits
);
2029 CallInst
*InitCall
= findSingleCall(
2031 (IVBits
> 32) ? omp::RuntimeFunction::OMPRTL___kmpc_for_static_init_8u
2032 : omp::RuntimeFunction::OMPRTL___kmpc_for_static_init_4u
,
2034 EXPECT_EQ(InitCall
->getParent(), Preheader
);
2035 EXPECT_EQ(cast
<ConstantInt
>(InitCall
->getArgOperand(2))->getSExtValue(), 33);
2036 EXPECT_EQ(cast
<ConstantInt
>(InitCall
->getArgOperand(7))->getSExtValue(), 1);
2037 EXPECT_EQ(cast
<ConstantInt
>(InitCall
->getArgOperand(8))->getSExtValue(), 5);
2039 CallInst
*FiniCall
= findSingleCall(
2040 F
, omp::RuntimeFunction::OMPRTL___kmpc_for_static_fini
, OMPBuilder
);
2041 EXPECT_EQ(FiniCall
->getParent(), DispatchExit
);
2043 CallInst
*BarrierCall
= findSingleCall(
2044 F
, omp::RuntimeFunction::OMPRTL___kmpc_barrier
, OMPBuilder
);
2045 EXPECT_EQ(BarrierCall
->getParent(), DispatchExit
);
2048 INSTANTIATE_TEST_SUITE_P(IVBits
, OpenMPIRBuilderTestWithIVBits
,
2049 ::testing::Values(8, 16, 32, 64));
2051 TEST_P(OpenMPIRBuilderTestWithParams
, DynamicWorkShareLoop
) {
2052 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
2053 OpenMPIRBuilder
OMPBuilder(*M
);
2054 OMPBuilder
.initialize();
2055 IRBuilder
<> Builder(BB
);
2056 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
2058 omp::OMPScheduleType SchedType
= GetParam();
2059 uint32_t ChunkSize
= 1;
2060 switch (SchedType
& ~OMPScheduleType::ModifierMask
) {
2061 case omp::OMPScheduleType::BaseDynamicChunked
:
2062 case omp::OMPScheduleType::BaseGuidedChunked
:
2065 case omp::OMPScheduleType::BaseAuto
:
2066 case omp::OMPScheduleType::BaseRuntime
:
2070 assert(0 && "unknown type for this test");
2074 Type
*LCTy
= Type::getInt32Ty(Ctx
);
2075 Value
*StartVal
= ConstantInt::get(LCTy
, 10);
2076 Value
*StopVal
= ConstantInt::get(LCTy
, 52);
2077 Value
*StepVal
= ConstantInt::get(LCTy
, 2);
2079 (ChunkSize
== 1) ? nullptr : ConstantInt::get(LCTy
, ChunkSize
);
2080 auto LoopBodyGen
= [&](InsertPointTy
, llvm::Value
*) {};
2082 CanonicalLoopInfo
*CLI
= OMPBuilder
.createCanonicalLoop(
2083 Loc
, LoopBodyGen
, StartVal
, StopVal
, StepVal
,
2084 /*IsSigned=*/false, /*InclusiveStop=*/false);
2086 Builder
.SetInsertPoint(BB
, BB
->getFirstInsertionPt());
2087 InsertPointTy AllocaIP
= Builder
.saveIP();
2089 // Collect all the info from CLI, as it isn't usable after the call to
2090 // createDynamicWorkshareLoop.
2091 InsertPointTy AfterIP
= CLI
->getAfterIP();
2092 BasicBlock
*Preheader
= CLI
->getPreheader();
2093 BasicBlock
*ExitBlock
= CLI
->getExit();
2094 BasicBlock
*LatchBlock
= CLI
->getLatch();
2095 Value
*IV
= CLI
->getIndVar();
2097 InsertPointTy EndIP
= OMPBuilder
.applyWorkshareLoop(
2098 DL
, CLI
, AllocaIP
, /*NeedsBarrier=*/true, getSchedKind(SchedType
),
2099 ChunkVal
, /*Simd=*/false,
2100 (SchedType
& omp::OMPScheduleType::ModifierMonotonic
) ==
2101 omp::OMPScheduleType::ModifierMonotonic
,
2102 (SchedType
& omp::OMPScheduleType::ModifierNonmonotonic
) ==
2103 omp::OMPScheduleType::ModifierNonmonotonic
,
2106 // The returned value should be the "after" point.
2107 ASSERT_EQ(EndIP
.getBlock(), AfterIP
.getBlock());
2108 ASSERT_EQ(EndIP
.getPoint(), AfterIP
.getPoint());
2110 auto AllocaIter
= BB
->begin();
2111 ASSERT_GE(std::distance(BB
->begin(), BB
->end()), 4);
2112 AllocaInst
*PLastIter
= dyn_cast
<AllocaInst
>(&*(AllocaIter
++));
2113 AllocaInst
*PLowerBound
= dyn_cast
<AllocaInst
>(&*(AllocaIter
++));
2114 AllocaInst
*PUpperBound
= dyn_cast
<AllocaInst
>(&*(AllocaIter
++));
2115 AllocaInst
*PStride
= dyn_cast
<AllocaInst
>(&*(AllocaIter
++));
2116 EXPECT_NE(PLastIter
, nullptr);
2117 EXPECT_NE(PLowerBound
, nullptr);
2118 EXPECT_NE(PUpperBound
, nullptr);
2119 EXPECT_NE(PStride
, nullptr);
2121 auto PreheaderIter
= Preheader
->begin();
2122 ASSERT_GE(std::distance(Preheader
->begin(), Preheader
->end()), 6);
2123 StoreInst
*LowerBoundStore
= dyn_cast
<StoreInst
>(&*(PreheaderIter
++));
2124 StoreInst
*UpperBoundStore
= dyn_cast
<StoreInst
>(&*(PreheaderIter
++));
2125 StoreInst
*StrideStore
= dyn_cast
<StoreInst
>(&*(PreheaderIter
++));
2126 ASSERT_NE(LowerBoundStore
, nullptr);
2127 ASSERT_NE(UpperBoundStore
, nullptr);
2128 ASSERT_NE(StrideStore
, nullptr);
2130 CallInst
*ThreadIdCall
= dyn_cast
<CallInst
>(&*(PreheaderIter
++));
2131 ASSERT_NE(ThreadIdCall
, nullptr);
2132 EXPECT_EQ(ThreadIdCall
->getCalledFunction()->getName(),
2133 "__kmpc_global_thread_num");
2135 CallInst
*InitCall
= dyn_cast
<CallInst
>(&*PreheaderIter
);
2137 ASSERT_NE(InitCall
, nullptr);
2138 EXPECT_EQ(InitCall
->getCalledFunction()->getName(),
2139 "__kmpc_dispatch_init_4u");
2140 EXPECT_EQ(InitCall
->arg_size(), 7U);
2141 EXPECT_EQ(InitCall
->getArgOperand(6), ConstantInt::get(LCTy
, ChunkSize
));
2142 ConstantInt
*SchedVal
= cast
<ConstantInt
>(InitCall
->getArgOperand(2));
2143 if ((SchedType
& OMPScheduleType::MonotonicityMask
) ==
2144 OMPScheduleType::None
) {
2145 // Implementation is allowed to add default nonmonotonicity flag
2147 static_cast<OMPScheduleType
>(SchedVal
->getValue().getZExtValue()) |
2148 OMPScheduleType::ModifierNonmonotonic
,
2149 SchedType
| OMPScheduleType::ModifierNonmonotonic
);
2151 EXPECT_EQ(static_cast<OMPScheduleType
>(SchedVal
->getValue().getZExtValue()),
2155 ConstantInt
*OrigLowerBound
=
2156 dyn_cast
<ConstantInt
>(LowerBoundStore
->getValueOperand());
2157 ConstantInt
*OrigUpperBound
=
2158 dyn_cast
<ConstantInt
>(UpperBoundStore
->getValueOperand());
2159 ConstantInt
*OrigStride
=
2160 dyn_cast
<ConstantInt
>(StrideStore
->getValueOperand());
2161 ASSERT_NE(OrigLowerBound
, nullptr);
2162 ASSERT_NE(OrigUpperBound
, nullptr);
2163 ASSERT_NE(OrigStride
, nullptr);
2164 EXPECT_EQ(OrigLowerBound
->getValue(), 1);
2165 EXPECT_EQ(OrigUpperBound
->getValue(), 21);
2166 EXPECT_EQ(OrigStride
->getValue(), 1);
2168 CallInst
*FiniCall
= dyn_cast
<CallInst
>(
2169 &*(LatchBlock
->getTerminator()->getPrevNonDebugInstruction(true)));
2170 EXPECT_EQ(FiniCall
, nullptr);
2172 // The original loop iterator should only be used in the condition, in the
2173 // increment and in the statement that adds the lower bound to it.
2174 EXPECT_EQ(std::distance(IV
->use_begin(), IV
->use_end()), 3);
2176 // The exit block should contain the barrier call, plus the call to obtain
2178 size_t NumCallsInExitBlock
=
2179 count_if(*ExitBlock
, [](Instruction
&I
) { return isa
<CallInst
>(I
); });
2180 EXPECT_EQ(NumCallsInExitBlock
, 2u);
2182 // Add a termination to our block and check that it is internally consistent.
2183 Builder
.restoreIP(EndIP
);
2184 Builder
.CreateRetVoid();
2185 OMPBuilder
.finalize();
2186 EXPECT_FALSE(verifyModule(*M
, &errs()));
2189 INSTANTIATE_TEST_SUITE_P(
2190 OpenMPWSLoopSchedulingTypes
, OpenMPIRBuilderTestWithParams
,
2191 ::testing::Values(omp::OMPScheduleType::UnorderedDynamicChunked
,
2192 omp::OMPScheduleType::UnorderedGuidedChunked
,
2193 omp::OMPScheduleType::UnorderedAuto
,
2194 omp::OMPScheduleType::UnorderedRuntime
,
2195 omp::OMPScheduleType::UnorderedDynamicChunked
|
2196 omp::OMPScheduleType::ModifierMonotonic
,
2197 omp::OMPScheduleType::UnorderedDynamicChunked
|
2198 omp::OMPScheduleType::ModifierNonmonotonic
,
2199 omp::OMPScheduleType::UnorderedGuidedChunked
|
2200 omp::OMPScheduleType::ModifierMonotonic
,
2201 omp::OMPScheduleType::UnorderedGuidedChunked
|
2202 omp::OMPScheduleType::ModifierNonmonotonic
,
2203 omp::OMPScheduleType::UnorderedAuto
|
2204 omp::OMPScheduleType::ModifierMonotonic
,
2205 omp::OMPScheduleType::UnorderedRuntime
|
2206 omp::OMPScheduleType::ModifierMonotonic
));
2208 TEST_F(OpenMPIRBuilderTest
, DynamicWorkShareLoopOrdered
) {
2209 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
2210 OpenMPIRBuilder
OMPBuilder(*M
);
2211 OMPBuilder
.initialize();
2212 IRBuilder
<> Builder(BB
);
2213 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
2215 uint32_t ChunkSize
= 1;
2216 Type
*LCTy
= Type::getInt32Ty(Ctx
);
2217 Value
*StartVal
= ConstantInt::get(LCTy
, 10);
2218 Value
*StopVal
= ConstantInt::get(LCTy
, 52);
2219 Value
*StepVal
= ConstantInt::get(LCTy
, 2);
2220 Value
*ChunkVal
= ConstantInt::get(LCTy
, ChunkSize
);
2221 auto LoopBodyGen
= [&](InsertPointTy
, llvm::Value
*) {};
2223 CanonicalLoopInfo
*CLI
= OMPBuilder
.createCanonicalLoop(
2224 Loc
, LoopBodyGen
, StartVal
, StopVal
, StepVal
,
2225 /*IsSigned=*/false, /*InclusiveStop=*/false);
2227 Builder
.SetInsertPoint(BB
, BB
->getFirstInsertionPt());
2228 InsertPointTy AllocaIP
= Builder
.saveIP();
2230 // Collect all the info from CLI, as it isn't usable after the call to
2231 // createDynamicWorkshareLoop.
2232 BasicBlock
*Preheader
= CLI
->getPreheader();
2233 BasicBlock
*ExitBlock
= CLI
->getExit();
2234 BasicBlock
*LatchBlock
= CLI
->getLatch();
2235 Value
*IV
= CLI
->getIndVar();
2237 InsertPointTy EndIP
= OMPBuilder
.applyWorkshareLoop(
2238 DL
, CLI
, AllocaIP
, /*NeedsBarrier=*/true, OMP_SCHEDULE_Static
, ChunkVal
,
2239 /*HasSimdModifier=*/false, /*HasMonotonicModifier=*/false,
2240 /*HasNonmonotonicModifier=*/false,
2241 /*HasOrderedClause=*/true);
2243 // Add a termination to our block and check that it is internally consistent.
2244 Builder
.restoreIP(EndIP
);
2245 Builder
.CreateRetVoid();
2246 OMPBuilder
.finalize();
2247 EXPECT_FALSE(verifyModule(*M
, &errs()));
2249 CallInst
*InitCall
= nullptr;
2250 for (Instruction
&EI
: *Preheader
) {
2251 Instruction
*Cur
= &EI
;
2252 if (isa
<CallInst
>(Cur
)) {
2253 InitCall
= cast
<CallInst
>(Cur
);
2254 if (InitCall
->getCalledFunction()->getName() == "__kmpc_dispatch_init_4u")
2259 EXPECT_NE(InitCall
, nullptr);
2260 EXPECT_EQ(InitCall
->arg_size(), 7U);
2261 ConstantInt
*SchedVal
= cast
<ConstantInt
>(InitCall
->getArgOperand(2));
2262 EXPECT_EQ(SchedVal
->getValue(),
2263 static_cast<uint64_t>(OMPScheduleType::OrderedStaticChunked
));
2265 CallInst
*FiniCall
= dyn_cast
<CallInst
>(
2266 &*(LatchBlock
->getTerminator()->getPrevNonDebugInstruction(true)));
2267 ASSERT_NE(FiniCall
, nullptr);
2268 EXPECT_EQ(FiniCall
->getCalledFunction()->getName(),
2269 "__kmpc_dispatch_fini_4u");
2270 EXPECT_EQ(FiniCall
->arg_size(), 2U);
2271 EXPECT_EQ(InitCall
->getArgOperand(0), FiniCall
->getArgOperand(0));
2272 EXPECT_EQ(InitCall
->getArgOperand(1), FiniCall
->getArgOperand(1));
2274 // The original loop iterator should only be used in the condition, in the
2275 // increment and in the statement that adds the lower bound to it.
2276 EXPECT_EQ(std::distance(IV
->use_begin(), IV
->use_end()), 3);
2278 // The exit block should contain the barrier call, plus the call to obtain
2280 size_t NumCallsInExitBlock
=
2281 count_if(*ExitBlock
, [](Instruction
&I
) { return isa
<CallInst
>(I
); });
2282 EXPECT_EQ(NumCallsInExitBlock
, 2u);
2285 TEST_F(OpenMPIRBuilderTest
, MasterDirective
) {
2286 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
2287 OpenMPIRBuilder
OMPBuilder(*M
);
2288 OMPBuilder
.initialize();
2290 IRBuilder
<> Builder(BB
);
2292 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
2294 AllocaInst
*PrivAI
= nullptr;
2296 BasicBlock
*EntryBB
= nullptr;
2297 BasicBlock
*ThenBB
= nullptr;
2299 auto BodyGenCB
= [&](InsertPointTy AllocaIP
, InsertPointTy CodeGenIP
) {
2300 if (AllocaIP
.isSet())
2301 Builder
.restoreIP(AllocaIP
);
2303 Builder
.SetInsertPoint(&*(F
->getEntryBlock().getFirstInsertionPt()));
2304 PrivAI
= Builder
.CreateAlloca(F
->arg_begin()->getType());
2305 Builder
.CreateStore(F
->arg_begin(), PrivAI
);
2307 llvm::BasicBlock
*CodeGenIPBB
= CodeGenIP
.getBlock();
2308 llvm::Instruction
*CodeGenIPInst
= &*CodeGenIP
.getPoint();
2309 EXPECT_EQ(CodeGenIPBB
->getTerminator(), CodeGenIPInst
);
2311 Builder
.restoreIP(CodeGenIP
);
2313 // collect some info for checks later
2314 ThenBB
= Builder
.GetInsertBlock();
2315 EntryBB
= ThenBB
->getUniquePredecessor();
2317 // simple instructions for body
2319 Builder
.CreateLoad(PrivAI
->getAllocatedType(), PrivAI
, "local.use");
2320 Builder
.CreateICmpNE(F
->arg_begin(), PrivLoad
);
2323 auto FiniCB
= [&](InsertPointTy IP
) {
2324 BasicBlock
*IPBB
= IP
.getBlock();
2325 EXPECT_NE(IPBB
->end(), IP
.getPoint());
2328 Builder
.restoreIP(OMPBuilder
.createMaster(Builder
, BodyGenCB
, FiniCB
));
2329 Value
*EntryBBTI
= EntryBB
->getTerminator();
2330 EXPECT_NE(EntryBBTI
, nullptr);
2331 EXPECT_TRUE(isa
<BranchInst
>(EntryBBTI
));
2332 BranchInst
*EntryBr
= cast
<BranchInst
>(EntryBB
->getTerminator());
2333 EXPECT_TRUE(EntryBr
->isConditional());
2334 EXPECT_EQ(EntryBr
->getSuccessor(0), ThenBB
);
2335 BasicBlock
*ExitBB
= ThenBB
->getUniqueSuccessor();
2336 EXPECT_EQ(EntryBr
->getSuccessor(1), ExitBB
);
2338 CmpInst
*CondInst
= cast
<CmpInst
>(EntryBr
->getCondition());
2339 EXPECT_TRUE(isa
<CallInst
>(CondInst
->getOperand(0)));
2341 CallInst
*MasterEntryCI
= cast
<CallInst
>(CondInst
->getOperand(0));
2342 EXPECT_EQ(MasterEntryCI
->arg_size(), 2U);
2343 EXPECT_EQ(MasterEntryCI
->getCalledFunction()->getName(), "__kmpc_master");
2344 EXPECT_TRUE(isa
<GlobalVariable
>(MasterEntryCI
->getArgOperand(0)));
2346 CallInst
*MasterEndCI
= nullptr;
2347 for (auto &FI
: *ThenBB
) {
2348 Instruction
*cur
= &FI
;
2349 if (isa
<CallInst
>(cur
)) {
2350 MasterEndCI
= cast
<CallInst
>(cur
);
2351 if (MasterEndCI
->getCalledFunction()->getName() == "__kmpc_end_master")
2353 MasterEndCI
= nullptr;
2356 EXPECT_NE(MasterEndCI
, nullptr);
2357 EXPECT_EQ(MasterEndCI
->arg_size(), 2U);
2358 EXPECT_TRUE(isa
<GlobalVariable
>(MasterEndCI
->getArgOperand(0)));
2359 EXPECT_EQ(MasterEndCI
->getArgOperand(1), MasterEntryCI
->getArgOperand(1));
2362 TEST_F(OpenMPIRBuilderTest
, MaskedDirective
) {
2363 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
2364 OpenMPIRBuilder
OMPBuilder(*M
);
2365 OMPBuilder
.initialize();
2367 IRBuilder
<> Builder(BB
);
2369 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
2371 AllocaInst
*PrivAI
= nullptr;
2373 BasicBlock
*EntryBB
= nullptr;
2374 BasicBlock
*ThenBB
= nullptr;
2376 auto BodyGenCB
= [&](InsertPointTy AllocaIP
, InsertPointTy CodeGenIP
) {
2377 if (AllocaIP
.isSet())
2378 Builder
.restoreIP(AllocaIP
);
2380 Builder
.SetInsertPoint(&*(F
->getEntryBlock().getFirstInsertionPt()));
2381 PrivAI
= Builder
.CreateAlloca(F
->arg_begin()->getType());
2382 Builder
.CreateStore(F
->arg_begin(), PrivAI
);
2384 llvm::BasicBlock
*CodeGenIPBB
= CodeGenIP
.getBlock();
2385 llvm::Instruction
*CodeGenIPInst
= &*CodeGenIP
.getPoint();
2386 EXPECT_EQ(CodeGenIPBB
->getTerminator(), CodeGenIPInst
);
2388 Builder
.restoreIP(CodeGenIP
);
2390 // collect some info for checks later
2391 ThenBB
= Builder
.GetInsertBlock();
2392 EntryBB
= ThenBB
->getUniquePredecessor();
2394 // simple instructions for body
2396 Builder
.CreateLoad(PrivAI
->getAllocatedType(), PrivAI
, "local.use");
2397 Builder
.CreateICmpNE(F
->arg_begin(), PrivLoad
);
2400 auto FiniCB
= [&](InsertPointTy IP
) {
2401 BasicBlock
*IPBB
= IP
.getBlock();
2402 EXPECT_NE(IPBB
->end(), IP
.getPoint());
2405 Constant
*Filter
= ConstantInt::get(Type::getInt32Ty(M
->getContext()), 0);
2407 OMPBuilder
.createMasked(Builder
, BodyGenCB
, FiniCB
, Filter
));
2408 Value
*EntryBBTI
= EntryBB
->getTerminator();
2409 EXPECT_NE(EntryBBTI
, nullptr);
2410 EXPECT_TRUE(isa
<BranchInst
>(EntryBBTI
));
2411 BranchInst
*EntryBr
= cast
<BranchInst
>(EntryBB
->getTerminator());
2412 EXPECT_TRUE(EntryBr
->isConditional());
2413 EXPECT_EQ(EntryBr
->getSuccessor(0), ThenBB
);
2414 BasicBlock
*ExitBB
= ThenBB
->getUniqueSuccessor();
2415 EXPECT_EQ(EntryBr
->getSuccessor(1), ExitBB
);
2417 CmpInst
*CondInst
= cast
<CmpInst
>(EntryBr
->getCondition());
2418 EXPECT_TRUE(isa
<CallInst
>(CondInst
->getOperand(0)));
2420 CallInst
*MaskedEntryCI
= cast
<CallInst
>(CondInst
->getOperand(0));
2421 EXPECT_EQ(MaskedEntryCI
->arg_size(), 3U);
2422 EXPECT_EQ(MaskedEntryCI
->getCalledFunction()->getName(), "__kmpc_masked");
2423 EXPECT_TRUE(isa
<GlobalVariable
>(MaskedEntryCI
->getArgOperand(0)));
2425 CallInst
*MaskedEndCI
= nullptr;
2426 for (auto &FI
: *ThenBB
) {
2427 Instruction
*cur
= &FI
;
2428 if (isa
<CallInst
>(cur
)) {
2429 MaskedEndCI
= cast
<CallInst
>(cur
);
2430 if (MaskedEndCI
->getCalledFunction()->getName() == "__kmpc_end_masked")
2432 MaskedEndCI
= nullptr;
2435 EXPECT_NE(MaskedEndCI
, nullptr);
2436 EXPECT_EQ(MaskedEndCI
->arg_size(), 2U);
2437 EXPECT_TRUE(isa
<GlobalVariable
>(MaskedEndCI
->getArgOperand(0)));
2438 EXPECT_EQ(MaskedEndCI
->getArgOperand(1), MaskedEntryCI
->getArgOperand(1));
2441 TEST_F(OpenMPIRBuilderTest
, CriticalDirective
) {
2442 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
2443 OpenMPIRBuilder
OMPBuilder(*M
);
2444 OMPBuilder
.initialize();
2446 IRBuilder
<> Builder(BB
);
2448 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
2450 AllocaInst
*PrivAI
= Builder
.CreateAlloca(F
->arg_begin()->getType());
2452 auto BodyGenCB
= [&](InsertPointTy AllocaIP
, InsertPointTy CodeGenIP
) {
2453 // actual start for bodyCB
2454 llvm::BasicBlock
*CodeGenIPBB
= CodeGenIP
.getBlock();
2455 llvm::Instruction
*CodeGenIPInst
= &*CodeGenIP
.getPoint();
2456 EXPECT_EQ(CodeGenIPBB
->getTerminator(), CodeGenIPInst
);
2459 Builder
.restoreIP(CodeGenIP
);
2460 Builder
.CreateStore(F
->arg_begin(), PrivAI
);
2462 Builder
.CreateLoad(PrivAI
->getAllocatedType(), PrivAI
, "local.use");
2463 Builder
.CreateICmpNE(F
->arg_begin(), PrivLoad
);
2466 auto FiniCB
= [&](InsertPointTy IP
) {
2467 BasicBlock
*IPBB
= IP
.getBlock();
2468 EXPECT_NE(IPBB
->end(), IP
.getPoint());
2470 BasicBlock
*EntryBB
= Builder
.GetInsertBlock();
2472 Builder
.restoreIP(OMPBuilder
.createCritical(Builder
, BodyGenCB
, FiniCB
,
2473 "testCRT", nullptr));
2475 CallInst
*CriticalEntryCI
= nullptr;
2476 for (auto &EI
: *EntryBB
) {
2477 Instruction
*cur
= &EI
;
2478 if (isa
<CallInst
>(cur
)) {
2479 CriticalEntryCI
= cast
<CallInst
>(cur
);
2480 if (CriticalEntryCI
->getCalledFunction()->getName() == "__kmpc_critical")
2482 CriticalEntryCI
= nullptr;
2485 EXPECT_NE(CriticalEntryCI
, nullptr);
2486 EXPECT_EQ(CriticalEntryCI
->arg_size(), 3U);
2487 EXPECT_EQ(CriticalEntryCI
->getCalledFunction()->getName(), "__kmpc_critical");
2488 EXPECT_TRUE(isa
<GlobalVariable
>(CriticalEntryCI
->getArgOperand(0)));
2490 CallInst
*CriticalEndCI
= nullptr;
2491 for (auto &FI
: *EntryBB
) {
2492 Instruction
*cur
= &FI
;
2493 if (isa
<CallInst
>(cur
)) {
2494 CriticalEndCI
= cast
<CallInst
>(cur
);
2495 if (CriticalEndCI
->getCalledFunction()->getName() ==
2496 "__kmpc_end_critical")
2498 CriticalEndCI
= nullptr;
2501 EXPECT_NE(CriticalEndCI
, nullptr);
2502 EXPECT_EQ(CriticalEndCI
->arg_size(), 3U);
2503 EXPECT_TRUE(isa
<GlobalVariable
>(CriticalEndCI
->getArgOperand(0)));
2504 EXPECT_EQ(CriticalEndCI
->getArgOperand(1), CriticalEntryCI
->getArgOperand(1));
2505 PointerType
*CriticalNamePtrTy
=
2506 PointerType::getUnqual(ArrayType::get(Type::getInt32Ty(Ctx
), 8));
2507 EXPECT_EQ(CriticalEndCI
->getArgOperand(2), CriticalEntryCI
->getArgOperand(2));
2508 EXPECT_EQ(CriticalEndCI
->getArgOperand(2)->getType(), CriticalNamePtrTy
);
2511 TEST_F(OpenMPIRBuilderTest
, OrderedDirectiveDependSource
) {
2512 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
2513 OpenMPIRBuilder
OMPBuilder(*M
);
2514 OMPBuilder
.initialize();
2516 IRBuilder
<> Builder(BB
);
2517 LLVMContext
&Ctx
= M
->getContext();
2519 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
2521 InsertPointTy
AllocaIP(&F
->getEntryBlock(),
2522 F
->getEntryBlock().getFirstInsertionPt());
2524 unsigned NumLoops
= 2;
2525 SmallVector
<Value
*, 2> StoreValues
;
2526 Type
*LCTy
= Type::getInt64Ty(Ctx
);
2527 StoreValues
.emplace_back(ConstantInt::get(LCTy
, 1));
2528 StoreValues
.emplace_back(ConstantInt::get(LCTy
, 2));
2530 // Test for "#omp ordered depend(source)"
2531 Builder
.restoreIP(OMPBuilder
.createOrderedDepend(Builder
, AllocaIP
, NumLoops
,
2532 StoreValues
, ".cnt.addr",
2533 /*IsDependSource=*/true));
2535 Builder
.CreateRetVoid();
2536 OMPBuilder
.finalize();
2537 EXPECT_FALSE(verifyModule(*M
, &errs()));
2539 AllocaInst
*AllocInst
= dyn_cast
<AllocaInst
>(&BB
->front());
2540 ASSERT_NE(AllocInst
, nullptr);
2541 ArrayType
*ArrType
= dyn_cast
<ArrayType
>(AllocInst
->getAllocatedType());
2542 EXPECT_EQ(ArrType
->getNumElements(), NumLoops
);
2544 AllocInst
->getAllocatedType()->getArrayElementType()->isIntegerTy(64));
2546 Instruction
*IterInst
= dyn_cast
<Instruction
>(AllocInst
);
2547 for (unsigned Iter
= 0; Iter
< NumLoops
; Iter
++) {
2548 GetElementPtrInst
*DependAddrGEPIter
=
2549 dyn_cast
<GetElementPtrInst
>(IterInst
->getNextNode());
2550 ASSERT_NE(DependAddrGEPIter
, nullptr);
2551 EXPECT_EQ(DependAddrGEPIter
->getPointerOperand(), AllocInst
);
2552 EXPECT_EQ(DependAddrGEPIter
->getNumIndices(), (unsigned)2);
2553 auto *FirstIdx
= dyn_cast
<ConstantInt
>(DependAddrGEPIter
->getOperand(1));
2554 auto *SecondIdx
= dyn_cast
<ConstantInt
>(DependAddrGEPIter
->getOperand(2));
2555 ASSERT_NE(FirstIdx
, nullptr);
2556 ASSERT_NE(SecondIdx
, nullptr);
2557 EXPECT_EQ(FirstIdx
->getValue(), 0);
2558 EXPECT_EQ(SecondIdx
->getValue(), Iter
);
2559 StoreInst
*StoreValue
=
2560 dyn_cast
<StoreInst
>(DependAddrGEPIter
->getNextNode());
2561 ASSERT_NE(StoreValue
, nullptr);
2562 EXPECT_EQ(StoreValue
->getValueOperand(), StoreValues
[Iter
]);
2563 EXPECT_EQ(StoreValue
->getPointerOperand(), DependAddrGEPIter
);
2564 EXPECT_EQ(StoreValue
->getAlign(), Align(8));
2565 IterInst
= dyn_cast
<Instruction
>(StoreValue
);
2568 GetElementPtrInst
*DependBaseAddrGEP
=
2569 dyn_cast
<GetElementPtrInst
>(IterInst
->getNextNode());
2570 ASSERT_NE(DependBaseAddrGEP
, nullptr);
2571 EXPECT_EQ(DependBaseAddrGEP
->getPointerOperand(), AllocInst
);
2572 EXPECT_EQ(DependBaseAddrGEP
->getNumIndices(), (unsigned)2);
2573 auto *FirstIdx
= dyn_cast
<ConstantInt
>(DependBaseAddrGEP
->getOperand(1));
2574 auto *SecondIdx
= dyn_cast
<ConstantInt
>(DependBaseAddrGEP
->getOperand(2));
2575 ASSERT_NE(FirstIdx
, nullptr);
2576 ASSERT_NE(SecondIdx
, nullptr);
2577 EXPECT_EQ(FirstIdx
->getValue(), 0);
2578 EXPECT_EQ(SecondIdx
->getValue(), 0);
2580 CallInst
*GTID
= dyn_cast
<CallInst
>(DependBaseAddrGEP
->getNextNode());
2581 ASSERT_NE(GTID
, nullptr);
2582 EXPECT_EQ(GTID
->arg_size(), 1U);
2583 EXPECT_EQ(GTID
->getCalledFunction()->getName(), "__kmpc_global_thread_num");
2584 EXPECT_FALSE(GTID
->getCalledFunction()->doesNotAccessMemory());
2585 EXPECT_FALSE(GTID
->getCalledFunction()->doesNotFreeMemory());
2587 CallInst
*Depend
= dyn_cast
<CallInst
>(GTID
->getNextNode());
2588 ASSERT_NE(Depend
, nullptr);
2589 EXPECT_EQ(Depend
->arg_size(), 3U);
2590 EXPECT_EQ(Depend
->getCalledFunction()->getName(), "__kmpc_doacross_post");
2591 EXPECT_TRUE(isa
<GlobalVariable
>(Depend
->getArgOperand(0)));
2592 EXPECT_EQ(Depend
->getArgOperand(1), GTID
);
2593 EXPECT_EQ(Depend
->getArgOperand(2), DependBaseAddrGEP
);
2596 TEST_F(OpenMPIRBuilderTest
, OrderedDirectiveDependSink
) {
2597 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
2598 OpenMPIRBuilder
OMPBuilder(*M
);
2599 OMPBuilder
.initialize();
2601 IRBuilder
<> Builder(BB
);
2602 LLVMContext
&Ctx
= M
->getContext();
2604 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
2606 InsertPointTy
AllocaIP(&F
->getEntryBlock(),
2607 F
->getEntryBlock().getFirstInsertionPt());
2609 unsigned NumLoops
= 2;
2610 SmallVector
<Value
*, 2> StoreValues
;
2611 Type
*LCTy
= Type::getInt64Ty(Ctx
);
2612 StoreValues
.emplace_back(ConstantInt::get(LCTy
, 1));
2613 StoreValues
.emplace_back(ConstantInt::get(LCTy
, 2));
2615 // Test for "#omp ordered depend(sink: vec)"
2616 Builder
.restoreIP(OMPBuilder
.createOrderedDepend(Builder
, AllocaIP
, NumLoops
,
2617 StoreValues
, ".cnt.addr",
2618 /*IsDependSource=*/false));
2620 Builder
.CreateRetVoid();
2621 OMPBuilder
.finalize();
2622 EXPECT_FALSE(verifyModule(*M
, &errs()));
2624 AllocaInst
*AllocInst
= dyn_cast
<AllocaInst
>(&BB
->front());
2625 ASSERT_NE(AllocInst
, nullptr);
2626 ArrayType
*ArrType
= dyn_cast
<ArrayType
>(AllocInst
->getAllocatedType());
2627 EXPECT_EQ(ArrType
->getNumElements(), NumLoops
);
2629 AllocInst
->getAllocatedType()->getArrayElementType()->isIntegerTy(64));
2631 Instruction
*IterInst
= dyn_cast
<Instruction
>(AllocInst
);
2632 for (unsigned Iter
= 0; Iter
< NumLoops
; Iter
++) {
2633 GetElementPtrInst
*DependAddrGEPIter
=
2634 dyn_cast
<GetElementPtrInst
>(IterInst
->getNextNode());
2635 ASSERT_NE(DependAddrGEPIter
, nullptr);
2636 EXPECT_EQ(DependAddrGEPIter
->getPointerOperand(), AllocInst
);
2637 EXPECT_EQ(DependAddrGEPIter
->getNumIndices(), (unsigned)2);
2638 auto *FirstIdx
= dyn_cast
<ConstantInt
>(DependAddrGEPIter
->getOperand(1));
2639 auto *SecondIdx
= dyn_cast
<ConstantInt
>(DependAddrGEPIter
->getOperand(2));
2640 ASSERT_NE(FirstIdx
, nullptr);
2641 ASSERT_NE(SecondIdx
, nullptr);
2642 EXPECT_EQ(FirstIdx
->getValue(), 0);
2643 EXPECT_EQ(SecondIdx
->getValue(), Iter
);
2644 StoreInst
*StoreValue
=
2645 dyn_cast
<StoreInst
>(DependAddrGEPIter
->getNextNode());
2646 ASSERT_NE(StoreValue
, nullptr);
2647 EXPECT_EQ(StoreValue
->getValueOperand(), StoreValues
[Iter
]);
2648 EXPECT_EQ(StoreValue
->getPointerOperand(), DependAddrGEPIter
);
2649 EXPECT_EQ(StoreValue
->getAlign(), Align(8));
2650 IterInst
= dyn_cast
<Instruction
>(StoreValue
);
2653 GetElementPtrInst
*DependBaseAddrGEP
=
2654 dyn_cast
<GetElementPtrInst
>(IterInst
->getNextNode());
2655 ASSERT_NE(DependBaseAddrGEP
, nullptr);
2656 EXPECT_EQ(DependBaseAddrGEP
->getPointerOperand(), AllocInst
);
2657 EXPECT_EQ(DependBaseAddrGEP
->getNumIndices(), (unsigned)2);
2658 auto *FirstIdx
= dyn_cast
<ConstantInt
>(DependBaseAddrGEP
->getOperand(1));
2659 auto *SecondIdx
= dyn_cast
<ConstantInt
>(DependBaseAddrGEP
->getOperand(2));
2660 ASSERT_NE(FirstIdx
, nullptr);
2661 ASSERT_NE(SecondIdx
, nullptr);
2662 EXPECT_EQ(FirstIdx
->getValue(), 0);
2663 EXPECT_EQ(SecondIdx
->getValue(), 0);
2665 CallInst
*GTID
= dyn_cast
<CallInst
>(DependBaseAddrGEP
->getNextNode());
2666 ASSERT_NE(GTID
, nullptr);
2667 EXPECT_EQ(GTID
->arg_size(), 1U);
2668 EXPECT_EQ(GTID
->getCalledFunction()->getName(), "__kmpc_global_thread_num");
2669 EXPECT_FALSE(GTID
->getCalledFunction()->doesNotAccessMemory());
2670 EXPECT_FALSE(GTID
->getCalledFunction()->doesNotFreeMemory());
2672 CallInst
*Depend
= dyn_cast
<CallInst
>(GTID
->getNextNode());
2673 ASSERT_NE(Depend
, nullptr);
2674 EXPECT_EQ(Depend
->arg_size(), 3U);
2675 EXPECT_EQ(Depend
->getCalledFunction()->getName(), "__kmpc_doacross_wait");
2676 EXPECT_TRUE(isa
<GlobalVariable
>(Depend
->getArgOperand(0)));
2677 EXPECT_EQ(Depend
->getArgOperand(1), GTID
);
2678 EXPECT_EQ(Depend
->getArgOperand(2), DependBaseAddrGEP
);
2681 TEST_F(OpenMPIRBuilderTest
, OrderedDirectiveThreads
) {
2682 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
2683 OpenMPIRBuilder
OMPBuilder(*M
);
2684 OMPBuilder
.initialize();
2686 IRBuilder
<> Builder(BB
);
2688 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
2690 AllocaInst
*PrivAI
=
2691 Builder
.CreateAlloca(F
->arg_begin()->getType(), nullptr, "priv.inst");
2693 auto BodyGenCB
= [&](InsertPointTy AllocaIP
, InsertPointTy CodeGenIP
) {
2694 llvm::BasicBlock
*CodeGenIPBB
= CodeGenIP
.getBlock();
2695 llvm::Instruction
*CodeGenIPInst
= &*CodeGenIP
.getPoint();
2696 EXPECT_EQ(CodeGenIPBB
->getTerminator(), CodeGenIPInst
);
2698 Builder
.restoreIP(CodeGenIP
);
2699 Builder
.CreateStore(F
->arg_begin(), PrivAI
);
2701 Builder
.CreateLoad(PrivAI
->getAllocatedType(), PrivAI
, "local.use");
2702 Builder
.CreateICmpNE(F
->arg_begin(), PrivLoad
);
2705 auto FiniCB
= [&](InsertPointTy IP
) {
2706 BasicBlock
*IPBB
= IP
.getBlock();
2707 EXPECT_NE(IPBB
->end(), IP
.getPoint());
2710 // Test for "#omp ordered [threads]"
2711 BasicBlock
*EntryBB
= Builder
.GetInsertBlock();
2713 OMPBuilder
.createOrderedThreadsSimd(Builder
, BodyGenCB
, FiniCB
, true));
2715 Builder
.CreateRetVoid();
2716 OMPBuilder
.finalize();
2717 EXPECT_FALSE(verifyModule(*M
, &errs()));
2719 EXPECT_NE(EntryBB
->getTerminator(), nullptr);
2721 CallInst
*OrderedEntryCI
= nullptr;
2722 for (auto &EI
: *EntryBB
) {
2723 Instruction
*Cur
= &EI
;
2724 if (isa
<CallInst
>(Cur
)) {
2725 OrderedEntryCI
= cast
<CallInst
>(Cur
);
2726 if (OrderedEntryCI
->getCalledFunction()->getName() == "__kmpc_ordered")
2728 OrderedEntryCI
= nullptr;
2731 EXPECT_NE(OrderedEntryCI
, nullptr);
2732 EXPECT_EQ(OrderedEntryCI
->arg_size(), 2U);
2733 EXPECT_EQ(OrderedEntryCI
->getCalledFunction()->getName(), "__kmpc_ordered");
2734 EXPECT_TRUE(isa
<GlobalVariable
>(OrderedEntryCI
->getArgOperand(0)));
2736 CallInst
*OrderedEndCI
= nullptr;
2737 for (auto &FI
: *EntryBB
) {
2738 Instruction
*Cur
= &FI
;
2739 if (isa
<CallInst
>(Cur
)) {
2740 OrderedEndCI
= cast
<CallInst
>(Cur
);
2741 if (OrderedEndCI
->getCalledFunction()->getName() == "__kmpc_end_ordered")
2743 OrderedEndCI
= nullptr;
2746 EXPECT_NE(OrderedEndCI
, nullptr);
2747 EXPECT_EQ(OrderedEndCI
->arg_size(), 2U);
2748 EXPECT_TRUE(isa
<GlobalVariable
>(OrderedEndCI
->getArgOperand(0)));
2749 EXPECT_EQ(OrderedEndCI
->getArgOperand(1), OrderedEntryCI
->getArgOperand(1));
2752 TEST_F(OpenMPIRBuilderTest
, OrderedDirectiveSimd
) {
2753 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
2754 OpenMPIRBuilder
OMPBuilder(*M
);
2755 OMPBuilder
.initialize();
2757 IRBuilder
<> Builder(BB
);
2759 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
2761 AllocaInst
*PrivAI
=
2762 Builder
.CreateAlloca(F
->arg_begin()->getType(), nullptr, "priv.inst");
2764 auto BodyGenCB
= [&](InsertPointTy AllocaIP
, InsertPointTy CodeGenIP
) {
2765 llvm::BasicBlock
*CodeGenIPBB
= CodeGenIP
.getBlock();
2766 llvm::Instruction
*CodeGenIPInst
= &*CodeGenIP
.getPoint();
2767 EXPECT_EQ(CodeGenIPBB
->getTerminator(), CodeGenIPInst
);
2769 Builder
.restoreIP(CodeGenIP
);
2770 Builder
.CreateStore(F
->arg_begin(), PrivAI
);
2772 Builder
.CreateLoad(PrivAI
->getAllocatedType(), PrivAI
, "local.use");
2773 Builder
.CreateICmpNE(F
->arg_begin(), PrivLoad
);
2776 auto FiniCB
= [&](InsertPointTy IP
) {
2777 BasicBlock
*IPBB
= IP
.getBlock();
2778 EXPECT_NE(IPBB
->end(), IP
.getPoint());
2781 // Test for "#omp ordered simd"
2782 BasicBlock
*EntryBB
= Builder
.GetInsertBlock();
2784 OMPBuilder
.createOrderedThreadsSimd(Builder
, BodyGenCB
, FiniCB
, false));
2786 Builder
.CreateRetVoid();
2787 OMPBuilder
.finalize();
2788 EXPECT_FALSE(verifyModule(*M
, &errs()));
2790 EXPECT_NE(EntryBB
->getTerminator(), nullptr);
2792 CallInst
*OrderedEntryCI
= nullptr;
2793 for (auto &EI
: *EntryBB
) {
2794 Instruction
*Cur
= &EI
;
2795 if (isa
<CallInst
>(Cur
)) {
2796 OrderedEntryCI
= cast
<CallInst
>(Cur
);
2797 if (OrderedEntryCI
->getCalledFunction()->getName() == "__kmpc_ordered")
2799 OrderedEntryCI
= nullptr;
2802 EXPECT_EQ(OrderedEntryCI
, nullptr);
2804 CallInst
*OrderedEndCI
= nullptr;
2805 for (auto &FI
: *EntryBB
) {
2806 Instruction
*Cur
= &FI
;
2807 if (isa
<CallInst
>(Cur
)) {
2808 OrderedEndCI
= cast
<CallInst
>(Cur
);
2809 if (OrderedEndCI
->getCalledFunction()->getName() == "__kmpc_end_ordered")
2811 OrderedEndCI
= nullptr;
2814 EXPECT_EQ(OrderedEndCI
, nullptr);
2817 TEST_F(OpenMPIRBuilderTest
, CopyinBlocks
) {
2818 OpenMPIRBuilder
OMPBuilder(*M
);
2819 OMPBuilder
.initialize();
2821 IRBuilder
<> Builder(BB
);
2823 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
2825 IntegerType
*Int32
= Type::getInt32Ty(M
->getContext());
2826 AllocaInst
*MasterAddress
= Builder
.CreateAlloca(Int32
->getPointerTo());
2827 AllocaInst
*PrivAddress
= Builder
.CreateAlloca(Int32
->getPointerTo());
2829 BasicBlock
*EntryBB
= BB
;
2831 OMPBuilder
.createCopyinClauseBlocks(Builder
.saveIP(), MasterAddress
,
2832 PrivAddress
, Int32
, /*BranchtoEnd*/ true);
2834 BranchInst
*EntryBr
= dyn_cast_or_null
<BranchInst
>(EntryBB
->getTerminator());
2836 EXPECT_NE(EntryBr
, nullptr);
2837 EXPECT_TRUE(EntryBr
->isConditional());
2839 BasicBlock
*NotMasterBB
= EntryBr
->getSuccessor(0);
2840 BasicBlock
*CopyinEnd
= EntryBr
->getSuccessor(1);
2841 CmpInst
*CMP
= dyn_cast_or_null
<CmpInst
>(EntryBr
->getCondition());
2843 EXPECT_NE(CMP
, nullptr);
2844 EXPECT_NE(NotMasterBB
, nullptr);
2845 EXPECT_NE(CopyinEnd
, nullptr);
2847 BranchInst
*NotMasterBr
=
2848 dyn_cast_or_null
<BranchInst
>(NotMasterBB
->getTerminator());
2849 EXPECT_NE(NotMasterBr
, nullptr);
2850 EXPECT_FALSE(NotMasterBr
->isConditional());
2851 EXPECT_EQ(CopyinEnd
, NotMasterBr
->getSuccessor(0));
2854 TEST_F(OpenMPIRBuilderTest
, SingleDirective
) {
2855 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
2856 OpenMPIRBuilder
OMPBuilder(*M
);
2857 OMPBuilder
.initialize();
2859 IRBuilder
<> Builder(BB
);
2861 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
2863 AllocaInst
*PrivAI
= nullptr;
2865 BasicBlock
*EntryBB
= nullptr;
2866 BasicBlock
*ThenBB
= nullptr;
2868 auto BodyGenCB
= [&](InsertPointTy AllocaIP
, InsertPointTy CodeGenIP
) {
2869 if (AllocaIP
.isSet())
2870 Builder
.restoreIP(AllocaIP
);
2872 Builder
.SetInsertPoint(&*(F
->getEntryBlock().getFirstInsertionPt()));
2873 PrivAI
= Builder
.CreateAlloca(F
->arg_begin()->getType());
2874 Builder
.CreateStore(F
->arg_begin(), PrivAI
);
2876 llvm::BasicBlock
*CodeGenIPBB
= CodeGenIP
.getBlock();
2877 llvm::Instruction
*CodeGenIPInst
= &*CodeGenIP
.getPoint();
2878 EXPECT_EQ(CodeGenIPBB
->getTerminator(), CodeGenIPInst
);
2880 Builder
.restoreIP(CodeGenIP
);
2882 // collect some info for checks later
2883 ThenBB
= Builder
.GetInsertBlock();
2884 EntryBB
= ThenBB
->getUniquePredecessor();
2886 // simple instructions for body
2888 Builder
.CreateLoad(PrivAI
->getAllocatedType(), PrivAI
, "local.use");
2889 Builder
.CreateICmpNE(F
->arg_begin(), PrivLoad
);
2892 auto FiniCB
= [&](InsertPointTy IP
) {
2893 BasicBlock
*IPBB
= IP
.getBlock();
2894 EXPECT_NE(IPBB
->end(), IP
.getPoint());
2897 Builder
.restoreIP(OMPBuilder
.createSingle(
2898 Builder
, BodyGenCB
, FiniCB
, /*IsNowait*/ false, /*DidIt*/ nullptr));
2899 Value
*EntryBBTI
= EntryBB
->getTerminator();
2900 EXPECT_NE(EntryBBTI
, nullptr);
2901 EXPECT_TRUE(isa
<BranchInst
>(EntryBBTI
));
2902 BranchInst
*EntryBr
= cast
<BranchInst
>(EntryBB
->getTerminator());
2903 EXPECT_TRUE(EntryBr
->isConditional());
2904 EXPECT_EQ(EntryBr
->getSuccessor(0), ThenBB
);
2905 BasicBlock
*ExitBB
= ThenBB
->getUniqueSuccessor();
2906 EXPECT_EQ(EntryBr
->getSuccessor(1), ExitBB
);
2908 CmpInst
*CondInst
= cast
<CmpInst
>(EntryBr
->getCondition());
2909 EXPECT_TRUE(isa
<CallInst
>(CondInst
->getOperand(0)));
2911 CallInst
*SingleEntryCI
= cast
<CallInst
>(CondInst
->getOperand(0));
2912 EXPECT_EQ(SingleEntryCI
->arg_size(), 2U);
2913 EXPECT_EQ(SingleEntryCI
->getCalledFunction()->getName(), "__kmpc_single");
2914 EXPECT_TRUE(isa
<GlobalVariable
>(SingleEntryCI
->getArgOperand(0)));
2916 CallInst
*SingleEndCI
= nullptr;
2917 for (auto &FI
: *ThenBB
) {
2918 Instruction
*cur
= &FI
;
2919 if (isa
<CallInst
>(cur
)) {
2920 SingleEndCI
= cast
<CallInst
>(cur
);
2921 if (SingleEndCI
->getCalledFunction()->getName() == "__kmpc_end_single")
2923 SingleEndCI
= nullptr;
2926 EXPECT_NE(SingleEndCI
, nullptr);
2927 EXPECT_EQ(SingleEndCI
->arg_size(), 2U);
2928 EXPECT_TRUE(isa
<GlobalVariable
>(SingleEndCI
->getArgOperand(0)));
2929 EXPECT_EQ(SingleEndCI
->getArgOperand(1), SingleEntryCI
->getArgOperand(1));
2931 bool FoundBarrier
= false;
2932 for (auto &FI
: *ExitBB
) {
2933 Instruction
*cur
= &FI
;
2934 if (auto CI
= dyn_cast
<CallInst
>(cur
)) {
2935 if (CI
->getCalledFunction()->getName() == "__kmpc_barrier") {
2936 FoundBarrier
= true;
2941 EXPECT_TRUE(FoundBarrier
);
2944 TEST_F(OpenMPIRBuilderTest
, SingleDirectiveNowait
) {
2945 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
2946 OpenMPIRBuilder
OMPBuilder(*M
);
2947 OMPBuilder
.initialize();
2949 IRBuilder
<> Builder(BB
);
2951 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
2953 AllocaInst
*PrivAI
= nullptr;
2955 BasicBlock
*EntryBB
= nullptr;
2956 BasicBlock
*ThenBB
= nullptr;
2958 auto BodyGenCB
= [&](InsertPointTy AllocaIP
, InsertPointTy CodeGenIP
) {
2959 if (AllocaIP
.isSet())
2960 Builder
.restoreIP(AllocaIP
);
2962 Builder
.SetInsertPoint(&*(F
->getEntryBlock().getFirstInsertionPt()));
2963 PrivAI
= Builder
.CreateAlloca(F
->arg_begin()->getType());
2964 Builder
.CreateStore(F
->arg_begin(), PrivAI
);
2966 llvm::BasicBlock
*CodeGenIPBB
= CodeGenIP
.getBlock();
2967 llvm::Instruction
*CodeGenIPInst
= &*CodeGenIP
.getPoint();
2968 EXPECT_EQ(CodeGenIPBB
->getTerminator(), CodeGenIPInst
);
2970 Builder
.restoreIP(CodeGenIP
);
2972 // collect some info for checks later
2973 ThenBB
= Builder
.GetInsertBlock();
2974 EntryBB
= ThenBB
->getUniquePredecessor();
2976 // simple instructions for body
2978 Builder
.CreateLoad(PrivAI
->getAllocatedType(), PrivAI
, "local.use");
2979 Builder
.CreateICmpNE(F
->arg_begin(), PrivLoad
);
2982 auto FiniCB
= [&](InsertPointTy IP
) {
2983 BasicBlock
*IPBB
= IP
.getBlock();
2984 EXPECT_NE(IPBB
->end(), IP
.getPoint());
2987 Builder
.restoreIP(OMPBuilder
.createSingle(
2988 Builder
, BodyGenCB
, FiniCB
, /*IsNowait*/ true, /*DidIt*/ nullptr));
2989 Value
*EntryBBTI
= EntryBB
->getTerminator();
2990 EXPECT_NE(EntryBBTI
, nullptr);
2991 EXPECT_TRUE(isa
<BranchInst
>(EntryBBTI
));
2992 BranchInst
*EntryBr
= cast
<BranchInst
>(EntryBB
->getTerminator());
2993 EXPECT_TRUE(EntryBr
->isConditional());
2994 EXPECT_EQ(EntryBr
->getSuccessor(0), ThenBB
);
2995 BasicBlock
*ExitBB
= ThenBB
->getUniqueSuccessor();
2996 EXPECT_EQ(EntryBr
->getSuccessor(1), ExitBB
);
2998 CmpInst
*CondInst
= cast
<CmpInst
>(EntryBr
->getCondition());
2999 EXPECT_TRUE(isa
<CallInst
>(CondInst
->getOperand(0)));
3001 CallInst
*SingleEntryCI
= cast
<CallInst
>(CondInst
->getOperand(0));
3002 EXPECT_EQ(SingleEntryCI
->arg_size(), 2U);
3003 EXPECT_EQ(SingleEntryCI
->getCalledFunction()->getName(), "__kmpc_single");
3004 EXPECT_TRUE(isa
<GlobalVariable
>(SingleEntryCI
->getArgOperand(0)));
3006 CallInst
*SingleEndCI
= nullptr;
3007 for (auto &FI
: *ThenBB
) {
3008 Instruction
*cur
= &FI
;
3009 if (isa
<CallInst
>(cur
)) {
3010 SingleEndCI
= cast
<CallInst
>(cur
);
3011 if (SingleEndCI
->getCalledFunction()->getName() == "__kmpc_end_single")
3013 SingleEndCI
= nullptr;
3016 EXPECT_NE(SingleEndCI
, nullptr);
3017 EXPECT_EQ(SingleEndCI
->arg_size(), 2U);
3018 EXPECT_TRUE(isa
<GlobalVariable
>(SingleEndCI
->getArgOperand(0)));
3019 EXPECT_EQ(SingleEndCI
->getArgOperand(1), SingleEntryCI
->getArgOperand(1));
3021 CallInst
*ExitBarrier
= nullptr;
3022 for (auto &FI
: *ExitBB
) {
3023 Instruction
*cur
= &FI
;
3024 if (auto CI
= dyn_cast
<CallInst
>(cur
)) {
3025 if (CI
->getCalledFunction()->getName() == "__kmpc_barrier") {
3031 EXPECT_EQ(ExitBarrier
, nullptr);
3034 TEST_F(OpenMPIRBuilderTest
, OMPAtomicReadFlt
) {
3035 OpenMPIRBuilder
OMPBuilder(*M
);
3036 OMPBuilder
.initialize();
3038 IRBuilder
<> Builder(BB
);
3040 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
3042 Type
*Float32
= Type::getFloatTy(M
->getContext());
3043 AllocaInst
*XVal
= Builder
.CreateAlloca(Float32
);
3044 XVal
->setName("AtomicVar");
3045 AllocaInst
*VVal
= Builder
.CreateAlloca(Float32
);
3046 VVal
->setName("AtomicRead");
3047 AtomicOrdering AO
= AtomicOrdering::Monotonic
;
3048 OpenMPIRBuilder::AtomicOpValue X
= {XVal
, Float32
, false, false};
3049 OpenMPIRBuilder::AtomicOpValue V
= {VVal
, Float32
, false, false};
3051 Builder
.restoreIP(OMPBuilder
.createAtomicRead(Loc
, X
, V
, AO
));
3053 IntegerType
*IntCastTy
=
3054 IntegerType::get(M
->getContext(), Float32
->getScalarSizeInBits());
3056 BitCastInst
*CastFrmFlt
= cast
<BitCastInst
>(VVal
->getNextNode());
3057 EXPECT_EQ(CastFrmFlt
->getSrcTy(), Float32
->getPointerTo());
3058 EXPECT_EQ(CastFrmFlt
->getDestTy(), IntCastTy
->getPointerTo());
3059 EXPECT_EQ(CastFrmFlt
->getOperand(0), XVal
);
3061 LoadInst
*AtomicLoad
= cast
<LoadInst
>(CastFrmFlt
->getNextNode());
3062 EXPECT_TRUE(AtomicLoad
->isAtomic());
3063 EXPECT_EQ(AtomicLoad
->getPointerOperand(), CastFrmFlt
);
3065 BitCastInst
*CastToFlt
= cast
<BitCastInst
>(AtomicLoad
->getNextNode());
3066 EXPECT_EQ(CastToFlt
->getSrcTy(), IntCastTy
);
3067 EXPECT_EQ(CastToFlt
->getDestTy(), Float32
);
3068 EXPECT_EQ(CastToFlt
->getOperand(0), AtomicLoad
);
3070 StoreInst
*StoreofAtomic
= cast
<StoreInst
>(CastToFlt
->getNextNode());
3071 EXPECT_EQ(StoreofAtomic
->getValueOperand(), CastToFlt
);
3072 EXPECT_EQ(StoreofAtomic
->getPointerOperand(), VVal
);
3074 Builder
.CreateRetVoid();
3075 OMPBuilder
.finalize();
3076 EXPECT_FALSE(verifyModule(*M
, &errs()));
3079 TEST_F(OpenMPIRBuilderTest
, OMPAtomicReadInt
) {
3080 OpenMPIRBuilder
OMPBuilder(*M
);
3081 OMPBuilder
.initialize();
3083 IRBuilder
<> Builder(BB
);
3085 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
3087 IntegerType
*Int32
= Type::getInt32Ty(M
->getContext());
3088 AllocaInst
*XVal
= Builder
.CreateAlloca(Int32
);
3089 XVal
->setName("AtomicVar");
3090 AllocaInst
*VVal
= Builder
.CreateAlloca(Int32
);
3091 VVal
->setName("AtomicRead");
3092 AtomicOrdering AO
= AtomicOrdering::Monotonic
;
3093 OpenMPIRBuilder::AtomicOpValue X
= {XVal
, Int32
, false, false};
3094 OpenMPIRBuilder::AtomicOpValue V
= {VVal
, Int32
, false, false};
3096 BasicBlock
*EntryBB
= BB
;
3098 Builder
.restoreIP(OMPBuilder
.createAtomicRead(Loc
, X
, V
, AO
));
3099 LoadInst
*AtomicLoad
= nullptr;
3100 StoreInst
*StoreofAtomic
= nullptr;
3102 for (Instruction
&Cur
: *EntryBB
) {
3103 if (isa
<LoadInst
>(Cur
)) {
3104 AtomicLoad
= cast
<LoadInst
>(&Cur
);
3105 if (AtomicLoad
->getPointerOperand() == XVal
)
3107 AtomicLoad
= nullptr;
3108 } else if (isa
<StoreInst
>(Cur
)) {
3109 StoreofAtomic
= cast
<StoreInst
>(&Cur
);
3110 if (StoreofAtomic
->getPointerOperand() == VVal
)
3112 StoreofAtomic
= nullptr;
3116 EXPECT_NE(AtomicLoad
, nullptr);
3117 EXPECT_TRUE(AtomicLoad
->isAtomic());
3119 EXPECT_NE(StoreofAtomic
, nullptr);
3120 EXPECT_EQ(StoreofAtomic
->getValueOperand(), AtomicLoad
);
3122 Builder
.CreateRetVoid();
3123 OMPBuilder
.finalize();
3125 EXPECT_FALSE(verifyModule(*M
, &errs()));
3128 TEST_F(OpenMPIRBuilderTest
, OMPAtomicWriteFlt
) {
3129 OpenMPIRBuilder
OMPBuilder(*M
);
3130 OMPBuilder
.initialize();
3132 IRBuilder
<> Builder(BB
);
3134 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
3136 LLVMContext
&Ctx
= M
->getContext();
3137 Type
*Float32
= Type::getFloatTy(Ctx
);
3138 AllocaInst
*XVal
= Builder
.CreateAlloca(Float32
);
3139 XVal
->setName("AtomicVar");
3140 OpenMPIRBuilder::AtomicOpValue X
= {XVal
, Float32
, false, false};
3141 AtomicOrdering AO
= AtomicOrdering::Monotonic
;
3142 Constant
*ValToWrite
= ConstantFP::get(Float32
, 1.0);
3144 Builder
.restoreIP(OMPBuilder
.createAtomicWrite(Loc
, X
, ValToWrite
, AO
));
3146 IntegerType
*IntCastTy
=
3147 IntegerType::get(M
->getContext(), Float32
->getScalarSizeInBits());
3149 BitCastInst
*CastFrmFlt
= cast
<BitCastInst
>(XVal
->getNextNode());
3150 EXPECT_EQ(CastFrmFlt
->getSrcTy(), Float32
->getPointerTo());
3151 EXPECT_EQ(CastFrmFlt
->getDestTy(), IntCastTy
->getPointerTo());
3152 EXPECT_EQ(CastFrmFlt
->getOperand(0), XVal
);
3154 Value
*ExprCast
= Builder
.CreateBitCast(ValToWrite
, IntCastTy
);
3156 StoreInst
*StoreofAtomic
= cast
<StoreInst
>(CastFrmFlt
->getNextNode());
3157 EXPECT_EQ(StoreofAtomic
->getValueOperand(), ExprCast
);
3158 EXPECT_EQ(StoreofAtomic
->getPointerOperand(), CastFrmFlt
);
3159 EXPECT_TRUE(StoreofAtomic
->isAtomic());
3161 Builder
.CreateRetVoid();
3162 OMPBuilder
.finalize();
3163 EXPECT_FALSE(verifyModule(*M
, &errs()));
3166 TEST_F(OpenMPIRBuilderTest
, OMPAtomicWriteInt
) {
3167 OpenMPIRBuilder
OMPBuilder(*M
);
3168 OMPBuilder
.initialize();
3170 IRBuilder
<> Builder(BB
);
3172 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
3174 LLVMContext
&Ctx
= M
->getContext();
3175 IntegerType
*Int32
= Type::getInt32Ty(Ctx
);
3176 AllocaInst
*XVal
= Builder
.CreateAlloca(Int32
);
3177 XVal
->setName("AtomicVar");
3178 OpenMPIRBuilder::AtomicOpValue X
= {XVal
, Int32
, false, false};
3179 AtomicOrdering AO
= AtomicOrdering::Monotonic
;
3180 ConstantInt
*ValToWrite
= ConstantInt::get(Type::getInt32Ty(Ctx
), 1U);
3182 BasicBlock
*EntryBB
= BB
;
3184 Builder
.restoreIP(OMPBuilder
.createAtomicWrite(Loc
, X
, ValToWrite
, AO
));
3186 StoreInst
*StoreofAtomic
= nullptr;
3188 for (Instruction
&Cur
: *EntryBB
) {
3189 if (isa
<StoreInst
>(Cur
)) {
3190 StoreofAtomic
= cast
<StoreInst
>(&Cur
);
3191 if (StoreofAtomic
->getPointerOperand() == XVal
)
3193 StoreofAtomic
= nullptr;
3197 EXPECT_NE(StoreofAtomic
, nullptr);
3198 EXPECT_TRUE(StoreofAtomic
->isAtomic());
3199 EXPECT_EQ(StoreofAtomic
->getValueOperand(), ValToWrite
);
3201 Builder
.CreateRetVoid();
3202 OMPBuilder
.finalize();
3203 EXPECT_FALSE(verifyModule(*M
, &errs()));
3206 TEST_F(OpenMPIRBuilderTest
, OMPAtomicUpdate
) {
3207 OpenMPIRBuilder
OMPBuilder(*M
);
3208 OMPBuilder
.initialize();
3210 IRBuilder
<> Builder(BB
);
3212 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
3214 IntegerType
*Int32
= Type::getInt32Ty(M
->getContext());
3215 AllocaInst
*XVal
= Builder
.CreateAlloca(Int32
);
3216 XVal
->setName("AtomicVar");
3217 Builder
.CreateStore(ConstantInt::get(Type::getInt32Ty(Ctx
), 0U), XVal
);
3218 OpenMPIRBuilder::AtomicOpValue X
= {XVal
, Int32
, false, false};
3219 AtomicOrdering AO
= AtomicOrdering::Monotonic
;
3220 ConstantInt
*ConstVal
= ConstantInt::get(Type::getInt32Ty(Ctx
), 1U);
3221 Value
*Expr
= nullptr;
3222 AtomicRMWInst::BinOp RMWOp
= AtomicRMWInst::Sub
;
3223 bool IsXLHSInRHSPart
= false;
3225 BasicBlock
*EntryBB
= BB
;
3226 OpenMPIRBuilder::InsertPointTy
AllocaIP(EntryBB
,
3227 EntryBB
->getFirstInsertionPt());
3228 Value
*Sub
= nullptr;
3230 auto UpdateOp
= [&](Value
*Atomic
, IRBuilder
<> &IRB
) {
3231 Sub
= IRB
.CreateSub(ConstVal
, Atomic
);
3234 Builder
.restoreIP(OMPBuilder
.createAtomicUpdate(
3235 Builder
, AllocaIP
, X
, Expr
, AO
, RMWOp
, UpdateOp
, IsXLHSInRHSPart
));
3236 BasicBlock
*ContBB
= EntryBB
->getSingleSuccessor();
3237 BranchInst
*ContTI
= dyn_cast
<BranchInst
>(ContBB
->getTerminator());
3238 EXPECT_NE(ContTI
, nullptr);
3239 BasicBlock
*EndBB
= ContTI
->getSuccessor(0);
3240 EXPECT_TRUE(ContTI
->isConditional());
3241 EXPECT_EQ(ContTI
->getSuccessor(1), ContBB
);
3242 EXPECT_NE(EndBB
, nullptr);
3244 PHINode
*Phi
= dyn_cast
<PHINode
>(&ContBB
->front());
3245 EXPECT_NE(Phi
, nullptr);
3246 EXPECT_EQ(Phi
->getNumIncomingValues(), 2U);
3247 EXPECT_EQ(Phi
->getIncomingBlock(0), EntryBB
);
3248 EXPECT_EQ(Phi
->getIncomingBlock(1), ContBB
);
3250 EXPECT_EQ(Sub
->getNumUses(), 1U);
3251 StoreInst
*St
= dyn_cast
<StoreInst
>(Sub
->user_back());
3252 AllocaInst
*UpdateTemp
= dyn_cast
<AllocaInst
>(St
->getPointerOperand());
3254 ExtractValueInst
*ExVI1
=
3255 dyn_cast
<ExtractValueInst
>(Phi
->getIncomingValueForBlock(ContBB
));
3256 EXPECT_NE(ExVI1
, nullptr);
3257 AtomicCmpXchgInst
*CmpExchg
=
3258 dyn_cast
<AtomicCmpXchgInst
>(ExVI1
->getAggregateOperand());
3259 EXPECT_NE(CmpExchg
, nullptr);
3260 EXPECT_EQ(CmpExchg
->getPointerOperand(), XVal
);
3261 EXPECT_EQ(CmpExchg
->getCompareOperand(), Phi
);
3262 EXPECT_EQ(CmpExchg
->getSuccessOrdering(), AtomicOrdering::Monotonic
);
3264 LoadInst
*Ld
= dyn_cast
<LoadInst
>(CmpExchg
->getNewValOperand());
3265 EXPECT_NE(Ld
, nullptr);
3266 EXPECT_EQ(UpdateTemp
, Ld
->getPointerOperand());
3268 Builder
.CreateRetVoid();
3269 OMPBuilder
.finalize();
3270 EXPECT_FALSE(verifyModule(*M
, &errs()));
3273 TEST_F(OpenMPIRBuilderTest
, OMPAtomicUpdateFloat
) {
3274 OpenMPIRBuilder
OMPBuilder(*M
);
3275 OMPBuilder
.initialize();
3277 IRBuilder
<> Builder(BB
);
3279 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
3281 Type
*FloatTy
= Type::getFloatTy(M
->getContext());
3282 AllocaInst
*XVal
= Builder
.CreateAlloca(FloatTy
);
3283 XVal
->setName("AtomicVar");
3284 Builder
.CreateStore(ConstantFP::get(Type::getFloatTy(Ctx
), 0.0), XVal
);
3285 OpenMPIRBuilder::AtomicOpValue X
= {XVal
, FloatTy
, false, false};
3286 AtomicOrdering AO
= AtomicOrdering::Monotonic
;
3287 Constant
*ConstVal
= ConstantFP::get(Type::getFloatTy(Ctx
), 1.0);
3288 Value
*Expr
= nullptr;
3289 AtomicRMWInst::BinOp RMWOp
= AtomicRMWInst::FSub
;
3290 bool IsXLHSInRHSPart
= false;
3292 BasicBlock
*EntryBB
= BB
;
3293 OpenMPIRBuilder::InsertPointTy
AllocaIP(EntryBB
,
3294 EntryBB
->getFirstInsertionPt());
3295 Value
*Sub
= nullptr;
3297 auto UpdateOp
= [&](Value
*Atomic
, IRBuilder
<> &IRB
) {
3298 Sub
= IRB
.CreateFSub(ConstVal
, Atomic
);
3301 Builder
.restoreIP(OMPBuilder
.createAtomicUpdate(
3302 Builder
, AllocaIP
, X
, Expr
, AO
, RMWOp
, UpdateOp
, IsXLHSInRHSPart
));
3303 BasicBlock
*ContBB
= EntryBB
->getSingleSuccessor();
3304 BranchInst
*ContTI
= dyn_cast
<BranchInst
>(ContBB
->getTerminator());
3305 EXPECT_NE(ContTI
, nullptr);
3306 BasicBlock
*EndBB
= ContTI
->getSuccessor(0);
3307 EXPECT_TRUE(ContTI
->isConditional());
3308 EXPECT_EQ(ContTI
->getSuccessor(1), ContBB
);
3309 EXPECT_NE(EndBB
, nullptr);
3311 PHINode
*Phi
= dyn_cast
<PHINode
>(&ContBB
->front());
3312 EXPECT_NE(Phi
, nullptr);
3313 EXPECT_EQ(Phi
->getNumIncomingValues(), 2U);
3314 EXPECT_EQ(Phi
->getIncomingBlock(0), EntryBB
);
3315 EXPECT_EQ(Phi
->getIncomingBlock(1), ContBB
);
3317 EXPECT_EQ(Sub
->getNumUses(), 1U);
3318 StoreInst
*St
= dyn_cast
<StoreInst
>(Sub
->user_back());
3319 AllocaInst
*UpdateTemp
= dyn_cast
<AllocaInst
>(St
->getPointerOperand());
3321 ExtractValueInst
*ExVI1
=
3322 dyn_cast
<ExtractValueInst
>(Phi
->getIncomingValueForBlock(ContBB
));
3323 EXPECT_NE(ExVI1
, nullptr);
3324 AtomicCmpXchgInst
*CmpExchg
=
3325 dyn_cast
<AtomicCmpXchgInst
>(ExVI1
->getAggregateOperand());
3326 EXPECT_NE(CmpExchg
, nullptr);
3327 BitCastInst
*BitCastNew
=
3328 dyn_cast
<BitCastInst
>(CmpExchg
->getPointerOperand());
3329 EXPECT_NE(BitCastNew
, nullptr);
3330 EXPECT_EQ(BitCastNew
->getOperand(0), XVal
);
3331 EXPECT_EQ(CmpExchg
->getCompareOperand(), Phi
);
3332 EXPECT_EQ(CmpExchg
->getSuccessOrdering(), AtomicOrdering::Monotonic
);
3334 LoadInst
*Ld
= dyn_cast
<LoadInst
>(CmpExchg
->getNewValOperand());
3335 EXPECT_NE(Ld
, nullptr);
3336 BitCastInst
*BitCastOld
= dyn_cast
<BitCastInst
>(Ld
->getPointerOperand());
3337 EXPECT_NE(BitCastOld
, nullptr);
3338 EXPECT_EQ(UpdateTemp
, BitCastOld
->getOperand(0));
3340 Builder
.CreateRetVoid();
3341 OMPBuilder
.finalize();
3342 EXPECT_FALSE(verifyModule(*M
, &errs()));
3345 TEST_F(OpenMPIRBuilderTest
, OMPAtomicUpdateIntr
) {
3346 OpenMPIRBuilder
OMPBuilder(*M
);
3347 OMPBuilder
.initialize();
3349 IRBuilder
<> Builder(BB
);
3351 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
3353 Type
*IntTy
= Type::getInt32Ty(M
->getContext());
3354 AllocaInst
*XVal
= Builder
.CreateAlloca(IntTy
);
3355 XVal
->setName("AtomicVar");
3356 Builder
.CreateStore(ConstantInt::get(Type::getInt32Ty(Ctx
), 0), XVal
);
3357 OpenMPIRBuilder::AtomicOpValue X
= {XVal
, IntTy
, false, false};
3358 AtomicOrdering AO
= AtomicOrdering::Monotonic
;
3359 Constant
*ConstVal
= ConstantInt::get(Type::getInt32Ty(Ctx
), 1);
3360 Value
*Expr
= ConstantInt::get(Type::getInt32Ty(Ctx
), 1);
3361 AtomicRMWInst::BinOp RMWOp
= AtomicRMWInst::UMax
;
3362 bool IsXLHSInRHSPart
= false;
3364 BasicBlock
*EntryBB
= BB
;
3365 OpenMPIRBuilder::InsertPointTy
AllocaIP(EntryBB
,
3366 EntryBB
->getFirstInsertionPt());
3367 Value
*Sub
= nullptr;
3369 auto UpdateOp
= [&](Value
*Atomic
, IRBuilder
<> &IRB
) {
3370 Sub
= IRB
.CreateSub(ConstVal
, Atomic
);
3373 Builder
.restoreIP(OMPBuilder
.createAtomicUpdate(
3374 Builder
, AllocaIP
, X
, Expr
, AO
, RMWOp
, UpdateOp
, IsXLHSInRHSPart
));
3375 BasicBlock
*ContBB
= EntryBB
->getSingleSuccessor();
3376 BranchInst
*ContTI
= dyn_cast
<BranchInst
>(ContBB
->getTerminator());
3377 EXPECT_NE(ContTI
, nullptr);
3378 BasicBlock
*EndBB
= ContTI
->getSuccessor(0);
3379 EXPECT_TRUE(ContTI
->isConditional());
3380 EXPECT_EQ(ContTI
->getSuccessor(1), ContBB
);
3381 EXPECT_NE(EndBB
, nullptr);
3383 PHINode
*Phi
= dyn_cast
<PHINode
>(&ContBB
->front());
3384 EXPECT_NE(Phi
, nullptr);
3385 EXPECT_EQ(Phi
->getNumIncomingValues(), 2U);
3386 EXPECT_EQ(Phi
->getIncomingBlock(0), EntryBB
);
3387 EXPECT_EQ(Phi
->getIncomingBlock(1), ContBB
);
3389 EXPECT_EQ(Sub
->getNumUses(), 1U);
3390 StoreInst
*St
= dyn_cast
<StoreInst
>(Sub
->user_back());
3391 AllocaInst
*UpdateTemp
= dyn_cast
<AllocaInst
>(St
->getPointerOperand());
3393 ExtractValueInst
*ExVI1
=
3394 dyn_cast
<ExtractValueInst
>(Phi
->getIncomingValueForBlock(ContBB
));
3395 EXPECT_NE(ExVI1
, nullptr);
3396 AtomicCmpXchgInst
*CmpExchg
=
3397 dyn_cast
<AtomicCmpXchgInst
>(ExVI1
->getAggregateOperand());
3398 EXPECT_NE(CmpExchg
, nullptr);
3399 EXPECT_EQ(CmpExchg
->getPointerOperand(), XVal
);
3400 EXPECT_EQ(CmpExchg
->getCompareOperand(), Phi
);
3401 EXPECT_EQ(CmpExchg
->getSuccessOrdering(), AtomicOrdering::Monotonic
);
3403 LoadInst
*Ld
= dyn_cast
<LoadInst
>(CmpExchg
->getNewValOperand());
3404 EXPECT_NE(Ld
, nullptr);
3405 EXPECT_EQ(UpdateTemp
, Ld
->getPointerOperand());
3407 Builder
.CreateRetVoid();
3408 OMPBuilder
.finalize();
3409 EXPECT_FALSE(verifyModule(*M
, &errs()));
3412 TEST_F(OpenMPIRBuilderTest
, OMPAtomicCapture
) {
3413 OpenMPIRBuilder
OMPBuilder(*M
);
3414 OMPBuilder
.initialize();
3416 IRBuilder
<> Builder(BB
);
3418 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
3420 LLVMContext
&Ctx
= M
->getContext();
3421 IntegerType
*Int32
= Type::getInt32Ty(Ctx
);
3422 AllocaInst
*XVal
= Builder
.CreateAlloca(Int32
);
3423 XVal
->setName("AtomicVar");
3424 AllocaInst
*VVal
= Builder
.CreateAlloca(Int32
);
3425 VVal
->setName("AtomicCapTar");
3427 Builder
.CreateStore(ConstantInt::get(Type::getInt32Ty(Ctx
), 0U), XVal
);
3429 OpenMPIRBuilder::AtomicOpValue X
= {XVal
, Int32
, false, false};
3430 OpenMPIRBuilder::AtomicOpValue V
= {VVal
, Int32
, false, false};
3431 AtomicOrdering AO
= AtomicOrdering::Monotonic
;
3432 ConstantInt
*Expr
= ConstantInt::get(Type::getInt32Ty(Ctx
), 1U);
3433 AtomicRMWInst::BinOp RMWOp
= AtomicRMWInst::Add
;
3434 bool IsXLHSInRHSPart
= true;
3435 bool IsPostfixUpdate
= true;
3436 bool UpdateExpr
= true;
3438 BasicBlock
*EntryBB
= BB
;
3439 OpenMPIRBuilder::InsertPointTy
AllocaIP(EntryBB
,
3440 EntryBB
->getFirstInsertionPt());
3442 // integer update - not used
3443 auto UpdateOp
= [&](Value
*Atomic
, IRBuilder
<> &IRB
) { return nullptr; };
3445 Builder
.restoreIP(OMPBuilder
.createAtomicCapture(
3446 Builder
, AllocaIP
, X
, V
, Expr
, AO
, RMWOp
, UpdateOp
, UpdateExpr
,
3447 IsPostfixUpdate
, IsXLHSInRHSPart
));
3448 EXPECT_EQ(EntryBB
->getParent()->size(), 1U);
3449 AtomicRMWInst
*ARWM
= dyn_cast
<AtomicRMWInst
>(Init
->getNextNode());
3450 EXPECT_NE(ARWM
, nullptr);
3451 EXPECT_EQ(ARWM
->getPointerOperand(), XVal
);
3452 EXPECT_EQ(ARWM
->getOperation(), RMWOp
);
3453 StoreInst
*St
= dyn_cast
<StoreInst
>(ARWM
->user_back());
3454 EXPECT_NE(St
, nullptr);
3455 EXPECT_EQ(St
->getPointerOperand(), VVal
);
3457 Builder
.CreateRetVoid();
3458 OMPBuilder
.finalize();
3459 EXPECT_FALSE(verifyModule(*M
, &errs()));
3462 TEST_F(OpenMPIRBuilderTest
, OMPAtomicCompare
) {
3463 OpenMPIRBuilder
OMPBuilder(*M
);
3464 OMPBuilder
.initialize();
3466 IRBuilder
<> Builder(BB
);
3468 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
3470 LLVMContext
&Ctx
= M
->getContext();
3471 IntegerType
*Int32
= Type::getInt32Ty(Ctx
);
3472 AllocaInst
*XVal
= Builder
.CreateAlloca(Int32
);
3475 Builder
.CreateStore(ConstantInt::get(Type::getInt32Ty(Ctx
), 0U), XVal
);
3477 OpenMPIRBuilder::AtomicOpValue XSigned
= {XVal
, Int32
, true, false};
3478 OpenMPIRBuilder::AtomicOpValue XUnsigned
= {XVal
, Int32
, false, false};
3479 // V and R are not used in atomic compare
3480 OpenMPIRBuilder::AtomicOpValue V
= {nullptr, nullptr, false, false};
3481 OpenMPIRBuilder::AtomicOpValue R
= {nullptr, nullptr, false, false};
3482 AtomicOrdering AO
= AtomicOrdering::Monotonic
;
3483 ConstantInt
*Expr
= ConstantInt::get(Type::getInt32Ty(Ctx
), 1U);
3484 ConstantInt
*D
= ConstantInt::get(Type::getInt32Ty(Ctx
), 1U);
3485 OMPAtomicCompareOp OpMax
= OMPAtomicCompareOp::MAX
;
3486 OMPAtomicCompareOp OpEQ
= OMPAtomicCompareOp::EQ
;
3488 Builder
.restoreIP(OMPBuilder
.createAtomicCompare(
3489 Builder
, XSigned
, V
, R
, Expr
, nullptr, AO
, OpMax
, true, false, false));
3490 Builder
.restoreIP(OMPBuilder
.createAtomicCompare(
3491 Builder
, XUnsigned
, V
, R
, Expr
, nullptr, AO
, OpMax
, false, false, false));
3492 Builder
.restoreIP(OMPBuilder
.createAtomicCompare(
3493 Builder
, XSigned
, V
, R
, Expr
, D
, AO
, OpEQ
, true, false, false));
3495 BasicBlock
*EntryBB
= BB
;
3496 EXPECT_EQ(EntryBB
->getParent()->size(), 1U);
3497 EXPECT_EQ(EntryBB
->size(), 5U);
3499 AtomicRMWInst
*ARWM1
= dyn_cast
<AtomicRMWInst
>(Init
->getNextNode());
3500 EXPECT_NE(ARWM1
, nullptr);
3501 EXPECT_EQ(ARWM1
->getPointerOperand(), XVal
);
3502 EXPECT_EQ(ARWM1
->getValOperand(), Expr
);
3503 EXPECT_EQ(ARWM1
->getOperation(), AtomicRMWInst::Min
);
3505 AtomicRMWInst
*ARWM2
= dyn_cast
<AtomicRMWInst
>(ARWM1
->getNextNode());
3506 EXPECT_NE(ARWM2
, nullptr);
3507 EXPECT_EQ(ARWM2
->getPointerOperand(), XVal
);
3508 EXPECT_EQ(ARWM2
->getValOperand(), Expr
);
3509 EXPECT_EQ(ARWM2
->getOperation(), AtomicRMWInst::UMax
);
3511 AtomicCmpXchgInst
*AXCHG
= dyn_cast
<AtomicCmpXchgInst
>(ARWM2
->getNextNode());
3512 EXPECT_NE(AXCHG
, nullptr);
3513 EXPECT_EQ(AXCHG
->getPointerOperand(), XVal
);
3514 EXPECT_EQ(AXCHG
->getCompareOperand(), Expr
);
3515 EXPECT_EQ(AXCHG
->getNewValOperand(), D
);
3517 Builder
.CreateRetVoid();
3518 OMPBuilder
.finalize();
3519 EXPECT_FALSE(verifyModule(*M
, &errs()));
3522 TEST_F(OpenMPIRBuilderTest
, OMPAtomicCompareCapture
) {
3523 OpenMPIRBuilder
OMPBuilder(*M
);
3524 OMPBuilder
.initialize();
3526 IRBuilder
<> Builder(BB
);
3528 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
3530 LLVMContext
&Ctx
= M
->getContext();
3531 IntegerType
*Int32
= Type::getInt32Ty(Ctx
);
3532 AllocaInst
*XVal
= Builder
.CreateAlloca(Int32
);
3534 AllocaInst
*VVal
= Builder
.CreateAlloca(Int32
);
3536 AllocaInst
*RVal
= Builder
.CreateAlloca(Int32
);
3540 Builder
.CreateStore(ConstantInt::get(Type::getInt32Ty(Ctx
), 0U), XVal
);
3542 OpenMPIRBuilder::AtomicOpValue X
= {XVal
, Int32
, true, false};
3543 OpenMPIRBuilder::AtomicOpValue V
= {VVal
, Int32
, false, false};
3544 OpenMPIRBuilder::AtomicOpValue NoV
= {nullptr, nullptr, false, false};
3545 OpenMPIRBuilder::AtomicOpValue R
= {RVal
, Int32
, false, false};
3546 OpenMPIRBuilder::AtomicOpValue NoR
= {nullptr, nullptr, false, false};
3548 AtomicOrdering AO
= AtomicOrdering::Monotonic
;
3549 ConstantInt
*Expr
= ConstantInt::get(Type::getInt32Ty(Ctx
), 1U);
3550 ConstantInt
*D
= ConstantInt::get(Type::getInt32Ty(Ctx
), 1U);
3551 OMPAtomicCompareOp OpMax
= OMPAtomicCompareOp::MAX
;
3552 OMPAtomicCompareOp OpEQ
= OMPAtomicCompareOp::EQ
;
3554 // { cond-update-stmt v = x; }
3555 Builder
.restoreIP(OMPBuilder
.createAtomicCompare(
3556 Builder
, X
, V
, NoR
, Expr
, D
, AO
, OpEQ
, /* IsXBinopExpr */ true,
3557 /* IsPostfixUpdate */ false,
3558 /* IsFailOnly */ false));
3559 // { v = x; cond-update-stmt }
3560 Builder
.restoreIP(OMPBuilder
.createAtomicCompare(
3561 Builder
, X
, V
, NoR
, Expr
, D
, AO
, OpEQ
, /* IsXBinopExpr */ true,
3562 /* IsPostfixUpdate */ true,
3563 /* IsFailOnly */ false));
3564 // if(x == e) { x = d; } else { v = x; }
3565 Builder
.restoreIP(OMPBuilder
.createAtomicCompare(
3566 Builder
, X
, V
, NoR
, Expr
, D
, AO
, OpEQ
, /* IsXBinopExpr */ true,
3567 /* IsPostfixUpdate */ false,
3568 /* IsFailOnly */ true));
3569 // { r = x == e; if(r) { x = d; } }
3570 Builder
.restoreIP(OMPBuilder
.createAtomicCompare(
3571 Builder
, X
, NoV
, R
, Expr
, D
, AO
, OpEQ
, /* IsXBinopExpr */ true,
3572 /* IsPostfixUpdate */ false,
3573 /* IsFailOnly */ false));
3574 // { r = x == e; if(r) { x = d; } else { v = x; } }
3575 Builder
.restoreIP(OMPBuilder
.createAtomicCompare(
3576 Builder
, X
, V
, R
, Expr
, D
, AO
, OpEQ
, /* IsXBinopExpr */ true,
3577 /* IsPostfixUpdate */ false,
3578 /* IsFailOnly */ true));
3580 // { v = x; cond-update-stmt }
3581 Builder
.restoreIP(OMPBuilder
.createAtomicCompare(
3582 Builder
, X
, V
, NoR
, Expr
, nullptr, AO
, OpMax
, /* IsXBinopExpr */ true,
3583 /* IsPostfixUpdate */ true,
3584 /* IsFailOnly */ false));
3585 // { cond-update-stmt v = x; }
3586 Builder
.restoreIP(OMPBuilder
.createAtomicCompare(
3587 Builder
, X
, V
, NoR
, Expr
, nullptr, AO
, OpMax
, /* IsXBinopExpr */ false,
3588 /* IsPostfixUpdate */ false,
3589 /* IsFailOnly */ false));
3591 BasicBlock
*EntryBB
= BB
;
3592 EXPECT_EQ(EntryBB
->getParent()->size(), 5U);
3593 BasicBlock
*Cont1
= dyn_cast
<BasicBlock
>(EntryBB
->getNextNode());
3594 EXPECT_NE(Cont1
, nullptr);
3595 BasicBlock
*Exit1
= dyn_cast
<BasicBlock
>(Cont1
->getNextNode());
3596 EXPECT_NE(Exit1
, nullptr);
3597 BasicBlock
*Cont2
= dyn_cast
<BasicBlock
>(Exit1
->getNextNode());
3598 EXPECT_NE(Cont2
, nullptr);
3599 BasicBlock
*Exit2
= dyn_cast
<BasicBlock
>(Cont2
->getNextNode());
3600 EXPECT_NE(Exit2
, nullptr);
3602 AtomicCmpXchgInst
*CmpXchg1
=
3603 dyn_cast
<AtomicCmpXchgInst
>(Init
->getNextNode());
3604 EXPECT_NE(CmpXchg1
, nullptr);
3605 EXPECT_EQ(CmpXchg1
->getPointerOperand(), XVal
);
3606 EXPECT_EQ(CmpXchg1
->getCompareOperand(), Expr
);
3607 EXPECT_EQ(CmpXchg1
->getNewValOperand(), D
);
3608 ExtractValueInst
*ExtVal1
=
3609 dyn_cast
<ExtractValueInst
>(CmpXchg1
->getNextNode());
3610 EXPECT_NE(ExtVal1
, nullptr);
3611 EXPECT_EQ(ExtVal1
->getAggregateOperand(), CmpXchg1
);
3612 EXPECT_EQ(ExtVal1
->getIndices(), ArrayRef
<unsigned int>(0U));
3613 ExtractValueInst
*ExtVal2
=
3614 dyn_cast
<ExtractValueInst
>(ExtVal1
->getNextNode());
3615 EXPECT_NE(ExtVal2
, nullptr);
3616 EXPECT_EQ(ExtVal2
->getAggregateOperand(), CmpXchg1
);
3617 EXPECT_EQ(ExtVal2
->getIndices(), ArrayRef
<unsigned int>(1U));
3618 SelectInst
*Sel1
= dyn_cast
<SelectInst
>(ExtVal2
->getNextNode());
3619 EXPECT_NE(Sel1
, nullptr);
3620 EXPECT_EQ(Sel1
->getCondition(), ExtVal2
);
3621 EXPECT_EQ(Sel1
->getTrueValue(), Expr
);
3622 EXPECT_EQ(Sel1
->getFalseValue(), ExtVal1
);
3623 StoreInst
*Store1
= dyn_cast
<StoreInst
>(Sel1
->getNextNode());
3624 EXPECT_NE(Store1
, nullptr);
3625 EXPECT_EQ(Store1
->getPointerOperand(), VVal
);
3626 EXPECT_EQ(Store1
->getValueOperand(), Sel1
);
3628 AtomicCmpXchgInst
*CmpXchg2
=
3629 dyn_cast
<AtomicCmpXchgInst
>(Store1
->getNextNode());
3630 EXPECT_NE(CmpXchg2
, nullptr);
3631 EXPECT_EQ(CmpXchg2
->getPointerOperand(), XVal
);
3632 EXPECT_EQ(CmpXchg2
->getCompareOperand(), Expr
);
3633 EXPECT_EQ(CmpXchg2
->getNewValOperand(), D
);
3634 ExtractValueInst
*ExtVal3
=
3635 dyn_cast
<ExtractValueInst
>(CmpXchg2
->getNextNode());
3636 EXPECT_NE(ExtVal3
, nullptr);
3637 EXPECT_EQ(ExtVal3
->getAggregateOperand(), CmpXchg2
);
3638 EXPECT_EQ(ExtVal3
->getIndices(), ArrayRef
<unsigned int>(0U));
3639 StoreInst
*Store2
= dyn_cast
<StoreInst
>(ExtVal3
->getNextNode());
3640 EXPECT_NE(Store2
, nullptr);
3641 EXPECT_EQ(Store2
->getPointerOperand(), VVal
);
3642 EXPECT_EQ(Store2
->getValueOperand(), ExtVal3
);
3644 AtomicCmpXchgInst
*CmpXchg3
=
3645 dyn_cast
<AtomicCmpXchgInst
>(Store2
->getNextNode());
3646 EXPECT_NE(CmpXchg3
, nullptr);
3647 EXPECT_EQ(CmpXchg3
->getPointerOperand(), XVal
);
3648 EXPECT_EQ(CmpXchg3
->getCompareOperand(), Expr
);
3649 EXPECT_EQ(CmpXchg3
->getNewValOperand(), D
);
3650 ExtractValueInst
*ExtVal4
=
3651 dyn_cast
<ExtractValueInst
>(CmpXchg3
->getNextNode());
3652 EXPECT_NE(ExtVal4
, nullptr);
3653 EXPECT_EQ(ExtVal4
->getAggregateOperand(), CmpXchg3
);
3654 EXPECT_EQ(ExtVal4
->getIndices(), ArrayRef
<unsigned int>(0U));
3655 ExtractValueInst
*ExtVal5
=
3656 dyn_cast
<ExtractValueInst
>(ExtVal4
->getNextNode());
3657 EXPECT_NE(ExtVal5
, nullptr);
3658 EXPECT_EQ(ExtVal5
->getAggregateOperand(), CmpXchg3
);
3659 EXPECT_EQ(ExtVal5
->getIndices(), ArrayRef
<unsigned int>(1U));
3660 BranchInst
*Br1
= dyn_cast
<BranchInst
>(ExtVal5
->getNextNode());
3661 EXPECT_NE(Br1
, nullptr);
3662 EXPECT_EQ(Br1
->isConditional(), true);
3663 EXPECT_EQ(Br1
->getCondition(), ExtVal5
);
3664 EXPECT_EQ(Br1
->getSuccessor(0), Exit1
);
3665 EXPECT_EQ(Br1
->getSuccessor(1), Cont1
);
3667 StoreInst
*Store3
= dyn_cast
<StoreInst
>(&Cont1
->front());
3668 EXPECT_NE(Store3
, nullptr);
3669 EXPECT_EQ(Store3
->getPointerOperand(), VVal
);
3670 EXPECT_EQ(Store3
->getValueOperand(), ExtVal4
);
3671 BranchInst
*Br2
= dyn_cast
<BranchInst
>(Store3
->getNextNode());
3672 EXPECT_NE(Br2
, nullptr);
3673 EXPECT_EQ(Br2
->isUnconditional(), true);
3674 EXPECT_EQ(Br2
->getSuccessor(0), Exit1
);
3676 AtomicCmpXchgInst
*CmpXchg4
= dyn_cast
<AtomicCmpXchgInst
>(&Exit1
->front());
3677 EXPECT_NE(CmpXchg4
, nullptr);
3678 EXPECT_EQ(CmpXchg4
->getPointerOperand(), XVal
);
3679 EXPECT_EQ(CmpXchg4
->getCompareOperand(), Expr
);
3680 EXPECT_EQ(CmpXchg4
->getNewValOperand(), D
);
3681 ExtractValueInst
*ExtVal6
=
3682 dyn_cast
<ExtractValueInst
>(CmpXchg4
->getNextNode());
3683 EXPECT_NE(ExtVal6
, nullptr);
3684 EXPECT_EQ(ExtVal6
->getAggregateOperand(), CmpXchg4
);
3685 EXPECT_EQ(ExtVal6
->getIndices(), ArrayRef
<unsigned int>(1U));
3686 ZExtInst
*ZExt1
= dyn_cast
<ZExtInst
>(ExtVal6
->getNextNode());
3687 EXPECT_NE(ZExt1
, nullptr);
3688 EXPECT_EQ(ZExt1
->getDestTy(), Int32
);
3689 StoreInst
*Store4
= dyn_cast
<StoreInst
>(ZExt1
->getNextNode());
3690 EXPECT_NE(Store4
, nullptr);
3691 EXPECT_EQ(Store4
->getPointerOperand(), RVal
);
3692 EXPECT_EQ(Store4
->getValueOperand(), ZExt1
);
3694 AtomicCmpXchgInst
*CmpXchg5
=
3695 dyn_cast
<AtomicCmpXchgInst
>(Store4
->getNextNode());
3696 EXPECT_NE(CmpXchg5
, nullptr);
3697 EXPECT_EQ(CmpXchg5
->getPointerOperand(), XVal
);
3698 EXPECT_EQ(CmpXchg5
->getCompareOperand(), Expr
);
3699 EXPECT_EQ(CmpXchg5
->getNewValOperand(), D
);
3700 ExtractValueInst
*ExtVal7
=
3701 dyn_cast
<ExtractValueInst
>(CmpXchg5
->getNextNode());
3702 EXPECT_NE(ExtVal7
, nullptr);
3703 EXPECT_EQ(ExtVal7
->getAggregateOperand(), CmpXchg5
);
3704 EXPECT_EQ(ExtVal7
->getIndices(), ArrayRef
<unsigned int>(0U));
3705 ExtractValueInst
*ExtVal8
=
3706 dyn_cast
<ExtractValueInst
>(ExtVal7
->getNextNode());
3707 EXPECT_NE(ExtVal8
, nullptr);
3708 EXPECT_EQ(ExtVal8
->getAggregateOperand(), CmpXchg5
);
3709 EXPECT_EQ(ExtVal8
->getIndices(), ArrayRef
<unsigned int>(1U));
3710 BranchInst
*Br3
= dyn_cast
<BranchInst
>(ExtVal8
->getNextNode());
3711 EXPECT_NE(Br3
, nullptr);
3712 EXPECT_EQ(Br3
->isConditional(), true);
3713 EXPECT_EQ(Br3
->getCondition(), ExtVal8
);
3714 EXPECT_EQ(Br3
->getSuccessor(0), Exit2
);
3715 EXPECT_EQ(Br3
->getSuccessor(1), Cont2
);
3717 StoreInst
*Store5
= dyn_cast
<StoreInst
>(&Cont2
->front());
3718 EXPECT_NE(Store5
, nullptr);
3719 EXPECT_EQ(Store5
->getPointerOperand(), VVal
);
3720 EXPECT_EQ(Store5
->getValueOperand(), ExtVal7
);
3721 BranchInst
*Br4
= dyn_cast
<BranchInst
>(Store5
->getNextNode());
3722 EXPECT_NE(Br4
, nullptr);
3723 EXPECT_EQ(Br4
->isUnconditional(), true);
3724 EXPECT_EQ(Br4
->getSuccessor(0), Exit2
);
3726 ExtractValueInst
*ExtVal9
= dyn_cast
<ExtractValueInst
>(&Exit2
->front());
3727 EXPECT_NE(ExtVal9
, nullptr);
3728 EXPECT_EQ(ExtVal9
->getAggregateOperand(), CmpXchg5
);
3729 EXPECT_EQ(ExtVal9
->getIndices(), ArrayRef
<unsigned int>(1U));
3730 ZExtInst
*ZExt2
= dyn_cast
<ZExtInst
>(ExtVal9
->getNextNode());
3731 EXPECT_NE(ZExt2
, nullptr);
3732 EXPECT_EQ(ZExt2
->getDestTy(), Int32
);
3733 StoreInst
*Store6
= dyn_cast
<StoreInst
>(ZExt2
->getNextNode());
3734 EXPECT_NE(Store6
, nullptr);
3735 EXPECT_EQ(Store6
->getPointerOperand(), RVal
);
3736 EXPECT_EQ(Store6
->getValueOperand(), ZExt2
);
3738 AtomicRMWInst
*ARWM1
= dyn_cast
<AtomicRMWInst
>(Store6
->getNextNode());
3739 EXPECT_NE(ARWM1
, nullptr);
3740 EXPECT_EQ(ARWM1
->getPointerOperand(), XVal
);
3741 EXPECT_EQ(ARWM1
->getValOperand(), Expr
);
3742 EXPECT_EQ(ARWM1
->getOperation(), AtomicRMWInst::Min
);
3743 StoreInst
*Store7
= dyn_cast
<StoreInst
>(ARWM1
->getNextNode());
3744 EXPECT_NE(Store7
, nullptr);
3745 EXPECT_EQ(Store7
->getPointerOperand(), VVal
);
3746 EXPECT_EQ(Store7
->getValueOperand(), ARWM1
);
3748 AtomicRMWInst
*ARWM2
= dyn_cast
<AtomicRMWInst
>(Store7
->getNextNode());
3749 EXPECT_NE(ARWM2
, nullptr);
3750 EXPECT_EQ(ARWM2
->getPointerOperand(), XVal
);
3751 EXPECT_EQ(ARWM2
->getValOperand(), Expr
);
3752 EXPECT_EQ(ARWM2
->getOperation(), AtomicRMWInst::Max
);
3753 CmpInst
*Cmp1
= dyn_cast
<CmpInst
>(ARWM2
->getNextNode());
3754 EXPECT_NE(Cmp1
, nullptr);
3755 EXPECT_EQ(Cmp1
->getPredicate(), CmpInst::ICMP_SGT
);
3756 EXPECT_EQ(Cmp1
->getOperand(0), ARWM2
);
3757 EXPECT_EQ(Cmp1
->getOperand(1), Expr
);
3758 SelectInst
*Sel2
= dyn_cast
<SelectInst
>(Cmp1
->getNextNode());
3759 EXPECT_NE(Sel2
, nullptr);
3760 EXPECT_EQ(Sel2
->getCondition(), Cmp1
);
3761 EXPECT_EQ(Sel2
->getTrueValue(), Expr
);
3762 EXPECT_EQ(Sel2
->getFalseValue(), ARWM2
);
3763 StoreInst
*Store8
= dyn_cast
<StoreInst
>(Sel2
->getNextNode());
3764 EXPECT_NE(Store8
, nullptr);
3765 EXPECT_EQ(Store8
->getPointerOperand(), VVal
);
3766 EXPECT_EQ(Store8
->getValueOperand(), Sel2
);
3768 Builder
.CreateRetVoid();
3769 OMPBuilder
.finalize();
3770 EXPECT_FALSE(verifyModule(*M
, &errs()));
3773 /// Returns the single instruction of InstTy type in BB that uses the value V.
3774 /// If there is more than one such instruction, returns null.
3775 template <typename InstTy
>
3776 static InstTy
*findSingleUserInBlock(Value
*V
, BasicBlock
*BB
) {
3777 InstTy
*Result
= nullptr;
3778 for (User
*U
: V
->users()) {
3779 auto *Inst
= dyn_cast
<InstTy
>(U
);
3780 if (!Inst
|| Inst
->getParent() != BB
)
3789 /// Returns true if BB contains a simple binary reduction that loads a value
3790 /// from Accum, performs some binary operation with it, and stores it back to
3792 static bool isSimpleBinaryReduction(Value
*Accum
, BasicBlock
*BB
,
3793 Instruction::BinaryOps
*OpCode
= nullptr) {
3794 StoreInst
*Store
= findSingleUserInBlock
<StoreInst
>(Accum
, BB
);
3797 auto *Stored
= dyn_cast
<BinaryOperator
>(Store
->getOperand(0));
3800 if (OpCode
&& *OpCode
!= Stored
->getOpcode())
3802 auto *Load
= dyn_cast
<LoadInst
>(Stored
->getOperand(0));
3803 return Load
&& Load
->getOperand(0) == Accum
;
3806 /// Returns true if BB contains a binary reduction that reduces V using a binary
3807 /// operator into an accumulator that is a function argument.
3808 static bool isValueReducedToFuncArg(Value
*V
, BasicBlock
*BB
) {
3809 auto *ReductionOp
= findSingleUserInBlock
<BinaryOperator
>(V
, BB
);
3813 auto *GlobalLoad
= dyn_cast
<LoadInst
>(ReductionOp
->getOperand(0));
3817 auto *Store
= findSingleUserInBlock
<StoreInst
>(ReductionOp
, BB
);
3821 return Store
->getPointerOperand() == GlobalLoad
->getPointerOperand() &&
3822 isa
<Argument
>(findAggregateFromValue(GlobalLoad
->getPointerOperand()));
3825 /// Finds among users of Ptr a pair of GEP instructions with indices [0, 0] and
3826 /// [0, 1], respectively, and assigns results of these instructions to Zero and
3827 /// One. Returns true on success, false on failure or if such instructions are
3828 /// not unique among the users of Ptr.
3829 static bool findGEPZeroOne(Value
*Ptr
, Value
*&Zero
, Value
*&One
) {
3832 for (User
*U
: Ptr
->users()) {
3833 if (auto *GEP
= dyn_cast
<GetElementPtrInst
>(U
)) {
3834 if (GEP
->getNumIndices() != 2)
3836 auto *FirstIdx
= dyn_cast
<ConstantInt
>(GEP
->getOperand(1));
3837 auto *SecondIdx
= dyn_cast
<ConstantInt
>(GEP
->getOperand(2));
3838 EXPECT_NE(FirstIdx
, nullptr);
3839 EXPECT_NE(SecondIdx
, nullptr);
3841 EXPECT_TRUE(FirstIdx
->isZero());
3842 if (SecondIdx
->isZero()) {
3846 } else if (SecondIdx
->isOne()) {
3855 return Zero
!= nullptr && One
!= nullptr;
3858 static OpenMPIRBuilder::InsertPointTy
3859 sumReduction(OpenMPIRBuilder::InsertPointTy IP
, Value
*LHS
, Value
*RHS
,
3861 IRBuilder
<> Builder(IP
.getBlock(), IP
.getPoint());
3862 Result
= Builder
.CreateFAdd(LHS
, RHS
, "red.add");
3863 return Builder
.saveIP();
3866 static OpenMPIRBuilder::InsertPointTy
3867 sumAtomicReduction(OpenMPIRBuilder::InsertPointTy IP
, Type
*Ty
, Value
*LHS
,
3869 IRBuilder
<> Builder(IP
.getBlock(), IP
.getPoint());
3870 Value
*Partial
= Builder
.CreateLoad(Ty
, RHS
, "red.partial");
3871 Builder
.CreateAtomicRMW(AtomicRMWInst::FAdd
, LHS
, Partial
, None
,
3872 AtomicOrdering::Monotonic
);
3873 return Builder
.saveIP();
3876 static OpenMPIRBuilder::InsertPointTy
3877 xorReduction(OpenMPIRBuilder::InsertPointTy IP
, Value
*LHS
, Value
*RHS
,
3879 IRBuilder
<> Builder(IP
.getBlock(), IP
.getPoint());
3880 Result
= Builder
.CreateXor(LHS
, RHS
, "red.xor");
3881 return Builder
.saveIP();
3884 static OpenMPIRBuilder::InsertPointTy
3885 xorAtomicReduction(OpenMPIRBuilder::InsertPointTy IP
, Type
*Ty
, Value
*LHS
,
3887 IRBuilder
<> Builder(IP
.getBlock(), IP
.getPoint());
3888 Value
*Partial
= Builder
.CreateLoad(Ty
, RHS
, "red.partial");
3889 Builder
.CreateAtomicRMW(AtomicRMWInst::Xor
, LHS
, Partial
, None
,
3890 AtomicOrdering::Monotonic
);
3891 return Builder
.saveIP();
3894 TEST_F(OpenMPIRBuilderTest
, CreateReductions
) {
3895 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
3896 OpenMPIRBuilder
OMPBuilder(*M
);
3897 OMPBuilder
.initialize();
3899 IRBuilder
<> Builder(BB
);
3901 BasicBlock
*EnterBB
= BasicBlock::Create(Ctx
, "parallel.enter", F
);
3902 Builder
.CreateBr(EnterBB
);
3903 Builder
.SetInsertPoint(EnterBB
);
3904 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
3906 // Create variables to be reduced.
3907 InsertPointTy
OuterAllocaIP(&F
->getEntryBlock(),
3908 F
->getEntryBlock().getFirstInsertionPt());
3909 Type
*SumType
= Builder
.getFloatTy();
3910 Type
*XorType
= Builder
.getInt32Ty();
3914 IRBuilderBase::InsertPointGuard
Guard(Builder
);
3915 Builder
.restoreIP(OuterAllocaIP
);
3916 SumReduced
= Builder
.CreateAlloca(SumType
);
3917 XorReduced
= Builder
.CreateAlloca(XorType
);
3920 // Store initial values of reductions into global variables.
3921 Builder
.CreateStore(ConstantFP::get(Builder
.getFloatTy(), 0.0), SumReduced
);
3922 Builder
.CreateStore(Builder
.getInt32(1), XorReduced
);
3924 // The loop body computes two reductions:
3925 // sum of (float) thread-id;
3926 // xor of thread-id;
3927 // and store the result in global variables.
3928 InsertPointTy BodyIP
, BodyAllocaIP
;
3929 auto BodyGenCB
= [&](InsertPointTy InnerAllocaIP
, InsertPointTy CodeGenIP
) {
3930 IRBuilderBase::InsertPointGuard
Guard(Builder
);
3931 Builder
.restoreIP(CodeGenIP
);
3934 Constant
*SrcLocStr
= OMPBuilder
.getOrCreateSrcLocStr(Loc
, StrSize
);
3935 Value
*Ident
= OMPBuilder
.getOrCreateIdent(SrcLocStr
, StrSize
);
3936 Value
*TID
= OMPBuilder
.getOrCreateThreadID(Ident
);
3938 Builder
.CreateUIToFP(TID
, Builder
.getFloatTy(), "sum.local");
3939 Value
*SumPartial
= Builder
.CreateLoad(SumType
, SumReduced
, "sum.partial");
3940 Value
*XorPartial
= Builder
.CreateLoad(XorType
, XorReduced
, "xor.partial");
3941 Value
*Sum
= Builder
.CreateFAdd(SumPartial
, SumLocal
, "sum");
3942 Value
*Xor
= Builder
.CreateXor(XorPartial
, TID
, "xor");
3943 Builder
.CreateStore(Sum
, SumReduced
);
3944 Builder
.CreateStore(Xor
, XorReduced
);
3946 BodyIP
= Builder
.saveIP();
3947 BodyAllocaIP
= InnerAllocaIP
;
3950 // Privatization for reduction creates local copies of reduction variables and
3951 // initializes them to reduction-neutral values.
3952 Value
*SumPrivatized
;
3953 Value
*XorPrivatized
;
3954 auto PrivCB
= [&](InsertPointTy InnerAllocaIP
, InsertPointTy CodeGenIP
,
3955 Value
&Original
, Value
&Inner
, Value
*&ReplVal
) {
3956 IRBuilderBase::InsertPointGuard
Guard(Builder
);
3957 Builder
.restoreIP(InnerAllocaIP
);
3958 if (&Original
== SumReduced
) {
3959 SumPrivatized
= Builder
.CreateAlloca(Builder
.getFloatTy());
3960 ReplVal
= SumPrivatized
;
3961 } else if (&Original
== XorReduced
) {
3962 XorPrivatized
= Builder
.CreateAlloca(Builder
.getInt32Ty());
3963 ReplVal
= XorPrivatized
;
3969 Builder
.restoreIP(CodeGenIP
);
3970 if (&Original
== SumReduced
)
3971 Builder
.CreateStore(ConstantFP::get(Builder
.getFloatTy(), 0.0),
3973 else if (&Original
== XorReduced
)
3974 Builder
.CreateStore(Builder
.getInt32(0), XorPrivatized
);
3976 return Builder
.saveIP();
3979 // Do nothing in finalization.
3980 auto FiniCB
= [&](InsertPointTy CodeGenIP
) { return CodeGenIP
; };
3982 InsertPointTy AfterIP
=
3983 OMPBuilder
.createParallel(Loc
, OuterAllocaIP
, BodyGenCB
, PrivCB
, FiniCB
,
3984 /* IfCondition */ nullptr,
3985 /* NumThreads */ nullptr, OMP_PROC_BIND_default
,
3986 /* IsCancellable */ false);
3987 Builder
.restoreIP(AfterIP
);
3989 OpenMPIRBuilder::ReductionInfo ReductionInfos
[] = {
3990 {SumType
, SumReduced
, SumPrivatized
, sumReduction
, sumAtomicReduction
},
3991 {XorType
, XorReduced
, XorPrivatized
, xorReduction
, xorAtomicReduction
}};
3993 OMPBuilder
.createReductions(BodyIP
, BodyAllocaIP
, ReductionInfos
);
3995 Builder
.restoreIP(AfterIP
);
3996 Builder
.CreateRetVoid();
3998 OMPBuilder
.finalize(F
);
4000 // The IR must be valid.
4001 EXPECT_FALSE(verifyModule(*M
));
4003 // Outlining must have happened.
4004 SmallVector
<CallInst
*> ForkCalls
;
4005 findCalls(F
, omp::RuntimeFunction::OMPRTL___kmpc_fork_call
, OMPBuilder
,
4007 ASSERT_EQ(ForkCalls
.size(), 1u);
4008 Value
*CalleeVal
= cast
<Constant
>(ForkCalls
[0]->getOperand(2))->getOperand(0);
4009 Function
*Outlined
= dyn_cast
<Function
>(CalleeVal
);
4010 EXPECT_NE(Outlined
, nullptr);
4012 // Check that the lock variable was created with the expected name.
4013 GlobalVariable
*LockVar
=
4014 M
->getGlobalVariable(".gomp_critical_user_.reduction.var");
4015 EXPECT_NE(LockVar
, nullptr);
4017 // Find the allocation of a local array that will be used to call the runtime
4018 // reduciton function.
4019 BasicBlock
&AllocBlock
= Outlined
->getEntryBlock();
4020 Value
*LocalArray
= nullptr;
4021 for (Instruction
&I
: AllocBlock
) {
4022 if (AllocaInst
*Alloc
= dyn_cast
<AllocaInst
>(&I
)) {
4023 if (!Alloc
->getAllocatedType()->isArrayTy() ||
4024 !Alloc
->getAllocatedType()->getArrayElementType()->isPointerTy())
4030 ASSERT_NE(LocalArray
, nullptr);
4032 // Find the call to the runtime reduction function.
4033 BasicBlock
*BB
= AllocBlock
.getUniqueSuccessor();
4034 Value
*LocalArrayPtr
= nullptr;
4035 Value
*ReductionFnVal
= nullptr;
4036 Value
*SwitchArg
= nullptr;
4037 for (Instruction
&I
: *BB
) {
4038 if (CallInst
*Call
= dyn_cast
<CallInst
>(&I
)) {
4039 if (Call
->getCalledFunction() !=
4040 OMPBuilder
.getOrCreateRuntimeFunctionPtr(
4041 RuntimeFunction::OMPRTL___kmpc_reduce
))
4043 LocalArrayPtr
= Call
->getOperand(4);
4044 ReductionFnVal
= Call
->getOperand(5);
4050 // Check that the local array is passed to the function.
4051 ASSERT_NE(LocalArrayPtr
, nullptr);
4052 BitCastInst
*BitCast
= dyn_cast
<BitCastInst
>(LocalArrayPtr
);
4053 ASSERT_NE(BitCast
, nullptr);
4054 EXPECT_EQ(BitCast
->getOperand(0), LocalArray
);
4056 // Find the GEP instructions preceding stores to the local array.
4057 Value
*FirstArrayElemPtr
= nullptr;
4058 Value
*SecondArrayElemPtr
= nullptr;
4059 EXPECT_EQ(LocalArray
->getNumUses(), 3u);
4061 findGEPZeroOne(LocalArray
, FirstArrayElemPtr
, SecondArrayElemPtr
));
4063 // Check that the values stored into the local array are privatized reduction
4065 auto *FirstStored
= dyn_cast_or_null
<BitCastInst
>(
4066 findStoredValue
<GetElementPtrInst
>(FirstArrayElemPtr
));
4067 auto *SecondStored
= dyn_cast_or_null
<BitCastInst
>(
4068 findStoredValue
<GetElementPtrInst
>(SecondArrayElemPtr
));
4069 ASSERT_NE(FirstStored
, nullptr);
4070 ASSERT_NE(SecondStored
, nullptr);
4071 Value
*FirstPrivatized
= FirstStored
->getOperand(0);
4072 Value
*SecondPrivatized
= SecondStored
->getOperand(0);
4074 isSimpleBinaryReduction(FirstPrivatized
, FirstStored
->getParent()));
4076 isSimpleBinaryReduction(SecondPrivatized
, SecondStored
->getParent()));
4078 // Check that the result of the runtime reduction call is used for further
4080 ASSERT_EQ(SwitchArg
->getNumUses(), 1u);
4081 SwitchInst
*Switch
= dyn_cast
<SwitchInst
>(*SwitchArg
->user_begin());
4082 ASSERT_NE(Switch
, nullptr);
4083 EXPECT_EQ(Switch
->getNumSuccessors(), 3u);
4084 BasicBlock
*NonAtomicBB
= Switch
->case_begin()->getCaseSuccessor();
4085 BasicBlock
*AtomicBB
= std::next(Switch
->case_begin())->getCaseSuccessor();
4087 // Non-atomic block contains reductions to the global reduction variable,
4088 // which is passed into the outlined function as an argument.
4090 findSingleUserInBlock
<LoadInst
>(FirstPrivatized
, NonAtomicBB
);
4092 findSingleUserInBlock
<LoadInst
>(SecondPrivatized
, NonAtomicBB
);
4093 EXPECT_TRUE(isValueReducedToFuncArg(FirstLoad
, NonAtomicBB
));
4094 EXPECT_TRUE(isValueReducedToFuncArg(SecondLoad
, NonAtomicBB
));
4096 // Atomic block also constains reductions to the global reduction variable.
4097 FirstLoad
= findSingleUserInBlock
<LoadInst
>(FirstPrivatized
, AtomicBB
);
4098 SecondLoad
= findSingleUserInBlock
<LoadInst
>(SecondPrivatized
, AtomicBB
);
4099 auto *FirstAtomic
= findSingleUserInBlock
<AtomicRMWInst
>(FirstLoad
, AtomicBB
);
4100 auto *SecondAtomic
=
4101 findSingleUserInBlock
<AtomicRMWInst
>(SecondLoad
, AtomicBB
);
4102 ASSERT_NE(FirstAtomic
, nullptr);
4103 Value
*AtomicStorePointer
= FirstAtomic
->getPointerOperand();
4104 EXPECT_TRUE(isa
<Argument
>(findAggregateFromValue(AtomicStorePointer
)));
4105 ASSERT_NE(SecondAtomic
, nullptr);
4106 AtomicStorePointer
= SecondAtomic
->getPointerOperand();
4107 EXPECT_TRUE(isa
<Argument
>(findAggregateFromValue(AtomicStorePointer
)));
4109 // Check that the separate reduction function also performs (non-atomic)
4110 // reductions after extracting reduction variables from its arguments.
4111 Function
*ReductionFn
= cast
<Function
>(ReductionFnVal
);
4112 BasicBlock
*FnReductionBB
= &ReductionFn
->getEntryBlock();
4114 findSingleUserInBlock
<BitCastInst
>(ReductionFn
->getArg(0), FnReductionBB
);
4116 Value
*SecondLHSPtr
;
4117 ASSERT_TRUE(findGEPZeroOne(Bitcast
, FirstLHSPtr
, SecondLHSPtr
));
4118 Value
*Opaque
= findSingleUserInBlock
<LoadInst
>(FirstLHSPtr
, FnReductionBB
);
4119 ASSERT_NE(Opaque
, nullptr);
4120 Bitcast
= findSingleUserInBlock
<BitCastInst
>(Opaque
, FnReductionBB
);
4121 ASSERT_NE(Bitcast
, nullptr);
4122 EXPECT_TRUE(isSimpleBinaryReduction(Bitcast
, FnReductionBB
));
4123 Opaque
= findSingleUserInBlock
<LoadInst
>(SecondLHSPtr
, FnReductionBB
);
4124 ASSERT_NE(Opaque
, nullptr);
4125 Bitcast
= findSingleUserInBlock
<BitCastInst
>(Opaque
, FnReductionBB
);
4126 ASSERT_NE(Bitcast
, nullptr);
4127 EXPECT_TRUE(isSimpleBinaryReduction(Bitcast
, FnReductionBB
));
4130 findSingleUserInBlock
<BitCastInst
>(ReductionFn
->getArg(1), FnReductionBB
);
4133 EXPECT_TRUE(findGEPZeroOne(Bitcast
, FirstRHS
, SecondRHS
));
4136 TEST_F(OpenMPIRBuilderTest
, CreateTwoReductions
) {
4137 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
4138 OpenMPIRBuilder
OMPBuilder(*M
);
4139 OMPBuilder
.initialize();
4141 IRBuilder
<> Builder(BB
);
4143 BasicBlock
*EnterBB
= BasicBlock::Create(Ctx
, "parallel.enter", F
);
4144 Builder
.CreateBr(EnterBB
);
4145 Builder
.SetInsertPoint(EnterBB
);
4146 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
4148 // Create variables to be reduced.
4149 InsertPointTy
OuterAllocaIP(&F
->getEntryBlock(),
4150 F
->getEntryBlock().getFirstInsertionPt());
4151 Type
*SumType
= Builder
.getFloatTy();
4152 Type
*XorType
= Builder
.getInt32Ty();
4156 IRBuilderBase::InsertPointGuard
Guard(Builder
);
4157 Builder
.restoreIP(OuterAllocaIP
);
4158 SumReduced
= Builder
.CreateAlloca(SumType
);
4159 XorReduced
= Builder
.CreateAlloca(XorType
);
4162 // Store initial values of reductions into global variables.
4163 Builder
.CreateStore(ConstantFP::get(Builder
.getFloatTy(), 0.0), SumReduced
);
4164 Builder
.CreateStore(Builder
.getInt32(1), XorReduced
);
4166 InsertPointTy FirstBodyIP
, FirstBodyAllocaIP
;
4167 auto FirstBodyGenCB
= [&](InsertPointTy InnerAllocaIP
,
4168 InsertPointTy CodeGenIP
) {
4169 IRBuilderBase::InsertPointGuard
Guard(Builder
);
4170 Builder
.restoreIP(CodeGenIP
);
4173 Constant
*SrcLocStr
= OMPBuilder
.getOrCreateSrcLocStr(Loc
, StrSize
);
4174 Value
*Ident
= OMPBuilder
.getOrCreateIdent(SrcLocStr
, StrSize
);
4175 Value
*TID
= OMPBuilder
.getOrCreateThreadID(Ident
);
4177 Builder
.CreateUIToFP(TID
, Builder
.getFloatTy(), "sum.local");
4178 Value
*SumPartial
= Builder
.CreateLoad(SumType
, SumReduced
, "sum.partial");
4179 Value
*Sum
= Builder
.CreateFAdd(SumPartial
, SumLocal
, "sum");
4180 Builder
.CreateStore(Sum
, SumReduced
);
4182 FirstBodyIP
= Builder
.saveIP();
4183 FirstBodyAllocaIP
= InnerAllocaIP
;
4186 InsertPointTy SecondBodyIP
, SecondBodyAllocaIP
;
4187 auto SecondBodyGenCB
= [&](InsertPointTy InnerAllocaIP
,
4188 InsertPointTy CodeGenIP
) {
4189 IRBuilderBase::InsertPointGuard
Guard(Builder
);
4190 Builder
.restoreIP(CodeGenIP
);
4193 Constant
*SrcLocStr
= OMPBuilder
.getOrCreateSrcLocStr(Loc
, StrSize
);
4194 Value
*Ident
= OMPBuilder
.getOrCreateIdent(SrcLocStr
, StrSize
);
4195 Value
*TID
= OMPBuilder
.getOrCreateThreadID(Ident
);
4196 Value
*XorPartial
= Builder
.CreateLoad(XorType
, XorReduced
, "xor.partial");
4197 Value
*Xor
= Builder
.CreateXor(XorPartial
, TID
, "xor");
4198 Builder
.CreateStore(Xor
, XorReduced
);
4200 SecondBodyIP
= Builder
.saveIP();
4201 SecondBodyAllocaIP
= InnerAllocaIP
;
4204 // Privatization for reduction creates local copies of reduction variables and
4205 // initializes them to reduction-neutral values. The same privatization
4206 // callback is used for both loops, with dispatch based on the value being
4208 Value
*SumPrivatized
;
4209 Value
*XorPrivatized
;
4210 auto PrivCB
= [&](InsertPointTy InnerAllocaIP
, InsertPointTy CodeGenIP
,
4211 Value
&Original
, Value
&Inner
, Value
*&ReplVal
) {
4212 IRBuilderBase::InsertPointGuard
Guard(Builder
);
4213 Builder
.restoreIP(InnerAllocaIP
);
4214 if (&Original
== SumReduced
) {
4215 SumPrivatized
= Builder
.CreateAlloca(Builder
.getFloatTy());
4216 ReplVal
= SumPrivatized
;
4217 } else if (&Original
== XorReduced
) {
4218 XorPrivatized
= Builder
.CreateAlloca(Builder
.getInt32Ty());
4219 ReplVal
= XorPrivatized
;
4225 Builder
.restoreIP(CodeGenIP
);
4226 if (&Original
== SumReduced
)
4227 Builder
.CreateStore(ConstantFP::get(Builder
.getFloatTy(), 0.0),
4229 else if (&Original
== XorReduced
)
4230 Builder
.CreateStore(Builder
.getInt32(0), XorPrivatized
);
4232 return Builder
.saveIP();
4235 // Do nothing in finalization.
4236 auto FiniCB
= [&](InsertPointTy CodeGenIP
) { return CodeGenIP
; };
4239 OMPBuilder
.createParallel(Loc
, OuterAllocaIP
, FirstBodyGenCB
, PrivCB
,
4240 FiniCB
, /* IfCondition */ nullptr,
4241 /* NumThreads */ nullptr, OMP_PROC_BIND_default
,
4242 /* IsCancellable */ false));
4243 InsertPointTy AfterIP
= OMPBuilder
.createParallel(
4244 {Builder
.saveIP(), DL
}, OuterAllocaIP
, SecondBodyGenCB
, PrivCB
, FiniCB
,
4245 /* IfCondition */ nullptr,
4246 /* NumThreads */ nullptr, OMP_PROC_BIND_default
,
4247 /* IsCancellable */ false);
4249 OMPBuilder
.createReductions(
4250 FirstBodyIP
, FirstBodyAllocaIP
,
4251 {{SumType
, SumReduced
, SumPrivatized
, sumReduction
, sumAtomicReduction
}});
4252 OMPBuilder
.createReductions(
4253 SecondBodyIP
, SecondBodyAllocaIP
,
4254 {{XorType
, XorReduced
, XorPrivatized
, xorReduction
, xorAtomicReduction
}});
4256 Builder
.restoreIP(AfterIP
);
4257 Builder
.CreateRetVoid();
4259 OMPBuilder
.finalize(F
);
4261 // The IR must be valid.
4262 EXPECT_FALSE(verifyModule(*M
));
4264 // Two different outlined functions must have been created.
4265 SmallVector
<CallInst
*> ForkCalls
;
4266 findCalls(F
, omp::RuntimeFunction::OMPRTL___kmpc_fork_call
, OMPBuilder
,
4268 ASSERT_EQ(ForkCalls
.size(), 2u);
4269 Value
*CalleeVal
= cast
<Constant
>(ForkCalls
[0]->getOperand(2))->getOperand(0);
4270 Function
*FirstCallee
= cast
<Function
>(CalleeVal
);
4271 CalleeVal
= cast
<Constant
>(ForkCalls
[1]->getOperand(2))->getOperand(0);
4272 Function
*SecondCallee
= cast
<Function
>(CalleeVal
);
4273 EXPECT_NE(FirstCallee
, SecondCallee
);
4275 // Two different reduction functions must have been created.
4276 SmallVector
<CallInst
*> ReduceCalls
;
4277 findCalls(FirstCallee
, omp::RuntimeFunction::OMPRTL___kmpc_reduce
, OMPBuilder
,
4279 ASSERT_EQ(ReduceCalls
.size(), 1u);
4280 auto *AddReduction
= cast
<Function
>(ReduceCalls
[0]->getOperand(5));
4281 ReduceCalls
.clear();
4282 findCalls(SecondCallee
, omp::RuntimeFunction::OMPRTL___kmpc_reduce
,
4283 OMPBuilder
, ReduceCalls
);
4284 auto *XorReduction
= cast
<Function
>(ReduceCalls
[0]->getOperand(5));
4285 EXPECT_NE(AddReduction
, XorReduction
);
4287 // Each reduction function does its own kind of reduction.
4288 BasicBlock
*FnReductionBB
= &AddReduction
->getEntryBlock();
4289 auto *Bitcast
= findSingleUserInBlock
<BitCastInst
>(AddReduction
->getArg(0),
4291 ASSERT_NE(Bitcast
, nullptr);
4292 Value
*FirstLHSPtr
=
4293 findSingleUserInBlock
<GetElementPtrInst
>(Bitcast
, FnReductionBB
);
4294 ASSERT_NE(FirstLHSPtr
, nullptr);
4295 Value
*Opaque
= findSingleUserInBlock
<LoadInst
>(FirstLHSPtr
, FnReductionBB
);
4296 ASSERT_NE(Opaque
, nullptr);
4297 Bitcast
= findSingleUserInBlock
<BitCastInst
>(Opaque
, FnReductionBB
);
4298 ASSERT_NE(Bitcast
, nullptr);
4299 Instruction::BinaryOps Opcode
= Instruction::FAdd
;
4300 EXPECT_TRUE(isSimpleBinaryReduction(Bitcast
, FnReductionBB
, &Opcode
));
4302 FnReductionBB
= &XorReduction
->getEntryBlock();
4303 Bitcast
= findSingleUserInBlock
<BitCastInst
>(XorReduction
->getArg(0),
4305 ASSERT_NE(Bitcast
, nullptr);
4306 Value
*SecondLHSPtr
=
4307 findSingleUserInBlock
<GetElementPtrInst
>(Bitcast
, FnReductionBB
);
4308 ASSERT_NE(FirstLHSPtr
, nullptr);
4309 Opaque
= findSingleUserInBlock
<LoadInst
>(SecondLHSPtr
, FnReductionBB
);
4310 ASSERT_NE(Opaque
, nullptr);
4311 Bitcast
= findSingleUserInBlock
<BitCastInst
>(Opaque
, FnReductionBB
);
4312 ASSERT_NE(Bitcast
, nullptr);
4313 Opcode
= Instruction::Xor
;
4314 EXPECT_TRUE(isSimpleBinaryReduction(Bitcast
, FnReductionBB
, &Opcode
));
4317 TEST_F(OpenMPIRBuilderTest
, CreateSectionsSimple
) {
4318 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
4319 using BodyGenCallbackTy
= llvm::OpenMPIRBuilder::StorableBodyGenCallbackTy
;
4320 OpenMPIRBuilder
OMPBuilder(*M
);
4321 OMPBuilder
.initialize();
4323 IRBuilder
<> Builder(BB
);
4325 BasicBlock
*EnterBB
= BasicBlock::Create(Ctx
, "sections.enter", F
);
4326 Builder
.CreateBr(EnterBB
);
4327 Builder
.SetInsertPoint(EnterBB
);
4328 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
4330 llvm::SmallVector
<BodyGenCallbackTy
, 4> SectionCBVector
;
4331 llvm::SmallVector
<BasicBlock
*, 4> CaseBBs
;
4333 auto FiniCB
= [&](InsertPointTy IP
) {};
4334 auto SectionCB
= [&](InsertPointTy AllocaIP
, InsertPointTy CodeGenIP
) {};
4335 SectionCBVector
.push_back(SectionCB
);
4337 auto PrivCB
= [](InsertPointTy AllocaIP
, InsertPointTy CodeGenIP
,
4338 llvm::Value
&, llvm::Value
&Val
,
4339 llvm::Value
*&ReplVal
) { return CodeGenIP
; };
4340 IRBuilder
<>::InsertPoint
AllocaIP(&F
->getEntryBlock(),
4341 F
->getEntryBlock().getFirstInsertionPt());
4342 Builder
.restoreIP(OMPBuilder
.createSections(Loc
, AllocaIP
, SectionCBVector
,
4343 PrivCB
, FiniCB
, false, false));
4344 Builder
.CreateRetVoid(); // Required at the end of the function
4345 EXPECT_NE(F
->getEntryBlock().getTerminator(), nullptr);
4346 EXPECT_FALSE(verifyModule(*M
, &errs()));
4349 TEST_F(OpenMPIRBuilderTest
, CreateSections
) {
4350 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
4351 using BodyGenCallbackTy
= llvm::OpenMPIRBuilder::StorableBodyGenCallbackTy
;
4352 OpenMPIRBuilder
OMPBuilder(*M
);
4353 OMPBuilder
.initialize();
4355 IRBuilder
<> Builder(BB
);
4357 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
4358 llvm::SmallVector
<BodyGenCallbackTy
, 4> SectionCBVector
;
4359 llvm::SmallVector
<BasicBlock
*, 4> CaseBBs
;
4361 BasicBlock
*SwitchBB
= nullptr;
4362 AllocaInst
*PrivAI
= nullptr;
4363 SwitchInst
*Switch
= nullptr;
4365 unsigned NumBodiesGenerated
= 0;
4366 unsigned NumFiniCBCalls
= 0;
4367 PrivAI
= Builder
.CreateAlloca(F
->arg_begin()->getType());
4369 auto FiniCB
= [&](InsertPointTy IP
) {
4371 BasicBlock
*IPBB
= IP
.getBlock();
4372 EXPECT_NE(IPBB
->end(), IP
.getPoint());
4375 auto SectionCB
= [&](InsertPointTy AllocaIP
, InsertPointTy CodeGenIP
) {
4376 ++NumBodiesGenerated
;
4377 CaseBBs
.push_back(CodeGenIP
.getBlock());
4378 SwitchBB
= CodeGenIP
.getBlock()->getSinglePredecessor();
4379 Builder
.restoreIP(CodeGenIP
);
4380 Builder
.CreateStore(F
->arg_begin(), PrivAI
);
4382 Builder
.CreateLoad(F
->arg_begin()->getType(), PrivAI
, "local.alloca");
4383 Builder
.CreateICmpNE(F
->arg_begin(), PrivLoad
);
4385 auto PrivCB
= [](InsertPointTy AllocaIP
, InsertPointTy CodeGenIP
,
4386 llvm::Value
&, llvm::Value
&Val
, llvm::Value
*&ReplVal
) {
4387 // TODO: Privatization not implemented yet
4391 SectionCBVector
.push_back(SectionCB
);
4392 SectionCBVector
.push_back(SectionCB
);
4394 IRBuilder
<>::InsertPoint
AllocaIP(&F
->getEntryBlock(),
4395 F
->getEntryBlock().getFirstInsertionPt());
4396 Builder
.restoreIP(OMPBuilder
.createSections(Loc
, AllocaIP
, SectionCBVector
,
4397 PrivCB
, FiniCB
, false, false));
4398 Builder
.CreateRetVoid(); // Required at the end of the function
4400 // Switch BB's predecessor is loop condition BB, whose successor at index 1 is
4402 BasicBlock
*ForExitBB
=
4403 SwitchBB
->getSinglePredecessor()->getTerminator()->getSuccessor(1);
4404 EXPECT_NE(ForExitBB
, nullptr);
4406 EXPECT_NE(PrivAI
, nullptr);
4407 Function
*OutlinedFn
= PrivAI
->getFunction();
4408 EXPECT_EQ(F
, OutlinedFn
);
4409 EXPECT_FALSE(verifyModule(*M
, &errs()));
4410 EXPECT_EQ(OutlinedFn
->arg_size(), 1U);
4412 BasicBlock
*LoopPreheaderBB
=
4413 OutlinedFn
->getEntryBlock().getSingleSuccessor();
4414 // loop variables are 5 - lower bound, upper bound, stride, islastiter, and
4416 bool FoundForInit
= false;
4417 for (Instruction
&Inst
: *LoopPreheaderBB
) {
4418 if (isa
<CallInst
>(Inst
)) {
4419 if (cast
<CallInst
>(&Inst
)->getCalledFunction()->getName() ==
4420 "__kmpc_for_static_init_4u") {
4421 FoundForInit
= true;
4425 EXPECT_EQ(FoundForInit
, true);
4427 bool FoundForExit
= false;
4428 bool FoundBarrier
= false;
4429 for (Instruction
&Inst
: *ForExitBB
) {
4430 if (isa
<CallInst
>(Inst
)) {
4431 if (cast
<CallInst
>(&Inst
)->getCalledFunction()->getName() ==
4432 "__kmpc_for_static_fini") {
4433 FoundForExit
= true;
4435 if (cast
<CallInst
>(&Inst
)->getCalledFunction()->getName() ==
4437 FoundBarrier
= true;
4439 if (FoundForExit
&& FoundBarrier
)
4443 EXPECT_EQ(FoundForExit
, true);
4444 EXPECT_EQ(FoundBarrier
, true);
4446 EXPECT_NE(SwitchBB
, nullptr);
4447 EXPECT_NE(SwitchBB
->getTerminator(), nullptr);
4448 EXPECT_EQ(isa
<SwitchInst
>(SwitchBB
->getTerminator()), true);
4449 Switch
= cast
<SwitchInst
>(SwitchBB
->getTerminator());
4450 EXPECT_EQ(Switch
->getNumCases(), 2U);
4452 EXPECT_EQ(CaseBBs
.size(), 2U);
4453 for (auto *&CaseBB
: CaseBBs
) {
4454 EXPECT_EQ(CaseBB
->getParent(), OutlinedFn
);
4457 ASSERT_EQ(NumBodiesGenerated
, 2U);
4458 ASSERT_EQ(NumFiniCBCalls
, 1U);
4459 EXPECT_FALSE(verifyModule(*M
, &errs()));
4462 TEST_F(OpenMPIRBuilderTest
, CreateSectionsNoWait
) {
4463 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
4464 using BodyGenCallbackTy
= llvm::OpenMPIRBuilder::StorableBodyGenCallbackTy
;
4465 OpenMPIRBuilder
OMPBuilder(*M
);
4466 OMPBuilder
.initialize();
4468 IRBuilder
<> Builder(BB
);
4470 BasicBlock
*EnterBB
= BasicBlock::Create(Ctx
, "sections.enter", F
);
4471 Builder
.CreateBr(EnterBB
);
4472 Builder
.SetInsertPoint(EnterBB
);
4473 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
4475 IRBuilder
<>::InsertPoint
AllocaIP(&F
->getEntryBlock(),
4476 F
->getEntryBlock().getFirstInsertionPt());
4477 llvm::SmallVector
<BodyGenCallbackTy
, 4> SectionCBVector
;
4478 auto PrivCB
= [](InsertPointTy AllocaIP
, InsertPointTy CodeGenIP
,
4479 llvm::Value
&, llvm::Value
&Val
,
4480 llvm::Value
*&ReplVal
) { return CodeGenIP
; };
4481 auto FiniCB
= [&](InsertPointTy IP
) {};
4483 Builder
.restoreIP(OMPBuilder
.createSections(Loc
, AllocaIP
, SectionCBVector
,
4484 PrivCB
, FiniCB
, false, true));
4485 Builder
.CreateRetVoid(); // Required at the end of the function
4486 for (auto &Inst
: instructions(*F
)) {
4487 EXPECT_FALSE(isa
<CallInst
>(Inst
) &&
4488 cast
<CallInst
>(&Inst
)->getCalledFunction()->getName() ==
4490 "call to function __kmpc_barrier found with nowait");
4494 TEST_F(OpenMPIRBuilderTest
, CreateOffloadMaptypes
) {
4495 OpenMPIRBuilder
OMPBuilder(*M
);
4496 OMPBuilder
.initialize();
4498 IRBuilder
<> Builder(BB
);
4500 SmallVector
<uint64_t> Mappings
= {0, 1};
4501 GlobalVariable
*OffloadMaptypesGlobal
=
4502 OMPBuilder
.createOffloadMaptypes(Mappings
, "offload_maptypes");
4503 EXPECT_FALSE(M
->global_empty());
4504 EXPECT_EQ(OffloadMaptypesGlobal
->getName(), "offload_maptypes");
4505 EXPECT_TRUE(OffloadMaptypesGlobal
->isConstant());
4506 EXPECT_TRUE(OffloadMaptypesGlobal
->hasGlobalUnnamedAddr());
4507 EXPECT_TRUE(OffloadMaptypesGlobal
->hasPrivateLinkage());
4508 EXPECT_TRUE(OffloadMaptypesGlobal
->hasInitializer());
4509 Constant
*Initializer
= OffloadMaptypesGlobal
->getInitializer();
4510 EXPECT_TRUE(isa
<ConstantDataArray
>(Initializer
));
4511 ConstantDataArray
*MappingInit
= dyn_cast
<ConstantDataArray
>(Initializer
);
4512 EXPECT_EQ(MappingInit
->getNumElements(), Mappings
.size());
4513 EXPECT_TRUE(MappingInit
->getType()->getElementType()->isIntegerTy(64));
4514 Constant
*CA
= ConstantDataArray::get(Builder
.getContext(), Mappings
);
4515 EXPECT_EQ(MappingInit
, CA
);
4518 TEST_F(OpenMPIRBuilderTest
, CreateOffloadMapnames
) {
4519 OpenMPIRBuilder
OMPBuilder(*M
);
4520 OMPBuilder
.initialize();
4522 IRBuilder
<> Builder(BB
);
4526 OMPBuilder
.getOrCreateSrcLocStr("array1", "file1", 2, 5, StrSize
);
4528 OMPBuilder
.getOrCreateSrcLocStr("array2", "file1", 3, 5, StrSize
);
4529 SmallVector
<llvm::Constant
*> Names
= {Cst1
, Cst2
};
4531 GlobalVariable
*OffloadMaptypesGlobal
=
4532 OMPBuilder
.createOffloadMapnames(Names
, "offload_mapnames");
4533 EXPECT_FALSE(M
->global_empty());
4534 EXPECT_EQ(OffloadMaptypesGlobal
->getName(), "offload_mapnames");
4535 EXPECT_TRUE(OffloadMaptypesGlobal
->isConstant());
4536 EXPECT_FALSE(OffloadMaptypesGlobal
->hasGlobalUnnamedAddr());
4537 EXPECT_TRUE(OffloadMaptypesGlobal
->hasPrivateLinkage());
4538 EXPECT_TRUE(OffloadMaptypesGlobal
->hasInitializer());
4539 Constant
*Initializer
= OffloadMaptypesGlobal
->getInitializer();
4540 EXPECT_TRUE(isa
<Constant
>(Initializer
->getOperand(0)->stripPointerCasts()));
4541 EXPECT_TRUE(isa
<Constant
>(Initializer
->getOperand(1)->stripPointerCasts()));
4543 GlobalVariable
*Name1Gbl
=
4544 cast
<GlobalVariable
>(Initializer
->getOperand(0)->stripPointerCasts());
4545 EXPECT_TRUE(isa
<ConstantDataArray
>(Name1Gbl
->getInitializer()));
4546 ConstantDataArray
*Name1GblCA
=
4547 dyn_cast
<ConstantDataArray
>(Name1Gbl
->getInitializer());
4548 EXPECT_EQ(Name1GblCA
->getAsCString(), ";file1;array1;2;5;;");
4550 GlobalVariable
*Name2Gbl
=
4551 cast
<GlobalVariable
>(Initializer
->getOperand(1)->stripPointerCasts());
4552 EXPECT_TRUE(isa
<ConstantDataArray
>(Name2Gbl
->getInitializer()));
4553 ConstantDataArray
*Name2GblCA
=
4554 dyn_cast
<ConstantDataArray
>(Name2Gbl
->getInitializer());
4555 EXPECT_EQ(Name2GblCA
->getAsCString(), ";file1;array2;3;5;;");
4557 EXPECT_TRUE(Initializer
->getType()->getArrayElementType()->isPointerTy());
4558 EXPECT_EQ(Initializer
->getType()->getArrayNumElements(), Names
.size());
4561 TEST_F(OpenMPIRBuilderTest
, CreateMapperAllocas
) {
4562 OpenMPIRBuilder
OMPBuilder(*M
);
4563 OMPBuilder
.initialize();
4565 IRBuilder
<> Builder(BB
);
4567 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
4569 unsigned TotalNbOperand
= 2;
4571 OpenMPIRBuilder::MapperAllocas MapperAllocas
;
4572 IRBuilder
<>::InsertPoint
AllocaIP(&F
->getEntryBlock(),
4573 F
->getEntryBlock().getFirstInsertionPt());
4574 OMPBuilder
.createMapperAllocas(Loc
, AllocaIP
, TotalNbOperand
, MapperAllocas
);
4575 EXPECT_NE(MapperAllocas
.ArgsBase
, nullptr);
4576 EXPECT_NE(MapperAllocas
.Args
, nullptr);
4577 EXPECT_NE(MapperAllocas
.ArgSizes
, nullptr);
4578 EXPECT_TRUE(MapperAllocas
.ArgsBase
->getAllocatedType()->isArrayTy());
4579 ArrayType
*ArrType
=
4580 dyn_cast
<ArrayType
>(MapperAllocas
.ArgsBase
->getAllocatedType());
4581 EXPECT_EQ(ArrType
->getNumElements(), TotalNbOperand
);
4582 EXPECT_TRUE(MapperAllocas
.ArgsBase
->getAllocatedType()
4583 ->getArrayElementType()
4587 MapperAllocas
.ArgsBase
->getAllocatedType()->getArrayElementType())
4588 ->isOpaqueOrPointeeTypeMatches(Builder
.getInt8Ty()));
4590 EXPECT_TRUE(MapperAllocas
.Args
->getAllocatedType()->isArrayTy());
4591 ArrType
= dyn_cast
<ArrayType
>(MapperAllocas
.Args
->getAllocatedType());
4592 EXPECT_EQ(ArrType
->getNumElements(), TotalNbOperand
);
4593 EXPECT_TRUE(MapperAllocas
.Args
->getAllocatedType()
4594 ->getArrayElementType()
4596 EXPECT_TRUE(cast
<PointerType
>(
4597 MapperAllocas
.Args
->getAllocatedType()->getArrayElementType())
4598 ->isOpaqueOrPointeeTypeMatches(Builder
.getInt8Ty()));
4600 EXPECT_TRUE(MapperAllocas
.ArgSizes
->getAllocatedType()->isArrayTy());
4601 ArrType
= dyn_cast
<ArrayType
>(MapperAllocas
.ArgSizes
->getAllocatedType());
4602 EXPECT_EQ(ArrType
->getNumElements(), TotalNbOperand
);
4603 EXPECT_TRUE(MapperAllocas
.ArgSizes
->getAllocatedType()
4604 ->getArrayElementType()
4608 TEST_F(OpenMPIRBuilderTest
, EmitMapperCall
) {
4609 OpenMPIRBuilder
OMPBuilder(*M
);
4610 OMPBuilder
.initialize();
4612 IRBuilder
<> Builder(BB
);
4613 LLVMContext
&Ctx
= M
->getContext();
4615 OpenMPIRBuilder::LocationDescription
Loc({Builder
.saveIP(), DL
});
4617 unsigned TotalNbOperand
= 2;
4619 OpenMPIRBuilder::MapperAllocas MapperAllocas
;
4620 IRBuilder
<>::InsertPoint
AllocaIP(&F
->getEntryBlock(),
4621 F
->getEntryBlock().getFirstInsertionPt());
4622 OMPBuilder
.createMapperAllocas(Loc
, AllocaIP
, TotalNbOperand
, MapperAllocas
);
4624 auto *BeginMapperFunc
= OMPBuilder
.getOrCreateRuntimeFunctionPtr(
4625 omp::OMPRTL___tgt_target_data_begin_mapper
);
4627 SmallVector
<uint64_t> Flags
= {0, 2};
4630 Constant
*SrcLocCst
=
4631 OMPBuilder
.getOrCreateSrcLocStr("", "file1", 2, 5, StrSize
);
4632 Value
*SrcLocInfo
= OMPBuilder
.getOrCreateIdent(SrcLocCst
, StrSize
);
4635 OMPBuilder
.getOrCreateSrcLocStr("array1", "file1", 2, 5, StrSize
);
4637 OMPBuilder
.getOrCreateSrcLocStr("array2", "file1", 3, 5, StrSize
);
4638 SmallVector
<llvm::Constant
*> Names
= {Cst1
, Cst2
};
4640 GlobalVariable
*Maptypes
=
4641 OMPBuilder
.createOffloadMaptypes(Flags
, ".offload_maptypes");
4642 Value
*MaptypesArg
= Builder
.CreateConstInBoundsGEP2_32(
4643 ArrayType::get(Type::getInt64Ty(Ctx
), TotalNbOperand
), Maptypes
,
4644 /*Idx0=*/0, /*Idx1=*/0);
4646 GlobalVariable
*Mapnames
=
4647 OMPBuilder
.createOffloadMapnames(Names
, ".offload_mapnames");
4648 Value
*MapnamesArg
= Builder
.CreateConstInBoundsGEP2_32(
4649 ArrayType::get(Type::getInt8PtrTy(Ctx
), TotalNbOperand
), Mapnames
,
4650 /*Idx0=*/0, /*Idx1=*/0);
4652 OMPBuilder
.emitMapperCall(Builder
.saveIP(), BeginMapperFunc
, SrcLocInfo
,
4653 MaptypesArg
, MapnamesArg
, MapperAllocas
, -1,
4656 CallInst
*MapperCall
= dyn_cast
<CallInst
>(&BB
->back());
4657 EXPECT_NE(MapperCall
, nullptr);
4658 EXPECT_EQ(MapperCall
->arg_size(), 9U);
4659 EXPECT_EQ(MapperCall
->getCalledFunction()->getName(),
4660 "__tgt_target_data_begin_mapper");
4661 EXPECT_EQ(MapperCall
->getOperand(0), SrcLocInfo
);
4662 EXPECT_TRUE(MapperCall
->getOperand(1)->getType()->isIntegerTy(64));
4663 EXPECT_TRUE(MapperCall
->getOperand(2)->getType()->isIntegerTy(32));
4665 EXPECT_EQ(MapperCall
->getOperand(6), MaptypesArg
);
4666 EXPECT_EQ(MapperCall
->getOperand(7), MapnamesArg
);
4667 EXPECT_TRUE(MapperCall
->getOperand(8)->getType()->isPointerTy());
4670 TEST_F(OpenMPIRBuilderTest
, CreateTask
) {
4671 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
4672 OpenMPIRBuilder
OMPBuilder(*M
);
4673 OMPBuilder
.initialize();
4675 IRBuilder
<> Builder(BB
);
4677 AllocaInst
*ValPtr32
= Builder
.CreateAlloca(Builder
.getInt32Ty());
4678 AllocaInst
*ValPtr128
= Builder
.CreateAlloca(Builder
.getInt128Ty());
4680 Builder
.CreateLoad(Builder
.getInt128Ty(), ValPtr128
, "bodygen.load");
4682 auto BodyGenCB
= [&](InsertPointTy AllocaIP
, InsertPointTy CodeGenIP
) {
4683 Builder
.restoreIP(AllocaIP
);
4684 AllocaInst
*Local128
= Builder
.CreateAlloca(Builder
.getInt128Ty(), nullptr,
4685 "bodygen.alloca128");
4687 Builder
.restoreIP(CodeGenIP
);
4688 // Loading and storing captured pointer and values
4689 Builder
.CreateStore(Val128
, Local128
);
4690 Value
*Val32
= Builder
.CreateLoad(ValPtr32
->getAllocatedType(), ValPtr32
,
4693 LoadInst
*PrivLoad128
= Builder
.CreateLoad(
4694 Local128
->getAllocatedType(), Local128
, "bodygen.local.load128");
4695 Value
*Cmp
= Builder
.CreateICmpNE(
4696 Val32
, Builder
.CreateTrunc(PrivLoad128
, Val32
->getType()));
4697 Instruction
*ThenTerm
, *ElseTerm
;
4698 SplitBlockAndInsertIfThenElse(Cmp
, CodeGenIP
.getBlock()->getTerminator(),
4699 &ThenTerm
, &ElseTerm
);
4702 BasicBlock
*AllocaBB
= Builder
.GetInsertBlock();
4703 BasicBlock
*BodyBB
= splitBB(Builder
, /*CreateBranch=*/true, "alloca.split");
4704 OpenMPIRBuilder::LocationDescription
Loc(
4705 InsertPointTy(BodyBB
, BodyBB
->getFirstInsertionPt()), DL
);
4706 Builder
.restoreIP(OMPBuilder
.createTask(
4707 Loc
, InsertPointTy(AllocaBB
, AllocaBB
->getFirstInsertionPt()),
4709 OMPBuilder
.finalize();
4710 Builder
.CreateRetVoid();
4712 EXPECT_FALSE(verifyModule(*M
, &errs()));
4714 CallInst
*TaskAllocCall
= dyn_cast
<CallInst
>(
4715 OMPBuilder
.getOrCreateRuntimeFunctionPtr(OMPRTL___kmpc_omp_task_alloc
)
4718 // Verify the Ident argument
4719 GlobalVariable
*Ident
= cast
<GlobalVariable
>(TaskAllocCall
->getArgOperand(0));
4720 ASSERT_NE(Ident
, nullptr);
4721 EXPECT_TRUE(Ident
->hasInitializer());
4722 Constant
*Initializer
= Ident
->getInitializer();
4723 GlobalVariable
*SrcStrGlob
=
4724 cast
<GlobalVariable
>(Initializer
->getOperand(4)->stripPointerCasts());
4725 ASSERT_NE(SrcStrGlob
, nullptr);
4726 ConstantDataArray
*SrcSrc
=
4727 dyn_cast
<ConstantDataArray
>(SrcStrGlob
->getInitializer());
4728 ASSERT_NE(SrcSrc
, nullptr);
4730 // Verify the num_threads argument.
4731 CallInst
*GTID
= dyn_cast
<CallInst
>(TaskAllocCall
->getArgOperand(1));
4732 ASSERT_NE(GTID
, nullptr);
4733 EXPECT_EQ(GTID
->arg_size(), 1U);
4734 EXPECT_EQ(GTID
->getCalledFunction()->getName(), "__kmpc_global_thread_num");
4737 // TODO: Check for others flags. Currently testing only for tiedness.
4738 ConstantInt
*Flags
= dyn_cast
<ConstantInt
>(TaskAllocCall
->getArgOperand(2));
4739 ASSERT_NE(Flags
, nullptr);
4740 EXPECT_EQ(Flags
->getSExtValue(), 1);
4742 // Verify the data size
4743 ConstantInt
*DataSize
=
4744 dyn_cast
<ConstantInt
>(TaskAllocCall
->getArgOperand(3));
4745 ASSERT_NE(DataSize
, nullptr);
4746 EXPECT_EQ(DataSize
->getSExtValue(), 24); // 64-bit pointer + 128-bit integer
4748 // TODO: Verify size of shared clause variables
4750 // Verify Wrapper function
4751 Function
*WrapperFunc
=
4752 dyn_cast
<Function
>(TaskAllocCall
->getArgOperand(5)->stripPointerCasts());
4753 ASSERT_NE(WrapperFunc
, nullptr);
4754 EXPECT_FALSE(WrapperFunc
->isDeclaration());
4755 CallInst
*OutlinedFnCall
= dyn_cast
<CallInst
>(WrapperFunc
->begin()->begin());
4756 ASSERT_NE(OutlinedFnCall
, nullptr);
4757 EXPECT_EQ(WrapperFunc
->getArg(0)->getType(), Builder
.getInt32Ty());
4758 EXPECT_EQ(OutlinedFnCall
->getArgOperand(0), WrapperFunc
->getArg(1));
4760 // Verify the presence of `trunc` and `icmp` instructions in Outlined function
4761 Function
*OutlinedFn
= OutlinedFnCall
->getCalledFunction();
4762 ASSERT_NE(OutlinedFn
, nullptr);
4763 EXPECT_TRUE(any_of(instructions(OutlinedFn
),
4764 [](Instruction
&inst
) { return isa
<TruncInst
>(&inst
); }));
4765 EXPECT_TRUE(any_of(instructions(OutlinedFn
),
4766 [](Instruction
&inst
) { return isa
<ICmpInst
>(&inst
); }));
4768 // Verify the execution of the task
4769 CallInst
*TaskCall
= dyn_cast
<CallInst
>(
4770 OMPBuilder
.getOrCreateRuntimeFunctionPtr(OMPRTL___kmpc_omp_task
)
4772 ASSERT_NE(TaskCall
, nullptr);
4773 EXPECT_EQ(TaskCall
->getArgOperand(0), Ident
);
4774 EXPECT_EQ(TaskCall
->getArgOperand(1), GTID
);
4775 EXPECT_EQ(TaskCall
->getArgOperand(2), TaskAllocCall
);
4777 // Verify that the argument data has been copied
4778 for (User
*in
: TaskAllocCall
->users()) {
4779 if (MemCpyInst
*memCpyInst
= dyn_cast
<MemCpyInst
>(in
)) {
4780 EXPECT_EQ(memCpyInst
->getDest(), TaskAllocCall
);
4785 TEST_F(OpenMPIRBuilderTest
, CreateTaskNoArgs
) {
4786 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
4787 OpenMPIRBuilder
OMPBuilder(*M
);
4788 OMPBuilder
.initialize();
4790 IRBuilder
<> Builder(BB
);
4792 auto BodyGenCB
= [&](InsertPointTy AllocaIP
, InsertPointTy CodeGenIP
) {};
4794 BasicBlock
*AllocaBB
= Builder
.GetInsertBlock();
4795 BasicBlock
*BodyBB
= splitBB(Builder
, /*CreateBranch=*/true, "alloca.split");
4796 OpenMPIRBuilder::LocationDescription
Loc(
4797 InsertPointTy(BodyBB
, BodyBB
->getFirstInsertionPt()), DL
);
4798 Builder
.restoreIP(OMPBuilder
.createTask(
4799 Loc
, InsertPointTy(AllocaBB
, AllocaBB
->getFirstInsertionPt()),
4801 OMPBuilder
.finalize();
4802 Builder
.CreateRetVoid();
4804 EXPECT_FALSE(verifyModule(*M
, &errs()));
4807 TEST_F(OpenMPIRBuilderTest
, CreateTaskUntied
) {
4808 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
4809 OpenMPIRBuilder
OMPBuilder(*M
);
4810 OMPBuilder
.initialize();
4812 IRBuilder
<> Builder(BB
);
4813 auto BodyGenCB
= [&](InsertPointTy AllocaIP
, InsertPointTy CodeGenIP
) {};
4814 BasicBlock
*AllocaBB
= Builder
.GetInsertBlock();
4815 BasicBlock
*BodyBB
= splitBB(Builder
, /*CreateBranch=*/true, "alloca.split");
4816 OpenMPIRBuilder::LocationDescription
Loc(
4817 InsertPointTy(BodyBB
, BodyBB
->getFirstInsertionPt()), DL
);
4818 Builder
.restoreIP(OMPBuilder
.createTask(
4819 Loc
, InsertPointTy(AllocaBB
, AllocaBB
->getFirstInsertionPt()), BodyGenCB
,
4821 OMPBuilder
.finalize();
4822 Builder
.CreateRetVoid();
4824 // Check for the `Tied` argument
4825 CallInst
*TaskAllocCall
= dyn_cast
<CallInst
>(
4826 OMPBuilder
.getOrCreateRuntimeFunctionPtr(OMPRTL___kmpc_omp_task_alloc
)
4828 ASSERT_NE(TaskAllocCall
, nullptr);
4829 ConstantInt
*Flags
= dyn_cast
<ConstantInt
>(TaskAllocCall
->getArgOperand(2));
4830 ASSERT_NE(Flags
, nullptr);
4831 EXPECT_EQ(Flags
->getZExtValue() & 1U, 0U);
4833 EXPECT_FALSE(verifyModule(*M
, &errs()));
4836 TEST_F(OpenMPIRBuilderTest
, CreateTaskFinal
) {
4837 using InsertPointTy
= OpenMPIRBuilder::InsertPointTy
;
4838 OpenMPIRBuilder
OMPBuilder(*M
);
4839 OMPBuilder
.initialize();
4841 IRBuilder
<> Builder(BB
);
4842 auto BodyGenCB
= [&](InsertPointTy AllocaIP
, InsertPointTy CodeGenIP
) {};
4843 IRBuilderBase::InsertPoint AllocaIP
= Builder
.saveIP();
4844 BasicBlock
*BodyBB
= splitBB(Builder
, /*CreateBranch=*/true, "alloca.split");
4845 Builder
.SetInsertPoint(BodyBB
);
4846 Value
*Final
= Builder
.CreateICmp(
4847 CmpInst::Predicate::ICMP_EQ
, F
->getArg(0),
4848 ConstantInt::get(Type::getInt32Ty(M
->getContext()), 0U));
4849 OpenMPIRBuilder::LocationDescription
Loc(Builder
.saveIP(), DL
);
4850 Builder
.restoreIP(OMPBuilder
.createTask(Loc
, AllocaIP
, BodyGenCB
,
4851 /*Tied=*/false, Final
));
4852 OMPBuilder
.finalize();
4853 Builder
.CreateRetVoid();
4855 // Check for the `Tied` argument
4856 CallInst
*TaskAllocCall
= dyn_cast
<CallInst
>(
4857 OMPBuilder
.getOrCreateRuntimeFunctionPtr(OMPRTL___kmpc_omp_task_alloc
)
4859 ASSERT_NE(TaskAllocCall
, nullptr);
4860 BinaryOperator
*OrInst
=
4861 dyn_cast
<BinaryOperator
>(TaskAllocCall
->getArgOperand(2));
4862 ASSERT_NE(OrInst
, nullptr);
4863 EXPECT_EQ(OrInst
->getOpcode(), BinaryOperator::BinaryOps::Or
);
4865 // One of the arguments to `or` instruction is the tied flag, which is equal
4867 EXPECT_TRUE(any_of(OrInst
->operands(), [](Value
*op
) {
4868 if (ConstantInt
*TiedValue
= dyn_cast
<ConstantInt
>(op
))
4869 return TiedValue
->getSExtValue() == 0;
4873 // One of the arguments to `or` instruction is the final condition.
4874 EXPECT_TRUE(any_of(OrInst
->operands(), [Final
](Value
*op
) {
4875 if (SelectInst
*Select
= dyn_cast
<SelectInst
>(op
)) {
4876 ConstantInt
*TrueValue
= dyn_cast
<ConstantInt
>(Select
->getTrueValue());
4877 ConstantInt
*FalseValue
= dyn_cast
<ConstantInt
>(Select
->getFalseValue());
4878 if (!TrueValue
|| !FalseValue
)
4880 return Select
->getCondition() == Final
&&
4881 TrueValue
->getSExtValue() == 2 && FalseValue
->getSExtValue() == 0;
4886 EXPECT_FALSE(verifyModule(*M
, &errs()));