/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/polly/lib/CodeGen/LoopGeneratorsGOMP.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===------ LoopGeneratorsGOMP.cpp - IR helper to create loops ------------===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | // |
9 | | // This file contains functions to create parallel loops as LLVM-IR. |
10 | | // |
11 | | //===----------------------------------------------------------------------===// |
12 | | |
13 | | #include "polly/CodeGen/LoopGeneratorsGOMP.h" |
14 | | #include "llvm/IR/Dominators.h" |
15 | | #include "llvm/IR/Module.h" |
16 | | |
17 | | using namespace llvm; |
18 | | using namespace polly; |
19 | | |
20 | | void ParallelLoopGeneratorGOMP::createCallSpawnThreads(Value *SubFn, |
21 | | Value *SubFnParam, |
22 | | Value *LB, Value *UB, |
23 | 31 | Value *Stride) { |
24 | 31 | const std::string Name = "GOMP_parallel_loop_runtime_start"; |
25 | 31 | |
26 | 31 | Function *F = M->getFunction(Name); |
27 | 31 | |
28 | 31 | // If F is not available, declare it. |
29 | 31 | if (!F) { |
30 | 28 | GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; |
31 | 28 | |
32 | 28 | Type *Params[] = {PointerType::getUnqual(FunctionType::get( |
33 | 28 | Builder.getVoidTy(), Builder.getInt8PtrTy(), false)), |
34 | 28 | Builder.getInt8PtrTy(), |
35 | 28 | Builder.getInt32Ty(), |
36 | 28 | LongType, |
37 | 28 | LongType, |
38 | 28 | LongType}; |
39 | 28 | |
40 | 28 | FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Params, false); |
41 | 28 | F = Function::Create(Ty, Linkage, Name, M); |
42 | 28 | } |
43 | 31 | |
44 | 31 | Value *Args[] = {SubFn, SubFnParam, Builder.getInt32(PollyNumThreads), |
45 | 31 | LB, UB, Stride}; |
46 | 31 | |
47 | 31 | Builder.CreateCall(F, Args); |
48 | 31 | } |
49 | | |
50 | | void ParallelLoopGeneratorGOMP::deployParallelExecution(Value *SubFn, |
51 | | Value *SubFnParam, |
52 | | Value *LB, Value *UB, |
53 | 31 | Value *Stride) { |
54 | 31 | // Tell the runtime we start a parallel loop |
55 | 31 | createCallSpawnThreads(SubFn, SubFnParam, LB, UB, Stride); |
56 | 31 | Builder.CreateCall(SubFn, SubFnParam); |
57 | 31 | createCallJoinThreads(); |
58 | 31 | } |
59 | | |
60 | 31 | Function *ParallelLoopGeneratorGOMP::prepareSubFnDefinition(Function *F) const { |
61 | 31 | FunctionType *FT = |
62 | 31 | FunctionType::get(Builder.getVoidTy(), {Builder.getInt8PtrTy()}, false); |
63 | 31 | Function *SubFn = Function::Create(FT, Function::InternalLinkage, |
64 | 31 | F->getName() + "_polly_subfn", M); |
65 | 31 | // Name the function's arguments |
66 | 31 | SubFn->arg_begin()->setName("polly.par.userContext"); |
67 | 31 | return SubFn; |
68 | 31 | } |
69 | | |
70 | | // Create a subfunction of the following (preliminary) structure: |
71 | | // |
72 | | // PrevBB |
73 | | // | |
74 | | // v |
75 | | // HeaderBB |
76 | | // | _____ |
77 | | // v v | |
78 | | // CheckNextBB PreHeaderBB |
79 | | // |\ | |
80 | | // | \______/ |
81 | | // | |
82 | | // v |
83 | | // ExitBB |
84 | | // |
85 | | // HeaderBB will hold allocations and loading of variables. |
86 | | // CheckNextBB will check for more work. |
87 | | // If there is more work to do: go to PreHeaderBB, otherwise go to ExitBB. |
88 | | // PreHeaderBB loads the new boundaries (& will lead to the loop body later on). |
89 | | // ExitBB marks the end of the parallel execution. |
90 | | std::tuple<Value *, Function *> |
91 | | ParallelLoopGeneratorGOMP::createSubFn(Value *Stride, AllocaInst *StructData, |
92 | | SetVector<Value *> Data, |
93 | 31 | ValueMapT &Map) { |
94 | 31 | if (PollyScheduling != OMPGeneralSchedulingType::Runtime) { |
95 | 0 | // User tried to influence the scheduling type (currently not supported) |
96 | 0 | errs() << "warning: Polly's GNU OpenMP backend solely " |
97 | 0 | "supports the scheduling type 'runtime'.\n"; |
98 | 0 | } |
99 | 31 | |
100 | 31 | if (PollyChunkSize != 0) { |
101 | 0 | // User tried to influence the chunk size (currently not supported) |
102 | 0 | errs() << "warning: Polly's GNU OpenMP backend solely " |
103 | 0 | "supports the default chunk size.\n"; |
104 | 0 | } |
105 | 31 | |
106 | 31 | Function *SubFn = createSubFnDefinition(); |
107 | 31 | LLVMContext &Context = SubFn->getContext(); |
108 | 31 | |
109 | 31 | // Store the previous basic block. |
110 | 31 | BasicBlock *PrevBB = Builder.GetInsertBlock(); |
111 | 31 | |
112 | 31 | // Create basic blocks. |
113 | 31 | BasicBlock *HeaderBB = BasicBlock::Create(Context, "polly.par.setup", SubFn); |
114 | 31 | BasicBlock *ExitBB = BasicBlock::Create(Context, "polly.par.exit", SubFn); |
115 | 31 | BasicBlock *CheckNextBB = |
116 | 31 | BasicBlock::Create(Context, "polly.par.checkNext", SubFn); |
117 | 31 | BasicBlock *PreHeaderBB = |
118 | 31 | BasicBlock::Create(Context, "polly.par.loadIVBounds", SubFn); |
119 | 31 | |
120 | 31 | DT.addNewBlock(HeaderBB, PrevBB); |
121 | 31 | DT.addNewBlock(ExitBB, HeaderBB); |
122 | 31 | DT.addNewBlock(CheckNextBB, HeaderBB); |
123 | 31 | DT.addNewBlock(PreHeaderBB, HeaderBB); |
124 | 31 | |
125 | 31 | // Fill up basic block HeaderBB. |
126 | 31 | Builder.SetInsertPoint(HeaderBB); |
127 | 31 | Value *LBPtr = Builder.CreateAlloca(LongType, nullptr, "polly.par.LBPtr"); |
128 | 31 | Value *UBPtr = Builder.CreateAlloca(LongType, nullptr, "polly.par.UBPtr"); |
129 | 31 | Value *UserContext = Builder.CreateBitCast( |
130 | 31 | &*SubFn->arg_begin(), StructData->getType(), "polly.par.userContext"); |
131 | 31 | |
132 | 31 | extractValuesFromStruct(Data, StructData->getAllocatedType(), UserContext, |
133 | 31 | Map); |
134 | 31 | Builder.CreateBr(CheckNextBB); |
135 | 31 | |
136 | 31 | // Add code to check if another set of iterations will be executed. |
137 | 31 | Builder.SetInsertPoint(CheckNextBB); |
138 | 31 | Value *Next = createCallGetWorkItem(LBPtr, UBPtr); |
139 | 31 | Value *HasNextSchedule = Builder.CreateTrunc( |
140 | 31 | Next, Builder.getInt1Ty(), "polly.par.hasNextScheduleBlock"); |
141 | 31 | Builder.CreateCondBr(HasNextSchedule, PreHeaderBB, ExitBB); |
142 | 31 | |
143 | 31 | // Add code to load the iv bounds for this set of iterations. |
144 | 31 | Builder.SetInsertPoint(PreHeaderBB); |
145 | 31 | Value *LB = Builder.CreateLoad(LBPtr, "polly.par.LB"); |
146 | 31 | Value *UB = Builder.CreateLoad(UBPtr, "polly.par.UB"); |
147 | 31 | |
148 | 31 | // Subtract one as the upper bound provided by OpenMP is a < comparison |
149 | 31 | // whereas the codegenForSequential function creates a <= comparison. |
150 | 31 | UB = Builder.CreateSub(UB, ConstantInt::get(LongType, 1), |
151 | 31 | "polly.par.UBAdjusted"); |
152 | 31 | |
153 | 31 | Builder.CreateBr(CheckNextBB); |
154 | 31 | Builder.SetInsertPoint(&*--Builder.GetInsertPoint()); |
155 | 31 | BasicBlock *AfterBB; |
156 | 31 | Value *IV = |
157 | 31 | createLoop(LB, UB, Stride, Builder, LI, DT, AfterBB, ICmpInst::ICMP_SLE, |
158 | 31 | nullptr, true, /* UseGuard */ false); |
159 | 31 | |
160 | 31 | BasicBlock::iterator LoopBody = Builder.GetInsertPoint(); |
161 | 31 | |
162 | 31 | // Add code to terminate this subfunction. |
163 | 31 | Builder.SetInsertPoint(ExitBB); |
164 | 31 | createCallCleanupThread(); |
165 | 31 | Builder.CreateRetVoid(); |
166 | 31 | |
167 | 31 | Builder.SetInsertPoint(&*LoopBody); |
168 | 31 | |
169 | 31 | return std::make_tuple(IV, SubFn); |
170 | 31 | } |
171 | | |
172 | | Value *ParallelLoopGeneratorGOMP::createCallGetWorkItem(Value *LBPtr, |
173 | 31 | Value *UBPtr) { |
174 | 31 | const std::string Name = "GOMP_loop_runtime_next"; |
175 | 31 | |
176 | 31 | Function *F = M->getFunction(Name); |
177 | 31 | |
178 | 31 | // If F is not available, declare it. |
179 | 31 | if (!F) { |
180 | 28 | GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; |
181 | 28 | Type *Params[] = {LongType->getPointerTo(), LongType->getPointerTo()}; |
182 | 28 | FunctionType *Ty = FunctionType::get(Builder.getInt8Ty(), Params, false); |
183 | 28 | F = Function::Create(Ty, Linkage, Name, M); |
184 | 28 | } |
185 | 31 | |
186 | 31 | Value *Args[] = {LBPtr, UBPtr}; |
187 | 31 | Value *Return = Builder.CreateCall(F, Args); |
188 | 31 | Return = Builder.CreateICmpNE( |
189 | 31 | Return, Builder.CreateZExt(Builder.getFalse(), Return->getType())); |
190 | 31 | return Return; |
191 | 31 | } |
192 | | |
193 | 31 | void ParallelLoopGeneratorGOMP::createCallJoinThreads() { |
194 | 31 | const std::string Name = "GOMP_parallel_end"; |
195 | 31 | |
196 | 31 | Function *F = M->getFunction(Name); |
197 | 31 | |
198 | 31 | // If F is not available, declare it. |
199 | 31 | if (!F) { |
200 | 28 | GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; |
201 | 28 | |
202 | 28 | FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), false); |
203 | 28 | F = Function::Create(Ty, Linkage, Name, M); |
204 | 28 | } |
205 | 31 | |
206 | 31 | Builder.CreateCall(F, {}); |
207 | 31 | } |
208 | | |
209 | 31 | void ParallelLoopGeneratorGOMP::createCallCleanupThread() { |
210 | 31 | const std::string Name = "GOMP_loop_end_nowait"; |
211 | 31 | |
212 | 31 | Function *F = M->getFunction(Name); |
213 | 31 | |
214 | 31 | // If F is not available, declare it. |
215 | 31 | if (!F) { |
216 | 28 | GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; |
217 | 28 | |
218 | 28 | FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), false); |
219 | 28 | F = Function::Create(Ty, Linkage, Name, M); |
220 | 28 | } |
221 | 31 | |
222 | 31 | Builder.CreateCall(F, {}); |
223 | 31 | } |