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