189251edeSMichael Kruse //===------ LoopGeneratorsKMP.cpp - IR helper to create loops -------------===//
289251edeSMichael Kruse //
389251edeSMichael Kruse // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
489251edeSMichael Kruse // See https://llvm.org/LICENSE.txt for license information.
589251edeSMichael Kruse // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
689251edeSMichael Kruse //
789251edeSMichael Kruse //===----------------------------------------------------------------------===//
889251edeSMichael Kruse //
989251edeSMichael Kruse // This file contains functions to create parallel loops as LLVM-IR.
1089251edeSMichael Kruse //
1189251edeSMichael Kruse //===----------------------------------------------------------------------===//
1289251edeSMichael Kruse 
1389251edeSMichael Kruse #include "polly/CodeGen/LoopGeneratorsKMP.h"
1489251edeSMichael Kruse #include "llvm/IR/Dominators.h"
1589251edeSMichael Kruse #include "llvm/IR/Module.h"
1689251edeSMichael Kruse 
1789251edeSMichael Kruse using namespace llvm;
1889251edeSMichael Kruse using namespace polly;
1989251edeSMichael Kruse 
createCallSpawnThreads(Value * SubFn,Value * SubFnParam,Value * LB,Value * UB,Value * Stride)2089251edeSMichael Kruse void ParallelLoopGeneratorKMP::createCallSpawnThreads(Value *SubFn,
2189251edeSMichael Kruse                                                       Value *SubFnParam,
2289251edeSMichael Kruse                                                       Value *LB, Value *UB,
2389251edeSMichael Kruse                                                       Value *Stride) {
2489251edeSMichael Kruse   const std::string Name = "__kmpc_fork_call";
2589251edeSMichael Kruse   Function *F = M->getFunction(Name);
26fe431683SNick Lewycky   Type *KMPCMicroTy = StructType::getTypeByName(M->getContext(), "kmpc_micro");
2789251edeSMichael Kruse 
2889251edeSMichael Kruse   if (!KMPCMicroTy) {
2989251edeSMichael Kruse     // void (*kmpc_micro)(kmp_int32 *global_tid, kmp_int32 *bound_tid, ...)
3089251edeSMichael Kruse     Type *MicroParams[] = {Builder.getInt32Ty()->getPointerTo(),
3189251edeSMichael Kruse                            Builder.getInt32Ty()->getPointerTo()};
3289251edeSMichael Kruse 
3389251edeSMichael Kruse     KMPCMicroTy = FunctionType::get(Builder.getVoidTy(), MicroParams, true);
3489251edeSMichael Kruse   }
3589251edeSMichael Kruse 
3689251edeSMichael Kruse   // If F is not available, declare it.
3789251edeSMichael Kruse   if (!F) {
38fe431683SNick Lewycky     StructType *IdentTy =
39fe431683SNick Lewycky         StructType::getTypeByName(M->getContext(), "struct.ident_t");
4089251edeSMichael Kruse 
4189251edeSMichael Kruse     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
4289251edeSMichael Kruse     Type *Params[] = {IdentTy->getPointerTo(), Builder.getInt32Ty(),
4389251edeSMichael Kruse                       KMPCMicroTy->getPointerTo()};
4489251edeSMichael Kruse 
4589251edeSMichael Kruse     FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Params, true);
4689251edeSMichael Kruse     F = Function::Create(Ty, Linkage, Name, M);
4789251edeSMichael Kruse   }
4889251edeSMichael Kruse 
4989251edeSMichael Kruse   Value *Task = Builder.CreatePointerBitCastOrAddrSpaceCast(
5089251edeSMichael Kruse       SubFn, KMPCMicroTy->getPointerTo());
5189251edeSMichael Kruse 
5289251edeSMichael Kruse   Value *Args[] = {SourceLocationInfo,
5389251edeSMichael Kruse                    Builder.getInt32(4) /* Number of arguments (w/o Task) */,
5489251edeSMichael Kruse                    Task,
5589251edeSMichael Kruse                    LB,
5689251edeSMichael Kruse                    UB,
5789251edeSMichael Kruse                    Stride,
5889251edeSMichael Kruse                    SubFnParam};
5989251edeSMichael Kruse 
60*fe0e5b3eSMichael Kruse   CallInst *Call = Builder.CreateCall(F, Args);
61*fe0e5b3eSMichael Kruse   Call->setDebugLoc(DLGenerated);
6289251edeSMichael Kruse }
6389251edeSMichael Kruse 
deployParallelExecution(Function * SubFn,Value * SubFnParam,Value * LB,Value * UB,Value * Stride)643e5d671cSEli Friedman void ParallelLoopGeneratorKMP::deployParallelExecution(Function *SubFn,
6589251edeSMichael Kruse                                                        Value *SubFnParam,
6689251edeSMichael Kruse                                                        Value *LB, Value *UB,
6789251edeSMichael Kruse                                                        Value *Stride) {
6889251edeSMichael Kruse   // Inform OpenMP runtime about the number of threads if greater than zero
6989251edeSMichael Kruse   if (PollyNumThreads > 0) {
7089251edeSMichael Kruse     Value *GlobalThreadID = createCallGlobalThreadNum();
7189251edeSMichael Kruse     createCallPushNumThreads(GlobalThreadID, Builder.getInt32(PollyNumThreads));
7289251edeSMichael Kruse   }
7389251edeSMichael Kruse 
7489251edeSMichael Kruse   // Tell the runtime we start a parallel loop
7589251edeSMichael Kruse   createCallSpawnThreads(SubFn, SubFnParam, LB, UB, Stride);
7689251edeSMichael Kruse }
7789251edeSMichael Kruse 
prepareSubFnDefinition(Function * F) const7889251edeSMichael Kruse Function *ParallelLoopGeneratorKMP::prepareSubFnDefinition(Function *F) const {
7989251edeSMichael Kruse   std::vector<Type *> Arguments = {Builder.getInt32Ty()->getPointerTo(),
8089251edeSMichael Kruse                                    Builder.getInt32Ty()->getPointerTo(),
8189251edeSMichael Kruse                                    LongType,
8289251edeSMichael Kruse                                    LongType,
8389251edeSMichael Kruse                                    LongType,
8489251edeSMichael Kruse                                    Builder.getInt8PtrTy()};
8589251edeSMichael Kruse 
8689251edeSMichael Kruse   FunctionType *FT = FunctionType::get(Builder.getVoidTy(), Arguments, false);
8789251edeSMichael Kruse   Function *SubFn = Function::Create(FT, Function::InternalLinkage,
8889251edeSMichael Kruse                                      F->getName() + "_polly_subfn", M);
8989251edeSMichael Kruse   // Name the function's arguments
9089251edeSMichael Kruse   Function::arg_iterator AI = SubFn->arg_begin();
9189251edeSMichael Kruse   AI->setName("polly.kmpc.global_tid");
9289251edeSMichael Kruse   std::advance(AI, 1);
9389251edeSMichael Kruse   AI->setName("polly.kmpc.bound_tid");
9489251edeSMichael Kruse   std::advance(AI, 1);
9589251edeSMichael Kruse   AI->setName("polly.kmpc.lb");
9689251edeSMichael Kruse   std::advance(AI, 1);
9789251edeSMichael Kruse   AI->setName("polly.kmpc.ub");
9889251edeSMichael Kruse   std::advance(AI, 1);
9989251edeSMichael Kruse   AI->setName("polly.kmpc.inc");
10089251edeSMichael Kruse   std::advance(AI, 1);
10189251edeSMichael Kruse   AI->setName("polly.kmpc.shared");
10289251edeSMichael Kruse 
10389251edeSMichael Kruse   return SubFn;
10489251edeSMichael Kruse }
10589251edeSMichael Kruse 
10689251edeSMichael Kruse // Create a subfunction of the following (preliminary) structure:
10789251edeSMichael Kruse //
10889251edeSMichael Kruse //        PrevBB
10989251edeSMichael Kruse //           |
11089251edeSMichael Kruse //           v
11189251edeSMichael Kruse //        HeaderBB
1121e0be76eSMichael Halkenhäuser //       /   |    _____
1131e0be76eSMichael Halkenhäuser //      /    v   v     |
1141e0be76eSMichael Halkenhäuser //     / PreHeaderBB   |
1151e0be76eSMichael Halkenhäuser //    |      |         |
1161e0be76eSMichael Halkenhäuser //    |      v         |
1171e0be76eSMichael Halkenhäuser //    |  CheckNextBB   |
1181e0be76eSMichael Halkenhäuser //     \     |   \_____/
1191e0be76eSMichael Halkenhäuser //      \    |
1201e0be76eSMichael Halkenhäuser //       v   v
12189251edeSMichael Kruse //       ExitBB
12289251edeSMichael Kruse //
12389251edeSMichael Kruse // HeaderBB will hold allocations, loading of variables and kmp-init calls.
1241e0be76eSMichael Halkenhäuser // CheckNextBB will check for more work (dynamic / static chunked) or will be
1251e0be76eSMichael Halkenhäuser // empty (static non chunked).
12689251edeSMichael Kruse // If there is more work to do: go to PreHeaderBB, otherwise go to ExitBB.
12789251edeSMichael Kruse // PreHeaderBB loads the new boundaries (& will lead to the loop body later on).
1281e0be76eSMichael Halkenhäuser // Just like CheckNextBB: PreHeaderBB is (preliminary) empty in the static non
1291e0be76eSMichael Halkenhäuser // chunked scheduling case. ExitBB marks the end of the parallel execution.
13089251edeSMichael Kruse // The possibly empty BasicBlocks will automatically be removed.
13189251edeSMichael Kruse std::tuple<Value *, Function *>
createSubFn(Value * SequentialLoopStride,AllocaInst * StructData,SetVector<Value * > Data,ValueMapT & Map)1321e0be76eSMichael Halkenhäuser ParallelLoopGeneratorKMP::createSubFn(Value *SequentialLoopStride,
13389251edeSMichael Kruse                                       AllocaInst *StructData,
13489251edeSMichael Kruse                                       SetVector<Value *> Data, ValueMapT &Map) {
13589251edeSMichael Kruse   Function *SubFn = createSubFnDefinition();
13689251edeSMichael Kruse   LLVMContext &Context = SubFn->getContext();
13789251edeSMichael Kruse 
13889251edeSMichael Kruse   // Store the previous basic block.
13989251edeSMichael Kruse   BasicBlock *PrevBB = Builder.GetInsertBlock();
14089251edeSMichael Kruse 
14189251edeSMichael Kruse   // Create basic blocks.
14289251edeSMichael Kruse   BasicBlock *HeaderBB = BasicBlock::Create(Context, "polly.par.setup", SubFn);
14389251edeSMichael Kruse   BasicBlock *ExitBB = BasicBlock::Create(Context, "polly.par.exit", SubFn);
14489251edeSMichael Kruse   BasicBlock *CheckNextBB =
14589251edeSMichael Kruse       BasicBlock::Create(Context, "polly.par.checkNext", SubFn);
14689251edeSMichael Kruse   BasicBlock *PreHeaderBB =
14789251edeSMichael Kruse       BasicBlock::Create(Context, "polly.par.loadIVBounds", SubFn);
14889251edeSMichael Kruse 
14989251edeSMichael Kruse   DT.addNewBlock(HeaderBB, PrevBB);
15089251edeSMichael Kruse   DT.addNewBlock(ExitBB, HeaderBB);
15189251edeSMichael Kruse   DT.addNewBlock(CheckNextBB, HeaderBB);
15289251edeSMichael Kruse   DT.addNewBlock(PreHeaderBB, HeaderBB);
15389251edeSMichael Kruse 
15489251edeSMichael Kruse   // Fill up basic block HeaderBB.
15589251edeSMichael Kruse   Builder.SetInsertPoint(HeaderBB);
15689251edeSMichael Kruse   Value *LBPtr = Builder.CreateAlloca(LongType, nullptr, "polly.par.LBPtr");
15789251edeSMichael Kruse   Value *UBPtr = Builder.CreateAlloca(LongType, nullptr, "polly.par.UBPtr");
15889251edeSMichael Kruse   Value *IsLastPtr = Builder.CreateAlloca(Builder.getInt32Ty(), nullptr,
15989251edeSMichael Kruse                                           "polly.par.lastIterPtr");
16089251edeSMichael Kruse   Value *StridePtr =
16189251edeSMichael Kruse       Builder.CreateAlloca(LongType, nullptr, "polly.par.StridePtr");
16289251edeSMichael Kruse 
16389251edeSMichael Kruse   // Get iterator for retrieving the previously defined parameters.
16489251edeSMichael Kruse   Function::arg_iterator AI = SubFn->arg_begin();
16589251edeSMichael Kruse   // First argument holds "global thread ID".
16689251edeSMichael Kruse   Value *IDPtr = &*AI;
16789251edeSMichael Kruse   // Skip "bound thread ID" since it is not used (but had to be defined).
16889251edeSMichael Kruse   std::advance(AI, 2);
16989251edeSMichael Kruse   // Move iterator to: LB, UB, Stride, Shared variable struct.
17089251edeSMichael Kruse   Value *LB = &*AI;
17189251edeSMichael Kruse   std::advance(AI, 1);
17289251edeSMichael Kruse   Value *UB = &*AI;
17389251edeSMichael Kruse   std::advance(AI, 1);
17489251edeSMichael Kruse   Value *Stride = &*AI;
17589251edeSMichael Kruse   std::advance(AI, 1);
17689251edeSMichael Kruse   Value *Shared = &*AI;
17789251edeSMichael Kruse 
17889251edeSMichael Kruse   Value *UserContext = Builder.CreateBitCast(Shared, StructData->getType(),
17989251edeSMichael Kruse                                              "polly.par.userContext");
18089251edeSMichael Kruse 
18189251edeSMichael Kruse   extractValuesFromStruct(Data, StructData->getAllocatedType(), UserContext,
18289251edeSMichael Kruse                           Map);
18389251edeSMichael Kruse 
18459f95222SGuillaume Chatelet   const auto Alignment = llvm::Align(is64BitArch() ? 8 : 4);
18546354bacSNikita Popov   Value *ID = Builder.CreateAlignedLoad(Builder.getInt32Ty(), IDPtr, Alignment,
18646354bacSNikita Popov                                         "polly.par.global_tid");
18789251edeSMichael Kruse 
18889251edeSMichael Kruse   Builder.CreateAlignedStore(LB, LBPtr, Alignment);
18989251edeSMichael Kruse   Builder.CreateAlignedStore(UB, UBPtr, Alignment);
19089251edeSMichael Kruse   Builder.CreateAlignedStore(Builder.getInt32(0), IsLastPtr, Alignment);
19189251edeSMichael Kruse   Builder.CreateAlignedStore(Stride, StridePtr, Alignment);
19289251edeSMichael Kruse 
19389251edeSMichael Kruse   // Subtract one as the upper bound provided by openmp is a < comparison
19489251edeSMichael Kruse   // whereas the codegenForSequential function creates a <= comparison.
19589251edeSMichael Kruse   Value *AdjustedUB = Builder.CreateAdd(UB, ConstantInt::get(LongType, -1),
19689251edeSMichael Kruse                                         "polly.indvar.UBAdjusted");
19789251edeSMichael Kruse 
19889251edeSMichael Kruse   Value *ChunkSize =
19989251edeSMichael Kruse       ConstantInt::get(LongType, std::max<int>(PollyChunkSize, 1));
20089251edeSMichael Kruse 
2011e0be76eSMichael Halkenhäuser   OMPGeneralSchedulingType Scheduling =
2021e0be76eSMichael Halkenhäuser       getSchedType(PollyChunkSize, PollyScheduling);
2031e0be76eSMichael Halkenhäuser 
2041e0be76eSMichael Halkenhäuser   switch (Scheduling) {
20589251edeSMichael Kruse   case OMPGeneralSchedulingType::Dynamic:
20689251edeSMichael Kruse   case OMPGeneralSchedulingType::Guided:
20789251edeSMichael Kruse   case OMPGeneralSchedulingType::Runtime:
20889251edeSMichael Kruse     // "DYNAMIC" scheduling types are handled below (including 'runtime')
20989251edeSMichael Kruse     {
21089251edeSMichael Kruse       UB = AdjustedUB;
21189251edeSMichael Kruse       createCallDispatchInit(ID, LB, UB, Stride, ChunkSize);
21289251edeSMichael Kruse       Value *HasWork =
21389251edeSMichael Kruse           createCallDispatchNext(ID, IsLastPtr, LBPtr, UBPtr, StridePtr);
21489251edeSMichael Kruse       Value *HasIteration =
21589251edeSMichael Kruse           Builder.CreateICmp(llvm::CmpInst::Predicate::ICMP_EQ, HasWork,
21689251edeSMichael Kruse                              Builder.getInt32(1), "polly.hasIteration");
21789251edeSMichael Kruse       Builder.CreateCondBr(HasIteration, PreHeaderBB, ExitBB);
21889251edeSMichael Kruse 
21989251edeSMichael Kruse       Builder.SetInsertPoint(CheckNextBB);
22089251edeSMichael Kruse       HasWork = createCallDispatchNext(ID, IsLastPtr, LBPtr, UBPtr, StridePtr);
22189251edeSMichael Kruse       HasIteration =
22289251edeSMichael Kruse           Builder.CreateICmp(llvm::CmpInst::Predicate::ICMP_EQ, HasWork,
22389251edeSMichael Kruse                              Builder.getInt32(1), "polly.hasWork");
22489251edeSMichael Kruse       Builder.CreateCondBr(HasIteration, PreHeaderBB, ExitBB);
22589251edeSMichael Kruse 
22689251edeSMichael Kruse       Builder.SetInsertPoint(PreHeaderBB);
22746354bacSNikita Popov       LB = Builder.CreateAlignedLoad(LongType, LBPtr, Alignment,
22846354bacSNikita Popov                                      "polly.indvar.LB");
22946354bacSNikita Popov       UB = Builder.CreateAlignedLoad(LongType, UBPtr, Alignment,
23046354bacSNikita Popov                                      "polly.indvar.UB");
23189251edeSMichael Kruse     }
23289251edeSMichael Kruse     break;
23389251edeSMichael Kruse   case OMPGeneralSchedulingType::StaticChunked:
23489251edeSMichael Kruse   case OMPGeneralSchedulingType::StaticNonChunked:
23589251edeSMichael Kruse     // "STATIC" scheduling types are handled below
23689251edeSMichael Kruse     {
2371e0be76eSMichael Halkenhäuser       Builder.CreateAlignedStore(AdjustedUB, UBPtr, Alignment);
23889251edeSMichael Kruse       createCallStaticInit(ID, IsLastPtr, LBPtr, UBPtr, StridePtr, ChunkSize);
23989251edeSMichael Kruse 
24046354bacSNikita Popov       Value *ChunkedStride = Builder.CreateAlignedLoad(
24146354bacSNikita Popov           LongType, StridePtr, Alignment, "polly.kmpc.stride");
2421e0be76eSMichael Halkenhäuser 
24346354bacSNikita Popov       LB = Builder.CreateAlignedLoad(LongType, LBPtr, Alignment,
24446354bacSNikita Popov                                      "polly.indvar.LB");
24546354bacSNikita Popov       UB = Builder.CreateAlignedLoad(LongType, UBPtr, Alignment,
24646354bacSNikita Popov                                      "polly.indvar.UB.temp");
24789251edeSMichael Kruse 
2481e0be76eSMichael Halkenhäuser       Value *UBInRange =
2491e0be76eSMichael Halkenhäuser           Builder.CreateICmp(llvm::CmpInst::Predicate::ICMP_SLE, UB, AdjustedUB,
2501e0be76eSMichael Halkenhäuser                              "polly.indvar.UB.inRange");
2511e0be76eSMichael Halkenhäuser       UB = Builder.CreateSelect(UBInRange, UB, AdjustedUB, "polly.indvar.UB");
25289251edeSMichael Kruse       Builder.CreateAlignedStore(UB, UBPtr, Alignment);
25389251edeSMichael Kruse 
25489251edeSMichael Kruse       Value *HasIteration = Builder.CreateICmp(
25589251edeSMichael Kruse           llvm::CmpInst::Predicate::ICMP_SLE, LB, UB, "polly.hasIteration");
25689251edeSMichael Kruse       Builder.CreateCondBr(HasIteration, PreHeaderBB, ExitBB);
25789251edeSMichael Kruse 
2581e0be76eSMichael Halkenhäuser       if (Scheduling == OMPGeneralSchedulingType::StaticChunked) {
2591e0be76eSMichael Halkenhäuser         Builder.SetInsertPoint(PreHeaderBB);
26046354bacSNikita Popov         LB = Builder.CreateAlignedLoad(LongType, LBPtr, Alignment,
2611e0be76eSMichael Halkenhäuser                                        "polly.indvar.LB.entry");
26246354bacSNikita Popov         UB = Builder.CreateAlignedLoad(LongType, UBPtr, Alignment,
2631e0be76eSMichael Halkenhäuser                                        "polly.indvar.UB.entry");
2641e0be76eSMichael Halkenhäuser       }
2651e0be76eSMichael Halkenhäuser 
26689251edeSMichael Kruse       Builder.SetInsertPoint(CheckNextBB);
2671e0be76eSMichael Halkenhäuser 
2681e0be76eSMichael Halkenhäuser       if (Scheduling == OMPGeneralSchedulingType::StaticChunked) {
2691e0be76eSMichael Halkenhäuser         Value *NextLB =
2701e0be76eSMichael Halkenhäuser             Builder.CreateAdd(LB, ChunkedStride, "polly.indvar.nextLB");
2711e0be76eSMichael Halkenhäuser         Value *NextUB = Builder.CreateAdd(UB, ChunkedStride);
2721e0be76eSMichael Halkenhäuser 
2731e0be76eSMichael Halkenhäuser         Value *NextUBOutOfBounds =
2741e0be76eSMichael Halkenhäuser             Builder.CreateICmp(llvm::CmpInst::Predicate::ICMP_SGT, NextUB,
2751e0be76eSMichael Halkenhäuser                                AdjustedUB, "polly.indvar.nextUB.outOfBounds");
2761e0be76eSMichael Halkenhäuser         NextUB = Builder.CreateSelect(NextUBOutOfBounds, AdjustedUB, NextUB,
2771e0be76eSMichael Halkenhäuser                                       "polly.indvar.nextUB");
2781e0be76eSMichael Halkenhäuser 
2791e0be76eSMichael Halkenhäuser         Builder.CreateAlignedStore(NextLB, LBPtr, Alignment);
2801e0be76eSMichael Halkenhäuser         Builder.CreateAlignedStore(NextUB, UBPtr, Alignment);
2811e0be76eSMichael Halkenhäuser 
2821e0be76eSMichael Halkenhäuser         Value *HasWork =
2831e0be76eSMichael Halkenhäuser             Builder.CreateICmp(llvm::CmpInst::Predicate::ICMP_SLE, NextLB,
2841e0be76eSMichael Halkenhäuser                                AdjustedUB, "polly.hasWork");
2851e0be76eSMichael Halkenhäuser         Builder.CreateCondBr(HasWork, PreHeaderBB, ExitBB);
2861e0be76eSMichael Halkenhäuser       } else {
28789251edeSMichael Kruse         Builder.CreateBr(ExitBB);
2881e0be76eSMichael Halkenhäuser       }
28989251edeSMichael Kruse 
29089251edeSMichael Kruse       Builder.SetInsertPoint(PreHeaderBB);
29189251edeSMichael Kruse     }
29289251edeSMichael Kruse     break;
29389251edeSMichael Kruse   }
29489251edeSMichael Kruse 
29589251edeSMichael Kruse   Builder.CreateBr(CheckNextBB);
29689251edeSMichael Kruse   Builder.SetInsertPoint(&*--Builder.GetInsertPoint());
29789251edeSMichael Kruse   BasicBlock *AfterBB;
2981e0be76eSMichael Halkenhäuser   Value *IV = createLoop(LB, UB, SequentialLoopStride, Builder, LI, DT, AfterBB,
29989251edeSMichael Kruse                          ICmpInst::ICMP_SLE, nullptr, true,
30089251edeSMichael Kruse                          /* UseGuard */ false);
30189251edeSMichael Kruse 
30289251edeSMichael Kruse   BasicBlock::iterator LoopBody = Builder.GetInsertPoint();
30389251edeSMichael Kruse 
30489251edeSMichael Kruse   // Add code to terminate this subfunction.
30589251edeSMichael Kruse   Builder.SetInsertPoint(ExitBB);
30689251edeSMichael Kruse   // Static (i.e. non-dynamic) scheduling types, are terminated with a fini-call
3071e0be76eSMichael Halkenhäuser   if (Scheduling == OMPGeneralSchedulingType::StaticChunked ||
3081e0be76eSMichael Halkenhäuser       Scheduling == OMPGeneralSchedulingType::StaticNonChunked) {
30989251edeSMichael Kruse     createCallStaticFini(ID);
31089251edeSMichael Kruse   }
31189251edeSMichael Kruse   Builder.CreateRetVoid();
31289251edeSMichael Kruse   Builder.SetInsertPoint(&*LoopBody);
31389251edeSMichael Kruse 
31489251edeSMichael Kruse   return std::make_tuple(IV, SubFn);
31589251edeSMichael Kruse }
31689251edeSMichael Kruse 
createCallGlobalThreadNum()31789251edeSMichael Kruse Value *ParallelLoopGeneratorKMP::createCallGlobalThreadNum() {
31889251edeSMichael Kruse   const std::string Name = "__kmpc_global_thread_num";
31989251edeSMichael Kruse   Function *F = M->getFunction(Name);
32089251edeSMichael Kruse 
32189251edeSMichael Kruse   // If F is not available, declare it.
32289251edeSMichael Kruse   if (!F) {
323fe431683SNick Lewycky     StructType *IdentTy =
324fe431683SNick Lewycky         StructType::getTypeByName(M->getContext(), "struct.ident_t");
32589251edeSMichael Kruse 
32689251edeSMichael Kruse     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
32789251edeSMichael Kruse     Type *Params[] = {IdentTy->getPointerTo()};
32889251edeSMichael Kruse 
32989251edeSMichael Kruse     FunctionType *Ty = FunctionType::get(Builder.getInt32Ty(), Params, false);
33089251edeSMichael Kruse     F = Function::Create(Ty, Linkage, Name, M);
33189251edeSMichael Kruse   }
33289251edeSMichael Kruse 
333*fe0e5b3eSMichael Kruse   CallInst *Call = Builder.CreateCall(F, {SourceLocationInfo});
334*fe0e5b3eSMichael Kruse   Call->setDebugLoc(DLGenerated);
335*fe0e5b3eSMichael Kruse   return Call;
33689251edeSMichael Kruse }
33789251edeSMichael Kruse 
createCallPushNumThreads(Value * GlobalThreadID,Value * NumThreads)33889251edeSMichael Kruse void ParallelLoopGeneratorKMP::createCallPushNumThreads(Value *GlobalThreadID,
33989251edeSMichael Kruse                                                         Value *NumThreads) {
34089251edeSMichael Kruse   const std::string Name = "__kmpc_push_num_threads";
34189251edeSMichael Kruse   Function *F = M->getFunction(Name);
34289251edeSMichael Kruse 
34389251edeSMichael Kruse   // If F is not available, declare it.
34489251edeSMichael Kruse   if (!F) {
345fe431683SNick Lewycky     StructType *IdentTy =
346fe431683SNick Lewycky         StructType::getTypeByName(M->getContext(), "struct.ident_t");
34789251edeSMichael Kruse 
34889251edeSMichael Kruse     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
34989251edeSMichael Kruse     Type *Params[] = {IdentTy->getPointerTo(), Builder.getInt32Ty(),
35089251edeSMichael Kruse                       Builder.getInt32Ty()};
35189251edeSMichael Kruse 
35289251edeSMichael Kruse     FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Params, false);
35389251edeSMichael Kruse     F = Function::Create(Ty, Linkage, Name, M);
35489251edeSMichael Kruse   }
35589251edeSMichael Kruse 
35689251edeSMichael Kruse   Value *Args[] = {SourceLocationInfo, GlobalThreadID, NumThreads};
35789251edeSMichael Kruse 
358*fe0e5b3eSMichael Kruse   CallInst *Call = Builder.CreateCall(F, Args);
359*fe0e5b3eSMichael Kruse   Call->setDebugLoc(DLGenerated);
36089251edeSMichael Kruse }
36189251edeSMichael Kruse 
createCallStaticInit(Value * GlobalThreadID,Value * IsLastPtr,Value * LBPtr,Value * UBPtr,Value * StridePtr,Value * ChunkSize)36289251edeSMichael Kruse void ParallelLoopGeneratorKMP::createCallStaticInit(Value *GlobalThreadID,
36389251edeSMichael Kruse                                                     Value *IsLastPtr,
36489251edeSMichael Kruse                                                     Value *LBPtr, Value *UBPtr,
36589251edeSMichael Kruse                                                     Value *StridePtr,
36689251edeSMichael Kruse                                                     Value *ChunkSize) {
36789251edeSMichael Kruse   const std::string Name =
36889251edeSMichael Kruse       is64BitArch() ? "__kmpc_for_static_init_8" : "__kmpc_for_static_init_4";
36989251edeSMichael Kruse   Function *F = M->getFunction(Name);
370fe431683SNick Lewycky   StructType *IdentTy =
371fe431683SNick Lewycky       StructType::getTypeByName(M->getContext(), "struct.ident_t");
37289251edeSMichael Kruse 
37389251edeSMichael Kruse   // If F is not available, declare it.
37489251edeSMichael Kruse   if (!F) {
37589251edeSMichael Kruse     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
37689251edeSMichael Kruse 
37789251edeSMichael Kruse     Type *Params[] = {IdentTy->getPointerTo(),
37889251edeSMichael Kruse                       Builder.getInt32Ty(),
37989251edeSMichael Kruse                       Builder.getInt32Ty(),
38089251edeSMichael Kruse                       Builder.getInt32Ty()->getPointerTo(),
38189251edeSMichael Kruse                       LongType->getPointerTo(),
38289251edeSMichael Kruse                       LongType->getPointerTo(),
38389251edeSMichael Kruse                       LongType->getPointerTo(),
38489251edeSMichael Kruse                       LongType,
38589251edeSMichael Kruse                       LongType};
38689251edeSMichael Kruse 
38789251edeSMichael Kruse     FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Params, false);
38889251edeSMichael Kruse     F = Function::Create(Ty, Linkage, Name, M);
38989251edeSMichael Kruse   }
39089251edeSMichael Kruse 
39189251edeSMichael Kruse   // The parameter 'ChunkSize' will hold strictly positive integer values,
39289251edeSMichael Kruse   // regardless of PollyChunkSize's value
39389251edeSMichael Kruse   Value *Args[] = {
39489251edeSMichael Kruse       SourceLocationInfo,
39589251edeSMichael Kruse       GlobalThreadID,
39689251edeSMichael Kruse       Builder.getInt32(int(getSchedType(PollyChunkSize, PollyScheduling))),
39789251edeSMichael Kruse       IsLastPtr,
39889251edeSMichael Kruse       LBPtr,
39989251edeSMichael Kruse       UBPtr,
40089251edeSMichael Kruse       StridePtr,
40189251edeSMichael Kruse       ConstantInt::get(LongType, 1),
40289251edeSMichael Kruse       ChunkSize};
40389251edeSMichael Kruse 
404*fe0e5b3eSMichael Kruse   CallInst *Call = Builder.CreateCall(F, Args);
405*fe0e5b3eSMichael Kruse   Call->setDebugLoc(DLGenerated);
40689251edeSMichael Kruse }
40789251edeSMichael Kruse 
createCallStaticFini(Value * GlobalThreadID)40889251edeSMichael Kruse void ParallelLoopGeneratorKMP::createCallStaticFini(Value *GlobalThreadID) {
40989251edeSMichael Kruse   const std::string Name = "__kmpc_for_static_fini";
41089251edeSMichael Kruse   Function *F = M->getFunction(Name);
411fe431683SNick Lewycky   StructType *IdentTy =
412fe431683SNick Lewycky       StructType::getTypeByName(M->getContext(), "struct.ident_t");
41389251edeSMichael Kruse 
41489251edeSMichael Kruse   // If F is not available, declare it.
41589251edeSMichael Kruse   if (!F) {
41689251edeSMichael Kruse     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
41789251edeSMichael Kruse     Type *Params[] = {IdentTy->getPointerTo(), Builder.getInt32Ty()};
41889251edeSMichael Kruse     FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Params, false);
41989251edeSMichael Kruse     F = Function::Create(Ty, Linkage, Name, M);
42089251edeSMichael Kruse   }
42189251edeSMichael Kruse 
42289251edeSMichael Kruse   Value *Args[] = {SourceLocationInfo, GlobalThreadID};
42389251edeSMichael Kruse 
424*fe0e5b3eSMichael Kruse   CallInst *Call = Builder.CreateCall(F, Args);
425*fe0e5b3eSMichael Kruse   Call->setDebugLoc(DLGenerated);
42689251edeSMichael Kruse }
42789251edeSMichael Kruse 
createCallDispatchInit(Value * GlobalThreadID,Value * LB,Value * UB,Value * Inc,Value * ChunkSize)42889251edeSMichael Kruse void ParallelLoopGeneratorKMP::createCallDispatchInit(Value *GlobalThreadID,
42989251edeSMichael Kruse                                                       Value *LB, Value *UB,
43089251edeSMichael Kruse                                                       Value *Inc,
43189251edeSMichael Kruse                                                       Value *ChunkSize) {
43289251edeSMichael Kruse   const std::string Name =
43389251edeSMichael Kruse       is64BitArch() ? "__kmpc_dispatch_init_8" : "__kmpc_dispatch_init_4";
43489251edeSMichael Kruse   Function *F = M->getFunction(Name);
435fe431683SNick Lewycky   StructType *IdentTy =
436fe431683SNick Lewycky       StructType::getTypeByName(M->getContext(), "struct.ident_t");
43789251edeSMichael Kruse 
43889251edeSMichael Kruse   // If F is not available, declare it.
43989251edeSMichael Kruse   if (!F) {
44089251edeSMichael Kruse     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
44189251edeSMichael Kruse 
44289251edeSMichael Kruse     Type *Params[] = {IdentTy->getPointerTo(),
44389251edeSMichael Kruse                       Builder.getInt32Ty(),
44489251edeSMichael Kruse                       Builder.getInt32Ty(),
44589251edeSMichael Kruse                       LongType,
44689251edeSMichael Kruse                       LongType,
44789251edeSMichael Kruse                       LongType,
44889251edeSMichael Kruse                       LongType};
44989251edeSMichael Kruse 
45089251edeSMichael Kruse     FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Params, false);
45189251edeSMichael Kruse     F = Function::Create(Ty, Linkage, Name, M);
45289251edeSMichael Kruse   }
45389251edeSMichael Kruse 
45489251edeSMichael Kruse   // The parameter 'ChunkSize' will hold strictly positive integer values,
45589251edeSMichael Kruse   // regardless of PollyChunkSize's value
45689251edeSMichael Kruse   Value *Args[] = {
45789251edeSMichael Kruse       SourceLocationInfo,
45889251edeSMichael Kruse       GlobalThreadID,
45989251edeSMichael Kruse       Builder.getInt32(int(getSchedType(PollyChunkSize, PollyScheduling))),
46089251edeSMichael Kruse       LB,
46189251edeSMichael Kruse       UB,
46289251edeSMichael Kruse       Inc,
46389251edeSMichael Kruse       ChunkSize};
46489251edeSMichael Kruse 
465*fe0e5b3eSMichael Kruse   CallInst *Call = Builder.CreateCall(F, Args);
466*fe0e5b3eSMichael Kruse   Call->setDebugLoc(DLGenerated);
46789251edeSMichael Kruse }
46889251edeSMichael Kruse 
createCallDispatchNext(Value * GlobalThreadID,Value * IsLastPtr,Value * LBPtr,Value * UBPtr,Value * StridePtr)46989251edeSMichael Kruse Value *ParallelLoopGeneratorKMP::createCallDispatchNext(Value *GlobalThreadID,
47089251edeSMichael Kruse                                                         Value *IsLastPtr,
47189251edeSMichael Kruse                                                         Value *LBPtr,
47289251edeSMichael Kruse                                                         Value *UBPtr,
47389251edeSMichael Kruse                                                         Value *StridePtr) {
47489251edeSMichael Kruse   const std::string Name =
47589251edeSMichael Kruse       is64BitArch() ? "__kmpc_dispatch_next_8" : "__kmpc_dispatch_next_4";
47689251edeSMichael Kruse   Function *F = M->getFunction(Name);
477fe431683SNick Lewycky   StructType *IdentTy =
478fe431683SNick Lewycky       StructType::getTypeByName(M->getContext(), "struct.ident_t");
47989251edeSMichael Kruse 
48089251edeSMichael Kruse   // If F is not available, declare it.
48189251edeSMichael Kruse   if (!F) {
48289251edeSMichael Kruse     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
48389251edeSMichael Kruse 
48489251edeSMichael Kruse     Type *Params[] = {IdentTy->getPointerTo(),
48589251edeSMichael Kruse                       Builder.getInt32Ty(),
48689251edeSMichael Kruse                       Builder.getInt32Ty()->getPointerTo(),
48789251edeSMichael Kruse                       LongType->getPointerTo(),
48889251edeSMichael Kruse                       LongType->getPointerTo(),
48989251edeSMichael Kruse                       LongType->getPointerTo()};
49089251edeSMichael Kruse 
49189251edeSMichael Kruse     FunctionType *Ty = FunctionType::get(Builder.getInt32Ty(), Params, false);
49289251edeSMichael Kruse     F = Function::Create(Ty, Linkage, Name, M);
49389251edeSMichael Kruse   }
49489251edeSMichael Kruse 
49589251edeSMichael Kruse   Value *Args[] = {SourceLocationInfo, GlobalThreadID, IsLastPtr, LBPtr, UBPtr,
49689251edeSMichael Kruse                    StridePtr};
49789251edeSMichael Kruse 
498*fe0e5b3eSMichael Kruse   CallInst *Call = Builder.CreateCall(F, Args);
499*fe0e5b3eSMichael Kruse   Call->setDebugLoc(DLGenerated);
500*fe0e5b3eSMichael Kruse   return Call;
50189251edeSMichael Kruse }
50289251edeSMichael Kruse 
50389251edeSMichael Kruse // TODO: This function currently creates a source location dummy. It might be
50489251edeSMichael Kruse // necessary to (actually) provide information, in the future.
createSourceLocation()50589251edeSMichael Kruse GlobalVariable *ParallelLoopGeneratorKMP::createSourceLocation() {
50689251edeSMichael Kruse   const std::string LocName = ".loc.dummy";
50789251edeSMichael Kruse   GlobalVariable *SourceLocDummy = M->getGlobalVariable(LocName);
50889251edeSMichael Kruse 
50989251edeSMichael Kruse   if (SourceLocDummy == nullptr) {
51089251edeSMichael Kruse     const std::string StructName = "struct.ident_t";
511fe431683SNick Lewycky     StructType *IdentTy =
512fe431683SNick Lewycky         StructType::getTypeByName(M->getContext(), StructName);
51389251edeSMichael Kruse 
51489251edeSMichael Kruse     // If the ident_t StructType is not available, declare it.
51589251edeSMichael Kruse     // in LLVM-IR: ident_t = type { i32, i32, i32, i32, i8* }
51689251edeSMichael Kruse     if (!IdentTy) {
51789251edeSMichael Kruse       Type *LocMembers[] = {Builder.getInt32Ty(), Builder.getInt32Ty(),
51889251edeSMichael Kruse                             Builder.getInt32Ty(), Builder.getInt32Ty(),
51989251edeSMichael Kruse                             Builder.getInt8PtrTy()};
52089251edeSMichael Kruse 
52189251edeSMichael Kruse       IdentTy =
52289251edeSMichael Kruse           StructType::create(M->getContext(), LocMembers, StructName, false);
52389251edeSMichael Kruse     }
52489251edeSMichael Kruse 
52589251edeSMichael Kruse     const auto ArrayType =
52689251edeSMichael Kruse         llvm::ArrayType::get(Builder.getInt8Ty(), /* Length */ 23);
52789251edeSMichael Kruse 
52889251edeSMichael Kruse     // Global Variable Definitions
529fb7cf900SKazu Hirata     GlobalVariable *StrVar =
530fb7cf900SKazu Hirata         new GlobalVariable(*M, ArrayType, true, GlobalValue::PrivateLinkage,
531fb7cf900SKazu Hirata                            nullptr, ".str.ident");
532805c157eSGuillaume Chatelet     StrVar->setAlignment(llvm::Align(1));
53389251edeSMichael Kruse 
53489251edeSMichael Kruse     SourceLocDummy = new GlobalVariable(
53589251edeSMichael Kruse         *M, IdentTy, true, GlobalValue::PrivateLinkage, nullptr, LocName);
5360e62011dSGuillaume Chatelet     SourceLocDummy->setAlignment(llvm::Align(8));
53789251edeSMichael Kruse 
53889251edeSMichael Kruse     // Constant Definitions
53989251edeSMichael Kruse     Constant *InitStr = ConstantDataArray::getString(
54089251edeSMichael Kruse         M->getContext(), "Source location dummy.", true);
54189251edeSMichael Kruse 
54289251edeSMichael Kruse     Constant *StrPtr = static_cast<Constant *>(Builder.CreateInBoundsGEP(
54389251edeSMichael Kruse         ArrayType, StrVar, {Builder.getInt32(0), Builder.getInt32(0)}));
54489251edeSMichael Kruse 
54589251edeSMichael Kruse     Constant *LocInitStruct = ConstantStruct::get(
54689251edeSMichael Kruse         IdentTy, {Builder.getInt32(0), Builder.getInt32(0), Builder.getInt32(0),
54789251edeSMichael Kruse                   Builder.getInt32(0), StrPtr});
54889251edeSMichael Kruse 
54989251edeSMichael Kruse     // Initialize variables
55089251edeSMichael Kruse     StrVar->setInitializer(InitStr);
55189251edeSMichael Kruse     SourceLocDummy->setInitializer(LocInitStruct);
55289251edeSMichael Kruse   }
55389251edeSMichael Kruse 
55489251edeSMichael Kruse   return SourceLocDummy;
55589251edeSMichael Kruse }
55689251edeSMichael Kruse 
is64BitArch()55789251edeSMichael Kruse bool ParallelLoopGeneratorKMP::is64BitArch() {
55889251edeSMichael Kruse   return (LongType->getIntegerBitWidth() == 64);
55989251edeSMichael Kruse }
56089251edeSMichael Kruse 
getSchedType(int ChunkSize,OMPGeneralSchedulingType Scheduling) const56189251edeSMichael Kruse OMPGeneralSchedulingType ParallelLoopGeneratorKMP::getSchedType(
56289251edeSMichael Kruse     int ChunkSize, OMPGeneralSchedulingType Scheduling) const {
56389251edeSMichael Kruse   if (ChunkSize == 0 && Scheduling == OMPGeneralSchedulingType::StaticChunked)
56489251edeSMichael Kruse     return OMPGeneralSchedulingType::StaticNonChunked;
56589251edeSMichael Kruse 
56689251edeSMichael Kruse   return Scheduling;
56789251edeSMichael Kruse }
568