Skip to content

Commit 1498d1d

Browse files
committed
[HLSL] Implement RWBuffer::operator[] via __builtin_hlsl_resource_getpointer
This introduces `__builtin_hlsl_resource_getpointer`, which lowers to `llvm.dx.resource.getpointer` and is used to implement indexing into resources. This will only work through the backend for typed buffers at this point, but the changes to structured buffers should be correct as far as the frontend is concerned. Note: We probably want this to return a reference in the HLSL device address space, but for now we're just using address space 0. Creating a device address space and updating this code can be done later as necessary. Fixes llvm#95956
1 parent 43b6b78 commit 1498d1d

19 files changed

+203
-123
lines changed

clang/include/clang/Basic/Builtins.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4738,6 +4738,12 @@ def GetDeviceSideMangledName : LangBuiltin<"CUDA_LANG"> {
47384738
}
47394739

47404740
// HLSL
4741+
def HLSLTypedBufferPointer : LangBuiltin<"HLSL_LANG"> {
4742+
let Spellings = ["__builtin_hlsl_resource_getpointer"];
4743+
let Attributes = [NoThrow];
4744+
let Prototype = "void(...)";
4745+
}
4746+
47414747
def HLSLAll : LangBuiltin<"HLSL_LANG"> {
47424748
let Spellings = ["__builtin_hlsl_all"];
47434749
let Attributes = [NoThrow, Const];

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12496,6 +12496,7 @@ def err_hlsl_pointers_unsupported : Error<
1249612496
"%select{pointers|references}0 are unsupported in HLSL">;
1249712497
def err_hlsl_missing_resource_class : Error<"HLSL resource needs to have [[hlsl::resource_class()]] attribute">;
1249812498
def err_hlsl_attribute_needs_intangible_type: Error<"attribute %0 can be used only on HLSL intangible type %1">;
12499+
def err_hlsl_builtin_requires_resource: Error<"operand must be of __hlsl_resource_t type">;
1249912500

1250012501
def err_hlsl_operator_unsupported : Error<
1250112502
"the '%select{&|*|->}0' operator is unsupported in HLSL">;

clang/lib/AST/Type.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4723,7 +4723,9 @@ LinkageInfo LinkageComputer::computeTypeLinkageInfo(const Type *T) {
47234723
case Type::Pipe:
47244724
return computeTypeLinkageInfo(cast<PipeType>(T)->getElementType());
47254725
case Type::HLSLAttributedResource:
4726-
llvm_unreachable("not yet implemented");
4726+
return computeTypeLinkageInfo(cast<HLSLAttributedResourceType>(T)
4727+
->getContainedType()
4728+
->getCanonicalTypeInternal());
47274729
}
47284730

47294731
llvm_unreachable("unhandled type class");

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19044,6 +19044,16 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
1904419044
return nullptr;
1904519045

1904619046
switch (BuiltinID) {
19047+
case Builtin::BI__builtin_hlsl_resource_getpointer: {
19048+
Value *HandleOp = EmitScalarExpr(E->getArg(0));
19049+
Value *IndexOp = EmitScalarExpr(E->getArg(1));
19050+
19051+
// TODO: Map to an hlsl_device address space.
19052+
llvm::Type *RetTy = llvm::PointerType::getUnqual(getLLVMContext());
19053+
19054+
return Builder.CreateIntrinsic(RetTy, Intrinsic::dx_resource_getpointer,
19055+
ArrayRef<Value *>{HandleOp, IndexOp});
19056+
}
1904719057
case Builtin::BI__builtin_hlsl_all: {
1904819058
Value *Op0 = EmitScalarExpr(E->getArg(0));
1904919059
return Builder.CreateIntrinsic(

clang/lib/Sema/HLSLExternalSemaSource.cpp

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -218,23 +218,33 @@ struct BuiltinTypeDeclBuilder {
218218
auto FnProtoLoc = TSInfo->getTypeLoc().getAs<FunctionProtoTypeLoc>();
219219
FnProtoLoc.setParam(0, IdxParam);
220220

221-
// FIXME: Placeholder to make sure we return the correct type - create
222-
// field of element_type and return reference to it. This field will go
223-
// away once indexing into resources is properly implemented in
224-
// llvm/llvm-project#95956.
225-
if (Fields.count("e") == 0) {
226-
addMemberVariable("e", ElemTy, {});
227-
}
228-
FieldDecl *ElemFieldDecl = Fields["e"];
229-
230221
auto *This =
231222
CXXThisExpr::Create(AST, SourceLocation(),
232223
MethodDecl->getFunctionObjectParameterType(), true);
233-
Expr *ElemField = MemberExpr::CreateImplicit(
234-
AST, This, false, ElemFieldDecl, ElemFieldDecl->getType(), VK_LValue,
235-
OK_Ordinary);
236-
auto *Return =
237-
ReturnStmt::Create(AST, SourceLocation(), ElemField, nullptr);
224+
FieldDecl *Handle = Fields["__handle"];
225+
auto *HandleExpr = MemberExpr::CreateImplicit(
226+
AST, This, false, Handle, Handle->getType(), VK_LValue, OK_Ordinary);
227+
228+
auto *IndexExpr = DeclRefExpr::Create(
229+
AST, NestedNameSpecifierLoc(), SourceLocation(), IdxParam, false,
230+
DeclarationNameInfo(IdxParam->getDeclName(), SourceLocation()),
231+
AST.UnsignedIntTy, VK_PRValue);
232+
233+
FunctionDecl *FD =
234+
lookupBuiltinFunction(SemaRef, "__builtin_hlsl_resource_getpointer");
235+
DeclRefExpr *Builtin = DeclRefExpr::Create(
236+
AST, NestedNameSpecifierLoc(), SourceLocation(), FD, false,
237+
FD->getNameInfo(), AST.BuiltinFnTy, VK_PRValue);
238+
239+
// TODO: Map to an hlsl_device address space.
240+
QualType ElemPtrTy = AST.getPointerType(ElemTy);
241+
Expr *Call = CallExpr::Create(AST, Builtin, {HandleExpr, IndexExpr},
242+
ElemPtrTy, VK_PRValue,
243+
SourceLocation(), FPOptionsOverride());
244+
Expr *Deref = UnaryOperator::Create(
245+
AST, Call, UO_Deref, ElemTy, VK_PRValue, OK_Ordinary, SourceLocation(),
246+
/*CanOverflow=*/false, FPOptionsOverride());
247+
auto *Return = ReturnStmt::Create(AST, SourceLocation(), Deref, nullptr);
238248

239249
MethodDecl->setBody(CompoundStmt::Create(AST, {Return}, FPOptionsOverride(),
240250
SourceLocation(),

clang/lib/Sema/SemaExpr.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -980,6 +980,9 @@ Sema::VarArgKind Sema::isValidVarArgType(const QualType &Ty) {
980980
if (Ty->isObjCObjectType())
981981
return VAK_Invalid;
982982

983+
if (getLangOpts().HLSL && Ty->getAs<HLSLAttributedResourceType>())
984+
return VAK_Valid;
985+
983986
if (getLangOpts().MSVCCompat)
984987
return VAK_MSVCUndefined;
985988

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1926,6 +1926,25 @@ static bool CheckResourceHandle(
19261926
// returning an ExprError
19271927
bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
19281928
switch (BuiltinID) {
1929+
case Builtin::BI__builtin_hlsl_resource_getpointer: {
1930+
if (SemaRef.checkArgCount(TheCall, 2))
1931+
return true;
1932+
auto *ResourceTy =
1933+
TheCall->getArg(0)->getType()->getAs<HLSLAttributedResourceType>();
1934+
if (!ResourceTy) {
1935+
SemaRef.Diag(TheCall->getBeginLoc(),
1936+
diag::err_hlsl_builtin_requires_resource)
1937+
<< TheCall->getArg(0)->getSourceRange();
1938+
return true;
1939+
}
1940+
1941+
QualType ContainedTy = ResourceTy->getContainedType();
1942+
// TODO: Map to an hlsl_device address space.
1943+
TheCall->setType(getASTContext().getPointerType(ContainedTy));
1944+
TheCall->setValueKind(VK_LValue);
1945+
1946+
break;
1947+
}
19291948
case Builtin::BI__builtin_hlsl_all:
19301949
case Builtin::BI__builtin_hlsl_any: {
19311950
if (SemaRef.checkArgCount(TheCall, 1))

clang/test/AST/HLSL/StructuredBuffers-AST.hlsl

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,16 +78,32 @@ RESOURCE<float> Buffer;
7878
// CHECK-SUBSCRIPT-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> Idx 'unsigned int'
7979
// CHECK-SUBSCRIPT-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
8080
// CHECK-SUBSCRIPT-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
81-
// CHECK-SUBSCRIPT-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' lvalue .e 0x{{[0-9A-Fa-f]+}}
81+
// CHECK-SUBSCRIPT-NEXT: UnaryOperator 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' prefix '*' cannot overflow
82+
// CHECK-SUBSCRIPT-NEXT: CallExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type *'
83+
// CHECK-SUBSCRIPT-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '<builtin fn type>' Function 0x{{[0-9A-Fa-f]+}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
84+
// CHECK-SUBSCRIPT-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '__hlsl_resource_t
85+
// CHECK-SUBSCRIPT-SAME{LITERAL}: [[hlsl::resource_class(
86+
// CHECK-SUBSCRIPT-SAME{LITERAL}: [[hlsl::raw_buffer]]
87+
// CHECK-SUBSCRIPT-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
88+
// CHECK-SUBSCRIPT-SAME: ' lvalue .__handle 0x{{[0-9A-Fa-f]+}}
8289
// CHECK-SUBSCRIPT-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'const [[RESOURCE]]<element_type>' lvalue implicit this
90+
// CHECK-SUBSCRIPT-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int' ParmVar 0x{{[0-9A-Fa-f]+}} 'Idx' 'unsigned int'
8391
// CHECK-SUBSCRIPT-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline
8492

8593
// CHECK-SUBSCRIPT-NEXT: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> operator[] 'element_type &(unsigned int)'
8694
// CHECK-SUBSCRIPT-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> Idx 'unsigned int'
8795
// CHECK-SUBSCRIPT-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
8896
// CHECK-SUBSCRIPT-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
89-
// CHECK-SUBSCRIPT-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' lvalue .e 0x{{[0-9A-Fa-f]+}}
97+
// CHECK-SUBSCRIPT-NEXT: UnaryOperator 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' prefix '*' cannot overflow
98+
// CHECK-SUBSCRIPT-NEXT: CallExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type *'
99+
// CHECK-SUBSCRIPT-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '<builtin fn type>' Function 0x{{[0-9A-Fa-f]+}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
100+
// CHECK-SUBSCRIPT-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '__hlsl_resource_t
101+
// CHECK-SUBSCRIPT-SAME{LITERAL}: [[hlsl::resource_class(
102+
// CHECK-SUBSCRIPT-SAME{LITERAL}: [[hlsl::raw_buffer]]
103+
// CHECK-SUBSCRIPT-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
104+
// CHECK-SUBSCRIPT-SAME: ' lvalue .__handle 0x{{[0-9A-Fa-f]+}}
90105
// CHECK-SUBSCRIPT-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '[[RESOURCE]]<element_type>' lvalue implicit this
106+
// CHECK-SUBSCRIPT-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int' ParmVar 0x{{[0-9A-Fa-f]+}} 'Idx' 'unsigned int'
91107
// CHECK-SUBSCRIPT-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline
92108

93109
// CHECK-NOSUBSCRIPT-NOT: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> operator[] 'const element_type &(unsigned int) const'

clang/test/AST/HLSL/TypedBuffers-AST.hlsl

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,16 +61,30 @@ RESOURCE<float> Buffer;
6161
// CHECK-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> Idx 'unsigned int'
6262
// CHECK-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
6363
// CHECK-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
64-
// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' lvalue .e 0x{{[0-9A-Fa-f]+}}
64+
// CHECK-NEXT: UnaryOperator 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' prefix '*' cannot overflow
65+
// CHECK-NEXT: CallExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type *'
66+
// CHECK-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '<builtin fn type>' Function 0x{{[0-9A-Fa-f]+}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
67+
// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '__hlsl_resource_t
68+
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
69+
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
70+
// CHECK-SAME: ' lvalue .__handle 0x{{[0-9A-Fa-f]+}}
6571
// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'const [[RESOURCE]]<element_type>' lvalue implicit this
72+
// CHECK-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int' ParmVar 0x{{[0-9A-Fa-f]+}} 'Idx' 'unsigned int'
6673
// CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline
6774

6875
// CHECK-NEXT: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> operator[] 'element_type &(unsigned int)'
6976
// CHECK-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> Idx 'unsigned int'
7077
// CHECK-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
7178
// CHECK-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
72-
// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' lvalue .e 0x{{[0-9A-Fa-f]+}}
79+
// CHECK-NEXT: UnaryOperator 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' prefix '*' cannot overflow
80+
// CHECK-NEXT: CallExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type *'
81+
// CHECK-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '<builtin fn type>' Function 0x{{[0-9A-Fa-f]+}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
82+
// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '__hlsl_resource_t
83+
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
84+
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
85+
// CHECK-SAME: ' lvalue .__handle 0x{{[0-9A-Fa-f]+}}
7386
// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '[[RESOURCE]]<element_type>' lvalue implicit this
87+
// CHECK-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int' ParmVar 0x{{[0-9A-Fa-f]+}} 'Idx' 'unsigned int'
7488
// CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline
7589

7690
// CHECK: ClassTemplateSpecializationDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> class [[RESOURCE]] definition

clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66

77
RWBuffer<float> Buf : register(u5, space3);
88

9-
// CHECK: %"class.hlsl::RWBuffer" = type { target("dx.TypedBuffer", float, 1, 0, 0), float }
9+
// CHECK: %"class.hlsl::RWBuffer" = type { target("dx.TypedBuffer", float, 1, 0, 0) }
1010
// CHECK: @Buf = global %"class.hlsl::RWBuffer" zeroinitializer, align 4
1111

12-
// CHECK: define linkonce_odr void @_ZN4hlsl8RWBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(8) %this)
12+
// CHECK: define linkonce_odr void @_ZN4hlsl8RWBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this)
1313
// CHECK-NEXT: entry:
1414

1515
// CHECK: define internal void @_GLOBAL__sub_I_RWBuffer_constructor.hlsl()

0 commit comments

Comments
 (0)