Skip to content

Commit 85001dc

Browse files
committed
Initialize resources by constructors
- add resource record constructor with explicit binding - completes implementation of default resource constructor - removes resource initialization for Codegen for resource records - cbuffer still needs to be initialized in Codegen because it does not have a resource class type
1 parent 01bc672 commit 85001dc

19 files changed

+610
-174
lines changed

clang/include/clang/Basic/Builtins.td

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4789,6 +4789,18 @@ def HLSLResourceGetPointer : LangBuiltin<"HLSL_LANG"> {
47894789
let Prototype = "void(...)";
47904790
}
47914791

4792+
def HLSLResourceCreatePoisonHandle : LangBuiltin<"HLSL_LANG"> {
4793+
let Spellings = ["__builtin_hlsl_resource_createpoisonhandle"];
4794+
let Attributes = [NoThrow];
4795+
let Prototype = "void(...)";
4796+
}
4797+
4798+
def HLSLResourceCreateHandleFromBinding : LangBuiltin<"HLSL_LANG"> {
4799+
let Spellings = ["__builtin_hlsl_resource_createhandlefrombinding"];
4800+
let Attributes = [NoThrow];
4801+
let Prototype = "void(...)";
4802+
}
4803+
47924804
def HLSLAll : LangBuiltin<"HLSL_LANG"> {
47934805
let Spellings = ["__builtin_hlsl_all"];
47944806
let Attributes = [NoThrow, Const];

clang/include/clang/Sema/SemaHLSL.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ class SemaHLSL : public SemaBase {
105105
HLSLParamModifierAttr::Spelling Spelling);
106106
void ActOnTopLevelFunction(FunctionDecl *FD);
107107
void ActOnVariableDeclarator(VarDecl *VD);
108+
bool ActOnUninitializedVarDecl(VarDecl *D);
108109
void ActOnEndOfTranslationUnit(TranslationUnitDecl *TU);
109110
void CheckEntryPoint(FunctionDecl *FD);
110111
void CheckSemanticAnnotation(FunctionDecl *EntryPoint, const Decl *Param,

clang/lib/CodeGen/CGHLSLBuiltins.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,24 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
287287
RetTy, CGM.getHLSLRuntime().getCreateResourceGetPointerIntrinsic(),
288288
ArrayRef<Value *>{HandleOp, IndexOp});
289289
}
290+
case Builtin::BI__builtin_hlsl_resource_createpoisonhandle: {
291+
llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType());
292+
return llvm::PoisonValue::get(HandleTy);
293+
}
294+
case Builtin::BI__builtin_hlsl_resource_createhandlefrombinding: {
295+
llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType());
296+
Value *SpaceNoOp = EmitScalarExpr(E->getArg(1));
297+
Value *RegisterNoOp = EmitScalarExpr(E->getArg(2));
298+
Value *RangeOp = EmitScalarExpr(E->getArg(3));
299+
Value *IndexOp = EmitScalarExpr(E->getArg(4));
300+
// FIXME: NonUniformResourceIndex bit is not yet implemented
301+
Value *NonUniform =
302+
llvm::ConstantInt::get(llvm::Type::getInt1Ty(getLLVMContext()), false);
303+
return Builder.CreateIntrinsic(
304+
HandleTy, CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic(),
305+
ArrayRef<Value *>{SpaceNoOp, RegisterNoOp, RangeOp, IndexOp,
306+
NonUniform});
307+
}
290308
case Builtin::BI__builtin_hlsl_all: {
291309
Value *Op0 = EmitScalarExpr(E->getArg(0));
292310
return Builder.CreateIntrinsic(

clang/lib/CodeGen/CGHLSLRuntime.cpp

Lines changed: 31 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ using namespace llvm;
4141

4242
using llvm::hlsl::CBufferRowSizeInBytes;
4343

44-
static void createResourceInitFn(CodeGenModule &CGM, llvm::GlobalVariable *GV,
45-
unsigned Slot, unsigned Space);
44+
static void initializeBufferFromBinding(CodeGenModule &CGM,
45+
llvm::GlobalVariable *GV, unsigned Slot,
46+
unsigned Space);
4647

4748
namespace {
4849

@@ -255,14 +256,14 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
255256
// Add globals for constant buffer elements and create metadata nodes
256257
emitBufferGlobalsAndMetadata(BufDecl, BufGV);
257258

258-
// Resource initialization
259+
// Initialize cbuffer from binding (implicit or explicit)
259260
const HLSLResourceBindingAttr *RBA =
260261
BufDecl->getAttr<HLSLResourceBindingAttr>();
261262
// FIXME: handle implicit binding if no binding attribute is found
262263
// (llvm/llvm-project#110722)
263264
if (RBA)
264-
createResourceInitFn(CGM, BufGV, RBA->getSlotNumber(),
265-
RBA->getSpaceNumber());
265+
initializeBufferFromBinding(CGM, BufGV, RBA->getSlotNumber(),
266+
RBA->getSpaceNumber());
266267
}
267268

268269
llvm::TargetExtType *
@@ -494,15 +495,15 @@ void CGHLSLRuntime::generateGlobalCtorDtorCalls() {
494495
}
495496
}
496497

497-
static void createResourceInitFn(CodeGenModule &CGM, llvm::GlobalVariable *GV,
498-
unsigned Slot, unsigned Space) {
499-
LLVMContext &Ctx = CGM.getLLVMContext();
500-
llvm::Type *Int1Ty = llvm::Type::getInt1Ty(Ctx);
498+
static void initializeBuffer(CodeGenModule &CGM, llvm::GlobalVariable *GV,
499+
Intrinsic::ID IntrID,
500+
ArrayRef<llvm::Value *> Args) {
501501

502+
LLVMContext &Ctx = CGM.getLLVMContext();
502503
llvm::Function *InitResFunc = llvm::Function::Create(
503504
llvm::FunctionType::get(CGM.VoidTy, false),
504505
llvm::GlobalValue::InternalLinkage,
505-
("_init_resource_" + GV->getName()).str(), CGM.getModule());
506+
("_init_buffer_" + GV->getName()).str(), CGM.getModule());
506507
InitResFunc->addFnAttr(llvm::Attribute::AlwaysInline);
507508

508509
llvm::BasicBlock *EntryBB =
@@ -511,28 +512,12 @@ static void createResourceInitFn(CodeGenModule &CGM, llvm::GlobalVariable *GV,
511512
const DataLayout &DL = CGM.getModule().getDataLayout();
512513
Builder.SetInsertPoint(EntryBB);
513514

514-
// Make sure the global variable is resource handle (cbuffer) or
515-
// resource class (=class where the first element is a resource handle).
515+
// Make sure the global variable is buffer resource handle
516516
llvm::Type *HandleTy = GV->getValueType();
517-
assert((HandleTy->isTargetExtTy() ||
518-
(HandleTy->isStructTy() &&
519-
HandleTy->getStructElementType(0)->isTargetExtTy())) &&
520-
"unexpected type of the global");
521-
if (!HandleTy->isTargetExtTy())
522-
HandleTy = HandleTy->getStructElementType(0);
517+
assert(HandleTy->isTargetExtTy() && "unexpected type of the buffer global");
523518

524-
llvm::Value *Args[] = {
525-
llvm::ConstantInt::get(CGM.IntTy, Space), /* reg_space */
526-
llvm::ConstantInt::get(CGM.IntTy, Slot), /* lower_bound */
527-
// FIXME: resource arrays are not yet implemented
528-
llvm::ConstantInt::get(CGM.IntTy, 1), /* range_size */
529-
llvm::ConstantInt::get(CGM.IntTy, 0), /* index */
530-
// FIXME: NonUniformResourceIndex bit is not yet implemented
531-
llvm::ConstantInt::get(Int1Ty, false) /* non-uniform */
532-
};
533519
llvm::Value *CreateHandle = Builder.CreateIntrinsic(
534-
/*ReturnType=*/HandleTy,
535-
CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic(), Args, nullptr,
520+
/*ReturnType=*/HandleTy, IntrID, Args, nullptr,
536521
Twine(GV->getName()).concat("_h"));
537522

538523
llvm::Value *HandleRef = Builder.CreateStructGEP(GV->getValueType(), GV, 0);
@@ -543,26 +528,25 @@ static void createResourceInitFn(CodeGenModule &CGM, llvm::GlobalVariable *GV,
543528
CGM.AddCXXGlobalInit(InitResFunc);
544529
}
545530

546-
void CGHLSLRuntime::handleGlobalVarDefinition(const VarDecl *VD,
547-
llvm::GlobalVariable *GV) {
548-
549-
// If the global variable has resource binding, create an init function
550-
// for the resource
551-
const HLSLResourceBindingAttr *RBA = VD->getAttr<HLSLResourceBindingAttr>();
552-
if (!RBA)
553-
// FIXME: collect unbound resources for implicit binding resolution later
554-
// on?
555-
return;
556-
557-
if (!VD->getType().getTypePtr()->isHLSLResourceRecord())
558-
// FIXME: Only simple declarations of resources are supported for now.
559-
// Arrays of resources or resources in user defined classes are
560-
// not implemented yet.
561-
return;
562-
563-
createResourceInitFn(CGM, GV, RBA->getSlotNumber(), RBA->getSpaceNumber());
531+
static void initializeBufferFromBinding(CodeGenModule &CGM,
532+
llvm::GlobalVariable *GV, unsigned Slot,
533+
unsigned Space) {
534+
llvm::Type *Int1Ty = llvm::Type::getInt1Ty(CGM.getLLVMContext());
535+
llvm::Value *Args[] = {
536+
llvm::ConstantInt::get(CGM.IntTy, Space), /* reg_space */
537+
llvm::ConstantInt::get(CGM.IntTy, Slot), /* lower_bound */
538+
llvm::ConstantInt::get(CGM.IntTy, 1), /* range_size */
539+
llvm::ConstantInt::get(CGM.IntTy, 0), /* index */
540+
llvm::ConstantInt::get(Int1Ty, false) /* non-uniform */
541+
};
542+
initializeBuffer(CGM, GV,
543+
CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic(),
544+
Args);
564545
}
565546

547+
void CGHLSLRuntime::handleGlobalVarDefinition(const VarDecl *VD,
548+
llvm::GlobalVariable *GV) {}
549+
566550
llvm::Instruction *CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) {
567551
if (!CGM.shouldEmitConvergenceTokens())
568552
return nullptr;

clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,7 @@ void BuiltinTypeMethodBuilder::createDecl() {
400400

401401
// create params & set them to the function prototype
402402
SmallVector<ParmVarDecl *> ParmDecls;
403+
unsigned CurScopeDepth = DeclBuilder.SemaRef.getCurScope()->getDepth();
403404
auto FnProtoLoc =
404405
Method->getTypeSourceInfo()->getTypeLoc().getAs<FunctionProtoTypeLoc>();
405406
for (int I = 0, E = Params.size(); I != E; I++) {
@@ -414,6 +415,7 @@ void BuiltinTypeMethodBuilder::createDecl() {
414415
HLSLParamModifierAttr::Create(AST, SourceRange(), MP.Modifier);
415416
Parm->addAttr(Mod);
416417
}
418+
Parm->setScopeInfo(CurScopeDepth, I);
417419
ParmDecls.push_back(Parm);
418420
FnProtoLoc.setParam(I, Parm);
419421
}
@@ -447,10 +449,14 @@ BuiltinTypeMethodBuilder::callBuiltin(StringRef BuiltinName,
447449
AST, NestedNameSpecifierLoc(), SourceLocation(), FD, false,
448450
FD->getNameInfo(), AST.BuiltinFnTy, VK_PRValue);
449451

452+
auto *ImpCast = ImplicitCastExpr::Create(
453+
AST, AST.getPointerType(FD->getType()), CK_BuiltinFnToFnPtr, DRE, nullptr,
454+
VK_PRValue, FPOptionsOverride());
455+
450456
if (ReturnType.isNull())
451457
ReturnType = FD->getReturnType();
452458

453-
Expr *Call = CallExpr::Create(AST, DRE, Args, ReturnType, VK_PRValue,
459+
Expr *Call = CallExpr::Create(AST, ImpCast, Args, ReturnType, VK_PRValue,
454460
SourceLocation(), FPOptionsOverride());
455461
StmtsList.push_back(Call);
456462
return *this;
@@ -632,11 +638,33 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDefaultHandleConstructor() {
632638
if (Record->isCompleteDefinition())
633639
return *this;
634640

635-
// FIXME: initialize handle to poison value; this can be added after
636-
// resource constructor from binding is implemented, otherwise the handle
637-
// value will get overwritten.
641+
using PH = BuiltinTypeMethodBuilder::PlaceHolder;
642+
QualType HandleType = getResourceHandleField()->getType();
638643
return BuiltinTypeMethodBuilder(*this, "", SemaRef.getASTContext().VoidTy,
639644
false, true)
645+
.callBuiltin("__builtin_hlsl_resource_createpoisonhandle", HandleType,
646+
PH::Handle)
647+
.assign(PH::Handle, PH::LastStmt)
648+
.finalize();
649+
}
650+
651+
BuiltinTypeDeclBuilder &
652+
BuiltinTypeDeclBuilder::addHandleConstructorFromBinding() {
653+
if (Record->isCompleteDefinition())
654+
return *this;
655+
656+
using PH = BuiltinTypeMethodBuilder::PlaceHolder;
657+
ASTContext &AST = SemaRef.getASTContext();
658+
QualType HandleType = getResourceHandleField()->getType();
659+
660+
return BuiltinTypeMethodBuilder(*this, "", AST.VoidTy, false, true)
661+
.addParam("spaceNo", AST.UnsignedIntTy)
662+
.addParam("registerNo", AST.UnsignedIntTy)
663+
.addParam("range", AST.IntTy)
664+
.addParam("index", AST.UnsignedIntTy)
665+
.callBuiltin("__builtin_hlsl_resource_createhandlefrombinding",
666+
HandleType, PH::Handle, PH::_0, PH::_1, PH::_2, PH::_3)
667+
.assign(PH::Handle, PH::LastStmt)
640668
.finalize();
641669
}
642670

clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ class BuiltinTypeDeclBuilder {
7878

7979
// Builtin types methods
8080
BuiltinTypeDeclBuilder &addDefaultHandleConstructor();
81+
BuiltinTypeDeclBuilder &addHandleConstructorFromBinding();
8182

8283
// Builtin types methods
8384
BuiltinTypeDeclBuilder &addLoadMethods();

clang/lib/Sema/HLSLExternalSemaSource.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,8 @@ static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
131131
bool RawBuffer) {
132132
return BuiltinTypeDeclBuilder(S, Decl)
133133
.addHandleMember(RC, IsROV, RawBuffer)
134-
.addDefaultHandleConstructor();
134+
.addDefaultHandleConstructor()
135+
.addHandleConstructorFromBinding();
135136
}
136137

137138
// This function is responsible for constructing the constraint expression for

clang/lib/Sema/SemaDecl.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14345,10 +14345,8 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
1434514345
Var->getType().getAddressSpace() == LangAS::opencl_local)
1434614346
return;
1434714347

14348-
// In HLSL, objects in the hlsl_constant address space are initialized
14349-
// externally, so don't synthesize an implicit initializer.
14350-
if (getLangOpts().HLSL &&
14351-
Var->getType().getAddressSpace() == LangAS::hlsl_constant)
14348+
// Handle HLSL uninitialized decls
14349+
if (getLangOpts().HLSL && HLSL().ActOnUninitializedVarDecl(Var))
1435214350
return;
1435314351

1435414352
// C++03 [dcl.init]p9:

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "clang/Sema/ParsedAttr.h"
3333
#include "clang/Sema/Sema.h"
3434
#include "clang/Sema/Template.h"
35+
#include "llvm/ADT/ArrayRef.h"
3536
#include "llvm/ADT/STLExtras.h"
3637
#include "llvm/ADT/SmallVector.h"
3738
#include "llvm/ADT/StringExtras.h"
@@ -305,6 +306,10 @@ static bool isResourceRecordTypeOrArrayOf(const Type *Ty) {
305306
return HLSLAttributedResourceType::findHandleTypeOnResource(Ty) != nullptr;
306307
}
307308

309+
static bool isResourceRecordTypeOrArrayOf(VarDecl *VD) {
310+
return isResourceRecordTypeOrArrayOf(VD->getType().getTypePtr());
311+
}
312+
308313
// Returns true if the type is a leaf element type that is not valid to be
309314
// included in HLSL Buffer, such as a resource class, empty struct, zero-sized
310315
// array, or a builtin intangible type. Returns false it is a valid leaf element
@@ -2385,6 +2390,29 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
23852390

23862391
break;
23872392
}
2393+
case Builtin::BI__builtin_hlsl_resource_createpoisonhandle: {
2394+
if (SemaRef.checkArgCount(TheCall, 1) ||
2395+
CheckResourceHandle(&SemaRef, TheCall, 0))
2396+
return true;
2397+
// use the type of the handle (arg0) as a return type
2398+
QualType ResourceTy = TheCall->getArg(0)->getType();
2399+
TheCall->setType(ResourceTy);
2400+
break;
2401+
}
2402+
case Builtin::BI__builtin_hlsl_resource_createhandlefrombinding: {
2403+
ASTContext &AST = SemaRef.getASTContext();
2404+
if (SemaRef.checkArgCount(TheCall, 5) ||
2405+
CheckResourceHandle(&SemaRef, TheCall, 0) ||
2406+
CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), AST.UnsignedIntTy) ||
2407+
CheckArgTypeMatches(&SemaRef, TheCall->getArg(2), AST.UnsignedIntTy) ||
2408+
CheckArgTypeMatches(&SemaRef, TheCall->getArg(3), AST.IntTy) ||
2409+
CheckArgTypeMatches(&SemaRef, TheCall->getArg(4), AST.UnsignedIntTy))
2410+
return true;
2411+
// use the type of the handle (arg0) as a return type
2412+
QualType ResourceTy = TheCall->getArg(0)->getType();
2413+
TheCall->setType(ResourceTy);
2414+
break;
2415+
}
23882416
case Builtin::BI__builtin_hlsl_and:
23892417
case Builtin::BI__builtin_hlsl_or: {
23902418
if (SemaRef.checkArgCount(TheCall, 2))
@@ -3179,6 +3207,67 @@ void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) {
31793207
}
31803208
}
31813209

3210+
static bool initVarDeclWithConstructor(Sema &S, VarDecl *VD,
3211+
MutableArrayRef<Expr *> Args) {
3212+
InitializedEntity Entity = InitializedEntity::InitializeVariable(VD);
3213+
InitializationKind Kind = InitializationKind::CreateDirect(
3214+
VD->getLocation(), SourceLocation(), SourceLocation());
3215+
3216+
InitializationSequence InitSeq(S, Entity, Kind, Args);
3217+
ExprResult Init = InitSeq.Perform(S, Entity, Kind, Args);
3218+
3219+
if (!Init.get())
3220+
return false;
3221+
3222+
VD->setInit(S.MaybeCreateExprWithCleanups(Init.get()));
3223+
VD->setInitStyle(VarDecl::CallInit);
3224+
S.CheckCompleteVariableDeclaration(VD);
3225+
return true;
3226+
}
3227+
3228+
static bool initGlobalResourceDecl(Sema &S, VarDecl *VD) {
3229+
HLSLResourceBindingAttr *RBA = VD->getAttr<HLSLResourceBindingAttr>();
3230+
if (!RBA)
3231+
// FIXME: add support for implicit binding (llvm/llvm-project#110722)
3232+
return false;
3233+
3234+
ASTContext &AST = S.getASTContext();
3235+
uint64_t UIntTySize = AST.getTypeSize(AST.UnsignedIntTy);
3236+
uint64_t IntTySize = AST.getTypeSize(AST.IntTy);
3237+
Expr *Args[] = {
3238+
IntegerLiteral::Create(AST,
3239+
llvm::APInt(UIntTySize, RBA->getSpaceNumber()),
3240+
AST.UnsignedIntTy, SourceLocation()),
3241+
IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, RBA->getSlotNumber()),
3242+
AST.UnsignedIntTy, SourceLocation()),
3243+
IntegerLiteral::Create(AST, llvm::APInt(IntTySize, 1), AST.IntTy,
3244+
SourceLocation()),
3245+
IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, 0), AST.UnsignedIntTy,
3246+
SourceLocation())};
3247+
3248+
return initVarDeclWithConstructor(S, VD, Args);
3249+
}
3250+
3251+
// Returns true in the initialization has been handled;
3252+
// Return false to let Clang handle the default initializaton.
3253+
bool SemaHLSL::ActOnUninitializedVarDecl(VarDecl *VD) {
3254+
// Objects in the hlsl_constant address space are initialized
3255+
// externally, so don't synthesize an implicit initializer.
3256+
if (VD->getType().getAddressSpace() == LangAS::hlsl_constant)
3257+
return true;
3258+
3259+
// Initialize resources
3260+
if (!isResourceRecordTypeOrArrayOf(VD))
3261+
return false;
3262+
3263+
// FIXME: We currectly support only simple resources - no arrays of resources
3264+
// or resources in user defined structs).
3265+
if (VD->getType()->isHLSLResourceRecord())
3266+
return initGlobalResourceDecl(SemaRef, VD);
3267+
3268+
return false;
3269+
}
3270+
31823271
// Walks though the global variable declaration, collects all resource binding
31833272
// requirements and adds them to Bindings
31843273
void SemaHLSL::collectResourceBindingsOnVarDecl(VarDecl *VD) {

0 commit comments

Comments
 (0)