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 
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);
26*fe431683SNick 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) {
38*fe431683SNick Lewycky     StructType *IdentTy =
39*fe431683SNick 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 
6089251edeSMichael Kruse   Builder.CreateCall(F, Args);
6189251edeSMichael Kruse }
6289251edeSMichael Kruse 
633e5d671cSEli Friedman void ParallelLoopGeneratorKMP::deployParallelExecution(Function *SubFn,
6489251edeSMichael Kruse                                                        Value *SubFnParam,
6589251edeSMichael Kruse                                                        Value *LB, Value *UB,
6689251edeSMichael Kruse                                                        Value *Stride) {
6789251edeSMichael Kruse   // Inform OpenMP runtime about the number of threads if greater than zero
6889251edeSMichael Kruse   if (PollyNumThreads > 0) {
6989251edeSMichael Kruse     Value *GlobalThreadID = createCallGlobalThreadNum();
7089251edeSMichael Kruse     createCallPushNumThreads(GlobalThreadID, Builder.getInt32(PollyNumThreads));
7189251edeSMichael Kruse   }
7289251edeSMichael Kruse 
7389251edeSMichael Kruse   // Tell the runtime we start a parallel loop
7489251edeSMichael Kruse   createCallSpawnThreads(SubFn, SubFnParam, LB, UB, Stride);
7589251edeSMichael Kruse }
7689251edeSMichael Kruse 
7789251edeSMichael Kruse Function *ParallelLoopGeneratorKMP::prepareSubFnDefinition(Function *F) const {
7889251edeSMichael Kruse   std::vector<Type *> Arguments = {Builder.getInt32Ty()->getPointerTo(),
7989251edeSMichael Kruse                                    Builder.getInt32Ty()->getPointerTo(),
8089251edeSMichael Kruse                                    LongType,
8189251edeSMichael Kruse                                    LongType,
8289251edeSMichael Kruse                                    LongType,
8389251edeSMichael Kruse                                    Builder.getInt8PtrTy()};
8489251edeSMichael Kruse 
8589251edeSMichael Kruse   FunctionType *FT = FunctionType::get(Builder.getVoidTy(), Arguments, false);
8689251edeSMichael Kruse   Function *SubFn = Function::Create(FT, Function::InternalLinkage,
8789251edeSMichael Kruse                                      F->getName() + "_polly_subfn", M);
8889251edeSMichael Kruse   // Name the function's arguments
8989251edeSMichael Kruse   Function::arg_iterator AI = SubFn->arg_begin();
9089251edeSMichael Kruse   AI->setName("polly.kmpc.global_tid");
9189251edeSMichael Kruse   std::advance(AI, 1);
9289251edeSMichael Kruse   AI->setName("polly.kmpc.bound_tid");
9389251edeSMichael Kruse   std::advance(AI, 1);
9489251edeSMichael Kruse   AI->setName("polly.kmpc.lb");
9589251edeSMichael Kruse   std::advance(AI, 1);
9689251edeSMichael Kruse   AI->setName("polly.kmpc.ub");
9789251edeSMichael Kruse   std::advance(AI, 1);
9889251edeSMichael Kruse   AI->setName("polly.kmpc.inc");
9989251edeSMichael Kruse   std::advance(AI, 1);
10089251edeSMichael Kruse   AI->setName("polly.kmpc.shared");
10189251edeSMichael Kruse 
10289251edeSMichael Kruse   return SubFn;
10389251edeSMichael Kruse }
10489251edeSMichael Kruse 
10589251edeSMichael Kruse // Create a subfunction of the following (preliminary) structure:
10689251edeSMichael Kruse //
10789251edeSMichael Kruse //        PrevBB
10889251edeSMichael Kruse //           |
10989251edeSMichael Kruse //           v
11089251edeSMichael Kruse //        HeaderBB
1111e0be76eSMichael Halkenhäuser //       /   |    _____
1121e0be76eSMichael Halkenhäuser //      /    v   v     |
1131e0be76eSMichael Halkenhäuser //     / PreHeaderBB   |
1141e0be76eSMichael Halkenhäuser //    |      |         |
1151e0be76eSMichael Halkenhäuser //    |      v         |
1161e0be76eSMichael Halkenhäuser //    |  CheckNextBB   |
1171e0be76eSMichael Halkenhäuser //     \     |   \_____/
1181e0be76eSMichael Halkenhäuser //      \    |
1191e0be76eSMichael Halkenhäuser //       v   v
12089251edeSMichael Kruse //       ExitBB
12189251edeSMichael Kruse //
12289251edeSMichael Kruse // HeaderBB will hold allocations, loading of variables and kmp-init calls.
1231e0be76eSMichael Halkenhäuser // CheckNextBB will check for more work (dynamic / static chunked) or will be
1241e0be76eSMichael Halkenhäuser // empty (static non chunked).
12589251edeSMichael Kruse // If there is more work to do: go to PreHeaderBB, otherwise go to ExitBB.
12689251edeSMichael Kruse // PreHeaderBB loads the new boundaries (& will lead to the loop body later on).
1271e0be76eSMichael Halkenhäuser // Just like CheckNextBB: PreHeaderBB is (preliminary) empty in the static non
1281e0be76eSMichael Halkenhäuser // chunked scheduling case. ExitBB marks the end of the parallel execution.
12989251edeSMichael Kruse // The possibly empty BasicBlocks will automatically be removed.
13089251edeSMichael Kruse std::tuple<Value *, Function *>
1311e0be76eSMichael Halkenhäuser ParallelLoopGeneratorKMP::createSubFn(Value *SequentialLoopStride,
13289251edeSMichael Kruse                                       AllocaInst *StructData,
13389251edeSMichael Kruse                                       SetVector<Value *> Data, ValueMapT &Map) {
13489251edeSMichael Kruse   Function *SubFn = createSubFnDefinition();
13589251edeSMichael Kruse   LLVMContext &Context = SubFn->getContext();
13689251edeSMichael Kruse 
13789251edeSMichael Kruse   // Store the previous basic block.
13889251edeSMichael Kruse   BasicBlock *PrevBB = Builder.GetInsertBlock();
13989251edeSMichael Kruse 
14089251edeSMichael Kruse   // Create basic blocks.
14189251edeSMichael Kruse   BasicBlock *HeaderBB = BasicBlock::Create(Context, "polly.par.setup", SubFn);
14289251edeSMichael Kruse   BasicBlock *ExitBB = BasicBlock::Create(Context, "polly.par.exit", SubFn);
14389251edeSMichael Kruse   BasicBlock *CheckNextBB =
14489251edeSMichael Kruse       BasicBlock::Create(Context, "polly.par.checkNext", SubFn);
14589251edeSMichael Kruse   BasicBlock *PreHeaderBB =
14689251edeSMichael Kruse       BasicBlock::Create(Context, "polly.par.loadIVBounds", SubFn);
14789251edeSMichael Kruse 
14889251edeSMichael Kruse   DT.addNewBlock(HeaderBB, PrevBB);
14989251edeSMichael Kruse   DT.addNewBlock(ExitBB, HeaderBB);
15089251edeSMichael Kruse   DT.addNewBlock(CheckNextBB, HeaderBB);
15189251edeSMichael Kruse   DT.addNewBlock(PreHeaderBB, HeaderBB);
15289251edeSMichael Kruse 
15389251edeSMichael Kruse   // Fill up basic block HeaderBB.
15489251edeSMichael Kruse   Builder.SetInsertPoint(HeaderBB);
15589251edeSMichael Kruse   Value *LBPtr = Builder.CreateAlloca(LongType, nullptr, "polly.par.LBPtr");
15689251edeSMichael Kruse   Value *UBPtr = Builder.CreateAlloca(LongType, nullptr, "polly.par.UBPtr");
15789251edeSMichael Kruse   Value *IsLastPtr = Builder.CreateAlloca(Builder.getInt32Ty(), nullptr,
15889251edeSMichael Kruse                                           "polly.par.lastIterPtr");
15989251edeSMichael Kruse   Value *StridePtr =
16089251edeSMichael Kruse       Builder.CreateAlloca(LongType, nullptr, "polly.par.StridePtr");
16189251edeSMichael Kruse 
16289251edeSMichael Kruse   // Get iterator for retrieving the previously defined parameters.
16389251edeSMichael Kruse   Function::arg_iterator AI = SubFn->arg_begin();
16489251edeSMichael Kruse   // First argument holds "global thread ID".
16589251edeSMichael Kruse   Value *IDPtr = &*AI;
16689251edeSMichael Kruse   // Skip "bound thread ID" since it is not used (but had to be defined).
16789251edeSMichael Kruse   std::advance(AI, 2);
16889251edeSMichael Kruse   // Move iterator to: LB, UB, Stride, Shared variable struct.
16989251edeSMichael Kruse   Value *LB = &*AI;
17089251edeSMichael Kruse   std::advance(AI, 1);
17189251edeSMichael Kruse   Value *UB = &*AI;
17289251edeSMichael Kruse   std::advance(AI, 1);
17389251edeSMichael Kruse   Value *Stride = &*AI;
17489251edeSMichael Kruse   std::advance(AI, 1);
17589251edeSMichael Kruse   Value *Shared = &*AI;
17689251edeSMichael Kruse 
17789251edeSMichael Kruse   Value *UserContext = Builder.CreateBitCast(Shared, StructData->getType(),
17889251edeSMichael Kruse                                              "polly.par.userContext");
17989251edeSMichael Kruse 
18089251edeSMichael Kruse   extractValuesFromStruct(Data, StructData->getAllocatedType(), UserContext,
18189251edeSMichael Kruse                           Map);
18289251edeSMichael Kruse 
18359f95222SGuillaume Chatelet   const auto Alignment = llvm::Align(is64BitArch() ? 8 : 4);
18489251edeSMichael Kruse   Value *ID =
18589251edeSMichael Kruse       Builder.CreateAlignedLoad(IDPtr, Alignment, "polly.par.global_tid");
18689251edeSMichael Kruse 
18789251edeSMichael Kruse   Builder.CreateAlignedStore(LB, LBPtr, Alignment);
18889251edeSMichael Kruse   Builder.CreateAlignedStore(UB, UBPtr, Alignment);
18989251edeSMichael Kruse   Builder.CreateAlignedStore(Builder.getInt32(0), IsLastPtr, Alignment);
19089251edeSMichael Kruse   Builder.CreateAlignedStore(Stride, StridePtr, Alignment);
19189251edeSMichael Kruse 
19289251edeSMichael Kruse   // Subtract one as the upper bound provided by openmp is a < comparison
19389251edeSMichael Kruse   // whereas the codegenForSequential function creates a <= comparison.
19489251edeSMichael Kruse   Value *AdjustedUB = Builder.CreateAdd(UB, ConstantInt::get(LongType, -1),
19589251edeSMichael Kruse                                         "polly.indvar.UBAdjusted");
19689251edeSMichael Kruse 
19789251edeSMichael Kruse   Value *ChunkSize =
19889251edeSMichael Kruse       ConstantInt::get(LongType, std::max<int>(PollyChunkSize, 1));
19989251edeSMichael Kruse 
2001e0be76eSMichael Halkenhäuser   OMPGeneralSchedulingType Scheduling =
2011e0be76eSMichael Halkenhäuser       getSchedType(PollyChunkSize, PollyScheduling);
2021e0be76eSMichael Halkenhäuser 
2031e0be76eSMichael Halkenhäuser   switch (Scheduling) {
20489251edeSMichael Kruse   case OMPGeneralSchedulingType::Dynamic:
20589251edeSMichael Kruse   case OMPGeneralSchedulingType::Guided:
20689251edeSMichael Kruse   case OMPGeneralSchedulingType::Runtime:
20789251edeSMichael Kruse     // "DYNAMIC" scheduling types are handled below (including 'runtime')
20889251edeSMichael Kruse     {
20989251edeSMichael Kruse       UB = AdjustedUB;
21089251edeSMichael Kruse       createCallDispatchInit(ID, LB, UB, Stride, ChunkSize);
21189251edeSMichael Kruse       Value *HasWork =
21289251edeSMichael Kruse           createCallDispatchNext(ID, IsLastPtr, LBPtr, UBPtr, StridePtr);
21389251edeSMichael Kruse       Value *HasIteration =
21489251edeSMichael Kruse           Builder.CreateICmp(llvm::CmpInst::Predicate::ICMP_EQ, HasWork,
21589251edeSMichael Kruse                              Builder.getInt32(1), "polly.hasIteration");
21689251edeSMichael Kruse       Builder.CreateCondBr(HasIteration, PreHeaderBB, ExitBB);
21789251edeSMichael Kruse 
21889251edeSMichael Kruse       Builder.SetInsertPoint(CheckNextBB);
21989251edeSMichael Kruse       HasWork = createCallDispatchNext(ID, IsLastPtr, LBPtr, UBPtr, StridePtr);
22089251edeSMichael Kruse       HasIteration =
22189251edeSMichael Kruse           Builder.CreateICmp(llvm::CmpInst::Predicate::ICMP_EQ, HasWork,
22289251edeSMichael Kruse                              Builder.getInt32(1), "polly.hasWork");
22389251edeSMichael Kruse       Builder.CreateCondBr(HasIteration, PreHeaderBB, ExitBB);
22489251edeSMichael Kruse 
22589251edeSMichael Kruse       Builder.SetInsertPoint(PreHeaderBB);
22689251edeSMichael Kruse       LB = Builder.CreateAlignedLoad(LBPtr, Alignment, "polly.indvar.LB");
22789251edeSMichael Kruse       UB = Builder.CreateAlignedLoad(UBPtr, Alignment, "polly.indvar.UB");
22889251edeSMichael Kruse     }
22989251edeSMichael Kruse     break;
23089251edeSMichael Kruse   case OMPGeneralSchedulingType::StaticChunked:
23189251edeSMichael Kruse   case OMPGeneralSchedulingType::StaticNonChunked:
23289251edeSMichael Kruse     // "STATIC" scheduling types are handled below
23389251edeSMichael Kruse     {
2341e0be76eSMichael Halkenhäuser       Builder.CreateAlignedStore(AdjustedUB, UBPtr, Alignment);
23589251edeSMichael Kruse       createCallStaticInit(ID, IsLastPtr, LBPtr, UBPtr, StridePtr, ChunkSize);
23689251edeSMichael Kruse 
2371e0be76eSMichael Halkenhäuser       Value *ChunkedStride =
2381e0be76eSMichael Halkenhäuser           Builder.CreateAlignedLoad(StridePtr, Alignment, "polly.kmpc.stride");
2391e0be76eSMichael Halkenhäuser 
24089251edeSMichael Kruse       LB = Builder.CreateAlignedLoad(LBPtr, Alignment, "polly.indvar.LB");
2411e0be76eSMichael Halkenhäuser       UB = Builder.CreateAlignedLoad(UBPtr, Alignment, "polly.indvar.UB.temp");
24289251edeSMichael Kruse 
2431e0be76eSMichael Halkenhäuser       Value *UBInRange =
2441e0be76eSMichael Halkenhäuser           Builder.CreateICmp(llvm::CmpInst::Predicate::ICMP_SLE, UB, AdjustedUB,
2451e0be76eSMichael Halkenhäuser                              "polly.indvar.UB.inRange");
2461e0be76eSMichael Halkenhäuser       UB = Builder.CreateSelect(UBInRange, UB, AdjustedUB, "polly.indvar.UB");
24789251edeSMichael Kruse       Builder.CreateAlignedStore(UB, UBPtr, Alignment);
24889251edeSMichael Kruse 
24989251edeSMichael Kruse       Value *HasIteration = Builder.CreateICmp(
25089251edeSMichael Kruse           llvm::CmpInst::Predicate::ICMP_SLE, LB, UB, "polly.hasIteration");
25189251edeSMichael Kruse       Builder.CreateCondBr(HasIteration, PreHeaderBB, ExitBB);
25289251edeSMichael Kruse 
2531e0be76eSMichael Halkenhäuser       if (Scheduling == OMPGeneralSchedulingType::StaticChunked) {
2541e0be76eSMichael Halkenhäuser         Builder.SetInsertPoint(PreHeaderBB);
2551e0be76eSMichael Halkenhäuser         LB = Builder.CreateAlignedLoad(LBPtr, Alignment,
2561e0be76eSMichael Halkenhäuser                                        "polly.indvar.LB.entry");
2571e0be76eSMichael Halkenhäuser         UB = Builder.CreateAlignedLoad(UBPtr, Alignment,
2581e0be76eSMichael Halkenhäuser                                        "polly.indvar.UB.entry");
2591e0be76eSMichael Halkenhäuser       }
2601e0be76eSMichael Halkenhäuser 
26189251edeSMichael Kruse       Builder.SetInsertPoint(CheckNextBB);
2621e0be76eSMichael Halkenhäuser 
2631e0be76eSMichael Halkenhäuser       if (Scheduling == OMPGeneralSchedulingType::StaticChunked) {
2641e0be76eSMichael Halkenhäuser         Value *NextLB =
2651e0be76eSMichael Halkenhäuser             Builder.CreateAdd(LB, ChunkedStride, "polly.indvar.nextLB");
2661e0be76eSMichael Halkenhäuser         Value *NextUB = Builder.CreateAdd(UB, ChunkedStride);
2671e0be76eSMichael Halkenhäuser 
2681e0be76eSMichael Halkenhäuser         Value *NextUBOutOfBounds =
2691e0be76eSMichael Halkenhäuser             Builder.CreateICmp(llvm::CmpInst::Predicate::ICMP_SGT, NextUB,
2701e0be76eSMichael Halkenhäuser                                AdjustedUB, "polly.indvar.nextUB.outOfBounds");
2711e0be76eSMichael Halkenhäuser         NextUB = Builder.CreateSelect(NextUBOutOfBounds, AdjustedUB, NextUB,
2721e0be76eSMichael Halkenhäuser                                       "polly.indvar.nextUB");
2731e0be76eSMichael Halkenhäuser 
2741e0be76eSMichael Halkenhäuser         Builder.CreateAlignedStore(NextLB, LBPtr, Alignment);
2751e0be76eSMichael Halkenhäuser         Builder.CreateAlignedStore(NextUB, UBPtr, Alignment);
2761e0be76eSMichael Halkenhäuser 
2771e0be76eSMichael Halkenhäuser         Value *HasWork =
2781e0be76eSMichael Halkenhäuser             Builder.CreateICmp(llvm::CmpInst::Predicate::ICMP_SLE, NextLB,
2791e0be76eSMichael Halkenhäuser                                AdjustedUB, "polly.hasWork");
2801e0be76eSMichael Halkenhäuser         Builder.CreateCondBr(HasWork, PreHeaderBB, ExitBB);
2811e0be76eSMichael Halkenhäuser       } else {
28289251edeSMichael Kruse         Builder.CreateBr(ExitBB);
2831e0be76eSMichael Halkenhäuser       }
28489251edeSMichael Kruse 
28589251edeSMichael Kruse       Builder.SetInsertPoint(PreHeaderBB);
28689251edeSMichael Kruse     }
28789251edeSMichael Kruse     break;
28889251edeSMichael Kruse   }
28989251edeSMichael Kruse 
29089251edeSMichael Kruse   Builder.CreateBr(CheckNextBB);
29189251edeSMichael Kruse   Builder.SetInsertPoint(&*--Builder.GetInsertPoint());
29289251edeSMichael Kruse   BasicBlock *AfterBB;
2931e0be76eSMichael Halkenhäuser   Value *IV = createLoop(LB, UB, SequentialLoopStride, Builder, LI, DT, AfterBB,
29489251edeSMichael Kruse                          ICmpInst::ICMP_SLE, nullptr, true,
29589251edeSMichael Kruse                          /* UseGuard */ false);
29689251edeSMichael Kruse 
29789251edeSMichael Kruse   BasicBlock::iterator LoopBody = Builder.GetInsertPoint();
29889251edeSMichael Kruse 
29989251edeSMichael Kruse   // Add code to terminate this subfunction.
30089251edeSMichael Kruse   Builder.SetInsertPoint(ExitBB);
30189251edeSMichael Kruse   // Static (i.e. non-dynamic) scheduling types, are terminated with a fini-call
3021e0be76eSMichael Halkenhäuser   if (Scheduling == OMPGeneralSchedulingType::StaticChunked ||
3031e0be76eSMichael Halkenhäuser       Scheduling == OMPGeneralSchedulingType::StaticNonChunked) {
30489251edeSMichael Kruse     createCallStaticFini(ID);
30589251edeSMichael Kruse   }
30689251edeSMichael Kruse   Builder.CreateRetVoid();
30789251edeSMichael Kruse   Builder.SetInsertPoint(&*LoopBody);
30889251edeSMichael Kruse 
30989251edeSMichael Kruse   return std::make_tuple(IV, SubFn);
31089251edeSMichael Kruse }
31189251edeSMichael Kruse 
31289251edeSMichael Kruse Value *ParallelLoopGeneratorKMP::createCallGlobalThreadNum() {
31389251edeSMichael Kruse   const std::string Name = "__kmpc_global_thread_num";
31489251edeSMichael Kruse   Function *F = M->getFunction(Name);
31589251edeSMichael Kruse 
31689251edeSMichael Kruse   // If F is not available, declare it.
31789251edeSMichael Kruse   if (!F) {
318*fe431683SNick Lewycky     StructType *IdentTy =
319*fe431683SNick Lewycky         StructType::getTypeByName(M->getContext(), "struct.ident_t");
32089251edeSMichael Kruse 
32189251edeSMichael Kruse     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
32289251edeSMichael Kruse     Type *Params[] = {IdentTy->getPointerTo()};
32389251edeSMichael Kruse 
32489251edeSMichael Kruse     FunctionType *Ty = FunctionType::get(Builder.getInt32Ty(), Params, false);
32589251edeSMichael Kruse     F = Function::Create(Ty, Linkage, Name, M);
32689251edeSMichael Kruse   }
32789251edeSMichael Kruse 
32889251edeSMichael Kruse   return Builder.CreateCall(F, {SourceLocationInfo});
32989251edeSMichael Kruse }
33089251edeSMichael Kruse 
33189251edeSMichael Kruse void ParallelLoopGeneratorKMP::createCallPushNumThreads(Value *GlobalThreadID,
33289251edeSMichael Kruse                                                         Value *NumThreads) {
33389251edeSMichael Kruse   const std::string Name = "__kmpc_push_num_threads";
33489251edeSMichael Kruse   Function *F = M->getFunction(Name);
33589251edeSMichael Kruse 
33689251edeSMichael Kruse   // If F is not available, declare it.
33789251edeSMichael Kruse   if (!F) {
338*fe431683SNick Lewycky     StructType *IdentTy =
339*fe431683SNick Lewycky         StructType::getTypeByName(M->getContext(), "struct.ident_t");
34089251edeSMichael Kruse 
34189251edeSMichael Kruse     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
34289251edeSMichael Kruse     Type *Params[] = {IdentTy->getPointerTo(), Builder.getInt32Ty(),
34389251edeSMichael Kruse                       Builder.getInt32Ty()};
34489251edeSMichael Kruse 
34589251edeSMichael Kruse     FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Params, false);
34689251edeSMichael Kruse     F = Function::Create(Ty, Linkage, Name, M);
34789251edeSMichael Kruse   }
34889251edeSMichael Kruse 
34989251edeSMichael Kruse   Value *Args[] = {SourceLocationInfo, GlobalThreadID, NumThreads};
35089251edeSMichael Kruse 
35189251edeSMichael Kruse   Builder.CreateCall(F, Args);
35289251edeSMichael Kruse }
35389251edeSMichael Kruse 
35489251edeSMichael Kruse void ParallelLoopGeneratorKMP::createCallStaticInit(Value *GlobalThreadID,
35589251edeSMichael Kruse                                                     Value *IsLastPtr,
35689251edeSMichael Kruse                                                     Value *LBPtr, Value *UBPtr,
35789251edeSMichael Kruse                                                     Value *StridePtr,
35889251edeSMichael Kruse                                                     Value *ChunkSize) {
35989251edeSMichael Kruse   const std::string Name =
36089251edeSMichael Kruse       is64BitArch() ? "__kmpc_for_static_init_8" : "__kmpc_for_static_init_4";
36189251edeSMichael Kruse   Function *F = M->getFunction(Name);
362*fe431683SNick Lewycky   StructType *IdentTy =
363*fe431683SNick Lewycky       StructType::getTypeByName(M->getContext(), "struct.ident_t");
36489251edeSMichael Kruse 
36589251edeSMichael Kruse   // If F is not available, declare it.
36689251edeSMichael Kruse   if (!F) {
36789251edeSMichael Kruse     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
36889251edeSMichael Kruse 
36989251edeSMichael Kruse     Type *Params[] = {IdentTy->getPointerTo(),
37089251edeSMichael Kruse                       Builder.getInt32Ty(),
37189251edeSMichael Kruse                       Builder.getInt32Ty(),
37289251edeSMichael Kruse                       Builder.getInt32Ty()->getPointerTo(),
37389251edeSMichael Kruse                       LongType->getPointerTo(),
37489251edeSMichael Kruse                       LongType->getPointerTo(),
37589251edeSMichael Kruse                       LongType->getPointerTo(),
37689251edeSMichael Kruse                       LongType,
37789251edeSMichael Kruse                       LongType};
37889251edeSMichael Kruse 
37989251edeSMichael Kruse     FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Params, false);
38089251edeSMichael Kruse     F = Function::Create(Ty, Linkage, Name, M);
38189251edeSMichael Kruse   }
38289251edeSMichael Kruse 
38389251edeSMichael Kruse   // The parameter 'ChunkSize' will hold strictly positive integer values,
38489251edeSMichael Kruse   // regardless of PollyChunkSize's value
38589251edeSMichael Kruse   Value *Args[] = {
38689251edeSMichael Kruse       SourceLocationInfo,
38789251edeSMichael Kruse       GlobalThreadID,
38889251edeSMichael Kruse       Builder.getInt32(int(getSchedType(PollyChunkSize, PollyScheduling))),
38989251edeSMichael Kruse       IsLastPtr,
39089251edeSMichael Kruse       LBPtr,
39189251edeSMichael Kruse       UBPtr,
39289251edeSMichael Kruse       StridePtr,
39389251edeSMichael Kruse       ConstantInt::get(LongType, 1),
39489251edeSMichael Kruse       ChunkSize};
39589251edeSMichael Kruse 
39689251edeSMichael Kruse   Builder.CreateCall(F, Args);
39789251edeSMichael Kruse }
39889251edeSMichael Kruse 
39989251edeSMichael Kruse void ParallelLoopGeneratorKMP::createCallStaticFini(Value *GlobalThreadID) {
40089251edeSMichael Kruse   const std::string Name = "__kmpc_for_static_fini";
40189251edeSMichael Kruse   Function *F = M->getFunction(Name);
402*fe431683SNick Lewycky   StructType *IdentTy =
403*fe431683SNick Lewycky       StructType::getTypeByName(M->getContext(), "struct.ident_t");
40489251edeSMichael Kruse 
40589251edeSMichael Kruse   // If F is not available, declare it.
40689251edeSMichael Kruse   if (!F) {
40789251edeSMichael Kruse     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
40889251edeSMichael Kruse     Type *Params[] = {IdentTy->getPointerTo(), Builder.getInt32Ty()};
40989251edeSMichael Kruse     FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Params, false);
41089251edeSMichael Kruse     F = Function::Create(Ty, Linkage, Name, M);
41189251edeSMichael Kruse   }
41289251edeSMichael Kruse 
41389251edeSMichael Kruse   Value *Args[] = {SourceLocationInfo, GlobalThreadID};
41489251edeSMichael Kruse 
41589251edeSMichael Kruse   Builder.CreateCall(F, Args);
41689251edeSMichael Kruse }
41789251edeSMichael Kruse 
41889251edeSMichael Kruse void ParallelLoopGeneratorKMP::createCallDispatchInit(Value *GlobalThreadID,
41989251edeSMichael Kruse                                                       Value *LB, Value *UB,
42089251edeSMichael Kruse                                                       Value *Inc,
42189251edeSMichael Kruse                                                       Value *ChunkSize) {
42289251edeSMichael Kruse   const std::string Name =
42389251edeSMichael Kruse       is64BitArch() ? "__kmpc_dispatch_init_8" : "__kmpc_dispatch_init_4";
42489251edeSMichael Kruse   Function *F = M->getFunction(Name);
425*fe431683SNick Lewycky   StructType *IdentTy =
426*fe431683SNick Lewycky       StructType::getTypeByName(M->getContext(), "struct.ident_t");
42789251edeSMichael Kruse 
42889251edeSMichael Kruse   // If F is not available, declare it.
42989251edeSMichael Kruse   if (!F) {
43089251edeSMichael Kruse     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
43189251edeSMichael Kruse 
43289251edeSMichael Kruse     Type *Params[] = {IdentTy->getPointerTo(),
43389251edeSMichael Kruse                       Builder.getInt32Ty(),
43489251edeSMichael Kruse                       Builder.getInt32Ty(),
43589251edeSMichael Kruse                       LongType,
43689251edeSMichael Kruse                       LongType,
43789251edeSMichael Kruse                       LongType,
43889251edeSMichael Kruse                       LongType};
43989251edeSMichael Kruse 
44089251edeSMichael Kruse     FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Params, false);
44189251edeSMichael Kruse     F = Function::Create(Ty, Linkage, Name, M);
44289251edeSMichael Kruse   }
44389251edeSMichael Kruse 
44489251edeSMichael Kruse   // The parameter 'ChunkSize' will hold strictly positive integer values,
44589251edeSMichael Kruse   // regardless of PollyChunkSize's value
44689251edeSMichael Kruse   Value *Args[] = {
44789251edeSMichael Kruse       SourceLocationInfo,
44889251edeSMichael Kruse       GlobalThreadID,
44989251edeSMichael Kruse       Builder.getInt32(int(getSchedType(PollyChunkSize, PollyScheduling))),
45089251edeSMichael Kruse       LB,
45189251edeSMichael Kruse       UB,
45289251edeSMichael Kruse       Inc,
45389251edeSMichael Kruse       ChunkSize};
45489251edeSMichael Kruse 
45589251edeSMichael Kruse   Builder.CreateCall(F, Args);
45689251edeSMichael Kruse }
45789251edeSMichael Kruse 
45889251edeSMichael Kruse Value *ParallelLoopGeneratorKMP::createCallDispatchNext(Value *GlobalThreadID,
45989251edeSMichael Kruse                                                         Value *IsLastPtr,
46089251edeSMichael Kruse                                                         Value *LBPtr,
46189251edeSMichael Kruse                                                         Value *UBPtr,
46289251edeSMichael Kruse                                                         Value *StridePtr) {
46389251edeSMichael Kruse   const std::string Name =
46489251edeSMichael Kruse       is64BitArch() ? "__kmpc_dispatch_next_8" : "__kmpc_dispatch_next_4";
46589251edeSMichael Kruse   Function *F = M->getFunction(Name);
466*fe431683SNick Lewycky   StructType *IdentTy =
467*fe431683SNick Lewycky       StructType::getTypeByName(M->getContext(), "struct.ident_t");
46889251edeSMichael Kruse 
46989251edeSMichael Kruse   // If F is not available, declare it.
47089251edeSMichael Kruse   if (!F) {
47189251edeSMichael Kruse     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
47289251edeSMichael Kruse 
47389251edeSMichael Kruse     Type *Params[] = {IdentTy->getPointerTo(),
47489251edeSMichael Kruse                       Builder.getInt32Ty(),
47589251edeSMichael Kruse                       Builder.getInt32Ty()->getPointerTo(),
47689251edeSMichael Kruse                       LongType->getPointerTo(),
47789251edeSMichael Kruse                       LongType->getPointerTo(),
47889251edeSMichael Kruse                       LongType->getPointerTo()};
47989251edeSMichael Kruse 
48089251edeSMichael Kruse     FunctionType *Ty = FunctionType::get(Builder.getInt32Ty(), Params, false);
48189251edeSMichael Kruse     F = Function::Create(Ty, Linkage, Name, M);
48289251edeSMichael Kruse   }
48389251edeSMichael Kruse 
48489251edeSMichael Kruse   Value *Args[] = {SourceLocationInfo, GlobalThreadID, IsLastPtr, LBPtr, UBPtr,
48589251edeSMichael Kruse                    StridePtr};
48689251edeSMichael Kruse 
48789251edeSMichael Kruse   return Builder.CreateCall(F, Args);
48889251edeSMichael Kruse }
48989251edeSMichael Kruse 
49089251edeSMichael Kruse // TODO: This function currently creates a source location dummy. It might be
49189251edeSMichael Kruse // necessary to (actually) provide information, in the future.
49289251edeSMichael Kruse GlobalVariable *ParallelLoopGeneratorKMP::createSourceLocation() {
49389251edeSMichael Kruse   const std::string LocName = ".loc.dummy";
49489251edeSMichael Kruse   GlobalVariable *SourceLocDummy = M->getGlobalVariable(LocName);
49589251edeSMichael Kruse 
49689251edeSMichael Kruse   if (SourceLocDummy == nullptr) {
49789251edeSMichael Kruse     const std::string StructName = "struct.ident_t";
498*fe431683SNick Lewycky     StructType *IdentTy =
499*fe431683SNick Lewycky         StructType::getTypeByName(M->getContext(), StructName);
50089251edeSMichael Kruse 
50189251edeSMichael Kruse     // If the ident_t StructType is not available, declare it.
50289251edeSMichael Kruse     // in LLVM-IR: ident_t = type { i32, i32, i32, i32, i8* }
50389251edeSMichael Kruse     if (!IdentTy) {
50489251edeSMichael Kruse       Type *LocMembers[] = {Builder.getInt32Ty(), Builder.getInt32Ty(),
50589251edeSMichael Kruse                             Builder.getInt32Ty(), Builder.getInt32Ty(),
50689251edeSMichael Kruse                             Builder.getInt8PtrTy()};
50789251edeSMichael Kruse 
50889251edeSMichael Kruse       IdentTy =
50989251edeSMichael Kruse           StructType::create(M->getContext(), LocMembers, StructName, false);
51089251edeSMichael Kruse     }
51189251edeSMichael Kruse 
51289251edeSMichael Kruse     const auto ArrayType =
51389251edeSMichael Kruse         llvm::ArrayType::get(Builder.getInt8Ty(), /* Length */ 23);
51489251edeSMichael Kruse 
51589251edeSMichael Kruse     // Global Variable Definitions
51689251edeSMichael Kruse     GlobalVariable *StrVar = new GlobalVariable(
51789251edeSMichael Kruse         *M, ArrayType, true, GlobalValue::PrivateLinkage, 0, ".str.ident");
518805c157eSGuillaume Chatelet     StrVar->setAlignment(llvm::Align(1));
51989251edeSMichael Kruse 
52089251edeSMichael Kruse     SourceLocDummy = new GlobalVariable(
52189251edeSMichael Kruse         *M, IdentTy, true, GlobalValue::PrivateLinkage, nullptr, LocName);
5220e62011dSGuillaume Chatelet     SourceLocDummy->setAlignment(llvm::Align(8));
52389251edeSMichael Kruse 
52489251edeSMichael Kruse     // Constant Definitions
52589251edeSMichael Kruse     Constant *InitStr = ConstantDataArray::getString(
52689251edeSMichael Kruse         M->getContext(), "Source location dummy.", true);
52789251edeSMichael Kruse 
52889251edeSMichael Kruse     Constant *StrPtr = static_cast<Constant *>(Builder.CreateInBoundsGEP(
52989251edeSMichael Kruse         ArrayType, StrVar, {Builder.getInt32(0), Builder.getInt32(0)}));
53089251edeSMichael Kruse 
53189251edeSMichael Kruse     Constant *LocInitStruct = ConstantStruct::get(
53289251edeSMichael Kruse         IdentTy, {Builder.getInt32(0), Builder.getInt32(0), Builder.getInt32(0),
53389251edeSMichael Kruse                   Builder.getInt32(0), StrPtr});
53489251edeSMichael Kruse 
53589251edeSMichael Kruse     // Initialize variables
53689251edeSMichael Kruse     StrVar->setInitializer(InitStr);
53789251edeSMichael Kruse     SourceLocDummy->setInitializer(LocInitStruct);
53889251edeSMichael Kruse   }
53989251edeSMichael Kruse 
54089251edeSMichael Kruse   return SourceLocDummy;
54189251edeSMichael Kruse }
54289251edeSMichael Kruse 
54389251edeSMichael Kruse bool ParallelLoopGeneratorKMP::is64BitArch() {
54489251edeSMichael Kruse   return (LongType->getIntegerBitWidth() == 64);
54589251edeSMichael Kruse }
54689251edeSMichael Kruse 
54789251edeSMichael Kruse OMPGeneralSchedulingType ParallelLoopGeneratorKMP::getSchedType(
54889251edeSMichael Kruse     int ChunkSize, OMPGeneralSchedulingType Scheduling) const {
54989251edeSMichael Kruse   if (ChunkSize == 0 && Scheduling == OMPGeneralSchedulingType::StaticChunked)
55089251edeSMichael Kruse     return OMPGeneralSchedulingType::StaticNonChunked;
55189251edeSMichael Kruse 
55289251edeSMichael Kruse   return Scheduling;
55389251edeSMichael Kruse }
554