/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/polly/lib/CodeGen/LoopGeneratorsKMP.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===------ LoopGeneratorsKMP.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/LoopGeneratorsKMP.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 ParallelLoopGeneratorKMP::createCallSpawnThreads(Value *SubFn, |
21 | | Value *SubFnParam, |
22 | | Value *LB, Value *UB, |
23 | 10 | Value *Stride) { |
24 | 10 | const std::string Name = "__kmpc_fork_call"; |
25 | 10 | Function *F = M->getFunction(Name); |
26 | 10 | Type *KMPCMicroTy = M->getTypeByName("kmpc_micro"); |
27 | 10 | |
28 | 10 | if (!KMPCMicroTy) { |
29 | 10 | // void (*kmpc_micro)(kmp_int32 *global_tid, kmp_int32 *bound_tid, ...) |
30 | 10 | Type *MicroParams[] = {Builder.getInt32Ty()->getPointerTo(), |
31 | 10 | Builder.getInt32Ty()->getPointerTo()}; |
32 | 10 | |
33 | 10 | KMPCMicroTy = FunctionType::get(Builder.getVoidTy(), MicroParams, true); |
34 | 10 | } |
35 | 10 | |
36 | 10 | // If F is not available, declare it. |
37 | 10 | if (!F) { |
38 | 10 | StructType *IdentTy = M->getTypeByName("struct.ident_t"); |
39 | 10 | |
40 | 10 | GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; |
41 | 10 | Type *Params[] = {IdentTy->getPointerTo(), Builder.getInt32Ty(), |
42 | 10 | KMPCMicroTy->getPointerTo()}; |
43 | 10 | |
44 | 10 | FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Params, true); |
45 | 10 | F = Function::Create(Ty, Linkage, Name, M); |
46 | 10 | } |
47 | 10 | |
48 | 10 | Value *Task = Builder.CreatePointerBitCastOrAddrSpaceCast( |
49 | 10 | SubFn, KMPCMicroTy->getPointerTo()); |
50 | 10 | |
51 | 10 | Value *Args[] = {SourceLocationInfo, |
52 | 10 | Builder.getInt32(4) /* Number of arguments (w/o Task) */, |
53 | 10 | Task, |
54 | 10 | LB, |
55 | 10 | UB, |
56 | 10 | Stride, |
57 | 10 | SubFnParam}; |
58 | 10 | |
59 | 10 | Builder.CreateCall(F, Args); |
60 | 10 | } |
61 | | |
62 | | void ParallelLoopGeneratorKMP::deployParallelExecution(Value *SubFn, |
63 | | Value *SubFnParam, |
64 | | Value *LB, Value *UB, |
65 | 10 | Value *Stride) { |
66 | 10 | // Inform OpenMP runtime about the number of threads if greater than zero |
67 | 10 | if (PollyNumThreads > 0) { |
68 | 2 | Value *GlobalThreadID = createCallGlobalThreadNum(); |
69 | 2 | createCallPushNumThreads(GlobalThreadID, Builder.getInt32(PollyNumThreads)); |
70 | 2 | } |
71 | 10 | |
72 | 10 | // Tell the runtime we start a parallel loop |
73 | 10 | createCallSpawnThreads(SubFn, SubFnParam, LB, UB, Stride); |
74 | 10 | } |
75 | | |
76 | 10 | Function *ParallelLoopGeneratorKMP::prepareSubFnDefinition(Function *F) const { |
77 | 10 | std::vector<Type *> Arguments = {Builder.getInt32Ty()->getPointerTo(), |
78 | 10 | Builder.getInt32Ty()->getPointerTo(), |
79 | 10 | LongType, |
80 | 10 | LongType, |
81 | 10 | LongType, |
82 | 10 | Builder.getInt8PtrTy()}; |
83 | 10 | |
84 | 10 | FunctionType *FT = FunctionType::get(Builder.getVoidTy(), Arguments, false); |
85 | 10 | Function *SubFn = Function::Create(FT, Function::InternalLinkage, |
86 | 10 | F->getName() + "_polly_subfn", M); |
87 | 10 | // Name the function's arguments |
88 | 10 | Function::arg_iterator AI = SubFn->arg_begin(); |
89 | 10 | AI->setName("polly.kmpc.global_tid"); |
90 | 10 | std::advance(AI, 1); |
91 | 10 | AI->setName("polly.kmpc.bound_tid"); |
92 | 10 | std::advance(AI, 1); |
93 | 10 | AI->setName("polly.kmpc.lb"); |
94 | 10 | std::advance(AI, 1); |
95 | 10 | AI->setName("polly.kmpc.ub"); |
96 | 10 | std::advance(AI, 1); |
97 | 10 | AI->setName("polly.kmpc.inc"); |
98 | 10 | std::advance(AI, 1); |
99 | 10 | AI->setName("polly.kmpc.shared"); |
100 | 10 | |
101 | 10 | return SubFn; |
102 | 10 | } |
103 | | |
104 | | // Create a subfunction of the following (preliminary) structure: |
105 | | // |
106 | | // PrevBB |
107 | | // | |
108 | | // v |
109 | | // HeaderBB |
110 | | // | _____ |
111 | | // v v | |
112 | | // CheckNextBB PreHeaderBB |
113 | | // |\ | |
114 | | // | \______/ |
115 | | // | |
116 | | // v |
117 | | // ExitBB |
118 | | // |
119 | | // HeaderBB will hold allocations, loading of variables and kmp-init calls. |
120 | | // CheckNextBB will check for more work (dynamic) or will be "empty" (static). |
121 | | // If there is more work to do: go to PreHeaderBB, otherwise go to ExitBB. |
122 | | // PreHeaderBB loads the new boundaries (& will lead to the loop body later on). |
123 | | // Just like CheckNextBB: PreHeaderBB is empty in the static scheduling case. |
124 | | // ExitBB marks the end of the parallel execution. |
125 | | // The possibly empty BasicBlocks will automatically be removed. |
126 | | std::tuple<Value *, Function *> |
127 | | ParallelLoopGeneratorKMP::createSubFn(Value *StrideNotUsed, |
128 | | AllocaInst *StructData, |
129 | 10 | SetVector<Value *> Data, ValueMapT &Map) { |
130 | 10 | Function *SubFn = createSubFnDefinition(); |
131 | 10 | LLVMContext &Context = SubFn->getContext(); |
132 | 10 | |
133 | 10 | // Store the previous basic block. |
134 | 10 | BasicBlock *PrevBB = Builder.GetInsertBlock(); |
135 | 10 | |
136 | 10 | // Create basic blocks. |
137 | 10 | BasicBlock *HeaderBB = BasicBlock::Create(Context, "polly.par.setup", SubFn); |
138 | 10 | BasicBlock *ExitBB = BasicBlock::Create(Context, "polly.par.exit", SubFn); |
139 | 10 | BasicBlock *CheckNextBB = |
140 | 10 | BasicBlock::Create(Context, "polly.par.checkNext", SubFn); |
141 | 10 | BasicBlock *PreHeaderBB = |
142 | 10 | BasicBlock::Create(Context, "polly.par.loadIVBounds", SubFn); |
143 | 10 | |
144 | 10 | DT.addNewBlock(HeaderBB, PrevBB); |
145 | 10 | DT.addNewBlock(ExitBB, HeaderBB); |
146 | 10 | DT.addNewBlock(CheckNextBB, HeaderBB); |
147 | 10 | DT.addNewBlock(PreHeaderBB, HeaderBB); |
148 | 10 | |
149 | 10 | // Fill up basic block HeaderBB. |
150 | 10 | Builder.SetInsertPoint(HeaderBB); |
151 | 10 | Value *LBPtr = Builder.CreateAlloca(LongType, nullptr, "polly.par.LBPtr"); |
152 | 10 | Value *UBPtr = Builder.CreateAlloca(LongType, nullptr, "polly.par.UBPtr"); |
153 | 10 | Value *IsLastPtr = Builder.CreateAlloca(Builder.getInt32Ty(), nullptr, |
154 | 10 | "polly.par.lastIterPtr"); |
155 | 10 | Value *StridePtr = |
156 | 10 | Builder.CreateAlloca(LongType, nullptr, "polly.par.StridePtr"); |
157 | 10 | |
158 | 10 | // Get iterator for retrieving the previously defined parameters. |
159 | 10 | Function::arg_iterator AI = SubFn->arg_begin(); |
160 | 10 | // First argument holds "global thread ID". |
161 | 10 | Value *IDPtr = &*AI; |
162 | 10 | // Skip "bound thread ID" since it is not used (but had to be defined). |
163 | 10 | std::advance(AI, 2); |
164 | 10 | // Move iterator to: LB, UB, Stride, Shared variable struct. |
165 | 10 | Value *LB = &*AI; |
166 | 10 | std::advance(AI, 1); |
167 | 10 | Value *UB = &*AI; |
168 | 10 | std::advance(AI, 1); |
169 | 10 | Value *Stride = &*AI; |
170 | 10 | std::advance(AI, 1); |
171 | 10 | Value *Shared = &*AI; |
172 | 10 | |
173 | 10 | Value *UserContext = Builder.CreateBitCast(Shared, StructData->getType(), |
174 | 10 | "polly.par.userContext"); |
175 | 10 | |
176 | 10 | extractValuesFromStruct(Data, StructData->getAllocatedType(), UserContext, |
177 | 10 | Map); |
178 | 10 | |
179 | 10 | const int Alignment = (is64BitArch()) ? 8 : 40 ; |
180 | 10 | Value *ID = |
181 | 10 | Builder.CreateAlignedLoad(IDPtr, Alignment, "polly.par.global_tid"); |
182 | 10 | |
183 | 10 | Builder.CreateAlignedStore(LB, LBPtr, Alignment); |
184 | 10 | Builder.CreateAlignedStore(UB, UBPtr, Alignment); |
185 | 10 | Builder.CreateAlignedStore(Builder.getInt32(0), IsLastPtr, Alignment); |
186 | 10 | Builder.CreateAlignedStore(Stride, StridePtr, Alignment); |
187 | 10 | |
188 | 10 | // Subtract one as the upper bound provided by openmp is a < comparison |
189 | 10 | // whereas the codegenForSequential function creates a <= comparison. |
190 | 10 | Value *AdjustedUB = Builder.CreateAdd(UB, ConstantInt::get(LongType, -1), |
191 | 10 | "polly.indvar.UBAdjusted"); |
192 | 10 | |
193 | 10 | Value *ChunkSize = |
194 | 10 | ConstantInt::get(LongType, std::max<int>(PollyChunkSize, 1)); |
195 | 10 | |
196 | 10 | switch (PollyScheduling) { |
197 | 10 | case OMPGeneralSchedulingType::Dynamic: |
198 | 8 | case OMPGeneralSchedulingType::Guided: |
199 | 8 | case OMPGeneralSchedulingType::Runtime: |
200 | 8 | // "DYNAMIC" scheduling types are handled below (including 'runtime') |
201 | 8 | { |
202 | 8 | UB = AdjustedUB; |
203 | 8 | createCallDispatchInit(ID, LB, UB, Stride, ChunkSize); |
204 | 8 | Value *HasWork = |
205 | 8 | createCallDispatchNext(ID, IsLastPtr, LBPtr, UBPtr, StridePtr); |
206 | 8 | Value *HasIteration = |
207 | 8 | Builder.CreateICmp(llvm::CmpInst::Predicate::ICMP_EQ, HasWork, |
208 | 8 | Builder.getInt32(1), "polly.hasIteration"); |
209 | 8 | Builder.CreateCondBr(HasIteration, PreHeaderBB, ExitBB); |
210 | 8 | |
211 | 8 | Builder.SetInsertPoint(CheckNextBB); |
212 | 8 | HasWork = createCallDispatchNext(ID, IsLastPtr, LBPtr, UBPtr, StridePtr); |
213 | 8 | HasIteration = |
214 | 8 | Builder.CreateICmp(llvm::CmpInst::Predicate::ICMP_EQ, HasWork, |
215 | 8 | Builder.getInt32(1), "polly.hasWork"); |
216 | 8 | Builder.CreateCondBr(HasIteration, PreHeaderBB, ExitBB); |
217 | 8 | |
218 | 8 | Builder.SetInsertPoint(PreHeaderBB); |
219 | 8 | LB = Builder.CreateAlignedLoad(LBPtr, Alignment, "polly.indvar.LB"); |
220 | 8 | UB = Builder.CreateAlignedLoad(UBPtr, Alignment, "polly.indvar.UB"); |
221 | 8 | } |
222 | 8 | break; |
223 | 8 | case OMPGeneralSchedulingType::StaticChunked: |
224 | 2 | case OMPGeneralSchedulingType::StaticNonChunked: |
225 | 2 | // "STATIC" scheduling types are handled below |
226 | 2 | { |
227 | 2 | createCallStaticInit(ID, IsLastPtr, LBPtr, UBPtr, StridePtr, ChunkSize); |
228 | 2 | |
229 | 2 | LB = Builder.CreateAlignedLoad(LBPtr, Alignment, "polly.indvar.LB"); |
230 | 2 | UB = Builder.CreateAlignedLoad(UBPtr, Alignment, "polly.indvar.UB"); |
231 | 2 | |
232 | 2 | Value *AdjUBOutOfBounds = |
233 | 2 | Builder.CreateICmp(llvm::CmpInst::Predicate::ICMP_SLT, UB, AdjustedUB, |
234 | 2 | "polly.adjustedUBOutOfBounds"); |
235 | 2 | |
236 | 2 | UB = Builder.CreateSelect(AdjUBOutOfBounds, UB, AdjustedUB); |
237 | 2 | Builder.CreateAlignedStore(UB, UBPtr, Alignment); |
238 | 2 | |
239 | 2 | Value *HasIteration = Builder.CreateICmp( |
240 | 2 | llvm::CmpInst::Predicate::ICMP_SLE, LB, UB, "polly.hasIteration"); |
241 | 2 | Builder.CreateCondBr(HasIteration, PreHeaderBB, ExitBB); |
242 | 2 | |
243 | 2 | Builder.SetInsertPoint(CheckNextBB); |
244 | 2 | Builder.CreateBr(ExitBB); |
245 | 2 | |
246 | 2 | Builder.SetInsertPoint(PreHeaderBB); |
247 | 2 | } |
248 | 2 | break; |
249 | 10 | } |
250 | 10 | |
251 | 10 | Builder.CreateBr(CheckNextBB); |
252 | 10 | Builder.SetInsertPoint(&*--Builder.GetInsertPoint()); |
253 | 10 | BasicBlock *AfterBB; |
254 | 10 | Value *IV = createLoop(LB, UB, Stride, Builder, LI, DT, AfterBB, |
255 | 10 | ICmpInst::ICMP_SLE, nullptr, true, |
256 | 10 | /* UseGuard */ false); |
257 | 10 | |
258 | 10 | BasicBlock::iterator LoopBody = Builder.GetInsertPoint(); |
259 | 10 | |
260 | 10 | // Add code to terminate this subfunction. |
261 | 10 | Builder.SetInsertPoint(ExitBB); |
262 | 10 | // Static (i.e. non-dynamic) scheduling types, are terminated with a fini-call |
263 | 10 | if (PollyScheduling == OMPGeneralSchedulingType::StaticChunked) { |
264 | 2 | createCallStaticFini(ID); |
265 | 2 | } |
266 | 10 | Builder.CreateRetVoid(); |
267 | 10 | Builder.SetInsertPoint(&*LoopBody); |
268 | 10 | |
269 | 10 | return std::make_tuple(IV, SubFn); |
270 | 10 | } |
271 | | |
272 | 2 | Value *ParallelLoopGeneratorKMP::createCallGlobalThreadNum() { |
273 | 2 | const std::string Name = "__kmpc_global_thread_num"; |
274 | 2 | Function *F = M->getFunction(Name); |
275 | 2 | |
276 | 2 | // If F is not available, declare it. |
277 | 2 | if (!F) { |
278 | 2 | StructType *IdentTy = M->getTypeByName("struct.ident_t"); |
279 | 2 | |
280 | 2 | GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; |
281 | 2 | Type *Params[] = {IdentTy->getPointerTo()}; |
282 | 2 | |
283 | 2 | FunctionType *Ty = FunctionType::get(Builder.getInt32Ty(), Params, false); |
284 | 2 | F = Function::Create(Ty, Linkage, Name, M); |
285 | 2 | } |
286 | 2 | |
287 | 2 | return Builder.CreateCall(F, {SourceLocationInfo}); |
288 | 2 | } |
289 | | |
290 | | void ParallelLoopGeneratorKMP::createCallPushNumThreads(Value *GlobalThreadID, |
291 | 2 | Value *NumThreads) { |
292 | 2 | const std::string Name = "__kmpc_push_num_threads"; |
293 | 2 | Function *F = M->getFunction(Name); |
294 | 2 | |
295 | 2 | // If F is not available, declare it. |
296 | 2 | if (!F) { |
297 | 2 | StructType *IdentTy = M->getTypeByName("struct.ident_t"); |
298 | 2 | |
299 | 2 | GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; |
300 | 2 | Type *Params[] = {IdentTy->getPointerTo(), Builder.getInt32Ty(), |
301 | 2 | Builder.getInt32Ty()}; |
302 | 2 | |
303 | 2 | FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Params, false); |
304 | 2 | F = Function::Create(Ty, Linkage, Name, M); |
305 | 2 | } |
306 | 2 | |
307 | 2 | Value *Args[] = {SourceLocationInfo, GlobalThreadID, NumThreads}; |
308 | 2 | |
309 | 2 | Builder.CreateCall(F, Args); |
310 | 2 | } |
311 | | |
312 | | void ParallelLoopGeneratorKMP::createCallStaticInit(Value *GlobalThreadID, |
313 | | Value *IsLastPtr, |
314 | | Value *LBPtr, Value *UBPtr, |
315 | | Value *StridePtr, |
316 | 2 | Value *ChunkSize) { |
317 | 2 | const std::string Name = |
318 | 2 | is64BitArch() ? "__kmpc_for_static_init_8" : "__kmpc_for_static_init_4"0 ; |
319 | 2 | Function *F = M->getFunction(Name); |
320 | 2 | StructType *IdentTy = M->getTypeByName("struct.ident_t"); |
321 | 2 | |
322 | 2 | // If F is not available, declare it. |
323 | 2 | if (!F) { |
324 | 2 | GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; |
325 | 2 | |
326 | 2 | Type *Params[] = {IdentTy->getPointerTo(), |
327 | 2 | Builder.getInt32Ty(), |
328 | 2 | Builder.getInt32Ty(), |
329 | 2 | Builder.getInt32Ty()->getPointerTo(), |
330 | 2 | LongType->getPointerTo(), |
331 | 2 | LongType->getPointerTo(), |
332 | 2 | LongType->getPointerTo(), |
333 | 2 | LongType, |
334 | 2 | LongType}; |
335 | 2 | |
336 | 2 | FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Params, false); |
337 | 2 | F = Function::Create(Ty, Linkage, Name, M); |
338 | 2 | } |
339 | 2 | |
340 | 2 | // The parameter 'ChunkSize' will hold strictly positive integer values, |
341 | 2 | // regardless of PollyChunkSize's value |
342 | 2 | Value *Args[] = { |
343 | 2 | SourceLocationInfo, |
344 | 2 | GlobalThreadID, |
345 | 2 | Builder.getInt32(int(getSchedType(PollyChunkSize, PollyScheduling))), |
346 | 2 | IsLastPtr, |
347 | 2 | LBPtr, |
348 | 2 | UBPtr, |
349 | 2 | StridePtr, |
350 | 2 | ConstantInt::get(LongType, 1), |
351 | 2 | ChunkSize}; |
352 | 2 | |
353 | 2 | Builder.CreateCall(F, Args); |
354 | 2 | } |
355 | | |
356 | 2 | void ParallelLoopGeneratorKMP::createCallStaticFini(Value *GlobalThreadID) { |
357 | 2 | const std::string Name = "__kmpc_for_static_fini"; |
358 | 2 | Function *F = M->getFunction(Name); |
359 | 2 | StructType *IdentTy = M->getTypeByName("struct.ident_t"); |
360 | 2 | |
361 | 2 | // If F is not available, declare it. |
362 | 2 | if (!F) { |
363 | 2 | GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; |
364 | 2 | Type *Params[] = {IdentTy->getPointerTo(), Builder.getInt32Ty()}; |
365 | 2 | FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Params, false); |
366 | 2 | F = Function::Create(Ty, Linkage, Name, M); |
367 | 2 | } |
368 | 2 | |
369 | 2 | Value *Args[] = {SourceLocationInfo, GlobalThreadID}; |
370 | 2 | |
371 | 2 | Builder.CreateCall(F, Args); |
372 | 2 | } |
373 | | |
374 | | void ParallelLoopGeneratorKMP::createCallDispatchInit(Value *GlobalThreadID, |
375 | | Value *LB, Value *UB, |
376 | | Value *Inc, |
377 | 8 | Value *ChunkSize) { |
378 | 8 | const std::string Name = |
379 | 8 | is64BitArch() ? "__kmpc_dispatch_init_8" : "__kmpc_dispatch_init_4"0 ; |
380 | 8 | Function *F = M->getFunction(Name); |
381 | 8 | StructType *IdentTy = M->getTypeByName("struct.ident_t"); |
382 | 8 | |
383 | 8 | // If F is not available, declare it. |
384 | 8 | if (!F) { |
385 | 8 | GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; |
386 | 8 | |
387 | 8 | Type *Params[] = {IdentTy->getPointerTo(), |
388 | 8 | Builder.getInt32Ty(), |
389 | 8 | Builder.getInt32Ty(), |
390 | 8 | LongType, |
391 | 8 | LongType, |
392 | 8 | LongType, |
393 | 8 | LongType}; |
394 | 8 | |
395 | 8 | FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Params, false); |
396 | 8 | F = Function::Create(Ty, Linkage, Name, M); |
397 | 8 | } |
398 | 8 | |
399 | 8 | // The parameter 'ChunkSize' will hold strictly positive integer values, |
400 | 8 | // regardless of PollyChunkSize's value |
401 | 8 | Value *Args[] = { |
402 | 8 | SourceLocationInfo, |
403 | 8 | GlobalThreadID, |
404 | 8 | Builder.getInt32(int(getSchedType(PollyChunkSize, PollyScheduling))), |
405 | 8 | LB, |
406 | 8 | UB, |
407 | 8 | Inc, |
408 | 8 | ChunkSize}; |
409 | 8 | |
410 | 8 | Builder.CreateCall(F, Args); |
411 | 8 | } |
412 | | |
413 | | Value *ParallelLoopGeneratorKMP::createCallDispatchNext(Value *GlobalThreadID, |
414 | | Value *IsLastPtr, |
415 | | Value *LBPtr, |
416 | | Value *UBPtr, |
417 | 16 | Value *StridePtr) { |
418 | 16 | const std::string Name = |
419 | 16 | is64BitArch() ? "__kmpc_dispatch_next_8" : "__kmpc_dispatch_next_4"0 ; |
420 | 16 | Function *F = M->getFunction(Name); |
421 | 16 | StructType *IdentTy = M->getTypeByName("struct.ident_t"); |
422 | 16 | |
423 | 16 | // If F is not available, declare it. |
424 | 16 | if (!F) { |
425 | 8 | GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; |
426 | 8 | |
427 | 8 | Type *Params[] = {IdentTy->getPointerTo(), |
428 | 8 | Builder.getInt32Ty(), |
429 | 8 | Builder.getInt32Ty()->getPointerTo(), |
430 | 8 | LongType->getPointerTo(), |
431 | 8 | LongType->getPointerTo(), |
432 | 8 | LongType->getPointerTo()}; |
433 | 8 | |
434 | 8 | FunctionType *Ty = FunctionType::get(Builder.getInt32Ty(), Params, false); |
435 | 8 | F = Function::Create(Ty, Linkage, Name, M); |
436 | 8 | } |
437 | 16 | |
438 | 16 | Value *Args[] = {SourceLocationInfo, GlobalThreadID, IsLastPtr, LBPtr, UBPtr, |
439 | 16 | StridePtr}; |
440 | 16 | |
441 | 16 | return Builder.CreateCall(F, Args); |
442 | 16 | } |
443 | | |
444 | | // TODO: This function currently creates a source location dummy. It might be |
445 | | // necessary to (actually) provide information, in the future. |
446 | 10 | GlobalVariable *ParallelLoopGeneratorKMP::createSourceLocation() { |
447 | 10 | const std::string LocName = ".loc.dummy"; |
448 | 10 | GlobalVariable *SourceLocDummy = M->getGlobalVariable(LocName); |
449 | 10 | |
450 | 10 | if (SourceLocDummy == nullptr) { |
451 | 10 | const std::string StructName = "struct.ident_t"; |
452 | 10 | StructType *IdentTy = M->getTypeByName(StructName); |
453 | 10 | |
454 | 10 | // If the ident_t StructType is not available, declare it. |
455 | 10 | // in LLVM-IR: ident_t = type { i32, i32, i32, i32, i8* } |
456 | 10 | if (!IdentTy) { |
457 | 10 | Type *LocMembers[] = {Builder.getInt32Ty(), Builder.getInt32Ty(), |
458 | 10 | Builder.getInt32Ty(), Builder.getInt32Ty(), |
459 | 10 | Builder.getInt8PtrTy()}; |
460 | 10 | |
461 | 10 | IdentTy = |
462 | 10 | StructType::create(M->getContext(), LocMembers, StructName, false); |
463 | 10 | } |
464 | 10 | |
465 | 10 | const auto ArrayType = |
466 | 10 | llvm::ArrayType::get(Builder.getInt8Ty(), /* Length */ 23); |
467 | 10 | |
468 | 10 | // Global Variable Definitions |
469 | 10 | GlobalVariable *StrVar = new GlobalVariable( |
470 | 10 | *M, ArrayType, true, GlobalValue::PrivateLinkage, 0, ".str.ident"); |
471 | 10 | StrVar->setAlignment(1); |
472 | 10 | |
473 | 10 | SourceLocDummy = new GlobalVariable( |
474 | 10 | *M, IdentTy, true, GlobalValue::PrivateLinkage, nullptr, LocName); |
475 | 10 | SourceLocDummy->setAlignment(8); |
476 | 10 | |
477 | 10 | // Constant Definitions |
478 | 10 | Constant *InitStr = ConstantDataArray::getString( |
479 | 10 | M->getContext(), "Source location dummy.", true); |
480 | 10 | |
481 | 10 | Constant *StrPtr = static_cast<Constant *>(Builder.CreateInBoundsGEP( |
482 | 10 | ArrayType, StrVar, {Builder.getInt32(0), Builder.getInt32(0)})); |
483 | 10 | |
484 | 10 | Constant *LocInitStruct = ConstantStruct::get( |
485 | 10 | IdentTy, {Builder.getInt32(0), Builder.getInt32(0), Builder.getInt32(0), |
486 | 10 | Builder.getInt32(0), StrPtr}); |
487 | 10 | |
488 | 10 | // Initialize variables |
489 | 10 | StrVar->setInitializer(InitStr); |
490 | 10 | SourceLocDummy->setInitializer(LocInitStruct); |
491 | 10 | } |
492 | 10 | |
493 | 10 | return SourceLocDummy; |
494 | 10 | } |
495 | | |
496 | 36 | bool ParallelLoopGeneratorKMP::is64BitArch() { |
497 | 36 | return (LongType->getIntegerBitWidth() == 64); |
498 | 36 | } |
499 | | |
500 | | OMPGeneralSchedulingType ParallelLoopGeneratorKMP::getSchedType( |
501 | 10 | int ChunkSize, OMPGeneralSchedulingType Scheduling) const { |
502 | 10 | if (ChunkSize == 0 && Scheduling == OMPGeneralSchedulingType::StaticChunked8 ) |
503 | 1 | return OMPGeneralSchedulingType::StaticNonChunked; |
504 | 9 | |
505 | 9 | return Scheduling; |
506 | 9 | } |