xref: /llvm-project/polly/lib/CodeGen/LoopGeneratorsGOMP.cpp (revision 467a9bde06e681cecc69afa18580aadf2ed9769b)
189251edeSMichael Kruse //===------ LoopGeneratorsGOMP.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/LoopGeneratorsGOMP.h"
1422c77f23SMichael Kruse #include "llvm/Analysis/LoopInfo.h"
1589251edeSMichael Kruse #include "llvm/IR/Dominators.h"
1689251edeSMichael Kruse #include "llvm/IR/Module.h"
1789251edeSMichael Kruse 
1889251edeSMichael Kruse using namespace llvm;
1989251edeSMichael Kruse using namespace polly;
2089251edeSMichael Kruse 
2189251edeSMichael Kruse void ParallelLoopGeneratorGOMP::createCallSpawnThreads(Value *SubFn,
2289251edeSMichael Kruse                                                        Value *SubFnParam,
2389251edeSMichael Kruse                                                        Value *LB, Value *UB,
2489251edeSMichael Kruse                                                        Value *Stride) {
2589251edeSMichael Kruse   const std::string Name = "GOMP_parallel_loop_runtime_start";
2689251edeSMichael Kruse 
2789251edeSMichael Kruse   Function *F = M->getFunction(Name);
2889251edeSMichael Kruse 
2989251edeSMichael Kruse   // If F is not available, declare it.
3089251edeSMichael Kruse   if (!F) {
3189251edeSMichael Kruse     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
3289251edeSMichael Kruse 
3389251edeSMichael Kruse     Type *Params[] = {PointerType::getUnqual(FunctionType::get(
34a3ef8589SFangrui Song                           Builder.getVoidTy(), Builder.getPtrTy(), false)),
35a3ef8589SFangrui Song                       Builder.getPtrTy(),
3689251edeSMichael Kruse                       Builder.getInt32Ty(),
3789251edeSMichael Kruse                       LongType,
3889251edeSMichael Kruse                       LongType,
3989251edeSMichael Kruse                       LongType};
4089251edeSMichael Kruse 
4189251edeSMichael Kruse     FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Params, false);
4289251edeSMichael Kruse     F = Function::Create(Ty, Linkage, Name, M);
4389251edeSMichael Kruse   }
4489251edeSMichael Kruse 
4589251edeSMichael Kruse   Value *Args[] = {SubFn, SubFnParam, Builder.getInt32(PollyNumThreads),
4689251edeSMichael Kruse                    LB,    UB,         Stride};
4789251edeSMichael Kruse 
48fe0e5b3eSMichael Kruse   CallInst *Call = Builder.CreateCall(F, Args);
49fe0e5b3eSMichael Kruse   Call->setDebugLoc(DLGenerated);
5089251edeSMichael Kruse }
5189251edeSMichael Kruse 
523e5d671cSEli Friedman void ParallelLoopGeneratorGOMP::deployParallelExecution(Function *SubFn,
5389251edeSMichael Kruse                                                         Value *SubFnParam,
5489251edeSMichael Kruse                                                         Value *LB, Value *UB,
5589251edeSMichael Kruse                                                         Value *Stride) {
5689251edeSMichael Kruse   // Tell the runtime we start a parallel loop
5789251edeSMichael Kruse   createCallSpawnThreads(SubFn, SubFnParam, LB, UB, Stride);
58fe0e5b3eSMichael Kruse   CallInst *Call = Builder.CreateCall(SubFn, SubFnParam);
59fe0e5b3eSMichael Kruse   Call->setDebugLoc(DLGenerated);
6089251edeSMichael Kruse   createCallJoinThreads();
6189251edeSMichael Kruse }
6289251edeSMichael Kruse 
6389251edeSMichael Kruse Function *ParallelLoopGeneratorGOMP::prepareSubFnDefinition(Function *F) const {
6489251edeSMichael Kruse   FunctionType *FT =
65a3ef8589SFangrui Song       FunctionType::get(Builder.getVoidTy(), {Builder.getPtrTy()}, false);
6689251edeSMichael Kruse   Function *SubFn = Function::Create(FT, Function::InternalLinkage,
6789251edeSMichael Kruse                                      F->getName() + "_polly_subfn", M);
6889251edeSMichael Kruse   // Name the function's arguments
6989251edeSMichael Kruse   SubFn->arg_begin()->setName("polly.par.userContext");
7089251edeSMichael Kruse   return SubFn;
7189251edeSMichael Kruse }
7289251edeSMichael Kruse 
7389251edeSMichael Kruse // Create a subfunction of the following (preliminary) structure:
7489251edeSMichael Kruse //
7589251edeSMichael Kruse //    PrevBB
7689251edeSMichael Kruse //       |
7789251edeSMichael Kruse //       v
7889251edeSMichael Kruse //    HeaderBB
7989251edeSMichael Kruse //       |   _____
8089251edeSMichael Kruse //       v  v    |
8189251edeSMichael Kruse //   CheckNextBB  PreHeaderBB
8289251edeSMichael Kruse //       |\       |
8389251edeSMichael Kruse //       | \______/
8489251edeSMichael Kruse //       |
8589251edeSMichael Kruse //       v
8689251edeSMichael Kruse //     ExitBB
8789251edeSMichael Kruse //
8889251edeSMichael Kruse // HeaderBB will hold allocations and loading of variables.
8989251edeSMichael Kruse // CheckNextBB will check for more work.
9089251edeSMichael Kruse // If there is more work to do: go to PreHeaderBB, otherwise go to ExitBB.
9189251edeSMichael Kruse // PreHeaderBB loads the new boundaries (& will lead to the loop body later on).
9289251edeSMichael Kruse // ExitBB marks the end of the parallel execution.
9389251edeSMichael Kruse std::tuple<Value *, Function *>
9489251edeSMichael Kruse ParallelLoopGeneratorGOMP::createSubFn(Value *Stride, AllocaInst *StructData,
9589251edeSMichael Kruse                                        SetVector<Value *> Data,
9689251edeSMichael Kruse                                        ValueMapT &Map) {
9789251edeSMichael Kruse   if (PollyScheduling != OMPGeneralSchedulingType::Runtime) {
9889251edeSMichael Kruse     // User tried to influence the scheduling type (currently not supported)
9989251edeSMichael Kruse     errs() << "warning: Polly's GNU OpenMP backend solely "
10089251edeSMichael Kruse               "supports the scheduling type 'runtime'.\n";
10189251edeSMichael Kruse   }
10289251edeSMichael Kruse 
10389251edeSMichael Kruse   if (PollyChunkSize != 0) {
10489251edeSMichael Kruse     // User tried to influence the chunk size (currently not supported)
10589251edeSMichael Kruse     errs() << "warning: Polly's GNU OpenMP backend solely "
10689251edeSMichael Kruse               "supports the default chunk size.\n";
10789251edeSMichael Kruse   }
10889251edeSMichael Kruse 
10989251edeSMichael Kruse   Function *SubFn = createSubFnDefinition();
11089251edeSMichael Kruse   LLVMContext &Context = SubFn->getContext();
11189251edeSMichael Kruse 
11289251edeSMichael Kruse   // Create basic blocks.
11389251edeSMichael Kruse   BasicBlock *HeaderBB = BasicBlock::Create(Context, "polly.par.setup", SubFn);
11422c77f23SMichael Kruse   SubFnDT = std::make_unique<DominatorTree>(*SubFn);
11522c77f23SMichael Kruse   SubFnLI = std::make_unique<LoopInfo>(*SubFnDT);
11622c77f23SMichael Kruse 
11789251edeSMichael Kruse   BasicBlock *ExitBB = BasicBlock::Create(Context, "polly.par.exit", SubFn);
11889251edeSMichael Kruse   BasicBlock *CheckNextBB =
11989251edeSMichael Kruse       BasicBlock::Create(Context, "polly.par.checkNext", SubFn);
12089251edeSMichael Kruse   BasicBlock *PreHeaderBB =
12189251edeSMichael Kruse       BasicBlock::Create(Context, "polly.par.loadIVBounds", SubFn);
12289251edeSMichael Kruse 
12322c77f23SMichael Kruse   SubFnDT->addNewBlock(ExitBB, HeaderBB);
12422c77f23SMichael Kruse   SubFnDT->addNewBlock(CheckNextBB, HeaderBB);
12522c77f23SMichael Kruse   SubFnDT->addNewBlock(PreHeaderBB, HeaderBB);
12689251edeSMichael Kruse 
12789251edeSMichael Kruse   // Fill up basic block HeaderBB.
12889251edeSMichael Kruse   Builder.SetInsertPoint(HeaderBB);
12989251edeSMichael Kruse   Value *LBPtr = Builder.CreateAlloca(LongType, nullptr, "polly.par.LBPtr");
13089251edeSMichael Kruse   Value *UBPtr = Builder.CreateAlloca(LongType, nullptr, "polly.par.UBPtr");
13118680a36SNikita Popov   Value *UserContext = &*SubFn->arg_begin();
13289251edeSMichael Kruse 
13389251edeSMichael Kruse   extractValuesFromStruct(Data, StructData->getAllocatedType(), UserContext,
13489251edeSMichael Kruse                           Map);
13589251edeSMichael Kruse   Builder.CreateBr(CheckNextBB);
13689251edeSMichael Kruse 
13789251edeSMichael Kruse   // Add code to check if another set of iterations will be executed.
13889251edeSMichael Kruse   Builder.SetInsertPoint(CheckNextBB);
13989251edeSMichael Kruse   Value *Next = createCallGetWorkItem(LBPtr, UBPtr);
14089251edeSMichael Kruse   Value *HasNextSchedule = Builder.CreateTrunc(
14189251edeSMichael Kruse       Next, Builder.getInt1Ty(), "polly.par.hasNextScheduleBlock");
14289251edeSMichael Kruse   Builder.CreateCondBr(HasNextSchedule, PreHeaderBB, ExitBB);
14389251edeSMichael Kruse 
14489251edeSMichael Kruse   // Add code to load the iv bounds for this set of iterations.
14589251edeSMichael Kruse   Builder.SetInsertPoint(PreHeaderBB);
14646354bacSNikita Popov   Value *LB = Builder.CreateLoad(LongType, LBPtr, "polly.par.LB");
14746354bacSNikita Popov   Value *UB = Builder.CreateLoad(LongType, UBPtr, "polly.par.UB");
14889251edeSMichael Kruse 
14989251edeSMichael Kruse   // Subtract one as the upper bound provided by OpenMP is a < comparison
15089251edeSMichael Kruse   // whereas the codegenForSequential function creates a <= comparison.
15189251edeSMichael Kruse   UB = Builder.CreateSub(UB, ConstantInt::get(LongType, 1),
15289251edeSMichael Kruse                          "polly.par.UBAdjusted");
15389251edeSMichael Kruse 
15489251edeSMichael Kruse   Builder.CreateBr(CheckNextBB);
15589251edeSMichael Kruse   Builder.SetInsertPoint(&*--Builder.GetInsertPoint());
15689251edeSMichael Kruse   BasicBlock *AfterBB;
15789251edeSMichael Kruse   Value *IV =
15822c77f23SMichael Kruse       createLoop(LB, UB, Stride, Builder, *SubFnLI, *SubFnDT, AfterBB,
15922c77f23SMichael Kruse                  ICmpInst::ICMP_SLE, nullptr, true, /* UseGuard */ false);
16089251edeSMichael Kruse 
16189251edeSMichael Kruse   BasicBlock::iterator LoopBody = Builder.GetInsertPoint();
16289251edeSMichael Kruse 
16389251edeSMichael Kruse   // Add code to terminate this subfunction.
16489251edeSMichael Kruse   Builder.SetInsertPoint(ExitBB);
16589251edeSMichael Kruse   createCallCleanupThread();
16689251edeSMichael Kruse   Builder.CreateRetVoid();
16789251edeSMichael Kruse 
16889251edeSMichael Kruse   Builder.SetInsertPoint(&*LoopBody);
16989251edeSMichael Kruse 
17022c77f23SMichael Kruse   // FIXME: Call SubFnDT->verify() and SubFnLI->verify() to check that the
17122c77f23SMichael Kruse   // DominatorTree/LoopInfo has been created correctly. Alternatively, recreate
17222c77f23SMichael Kruse   // from scratch since it is not needed here directly.
17322c77f23SMichael Kruse 
17489251edeSMichael Kruse   return std::make_tuple(IV, SubFn);
17589251edeSMichael Kruse }
17689251edeSMichael Kruse 
17789251edeSMichael Kruse Value *ParallelLoopGeneratorGOMP::createCallGetWorkItem(Value *LBPtr,
17889251edeSMichael Kruse                                                         Value *UBPtr) {
17989251edeSMichael Kruse   const std::string Name = "GOMP_loop_runtime_next";
18089251edeSMichael Kruse 
18189251edeSMichael Kruse   Function *F = M->getFunction(Name);
18289251edeSMichael Kruse 
18389251edeSMichael Kruse   // If F is not available, declare it.
18489251edeSMichael Kruse   if (!F) {
18589251edeSMichael Kruse     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
186*467a9bdeSYoungsuk Kim     Type *Params[] = {Builder.getPtrTy(0), Builder.getPtrTy(0)};
18789251edeSMichael Kruse     FunctionType *Ty = FunctionType::get(Builder.getInt8Ty(), Params, false);
18889251edeSMichael Kruse     F = Function::Create(Ty, Linkage, Name, M);
18989251edeSMichael Kruse   }
19089251edeSMichael Kruse 
19189251edeSMichael Kruse   Value *Args[] = {LBPtr, UBPtr};
192fe0e5b3eSMichael Kruse   CallInst *Call = Builder.CreateCall(F, Args);
193fe0e5b3eSMichael Kruse   Call->setDebugLoc(DLGenerated);
194fe0e5b3eSMichael Kruse   Value *Return = Builder.CreateICmpNE(
195fe0e5b3eSMichael Kruse       Call, Builder.CreateZExt(Builder.getFalse(), Call->getType()));
19689251edeSMichael Kruse   return Return;
19789251edeSMichael Kruse }
19889251edeSMichael Kruse 
19989251edeSMichael Kruse void ParallelLoopGeneratorGOMP::createCallJoinThreads() {
20089251edeSMichael Kruse   const std::string Name = "GOMP_parallel_end";
20189251edeSMichael Kruse 
20289251edeSMichael Kruse   Function *F = M->getFunction(Name);
20389251edeSMichael Kruse 
20489251edeSMichael Kruse   // If F is not available, declare it.
20589251edeSMichael Kruse   if (!F) {
20689251edeSMichael Kruse     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
20789251edeSMichael Kruse 
20889251edeSMichael Kruse     FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), false);
20989251edeSMichael Kruse     F = Function::Create(Ty, Linkage, Name, M);
21089251edeSMichael Kruse   }
21189251edeSMichael Kruse 
212fe0e5b3eSMichael Kruse   CallInst *Call = Builder.CreateCall(F, {});
213fe0e5b3eSMichael Kruse   Call->setDebugLoc(DLGenerated);
21489251edeSMichael Kruse }
21589251edeSMichael Kruse 
21689251edeSMichael Kruse void ParallelLoopGeneratorGOMP::createCallCleanupThread() {
21789251edeSMichael Kruse   const std::string Name = "GOMP_loop_end_nowait";
21889251edeSMichael Kruse 
21989251edeSMichael Kruse   Function *F = M->getFunction(Name);
22089251edeSMichael Kruse 
22189251edeSMichael Kruse   // If F is not available, declare it.
22289251edeSMichael Kruse   if (!F) {
22389251edeSMichael Kruse     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
22489251edeSMichael Kruse 
22589251edeSMichael Kruse     FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), false);
22689251edeSMichael Kruse     F = Function::Create(Ty, Linkage, Name, M);
22789251edeSMichael Kruse   }
22889251edeSMichael Kruse 
229fe0e5b3eSMichael Kruse   CallInst *Call = Builder.CreateCall(F, {});
230fe0e5b3eSMichael Kruse   Call->setDebugLoc(DLGenerated);
23189251edeSMichael Kruse }
232