1 //===----- CGHLSLRuntime.cpp - Interface to HLSL Runtimes -----------------===// 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 provides an abstract class for HLSL code generation. Concrete 10 // subclasses of this implement code generation for specific HLSL 11 // runtime libraries. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "CGHLSLRuntime.h" 16 #include "CGDebugInfo.h" 17 #include "CodeGenModule.h" 18 #include "TargetInfo.h" 19 #include "clang/AST/Decl.h" 20 #include "clang/Basic/TargetOptions.h" 21 #include "llvm/IR/GlobalVariable.h" 22 #include "llvm/IR/LLVMContext.h" 23 #include "llvm/IR/Metadata.h" 24 #include "llvm/IR/Module.h" 25 #include "llvm/IR/Value.h" 26 #include "llvm/Support/Alignment.h" 27 28 #include "llvm/Support/FormatVariadic.h" 29 30 using namespace clang; 31 using namespace CodeGen; 32 using namespace clang::hlsl; 33 using namespace llvm; 34 35 namespace { 36 37 void addDxilValVersion(StringRef ValVersionStr, llvm::Module &M) { 38 // The validation of ValVersionStr is done at HLSLToolChain::TranslateArgs. 39 // Assume ValVersionStr is legal here. 40 VersionTuple Version; 41 if (Version.tryParse(ValVersionStr) || Version.getBuild() || 42 Version.getSubminor() || !Version.getMinor()) { 43 return; 44 } 45 46 uint64_t Major = Version.getMajor(); 47 uint64_t Minor = *Version.getMinor(); 48 49 auto &Ctx = M.getContext(); 50 IRBuilder<> B(M.getContext()); 51 MDNode *Val = MDNode::get(Ctx, {ConstantAsMetadata::get(B.getInt32(Major)), 52 ConstantAsMetadata::get(B.getInt32(Minor))}); 53 StringRef DXILValKey = "dx.valver"; 54 auto *DXILValMD = M.getOrInsertNamedMetadata(DXILValKey); 55 DXILValMD->addOperand(Val); 56 } 57 void addDisableOptimizations(llvm::Module &M) { 58 StringRef Key = "dx.disable_optimizations"; 59 M.addModuleFlag(llvm::Module::ModFlagBehavior::Override, Key, 1); 60 } 61 // cbuffer will be translated into global variable in special address space. 62 // If translate into C, 63 // cbuffer A { 64 // float a; 65 // float b; 66 // } 67 // float foo() { return a + b; } 68 // 69 // will be translated into 70 // 71 // struct A { 72 // float a; 73 // float b; 74 // } cbuffer_A __attribute__((address_space(4))); 75 // float foo() { return cbuffer_A.a + cbuffer_A.b; } 76 // 77 // layoutBuffer will create the struct A type. 78 // replaceBuffer will replace use of global variable a and b with cbuffer_A.a 79 // and cbuffer_A.b. 80 // 81 void layoutBuffer(CGHLSLRuntime::Buffer &Buf, const DataLayout &DL) { 82 if (Buf.Constants.empty()) 83 return; 84 85 std::vector<llvm::Type *> EltTys; 86 for (auto &Const : Buf.Constants) { 87 GlobalVariable *GV = Const.first; 88 Const.second = EltTys.size(); 89 llvm::Type *Ty = GV->getValueType(); 90 EltTys.emplace_back(Ty); 91 } 92 Buf.LayoutStruct = llvm::StructType::get(EltTys[0]->getContext(), EltTys); 93 } 94 95 GlobalVariable *replaceBuffer(CGHLSLRuntime::Buffer &Buf) { 96 // Create global variable for CB. 97 GlobalVariable *CBGV = new GlobalVariable( 98 Buf.LayoutStruct, /*isConstant*/ true, 99 GlobalValue::LinkageTypes::ExternalLinkage, nullptr, 100 llvm::formatv("{0}{1}", Buf.Name, Buf.IsCBuffer ? ".cb." : ".tb."), 101 GlobalValue::NotThreadLocal); 102 103 return CBGV; 104 } 105 106 } // namespace 107 108 llvm::Type *CGHLSLRuntime::convertHLSLSpecificType(const Type *T) { 109 assert(T->isHLSLSpecificType() && "Not an HLSL specific type!"); 110 111 // Check if the target has a specific translation for this type first. 112 if (llvm::Type *TargetTy = CGM.getTargetCodeGenInfo().getHLSLType(CGM, T)) 113 return TargetTy; 114 115 llvm_unreachable("Generic handling of HLSL types is not supported."); 116 } 117 118 llvm::Triple::ArchType CGHLSLRuntime::getArch() { 119 return CGM.getTarget().getTriple().getArch(); 120 } 121 122 void CGHLSLRuntime::addConstant(VarDecl *D, Buffer &CB) { 123 if (D->getStorageClass() == SC_Static) { 124 // For static inside cbuffer, take as global static. 125 // Don't add to cbuffer. 126 CGM.EmitGlobal(D); 127 return; 128 } 129 130 auto *GV = cast<GlobalVariable>(CGM.GetAddrOfGlobalVar(D)); 131 GV->setExternallyInitialized(true); 132 // Add debug info for constVal. 133 if (CGDebugInfo *DI = CGM.getModuleDebugInfo()) 134 if (CGM.getCodeGenOpts().getDebugInfo() >= 135 codegenoptions::DebugInfoKind::LimitedDebugInfo) 136 DI->EmitGlobalVariable(cast<GlobalVariable>(GV), D); 137 138 // FIXME: support packoffset. 139 // See https://github.com/llvm/llvm-project/issues/57914. 140 uint32_t Offset = 0; 141 bool HasUserOffset = false; 142 143 unsigned LowerBound = HasUserOffset ? Offset : UINT_MAX; 144 CB.Constants.emplace_back(std::make_pair(GV, LowerBound)); 145 } 146 147 void CGHLSLRuntime::addBufferDecls(const DeclContext *DC, Buffer &CB) { 148 for (Decl *it : DC->decls()) { 149 if (auto *ConstDecl = dyn_cast<VarDecl>(it)) { 150 addConstant(ConstDecl, CB); 151 } else if (isa<CXXRecordDecl, EmptyDecl>(it)) { 152 // Nothing to do for this declaration. 153 } else if (isa<FunctionDecl>(it)) { 154 // A function within an cbuffer is effectively a top-level function, 155 // as it only refers to globally scoped declarations. 156 CGM.EmitTopLevelDecl(it); 157 } 158 } 159 } 160 161 void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *D) { 162 Buffers.emplace_back(Buffer(D)); 163 addBufferDecls(D, Buffers.back()); 164 } 165 166 void CGHLSLRuntime::finishCodeGen() { 167 auto &TargetOpts = CGM.getTarget().getTargetOpts(); 168 llvm::Module &M = CGM.getModule(); 169 Triple T(M.getTargetTriple()); 170 if (T.getArch() == Triple::ArchType::dxil) 171 addDxilValVersion(TargetOpts.DxilValidatorVersion, M); 172 173 generateGlobalCtorDtorCalls(); 174 if (CGM.getCodeGenOpts().OptimizationLevel == 0) 175 addDisableOptimizations(M); 176 177 const DataLayout &DL = M.getDataLayout(); 178 179 for (auto &Buf : Buffers) { 180 layoutBuffer(Buf, DL); 181 GlobalVariable *GV = replaceBuffer(Buf); 182 M.insertGlobalVariable(GV); 183 llvm::hlsl::ResourceClass RC = Buf.IsCBuffer 184 ? llvm::hlsl::ResourceClass::CBuffer 185 : llvm::hlsl::ResourceClass::SRV; 186 llvm::hlsl::ResourceKind RK = Buf.IsCBuffer 187 ? llvm::hlsl::ResourceKind::CBuffer 188 : llvm::hlsl::ResourceKind::TBuffer; 189 addBufferResourceAnnotation(GV, RC, RK, /*IsROV=*/false, 190 llvm::hlsl::ElementType::Invalid, Buf.Binding); 191 } 192 } 193 194 CGHLSLRuntime::Buffer::Buffer(const HLSLBufferDecl *D) 195 : Name(D->getName()), IsCBuffer(D->isCBuffer()), 196 Binding(D->getAttr<HLSLResourceBindingAttr>()) {} 197 198 void CGHLSLRuntime::addBufferResourceAnnotation(llvm::GlobalVariable *GV, 199 llvm::hlsl::ResourceClass RC, 200 llvm::hlsl::ResourceKind RK, 201 bool IsROV, 202 llvm::hlsl::ElementType ET, 203 BufferResBinding &Binding) { 204 llvm::Module &M = CGM.getModule(); 205 206 NamedMDNode *ResourceMD = nullptr; 207 switch (RC) { 208 case llvm::hlsl::ResourceClass::UAV: 209 ResourceMD = M.getOrInsertNamedMetadata("hlsl.uavs"); 210 break; 211 case llvm::hlsl::ResourceClass::SRV: 212 ResourceMD = M.getOrInsertNamedMetadata("hlsl.srvs"); 213 break; 214 case llvm::hlsl::ResourceClass::CBuffer: 215 ResourceMD = M.getOrInsertNamedMetadata("hlsl.cbufs"); 216 break; 217 default: 218 assert(false && "Unsupported buffer type!"); 219 return; 220 } 221 assert(ResourceMD != nullptr && 222 "ResourceMD must have been set by the switch above."); 223 224 llvm::hlsl::FrontendResource Res( 225 GV, RK, ET, IsROV, Binding.Reg.value_or(UINT_MAX), Binding.Space); 226 ResourceMD->addOperand(Res.getMetadata()); 227 } 228 229 static llvm::hlsl::ElementType 230 calculateElementType(const ASTContext &Context, const clang::Type *ResourceTy) { 231 using llvm::hlsl::ElementType; 232 233 // TODO: We may need to update this when we add things like ByteAddressBuffer 234 // that don't have a template parameter (or, indeed, an element type). 235 const auto *TST = ResourceTy->getAs<TemplateSpecializationType>(); 236 assert(TST && "Resource types must be template specializations"); 237 ArrayRef<TemplateArgument> Args = TST->template_arguments(); 238 assert(!Args.empty() && "Resource has no element type"); 239 240 // At this point we have a resource with an element type, so we can assume 241 // that it's valid or we would have diagnosed the error earlier. 242 QualType ElTy = Args[0].getAsType(); 243 244 // We should either have a basic type or a vector of a basic type. 245 if (const auto *VecTy = ElTy->getAs<clang::VectorType>()) 246 ElTy = VecTy->getElementType(); 247 248 if (ElTy->isSignedIntegerType()) { 249 switch (Context.getTypeSize(ElTy)) { 250 case 16: 251 return ElementType::I16; 252 case 32: 253 return ElementType::I32; 254 case 64: 255 return ElementType::I64; 256 } 257 } else if (ElTy->isUnsignedIntegerType()) { 258 switch (Context.getTypeSize(ElTy)) { 259 case 16: 260 return ElementType::U16; 261 case 32: 262 return ElementType::U32; 263 case 64: 264 return ElementType::U64; 265 } 266 } else if (ElTy->isSpecificBuiltinType(BuiltinType::Half)) 267 return ElementType::F16; 268 else if (ElTy->isSpecificBuiltinType(BuiltinType::Float)) 269 return ElementType::F32; 270 else if (ElTy->isSpecificBuiltinType(BuiltinType::Double)) 271 return ElementType::F64; 272 273 // TODO: We need to handle unorm/snorm float types here once we support them 274 llvm_unreachable("Invalid element type for resource"); 275 } 276 277 void CGHLSLRuntime::annotateHLSLResource(const VarDecl *D, GlobalVariable *GV) { 278 const Type *Ty = D->getType()->getPointeeOrArrayElementType(); 279 if (!Ty) 280 return; 281 const auto *RD = Ty->getAsCXXRecordDecl(); 282 if (!RD) 283 return; 284 // the resource related attributes are on the handle member 285 // inside the record decl 286 for (auto *FD : RD->fields()) { 287 const auto *HLSLResAttr = FD->getAttr<HLSLResourceAttr>(); 288 const HLSLAttributedResourceType *AttrResType = 289 dyn_cast<HLSLAttributedResourceType>(FD->getType().getTypePtr()); 290 if (!HLSLResAttr || !AttrResType) 291 continue; 292 293 llvm::hlsl::ResourceClass RC = AttrResType->getAttrs().ResourceClass; 294 if (RC == llvm::hlsl::ResourceClass::UAV || 295 RC == llvm::hlsl::ResourceClass::SRV) 296 // UAVs and SRVs have already been converted to use LLVM target types, 297 // we can disable generating of these resource annotations. This will 298 // enable progress on structured buffers with user defined types this 299 // resource annotations code does not handle and it crashes. 300 // This whole function is going to be removed as soon as cbuffers are 301 // converted to target types (llvm/llvm-project #114126). 302 return; 303 304 bool IsROV = AttrResType->getAttrs().IsROV; 305 llvm::hlsl::ResourceKind RK = HLSLResAttr->getResourceKind(); 306 llvm::hlsl::ElementType ET = calculateElementType(CGM.getContext(), Ty); 307 308 BufferResBinding Binding(D->getAttr<HLSLResourceBindingAttr>()); 309 addBufferResourceAnnotation(GV, RC, RK, IsROV, ET, Binding); 310 } 311 } 312 313 CGHLSLRuntime::BufferResBinding::BufferResBinding( 314 HLSLResourceBindingAttr *Binding) { 315 if (Binding) { 316 llvm::APInt RegInt(64, 0); 317 Binding->getSlot().substr(1).getAsInteger(10, RegInt); 318 Reg = RegInt.getLimitedValue(); 319 llvm::APInt SpaceInt(64, 0); 320 Binding->getSpace().substr(5).getAsInteger(10, SpaceInt); 321 Space = SpaceInt.getLimitedValue(); 322 } else { 323 Space = 0; 324 } 325 } 326 327 void clang::CodeGen::CGHLSLRuntime::setHLSLEntryAttributes( 328 const FunctionDecl *FD, llvm::Function *Fn) { 329 const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>(); 330 assert(ShaderAttr && "All entry functions must have a HLSLShaderAttr"); 331 const StringRef ShaderAttrKindStr = "hlsl.shader"; 332 Fn->addFnAttr(ShaderAttrKindStr, 333 llvm::Triple::getEnvironmentTypeName(ShaderAttr->getType())); 334 if (HLSLNumThreadsAttr *NumThreadsAttr = FD->getAttr<HLSLNumThreadsAttr>()) { 335 const StringRef NumThreadsKindStr = "hlsl.numthreads"; 336 std::string NumThreadsStr = 337 formatv("{0},{1},{2}", NumThreadsAttr->getX(), NumThreadsAttr->getY(), 338 NumThreadsAttr->getZ()); 339 Fn->addFnAttr(NumThreadsKindStr, NumThreadsStr); 340 } 341 if (HLSLWaveSizeAttr *WaveSizeAttr = FD->getAttr<HLSLWaveSizeAttr>()) { 342 const StringRef WaveSizeKindStr = "hlsl.wavesize"; 343 std::string WaveSizeStr = 344 formatv("{0},{1},{2}", WaveSizeAttr->getMin(), WaveSizeAttr->getMax(), 345 WaveSizeAttr->getPreferred()); 346 Fn->addFnAttr(WaveSizeKindStr, WaveSizeStr); 347 } 348 Fn->addFnAttr(llvm::Attribute::NoInline); 349 } 350 351 static Value *buildVectorInput(IRBuilder<> &B, Function *F, llvm::Type *Ty) { 352 if (const auto *VT = dyn_cast<FixedVectorType>(Ty)) { 353 Value *Result = PoisonValue::get(Ty); 354 for (unsigned I = 0; I < VT->getNumElements(); ++I) { 355 Value *Elt = B.CreateCall(F, {B.getInt32(I)}); 356 Result = B.CreateInsertElement(Result, Elt, I); 357 } 358 return Result; 359 } 360 return B.CreateCall(F, {B.getInt32(0)}); 361 } 362 363 llvm::Value *CGHLSLRuntime::emitInputSemantic(IRBuilder<> &B, 364 const ParmVarDecl &D, 365 llvm::Type *Ty) { 366 assert(D.hasAttrs() && "Entry parameter missing annotation attribute!"); 367 if (D.hasAttr<HLSLSV_GroupIndexAttr>()) { 368 llvm::Function *DxGroupIndex = 369 CGM.getIntrinsic(Intrinsic::dx_flattened_thread_id_in_group); 370 return B.CreateCall(FunctionCallee(DxGroupIndex)); 371 } 372 if (D.hasAttr<HLSLSV_DispatchThreadIDAttr>()) { 373 llvm::Function *ThreadIDIntrinsic = 374 CGM.getIntrinsic(getThreadIdIntrinsic()); 375 return buildVectorInput(B, ThreadIDIntrinsic, Ty); 376 } 377 if (D.hasAttr<HLSLSV_GroupThreadIDAttr>()) { 378 llvm::Function *GroupThreadIDIntrinsic = 379 CGM.getIntrinsic(getGroupThreadIdIntrinsic()); 380 return buildVectorInput(B, GroupThreadIDIntrinsic, Ty); 381 } 382 if (D.hasAttr<HLSLSV_GroupIDAttr>()) { 383 llvm::Function *GroupIDIntrinsic = CGM.getIntrinsic(getGroupIdIntrinsic()); 384 return buildVectorInput(B, GroupIDIntrinsic, Ty); 385 } 386 assert(false && "Unhandled parameter attribute"); 387 return nullptr; 388 } 389 390 void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD, 391 llvm::Function *Fn) { 392 llvm::Module &M = CGM.getModule(); 393 llvm::LLVMContext &Ctx = M.getContext(); 394 auto *EntryTy = llvm::FunctionType::get(llvm::Type::getVoidTy(Ctx), false); 395 Function *EntryFn = 396 Function::Create(EntryTy, Function::ExternalLinkage, FD->getName(), &M); 397 398 // Copy function attributes over, we have no argument or return attributes 399 // that can be valid on the real entry. 400 AttributeList NewAttrs = AttributeList::get(Ctx, AttributeList::FunctionIndex, 401 Fn->getAttributes().getFnAttrs()); 402 EntryFn->setAttributes(NewAttrs); 403 setHLSLEntryAttributes(FD, EntryFn); 404 405 // Set the called function as internal linkage. 406 Fn->setLinkage(GlobalValue::InternalLinkage); 407 408 BasicBlock *BB = BasicBlock::Create(Ctx, "entry", EntryFn); 409 IRBuilder<> B(BB); 410 llvm::SmallVector<Value *> Args; 411 412 SmallVector<OperandBundleDef, 1> OB; 413 if (CGM.shouldEmitConvergenceTokens()) { 414 assert(EntryFn->isConvergent()); 415 llvm::Value *I = B.CreateIntrinsic( 416 llvm::Intrinsic::experimental_convergence_entry, {}, {}); 417 llvm::Value *bundleArgs[] = {I}; 418 OB.emplace_back("convergencectrl", bundleArgs); 419 } 420 421 // FIXME: support struct parameters where semantics are on members. 422 // See: https://github.com/llvm/llvm-project/issues/57874 423 unsigned SRetOffset = 0; 424 for (const auto &Param : Fn->args()) { 425 if (Param.hasStructRetAttr()) { 426 // FIXME: support output. 427 // See: https://github.com/llvm/llvm-project/issues/57874 428 SRetOffset = 1; 429 Args.emplace_back(PoisonValue::get(Param.getType())); 430 continue; 431 } 432 const ParmVarDecl *PD = FD->getParamDecl(Param.getArgNo() - SRetOffset); 433 Args.push_back(emitInputSemantic(B, *PD, Param.getType())); 434 } 435 436 CallInst *CI = B.CreateCall(FunctionCallee(Fn), Args, OB); 437 CI->setCallingConv(Fn->getCallingConv()); 438 // FIXME: Handle codegen for return type semantics. 439 // See: https://github.com/llvm/llvm-project/issues/57875 440 B.CreateRetVoid(); 441 } 442 443 void CGHLSLRuntime::setHLSLFunctionAttributes(const FunctionDecl *FD, 444 llvm::Function *Fn) { 445 if (FD->isInExportDeclContext()) { 446 const StringRef ExportAttrKindStr = "hlsl.export"; 447 Fn->addFnAttr(ExportAttrKindStr); 448 } 449 } 450 451 static void gatherFunctions(SmallVectorImpl<Function *> &Fns, llvm::Module &M, 452 bool CtorOrDtor) { 453 const auto *GV = 454 M.getNamedGlobal(CtorOrDtor ? "llvm.global_ctors" : "llvm.global_dtors"); 455 if (!GV) 456 return; 457 const auto *CA = dyn_cast<ConstantArray>(GV->getInitializer()); 458 if (!CA) 459 return; 460 // The global_ctor array elements are a struct [Priority, Fn *, COMDat]. 461 // HLSL neither supports priorities or COMDat values, so we will check those 462 // in an assert but not handle them. 463 464 llvm::SmallVector<Function *> CtorFns; 465 for (const auto &Ctor : CA->operands()) { 466 if (isa<ConstantAggregateZero>(Ctor)) 467 continue; 468 ConstantStruct *CS = cast<ConstantStruct>(Ctor); 469 470 assert(cast<ConstantInt>(CS->getOperand(0))->getValue() == 65535 && 471 "HLSL doesn't support setting priority for global ctors."); 472 assert(isa<ConstantPointerNull>(CS->getOperand(2)) && 473 "HLSL doesn't support COMDat for global ctors."); 474 Fns.push_back(cast<Function>(CS->getOperand(1))); 475 } 476 } 477 478 void CGHLSLRuntime::generateGlobalCtorDtorCalls() { 479 llvm::Module &M = CGM.getModule(); 480 SmallVector<Function *> CtorFns; 481 SmallVector<Function *> DtorFns; 482 gatherFunctions(CtorFns, M, true); 483 gatherFunctions(DtorFns, M, false); 484 485 // Insert a call to the global constructor at the beginning of the entry block 486 // to externally exported functions. This is a bit of a hack, but HLSL allows 487 // global constructors, but doesn't support driver initialization of globals. 488 for (auto &F : M.functions()) { 489 if (!F.hasFnAttribute("hlsl.shader")) 490 continue; 491 auto *Token = getConvergenceToken(F.getEntryBlock()); 492 Instruction *IP = &*F.getEntryBlock().begin(); 493 SmallVector<OperandBundleDef, 1> OB; 494 if (Token) { 495 llvm::Value *bundleArgs[] = {Token}; 496 OB.emplace_back("convergencectrl", bundleArgs); 497 IP = Token->getNextNode(); 498 } 499 IRBuilder<> B(IP); 500 for (auto *Fn : CtorFns) { 501 auto CI = B.CreateCall(FunctionCallee(Fn), {}, OB); 502 CI->setCallingConv(Fn->getCallingConv()); 503 } 504 505 // Insert global dtors before the terminator of the last instruction 506 B.SetInsertPoint(F.back().getTerminator()); 507 for (auto *Fn : DtorFns) { 508 auto CI = B.CreateCall(FunctionCallee(Fn), {}, OB); 509 CI->setCallingConv(Fn->getCallingConv()); 510 } 511 } 512 513 // No need to keep global ctors/dtors for non-lib profile after call to 514 // ctors/dtors added for entry. 515 Triple T(M.getTargetTriple()); 516 if (T.getEnvironment() != Triple::EnvironmentType::Library) { 517 if (auto *GV = M.getNamedGlobal("llvm.global_ctors")) 518 GV->eraseFromParent(); 519 if (auto *GV = M.getNamedGlobal("llvm.global_dtors")) 520 GV->eraseFromParent(); 521 } 522 } 523 524 // Returns true if the type is an HLSL resource class 525 static bool isResourceRecordType(const clang::Type *Ty) { 526 return HLSLAttributedResourceType::findHandleTypeOnResource(Ty) != nullptr; 527 } 528 529 static void createResourceInitFn(CodeGenModule &CGM, const VarDecl *VD, 530 llvm::GlobalVariable *GV, unsigned Slot, 531 unsigned Space) { 532 LLVMContext &Ctx = CGM.getLLVMContext(); 533 llvm::Type *Int1Ty = llvm::Type::getInt1Ty(Ctx); 534 535 llvm::Function *InitResFunc = llvm::Function::Create( 536 llvm::FunctionType::get(CGM.VoidTy, false), 537 llvm::GlobalValue::InternalLinkage, 538 ("_init_resource_" + VD->getName()).str(), CGM.getModule()); 539 InitResFunc->addFnAttr(llvm::Attribute::AlwaysInline); 540 541 llvm::BasicBlock *EntryBB = 542 llvm::BasicBlock::Create(Ctx, "entry", InitResFunc); 543 CGBuilderTy Builder(CGM, Ctx); 544 const DataLayout &DL = CGM.getModule().getDataLayout(); 545 Builder.SetInsertPoint(EntryBB); 546 547 const HLSLAttributedResourceType *AttrResType = 548 HLSLAttributedResourceType::findHandleTypeOnResource( 549 VD->getType().getTypePtr()); 550 551 // FIXME: Only simple declarations of resources are supported for now. 552 // Arrays of resources or resources in user defined classes are 553 // not implemented yet. 554 assert(AttrResType != nullptr && 555 "Resource class must have a handle of HLSLAttributedResourceType"); 556 557 llvm::Type *TargetTy = 558 CGM.getTargetCodeGenInfo().getHLSLType(CGM, AttrResType); 559 assert(TargetTy != nullptr && 560 "Failed to convert resource handle to target type"); 561 562 llvm::Value *Args[] = { 563 llvm::ConstantInt::get(CGM.IntTy, Space), /* reg_space */ 564 llvm::ConstantInt::get(CGM.IntTy, Slot), /* lower_bound */ 565 // FIXME: resource arrays are not yet implemented 566 llvm::ConstantInt::get(CGM.IntTy, 1), /* range_size */ 567 llvm::ConstantInt::get(CGM.IntTy, 0), /* index */ 568 // FIXME: NonUniformResourceIndex bit is not yet implemented 569 llvm::ConstantInt::get(Int1Ty, false) /* non-uniform */ 570 }; 571 llvm::Value *CreateHandle = Builder.CreateIntrinsic( 572 /*ReturnType=*/TargetTy, 573 CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic(), Args, nullptr, 574 Twine(VD->getName()).concat("_h")); 575 576 llvm::Value *HandleRef = Builder.CreateStructGEP(GV->getValueType(), GV, 0); 577 Builder.CreateAlignedStore(CreateHandle, HandleRef, 578 HandleRef->getPointerAlignment(DL)); 579 Builder.CreateRetVoid(); 580 581 CGM.AddCXXGlobalInit(InitResFunc); 582 } 583 584 void CGHLSLRuntime::handleGlobalVarDefinition(const VarDecl *VD, 585 llvm::GlobalVariable *GV) { 586 587 // If the global variable has resource binding, create an init function 588 // for the resource 589 const HLSLResourceBindingAttr *RBA = VD->getAttr<HLSLResourceBindingAttr>(); 590 if (!RBA) 591 // FIXME: collect unbound resources for implicit binding resolution later 592 // on? 593 return; 594 595 if (!isResourceRecordType(VD->getType().getTypePtr())) 596 // FIXME: Only simple declarations of resources are supported for now. 597 // Arrays of resources or resources in user defined classes are 598 // not implemented yet. 599 return; 600 601 createResourceInitFn(CGM, VD, GV, RBA->getSlotNumber(), 602 RBA->getSpaceNumber()); 603 } 604 605 llvm::Instruction *CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) { 606 if (!CGM.shouldEmitConvergenceTokens()) 607 return nullptr; 608 609 auto E = BB.end(); 610 for (auto I = BB.begin(); I != E; ++I) { 611 auto *II = dyn_cast<llvm::IntrinsicInst>(&*I); 612 if (II && llvm::isConvergenceControlIntrinsic(II->getIntrinsicID())) { 613 return II; 614 } 615 } 616 llvm_unreachable("Convergence token should have been emitted."); 617 return nullptr; 618 } 619