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