1 //===----- CGOpenMPRuntime.cpp - Interface to OpenMP Runtimes -------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This provides a class for OpenMP runtime code generation.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "CGOpenMPRuntime.h"
15 #include "CodeGenFunction.h"
16 #include "clang/AST/Decl.h"
17 #include "llvm/ADT/ArrayRef.h"
18 #include "llvm/IR/DerivedTypes.h"
19 #include "llvm/IR/GlobalValue.h"
20 #include "llvm/IR/Value.h"
21 #include "llvm/Support/raw_ostream.h"
22 #include <cassert>
23 
24 using namespace clang;
25 using namespace CodeGen;
26 
27 CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM)
28     : CGM(CGM), DefaultOpenMPPSource(nullptr) {
29   IdentTy = llvm::StructType::create(
30       "ident_t", CGM.Int32Ty /* reserved_1 */, CGM.Int32Ty /* flags */,
31       CGM.Int32Ty /* reserved_2 */, CGM.Int32Ty /* reserved_3 */,
32       CGM.Int8PtrTy /* psource */, nullptr);
33   // Build void (*kmpc_micro)(kmp_int32 *global_tid, kmp_int32 *bound_tid,...)
34   llvm::Type *MicroParams[] = {llvm::PointerType::getUnqual(CGM.Int32Ty),
35                                llvm::PointerType::getUnqual(CGM.Int32Ty)};
36   Kmpc_MicroTy = llvm::FunctionType::get(CGM.VoidTy, MicroParams, true);
37   KmpCriticalNameTy = llvm::ArrayType::get(CGM.Int32Ty, /*NumElements*/ 8);
38 }
39 
40 llvm::Value *
41 CGOpenMPRuntime::GetOrCreateDefaultOpenMPLocation(OpenMPLocationFlags Flags) {
42   llvm::Value *Entry = OpenMPDefaultLocMap.lookup(Flags);
43   if (!Entry) {
44     if (!DefaultOpenMPPSource) {
45       // Initialize default location for psource field of ident_t structure of
46       // all ident_t objects. Format is ";file;function;line;column;;".
47       // Taken from
48       // http://llvm.org/svn/llvm-project/openmp/trunk/runtime/src/kmp_str.c
49       DefaultOpenMPPSource =
50           CGM.GetAddrOfConstantCString(";unknown;unknown;0;0;;");
51       DefaultOpenMPPSource =
52           llvm::ConstantExpr::getBitCast(DefaultOpenMPPSource, CGM.Int8PtrTy);
53     }
54     llvm::GlobalVariable *DefaultOpenMPLocation = cast<llvm::GlobalVariable>(
55         CGM.CreateRuntimeVariable(IdentTy, ".kmpc_default_loc.addr"));
56     DefaultOpenMPLocation->setUnnamedAddr(true);
57     DefaultOpenMPLocation->setConstant(true);
58     DefaultOpenMPLocation->setLinkage(llvm::GlobalValue::PrivateLinkage);
59 
60     llvm::Constant *Zero = llvm::ConstantInt::get(CGM.Int32Ty, 0, true);
61     llvm::Constant *Values[] = {Zero,
62                                 llvm::ConstantInt::get(CGM.Int32Ty, Flags),
63                                 Zero, Zero, DefaultOpenMPPSource};
64     llvm::Constant *Init = llvm::ConstantStruct::get(IdentTy, Values);
65     DefaultOpenMPLocation->setInitializer(Init);
66     return DefaultOpenMPLocation;
67   }
68   return Entry;
69 }
70 
71 llvm::Value *CGOpenMPRuntime::EmitOpenMPUpdateLocation(
72     CodeGenFunction &CGF, SourceLocation Loc, OpenMPLocationFlags Flags) {
73   // If no debug info is generated - return global default location.
74   if (CGM.getCodeGenOpts().getDebugInfo() == CodeGenOptions::NoDebugInfo ||
75       Loc.isInvalid())
76     return GetOrCreateDefaultOpenMPLocation(Flags);
77 
78   assert(CGF.CurFn && "No function in current CodeGenFunction.");
79 
80   llvm::Value *LocValue = nullptr;
81   OpenMPLocMapTy::iterator I = OpenMPLocMap.find(CGF.CurFn);
82   if (I != OpenMPLocMap.end()) {
83     LocValue = I->second;
84   } else {
85     // Generate "ident_t .kmpc_loc.addr;"
86     llvm::AllocaInst *AI = CGF.CreateTempAlloca(IdentTy, ".kmpc_loc.addr");
87     AI->setAlignment(CGM.getDataLayout().getPrefTypeAlignment(IdentTy));
88     OpenMPLocMap[CGF.CurFn] = AI;
89     LocValue = AI;
90 
91     CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
92     CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt);
93     CGF.Builder.CreateMemCpy(LocValue, GetOrCreateDefaultOpenMPLocation(Flags),
94                              llvm::ConstantExpr::getSizeOf(IdentTy),
95                              CGM.PointerAlignInBytes);
96   }
97 
98   // char **psource = &.kmpc_loc_<flags>.addr.psource;
99   llvm::Value *PSource =
100       CGF.Builder.CreateConstInBoundsGEP2_32(LocValue, 0, IdentField_PSource);
101 
102   auto OMPDebugLoc = OpenMPDebugLocMap.lookup(Loc.getRawEncoding());
103   if (OMPDebugLoc == nullptr) {
104     SmallString<128> Buffer2;
105     llvm::raw_svector_ostream OS2(Buffer2);
106     // Build debug location
107     PresumedLoc PLoc = CGF.getContext().getSourceManager().getPresumedLoc(Loc);
108     OS2 << ";" << PLoc.getFilename() << ";";
109     if (const FunctionDecl *FD =
110             dyn_cast_or_null<FunctionDecl>(CGF.CurFuncDecl)) {
111       OS2 << FD->getQualifiedNameAsString();
112     }
113     OS2 << ";" << PLoc.getLine() << ";" << PLoc.getColumn() << ";;";
114     OMPDebugLoc = CGF.Builder.CreateGlobalStringPtr(OS2.str());
115     OpenMPDebugLocMap[Loc.getRawEncoding()] = OMPDebugLoc;
116   }
117   // *psource = ";<File>;<Function>;<Line>;<Column>;;";
118   CGF.Builder.CreateStore(OMPDebugLoc, PSource);
119 
120   return LocValue;
121 }
122 
123 llvm::Value *CGOpenMPRuntime::GetOpenMPGlobalThreadNum(CodeGenFunction &CGF,
124                                                        SourceLocation Loc) {
125   assert(CGF.CurFn && "No function in current CodeGenFunction.");
126 
127   llvm::Value *GTid = nullptr;
128   OpenMPGtidMapTy::iterator I = OpenMPGtidMap.find(CGF.CurFn);
129   if (I != OpenMPGtidMap.end()) {
130     GTid = I->second;
131   } else {
132     // Check if current function is a function which has first parameter
133     // with type int32 and name ".global_tid.".
134     if (!CGF.CurFn->arg_empty() &&
135         CGF.CurFn->arg_begin()->getType()->isPointerTy() &&
136         CGF.CurFn->arg_begin()
137             ->getType()
138             ->getPointerElementType()
139             ->isIntegerTy() &&
140         CGF.CurFn->arg_begin()
141                 ->getType()
142                 ->getPointerElementType()
143                 ->getIntegerBitWidth() == 32 &&
144         CGF.CurFn->arg_begin()->hasName() &&
145         CGF.CurFn->arg_begin()->getName() == ".global_tid.") {
146       CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
147       CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt);
148       GTid = CGF.Builder.CreateLoad(CGF.CurFn->arg_begin());
149     } else {
150       // Generate "int32 .kmpc_global_thread_num.addr;"
151       CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
152       CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt);
153       llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc)};
154       GTid = CGF.EmitRuntimeCall(
155           CreateRuntimeFunction(OMPRTL__kmpc_global_thread_num), Args);
156     }
157     OpenMPGtidMap[CGF.CurFn] = GTid;
158   }
159   return GTid;
160 }
161 
162 void CGOpenMPRuntime::FunctionFinished(CodeGenFunction &CGF) {
163   assert(CGF.CurFn && "No function in current CodeGenFunction.");
164   if (OpenMPGtidMap.count(CGF.CurFn))
165     OpenMPGtidMap.erase(CGF.CurFn);
166   if (OpenMPLocMap.count(CGF.CurFn))
167     OpenMPLocMap.erase(CGF.CurFn);
168 }
169 
170 llvm::Type *CGOpenMPRuntime::getIdentTyPointerTy() {
171   return llvm::PointerType::getUnqual(IdentTy);
172 }
173 
174 llvm::Type *CGOpenMPRuntime::getKmpc_MicroPointerTy() {
175   return llvm::PointerType::getUnqual(Kmpc_MicroTy);
176 }
177 
178 llvm::Constant *
179 CGOpenMPRuntime::CreateRuntimeFunction(OpenMPRTLFunction Function) {
180   llvm::Constant *RTLFn = nullptr;
181   switch (Function) {
182   case OMPRTL__kmpc_fork_call: {
183     // Build void __kmpc_fork_call(ident_t *loc, kmp_int32 argc, kmpc_micro
184     // microtask, ...);
185     llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty,
186                                 getKmpc_MicroPointerTy()};
187     llvm::FunctionType *FnTy =
188         llvm::FunctionType::get(CGM.VoidTy, TypeParams, true);
189     RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_fork_call");
190     break;
191   }
192   case OMPRTL__kmpc_global_thread_num: {
193     // Build kmp_int32 __kmpc_global_thread_num(ident_t *loc);
194     llvm::Type *TypeParams[] = {getIdentTyPointerTy()};
195     llvm::FunctionType *FnTy =
196         llvm::FunctionType::get(CGM.Int32Ty, TypeParams, false);
197     RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_global_thread_num");
198     break;
199   }
200   case OMPRTL__kmpc_critical: {
201     // Build void __kmpc_critical(ident_t *loc, kmp_int32 global_tid,
202     // kmp_critical_name *crit);
203     llvm::Type *TypeParams[] = {
204         getIdentTyPointerTy(), CGM.Int32Ty,
205         llvm::PointerType::getUnqual(KmpCriticalNameTy)};
206     llvm::FunctionType *FnTy =
207         llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
208     RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_critical");
209     break;
210   }
211   case OMPRTL__kmpc_end_critical: {
212     // Build void __kmpc_end_critical(ident_t *loc, kmp_int32 global_tid,
213     // kmp_critical_name *crit);
214     llvm::Type *TypeParams[] = {
215         getIdentTyPointerTy(), CGM.Int32Ty,
216         llvm::PointerType::getUnqual(KmpCriticalNameTy)};
217     llvm::FunctionType *FnTy =
218         llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
219     RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_end_critical");
220     break;
221   }
222   }
223   return RTLFn;
224 }
225 
226 llvm::Value *CGOpenMPRuntime::GetCriticalRegionLock(StringRef CriticalName) {
227   SmallString<256> Buffer;
228   llvm::raw_svector_ostream Out(Buffer);
229   Out << ".gomp_critical_user_" << CriticalName << ".var";
230   auto RuntimeCriticalName = Out.str();
231   auto &Elem = CriticalRegionVarNames.GetOrCreateValue(RuntimeCriticalName);
232   if (Elem.getValue() != nullptr)
233     return Elem.getValue();
234 
235   auto Lock = new llvm::GlobalVariable(
236       CGM.getModule(), KmpCriticalNameTy, /*IsConstant*/ false,
237       llvm::GlobalValue::CommonLinkage,
238       llvm::Constant::getNullValue(KmpCriticalNameTy), Elem.getKey());
239   Elem.setValue(Lock);
240   return Lock;
241 }
242 
243 void CGOpenMPRuntime::EmitOMPCriticalRegionStart(CodeGenFunction &CGF,
244                                                  llvm::Value *RegionLock,
245                                                  SourceLocation Loc) {
246   // Prepare other arguments and build a call to __kmpc_critical
247   llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc),
248                          GetOpenMPGlobalThreadNum(CGF, Loc), RegionLock};
249   auto RTLFn = CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_critical);
250   CGF.EmitRuntimeCall(RTLFn, Args);
251 }
252 
253 void CGOpenMPRuntime::EmitOMPCriticalRegionEnd(CodeGenFunction &CGF,
254                                                llvm::Value *RegionLock,
255                                                SourceLocation Loc) {
256   // Prepare other arguments and build a call to __kmpc_end_critical
257   llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc),
258                          GetOpenMPGlobalThreadNum(CGF, Loc), RegionLock};
259   auto RTLFn =
260       CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_end_critical);
261   CGF.EmitRuntimeCall(RTLFn, Args);
262 }
263