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