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