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/StmtOpenMP.h" 17 #include "clang/AST/Decl.h" 18 #include "llvm/ADT/ArrayRef.h" 19 #include "llvm/IR/CallSite.h" 20 #include "llvm/IR/DerivedTypes.h" 21 #include "llvm/IR/GlobalValue.h" 22 #include "llvm/IR/Value.h" 23 #include "llvm/Support/raw_ostream.h" 24 #include <cassert> 25 26 using namespace clang; 27 using namespace CodeGen; 28 29 namespace { 30 /// \brief API for captured statement code generation in OpenMP constructs. 31 class CGOpenMPRegionInfo : public CodeGenFunction::CGCapturedStmtInfo { 32 public: 33 CGOpenMPRegionInfo(const OMPExecutableDirective &D, const CapturedStmt &CS, 34 const VarDecl *ThreadIDVar) 35 : CGCapturedStmtInfo(CS, CR_OpenMP), ThreadIDVar(ThreadIDVar), 36 Directive(D) { 37 assert(ThreadIDVar != nullptr && "No ThreadID in OpenMP region."); 38 } 39 40 /// \brief Gets a variable or parameter for storing global thread id 41 /// inside OpenMP construct. 42 const VarDecl *getThreadIDVariable() const { return ThreadIDVar; } 43 44 /// \brief Gets an LValue for the current ThreadID variable. 45 LValue getThreadIDVariableLValue(CodeGenFunction &CGF); 46 47 static bool classof(const CGCapturedStmtInfo *Info) { 48 return Info->getKind() == CR_OpenMP; 49 } 50 51 /// \brief Emit the captured statement body. 52 void EmitBody(CodeGenFunction &CGF, Stmt *S) override; 53 54 /// \brief Get the name of the capture helper. 55 StringRef getHelperName() const override { return ".omp_outlined."; } 56 57 private: 58 /// \brief A variable or parameter storing global thread id for OpenMP 59 /// constructs. 60 const VarDecl *ThreadIDVar; 61 /// \brief OpenMP executable directive associated with the region. 62 const OMPExecutableDirective &Directive; 63 }; 64 } // namespace 65 66 LValue CGOpenMPRegionInfo::getThreadIDVariableLValue(CodeGenFunction &CGF) { 67 return CGF.MakeNaturalAlignAddrLValue( 68 CGF.GetAddrOfLocalVar(ThreadIDVar), 69 CGF.getContext().getPointerType(ThreadIDVar->getType())); 70 } 71 72 void CGOpenMPRegionInfo::EmitBody(CodeGenFunction &CGF, Stmt *S) { 73 CodeGenFunction::OMPPrivateScope PrivateScope(CGF); 74 CGF.EmitOMPFirstprivateClause(Directive, PrivateScope); 75 if (PrivateScope.Privatize()) { 76 // Emit implicit barrier to synchronize threads and avoid data races. 77 auto Flags = static_cast<CGOpenMPRuntime::OpenMPLocationFlags>( 78 CGOpenMPRuntime::OMP_IDENT_KMPC | 79 CGOpenMPRuntime::OMP_IDENT_BARRIER_IMPL); 80 CGF.CGM.getOpenMPRuntime().EmitOMPBarrierCall(CGF, Directive.getLocStart(), 81 Flags); 82 } 83 CGCapturedStmtInfo::EmitBody(CGF, S); 84 } 85 86 CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM) 87 : CGM(CGM), DefaultOpenMPPSource(nullptr) { 88 IdentTy = llvm::StructType::create( 89 "ident_t", CGM.Int32Ty /* reserved_1 */, CGM.Int32Ty /* flags */, 90 CGM.Int32Ty /* reserved_2 */, CGM.Int32Ty /* reserved_3 */, 91 CGM.Int8PtrTy /* psource */, nullptr); 92 // Build void (*kmpc_micro)(kmp_int32 *global_tid, kmp_int32 *bound_tid,...) 93 llvm::Type *MicroParams[] = {llvm::PointerType::getUnqual(CGM.Int32Ty), 94 llvm::PointerType::getUnqual(CGM.Int32Ty)}; 95 Kmpc_MicroTy = llvm::FunctionType::get(CGM.VoidTy, MicroParams, true); 96 KmpCriticalNameTy = llvm::ArrayType::get(CGM.Int32Ty, /*NumElements*/ 8); 97 } 98 99 llvm::Value * 100 CGOpenMPRuntime::EmitOpenMPOutlinedFunction(const OMPExecutableDirective &D, 101 const VarDecl *ThreadIDVar) { 102 const CapturedStmt *CS = cast<CapturedStmt>(D.getAssociatedStmt()); 103 CodeGenFunction CGF(CGM, true); 104 CGOpenMPRegionInfo CGInfo(D, *CS, ThreadIDVar); 105 CGF.CapturedStmtInfo = &CGInfo; 106 return CGF.GenerateCapturedStmtFunction(*CS); 107 } 108 109 llvm::Value * 110 CGOpenMPRuntime::GetOrCreateDefaultOpenMPLocation(OpenMPLocationFlags Flags) { 111 llvm::Value *Entry = OpenMPDefaultLocMap.lookup(Flags); 112 if (!Entry) { 113 if (!DefaultOpenMPPSource) { 114 // Initialize default location for psource field of ident_t structure of 115 // all ident_t objects. Format is ";file;function;line;column;;". 116 // Taken from 117 // http://llvm.org/svn/llvm-project/openmp/trunk/runtime/src/kmp_str.c 118 DefaultOpenMPPSource = 119 CGM.GetAddrOfConstantCString(";unknown;unknown;0;0;;"); 120 DefaultOpenMPPSource = 121 llvm::ConstantExpr::getBitCast(DefaultOpenMPPSource, CGM.Int8PtrTy); 122 } 123 auto DefaultOpenMPLocation = new llvm::GlobalVariable( 124 CGM.getModule(), IdentTy, /*isConstant*/ true, 125 llvm::GlobalValue::PrivateLinkage, /*Initializer*/ nullptr); 126 DefaultOpenMPLocation->setUnnamedAddr(true); 127 128 llvm::Constant *Zero = llvm::ConstantInt::get(CGM.Int32Ty, 0, true); 129 llvm::Constant *Values[] = {Zero, 130 llvm::ConstantInt::get(CGM.Int32Ty, Flags), 131 Zero, Zero, DefaultOpenMPPSource}; 132 llvm::Constant *Init = llvm::ConstantStruct::get(IdentTy, Values); 133 DefaultOpenMPLocation->setInitializer(Init); 134 OpenMPDefaultLocMap[Flags] = DefaultOpenMPLocation; 135 return DefaultOpenMPLocation; 136 } 137 return Entry; 138 } 139 140 llvm::Value *CGOpenMPRuntime::EmitOpenMPUpdateLocation( 141 CodeGenFunction &CGF, SourceLocation Loc, OpenMPLocationFlags Flags) { 142 // If no debug info is generated - return global default location. 143 if (CGM.getCodeGenOpts().getDebugInfo() == CodeGenOptions::NoDebugInfo || 144 Loc.isInvalid()) 145 return GetOrCreateDefaultOpenMPLocation(Flags); 146 147 assert(CGF.CurFn && "No function in current CodeGenFunction."); 148 149 llvm::Value *LocValue = nullptr; 150 OpenMPLocThreadIDMapTy::iterator I = OpenMPLocThreadIDMap.find(CGF.CurFn); 151 if (I != OpenMPLocThreadIDMap.end()) { 152 LocValue = I->second.DebugLoc; 153 } else { 154 // Generate "ident_t .kmpc_loc.addr;" 155 llvm::AllocaInst *AI = CGF.CreateTempAlloca(IdentTy, ".kmpc_loc.addr"); 156 AI->setAlignment(CGM.getDataLayout().getPrefTypeAlignment(IdentTy)); 157 auto &Elem = OpenMPLocThreadIDMap.FindAndConstruct(CGF.CurFn); 158 Elem.second.DebugLoc = AI; 159 LocValue = AI; 160 161 CGBuilderTy::InsertPointGuard IPG(CGF.Builder); 162 CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt); 163 CGF.Builder.CreateMemCpy(LocValue, GetOrCreateDefaultOpenMPLocation(Flags), 164 llvm::ConstantExpr::getSizeOf(IdentTy), 165 CGM.PointerAlignInBytes); 166 } 167 168 // char **psource = &.kmpc_loc_<flags>.addr.psource; 169 llvm::Value *PSource = 170 CGF.Builder.CreateConstInBoundsGEP2_32(LocValue, 0, IdentField_PSource); 171 172 auto OMPDebugLoc = OpenMPDebugLocMap.lookup(Loc.getRawEncoding()); 173 if (OMPDebugLoc == nullptr) { 174 SmallString<128> Buffer2; 175 llvm::raw_svector_ostream OS2(Buffer2); 176 // Build debug location 177 PresumedLoc PLoc = CGF.getContext().getSourceManager().getPresumedLoc(Loc); 178 OS2 << ";" << PLoc.getFilename() << ";"; 179 if (const FunctionDecl *FD = 180 dyn_cast_or_null<FunctionDecl>(CGF.CurFuncDecl)) { 181 OS2 << FD->getQualifiedNameAsString(); 182 } 183 OS2 << ";" << PLoc.getLine() << ";" << PLoc.getColumn() << ";;"; 184 OMPDebugLoc = CGF.Builder.CreateGlobalStringPtr(OS2.str()); 185 OpenMPDebugLocMap[Loc.getRawEncoding()] = OMPDebugLoc; 186 } 187 // *psource = ";<File>;<Function>;<Line>;<Column>;;"; 188 CGF.Builder.CreateStore(OMPDebugLoc, PSource); 189 190 return LocValue; 191 } 192 193 llvm::Value *CGOpenMPRuntime::GetOpenMPThreadID(CodeGenFunction &CGF, 194 SourceLocation Loc) { 195 assert(CGF.CurFn && "No function in current CodeGenFunction."); 196 197 llvm::Value *ThreadID = nullptr; 198 // Check whether we've already cached a load of the thread id in this 199 // function. 200 OpenMPLocThreadIDMapTy::iterator I = OpenMPLocThreadIDMap.find(CGF.CurFn); 201 if (I != OpenMPLocThreadIDMap.end()) { 202 ThreadID = I->second.ThreadID; 203 } else if (auto OMPRegionInfo = 204 dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) { 205 // Check if this an outlined function with thread id passed as argument. 206 auto ThreadIDVar = OMPRegionInfo->getThreadIDVariable(); 207 auto LVal = OMPRegionInfo->getThreadIDVariableLValue(CGF); 208 auto RVal = CGF.EmitLoadOfLValue(LVal, Loc); 209 LVal = CGF.MakeNaturalAlignAddrLValue(RVal.getScalarVal(), 210 ThreadIDVar->getType()); 211 ThreadID = CGF.EmitLoadOfLValue(LVal, Loc).getScalarVal(); 212 // If value loaded in entry block, cache it and use it everywhere in 213 // function. 214 if (CGF.Builder.GetInsertBlock() == CGF.AllocaInsertPt->getParent()) { 215 auto &Elem = OpenMPLocThreadIDMap.FindAndConstruct(CGF.CurFn); 216 Elem.second.ThreadID = ThreadID; 217 } 218 } else { 219 // This is not an outlined function region - need to call __kmpc_int32 220 // kmpc_global_thread_num(ident_t *loc). 221 // Generate thread id value and cache this value for use across the 222 // function. 223 CGBuilderTy::InsertPointGuard IPG(CGF.Builder); 224 CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt); 225 llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc)}; 226 ThreadID = CGF.EmitRuntimeCall( 227 CreateRuntimeFunction(OMPRTL__kmpc_global_thread_num), Args); 228 auto &Elem = OpenMPLocThreadIDMap.FindAndConstruct(CGF.CurFn); 229 Elem.second.ThreadID = ThreadID; 230 } 231 return ThreadID; 232 } 233 234 void CGOpenMPRuntime::FunctionFinished(CodeGenFunction &CGF) { 235 assert(CGF.CurFn && "No function in current CodeGenFunction."); 236 OpenMPLocThreadIDMap.erase(CGF.CurFn); 237 } 238 239 llvm::Type *CGOpenMPRuntime::getIdentTyPointerTy() { 240 return llvm::PointerType::getUnqual(IdentTy); 241 } 242 243 llvm::Type *CGOpenMPRuntime::getKmpc_MicroPointerTy() { 244 return llvm::PointerType::getUnqual(Kmpc_MicroTy); 245 } 246 247 llvm::Constant * 248 CGOpenMPRuntime::CreateRuntimeFunction(OpenMPRTLFunction Function) { 249 llvm::Constant *RTLFn = nullptr; 250 switch (Function) { 251 case OMPRTL__kmpc_fork_call: { 252 // Build void __kmpc_fork_call(ident_t *loc, kmp_int32 argc, kmpc_micro 253 // microtask, ...); 254 llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty, 255 getKmpc_MicroPointerTy()}; 256 llvm::FunctionType *FnTy = 257 llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ true); 258 RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_fork_call"); 259 break; 260 } 261 case OMPRTL__kmpc_global_thread_num: { 262 // Build kmp_int32 __kmpc_global_thread_num(ident_t *loc); 263 llvm::Type *TypeParams[] = {getIdentTyPointerTy()}; 264 llvm::FunctionType *FnTy = 265 llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false); 266 RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_global_thread_num"); 267 break; 268 } 269 case OMPRTL__kmpc_critical: { 270 // Build void __kmpc_critical(ident_t *loc, kmp_int32 global_tid, 271 // kmp_critical_name *crit); 272 llvm::Type *TypeParams[] = { 273 getIdentTyPointerTy(), CGM.Int32Ty, 274 llvm::PointerType::getUnqual(KmpCriticalNameTy)}; 275 llvm::FunctionType *FnTy = 276 llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false); 277 RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_critical"); 278 break; 279 } 280 case OMPRTL__kmpc_end_critical: { 281 // Build void __kmpc_end_critical(ident_t *loc, kmp_int32 global_tid, 282 // kmp_critical_name *crit); 283 llvm::Type *TypeParams[] = { 284 getIdentTyPointerTy(), CGM.Int32Ty, 285 llvm::PointerType::getUnqual(KmpCriticalNameTy)}; 286 llvm::FunctionType *FnTy = 287 llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false); 288 RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_end_critical"); 289 break; 290 } 291 case OMPRTL__kmpc_barrier: { 292 // Build void __kmpc_barrier(ident_t *loc, kmp_int32 global_tid); 293 llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty}; 294 llvm::FunctionType *FnTy = 295 llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false); 296 RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name*/ "__kmpc_barrier"); 297 break; 298 } 299 case OMPRTL__kmpc_push_num_threads: { 300 // Build void __kmpc_push_num_threads(ident_t *loc, kmp_int32 global_tid, 301 // kmp_int32 num_threads) 302 llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty, 303 CGM.Int32Ty}; 304 llvm::FunctionType *FnTy = 305 llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false); 306 RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_push_num_threads"); 307 break; 308 } 309 case OMPRTL__kmpc_serialized_parallel: { 310 // Build void __kmpc_serialized_parallel(ident_t *loc, kmp_int32 311 // global_tid); 312 llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty}; 313 llvm::FunctionType *FnTy = 314 llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false); 315 RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_serialized_parallel"); 316 break; 317 } 318 case OMPRTL__kmpc_end_serialized_parallel: { 319 // Build void __kmpc_end_serialized_parallel(ident_t *loc, kmp_int32 320 // global_tid); 321 llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty}; 322 llvm::FunctionType *FnTy = 323 llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false); 324 RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_end_serialized_parallel"); 325 break; 326 } 327 } 328 return RTLFn; 329 } 330 331 void CGOpenMPRuntime::EmitOMPParallelCall(CodeGenFunction &CGF, 332 SourceLocation Loc, 333 llvm::Value *OutlinedFn, 334 llvm::Value *CapturedStruct) { 335 // Build call __kmpc_fork_call(loc, 1, microtask, captured_struct/*context*/) 336 llvm::Value *Args[] = { 337 EmitOpenMPUpdateLocation(CGF, Loc), 338 CGF.Builder.getInt32(1), // Number of arguments after 'microtask' argument 339 // (there is only one additional argument - 'context') 340 CGF.Builder.CreateBitCast(OutlinedFn, getKmpc_MicroPointerTy()), 341 CGF.EmitCastToVoidPtr(CapturedStruct)}; 342 auto RTLFn = CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_fork_call); 343 CGF.EmitRuntimeCall(RTLFn, Args); 344 } 345 346 void CGOpenMPRuntime::EmitOMPSerialCall(CodeGenFunction &CGF, 347 SourceLocation Loc, 348 llvm::Value *OutlinedFn, 349 llvm::Value *CapturedStruct) { 350 auto ThreadID = GetOpenMPThreadID(CGF, Loc); 351 // Build calls: 352 // __kmpc_serialized_parallel(&Loc, GTid); 353 llvm::Value *SerArgs[] = {EmitOpenMPUpdateLocation(CGF, Loc), ThreadID}; 354 auto RTLFn = 355 CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_serialized_parallel); 356 CGF.EmitRuntimeCall(RTLFn, SerArgs); 357 358 // OutlinedFn(>id, &zero, CapturedStruct); 359 auto ThreadIDAddr = EmitThreadIDAddress(CGF, Loc); 360 auto Int32Ty = 361 CGF.getContext().getIntTypeForBitwidth(/*DestWidth*/ 32, /*Signed*/ true); 362 auto ZeroAddr = CGF.CreateMemTemp(Int32Ty, /*Name*/ ".zero.addr"); 363 CGF.InitTempAlloca(ZeroAddr, CGF.Builder.getInt32(/*C*/ 0)); 364 llvm::Value *OutlinedFnArgs[] = {ThreadIDAddr, ZeroAddr, CapturedStruct}; 365 CGF.EmitCallOrInvoke(OutlinedFn, OutlinedFnArgs); 366 367 // __kmpc_end_serialized_parallel(&Loc, GTid); 368 llvm::Value *EndSerArgs[] = {EmitOpenMPUpdateLocation(CGF, Loc), ThreadID}; 369 RTLFn = CreateRuntimeFunction( 370 CGOpenMPRuntime::OMPRTL__kmpc_end_serialized_parallel); 371 CGF.EmitRuntimeCall(RTLFn, EndSerArgs); 372 } 373 374 // If we’re inside an (outlined) parallel region, use the region info’s 375 // thread-ID variable (it is passed in a first argument of the outlined function 376 // as "kmp_int32 *gtid"). Otherwise, if we're not inside parallel region, but in 377 // regular serial code region, get thread ID by calling kmp_int32 378 // kmpc_global_thread_num(ident_t *loc), stash this thread ID in a temporary and 379 // return the address of that temp. 380 llvm::Value *CGOpenMPRuntime::EmitThreadIDAddress(CodeGenFunction &CGF, 381 SourceLocation Loc) { 382 if (auto OMPRegionInfo = 383 dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) 384 return CGF.EmitLoadOfLValue(OMPRegionInfo->getThreadIDVariableLValue(CGF), 385 SourceLocation()).getScalarVal(); 386 auto ThreadID = GetOpenMPThreadID(CGF, Loc); 387 auto Int32Ty = 388 CGF.getContext().getIntTypeForBitwidth(/*DestWidth*/ 32, /*Signed*/ true); 389 auto ThreadIDTemp = CGF.CreateMemTemp(Int32Ty, /*Name*/ ".threadid_temp."); 390 CGF.EmitStoreOfScalar(ThreadID, 391 CGF.MakeNaturalAlignAddrLValue(ThreadIDTemp, Int32Ty)); 392 393 return ThreadIDTemp; 394 } 395 396 llvm::Value *CGOpenMPRuntime::GetCriticalRegionLock(StringRef CriticalName) { 397 SmallString<256> Buffer; 398 llvm::raw_svector_ostream Out(Buffer); 399 Out << ".gomp_critical_user_" << CriticalName << ".var"; 400 auto RuntimeCriticalName = Out.str(); 401 auto &Elem = CriticalRegionVarNames.GetOrCreateValue(RuntimeCriticalName); 402 if (Elem.getValue() != nullptr) 403 return Elem.getValue(); 404 405 auto Lock = new llvm::GlobalVariable( 406 CGM.getModule(), KmpCriticalNameTy, /*IsConstant*/ false, 407 llvm::GlobalValue::CommonLinkage, 408 llvm::Constant::getNullValue(KmpCriticalNameTy), Elem.getKey()); 409 Elem.setValue(Lock); 410 return Lock; 411 } 412 413 void CGOpenMPRuntime::EmitOMPCriticalRegionStart(CodeGenFunction &CGF, 414 llvm::Value *RegionLock, 415 SourceLocation Loc) { 416 // Prepare other arguments and build a call to __kmpc_critical 417 llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc), 418 GetOpenMPThreadID(CGF, Loc), RegionLock}; 419 auto RTLFn = CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_critical); 420 CGF.EmitRuntimeCall(RTLFn, Args); 421 } 422 423 void CGOpenMPRuntime::EmitOMPCriticalRegionEnd(CodeGenFunction &CGF, 424 llvm::Value *RegionLock, 425 SourceLocation Loc) { 426 // Prepare other arguments and build a call to __kmpc_end_critical 427 llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc), 428 GetOpenMPThreadID(CGF, Loc), RegionLock}; 429 auto RTLFn = 430 CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_end_critical); 431 CGF.EmitRuntimeCall(RTLFn, Args); 432 } 433 434 void CGOpenMPRuntime::EmitOMPBarrierCall(CodeGenFunction &CGF, 435 SourceLocation Loc, 436 OpenMPLocationFlags Flags) { 437 // Build call __kmpc_barrier(loc, thread_id) 438 llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc, Flags), 439 GetOpenMPThreadID(CGF, Loc)}; 440 auto RTLFn = CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_barrier); 441 CGF.EmitRuntimeCall(RTLFn, Args); 442 } 443 444 void CGOpenMPRuntime::EmitOMPNumThreadsClause(CodeGenFunction &CGF, 445 llvm::Value *NumThreads, 446 SourceLocation Loc) { 447 // Build call __kmpc_push_num_threads(&loc, global_tid, num_threads) 448 llvm::Value *Args[] = { 449 EmitOpenMPUpdateLocation(CGF, Loc), GetOpenMPThreadID(CGF, Loc), 450 CGF.Builder.CreateIntCast(NumThreads, CGF.Int32Ty, /*isSigned*/ true)}; 451 llvm::Constant *RTLFn = CGF.CGM.getOpenMPRuntime().CreateRuntimeFunction( 452 CGOpenMPRuntime::OMPRTL__kmpc_push_num_threads); 453 CGF.EmitRuntimeCall(RTLFn, Args); 454 } 455 456