• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 =
185       Builder.CreateAlignedLoad(IDPtr, Alignment, "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(LBPtr, Alignment, "polly.indvar.LB");
227       UB = Builder.CreateAlignedLoad(UBPtr, Alignment, "polly.indvar.UB");
228     }
229     break;
230   case OMPGeneralSchedulingType::StaticChunked:
231   case OMPGeneralSchedulingType::StaticNonChunked:
232     // "STATIC" scheduling types are handled below
233     {
234       Builder.CreateAlignedStore(AdjustedUB, UBPtr, Alignment);
235       createCallStaticInit(ID, IsLastPtr, LBPtr, UBPtr, StridePtr, ChunkSize);
236 
237       Value *ChunkedStride =
238           Builder.CreateAlignedLoad(StridePtr, Alignment, "polly.kmpc.stride");
239 
240       LB = Builder.CreateAlignedLoad(LBPtr, Alignment, "polly.indvar.LB");
241       UB = Builder.CreateAlignedLoad(UBPtr, Alignment, "polly.indvar.UB.temp");
242 
243       Value *UBInRange =
244           Builder.CreateICmp(llvm::CmpInst::Predicate::ICMP_SLE, UB, AdjustedUB,
245                              "polly.indvar.UB.inRange");
246       UB = Builder.CreateSelect(UBInRange, UB, AdjustedUB, "polly.indvar.UB");
247       Builder.CreateAlignedStore(UB, UBPtr, Alignment);
248 
249       Value *HasIteration = Builder.CreateICmp(
250           llvm::CmpInst::Predicate::ICMP_SLE, LB, UB, "polly.hasIteration");
251       Builder.CreateCondBr(HasIteration, PreHeaderBB, ExitBB);
252 
253       if (Scheduling == OMPGeneralSchedulingType::StaticChunked) {
254         Builder.SetInsertPoint(PreHeaderBB);
255         LB = Builder.CreateAlignedLoad(LBPtr, Alignment,
256                                        "polly.indvar.LB.entry");
257         UB = Builder.CreateAlignedLoad(UBPtr, Alignment,
258                                        "polly.indvar.UB.entry");
259       }
260 
261       Builder.SetInsertPoint(CheckNextBB);
262 
263       if (Scheduling == OMPGeneralSchedulingType::StaticChunked) {
264         Value *NextLB =
265             Builder.CreateAdd(LB, ChunkedStride, "polly.indvar.nextLB");
266         Value *NextUB = Builder.CreateAdd(UB, ChunkedStride);
267 
268         Value *NextUBOutOfBounds =
269             Builder.CreateICmp(llvm::CmpInst::Predicate::ICMP_SGT, NextUB,
270                                AdjustedUB, "polly.indvar.nextUB.outOfBounds");
271         NextUB = Builder.CreateSelect(NextUBOutOfBounds, AdjustedUB, NextUB,
272                                       "polly.indvar.nextUB");
273 
274         Builder.CreateAlignedStore(NextLB, LBPtr, Alignment);
275         Builder.CreateAlignedStore(NextUB, UBPtr, Alignment);
276 
277         Value *HasWork =
278             Builder.CreateICmp(llvm::CmpInst::Predicate::ICMP_SLE, NextLB,
279                                AdjustedUB, "polly.hasWork");
280         Builder.CreateCondBr(HasWork, PreHeaderBB, ExitBB);
281       } else {
282         Builder.CreateBr(ExitBB);
283       }
284 
285       Builder.SetInsertPoint(PreHeaderBB);
286     }
287     break;
288   }
289 
290   Builder.CreateBr(CheckNextBB);
291   Builder.SetInsertPoint(&*--Builder.GetInsertPoint());
292   BasicBlock *AfterBB;
293   Value *IV = createLoop(LB, UB, SequentialLoopStride, Builder, LI, DT, AfterBB,
294                          ICmpInst::ICMP_SLE, nullptr, true,
295                          /* UseGuard */ false);
296 
297   BasicBlock::iterator LoopBody = Builder.GetInsertPoint();
298 
299   // Add code to terminate this subfunction.
300   Builder.SetInsertPoint(ExitBB);
301   // Static (i.e. non-dynamic) scheduling types, are terminated with a fini-call
302   if (Scheduling == OMPGeneralSchedulingType::StaticChunked ||
303       Scheduling == OMPGeneralSchedulingType::StaticNonChunked) {
304     createCallStaticFini(ID);
305   }
306   Builder.CreateRetVoid();
307   Builder.SetInsertPoint(&*LoopBody);
308 
309   return std::make_tuple(IV, SubFn);
310 }
311 
createCallGlobalThreadNum()312 Value *ParallelLoopGeneratorKMP::createCallGlobalThreadNum() {
313   const std::string Name = "__kmpc_global_thread_num";
314   Function *F = M->getFunction(Name);
315 
316   // If F is not available, declare it.
317   if (!F) {
318     StructType *IdentTy =
319         StructType::getTypeByName(M->getContext(), "struct.ident_t");
320 
321     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
322     Type *Params[] = {IdentTy->getPointerTo()};
323 
324     FunctionType *Ty = FunctionType::get(Builder.getInt32Ty(), Params, false);
325     F = Function::Create(Ty, Linkage, Name, M);
326   }
327 
328   return Builder.CreateCall(F, {SourceLocationInfo});
329 }
330 
createCallPushNumThreads(Value * GlobalThreadID,Value * NumThreads)331 void ParallelLoopGeneratorKMP::createCallPushNumThreads(Value *GlobalThreadID,
332                                                         Value *NumThreads) {
333   const std::string Name = "__kmpc_push_num_threads";
334   Function *F = M->getFunction(Name);
335 
336   // If F is not available, declare it.
337   if (!F) {
338     StructType *IdentTy =
339         StructType::getTypeByName(M->getContext(), "struct.ident_t");
340 
341     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
342     Type *Params[] = {IdentTy->getPointerTo(), Builder.getInt32Ty(),
343                       Builder.getInt32Ty()};
344 
345     FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Params, false);
346     F = Function::Create(Ty, Linkage, Name, M);
347   }
348 
349   Value *Args[] = {SourceLocationInfo, GlobalThreadID, NumThreads};
350 
351   Builder.CreateCall(F, Args);
352 }
353 
createCallStaticInit(Value * GlobalThreadID,Value * IsLastPtr,Value * LBPtr,Value * UBPtr,Value * StridePtr,Value * ChunkSize)354 void ParallelLoopGeneratorKMP::createCallStaticInit(Value *GlobalThreadID,
355                                                     Value *IsLastPtr,
356                                                     Value *LBPtr, Value *UBPtr,
357                                                     Value *StridePtr,
358                                                     Value *ChunkSize) {
359   const std::string Name =
360       is64BitArch() ? "__kmpc_for_static_init_8" : "__kmpc_for_static_init_4";
361   Function *F = M->getFunction(Name);
362   StructType *IdentTy =
363       StructType::getTypeByName(M->getContext(), "struct.ident_t");
364 
365   // If F is not available, declare it.
366   if (!F) {
367     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
368 
369     Type *Params[] = {IdentTy->getPointerTo(),
370                       Builder.getInt32Ty(),
371                       Builder.getInt32Ty(),
372                       Builder.getInt32Ty()->getPointerTo(),
373                       LongType->getPointerTo(),
374                       LongType->getPointerTo(),
375                       LongType->getPointerTo(),
376                       LongType,
377                       LongType};
378 
379     FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Params, false);
380     F = Function::Create(Ty, Linkage, Name, M);
381   }
382 
383   // The parameter 'ChunkSize' will hold strictly positive integer values,
384   // regardless of PollyChunkSize's value
385   Value *Args[] = {
386       SourceLocationInfo,
387       GlobalThreadID,
388       Builder.getInt32(int(getSchedType(PollyChunkSize, PollyScheduling))),
389       IsLastPtr,
390       LBPtr,
391       UBPtr,
392       StridePtr,
393       ConstantInt::get(LongType, 1),
394       ChunkSize};
395 
396   Builder.CreateCall(F, Args);
397 }
398 
createCallStaticFini(Value * GlobalThreadID)399 void ParallelLoopGeneratorKMP::createCallStaticFini(Value *GlobalThreadID) {
400   const std::string Name = "__kmpc_for_static_fini";
401   Function *F = M->getFunction(Name);
402   StructType *IdentTy =
403       StructType::getTypeByName(M->getContext(), "struct.ident_t");
404 
405   // If F is not available, declare it.
406   if (!F) {
407     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
408     Type *Params[] = {IdentTy->getPointerTo(), Builder.getInt32Ty()};
409     FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Params, false);
410     F = Function::Create(Ty, Linkage, Name, M);
411   }
412 
413   Value *Args[] = {SourceLocationInfo, GlobalThreadID};
414 
415   Builder.CreateCall(F, Args);
416 }
417 
createCallDispatchInit(Value * GlobalThreadID,Value * LB,Value * UB,Value * Inc,Value * ChunkSize)418 void ParallelLoopGeneratorKMP::createCallDispatchInit(Value *GlobalThreadID,
419                                                       Value *LB, Value *UB,
420                                                       Value *Inc,
421                                                       Value *ChunkSize) {
422   const std::string Name =
423       is64BitArch() ? "__kmpc_dispatch_init_8" : "__kmpc_dispatch_init_4";
424   Function *F = M->getFunction(Name);
425   StructType *IdentTy =
426       StructType::getTypeByName(M->getContext(), "struct.ident_t");
427 
428   // If F is not available, declare it.
429   if (!F) {
430     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
431 
432     Type *Params[] = {IdentTy->getPointerTo(),
433                       Builder.getInt32Ty(),
434                       Builder.getInt32Ty(),
435                       LongType,
436                       LongType,
437                       LongType,
438                       LongType};
439 
440     FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), Params, false);
441     F = Function::Create(Ty, Linkage, Name, M);
442   }
443 
444   // The parameter 'ChunkSize' will hold strictly positive integer values,
445   // regardless of PollyChunkSize's value
446   Value *Args[] = {
447       SourceLocationInfo,
448       GlobalThreadID,
449       Builder.getInt32(int(getSchedType(PollyChunkSize, PollyScheduling))),
450       LB,
451       UB,
452       Inc,
453       ChunkSize};
454 
455   Builder.CreateCall(F, Args);
456 }
457 
createCallDispatchNext(Value * GlobalThreadID,Value * IsLastPtr,Value * LBPtr,Value * UBPtr,Value * StridePtr)458 Value *ParallelLoopGeneratorKMP::createCallDispatchNext(Value *GlobalThreadID,
459                                                         Value *IsLastPtr,
460                                                         Value *LBPtr,
461                                                         Value *UBPtr,
462                                                         Value *StridePtr) {
463   const std::string Name =
464       is64BitArch() ? "__kmpc_dispatch_next_8" : "__kmpc_dispatch_next_4";
465   Function *F = M->getFunction(Name);
466   StructType *IdentTy =
467       StructType::getTypeByName(M->getContext(), "struct.ident_t");
468 
469   // If F is not available, declare it.
470   if (!F) {
471     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
472 
473     Type *Params[] = {IdentTy->getPointerTo(),
474                       Builder.getInt32Ty(),
475                       Builder.getInt32Ty()->getPointerTo(),
476                       LongType->getPointerTo(),
477                       LongType->getPointerTo(),
478                       LongType->getPointerTo()};
479 
480     FunctionType *Ty = FunctionType::get(Builder.getInt32Ty(), Params, false);
481     F = Function::Create(Ty, Linkage, Name, M);
482   }
483 
484   Value *Args[] = {SourceLocationInfo, GlobalThreadID, IsLastPtr, LBPtr, UBPtr,
485                    StridePtr};
486 
487   return Builder.CreateCall(F, Args);
488 }
489 
490 // TODO: This function currently creates a source location dummy. It might be
491 // necessary to (actually) provide information, in the future.
createSourceLocation()492 GlobalVariable *ParallelLoopGeneratorKMP::createSourceLocation() {
493   const std::string LocName = ".loc.dummy";
494   GlobalVariable *SourceLocDummy = M->getGlobalVariable(LocName);
495 
496   if (SourceLocDummy == nullptr) {
497     const std::string StructName = "struct.ident_t";
498     StructType *IdentTy =
499         StructType::getTypeByName(M->getContext(), StructName);
500 
501     // If the ident_t StructType is not available, declare it.
502     // in LLVM-IR: ident_t = type { i32, i32, i32, i32, i8* }
503     if (!IdentTy) {
504       Type *LocMembers[] = {Builder.getInt32Ty(), Builder.getInt32Ty(),
505                             Builder.getInt32Ty(), Builder.getInt32Ty(),
506                             Builder.getInt8PtrTy()};
507 
508       IdentTy =
509           StructType::create(M->getContext(), LocMembers, StructName, false);
510     }
511 
512     const auto ArrayType =
513         llvm::ArrayType::get(Builder.getInt8Ty(), /* Length */ 23);
514 
515     // Global Variable Definitions
516     GlobalVariable *StrVar = new GlobalVariable(
517         *M, ArrayType, true, GlobalValue::PrivateLinkage, 0, ".str.ident");
518     StrVar->setAlignment(llvm::Align(1));
519 
520     SourceLocDummy = new GlobalVariable(
521         *M, IdentTy, true, GlobalValue::PrivateLinkage, nullptr, LocName);
522     SourceLocDummy->setAlignment(llvm::Align(8));
523 
524     // Constant Definitions
525     Constant *InitStr = ConstantDataArray::getString(
526         M->getContext(), "Source location dummy.", true);
527 
528     Constant *StrPtr = static_cast<Constant *>(Builder.CreateInBoundsGEP(
529         ArrayType, StrVar, {Builder.getInt32(0), Builder.getInt32(0)}));
530 
531     Constant *LocInitStruct = ConstantStruct::get(
532         IdentTy, {Builder.getInt32(0), Builder.getInt32(0), Builder.getInt32(0),
533                   Builder.getInt32(0), StrPtr});
534 
535     // Initialize variables
536     StrVar->setInitializer(InitStr);
537     SourceLocDummy->setInitializer(LocInitStruct);
538   }
539 
540   return SourceLocDummy;
541 }
542 
is64BitArch()543 bool ParallelLoopGeneratorKMP::is64BitArch() {
544   return (LongType->getIntegerBitWidth() == 64);
545 }
546 
getSchedType(int ChunkSize,OMPGeneralSchedulingType Scheduling) const547 OMPGeneralSchedulingType ParallelLoopGeneratorKMP::getSchedType(
548     int ChunkSize, OMPGeneralSchedulingType Scheduling) const {
549   if (ChunkSize == 0 && Scheduling == OMPGeneralSchedulingType::StaticChunked)
550     return OMPGeneralSchedulingType::StaticNonChunked;
551 
552   return Scheduling;
553 }
554