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