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); 2689251edeSMichael Kruse Type *KMPCMicroTy = M->getTypeByName("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) { 3889251edeSMichael Kruse StructType *IdentTy = M->getTypeByName("struct.ident_t"); 3989251edeSMichael Kruse 4089251edeSMichael Kruse GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; 4189251edeSMichael Kruse Type *Params[] = {IdentTy->getPointerTo(), Builder.getInt32Ty(), 4289251edeSMichael Kruse KMPCMicroTy->getPointerTo()}; 4389251edeSMichael Kruse 4489251edeSMichael Kruse FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Params, true); 4589251edeSMichael Kruse F = Function::Create(Ty, Linkage, Name, M); 4689251edeSMichael Kruse } 4789251edeSMichael Kruse 4889251edeSMichael Kruse Value *Task = Builder.CreatePointerBitCastOrAddrSpaceCast( 4989251edeSMichael Kruse SubFn, KMPCMicroTy->getPointerTo()); 5089251edeSMichael Kruse 5189251edeSMichael Kruse Value *Args[] = {SourceLocationInfo, 5289251edeSMichael Kruse Builder.getInt32(4) /* Number of arguments (w/o Task) */, 5389251edeSMichael Kruse Task, 5489251edeSMichael Kruse LB, 5589251edeSMichael Kruse UB, 5689251edeSMichael Kruse Stride, 5789251edeSMichael Kruse SubFnParam}; 5889251edeSMichael Kruse 5989251edeSMichael Kruse Builder.CreateCall(F, Args); 6089251edeSMichael Kruse } 6189251edeSMichael Kruse 6289251edeSMichael Kruse void ParallelLoopGeneratorKMP::deployParallelExecution(Value *SubFn, 6389251edeSMichael Kruse Value *SubFnParam, 6489251edeSMichael Kruse Value *LB, Value *UB, 6589251edeSMichael Kruse Value *Stride) { 6689251edeSMichael Kruse // Inform OpenMP runtime about the number of threads if greater than zero 6789251edeSMichael Kruse if (PollyNumThreads > 0) { 6889251edeSMichael Kruse Value *GlobalThreadID = createCallGlobalThreadNum(); 6989251edeSMichael Kruse createCallPushNumThreads(GlobalThreadID, Builder.getInt32(PollyNumThreads)); 7089251edeSMichael Kruse } 7189251edeSMichael Kruse 7289251edeSMichael Kruse // Tell the runtime we start a parallel loop 7389251edeSMichael Kruse createCallSpawnThreads(SubFn, SubFnParam, LB, UB, Stride); 7489251edeSMichael Kruse } 7589251edeSMichael Kruse 7689251edeSMichael Kruse Function *ParallelLoopGeneratorKMP::prepareSubFnDefinition(Function *F) const { 7789251edeSMichael Kruse std::vector<Type *> Arguments = {Builder.getInt32Ty()->getPointerTo(), 7889251edeSMichael Kruse Builder.getInt32Ty()->getPointerTo(), 7989251edeSMichael Kruse LongType, 8089251edeSMichael Kruse LongType, 8189251edeSMichael Kruse LongType, 8289251edeSMichael Kruse Builder.getInt8PtrTy()}; 8389251edeSMichael Kruse 8489251edeSMichael Kruse FunctionType *FT = FunctionType::get(Builder.getVoidTy(), Arguments, false); 8589251edeSMichael Kruse Function *SubFn = Function::Create(FT, Function::InternalLinkage, 8689251edeSMichael Kruse F->getName() + "_polly_subfn", M); 8789251edeSMichael Kruse // Name the function's arguments 8889251edeSMichael Kruse Function::arg_iterator AI = SubFn->arg_begin(); 8989251edeSMichael Kruse AI->setName("polly.kmpc.global_tid"); 9089251edeSMichael Kruse std::advance(AI, 1); 9189251edeSMichael Kruse AI->setName("polly.kmpc.bound_tid"); 9289251edeSMichael Kruse std::advance(AI, 1); 9389251edeSMichael Kruse AI->setName("polly.kmpc.lb"); 9489251edeSMichael Kruse std::advance(AI, 1); 9589251edeSMichael Kruse AI->setName("polly.kmpc.ub"); 9689251edeSMichael Kruse std::advance(AI, 1); 9789251edeSMichael Kruse AI->setName("polly.kmpc.inc"); 9889251edeSMichael Kruse std::advance(AI, 1); 9989251edeSMichael Kruse AI->setName("polly.kmpc.shared"); 10089251edeSMichael Kruse 10189251edeSMichael Kruse return SubFn; 10289251edeSMichael Kruse } 10389251edeSMichael Kruse 10489251edeSMichael Kruse // Create a subfunction of the following (preliminary) structure: 10589251edeSMichael Kruse // 10689251edeSMichael Kruse // PrevBB 10789251edeSMichael Kruse // | 10889251edeSMichael Kruse // v 10989251edeSMichael Kruse // HeaderBB 11089251edeSMichael Kruse // | _____ 11189251edeSMichael Kruse // v v | 11289251edeSMichael Kruse // CheckNextBB PreHeaderBB 11389251edeSMichael Kruse // |\ | 11489251edeSMichael Kruse // | \______/ 11589251edeSMichael Kruse // | 11689251edeSMichael Kruse // v 11789251edeSMichael Kruse // ExitBB 11889251edeSMichael Kruse // 11989251edeSMichael Kruse // HeaderBB will hold allocations, loading of variables and kmp-init calls. 12089251edeSMichael Kruse // CheckNextBB will check for more work (dynamic) or will be "empty" (static). 12189251edeSMichael Kruse // If there is more work to do: go to PreHeaderBB, otherwise go to ExitBB. 12289251edeSMichael Kruse // PreHeaderBB loads the new boundaries (& will lead to the loop body later on). 12389251edeSMichael Kruse // Just like CheckNextBB: PreHeaderBB is empty in the static scheduling case. 12489251edeSMichael Kruse // ExitBB marks the end of the parallel execution. 12589251edeSMichael Kruse // The possibly empty BasicBlocks will automatically be removed. 12689251edeSMichael Kruse std::tuple<Value *, Function *> 12789251edeSMichael Kruse ParallelLoopGeneratorKMP::createSubFn(Value *StrideNotUsed, 12889251edeSMichael Kruse AllocaInst *StructData, 12989251edeSMichael Kruse SetVector<Value *> Data, ValueMapT &Map) { 13089251edeSMichael Kruse Function *SubFn = createSubFnDefinition(); 13189251edeSMichael Kruse LLVMContext &Context = SubFn->getContext(); 13289251edeSMichael Kruse 13389251edeSMichael Kruse // Store the previous basic block. 13489251edeSMichael Kruse BasicBlock *PrevBB = Builder.GetInsertBlock(); 13589251edeSMichael Kruse 13689251edeSMichael Kruse // Create basic blocks. 13789251edeSMichael Kruse BasicBlock *HeaderBB = BasicBlock::Create(Context, "polly.par.setup", SubFn); 13889251edeSMichael Kruse BasicBlock *ExitBB = BasicBlock::Create(Context, "polly.par.exit", SubFn); 13989251edeSMichael Kruse BasicBlock *CheckNextBB = 14089251edeSMichael Kruse BasicBlock::Create(Context, "polly.par.checkNext", SubFn); 14189251edeSMichael Kruse BasicBlock *PreHeaderBB = 14289251edeSMichael Kruse BasicBlock::Create(Context, "polly.par.loadIVBounds", SubFn); 14389251edeSMichael Kruse 14489251edeSMichael Kruse DT.addNewBlock(HeaderBB, PrevBB); 14589251edeSMichael Kruse DT.addNewBlock(ExitBB, HeaderBB); 14689251edeSMichael Kruse DT.addNewBlock(CheckNextBB, HeaderBB); 14789251edeSMichael Kruse DT.addNewBlock(PreHeaderBB, HeaderBB); 14889251edeSMichael Kruse 14989251edeSMichael Kruse // Fill up basic block HeaderBB. 15089251edeSMichael Kruse Builder.SetInsertPoint(HeaderBB); 15189251edeSMichael Kruse Value *LBPtr = Builder.CreateAlloca(LongType, nullptr, "polly.par.LBPtr"); 15289251edeSMichael Kruse Value *UBPtr = Builder.CreateAlloca(LongType, nullptr, "polly.par.UBPtr"); 15389251edeSMichael Kruse Value *IsLastPtr = Builder.CreateAlloca(Builder.getInt32Ty(), nullptr, 15489251edeSMichael Kruse "polly.par.lastIterPtr"); 15589251edeSMichael Kruse Value *StridePtr = 15689251edeSMichael Kruse Builder.CreateAlloca(LongType, nullptr, "polly.par.StridePtr"); 15789251edeSMichael Kruse 15889251edeSMichael Kruse // Get iterator for retrieving the previously defined parameters. 15989251edeSMichael Kruse Function::arg_iterator AI = SubFn->arg_begin(); 16089251edeSMichael Kruse // First argument holds "global thread ID". 16189251edeSMichael Kruse Value *IDPtr = &*AI; 16289251edeSMichael Kruse // Skip "bound thread ID" since it is not used (but had to be defined). 16389251edeSMichael Kruse std::advance(AI, 2); 16489251edeSMichael Kruse // Move iterator to: LB, UB, Stride, Shared variable struct. 16589251edeSMichael Kruse Value *LB = &*AI; 16689251edeSMichael Kruse std::advance(AI, 1); 16789251edeSMichael Kruse Value *UB = &*AI; 16889251edeSMichael Kruse std::advance(AI, 1); 16989251edeSMichael Kruse Value *Stride = &*AI; 17089251edeSMichael Kruse std::advance(AI, 1); 17189251edeSMichael Kruse Value *Shared = &*AI; 17289251edeSMichael Kruse 17389251edeSMichael Kruse Value *UserContext = Builder.CreateBitCast(Shared, StructData->getType(), 17489251edeSMichael Kruse "polly.par.userContext"); 17589251edeSMichael Kruse 17689251edeSMichael Kruse extractValuesFromStruct(Data, StructData->getAllocatedType(), UserContext, 17789251edeSMichael Kruse Map); 17889251edeSMichael Kruse 17989251edeSMichael Kruse const int Alignment = (is64BitArch()) ? 8 : 4; 18089251edeSMichael Kruse Value *ID = 18189251edeSMichael Kruse Builder.CreateAlignedLoad(IDPtr, Alignment, "polly.par.global_tid"); 18289251edeSMichael Kruse 18389251edeSMichael Kruse Builder.CreateAlignedStore(LB, LBPtr, Alignment); 18489251edeSMichael Kruse Builder.CreateAlignedStore(UB, UBPtr, Alignment); 18589251edeSMichael Kruse Builder.CreateAlignedStore(Builder.getInt32(0), IsLastPtr, Alignment); 18689251edeSMichael Kruse Builder.CreateAlignedStore(Stride, StridePtr, Alignment); 18789251edeSMichael Kruse 18889251edeSMichael Kruse // Subtract one as the upper bound provided by openmp is a < comparison 18989251edeSMichael Kruse // whereas the codegenForSequential function creates a <= comparison. 19089251edeSMichael Kruse Value *AdjustedUB = Builder.CreateAdd(UB, ConstantInt::get(LongType, -1), 19189251edeSMichael Kruse "polly.indvar.UBAdjusted"); 19289251edeSMichael Kruse 19389251edeSMichael Kruse Value *ChunkSize = 19489251edeSMichael Kruse ConstantInt::get(LongType, std::max<int>(PollyChunkSize, 1)); 19589251edeSMichael Kruse 19689251edeSMichael Kruse switch (PollyScheduling) { 19789251edeSMichael Kruse case OMPGeneralSchedulingType::Dynamic: 19889251edeSMichael Kruse case OMPGeneralSchedulingType::Guided: 19989251edeSMichael Kruse case OMPGeneralSchedulingType::Runtime: 20089251edeSMichael Kruse // "DYNAMIC" scheduling types are handled below (including 'runtime') 20189251edeSMichael Kruse { 20289251edeSMichael Kruse UB = AdjustedUB; 20389251edeSMichael Kruse createCallDispatchInit(ID, LB, UB, Stride, ChunkSize); 20489251edeSMichael Kruse Value *HasWork = 20589251edeSMichael Kruse createCallDispatchNext(ID, IsLastPtr, LBPtr, UBPtr, StridePtr); 20689251edeSMichael Kruse Value *HasIteration = 20789251edeSMichael Kruse Builder.CreateICmp(llvm::CmpInst::Predicate::ICMP_EQ, HasWork, 20889251edeSMichael Kruse Builder.getInt32(1), "polly.hasIteration"); 20989251edeSMichael Kruse Builder.CreateCondBr(HasIteration, PreHeaderBB, ExitBB); 21089251edeSMichael Kruse 21189251edeSMichael Kruse Builder.SetInsertPoint(CheckNextBB); 21289251edeSMichael Kruse HasWork = createCallDispatchNext(ID, IsLastPtr, LBPtr, UBPtr, StridePtr); 21389251edeSMichael Kruse HasIteration = 21489251edeSMichael Kruse Builder.CreateICmp(llvm::CmpInst::Predicate::ICMP_EQ, HasWork, 21589251edeSMichael Kruse Builder.getInt32(1), "polly.hasWork"); 21689251edeSMichael Kruse Builder.CreateCondBr(HasIteration, PreHeaderBB, ExitBB); 21789251edeSMichael Kruse 21889251edeSMichael Kruse Builder.SetInsertPoint(PreHeaderBB); 21989251edeSMichael Kruse LB = Builder.CreateAlignedLoad(LBPtr, Alignment, "polly.indvar.LB"); 22089251edeSMichael Kruse UB = Builder.CreateAlignedLoad(UBPtr, Alignment, "polly.indvar.UB"); 22189251edeSMichael Kruse } 22289251edeSMichael Kruse break; 22389251edeSMichael Kruse case OMPGeneralSchedulingType::StaticChunked: 22489251edeSMichael Kruse case OMPGeneralSchedulingType::StaticNonChunked: 22589251edeSMichael Kruse // "STATIC" scheduling types are handled below 22689251edeSMichael Kruse { 22789251edeSMichael Kruse createCallStaticInit(ID, IsLastPtr, LBPtr, UBPtr, StridePtr, ChunkSize); 22889251edeSMichael Kruse 22989251edeSMichael Kruse LB = Builder.CreateAlignedLoad(LBPtr, Alignment, "polly.indvar.LB"); 23089251edeSMichael Kruse UB = Builder.CreateAlignedLoad(UBPtr, Alignment, "polly.indvar.UB"); 23189251edeSMichael Kruse 23289251edeSMichael Kruse Value *AdjUBOutOfBounds = 23389251edeSMichael Kruse Builder.CreateICmp(llvm::CmpInst::Predicate::ICMP_SLT, UB, AdjustedUB, 23489251edeSMichael Kruse "polly.adjustedUBOutOfBounds"); 23589251edeSMichael Kruse 23689251edeSMichael Kruse UB = Builder.CreateSelect(AdjUBOutOfBounds, UB, AdjustedUB); 23789251edeSMichael Kruse Builder.CreateAlignedStore(UB, UBPtr, Alignment); 23889251edeSMichael Kruse 23989251edeSMichael Kruse Value *HasIteration = Builder.CreateICmp( 24089251edeSMichael Kruse llvm::CmpInst::Predicate::ICMP_SLE, LB, UB, "polly.hasIteration"); 24189251edeSMichael Kruse Builder.CreateCondBr(HasIteration, PreHeaderBB, ExitBB); 24289251edeSMichael Kruse 24389251edeSMichael Kruse Builder.SetInsertPoint(CheckNextBB); 24489251edeSMichael Kruse Builder.CreateBr(ExitBB); 24589251edeSMichael Kruse 24689251edeSMichael Kruse Builder.SetInsertPoint(PreHeaderBB); 24789251edeSMichael Kruse } 24889251edeSMichael Kruse break; 24989251edeSMichael Kruse } 25089251edeSMichael Kruse 25189251edeSMichael Kruse Builder.CreateBr(CheckNextBB); 25289251edeSMichael Kruse Builder.SetInsertPoint(&*--Builder.GetInsertPoint()); 25389251edeSMichael Kruse BasicBlock *AfterBB; 25489251edeSMichael Kruse Value *IV = createLoop(LB, UB, Stride, Builder, LI, DT, AfterBB, 25589251edeSMichael Kruse ICmpInst::ICMP_SLE, nullptr, true, 25689251edeSMichael Kruse /* UseGuard */ false); 25789251edeSMichael Kruse 25889251edeSMichael Kruse BasicBlock::iterator LoopBody = Builder.GetInsertPoint(); 25989251edeSMichael Kruse 26089251edeSMichael Kruse // Add code to terminate this subfunction. 26189251edeSMichael Kruse Builder.SetInsertPoint(ExitBB); 26289251edeSMichael Kruse // Static (i.e. non-dynamic) scheduling types, are terminated with a fini-call 26389251edeSMichael Kruse if (PollyScheduling == OMPGeneralSchedulingType::StaticChunked) { 26489251edeSMichael Kruse createCallStaticFini(ID); 26589251edeSMichael Kruse } 26689251edeSMichael Kruse Builder.CreateRetVoid(); 26789251edeSMichael Kruse Builder.SetInsertPoint(&*LoopBody); 26889251edeSMichael Kruse 26989251edeSMichael Kruse return std::make_tuple(IV, SubFn); 27089251edeSMichael Kruse } 27189251edeSMichael Kruse 27289251edeSMichael Kruse Value *ParallelLoopGeneratorKMP::createCallGlobalThreadNum() { 27389251edeSMichael Kruse const std::string Name = "__kmpc_global_thread_num"; 27489251edeSMichael Kruse Function *F = M->getFunction(Name); 27589251edeSMichael Kruse 27689251edeSMichael Kruse // If F is not available, declare it. 27789251edeSMichael Kruse if (!F) { 27889251edeSMichael Kruse StructType *IdentTy = M->getTypeByName("struct.ident_t"); 27989251edeSMichael Kruse 28089251edeSMichael Kruse GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; 28189251edeSMichael Kruse Type *Params[] = {IdentTy->getPointerTo()}; 28289251edeSMichael Kruse 28389251edeSMichael Kruse FunctionType *Ty = FunctionType::get(Builder.getInt32Ty(), Params, false); 28489251edeSMichael Kruse F = Function::Create(Ty, Linkage, Name, M); 28589251edeSMichael Kruse } 28689251edeSMichael Kruse 28789251edeSMichael Kruse return Builder.CreateCall(F, {SourceLocationInfo}); 28889251edeSMichael Kruse } 28989251edeSMichael Kruse 29089251edeSMichael Kruse void ParallelLoopGeneratorKMP::createCallPushNumThreads(Value *GlobalThreadID, 29189251edeSMichael Kruse Value *NumThreads) { 29289251edeSMichael Kruse const std::string Name = "__kmpc_push_num_threads"; 29389251edeSMichael Kruse Function *F = M->getFunction(Name); 29489251edeSMichael Kruse 29589251edeSMichael Kruse // If F is not available, declare it. 29689251edeSMichael Kruse if (!F) { 29789251edeSMichael Kruse StructType *IdentTy = M->getTypeByName("struct.ident_t"); 29889251edeSMichael Kruse 29989251edeSMichael Kruse GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; 30089251edeSMichael Kruse Type *Params[] = {IdentTy->getPointerTo(), Builder.getInt32Ty(), 30189251edeSMichael Kruse Builder.getInt32Ty()}; 30289251edeSMichael Kruse 30389251edeSMichael Kruse FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Params, false); 30489251edeSMichael Kruse F = Function::Create(Ty, Linkage, Name, M); 30589251edeSMichael Kruse } 30689251edeSMichael Kruse 30789251edeSMichael Kruse Value *Args[] = {SourceLocationInfo, GlobalThreadID, NumThreads}; 30889251edeSMichael Kruse 30989251edeSMichael Kruse Builder.CreateCall(F, Args); 31089251edeSMichael Kruse } 31189251edeSMichael Kruse 31289251edeSMichael Kruse void ParallelLoopGeneratorKMP::createCallStaticInit(Value *GlobalThreadID, 31389251edeSMichael Kruse Value *IsLastPtr, 31489251edeSMichael Kruse Value *LBPtr, Value *UBPtr, 31589251edeSMichael Kruse Value *StridePtr, 31689251edeSMichael Kruse Value *ChunkSize) { 31789251edeSMichael Kruse const std::string Name = 31889251edeSMichael Kruse is64BitArch() ? "__kmpc_for_static_init_8" : "__kmpc_for_static_init_4"; 31989251edeSMichael Kruse Function *F = M->getFunction(Name); 32089251edeSMichael Kruse StructType *IdentTy = M->getTypeByName("struct.ident_t"); 32189251edeSMichael Kruse 32289251edeSMichael Kruse // If F is not available, declare it. 32389251edeSMichael Kruse if (!F) { 32489251edeSMichael Kruse GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; 32589251edeSMichael Kruse 32689251edeSMichael Kruse Type *Params[] = {IdentTy->getPointerTo(), 32789251edeSMichael Kruse Builder.getInt32Ty(), 32889251edeSMichael Kruse Builder.getInt32Ty(), 32989251edeSMichael Kruse Builder.getInt32Ty()->getPointerTo(), 33089251edeSMichael Kruse LongType->getPointerTo(), 33189251edeSMichael Kruse LongType->getPointerTo(), 33289251edeSMichael Kruse LongType->getPointerTo(), 33389251edeSMichael Kruse LongType, 33489251edeSMichael Kruse LongType}; 33589251edeSMichael Kruse 33689251edeSMichael Kruse FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Params, false); 33789251edeSMichael Kruse F = Function::Create(Ty, Linkage, Name, M); 33889251edeSMichael Kruse } 33989251edeSMichael Kruse 34089251edeSMichael Kruse // The parameter 'ChunkSize' will hold strictly positive integer values, 34189251edeSMichael Kruse // regardless of PollyChunkSize's value 34289251edeSMichael Kruse Value *Args[] = { 34389251edeSMichael Kruse SourceLocationInfo, 34489251edeSMichael Kruse GlobalThreadID, 34589251edeSMichael Kruse Builder.getInt32(int(getSchedType(PollyChunkSize, PollyScheduling))), 34689251edeSMichael Kruse IsLastPtr, 34789251edeSMichael Kruse LBPtr, 34889251edeSMichael Kruse UBPtr, 34989251edeSMichael Kruse StridePtr, 35089251edeSMichael Kruse ConstantInt::get(LongType, 1), 35189251edeSMichael Kruse ChunkSize}; 35289251edeSMichael Kruse 35389251edeSMichael Kruse Builder.CreateCall(F, Args); 35489251edeSMichael Kruse } 35589251edeSMichael Kruse 35689251edeSMichael Kruse void ParallelLoopGeneratorKMP::createCallStaticFini(Value *GlobalThreadID) { 35789251edeSMichael Kruse const std::string Name = "__kmpc_for_static_fini"; 35889251edeSMichael Kruse Function *F = M->getFunction(Name); 35989251edeSMichael Kruse StructType *IdentTy = M->getTypeByName("struct.ident_t"); 36089251edeSMichael Kruse 36189251edeSMichael Kruse // If F is not available, declare it. 36289251edeSMichael Kruse if (!F) { 36389251edeSMichael Kruse GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; 36489251edeSMichael Kruse Type *Params[] = {IdentTy->getPointerTo(), Builder.getInt32Ty()}; 36589251edeSMichael Kruse FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Params, false); 36689251edeSMichael Kruse F = Function::Create(Ty, Linkage, Name, M); 36789251edeSMichael Kruse } 36889251edeSMichael Kruse 36989251edeSMichael Kruse Value *Args[] = {SourceLocationInfo, GlobalThreadID}; 37089251edeSMichael Kruse 37189251edeSMichael Kruse Builder.CreateCall(F, Args); 37289251edeSMichael Kruse } 37389251edeSMichael Kruse 37489251edeSMichael Kruse void ParallelLoopGeneratorKMP::createCallDispatchInit(Value *GlobalThreadID, 37589251edeSMichael Kruse Value *LB, Value *UB, 37689251edeSMichael Kruse Value *Inc, 37789251edeSMichael Kruse Value *ChunkSize) { 37889251edeSMichael Kruse const std::string Name = 37989251edeSMichael Kruse is64BitArch() ? "__kmpc_dispatch_init_8" : "__kmpc_dispatch_init_4"; 38089251edeSMichael Kruse Function *F = M->getFunction(Name); 38189251edeSMichael Kruse StructType *IdentTy = M->getTypeByName("struct.ident_t"); 38289251edeSMichael Kruse 38389251edeSMichael Kruse // If F is not available, declare it. 38489251edeSMichael Kruse if (!F) { 38589251edeSMichael Kruse GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; 38689251edeSMichael Kruse 38789251edeSMichael Kruse Type *Params[] = {IdentTy->getPointerTo(), 38889251edeSMichael Kruse Builder.getInt32Ty(), 38989251edeSMichael Kruse Builder.getInt32Ty(), 39089251edeSMichael Kruse LongType, 39189251edeSMichael Kruse LongType, 39289251edeSMichael Kruse LongType, 39389251edeSMichael Kruse LongType}; 39489251edeSMichael Kruse 39589251edeSMichael Kruse FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Params, false); 39689251edeSMichael Kruse F = Function::Create(Ty, Linkage, Name, M); 39789251edeSMichael Kruse } 39889251edeSMichael Kruse 39989251edeSMichael Kruse // The parameter 'ChunkSize' will hold strictly positive integer values, 40089251edeSMichael Kruse // regardless of PollyChunkSize's value 40189251edeSMichael Kruse Value *Args[] = { 40289251edeSMichael Kruse SourceLocationInfo, 40389251edeSMichael Kruse GlobalThreadID, 40489251edeSMichael Kruse Builder.getInt32(int(getSchedType(PollyChunkSize, PollyScheduling))), 40589251edeSMichael Kruse LB, 40689251edeSMichael Kruse UB, 40789251edeSMichael Kruse Inc, 40889251edeSMichael Kruse ChunkSize}; 40989251edeSMichael Kruse 41089251edeSMichael Kruse Builder.CreateCall(F, Args); 41189251edeSMichael Kruse } 41289251edeSMichael Kruse 41389251edeSMichael Kruse Value *ParallelLoopGeneratorKMP::createCallDispatchNext(Value *GlobalThreadID, 41489251edeSMichael Kruse Value *IsLastPtr, 41589251edeSMichael Kruse Value *LBPtr, 41689251edeSMichael Kruse Value *UBPtr, 41789251edeSMichael Kruse Value *StridePtr) { 41889251edeSMichael Kruse const std::string Name = 41989251edeSMichael Kruse is64BitArch() ? "__kmpc_dispatch_next_8" : "__kmpc_dispatch_next_4"; 42089251edeSMichael Kruse Function *F = M->getFunction(Name); 42189251edeSMichael Kruse StructType *IdentTy = M->getTypeByName("struct.ident_t"); 42289251edeSMichael Kruse 42389251edeSMichael Kruse // If F is not available, declare it. 42489251edeSMichael Kruse if (!F) { 42589251edeSMichael Kruse GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; 42689251edeSMichael Kruse 42789251edeSMichael Kruse Type *Params[] = {IdentTy->getPointerTo(), 42889251edeSMichael Kruse Builder.getInt32Ty(), 42989251edeSMichael Kruse Builder.getInt32Ty()->getPointerTo(), 43089251edeSMichael Kruse LongType->getPointerTo(), 43189251edeSMichael Kruse LongType->getPointerTo(), 43289251edeSMichael Kruse LongType->getPointerTo()}; 43389251edeSMichael Kruse 43489251edeSMichael Kruse FunctionType *Ty = FunctionType::get(Builder.getInt32Ty(), Params, false); 43589251edeSMichael Kruse F = Function::Create(Ty, Linkage, Name, M); 43689251edeSMichael Kruse } 43789251edeSMichael Kruse 43889251edeSMichael Kruse Value *Args[] = {SourceLocationInfo, GlobalThreadID, IsLastPtr, LBPtr, UBPtr, 43989251edeSMichael Kruse StridePtr}; 44089251edeSMichael Kruse 44189251edeSMichael Kruse return Builder.CreateCall(F, Args); 44289251edeSMichael Kruse } 44389251edeSMichael Kruse 44489251edeSMichael Kruse // TODO: This function currently creates a source location dummy. It might be 44589251edeSMichael Kruse // necessary to (actually) provide information, in the future. 44689251edeSMichael Kruse GlobalVariable *ParallelLoopGeneratorKMP::createSourceLocation() { 44789251edeSMichael Kruse const std::string LocName = ".loc.dummy"; 44889251edeSMichael Kruse GlobalVariable *SourceLocDummy = M->getGlobalVariable(LocName); 44989251edeSMichael Kruse 45089251edeSMichael Kruse if (SourceLocDummy == nullptr) { 45189251edeSMichael Kruse const std::string StructName = "struct.ident_t"; 45289251edeSMichael Kruse StructType *IdentTy = M->getTypeByName(StructName); 45389251edeSMichael Kruse 45489251edeSMichael Kruse // If the ident_t StructType is not available, declare it. 45589251edeSMichael Kruse // in LLVM-IR: ident_t = type { i32, i32, i32, i32, i8* } 45689251edeSMichael Kruse if (!IdentTy) { 45789251edeSMichael Kruse Type *LocMembers[] = {Builder.getInt32Ty(), Builder.getInt32Ty(), 45889251edeSMichael Kruse Builder.getInt32Ty(), Builder.getInt32Ty(), 45989251edeSMichael Kruse Builder.getInt8PtrTy()}; 46089251edeSMichael Kruse 46189251edeSMichael Kruse IdentTy = 46289251edeSMichael Kruse StructType::create(M->getContext(), LocMembers, StructName, false); 46389251edeSMichael Kruse } 46489251edeSMichael Kruse 46589251edeSMichael Kruse const auto ArrayType = 46689251edeSMichael Kruse llvm::ArrayType::get(Builder.getInt8Ty(), /* Length */ 23); 46789251edeSMichael Kruse 46889251edeSMichael Kruse // Global Variable Definitions 46989251edeSMichael Kruse GlobalVariable *StrVar = new GlobalVariable( 47089251edeSMichael Kruse *M, ArrayType, true, GlobalValue::PrivateLinkage, 0, ".str.ident"); 471*0e62011dSGuillaume Chatelet StrVar->setAlignment(llvm::Align::None()); 47289251edeSMichael Kruse 47389251edeSMichael Kruse SourceLocDummy = new GlobalVariable( 47489251edeSMichael Kruse *M, IdentTy, true, GlobalValue::PrivateLinkage, nullptr, LocName); 475*0e62011dSGuillaume Chatelet SourceLocDummy->setAlignment(llvm::Align(8)); 47689251edeSMichael Kruse 47789251edeSMichael Kruse // Constant Definitions 47889251edeSMichael Kruse Constant *InitStr = ConstantDataArray::getString( 47989251edeSMichael Kruse M->getContext(), "Source location dummy.", true); 48089251edeSMichael Kruse 48189251edeSMichael Kruse Constant *StrPtr = static_cast<Constant *>(Builder.CreateInBoundsGEP( 48289251edeSMichael Kruse ArrayType, StrVar, {Builder.getInt32(0), Builder.getInt32(0)})); 48389251edeSMichael Kruse 48489251edeSMichael Kruse Constant *LocInitStruct = ConstantStruct::get( 48589251edeSMichael Kruse IdentTy, {Builder.getInt32(0), Builder.getInt32(0), Builder.getInt32(0), 48689251edeSMichael Kruse Builder.getInt32(0), StrPtr}); 48789251edeSMichael Kruse 48889251edeSMichael Kruse // Initialize variables 48989251edeSMichael Kruse StrVar->setInitializer(InitStr); 49089251edeSMichael Kruse SourceLocDummy->setInitializer(LocInitStruct); 49189251edeSMichael Kruse } 49289251edeSMichael Kruse 49389251edeSMichael Kruse return SourceLocDummy; 49489251edeSMichael Kruse } 49589251edeSMichael Kruse 49689251edeSMichael Kruse bool ParallelLoopGeneratorKMP::is64BitArch() { 49789251edeSMichael Kruse return (LongType->getIntegerBitWidth() == 64); 49889251edeSMichael Kruse } 49989251edeSMichael Kruse 50089251edeSMichael Kruse OMPGeneralSchedulingType ParallelLoopGeneratorKMP::getSchedType( 50189251edeSMichael Kruse int ChunkSize, OMPGeneralSchedulingType Scheduling) const { 50289251edeSMichael Kruse if (ChunkSize == 0 && Scheduling == OMPGeneralSchedulingType::StaticChunked) 50389251edeSMichael Kruse return OMPGeneralSchedulingType::StaticNonChunked; 50489251edeSMichael Kruse 50589251edeSMichael Kruse return Scheduling; 50689251edeSMichael Kruse } 507