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