clang API Documentation
00001 //===----- CGOpenMPRuntime.cpp - Interface to OpenMP Runtimes -------------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This provides a class for OpenMP runtime code generation. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 #include "CGOpenMPRuntime.h" 00015 #include "CodeGenFunction.h" 00016 #include "clang/AST/StmtOpenMP.h" 00017 #include "clang/AST/Decl.h" 00018 #include "llvm/ADT/ArrayRef.h" 00019 #include "llvm/IR/CallSite.h" 00020 #include "llvm/IR/DerivedTypes.h" 00021 #include "llvm/IR/GlobalValue.h" 00022 #include "llvm/IR/Value.h" 00023 #include "llvm/Support/raw_ostream.h" 00024 #include <cassert> 00025 00026 using namespace clang; 00027 using namespace CodeGen; 00028 00029 namespace { 00030 /// \brief API for captured statement code generation in OpenMP constructs. 00031 class CGOpenMPRegionInfo : public CodeGenFunction::CGCapturedStmtInfo { 00032 public: 00033 CGOpenMPRegionInfo(const OMPExecutableDirective &D, const CapturedStmt &CS, 00034 const VarDecl *ThreadIDVar) 00035 : CGCapturedStmtInfo(CS, CR_OpenMP), ThreadIDVar(ThreadIDVar), 00036 Directive(D) { 00037 assert(ThreadIDVar != nullptr && "No ThreadID in OpenMP region."); 00038 } 00039 00040 /// \brief Gets a variable or parameter for storing global thread id 00041 /// inside OpenMP construct. 00042 const VarDecl *getThreadIDVariable() const { return ThreadIDVar; } 00043 00044 /// \brief Gets an LValue for the current ThreadID variable. 00045 LValue getThreadIDVariableLValue(CodeGenFunction &CGF); 00046 00047 static bool classof(const CGCapturedStmtInfo *Info) { 00048 return Info->getKind() == CR_OpenMP; 00049 } 00050 00051 /// \brief Emit the captured statement body. 00052 void EmitBody(CodeGenFunction &CGF, Stmt *S) override; 00053 00054 /// \brief Get the name of the capture helper. 00055 StringRef getHelperName() const override { return ".omp_outlined."; } 00056 00057 private: 00058 /// \brief A variable or parameter storing global thread id for OpenMP 00059 /// constructs. 00060 const VarDecl *ThreadIDVar; 00061 /// \brief OpenMP executable directive associated with the region. 00062 const OMPExecutableDirective &Directive; 00063 }; 00064 } // namespace 00065 00066 LValue CGOpenMPRegionInfo::getThreadIDVariableLValue(CodeGenFunction &CGF) { 00067 return CGF.MakeNaturalAlignAddrLValue( 00068 CGF.GetAddrOfLocalVar(ThreadIDVar), 00069 CGF.getContext().getPointerType(ThreadIDVar->getType())); 00070 } 00071 00072 void CGOpenMPRegionInfo::EmitBody(CodeGenFunction &CGF, Stmt *S) { 00073 CodeGenFunction::OMPPrivateScope PrivateScope(CGF); 00074 CGF.EmitOMPPrivateClause(Directive, PrivateScope); 00075 CGF.EmitOMPFirstprivateClause(Directive, PrivateScope); 00076 if (PrivateScope.Privatize()) { 00077 // Emit implicit barrier to synchronize threads and avoid data races. 00078 auto Flags = static_cast<CGOpenMPRuntime::OpenMPLocationFlags>( 00079 CGOpenMPRuntime::OMP_IDENT_KMPC | 00080 CGOpenMPRuntime::OMP_IDENT_BARRIER_IMPL); 00081 CGF.CGM.getOpenMPRuntime().EmitOMPBarrierCall(CGF, Directive.getLocStart(), 00082 Flags); 00083 } 00084 CGCapturedStmtInfo::EmitBody(CGF, S); 00085 } 00086 00087 CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM) 00088 : CGM(CGM), DefaultOpenMPPSource(nullptr) { 00089 IdentTy = llvm::StructType::create( 00090 "ident_t", CGM.Int32Ty /* reserved_1 */, CGM.Int32Ty /* flags */, 00091 CGM.Int32Ty /* reserved_2 */, CGM.Int32Ty /* reserved_3 */, 00092 CGM.Int8PtrTy /* psource */, nullptr); 00093 // Build void (*kmpc_micro)(kmp_int32 *global_tid, kmp_int32 *bound_tid,...) 00094 llvm::Type *MicroParams[] = {llvm::PointerType::getUnqual(CGM.Int32Ty), 00095 llvm::PointerType::getUnqual(CGM.Int32Ty)}; 00096 Kmpc_MicroTy = llvm::FunctionType::get(CGM.VoidTy, MicroParams, true); 00097 KmpCriticalNameTy = llvm::ArrayType::get(CGM.Int32Ty, /*NumElements*/ 8); 00098 } 00099 00100 llvm::Value * 00101 CGOpenMPRuntime::EmitOpenMPOutlinedFunction(const OMPExecutableDirective &D, 00102 const VarDecl *ThreadIDVar) { 00103 const CapturedStmt *CS = cast<CapturedStmt>(D.getAssociatedStmt()); 00104 CodeGenFunction CGF(CGM, true); 00105 CGOpenMPRegionInfo CGInfo(D, *CS, ThreadIDVar); 00106 CGF.CapturedStmtInfo = &CGInfo; 00107 return CGF.GenerateCapturedStmtFunction(*CS); 00108 } 00109 00110 llvm::Value * 00111 CGOpenMPRuntime::GetOrCreateDefaultOpenMPLocation(OpenMPLocationFlags Flags) { 00112 llvm::Value *Entry = OpenMPDefaultLocMap.lookup(Flags); 00113 if (!Entry) { 00114 if (!DefaultOpenMPPSource) { 00115 // Initialize default location for psource field of ident_t structure of 00116 // all ident_t objects. Format is ";file;function;line;column;;". 00117 // Taken from 00118 // http://llvm.org/svn/llvm-project/openmp/trunk/runtime/src/kmp_str.c 00119 DefaultOpenMPPSource = 00120 CGM.GetAddrOfConstantCString(";unknown;unknown;0;0;;"); 00121 DefaultOpenMPPSource = 00122 llvm::ConstantExpr::getBitCast(DefaultOpenMPPSource, CGM.Int8PtrTy); 00123 } 00124 auto DefaultOpenMPLocation = new llvm::GlobalVariable( 00125 CGM.getModule(), IdentTy, /*isConstant*/ true, 00126 llvm::GlobalValue::PrivateLinkage, /*Initializer*/ nullptr); 00127 DefaultOpenMPLocation->setUnnamedAddr(true); 00128 00129 llvm::Constant *Zero = llvm::ConstantInt::get(CGM.Int32Ty, 0, true); 00130 llvm::Constant *Values[] = {Zero, 00131 llvm::ConstantInt::get(CGM.Int32Ty, Flags), 00132 Zero, Zero, DefaultOpenMPPSource}; 00133 llvm::Constant *Init = llvm::ConstantStruct::get(IdentTy, Values); 00134 DefaultOpenMPLocation->setInitializer(Init); 00135 OpenMPDefaultLocMap[Flags] = DefaultOpenMPLocation; 00136 return DefaultOpenMPLocation; 00137 } 00138 return Entry; 00139 } 00140 00141 llvm::Value *CGOpenMPRuntime::EmitOpenMPUpdateLocation( 00142 CodeGenFunction &CGF, SourceLocation Loc, OpenMPLocationFlags Flags) { 00143 // If no debug info is generated - return global default location. 00144 if (CGM.getCodeGenOpts().getDebugInfo() == CodeGenOptions::NoDebugInfo || 00145 Loc.isInvalid()) 00146 return GetOrCreateDefaultOpenMPLocation(Flags); 00147 00148 assert(CGF.CurFn && "No function in current CodeGenFunction."); 00149 00150 llvm::Value *LocValue = nullptr; 00151 OpenMPLocThreadIDMapTy::iterator I = OpenMPLocThreadIDMap.find(CGF.CurFn); 00152 if (I != OpenMPLocThreadIDMap.end()) { 00153 LocValue = I->second.DebugLoc; 00154 } else { 00155 // Generate "ident_t .kmpc_loc.addr;" 00156 llvm::AllocaInst *AI = CGF.CreateTempAlloca(IdentTy, ".kmpc_loc.addr"); 00157 AI->setAlignment(CGM.getDataLayout().getPrefTypeAlignment(IdentTy)); 00158 auto &Elem = OpenMPLocThreadIDMap.FindAndConstruct(CGF.CurFn); 00159 Elem.second.DebugLoc = AI; 00160 LocValue = AI; 00161 00162 CGBuilderTy::InsertPointGuard IPG(CGF.Builder); 00163 CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt); 00164 CGF.Builder.CreateMemCpy(LocValue, GetOrCreateDefaultOpenMPLocation(Flags), 00165 llvm::ConstantExpr::getSizeOf(IdentTy), 00166 CGM.PointerAlignInBytes); 00167 } 00168 00169 // char **psource = &.kmpc_loc_<flags>.addr.psource; 00170 llvm::Value *PSource = 00171 CGF.Builder.CreateConstInBoundsGEP2_32(LocValue, 0, IdentField_PSource); 00172 00173 auto OMPDebugLoc = OpenMPDebugLocMap.lookup(Loc.getRawEncoding()); 00174 if (OMPDebugLoc == nullptr) { 00175 SmallString<128> Buffer2; 00176 llvm::raw_svector_ostream OS2(Buffer2); 00177 // Build debug location 00178 PresumedLoc PLoc = CGF.getContext().getSourceManager().getPresumedLoc(Loc); 00179 OS2 << ";" << PLoc.getFilename() << ";"; 00180 if (const FunctionDecl *FD = 00181 dyn_cast_or_null<FunctionDecl>(CGF.CurFuncDecl)) { 00182 OS2 << FD->getQualifiedNameAsString(); 00183 } 00184 OS2 << ";" << PLoc.getLine() << ";" << PLoc.getColumn() << ";;"; 00185 OMPDebugLoc = CGF.Builder.CreateGlobalStringPtr(OS2.str()); 00186 OpenMPDebugLocMap[Loc.getRawEncoding()] = OMPDebugLoc; 00187 } 00188 // *psource = ";<File>;<Function>;<Line>;<Column>;;"; 00189 CGF.Builder.CreateStore(OMPDebugLoc, PSource); 00190 00191 return LocValue; 00192 } 00193 00194 llvm::Value *CGOpenMPRuntime::GetOpenMPThreadID(CodeGenFunction &CGF, 00195 SourceLocation Loc) { 00196 assert(CGF.CurFn && "No function in current CodeGenFunction."); 00197 00198 llvm::Value *ThreadID = nullptr; 00199 // Check whether we've already cached a load of the thread id in this 00200 // function. 00201 OpenMPLocThreadIDMapTy::iterator I = OpenMPLocThreadIDMap.find(CGF.CurFn); 00202 if (I != OpenMPLocThreadIDMap.end()) { 00203 ThreadID = I->second.ThreadID; 00204 if (ThreadID != nullptr) 00205 return ThreadID; 00206 } 00207 if (auto OMPRegionInfo = 00208 dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) { 00209 // Check if this an outlined function with thread id passed as argument. 00210 auto ThreadIDVar = OMPRegionInfo->getThreadIDVariable(); 00211 auto LVal = OMPRegionInfo->getThreadIDVariableLValue(CGF); 00212 auto RVal = CGF.EmitLoadOfLValue(LVal, Loc); 00213 LVal = CGF.MakeNaturalAlignAddrLValue(RVal.getScalarVal(), 00214 ThreadIDVar->getType()); 00215 ThreadID = CGF.EmitLoadOfLValue(LVal, Loc).getScalarVal(); 00216 // If value loaded in entry block, cache it and use it everywhere in 00217 // function. 00218 if (CGF.Builder.GetInsertBlock() == CGF.AllocaInsertPt->getParent()) { 00219 auto &Elem = OpenMPLocThreadIDMap.FindAndConstruct(CGF.CurFn); 00220 Elem.second.ThreadID = ThreadID; 00221 } 00222 } else { 00223 // This is not an outlined function region - need to call __kmpc_int32 00224 // kmpc_global_thread_num(ident_t *loc). 00225 // Generate thread id value and cache this value for use across the 00226 // function. 00227 CGBuilderTy::InsertPointGuard IPG(CGF.Builder); 00228 CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt); 00229 llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc)}; 00230 ThreadID = CGF.EmitRuntimeCall( 00231 CreateRuntimeFunction(OMPRTL__kmpc_global_thread_num), Args); 00232 auto &Elem = OpenMPLocThreadIDMap.FindAndConstruct(CGF.CurFn); 00233 Elem.second.ThreadID = ThreadID; 00234 } 00235 return ThreadID; 00236 } 00237 00238 void CGOpenMPRuntime::FunctionFinished(CodeGenFunction &CGF) { 00239 assert(CGF.CurFn && "No function in current CodeGenFunction."); 00240 if (OpenMPLocThreadIDMap.count(CGF.CurFn)) 00241 OpenMPLocThreadIDMap.erase(CGF.CurFn); 00242 } 00243 00244 llvm::Type *CGOpenMPRuntime::getIdentTyPointerTy() { 00245 return llvm::PointerType::getUnqual(IdentTy); 00246 } 00247 00248 llvm::Type *CGOpenMPRuntime::getKmpc_MicroPointerTy() { 00249 return llvm::PointerType::getUnqual(Kmpc_MicroTy); 00250 } 00251 00252 llvm::Constant * 00253 CGOpenMPRuntime::CreateRuntimeFunction(OpenMPRTLFunction Function) { 00254 llvm::Constant *RTLFn = nullptr; 00255 switch (Function) { 00256 case OMPRTL__kmpc_fork_call: { 00257 // Build void __kmpc_fork_call(ident_t *loc, kmp_int32 argc, kmpc_micro 00258 // microtask, ...); 00259 llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty, 00260 getKmpc_MicroPointerTy()}; 00261 llvm::FunctionType *FnTy = 00262 llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ true); 00263 RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_fork_call"); 00264 break; 00265 } 00266 case OMPRTL__kmpc_global_thread_num: { 00267 // Build kmp_int32 __kmpc_global_thread_num(ident_t *loc); 00268 llvm::Type *TypeParams[] = {getIdentTyPointerTy()}; 00269 llvm::FunctionType *FnTy = 00270 llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false); 00271 RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_global_thread_num"); 00272 break; 00273 } 00274 case OMPRTL__kmpc_threadprivate_cached: { 00275 // Build void *__kmpc_threadprivate_cached(ident_t *loc, 00276 // kmp_int32 global_tid, void *data, size_t size, void ***cache); 00277 llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty, 00278 CGM.VoidPtrTy, CGM.SizeTy, 00279 CGM.VoidPtrTy->getPointerTo()->getPointerTo()}; 00280 llvm::FunctionType *FnTy = 00281 llvm::FunctionType::get(CGM.VoidPtrTy, TypeParams, /*isVarArg*/ false); 00282 RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_threadprivate_cached"); 00283 break; 00284 } 00285 case OMPRTL__kmpc_critical: { 00286 // Build void __kmpc_critical(ident_t *loc, kmp_int32 global_tid, 00287 // kmp_critical_name *crit); 00288 llvm::Type *TypeParams[] = { 00289 getIdentTyPointerTy(), CGM.Int32Ty, 00290 llvm::PointerType::getUnqual(KmpCriticalNameTy)}; 00291 llvm::FunctionType *FnTy = 00292 llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false); 00293 RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_critical"); 00294 break; 00295 } 00296 case OMPRTL__kmpc_threadprivate_register: { 00297 // Build void __kmpc_threadprivate_register(ident_t *, void *data, 00298 // kmpc_ctor ctor, kmpc_cctor cctor, kmpc_dtor dtor); 00299 // typedef void *(*kmpc_ctor)(void *); 00300 auto KmpcCtorTy = 00301 llvm::FunctionType::get(CGM.VoidPtrTy, CGM.VoidPtrTy, 00302 /*isVarArg*/ false)->getPointerTo(); 00303 // typedef void *(*kmpc_cctor)(void *, void *); 00304 llvm::Type *KmpcCopyCtorTyArgs[] = {CGM.VoidPtrTy, CGM.VoidPtrTy}; 00305 auto KmpcCopyCtorTy = 00306 llvm::FunctionType::get(CGM.VoidPtrTy, KmpcCopyCtorTyArgs, 00307 /*isVarArg*/ false)->getPointerTo(); 00308 // typedef void (*kmpc_dtor)(void *); 00309 auto KmpcDtorTy = 00310 llvm::FunctionType::get(CGM.VoidTy, CGM.VoidPtrTy, /*isVarArg*/ false) 00311 ->getPointerTo(); 00312 llvm::Type *FnTyArgs[] = {getIdentTyPointerTy(), CGM.VoidPtrTy, KmpcCtorTy, 00313 KmpcCopyCtorTy, KmpcDtorTy}; 00314 auto FnTy = llvm::FunctionType::get(CGM.VoidTy, FnTyArgs, 00315 /*isVarArg*/ false); 00316 RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_threadprivate_register"); 00317 break; 00318 } 00319 case OMPRTL__kmpc_end_critical: { 00320 // Build void __kmpc_end_critical(ident_t *loc, kmp_int32 global_tid, 00321 // kmp_critical_name *crit); 00322 llvm::Type *TypeParams[] = { 00323 getIdentTyPointerTy(), CGM.Int32Ty, 00324 llvm::PointerType::getUnqual(KmpCriticalNameTy)}; 00325 llvm::FunctionType *FnTy = 00326 llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false); 00327 RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_end_critical"); 00328 break; 00329 } 00330 case OMPRTL__kmpc_barrier: { 00331 // Build void __kmpc_barrier(ident_t *loc, kmp_int32 global_tid); 00332 llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty}; 00333 llvm::FunctionType *FnTy = 00334 llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false); 00335 RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name*/ "__kmpc_barrier"); 00336 break; 00337 } 00338 case OMPRTL__kmpc_push_num_threads: { 00339 // Build void __kmpc_push_num_threads(ident_t *loc, kmp_int32 global_tid, 00340 // kmp_int32 num_threads) 00341 llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty, 00342 CGM.Int32Ty}; 00343 llvm::FunctionType *FnTy = 00344 llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false); 00345 RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_push_num_threads"); 00346 break; 00347 } 00348 case OMPRTL__kmpc_serialized_parallel: { 00349 // Build void __kmpc_serialized_parallel(ident_t *loc, kmp_int32 00350 // global_tid); 00351 llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty}; 00352 llvm::FunctionType *FnTy = 00353 llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false); 00354 RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_serialized_parallel"); 00355 break; 00356 } 00357 case OMPRTL__kmpc_end_serialized_parallel: { 00358 // Build void __kmpc_end_serialized_parallel(ident_t *loc, kmp_int32 00359 // global_tid); 00360 llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty}; 00361 llvm::FunctionType *FnTy = 00362 llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false); 00363 RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_end_serialized_parallel"); 00364 break; 00365 } 00366 } 00367 return RTLFn; 00368 } 00369 00370 llvm::Constant * 00371 CGOpenMPRuntime::getOrCreateThreadPrivateCache(const VarDecl *VD) { 00372 // Lookup the entry, lazily creating it if necessary. 00373 return GetOrCreateInternalVariable(CGM.Int8PtrPtrTy, 00374 Twine(CGM.getMangledName(VD)) + ".cache."); 00375 } 00376 00377 llvm::Value *CGOpenMPRuntime::getOMPAddrOfThreadPrivate(CodeGenFunction &CGF, 00378 const VarDecl *VD, 00379 llvm::Value *VDAddr, 00380 SourceLocation Loc) { 00381 auto VarTy = VDAddr->getType()->getPointerElementType(); 00382 llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc), 00383 GetOpenMPThreadID(CGF, Loc), 00384 CGF.Builder.CreatePointerCast(VDAddr, CGM.Int8PtrTy), 00385 CGM.getSize(CGM.GetTargetTypeStoreSize(VarTy)), 00386 getOrCreateThreadPrivateCache(VD)}; 00387 return CGF.EmitRuntimeCall( 00388 CreateRuntimeFunction(OMPRTL__kmpc_threadprivate_cached), Args); 00389 } 00390 00391 void CGOpenMPRuntime::EmitOMPThreadPrivateVarInit( 00392 CodeGenFunction &CGF, llvm::Value *VDAddr, llvm::Value *Ctor, 00393 llvm::Value *CopyCtor, llvm::Value *Dtor, SourceLocation Loc) { 00394 // Call kmp_int32 __kmpc_global_thread_num(&loc) to init OpenMP runtime 00395 // library. 00396 auto OMPLoc = EmitOpenMPUpdateLocation(CGF, Loc); 00397 CGF.EmitRuntimeCall(CreateRuntimeFunction(OMPRTL__kmpc_global_thread_num), 00398 OMPLoc); 00399 // Call __kmpc_threadprivate_register(&loc, &var, ctor, cctor/*NULL*/, dtor) 00400 // to register constructor/destructor for variable. 00401 llvm::Value *Args[] = {OMPLoc, 00402 CGF.Builder.CreatePointerCast(VDAddr, CGM.VoidPtrTy), 00403 Ctor, CopyCtor, Dtor}; 00404 CGF.EmitRuntimeCall(CreateRuntimeFunction( 00405 CGOpenMPRuntime::OMPRTL__kmpc_threadprivate_register), 00406 Args); 00407 } 00408 00409 llvm::Function *CGOpenMPRuntime::EmitOMPThreadPrivateVarDefinition( 00410 const VarDecl *VD, llvm::Value *VDAddr, SourceLocation Loc, 00411 bool PerformInit, CodeGenFunction *CGF) { 00412 VD = VD->getDefinition(CGM.getContext()); 00413 if (VD && ThreadPrivateWithDefinition.count(VD) == 0) { 00414 ThreadPrivateWithDefinition.insert(VD); 00415 QualType ASTTy = VD->getType(); 00416 00417 llvm::Value *Ctor = nullptr, *CopyCtor = nullptr, *Dtor = nullptr; 00418 auto Init = VD->getAnyInitializer(); 00419 if (CGM.getLangOpts().CPlusPlus && PerformInit) { 00420 // Generate function that re-emits the declaration's initializer into the 00421 // threadprivate copy of the variable VD 00422 CodeGenFunction CtorCGF(CGM); 00423 FunctionArgList Args; 00424 ImplicitParamDecl Dst(CGM.getContext(), /*DC=*/nullptr, SourceLocation(), 00425 /*Id=*/nullptr, CGM.getContext().VoidPtrTy); 00426 Args.push_back(&Dst); 00427 00428 auto &FI = CGM.getTypes().arrangeFreeFunctionDeclaration( 00429 CGM.getContext().VoidPtrTy, Args, FunctionType::ExtInfo(), 00430 /*isVariadic=*/false); 00431 auto FTy = CGM.getTypes().GetFunctionType(FI); 00432 auto Fn = CGM.CreateGlobalInitOrDestructFunction( 00433 FTy, ".__kmpc_global_ctor_.", Loc); 00434 CtorCGF.StartFunction(GlobalDecl(), CGM.getContext().VoidPtrTy, Fn, FI, 00435 Args, SourceLocation()); 00436 auto ArgVal = CtorCGF.EmitLoadOfScalar( 00437 CtorCGF.GetAddrOfLocalVar(&Dst), 00438 /*Volatile=*/false, CGM.PointerAlignInBytes, 00439 CGM.getContext().VoidPtrTy, Dst.getLocation()); 00440 auto Arg = CtorCGF.Builder.CreatePointerCast( 00441 ArgVal, 00442 CtorCGF.ConvertTypeForMem(CGM.getContext().getPointerType(ASTTy))); 00443 CtorCGF.EmitAnyExprToMem(Init, Arg, Init->getType().getQualifiers(), 00444 /*IsInitializer=*/true); 00445 ArgVal = CtorCGF.EmitLoadOfScalar( 00446 CtorCGF.GetAddrOfLocalVar(&Dst), 00447 /*Volatile=*/false, CGM.PointerAlignInBytes, 00448 CGM.getContext().VoidPtrTy, Dst.getLocation()); 00449 CtorCGF.Builder.CreateStore(ArgVal, CtorCGF.ReturnValue); 00450 CtorCGF.FinishFunction(); 00451 Ctor = Fn; 00452 } 00453 if (VD->getType().isDestructedType() != QualType::DK_none) { 00454 // Generate function that emits destructor call for the threadprivate copy 00455 // of the variable VD 00456 CodeGenFunction DtorCGF(CGM); 00457 FunctionArgList Args; 00458 ImplicitParamDecl Dst(CGM.getContext(), /*DC=*/nullptr, SourceLocation(), 00459 /*Id=*/nullptr, CGM.getContext().VoidPtrTy); 00460 Args.push_back(&Dst); 00461 00462 auto &FI = CGM.getTypes().arrangeFreeFunctionDeclaration( 00463 CGM.getContext().VoidTy, Args, FunctionType::ExtInfo(), 00464 /*isVariadic=*/false); 00465 auto FTy = CGM.getTypes().GetFunctionType(FI); 00466 auto Fn = CGM.CreateGlobalInitOrDestructFunction( 00467 FTy, ".__kmpc_global_dtor_.", Loc); 00468 DtorCGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, Fn, FI, Args, 00469 SourceLocation()); 00470 auto ArgVal = DtorCGF.EmitLoadOfScalar( 00471 DtorCGF.GetAddrOfLocalVar(&Dst), 00472 /*Volatile=*/false, CGM.PointerAlignInBytes, 00473 CGM.getContext().VoidPtrTy, Dst.getLocation()); 00474 DtorCGF.emitDestroy(ArgVal, ASTTy, 00475 DtorCGF.getDestroyer(ASTTy.isDestructedType()), 00476 DtorCGF.needsEHCleanup(ASTTy.isDestructedType())); 00477 DtorCGF.FinishFunction(); 00478 Dtor = Fn; 00479 } 00480 // Do not emit init function if it is not required. 00481 if (!Ctor && !Dtor) 00482 return nullptr; 00483 00484 llvm::Type *CopyCtorTyArgs[] = {CGM.VoidPtrTy, CGM.VoidPtrTy}; 00485 auto CopyCtorTy = 00486 llvm::FunctionType::get(CGM.VoidPtrTy, CopyCtorTyArgs, 00487 /*isVarArg=*/false)->getPointerTo(); 00488 // Copying constructor for the threadprivate variable. 00489 // Must be NULL - reserved by runtime, but currently it requires that this 00490 // parameter is always NULL. Otherwise it fires assertion. 00491 CopyCtor = llvm::Constant::getNullValue(CopyCtorTy); 00492 if (Ctor == nullptr) { 00493 auto CtorTy = llvm::FunctionType::get(CGM.VoidPtrTy, CGM.VoidPtrTy, 00494 /*isVarArg=*/false)->getPointerTo(); 00495 Ctor = llvm::Constant::getNullValue(CtorTy); 00496 } 00497 if (Dtor == nullptr) { 00498 auto DtorTy = llvm::FunctionType::get(CGM.VoidTy, CGM.VoidPtrTy, 00499 /*isVarArg=*/false)->getPointerTo(); 00500 Dtor = llvm::Constant::getNullValue(DtorTy); 00501 } 00502 if (!CGF) { 00503 auto InitFunctionTy = 00504 llvm::FunctionType::get(CGM.VoidTy, /*isVarArg*/ false); 00505 auto InitFunction = CGM.CreateGlobalInitOrDestructFunction( 00506 InitFunctionTy, ".__omp_threadprivate_init_."); 00507 CodeGenFunction InitCGF(CGM); 00508 FunctionArgList ArgList; 00509 InitCGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, InitFunction, 00510 CGM.getTypes().arrangeNullaryFunction(), ArgList, 00511 Loc); 00512 EmitOMPThreadPrivateVarInit(InitCGF, VDAddr, Ctor, CopyCtor, Dtor, Loc); 00513 InitCGF.FinishFunction(); 00514 return InitFunction; 00515 } 00516 EmitOMPThreadPrivateVarInit(*CGF, VDAddr, Ctor, CopyCtor, Dtor, Loc); 00517 } 00518 return nullptr; 00519 } 00520 00521 void CGOpenMPRuntime::EmitOMPParallelCall(CodeGenFunction &CGF, 00522 SourceLocation Loc, 00523 llvm::Value *OutlinedFn, 00524 llvm::Value *CapturedStruct) { 00525 // Build call __kmpc_fork_call(loc, 1, microtask, captured_struct/*context*/) 00526 llvm::Value *Args[] = { 00527 EmitOpenMPUpdateLocation(CGF, Loc), 00528 CGF.Builder.getInt32(1), // Number of arguments after 'microtask' argument 00529 // (there is only one additional argument - 'context') 00530 CGF.Builder.CreateBitCast(OutlinedFn, getKmpc_MicroPointerTy()), 00531 CGF.EmitCastToVoidPtr(CapturedStruct)}; 00532 auto RTLFn = CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_fork_call); 00533 CGF.EmitRuntimeCall(RTLFn, Args); 00534 } 00535 00536 void CGOpenMPRuntime::EmitOMPSerialCall(CodeGenFunction &CGF, 00537 SourceLocation Loc, 00538 llvm::Value *OutlinedFn, 00539 llvm::Value *CapturedStruct) { 00540 auto ThreadID = GetOpenMPThreadID(CGF, Loc); 00541 // Build calls: 00542 // __kmpc_serialized_parallel(&Loc, GTid); 00543 llvm::Value *SerArgs[] = {EmitOpenMPUpdateLocation(CGF, Loc), ThreadID}; 00544 auto RTLFn = 00545 CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_serialized_parallel); 00546 CGF.EmitRuntimeCall(RTLFn, SerArgs); 00547 00548 // OutlinedFn(>id, &zero, CapturedStruct); 00549 auto ThreadIDAddr = EmitThreadIDAddress(CGF, Loc); 00550 auto Int32Ty = 00551 CGF.getContext().getIntTypeForBitwidth(/*DestWidth*/ 32, /*Signed*/ true); 00552 auto ZeroAddr = CGF.CreateMemTemp(Int32Ty, /*Name*/ ".zero.addr"); 00553 CGF.InitTempAlloca(ZeroAddr, CGF.Builder.getInt32(/*C*/ 0)); 00554 llvm::Value *OutlinedFnArgs[] = {ThreadIDAddr, ZeroAddr, CapturedStruct}; 00555 CGF.EmitCallOrInvoke(OutlinedFn, OutlinedFnArgs); 00556 00557 // __kmpc_end_serialized_parallel(&Loc, GTid); 00558 llvm::Value *EndSerArgs[] = {EmitOpenMPUpdateLocation(CGF, Loc), ThreadID}; 00559 RTLFn = CreateRuntimeFunction( 00560 CGOpenMPRuntime::OMPRTL__kmpc_end_serialized_parallel); 00561 CGF.EmitRuntimeCall(RTLFn, EndSerArgs); 00562 } 00563 00564 // If we're inside an (outlined) parallel region, use the region info's 00565 // thread-ID variable (it is passed in a first argument of the outlined function 00566 // as "kmp_int32 *gtid"). Otherwise, if we're not inside parallel region, but in 00567 // regular serial code region, get thread ID by calling kmp_int32 00568 // kmpc_global_thread_num(ident_t *loc), stash this thread ID in a temporary and 00569 // return the address of that temp. 00570 llvm::Value *CGOpenMPRuntime::EmitThreadIDAddress(CodeGenFunction &CGF, 00571 SourceLocation Loc) { 00572 if (auto OMPRegionInfo = 00573 dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) 00574 return CGF.EmitLoadOfLValue(OMPRegionInfo->getThreadIDVariableLValue(CGF), 00575 SourceLocation()).getScalarVal(); 00576 auto ThreadID = GetOpenMPThreadID(CGF, Loc); 00577 auto Int32Ty = 00578 CGF.getContext().getIntTypeForBitwidth(/*DestWidth*/ 32, /*Signed*/ true); 00579 auto ThreadIDTemp = CGF.CreateMemTemp(Int32Ty, /*Name*/ ".threadid_temp."); 00580 CGF.EmitStoreOfScalar(ThreadID, 00581 CGF.MakeNaturalAlignAddrLValue(ThreadIDTemp, Int32Ty)); 00582 00583 return ThreadIDTemp; 00584 } 00585 00586 llvm::Constant * 00587 CGOpenMPRuntime::GetOrCreateInternalVariable(llvm::Type *Ty, 00588 const llvm::Twine &Name) { 00589 SmallString<256> Buffer; 00590 llvm::raw_svector_ostream Out(Buffer); 00591 Out << Name; 00592 auto RuntimeName = Out.str(); 00593 auto &Elem = InternalVars.GetOrCreateValue(RuntimeName); 00594 if (Elem.getValue()) { 00595 assert(Elem.getValue()->getType()->getPointerElementType() == Ty && 00596 "OMP internal variable has different type than requested"); 00597 return &*Elem.getValue(); 00598 } 00599 00600 auto Item = new llvm::GlobalVariable( 00601 CGM.getModule(), Ty, /*IsConstant*/ false, 00602 llvm::GlobalValue::CommonLinkage, 00603 llvm::Constant::getNullValue(Ty), Elem.getKey()); 00604 Elem.setValue(Item); 00605 return Item; 00606 } 00607 00608 llvm::Value *CGOpenMPRuntime::GetCriticalRegionLock(StringRef CriticalName) { 00609 llvm::Twine Name(".gomp_critical_user_", CriticalName); 00610 return GetOrCreateInternalVariable(KmpCriticalNameTy, Name.concat(".var")); 00611 } 00612 00613 void CGOpenMPRuntime::EmitOMPCriticalRegionStart(CodeGenFunction &CGF, 00614 llvm::Value *RegionLock, 00615 SourceLocation Loc) { 00616 // Prepare other arguments and build a call to __kmpc_critical 00617 llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc), 00618 GetOpenMPThreadID(CGF, Loc), RegionLock}; 00619 auto RTLFn = CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_critical); 00620 CGF.EmitRuntimeCall(RTLFn, Args); 00621 } 00622 00623 void CGOpenMPRuntime::EmitOMPCriticalRegionEnd(CodeGenFunction &CGF, 00624 llvm::Value *RegionLock, 00625 SourceLocation Loc) { 00626 // Prepare other arguments and build a call to __kmpc_end_critical 00627 llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc), 00628 GetOpenMPThreadID(CGF, Loc), RegionLock}; 00629 auto RTLFn = 00630 CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_end_critical); 00631 CGF.EmitRuntimeCall(RTLFn, Args); 00632 } 00633 00634 void CGOpenMPRuntime::EmitOMPBarrierCall(CodeGenFunction &CGF, 00635 SourceLocation Loc, 00636 OpenMPLocationFlags Flags) { 00637 // Build call __kmpc_barrier(loc, thread_id) 00638 llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc, Flags), 00639 GetOpenMPThreadID(CGF, Loc)}; 00640 auto RTLFn = CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_barrier); 00641 CGF.EmitRuntimeCall(RTLFn, Args); 00642 } 00643 00644 void CGOpenMPRuntime::EmitOMPNumThreadsClause(CodeGenFunction &CGF, 00645 llvm::Value *NumThreads, 00646 SourceLocation Loc) { 00647 // Build call __kmpc_push_num_threads(&loc, global_tid, num_threads) 00648 llvm::Value *Args[] = { 00649 EmitOpenMPUpdateLocation(CGF, Loc), GetOpenMPThreadID(CGF, Loc), 00650 CGF.Builder.CreateIntCast(NumThreads, CGF.Int32Ty, /*isSigned*/ true)}; 00651 llvm::Constant *RTLFn = CGF.CGM.getOpenMPRuntime().CreateRuntimeFunction( 00652 CGOpenMPRuntime::OMPRTL__kmpc_push_num_threads); 00653 CGF.EmitRuntimeCall(RTLFn, Args); 00654 } 00655