[clang] Implement `ByteAddressBuffer` Load/Store methods (PR #176058)
Kaitlin Peng via cfe-commits
cfe-commits at lists.llvm.org
Mon Jan 26 23:28:26 PST 2026
https://github.com/kmpeng updated https://github.com/llvm/llvm-project/pull/176058
>From fd7f821efcbd70538b273d70ec614272b2b0fc15 Mon Sep 17 00:00:00 2001
From: kmpeng <kaitlinpeng at microsoft.com>
Date: Thu, 18 Dec 2025 04:28:46 -0800
Subject: [PATCH 01/12] regular uint load/store working, templated WIP
---
clang/include/clang/Basic/Builtins.td | 18 +++
clang/lib/CodeGen/CGHLSLBuiltins.cpp | 58 ++++++++
clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 135 +++++++++++++++++-
clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h | 2 +
clang/lib/Sema/HLSLExternalSemaSource.cpp | 3 +
clang/lib/Sema/SemaHLSL.cpp | 43 ++++++
.../test/AST/HLSL/ByteAddressBuffers-AST.hlsl | 9 +-
.../resources/ByteAddressBuffers-methods.hlsl | 34 +++++
8 files changed, 299 insertions(+), 3 deletions(-)
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index dcf07d659cb15..bc127ff91fe50 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -5001,6 +5001,24 @@ def HLSLResourceLoadWithStatus : LangBuiltin<"HLSL_LANG"> {
let Prototype = "void(...)";
}
+def HLSLByteAddressBufferLoad : LangBuiltin<"HLSL_LANG"> {
+ let Spellings = ["__builtin_hlsl_byteaddressbuffer_load"];
+ let Attributes = [NoThrow];
+ let Prototype = "void(...)";
+}
+
+def HLSLByteAddressBufferLoadWithStatus : LangBuiltin<"HLSL_LANG"> {
+ let Spellings = ["__builtin_hlsl_byteaddressbuffer_load_with_status"];
+ let Attributes = [NoThrow];
+ let Prototype = "void(...)";
+}
+
+def HLSLByteAddressBufferStore : LangBuiltin<"HLSL_LANG"> {
+ let Spellings = ["__builtin_hlsl_byteaddressbuffer_store"];
+ let Attributes = [NoThrow];
+ let Prototype = "void(...)";
+}
+
def HLSLResourceUninitializedHandle : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_resource_uninitializedhandle"];
let Attributes = [NoThrow];
diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
index cfe5be354a494..c5f29fd2602df 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -536,6 +536,64 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
return LoadedValue;
}
+ case Builtin::BI__builtin_hlsl_byteaddressbuffer_load: {
+ Value *HandleOp = EmitScalarExpr(E->getArg(0));
+ Value *ByteOffsetOp = EmitScalarExpr(E->getArg(1));
+ Value *ElementOffset = llvm::PoisonValue::get(Builder.getInt32Ty());
+
+ llvm::Type *DataTy = ConvertType(E->getType());
+ llvm::Type *RetTy = llvm::StructType::get(Builder.getContext(),
+ {DataTy, Builder.getInt1Ty()});
+
+ SmallVector<Value *, 3> Args = {HandleOp, ByteOffsetOp, ElementOffset};
+
+ Value *ResRet = Builder.CreateIntrinsic(
+ RetTy, Intrinsic::dx_resource_load_rawbuffer, Args);
+ return Builder.CreateExtractValue(ResRet, {0}, "ld.value");
+ }
+ case Builtin::BI__builtin_hlsl_byteaddressbuffer_load_with_status: {
+ Value *HandleOp = EmitScalarExpr(E->getArg(0));
+ Value *ByteOffsetOp = EmitScalarExpr(E->getArg(1));
+ Value *ElementOffset = llvm::PoisonValue::get(Builder.getInt32Ty());
+
+ // Get the *address* of the status argument to write to it by reference
+ LValue StatusLVal = EmitLValue(E->getArg(2));
+ Address StatusAddr = StatusLVal.getAddress();
+
+ assert(CGM.getTarget().getTriple().getArch() == llvm::Triple::dxil &&
+ "Only DXIL currently implements load with status");
+
+ llvm::Type *DataTy = ConvertType(E->getType());
+ llvm::Type *RetTy = llvm::StructType::get(Builder.getContext(),
+ {DataTy, Builder.getInt1Ty()});
+
+ SmallVector<Value *, 3> Args = {HandleOp, ByteOffsetOp, ElementOffset};
+
+ // The load intrinsics give us a (T value, i1 status) pair -
+ // shepherd these into the return value and out reference respectively.
+ Value *ResRet = Builder.CreateIntrinsic(
+ RetTy, Intrinsic::dx_resource_load_rawbuffer, Args, {}, "ld.struct");
+ Value *LoadedValue = Builder.CreateExtractValue(ResRet, {0}, "ld.value");
+ Value *StatusBit = Builder.CreateExtractValue(ResRet, {1}, "ld.status");
+ Value *ExtendedStatus =
+ Builder.CreateZExt(StatusBit, Builder.getInt32Ty(), "ld.status.ext");
+ Builder.CreateStore(ExtendedStatus, StatusAddr);
+
+ return LoadedValue;
+ }
+ case Builtin::BI__builtin_hlsl_byteaddressbuffer_store: {
+ Value *HandleOp = EmitScalarExpr(E->getArg(0));
+ Value *ByteOffsetOp = EmitScalarExpr(E->getArg(1));
+ Value *ValueOp = EmitScalarExpr(E->getArg(2));
+ Value *ElementOffset = llvm::PoisonValue::get(Builder.getInt32Ty());
+
+ SmallVector<Value *, 4> Args = {HandleOp, ByteOffsetOp, ElementOffset,
+ ValueOp};
+
+ return Builder.CreateIntrinsic(Intrinsic::dx_resource_store_rawbuffer,
+ {HandleOp->getType(), ValueOp->getType()},
+ Args);
+ }
case Builtin::BI__builtin_hlsl_resource_uninitializedhandle: {
llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType());
return llvm::PoisonValue::get(HandleTy);
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index f74aabf08d2c7..5d5a1758590a5 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -153,6 +153,8 @@ struct BuiltinTypeMethodBuilder {
StorageClass SC;
llvm::SmallVector<Param> Params;
llvm::SmallVector<Stmt *> StmtsList;
+ TemplateParameterList *TemplateParams;
+ llvm::SmallVector<NamedDecl *> TemplateParamDecls;
// Argument placeholders, inspired by std::placeholder. These are the indices
// of arguments to forward to `callBuiltin` and other method builder methods.
@@ -184,11 +186,14 @@ struct BuiltinTypeMethodBuilder {
QualType ReturnTy, bool IsConst = false,
bool IsCtor = false, StorageClass SC = SC_None)
: DeclBuilder(DB), Name(Name), ReturnTy(ReturnTy), Method(nullptr),
- IsConst(IsConst), IsCtor(IsCtor), SC(SC) {}
+ IsConst(IsConst), IsCtor(IsCtor), SC(SC), TemplateParams(nullptr) {}
BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, StringRef NameStr,
QualType ReturnTy, bool IsConst = false,
bool IsCtor = false, StorageClass SC = SC_None);
+
+ // converttype maybe? - qualtype or template parameter index
+
BuiltinTypeMethodBuilder(const BuiltinTypeMethodBuilder &Other) = delete;
~BuiltinTypeMethodBuilder() { finalize(); }
@@ -199,6 +204,7 @@ struct BuiltinTypeMethodBuilder {
BuiltinTypeMethodBuilder &addParam(StringRef Name, QualType Ty,
HLSLParamModifierAttr::Spelling Modifier =
HLSLParamModifierAttr::Keyword_in);
+ QualType addTemplateTypeParam(StringRef Name);
BuiltinTypeMethodBuilder &declareLocalVar(LocalVar &Var);
template <typename... Ts>
BuiltinTypeMethodBuilder &callBuiltin(StringRef BuiltinName,
@@ -453,6 +459,22 @@ BuiltinTypeMethodBuilder::addParam(StringRef Name, QualType Ty,
Params.emplace_back(II, Ty, Modifier);
return *this;
}
+QualType BuiltinTypeMethodBuilder::addTemplateTypeParam(StringRef Name) {
+ assert(Method == nullptr &&
+ "Cannot add template param, method already created");
+ ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
+ unsigned Position = static_cast<unsigned>(TemplateParamDecls.size());
+ auto *Decl = TemplateTypeParmDecl::Create(
+ AST, DeclBuilder.Record, SourceLocation(), SourceLocation(),
+ /* TemplateDepth */ 0, Position,
+ &AST.Idents.get(Name, tok::TokenKind::identifier),
+ /* Typename */ true,
+ /* ParameterPack */ false,
+ /* HasTypeConstraint*/ false);
+ TemplateParamDecls.emplace_back(Decl);
+
+ return QualType(Decl->getTypeForDecl(), 0);
+}
void BuiltinTypeMethodBuilder::createDecl() {
assert(Method == nullptr && "Method or constructor is already created");
@@ -765,7 +787,22 @@ BuiltinTypeDeclBuilder &BuiltinTypeMethodBuilder::finalize() {
Method->setAccess(AS_public);
Method->addAttr(AlwaysInlineAttr::CreateImplicit(
AST, SourceRange(), AlwaysInlineAttr::CXX11_clang_always_inline));
- DeclBuilder.Record->addDecl(Method);
+ if (!TemplateParamDecls.empty()) {
+ TemplateParams = TemplateParameterList::Create(
+ AST, SourceLocation(), SourceLocation(), TemplateParamDecls,
+ SourceLocation(), nullptr);
+
+ auto *FuncTemplate = FunctionTemplateDecl::Create(AST, DeclBuilder.Record,
+ SourceLocation(), Name,
+ TemplateParams, Method);
+ FuncTemplate->setAccess(AS_public);
+ FuncTemplate->setLexicalDeclContext(DeclBuilder.Record);
+ FuncTemplate->setImplicit(true);
+ Method->setDescribedFunctionTemplate(FuncTemplate);
+ DeclBuilder.Record->addDecl(FuncTemplate);
+ } else {
+ DeclBuilder.Record->addDecl(Method);
+ }
}
return DeclBuilder;
}
@@ -1165,6 +1202,100 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addLoadMethods() {
return *this;
}
+BuiltinTypeDeclBuilder &
+BuiltinTypeDeclBuilder::addByteAddressBufferLoadMethods() {
+ assert(!Record->isCompleteDefinition() && "record is already complete");
+
+ using PH = BuiltinTypeMethodBuilder::PlaceHolder;
+ ASTContext &AST = SemaRef.getASTContext();
+
+ // Helper to add uint Load methods
+ auto addLoadMethod = [&](StringRef MethodName, QualType ReturnType) {
+ IdentifierInfo &II = AST.Idents.get(MethodName, tok::TokenKind::identifier);
+ DeclarationName Load(&II);
+
+ // Load without status
+ BuiltinTypeMethodBuilder(*this, Load, ReturnType, /*IsConst=*/false)
+ .addParam("byteOffset", AST.UnsignedIntTy)
+ .callBuiltin("__builtin_hlsl_byteaddressbuffer_load", ReturnType,
+ PH::Handle, PH::_0)
+ .finalize();
+
+ // Load with status
+ BuiltinTypeMethodBuilder(*this, Load, ReturnType, /*IsConst=*/false)
+ .addParam("byteOffset", AST.UnsignedIntTy)
+ .addParam("status", AST.UnsignedIntTy,
+ HLSLParamModifierAttr::Keyword_out)
+ .callBuiltin("__builtin_hlsl_byteaddressbuffer_load_with_status",
+ ReturnType, PH::Handle, PH::_0, PH::_1)
+ .finalize();
+ };
+
+ addLoadMethod("Load", AST.UnsignedIntTy);
+ addLoadMethod("Load2", AST.getExtVectorType(AST.UnsignedIntTy, 2));
+ addLoadMethod("Load3", AST.getExtVectorType(AST.UnsignedIntTy, 3));
+ addLoadMethod("Load4", AST.getExtVectorType(AST.UnsignedIntTy, 4));
+
+ // templated
+ {
+ IdentifierInfo &II = AST.Idents.get("Load", tok::TokenKind::identifier);
+ DeclarationName Load(&II);
+ BuiltinTypeMethodBuilder Builder(*this, Load, AST.UnsignedIntTy,
+ /*IsConst=*/false);
+ QualType TType = Builder.addTemplateTypeParam("element_type");
+ Builder.ReturnTy = TType; // Update return type to template parameter
+
+ Builder.addParam("byteOffset", AST.UnsignedIntTy)
+ .callBuiltin("__builtin_hlsl_byteaddressbuffer_load", TType, PH::Handle,
+ PH::_0)
+ .finalize();
+ }
+
+ return *this;
+}
+
+BuiltinTypeDeclBuilder &
+BuiltinTypeDeclBuilder::addByteAddressBufferStoreMethods() {
+ assert(!Record->isCompleteDefinition() && "record is already complete");
+
+ using PH = BuiltinTypeMethodBuilder::PlaceHolder;
+ ASTContext &AST = SemaRef.getASTContext();
+
+ // Helper to add uint Store methods
+ auto addStoreMethod = [&](StringRef MethodName, QualType ValueType) {
+ IdentifierInfo &II = AST.Idents.get(MethodName, tok::TokenKind::identifier);
+ DeclarationName Store(&II);
+
+ BuiltinTypeMethodBuilder(*this, Store, AST.VoidTy, /*IsConst=*/false)
+ .addParam("byteOffset", AST.UnsignedIntTy)
+ .addParam("value", ValueType)
+ .callBuiltin("__builtin_hlsl_byteaddressbuffer_store", AST.VoidTy,
+ PH::Handle, PH::_0, PH::_1)
+ .finalize();
+ };
+
+ addStoreMethod("Store", AST.UnsignedIntTy);
+ addStoreMethod("Store2", AST.getExtVectorType(AST.UnsignedIntTy, 2));
+ addStoreMethod("Store3", AST.getExtVectorType(AST.UnsignedIntTy, 3));
+ addStoreMethod("Store4", AST.getExtVectorType(AST.UnsignedIntTy, 4));
+
+ // {
+ // IdentifierInfo &II = AST.Idents.get("Store", tok::TokenKind::identifier);
+ // DeclarationName Store(&II);
+
+ // BuiltinTypeMethodBuilder Builder(*this, Store, AST.VoidTy,
+ // /*IsConst=*/false); QualType TType =
+ // Builder.addTemplateTypeParam("element_type");
+ // Builder.addParam("byteOffset", AST.UnsignedIntTy)
+ // .addParam("value", TType)
+ // .callBuiltin("__builtin_hlsl_byteaddressbuffer_store", AST.VoidTy,
+ // PH::Handle, PH::_0, PH::_1)
+ // .finalize();
+ // }
+
+ return *this;
+}
+
FieldDecl *BuiltinTypeDeclBuilder::getResourceHandleField() const {
auto I = Fields.find("__handle");
assert(I != Fields.end() &&
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
index 47c8b0e225612..8309ba990fda0 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
@@ -87,6 +87,8 @@ class BuiltinTypeDeclBuilder {
// Builtin types methods
BuiltinTypeDeclBuilder &addLoadMethods();
+ BuiltinTypeDeclBuilder &addByteAddressBufferLoadMethods();
+ BuiltinTypeDeclBuilder &addByteAddressBufferStoreMethods();
BuiltinTypeDeclBuilder &addIncrementCounterMethod();
BuiltinTypeDeclBuilder &addDecrementCounterMethod();
BuiltinTypeDeclBuilder &addHandleAccessFunction(DeclarationName &Name,
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 6be84f19a8f08..948005312f4dd 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -480,6 +480,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
onCompletion(Decl, [this](CXXRecordDecl *Decl) {
setupBufferType(Decl, *SemaPtr, ResourceClass::SRV, /*IsROV=*/false,
/*RawBuffer=*/true, /*HasCounter=*/false)
+ .addByteAddressBufferLoadMethods()
.addGetDimensionsMethodForBuffer()
.completeDefinition();
});
@@ -488,6 +489,8 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
onCompletion(Decl, [this](CXXRecordDecl *Decl) {
setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, /*IsROV=*/false,
/*RawBuffer=*/true, /*HasCounter=*/false)
+ .addByteAddressBufferLoadMethods()
+ .addByteAddressBufferStoreMethods()
.addGetDimensionsMethodForBuffer()
.completeDefinition();
});
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 1d8e035cd9713..93ac08dc9fe83 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3348,7 +3348,50 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
break;
}
+ case Builtin::BI__builtin_hlsl_byteaddressbuffer_load: {
+ if (SemaRef.checkArgCount(TheCall, 2) ||
+ CheckResourceHandle(&SemaRef, TheCall, 0) ||
+ CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
+ SemaRef.getASTContext().UnsignedIntTy))
+ return true;
+
+ auto *ResourceTy =
+ TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
+ QualType ReturnType = ResourceTy->getContainedType();
+ TheCall->setType(ReturnType);
+ break;
+ }
+ case Builtin::BI__builtin_hlsl_byteaddressbuffer_load_with_status: {
+ if (SemaRef.checkArgCount(TheCall, 3) ||
+ CheckResourceHandle(&SemaRef, TheCall, 0) ||
+ CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
+ SemaRef.getASTContext().UnsignedIntTy) ||
+ CheckArgTypeMatches(&SemaRef, TheCall->getArg(2),
+ SemaRef.getASTContext().UnsignedIntTy) ||
+ CheckModifiableLValue(&SemaRef, TheCall, 2))
+ return true;
+
+ auto *ResourceTy =
+ TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
+ QualType ReturnType = ResourceTy->getContainedType();
+ TheCall->setType(ReturnType);
+
+ break;
+ }
+ case Builtin::BI__builtin_hlsl_byteaddressbuffer_store: {
+ if (SemaRef.checkArgCount(TheCall, 3) ||
+ CheckResourceHandle(&SemaRef, TheCall, 0) ||
+ CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
+ SemaRef.getASTContext().UnsignedIntTy))
+ return true;
+
+ // || CheckArgTypeMatches(&SemaRef, TheCall->getArg(2),
+ // SemaRef.getASTContext().UnsignedIntTy)
+
+ TheCall->setType(SemaRef.Context.VoidTy);
+ break;
+ }
case Builtin::BI__builtin_hlsl_resource_uninitializedhandle: {
assert(TheCall->getNumArgs() == 1 && "expected 1 arg");
// Update return type to be the attributed resource type from arg0.
diff --git a/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl b/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
index 619b12a278b10..4bfecaeaba341 100644
--- a/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
+++ b/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
@@ -152,9 +152,16 @@ RESOURCE Buffer;
// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue Var {{.*}} 'tmp' 'hlsl::[[RESOURCE]]'
// CHECK-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
+// Load method
+
+// CHECK-SRV: CXXMethodDecl {{.*}} Load 'unsigned int (unsigned int)'
+// CHECK-SRV: CXXMethodDecl {{.*}} Load 'unsigned int (unsigned int, out unsigned int)
+
+// Store method
+
// GetDimensions method
-// CHECK-NEXT: CXXMethodDecl {{.*}} GetDimensions 'void (out unsigned int)'
+// CHECK: CXXMethodDecl {{.*}} GetDimensions 'void (out unsigned int)'
// CHECK-NEXT: ParmVarDecl {{.*}} dim 'unsigned int &__restrict'
// CHECK-NEXT: HLSLParamModifierAttr {{.*}} out
// CHECK-NEXT: CompoundStmt
diff --git a/clang/test/CodeGenHLSL/resources/ByteAddressBuffers-methods.hlsl b/clang/test/CodeGenHLSL/resources/ByteAddressBuffers-methods.hlsl
index 9dd02287620e7..0233c117bc000 100644
--- a/clang/test/CodeGenHLSL/resources/ByteAddressBuffers-methods.hlsl
+++ b/clang/test/CodeGenHLSL/resources/ByteAddressBuffers-methods.hlsl
@@ -12,6 +12,40 @@ RWByteAddressBuffer RWBuf : register(u0);
// DXIL: @Buf = internal global %"class.hlsl::ByteAddressBuffer" poison
// DXIL: @RWBuf = internal global %"class.hlsl::RWByteAddressBuffer" poison
+export uint TestLoad() {
+ uint u = Buf.Load(0);
+ uint2 v = Buf.Load2(0);
+ float f = Buf.Load<float>(4);
+ //float4 v = RWBuf.Load<float4>(8);
+ return u;
+}
+
+// CHECK: define {{.*}} i32 @TestLoad()()
+// CHECK: call {{.*}} i32 @hlsl::ByteAddressBuffer::Load(unsigned int)(ptr {{.*}} @Buf, i32 noundef 0)
+// CHECK: ret i32
+
+export uint TestLoadWithStatus() {
+ uint s1;
+ uint u = Buf.Load(0, s1);
+ return u;
+}
+
+// CHECK: define {{.*}} i32 @TestLoadWithStatus()()
+// CHECK: call {{.*}} i32 @hlsl::ByteAddressBuffer::Load(unsigned int, unsigned int&)(ptr {{.*}} @Buf, i32 noundef 0, ptr {{.*}} %tmp)
+// CHECK: ret i32
+
+export void TestStore() {
+ uint u0;
+ //float f0;
+ RWBuf.Store(0, u0);
+ //RWBuf.Store<float>(0, f0);
+ return;
+}
+
+// CHECK: define void @TestStore()()
+// CHECK: call void @hlsl::RWByteAddressBuffer::Store(unsigned int, unsigned int)(ptr {{.*}} @RWBuf, i32 noundef 0, i32 noundef %{{.*}})
+// CHECK: ret void
+
export uint TestGetDimensions() {
uint dim1, dim2;
Buf.GetDimensions(dim1);
>From 956e0c3dd3d27e8d5863da2f0bc9aa74d7f6888f Mon Sep 17 00:00:00 2001
From: kmpeng <kaitlinpeng at microsoft.com>
Date: Thu, 18 Dec 2025 21:47:07 -0800
Subject: [PATCH 02/12] templated load/store mostly working, bugs with
bool/aggregate types
---
clang/lib/CodeGen/CGHLSLBuiltins.cpp | 6 +-
clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 61 +++---
clang/lib/Sema/SemaHLSL.cpp | 15 +-
.../lib/Sema/SemaTemplateInstantiateDecl.cpp | 16 +-
.../test/AST/HLSL/ByteAddressBuffers-AST.hlsl | 201 +++++++++++++++++-
.../resources/ByteAddressBuffers-methods.hlsl | 18 +-
6 files changed, 268 insertions(+), 49 deletions(-)
diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
index c5f29fd2602df..955a24cd26d7e 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -584,7 +584,11 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
case Builtin::BI__builtin_hlsl_byteaddressbuffer_store: {
Value *HandleOp = EmitScalarExpr(E->getArg(0));
Value *ByteOffsetOp = EmitScalarExpr(E->getArg(1));
- Value *ValueOp = EmitScalarExpr(E->getArg(2));
+ RValue RVal = EmitAnyExpr(E->getArg(2));
+ Value *ValueOp =
+ RVal.isScalar()
+ ? RVal.getScalarVal()
+ : Builder.CreateLoad(RVal.getAggregateAddress(), "store_val");
Value *ElementOffset = llvm::PoisonValue::get(Builder.getInt32Ty());
SmallVector<Value *, 4> Args = {HandleOp, ByteOffsetOp, ElementOffset,
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index 5d5a1758590a5..0877b763c21e6 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -1236,20 +1236,29 @@ BuiltinTypeDeclBuilder::addByteAddressBufferLoadMethods() {
addLoadMethod("Load3", AST.getExtVectorType(AST.UnsignedIntTy, 3));
addLoadMethod("Load4", AST.getExtVectorType(AST.UnsignedIntTy, 4));
- // templated
- {
- IdentifierInfo &II = AST.Idents.get("Load", tok::TokenKind::identifier);
- DeclarationName Load(&II);
- BuiltinTypeMethodBuilder Builder(*this, Load, AST.UnsignedIntTy,
- /*IsConst=*/false);
- QualType TType = Builder.addTemplateTypeParam("element_type");
- Builder.ReturnTy = TType; // Update return type to template parameter
-
- Builder.addParam("byteOffset", AST.UnsignedIntTy)
- .callBuiltin("__builtin_hlsl_byteaddressbuffer_load", TType, PH::Handle,
- PH::_0)
- .finalize();
- }
+ // Templated Load method
+ IdentifierInfo &II = AST.Idents.get("Load", tok::TokenKind::identifier);
+ DeclarationName Load(&II);
+
+ BuiltinTypeMethodBuilder MMB(*this, Load, AST.UnsignedIntTy,
+ /*IsConst=*/false);
+ QualType ReturnType = MMB.addTemplateTypeParam("element_type");
+ MMB.ReturnTy = ReturnType; // Update return type to template parameter
+ MMB.addParam("byteOffset", AST.UnsignedIntTy)
+ .callBuiltin("__builtin_hlsl_byteaddressbuffer_load", ReturnType,
+ PH::Handle, PH::_0)
+ .finalize();
+
+ // Templated Load with status method
+ BuiltinTypeMethodBuilder MMB2(*this, Load, AST.UnsignedIntTy,
+ /*IsConst=*/false);
+ QualType ReturnType2 = MMB2.addTemplateTypeParam("element_type");
+ MMB2.ReturnTy = ReturnType2; // Update return type to template parameter
+ MMB2.addParam("byteOffset", AST.UnsignedIntTy)
+ .addParam("status", AST.UnsignedIntTy, HLSLParamModifierAttr::Keyword_out)
+ .callBuiltin("__builtin_hlsl_byteaddressbuffer_load_with_status",
+ ReturnType2, PH::Handle, PH::_0, PH::_1)
+ .finalize();
return *this;
}
@@ -1279,19 +1288,17 @@ BuiltinTypeDeclBuilder::addByteAddressBufferStoreMethods() {
addStoreMethod("Store3", AST.getExtVectorType(AST.UnsignedIntTy, 3));
addStoreMethod("Store4", AST.getExtVectorType(AST.UnsignedIntTy, 4));
- // {
- // IdentifierInfo &II = AST.Idents.get("Store", tok::TokenKind::identifier);
- // DeclarationName Store(&II);
-
- // BuiltinTypeMethodBuilder Builder(*this, Store, AST.VoidTy,
- // /*IsConst=*/false); QualType TType =
- // Builder.addTemplateTypeParam("element_type");
- // Builder.addParam("byteOffset", AST.UnsignedIntTy)
- // .addParam("value", TType)
- // .callBuiltin("__builtin_hlsl_byteaddressbuffer_store", AST.VoidTy,
- // PH::Handle, PH::_0, PH::_1)
- // .finalize();
- // }
+ // Templated Store method
+ IdentifierInfo &II = AST.Idents.get("Store", tok::TokenKind::identifier);
+ DeclarationName Store(&II);
+
+ BuiltinTypeMethodBuilder Builder(*this, Store, AST.VoidTy, /*IsConst=*/false);
+ QualType ReturnType = Builder.addTemplateTypeParam("element_type");
+ Builder.addParam("byteOffset", AST.UnsignedIntTy)
+ .addParam("value", ReturnType)
+ .callBuiltin("__builtin_hlsl_byteaddressbuffer_store", AST.VoidTy,
+ PH::Handle, PH::_0, PH::_1)
+ .finalize();
return *this;
}
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 93ac08dc9fe83..d97c9716aef48 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3355,10 +3355,8 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
SemaRef.getASTContext().UnsignedIntTy))
return true;
- auto *ResourceTy =
- TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
- QualType ReturnType = ResourceTy->getContainedType();
- TheCall->setType(ReturnType);
+ auto *FD = dyn_cast<FunctionDecl>(SemaRef.CurContext);
+ TheCall->setType(FD->getReturnType());
break;
}
@@ -3372,10 +3370,8 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
CheckModifiableLValue(&SemaRef, TheCall, 2))
return true;
- auto *ResourceTy =
- TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
- QualType ReturnType = ResourceTy->getContainedType();
- TheCall->setType(ReturnType);
+ auto *FD = dyn_cast<FunctionDecl>(SemaRef.CurContext);
+ TheCall->setType(FD->getReturnType());
break;
}
@@ -3386,8 +3382,7 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
SemaRef.getASTContext().UnsignedIntTy))
return true;
- // || CheckArgTypeMatches(&SemaRef, TheCall->getArg(2),
- // SemaRef.getASTContext().UnsignedIntTy)
+ // need to check anything for the 2nd parameter? not an array?
TheCall->setType(SemaRef.Context.VoidTy);
break;
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index e74c41517ecbf..348ac5e75af7c 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -6901,8 +6901,20 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
// whose type is not instantiation dependent, do nothing to the decl
// - otherwise find its instantiated decl.
if (isa<ParmVarDecl>(D) && !ParentDependsOnArgs &&
- !cast<ParmVarDecl>(D)->getType()->isInstantiationDependentType())
- return D;
+ !cast<ParmVarDecl>(D)->getType()->isInstantiationDependentType()) {
+ // Check if D belongs to a function template
+ auto *PVD = cast<ParmVarDecl>(D);
+ bool IsFromFunctionTemplate =
+ llvm::any_of(ParentDC->decls(), [PVD](Decl *D) {
+ if (auto *FTD = dyn_cast<FunctionTemplateDecl>(D))
+ return llvm::is_contained(FTD->getTemplatedDecl()->parameters(),
+ PVD);
+ return false;
+ });
+
+ if (!IsFromFunctionTemplate)
+ return D;
+ }
if (isa<ParmVarDecl>(D) || isa<NonTypeTemplateParmDecl>(D) ||
isa<TemplateTypeParmDecl>(D) || isa<TemplateTemplateParmDecl>(D) ||
(ParentDependsOnArgs && (ParentDC->isFunctionOrMethod() ||
diff --git a/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl b/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
index 4bfecaeaba341..8be0379a76029 100644
--- a/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
+++ b/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
@@ -4,7 +4,7 @@
//
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump \
// RUN: -DRESOURCE=ByteAddressBuffer %s | FileCheck -DRESOURCE=ByteAddressBuffer \
-// RUN: -check-prefixes=CHECK,CHECK-SRV,CHECK-NOSUBSCRIPT %s
+// RUN: -check-prefixes=CHECK,CHECK-SRV,CHECK-NOSUBSCRIPT,CHECK-LOAD %s
//
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump -DEMPTY \
// RUN: -DRESOURCE=RWByteAddressBuffer %s | FileCheck -DRESOURCE=RWByteAddressBuffer \
@@ -12,7 +12,7 @@
//
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump \
// RUN: -DRESOURCE=RWByteAddressBuffer %s | FileCheck -DRESOURCE=RWByteAddressBuffer \
-// RUN: -check-prefixes=CHECK,CHECK-UAV,CHECK-NOSUBSCRIPT %s
+// RUN: -check-prefixes=CHECK,CHECK-UAV,CHECK-NOSUBSCRIPT,CHECK-LOAD,CHECK-STORE %s
//
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump -DEMPTY \
// RUN: -DRESOURCE=RasterizerOrderedByteAddressBuffer %s | FileCheck -DRESOURCE=RasterizerOrderedByteAddressBuffer \
@@ -152,12 +152,203 @@ RESOURCE Buffer;
// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue Var {{.*}} 'tmp' 'hlsl::[[RESOURCE]]'
// CHECK-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
-// Load method
+// Load methods
+
+// CHECK-LOAD: CXXMethodDecl {{.*}} Load 'unsigned int (unsigned int)'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} byteOffset 'unsigned int'
+// CHECK-LOAD-NEXT: CompoundStmt
+// CHECK-LOAD-NEXT: ReturnStmt
+// CHECK-LOAD-NEXT: CallExpr {{.*}} 'unsigned int'
+// CHECK-LOAD-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_load' 'void (...) noexcept'
+// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
+// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'byteOffset' 'unsigned int'
+// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
+// CHECK-LOAD: CXXMethodDecl {{.*}} Load 'unsigned int (unsigned int, out unsigned int)
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} byteOffset 'unsigned int'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} status 'unsigned int &__restrict'
+// CHECK-LOAD-NEXT: HLSLParamModifierAttr {{.*}} out
+// CHECK-LOAD-NEXT: CompoundStmt
+// CHECK-LOAD-NEXT: ReturnStmt
+// CHECK-LOAD-NEXT: CallExpr {{.*}} 'unsigned int'
+// CHECK-LOAD-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_load_with_status' 'void (...) noexcept'
+// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
+// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'byteOffset' 'unsigned int'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'status' 'unsigned int &__restrict'
+// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
+
+// CHECK-LOAD: CXXMethodDecl {{.*}} Load2 'vector<unsigned int (unsigned int), 2>'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} byteOffset 'unsigned int'
+// CHECK-LOAD-NEXT: CompoundStmt
+// CHECK-LOAD-NEXT: ReturnStmt
+// CHECK-LOAD-NEXT: CallExpr {{.*}} 'vector<unsigned int, 2>'
+// CHECK-LOAD-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_load' 'void (...) noexcept'
+// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
+// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'byteOffset' 'unsigned int'
+// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
+// CHECK-LOAD: CXXMethodDecl {{.*}} Load2 'vector<unsigned int (unsigned int, out unsigned int), 2>'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} byteOffset 'unsigned int'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} status 'unsigned int &__restrict'
+// CHECK-LOAD-NEXT: HLSLParamModifierAttr {{.*}} out
+// CHECK-LOAD-NEXT: CompoundStmt
+// CHECK-LOAD-NEXT: ReturnStmt
+// CHECK-LOAD-NEXT: CallExpr {{.*}} 'vector<unsigned int, 2>'
+// CHECK-LOAD-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_load_with_status' 'void (...) noexcept'
+// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
+// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'byteOffset' 'unsigned int'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'status' 'unsigned int &__restrict'
+// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
+
+// CHECK-LOAD: CXXMethodDecl {{.*}} Load3 'vector<unsigned int (unsigned int), 3>'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} byteOffset 'unsigned int'
+// CHECK-LOAD-NEXT: CompoundStmt
+// CHECK-LOAD-NEXT: ReturnStmt
+// CHECK-LOAD-NEXT: CallExpr {{.*}} 'vector<unsigned int, 3>'
+// CHECK-LOAD-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_load' 'void (...) noexcept'
+// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
+// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'byteOffset' 'unsigned int'
+// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
+// CHECK-LOAD: CXXMethodDecl {{.*}} Load3 'vector<unsigned int (unsigned int, out unsigned int), 3>'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} byteOffset 'unsigned int'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} status 'unsigned int &__restrict'
+// CHECK-LOAD-NEXT: HLSLParamModifierAttr {{.*}} out
+// CHECK-LOAD-NEXT: CompoundStmt
+// CHECK-LOAD-NEXT: ReturnStmt
+// CHECK-LOAD-NEXT: CallExpr {{.*}} 'vector<unsigned int, 3>'
+// CHECK-LOAD-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_load_with_status' 'void (...) noexcept'
+// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
+// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'byteOffset' 'unsigned int'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'status' 'unsigned int &__restrict'
+// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
+
+// CHECK-LOAD: CXXMethodDecl {{.*}} Load4 'vector<unsigned int (unsigned int), 4>'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} byteOffset 'unsigned int'
+// CHECK-LOAD-NEXT: CompoundStmt
+// CHECK-LOAD-NEXT: ReturnStmt
+// CHECK-LOAD-NEXT: CallExpr {{.*}} 'vector<unsigned int, 4>'
+// CHECK-LOAD-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_load' 'void (...) noexcept'
+// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
+// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'byteOffset' 'unsigned int'
+// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
+// CHECK-LOAD: CXXMethodDecl {{.*}} Load4 'vector<unsigned int (unsigned int, out unsigned int), 4>'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} byteOffset 'unsigned int'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} status 'unsigned int &__restrict'
+// CHECK-LOAD-NEXT: HLSLParamModifierAttr {{.*}} out
+// CHECK-LOAD-NEXT: CompoundStmt
+// CHECK-LOAD-NEXT: ReturnStmt
+// CHECK-LOAD-NEXT: CallExpr {{.*}} 'vector<unsigned int, 4>'
+// CHECK-LOAD-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_load_with_status' 'void (...) noexcept'
+// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
+// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'byteOffset' 'unsigned int'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'status' 'unsigned int &__restrict'
+// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
-// CHECK-SRV: CXXMethodDecl {{.*}} Load 'unsigned int (unsigned int)'
-// CHECK-SRV: CXXMethodDecl {{.*}} Load 'unsigned int (unsigned int, out unsigned int)
+// CHECK-LOAD: CXXMethodDecl {{.*}} Load 'element_type (unsigned int)'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} byteOffset 'unsigned int'
+// CHECK-LOAD-NEXT: CompoundStmt
+// CHECK-LOAD-NEXT: ReturnStmt
+// CHECK-LOAD-NEXT: CallExpr {{.*}} 'element_type'
+// CHECK-LOAD-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_load' 'void (...) noexcept'
+// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
+// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'byteOffset' 'unsigned int'
+// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
+// CHECK-LOAD: CXXMethodDecl {{.*}} Load 'element_type (unsigned int, out unsigned int)
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} byteOffset 'unsigned int'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} status 'unsigned int &__restrict'
+// CHECK-LOAD-NEXT: HLSLParamModifierAttr {{.*}} out
+// CHECK-LOAD-NEXT: CompoundStmt
+// CHECK-LOAD-NEXT: ReturnStmt
+// CHECK-LOAD-NEXT: CallExpr {{.*}} 'element_type'
+// CHECK-LOAD-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_load_with_status' 'void (...) noexcept'
+// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
+// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'byteOffset' 'unsigned int'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'status' 'unsigned int &__restrict'
+// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
// Store method
+// CHECK-STORE: CXXMethodDecl {{.*}} Store 'void (unsigned int, unsigned int)'
+// CHECK-STORE-NEXT: ParmVarDecl {{.*}} byteOffset 'unsigned int'
+// CHECK-STORE-NEXT: ParmVarDecl {{.*}} value 'unsigned int'
+// CHECK-STORE-NEXT: CompoundStmt
+// CHECK-STORE-NEXT: CallExpr {{.*}} 'void'
+// CHECK-STORE-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_store' 'void (...) noexcept'
+// CHECK-STORE-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
+// CHECK-STORE-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'byteOffset' 'unsigned int'
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'value' 'unsigned int'
+// CHECK-STORE-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
+
+// CHECK-STORE: CXXMethodDecl {{.*}} Store2 'void (unsigned int, vector<unsigned int, 2>)'
+// CHECK-STORE-NEXT: ParmVarDecl {{.*}} byteOffset 'unsigned int'
+// CHECK-STORE-NEXT: ParmVarDecl {{.*}} value 'vector<unsigned int, 2>'
+// CHECK-STORE-NEXT: CompoundStmt
+// CHECK-STORE-NEXT: CallExpr {{.*}} 'void'
+// CHECK-STORE-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_store' 'void (...) noexcept'
+// CHECK-STORE-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
+// CHECK-STORE-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'byteOffset' 'unsigned int'
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'vector<unsigned int, 2>' ParmVar {{.*}} 'value' 'vector<unsigned int, 2>'
+// CHECK-STORE-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
+
+// CHECK-STORE: CXXMethodDecl {{.*}} Store3 'void (unsigned int, vector<unsigned int, 3>)'
+// CHECK-STORE-NEXT: ParmVarDecl {{.*}} byteOffset 'unsigned int'
+// CHECK-STORE-NEXT: ParmVarDecl {{.*}} value 'vector<unsigned int, 3>'
+// CHECK-STORE-NEXT: CompoundStmt
+// CHECK-STORE-NEXT: CallExpr {{.*}} 'void'
+// CHECK-STORE-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_store' 'void (...) noexcept'
+// CHECK-STORE-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
+// CHECK-STORE-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'byteOffset' 'unsigned int'
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'vector<unsigned int, 3>' ParmVar {{.*}} 'value' 'vector<unsigned int, 3>'
+// CHECK-STORE-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
+
+// CHECK-STORE: CXXMethodDecl {{.*}} Store4 'void (unsigned int, vector<unsigned int, 4>)'
+// CHECK-STORE-NEXT: ParmVarDecl {{.*}} byteOffset 'unsigned int'
+// CHECK-STORE-NEXT: ParmVarDecl {{.*}} value 'vector<unsigned int, 4>'
+// CHECK-STORE-NEXT: CompoundStmt
+// CHECK-STORE-NEXT: CallExpr {{.*}} 'void'
+// CHECK-STORE-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_store' 'void (...) noexcept'
+// CHECK-STORE-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
+// CHECK-STORE-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'byteOffset' 'unsigned int'
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'vector<unsigned int, 4>' ParmVar {{.*}} 'value' 'vector<unsigned int, 4>'
+// CHECK-STORE-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
+
+// CHECK-STORE: CXXMethodDecl {{.*}} Store 'void (unsigned int, element_type)'
+// CHECK-STORE-NEXT: ParmVarDecl {{.*}} byteOffset 'unsigned int'
+// CHECK-STORE-NEXT: ParmVarDecl {{.*}} value 'element_type'
+// CHECK-STORE-NEXT: CompoundStmt
+// CHECK-STORE-NEXT: CallExpr {{.*}} 'void'
+// CHECK-STORE-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_store' 'void (...) noexcept'
+// CHECK-STORE-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
+// CHECK-STORE-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'byteOffset' 'unsigned int'
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'element_type' ParmVar {{.*}} 'value' 'element_type'
+// CHECK-STORE-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
// GetDimensions method
diff --git a/clang/test/CodeGenHLSL/resources/ByteAddressBuffers-methods.hlsl b/clang/test/CodeGenHLSL/resources/ByteAddressBuffers-methods.hlsl
index 0233c117bc000..ba6f059c6346b 100644
--- a/clang/test/CodeGenHLSL/resources/ByteAddressBuffers-methods.hlsl
+++ b/clang/test/CodeGenHLSL/resources/ByteAddressBuffers-methods.hlsl
@@ -3,6 +3,11 @@
// NOTE: SPIRV codegen for resource methods is not yet implemented
+struct SmallStruct {
+ int a;
+ uint b;
+};
+
ByteAddressBuffer Buf : register(t0);
RWByteAddressBuffer RWBuf : register(u0);
@@ -16,7 +21,8 @@ export uint TestLoad() {
uint u = Buf.Load(0);
uint2 v = Buf.Load2(0);
float f = Buf.Load<float>(4);
- //float4 v = RWBuf.Load<float4>(8);
+ float4 g = Buf.Load<float4>(8);
+ SmallStruct U9 = Buf.Load<SmallStruct>(0);
return u;
}
@@ -25,8 +31,10 @@ export uint TestLoad() {
// CHECK: ret i32
export uint TestLoadWithStatus() {
- uint s1;
+ uint s1, s2, s3;
uint u = Buf.Load(0, s1);
+ float f = Buf.Load<float>(4, s2);
+ SmallStruct U9 = Buf.Load<SmallStruct>(0, s3);
return u;
}
@@ -36,9 +44,11 @@ export uint TestLoadWithStatus() {
export void TestStore() {
uint u0;
- //float f0;
+ float f0;
RWBuf.Store(0, u0);
- //RWBuf.Store<float>(0, f0);
+ RWBuf.Store<float>(0, f0);
+ SmallStruct TempStruct1;
+ RWBuf.Store<SmallStruct>(144, TempStruct1);
return;
}
>From f7d3112a590b328682ffee18b86fd986b5d24e1b Mon Sep 17 00:00:00 2001
From: kmpeng <kaitlinpeng at microsoft.com>
Date: Fri, 19 Dec 2025 01:43:59 -0800
Subject: [PATCH 03/12] change load with status and store builtins, change
param names
---
clang/include/clang/Basic/Builtins.td | 10 +-
clang/lib/CodeGen/CGHLSLBuiltins.cpp | 73 +++++------
clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 54 +++++---
clang/lib/Sema/SemaHLSL.cpp | 27 ++--
.../test/AST/HLSL/ByteAddressBuffers-AST.hlsl | 120 +++++++++---------
5 files changed, 139 insertions(+), 145 deletions(-)
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index bc127ff91fe50..86f931fa42ad6 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -5007,14 +5007,8 @@ def HLSLByteAddressBufferLoad : LangBuiltin<"HLSL_LANG"> {
let Prototype = "void(...)";
}
-def HLSLByteAddressBufferLoadWithStatus : LangBuiltin<"HLSL_LANG"> {
- let Spellings = ["__builtin_hlsl_byteaddressbuffer_load_with_status"];
- let Attributes = [NoThrow];
- let Prototype = "void(...)";
-}
-
-def HLSLByteAddressBufferStore : LangBuiltin<"HLSL_LANG"> {
- let Spellings = ["__builtin_hlsl_byteaddressbuffer_store"];
+def HLSLResourceStore : LangBuiltin<"HLSL_LANG"> {
+ let Spellings = ["__builtin_hlsl_resource_store"];
let Attributes = [NoThrow];
let Prototype = "void(...)";
}
diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
index 955a24cd26d7e..392d64a435926 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -489,6 +489,10 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
Value *IndexOp = EmitScalarExpr(E->getArg(1));
llvm::Type *RetTy = ConvertType(E->getType());
+ // byteaddressbufferload attempt
+ // tried replacing last parameter with a SmallVector<Value *> Args like
+ // load_with_status where the last arg is poison but that broke every
+ // intrinsic that uses this builtin
return Builder.CreateIntrinsic(
RetTy, CGM.getHLSLRuntime().getCreateResourceGetPointerIntrinsic(),
ArrayRef<Value *>{HandleOp, IndexOp});
@@ -521,6 +525,9 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
if (RT->getAttrs().RawBuffer) {
Value *Offset = Builder.getInt32(0);
+ // Offset is poison for ByteAddressBuffer
+ if (RT->getContainedType()->isChar8Type())
+ Offset = llvm::PoisonValue::get(Builder.getInt32Ty());
Args.push_back(Offset);
}
@@ -538,65 +545,49 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
}
case Builtin::BI__builtin_hlsl_byteaddressbuffer_load: {
Value *HandleOp = EmitScalarExpr(E->getArg(0));
- Value *ByteOffsetOp = EmitScalarExpr(E->getArg(1));
- Value *ElementOffset = llvm::PoisonValue::get(Builder.getInt32Ty());
+ Value *IndexOp = EmitScalarExpr(E->getArg(1));
+ Value *Offset = llvm::PoisonValue::get(Builder.getInt32Ty());
llvm::Type *DataTy = ConvertType(E->getType());
llvm::Type *RetTy = llvm::StructType::get(Builder.getContext(),
{DataTy, Builder.getInt1Ty()});
- SmallVector<Value *, 3> Args = {HandleOp, ByteOffsetOp, ElementOffset};
+ SmallVector<Value *, 3> Args = {HandleOp, IndexOp, Offset};
Value *ResRet = Builder.CreateIntrinsic(
RetTy, Intrinsic::dx_resource_load_rawbuffer, Args);
return Builder.CreateExtractValue(ResRet, {0}, "ld.value");
}
- case Builtin::BI__builtin_hlsl_byteaddressbuffer_load_with_status: {
+ case Builtin::BI__builtin_hlsl_resource_store: {
Value *HandleOp = EmitScalarExpr(E->getArg(0));
- Value *ByteOffsetOp = EmitScalarExpr(E->getArg(1));
- Value *ElementOffset = llvm::PoisonValue::get(Builder.getInt32Ty());
-
- // Get the *address* of the status argument to write to it by reference
- LValue StatusLVal = EmitLValue(E->getArg(2));
- Address StatusAddr = StatusLVal.getAddress();
-
- assert(CGM.getTarget().getTriple().getArch() == llvm::Triple::dxil &&
- "Only DXIL currently implements load with status");
-
- llvm::Type *DataTy = ConvertType(E->getType());
- llvm::Type *RetTy = llvm::StructType::get(Builder.getContext(),
- {DataTy, Builder.getInt1Ty()});
-
- SmallVector<Value *, 3> Args = {HandleOp, ByteOffsetOp, ElementOffset};
-
- // The load intrinsics give us a (T value, i1 status) pair -
- // shepherd these into the return value and out reference respectively.
- Value *ResRet = Builder.CreateIntrinsic(
- RetTy, Intrinsic::dx_resource_load_rawbuffer, Args, {}, "ld.struct");
- Value *LoadedValue = Builder.CreateExtractValue(ResRet, {0}, "ld.value");
- Value *StatusBit = Builder.CreateExtractValue(ResRet, {1}, "ld.status");
- Value *ExtendedStatus =
- Builder.CreateZExt(StatusBit, Builder.getInt32Ty(), "ld.status.ext");
- Builder.CreateStore(ExtendedStatus, StatusAddr);
-
- return LoadedValue;
- }
- case Builtin::BI__builtin_hlsl_byteaddressbuffer_store: {
- Value *HandleOp = EmitScalarExpr(E->getArg(0));
- Value *ByteOffsetOp = EmitScalarExpr(E->getArg(1));
+ Value *IndexOp = EmitScalarExpr(E->getArg(1));
RValue RVal = EmitAnyExpr(E->getArg(2));
Value *ValueOp =
RVal.isScalar()
? RVal.getScalarVal()
: Builder.CreateLoad(RVal.getAggregateAddress(), "store_val");
- Value *ElementOffset = llvm::PoisonValue::get(Builder.getInt32Ty());
- SmallVector<Value *, 4> Args = {HandleOp, ByteOffsetOp, ElementOffset,
- ValueOp};
+ QualType HandleTy = E->getArg(0)->getType();
+ const HLSLAttributedResourceType *RT =
+ HandleTy->getAs<HLSLAttributedResourceType>();
+ Intrinsic::ID IntrID = RT->getAttrs().RawBuffer
+ ? llvm::Intrinsic::dx_resource_store_rawbuffer
+ : llvm::Intrinsic::dx_resource_store_typedbuffer;
- return Builder.CreateIntrinsic(Intrinsic::dx_resource_store_rawbuffer,
- {HandleOp->getType(), ValueOp->getType()},
- Args);
+ SmallVector<Value *, 4> Args;
+ Args.push_back(HandleOp);
+ Args.push_back(IndexOp);
+ if (RT->getAttrs().RawBuffer) {
+ Value *Offset = Builder.getInt32(0);
+ // Offset is poison for ByteAddressBuffer
+ if (RT->getContainedType()->isChar8Type())
+ Offset = llvm::PoisonValue::get(Builder.getInt32Ty());
+ Args.push_back(Offset);
+ }
+ Args.push_back(ValueOp);
+
+ return Builder.CreateIntrinsic(
+ IntrID, {HandleOp->getType(), ValueOp->getType()}, Args);
}
case Builtin::BI__builtin_hlsl_resource_uninitializedhandle: {
llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType());
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index 0877b763c21e6..2a1ae0dc1bf01 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -1209,25 +1209,25 @@ BuiltinTypeDeclBuilder::addByteAddressBufferLoadMethods() {
using PH = BuiltinTypeMethodBuilder::PlaceHolder;
ASTContext &AST = SemaRef.getASTContext();
- // Helper to add uint Load methods
+ // Add uint Load methods
auto addLoadMethod = [&](StringRef MethodName, QualType ReturnType) {
IdentifierInfo &II = AST.Idents.get(MethodName, tok::TokenKind::identifier);
DeclarationName Load(&II);
// Load without status
BuiltinTypeMethodBuilder(*this, Load, ReturnType, /*IsConst=*/false)
- .addParam("byteOffset", AST.UnsignedIntTy)
+ .addParam("Index", AST.UnsignedIntTy)
.callBuiltin("__builtin_hlsl_byteaddressbuffer_load", ReturnType,
PH::Handle, PH::_0)
.finalize();
// Load with status
BuiltinTypeMethodBuilder(*this, Load, ReturnType, /*IsConst=*/false)
- .addParam("byteOffset", AST.UnsignedIntTy)
- .addParam("status", AST.UnsignedIntTy,
+ .addParam("Index", AST.UnsignedIntTy)
+ .addParam("Status", AST.UnsignedIntTy,
HLSLParamModifierAttr::Keyword_out)
- .callBuiltin("__builtin_hlsl_byteaddressbuffer_load_with_status",
- ReturnType, PH::Handle, PH::_0, PH::_1)
+ .callBuiltin("__builtin_hlsl_resource_load_with_status", ReturnType,
+ PH::Handle, PH::_0, PH::_1)
.finalize();
};
@@ -1244,20 +1244,34 @@ BuiltinTypeDeclBuilder::addByteAddressBufferLoadMethods() {
/*IsConst=*/false);
QualType ReturnType = MMB.addTemplateTypeParam("element_type");
MMB.ReturnTy = ReturnType; // Update return type to template parameter
- MMB.addParam("byteOffset", AST.UnsignedIntTy)
+ MMB.addParam("Index", AST.UnsignedIntTy)
.callBuiltin("__builtin_hlsl_byteaddressbuffer_load", ReturnType,
PH::Handle, PH::_0)
.finalize();
+ // __builtin_hlsl_resource_getpointer attempt
+ // BuiltinTypeMethodBuilder MMB(*this, Load, AST.UnsignedIntTy,
+ // /*IsConst=*/false);
+ // QualType ReturnType = MMB.addTemplateTypeParam("element_type");
+ // MMB.ReturnTy = ReturnType; // Update return type to template parameter
+ // QualType AddrSpaceElemTy =
+ // AST.getAddrSpaceQualType(ReturnType, LangAS::hlsl_device);
+ // QualType ElemPtrTy = AST.getPointerType(AddrSpaceElemTy);
+ // MMB.addParam("Index", AST.UnsignedIntTy)
+ // .callBuiltin("__builtin_hlsl_resource_getpointer", ElemPtrTy,
+ // PH::Handle, PH::_0)
+ // .dereference(PH::LastStmt)
+ // .finalize();
+
// Templated Load with status method
BuiltinTypeMethodBuilder MMB2(*this, Load, AST.UnsignedIntTy,
/*IsConst=*/false);
QualType ReturnType2 = MMB2.addTemplateTypeParam("element_type");
MMB2.ReturnTy = ReturnType2; // Update return type to template parameter
- MMB2.addParam("byteOffset", AST.UnsignedIntTy)
- .addParam("status", AST.UnsignedIntTy, HLSLParamModifierAttr::Keyword_out)
- .callBuiltin("__builtin_hlsl_byteaddressbuffer_load_with_status",
- ReturnType2, PH::Handle, PH::_0, PH::_1)
+ MMB2.addParam("Index", AST.UnsignedIntTy)
+ .addParam("Status", AST.UnsignedIntTy, HLSLParamModifierAttr::Keyword_out)
+ .callBuiltin("__builtin_hlsl_resource_load_with_status", ReturnType2,
+ PH::Handle, PH::_0, PH::_1)
.finalize();
return *this;
@@ -1276,10 +1290,10 @@ BuiltinTypeDeclBuilder::addByteAddressBufferStoreMethods() {
DeclarationName Store(&II);
BuiltinTypeMethodBuilder(*this, Store, AST.VoidTy, /*IsConst=*/false)
- .addParam("byteOffset", AST.UnsignedIntTy)
- .addParam("value", ValueType)
- .callBuiltin("__builtin_hlsl_byteaddressbuffer_store", AST.VoidTy,
- PH::Handle, PH::_0, PH::_1)
+ .addParam("Index", AST.UnsignedIntTy)
+ .addParam("Value", ValueType)
+ .callBuiltin("__builtin_hlsl_resource_store", AST.VoidTy, PH::Handle,
+ PH::_0, PH::_1)
.finalize();
};
@@ -1293,11 +1307,11 @@ BuiltinTypeDeclBuilder::addByteAddressBufferStoreMethods() {
DeclarationName Store(&II);
BuiltinTypeMethodBuilder Builder(*this, Store, AST.VoidTy, /*IsConst=*/false);
- QualType ReturnType = Builder.addTemplateTypeParam("element_type");
- Builder.addParam("byteOffset", AST.UnsignedIntTy)
- .addParam("value", ReturnType)
- .callBuiltin("__builtin_hlsl_byteaddressbuffer_store", AST.VoidTy,
- PH::Handle, PH::_0, PH::_1)
+ QualType ValueType = Builder.addTemplateTypeParam("element_type");
+ Builder.addParam("Index", AST.UnsignedIntTy)
+ .addParam("Value", ValueType)
+ .callBuiltin("__builtin_hlsl_resource_store", AST.VoidTy, PH::Handle,
+ PH::_0, PH::_1)
.finalize();
return *this;
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index d97c9716aef48..bf6d50333c99a 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3323,6 +3323,11 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
auto *ResourceTy =
TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
QualType ContainedTy = ResourceTy->getContainedType();
+ // byteaddressbuffer load attempt
+ // if (ResourceTy->getAttrs().RawBuffer && ContainedTy->isChar8Type()) {
+ // ContainedTy =
+ // dyn_cast<FunctionDecl>(SemaRef.CurContext)->getReturnType();
+ // }
auto ReturnType =
SemaRef.Context.getAddrSpaceQualType(ContainedTy, LangAS::hlsl_device);
ReturnType = SemaRef.Context.getPointerType(ReturnType);
@@ -3344,6 +3349,11 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
auto *ResourceTy =
TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
QualType ReturnType = ResourceTy->getContainedType();
+ // ByteAddressBuffer returns FunctionDecl return type instead of contained
+ // type
+ if (ResourceTy->getAttrs().RawBuffer && ReturnType->isChar8Type()) {
+ ReturnType = dyn_cast<FunctionDecl>(SemaRef.CurContext)->getReturnType();
+ }
TheCall->setType(ReturnType);
break;
@@ -3360,22 +3370,7 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
break;
}
- case Builtin::BI__builtin_hlsl_byteaddressbuffer_load_with_status: {
- if (SemaRef.checkArgCount(TheCall, 3) ||
- CheckResourceHandle(&SemaRef, TheCall, 0) ||
- CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
- SemaRef.getASTContext().UnsignedIntTy) ||
- CheckArgTypeMatches(&SemaRef, TheCall->getArg(2),
- SemaRef.getASTContext().UnsignedIntTy) ||
- CheckModifiableLValue(&SemaRef, TheCall, 2))
- return true;
-
- auto *FD = dyn_cast<FunctionDecl>(SemaRef.CurContext);
- TheCall->setType(FD->getReturnType());
-
- break;
- }
- case Builtin::BI__builtin_hlsl_byteaddressbuffer_store: {
+ case Builtin::BI__builtin_hlsl_resource_store: {
if (SemaRef.checkArgCount(TheCall, 3) ||
CheckResourceHandle(&SemaRef, TheCall, 0) ||
CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
diff --git a/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl b/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
index 8be0379a76029..3a6d08b20e43c 100644
--- a/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
+++ b/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
@@ -155,7 +155,7 @@ RESOURCE Buffer;
// Load methods
// CHECK-LOAD: CXXMethodDecl {{.*}} Load 'unsigned int (unsigned int)'
-// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} byteOffset 'unsigned int'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
// CHECK-LOAD-NEXT: CompoundStmt
// CHECK-LOAD-NEXT: ReturnStmt
// CHECK-LOAD-NEXT: CallExpr {{.*}} 'unsigned int'
@@ -163,25 +163,25 @@ RESOURCE Buffer;
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_load' 'void (...) noexcept'
// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'byteOffset' 'unsigned int'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
// CHECK-LOAD: CXXMethodDecl {{.*}} Load 'unsigned int (unsigned int, out unsigned int)
-// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} byteOffset 'unsigned int'
-// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} status 'unsigned int &__restrict'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Status 'unsigned int &__restrict'
// CHECK-LOAD-NEXT: HLSLParamModifierAttr {{.*}} out
// CHECK-LOAD-NEXT: CompoundStmt
// CHECK-LOAD-NEXT: ReturnStmt
// CHECK-LOAD-NEXT: CallExpr {{.*}} 'unsigned int'
// CHECK-LOAD-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_load_with_status' 'void (...) noexcept'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_load_with_status' 'void (...) noexcept'
// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'byteOffset' 'unsigned int'
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'status' 'unsigned int &__restrict'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Status' 'unsigned int &__restrict'
// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
// CHECK-LOAD: CXXMethodDecl {{.*}} Load2 'vector<unsigned int (unsigned int), 2>'
-// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} byteOffset 'unsigned int'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
// CHECK-LOAD-NEXT: CompoundStmt
// CHECK-LOAD-NEXT: ReturnStmt
// CHECK-LOAD-NEXT: CallExpr {{.*}} 'vector<unsigned int, 2>'
@@ -189,25 +189,25 @@ RESOURCE Buffer;
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_load' 'void (...) noexcept'
// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'byteOffset' 'unsigned int'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
// CHECK-LOAD: CXXMethodDecl {{.*}} Load2 'vector<unsigned int (unsigned int, out unsigned int), 2>'
-// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} byteOffset 'unsigned int'
-// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} status 'unsigned int &__restrict'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Status 'unsigned int &__restrict'
// CHECK-LOAD-NEXT: HLSLParamModifierAttr {{.*}} out
// CHECK-LOAD-NEXT: CompoundStmt
// CHECK-LOAD-NEXT: ReturnStmt
// CHECK-LOAD-NEXT: CallExpr {{.*}} 'vector<unsigned int, 2>'
// CHECK-LOAD-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_load_with_status' 'void (...) noexcept'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_load_with_status' 'void (...) noexcept'
// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'byteOffset' 'unsigned int'
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'status' 'unsigned int &__restrict'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Status' 'unsigned int &__restrict'
// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
// CHECK-LOAD: CXXMethodDecl {{.*}} Load3 'vector<unsigned int (unsigned int), 3>'
-// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} byteOffset 'unsigned int'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
// CHECK-LOAD-NEXT: CompoundStmt
// CHECK-LOAD-NEXT: ReturnStmt
// CHECK-LOAD-NEXT: CallExpr {{.*}} 'vector<unsigned int, 3>'
@@ -215,25 +215,25 @@ RESOURCE Buffer;
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_load' 'void (...) noexcept'
// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'byteOffset' 'unsigned int'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
// CHECK-LOAD: CXXMethodDecl {{.*}} Load3 'vector<unsigned int (unsigned int, out unsigned int), 3>'
-// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} byteOffset 'unsigned int'
-// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} status 'unsigned int &__restrict'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Status 'unsigned int &__restrict'
// CHECK-LOAD-NEXT: HLSLParamModifierAttr {{.*}} out
// CHECK-LOAD-NEXT: CompoundStmt
// CHECK-LOAD-NEXT: ReturnStmt
// CHECK-LOAD-NEXT: CallExpr {{.*}} 'vector<unsigned int, 3>'
// CHECK-LOAD-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_load_with_status' 'void (...) noexcept'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_load_with_status' 'void (...) noexcept'
// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'byteOffset' 'unsigned int'
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'status' 'unsigned int &__restrict'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Status' 'unsigned int &__restrict'
// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
// CHECK-LOAD: CXXMethodDecl {{.*}} Load4 'vector<unsigned int (unsigned int), 4>'
-// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} byteOffset 'unsigned int'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
// CHECK-LOAD-NEXT: CompoundStmt
// CHECK-LOAD-NEXT: ReturnStmt
// CHECK-LOAD-NEXT: CallExpr {{.*}} 'vector<unsigned int, 4>'
@@ -241,25 +241,25 @@ RESOURCE Buffer;
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_load' 'void (...) noexcept'
// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'byteOffset' 'unsigned int'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
// CHECK-LOAD: CXXMethodDecl {{.*}} Load4 'vector<unsigned int (unsigned int, out unsigned int), 4>'
-// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} byteOffset 'unsigned int'
-// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} status 'unsigned int &__restrict'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Status 'unsigned int &__restrict'
// CHECK-LOAD-NEXT: HLSLParamModifierAttr {{.*}} out
// CHECK-LOAD-NEXT: CompoundStmt
// CHECK-LOAD-NEXT: ReturnStmt
// CHECK-LOAD-NEXT: CallExpr {{.*}} 'vector<unsigned int, 4>'
// CHECK-LOAD-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_load_with_status' 'void (...) noexcept'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_load_with_status' 'void (...) noexcept'
// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'byteOffset' 'unsigned int'
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'status' 'unsigned int &__restrict'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Status' 'unsigned int &__restrict'
// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
// CHECK-LOAD: CXXMethodDecl {{.*}} Load 'element_type (unsigned int)'
-// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} byteOffset 'unsigned int'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
// CHECK-LOAD-NEXT: CompoundStmt
// CHECK-LOAD-NEXT: ReturnStmt
// CHECK-LOAD-NEXT: CallExpr {{.*}} 'element_type'
@@ -267,87 +267,87 @@ RESOURCE Buffer;
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_load' 'void (...) noexcept'
// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'byteOffset' 'unsigned int'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
// CHECK-LOAD: CXXMethodDecl {{.*}} Load 'element_type (unsigned int, out unsigned int)
-// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} byteOffset 'unsigned int'
-// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} status 'unsigned int &__restrict'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Status 'unsigned int &__restrict'
// CHECK-LOAD-NEXT: HLSLParamModifierAttr {{.*}} out
// CHECK-LOAD-NEXT: CompoundStmt
// CHECK-LOAD-NEXT: ReturnStmt
// CHECK-LOAD-NEXT: CallExpr {{.*}} 'element_type'
// CHECK-LOAD-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_load_with_status' 'void (...) noexcept'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_load_with_status' 'void (...) noexcept'
// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'byteOffset' 'unsigned int'
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'status' 'unsigned int &__restrict'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Status' 'unsigned int &__restrict'
// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
// Store method
// CHECK-STORE: CXXMethodDecl {{.*}} Store 'void (unsigned int, unsigned int)'
-// CHECK-STORE-NEXT: ParmVarDecl {{.*}} byteOffset 'unsigned int'
-// CHECK-STORE-NEXT: ParmVarDecl {{.*}} value 'unsigned int'
+// CHECK-STORE-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
+// CHECK-STORE-NEXT: ParmVarDecl {{.*}} Value 'unsigned int'
// CHECK-STORE-NEXT: CompoundStmt
// CHECK-STORE-NEXT: CallExpr {{.*}} 'void'
// CHECK-STORE-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
-// CHECK-STORE-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_store' 'void (...) noexcept'
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_store' 'void (...) noexcept'
// CHECK-STORE-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-STORE-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
-// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'byteOffset' 'unsigned int'
-// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'value' 'unsigned int'
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Value' 'unsigned int'
// CHECK-STORE-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
// CHECK-STORE: CXXMethodDecl {{.*}} Store2 'void (unsigned int, vector<unsigned int, 2>)'
-// CHECK-STORE-NEXT: ParmVarDecl {{.*}} byteOffset 'unsigned int'
-// CHECK-STORE-NEXT: ParmVarDecl {{.*}} value 'vector<unsigned int, 2>'
+// CHECK-STORE-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
+// CHECK-STORE-NEXT: ParmVarDecl {{.*}} Value 'vector<unsigned int, 2>'
// CHECK-STORE-NEXT: CompoundStmt
// CHECK-STORE-NEXT: CallExpr {{.*}} 'void'
// CHECK-STORE-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
-// CHECK-STORE-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_store' 'void (...) noexcept'
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_store' 'void (...) noexcept'
// CHECK-STORE-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-STORE-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
-// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'byteOffset' 'unsigned int'
-// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'vector<unsigned int, 2>' ParmVar {{.*}} 'value' 'vector<unsigned int, 2>'
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'vector<unsigned int, 2>' ParmVar {{.*}} 'Value' 'vector<unsigned int, 2>'
// CHECK-STORE-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
// CHECK-STORE: CXXMethodDecl {{.*}} Store3 'void (unsigned int, vector<unsigned int, 3>)'
-// CHECK-STORE-NEXT: ParmVarDecl {{.*}} byteOffset 'unsigned int'
-// CHECK-STORE-NEXT: ParmVarDecl {{.*}} value 'vector<unsigned int, 3>'
+// CHECK-STORE-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
+// CHECK-STORE-NEXT: ParmVarDecl {{.*}} Value 'vector<unsigned int, 3>'
// CHECK-STORE-NEXT: CompoundStmt
// CHECK-STORE-NEXT: CallExpr {{.*}} 'void'
// CHECK-STORE-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
-// CHECK-STORE-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_store' 'void (...) noexcept'
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_store' 'void (...) noexcept'
// CHECK-STORE-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-STORE-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
-// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'byteOffset' 'unsigned int'
-// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'vector<unsigned int, 3>' ParmVar {{.*}} 'value' 'vector<unsigned int, 3>'
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'vector<unsigned int, 3>' ParmVar {{.*}} 'Value' 'vector<unsigned int, 3>'
// CHECK-STORE-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
// CHECK-STORE: CXXMethodDecl {{.*}} Store4 'void (unsigned int, vector<unsigned int, 4>)'
-// CHECK-STORE-NEXT: ParmVarDecl {{.*}} byteOffset 'unsigned int'
-// CHECK-STORE-NEXT: ParmVarDecl {{.*}} value 'vector<unsigned int, 4>'
+// CHECK-STORE-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
+// CHECK-STORE-NEXT: ParmVarDecl {{.*}} Value 'vector<unsigned int, 4>'
// CHECK-STORE-NEXT: CompoundStmt
// CHECK-STORE-NEXT: CallExpr {{.*}} 'void'
// CHECK-STORE-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
-// CHECK-STORE-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_store' 'void (...) noexcept'
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_store' 'void (...) noexcept'
// CHECK-STORE-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-STORE-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
-// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'byteOffset' 'unsigned int'
-// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'vector<unsigned int, 4>' ParmVar {{.*}} 'value' 'vector<unsigned int, 4>'
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'vector<unsigned int, 4>' ParmVar {{.*}} 'Value' 'vector<unsigned int, 4>'
// CHECK-STORE-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
// CHECK-STORE: CXXMethodDecl {{.*}} Store 'void (unsigned int, element_type)'
-// CHECK-STORE-NEXT: ParmVarDecl {{.*}} byteOffset 'unsigned int'
-// CHECK-STORE-NEXT: ParmVarDecl {{.*}} value 'element_type'
+// CHECK-STORE-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
+// CHECK-STORE-NEXT: ParmVarDecl {{.*}} Value 'element_type'
// CHECK-STORE-NEXT: CompoundStmt
// CHECK-STORE-NEXT: CallExpr {{.*}} 'void'
// CHECK-STORE-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
-// CHECK-STORE-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_store' 'void (...) noexcept'
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_store' 'void (...) noexcept'
// CHECK-STORE-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-STORE-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
-// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'byteOffset' 'unsigned int'
-// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'element_type' ParmVar {{.*}} 'value' 'element_type'
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'element_type' ParmVar {{.*}} 'Value' 'element_type'
// CHECK-STORE-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
// GetDimensions method
>From b0c5ddd62278116559fbc72cd657c15597765ccd Mon Sep 17 00:00:00 2001
From: kmpeng <kaitlinpeng at microsoft.com>
Date: Fri, 19 Dec 2025 15:45:45 -0800
Subject: [PATCH 04/12] change load builtin, bugs with vector uint loads
---
clang/include/clang/Basic/Builtins.td | 6 ----
clang/lib/AST/ExprConstant.cpp | 5 +++
clang/lib/CodeGen/CGHLSLBuiltins.cpp | 19 ------------
clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 31 ++++++++-----------
clang/lib/Sema/SemaHLSL.cpp | 24 ++++----------
5 files changed, 24 insertions(+), 61 deletions(-)
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 86f931fa42ad6..4bd15d842cad0 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -5001,12 +5001,6 @@ def HLSLResourceLoadWithStatus : LangBuiltin<"HLSL_LANG"> {
let Prototype = "void(...)";
}
-def HLSLByteAddressBufferLoad : LangBuiltin<"HLSL_LANG"> {
- let Spellings = ["__builtin_hlsl_byteaddressbuffer_load"];
- let Attributes = [NoThrow];
- let Prototype = "void(...)";
-}
-
def HLSLResourceStore : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_resource_store"];
let Attributes = [NoThrow];
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 857688ed8039d..10743a6a82a0e 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -11974,6 +11974,11 @@ static std::optional<APValue> handleVectorUnaryOperator(ASTContext &Ctx,
bool VectorExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
Expr *SubExpr = E->getSubExpr();
+ // solution #2?
+ // auto Pointee = SubExpr->getType();
+ // if (const auto *PT = SubExpr->getType()->getAs<clang::PointerType>())
+ // Pointee = PT->getPointeeType();
+ // const auto *VD = Pointee->castAs<VectorType>();
const auto *VD = SubExpr->getType()->castAs<VectorType>();
// This result element type differs in the case of negating a floating point
// vector, since the result type is the a vector of the equivilant sized
diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
index 392d64a435926..238b93ebe8ff0 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -489,10 +489,6 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
Value *IndexOp = EmitScalarExpr(E->getArg(1));
llvm::Type *RetTy = ConvertType(E->getType());
- // byteaddressbufferload attempt
- // tried replacing last parameter with a SmallVector<Value *> Args like
- // load_with_status where the last arg is poison but that broke every
- // intrinsic that uses this builtin
return Builder.CreateIntrinsic(
RetTy, CGM.getHLSLRuntime().getCreateResourceGetPointerIntrinsic(),
ArrayRef<Value *>{HandleOp, IndexOp});
@@ -543,21 +539,6 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
return LoadedValue;
}
- case Builtin::BI__builtin_hlsl_byteaddressbuffer_load: {
- Value *HandleOp = EmitScalarExpr(E->getArg(0));
- Value *IndexOp = EmitScalarExpr(E->getArg(1));
- Value *Offset = llvm::PoisonValue::get(Builder.getInt32Ty());
-
- llvm::Type *DataTy = ConvertType(E->getType());
- llvm::Type *RetTy = llvm::StructType::get(Builder.getContext(),
- {DataTy, Builder.getInt1Ty()});
-
- SmallVector<Value *, 3> Args = {HandleOp, IndexOp, Offset};
-
- Value *ResRet = Builder.CreateIntrinsic(
- RetTy, Intrinsic::dx_resource_load_rawbuffer, Args);
- return Builder.CreateExtractValue(ResRet, {0}, "ld.value");
- }
case Builtin::BI__builtin_hlsl_resource_store: {
Value *HandleOp = EmitScalarExpr(E->getArg(0));
Value *IndexOp = EmitScalarExpr(E->getArg(1));
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index 2a1ae0dc1bf01..d012beeb2fc17 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -647,7 +647,8 @@ BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::dereference(T Ptr) {
Expr *Deref =
UnaryOperator::Create(DeclBuilder.SemaRef.getASTContext(), PtrExpr,
UO_Deref, PtrExpr->getType()->getPointeeType(),
- VK_PRValue, OK_Ordinary, SourceLocation(),
+ /*solution #1? use VK_LValue instead*/ VK_PRValue,
+ OK_Ordinary, SourceLocation(),
/*CanOverflow=*/false, FPOptionsOverride());
StmtsList.push_back(Deref);
return *this;
@@ -1215,10 +1216,14 @@ BuiltinTypeDeclBuilder::addByteAddressBufferLoadMethods() {
DeclarationName Load(&II);
// Load without status
+ QualType AddrSpaceElemTy =
+ AST.getAddrSpaceQualType(ReturnType, LangAS::hlsl_device);
+ QualType ElemPtrTy = AST.getPointerType(AddrSpaceElemTy);
BuiltinTypeMethodBuilder(*this, Load, ReturnType, /*IsConst=*/false)
.addParam("Index", AST.UnsignedIntTy)
- .callBuiltin("__builtin_hlsl_byteaddressbuffer_load", ReturnType,
+ .callBuiltin("__builtin_hlsl_resource_getpointer", ElemPtrTy,
PH::Handle, PH::_0)
+ .dereference(PH::LastStmt)
.finalize();
// Load with status
@@ -1244,25 +1249,15 @@ BuiltinTypeDeclBuilder::addByteAddressBufferLoadMethods() {
/*IsConst=*/false);
QualType ReturnType = MMB.addTemplateTypeParam("element_type");
MMB.ReturnTy = ReturnType; // Update return type to template parameter
+ QualType AddrSpaceElemTy =
+ AST.getAddrSpaceQualType(ReturnType, LangAS::hlsl_device);
+ QualType ElemPtrTy = AST.getPointerType(AddrSpaceElemTy);
MMB.addParam("Index", AST.UnsignedIntTy)
- .callBuiltin("__builtin_hlsl_byteaddressbuffer_load", ReturnType,
- PH::Handle, PH::_0)
+ .callBuiltin("__builtin_hlsl_resource_getpointer", ElemPtrTy, PH::Handle,
+ PH::_0)
+ .dereference(PH::LastStmt)
.finalize();
- // __builtin_hlsl_resource_getpointer attempt
- // BuiltinTypeMethodBuilder MMB(*this, Load, AST.UnsignedIntTy,
- // /*IsConst=*/false);
- // QualType ReturnType = MMB.addTemplateTypeParam("element_type");
- // MMB.ReturnTy = ReturnType; // Update return type to template parameter
- // QualType AddrSpaceElemTy =
- // AST.getAddrSpaceQualType(ReturnType, LangAS::hlsl_device);
- // QualType ElemPtrTy = AST.getPointerType(AddrSpaceElemTy);
- // MMB.addParam("Index", AST.UnsignedIntTy)
- // .callBuiltin("__builtin_hlsl_resource_getpointer", ElemPtrTy,
- // PH::Handle, PH::_0)
- // .dereference(PH::LastStmt)
- // .finalize();
-
// Templated Load with status method
BuiltinTypeMethodBuilder MMB2(*this, Load, AST.UnsignedIntTy,
/*IsConst=*/false);
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index bf6d50333c99a..ebc3806121ae6 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3323,11 +3323,11 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
auto *ResourceTy =
TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
QualType ContainedTy = ResourceTy->getContainedType();
- // byteaddressbuffer load attempt
- // if (ResourceTy->getAttrs().RawBuffer && ContainedTy->isChar8Type()) {
- // ContainedTy =
- // dyn_cast<FunctionDecl>(SemaRef.CurContext)->getReturnType();
- // }
+ // ByteAddressBuffer uses FunctionDecl return type instead of contained
+ // type
+ if (ResourceTy->getAttrs().RawBuffer && ContainedTy->isChar8Type()) {
+ ContainedTy = dyn_cast<FunctionDecl>(SemaRef.CurContext)->getReturnType();
+ }
auto ReturnType =
SemaRef.Context.getAddrSpaceQualType(ContainedTy, LangAS::hlsl_device);
ReturnType = SemaRef.Context.getPointerType(ReturnType);
@@ -3349,7 +3349,7 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
auto *ResourceTy =
TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
QualType ReturnType = ResourceTy->getContainedType();
- // ByteAddressBuffer returns FunctionDecl return type instead of contained
+ // ByteAddressBuffer uses FunctionDecl return type instead of contained
// type
if (ResourceTy->getAttrs().RawBuffer && ReturnType->isChar8Type()) {
ReturnType = dyn_cast<FunctionDecl>(SemaRef.CurContext)->getReturnType();
@@ -3358,18 +3358,6 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
break;
}
- case Builtin::BI__builtin_hlsl_byteaddressbuffer_load: {
- if (SemaRef.checkArgCount(TheCall, 2) ||
- CheckResourceHandle(&SemaRef, TheCall, 0) ||
- CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
- SemaRef.getASTContext().UnsignedIntTy))
- return true;
-
- auto *FD = dyn_cast<FunctionDecl>(SemaRef.CurContext);
- TheCall->setType(FD->getReturnType());
-
- break;
- }
case Builtin::BI__builtin_hlsl_resource_store: {
if (SemaRef.checkArgCount(TheCall, 3) ||
CheckResourceHandle(&SemaRef, TheCall, 0) ||
>From 671cee734bab16977edf0f6c570428b93048077a Mon Sep 17 00:00:00 2001
From: kmpeng <kaitlinpeng at microsoft.com>
Date: Tue, 23 Dec 2025 15:17:25 -0800
Subject: [PATCH 05/12] fix load bugs, change store to use
__builtin_hlsl_resource_getpointer, bugs with templated store
---
clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 21 +++++++++++++------
.../test/AST/HLSL/StructuredBuffers-AST.hlsl | 10 ++++-----
clang/test/AST/HLSL/TypedBuffers-AST.hlsl | 6 +++---
3 files changed, 23 insertions(+), 14 deletions(-)
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index d012beeb2fc17..cc9e458cdf5de 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -647,8 +647,7 @@ BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::dereference(T Ptr) {
Expr *Deref =
UnaryOperator::Create(DeclBuilder.SemaRef.getASTContext(), PtrExpr,
UO_Deref, PtrExpr->getType()->getPointeeType(),
- /*solution #1? use VK_LValue instead*/ VK_PRValue,
- OK_Ordinary, SourceLocation(),
+ VK_LValue, OK_Ordinary, SourceLocation(),
/*CanOverflow=*/false, FPOptionsOverride());
StmtsList.push_back(Deref);
return *this;
@@ -1284,11 +1283,16 @@ BuiltinTypeDeclBuilder::addByteAddressBufferStoreMethods() {
IdentifierInfo &II = AST.Idents.get(MethodName, tok::TokenKind::identifier);
DeclarationName Store(&II);
+ QualType AddrSpaceElemTy =
+ AST.getAddrSpaceQualType(ValueType, LangAS::hlsl_device);
+ QualType ElemPtrTy = AST.getPointerType(AddrSpaceElemTy);
BuiltinTypeMethodBuilder(*this, Store, AST.VoidTy, /*IsConst=*/false)
.addParam("Index", AST.UnsignedIntTy)
.addParam("Value", ValueType)
- .callBuiltin("__builtin_hlsl_resource_store", AST.VoidTy, PH::Handle,
- PH::_0, PH::_1)
+ .callBuiltin("__builtin_hlsl_resource_getpointer", ElemPtrTy,
+ PH::Handle, PH::_0)
+ .dereference(PH::LastStmt)
+ .assign(PH::LastStmt, PH::_1)
.finalize();
};
@@ -1303,10 +1307,15 @@ BuiltinTypeDeclBuilder::addByteAddressBufferStoreMethods() {
BuiltinTypeMethodBuilder Builder(*this, Store, AST.VoidTy, /*IsConst=*/false);
QualType ValueType = Builder.addTemplateTypeParam("element_type");
+ QualType AddrSpaceElemTy =
+ AST.getAddrSpaceQualType(ValueType, LangAS::hlsl_device);
+ QualType ElemPtrTy = AST.getPointerType(AddrSpaceElemTy);
Builder.addParam("Index", AST.UnsignedIntTy)
.addParam("Value", ValueType)
- .callBuiltin("__builtin_hlsl_resource_store", AST.VoidTy, PH::Handle,
- PH::_0, PH::_1)
+ .callBuiltin("__builtin_hlsl_resource_getpointer", ElemPtrTy, PH::Handle,
+ PH::_0)
+ .dereference(PH::LastStmt)
+ .assign(PH::LastStmt, PH::_1)
.finalize();
return *this;
diff --git a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl
index 2bcca4854b136..c6411ccf77075 100644
--- a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl
+++ b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl
@@ -275,7 +275,7 @@ RESOURCE<float> Buffer;
// CHECK-SUBSCRIPT-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
// CHECK-SUBSCRIPT-NEXT: CompoundStmt
// CHECK-SUBSCRIPT-NEXT: ReturnStmt
-// CHECK-SUBSCRIPT-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' prefix '*' cannot overflow
+// CHECK-SUBSCRIPT-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' lvalue prefix '*' cannot overflow
// CHECK-SUBSCRIPT-NEXT: CStyleCastExpr {{.*}} 'hlsl_device element_type *'
// CHECK-SUBSCRIPT-NEXT: CallExpr
// CHECK-SUBSCRIPT-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
@@ -292,7 +292,7 @@ RESOURCE<float> Buffer;
// CHECK-SUBSCRIPT-UAV-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
// CHECK-SUBSCRIPT-UAV-NEXT: CompoundStmt
// CHECK-SUBSCRIPT-UAV-NEXT: ReturnStmt
-// CHECK-SUBSCRIPT-UAV-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' prefix '*' cannot overflow
+// CHECK-SUBSCRIPT-UAV-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' lvalue prefix '*' cannot overflow
// CHECK-SUBSCRIPT-UAV-NEXT: CStyleCastExpr {{.*}} 'hlsl_device element_type *'
// CHECK-SUBSCRIPT-UAV-NEXT: CallExpr
// CHECK-SUBSCRIPT-UAV-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
@@ -314,7 +314,7 @@ RESOURCE<float> Buffer;
// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
// CHECK-LOAD-NEXT: CompoundStmt
// CHECK-LOAD-NEXT: ReturnStmt
-// CHECK-LOAD-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' prefix '*' cannot overflow
+// CHECK-LOAD-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' lvalue prefix '*' cannot overflow
// CHECK-LOAD-NEXT: CStyleCastExpr {{.*}} 'hlsl_device element_type *'
// CHECK-LOAD-NEXT: CallExpr
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
@@ -384,7 +384,7 @@ RESOURCE<float> Buffer;
// CHECK-APPEND-NEXT: ParmVarDecl {{.*}} value 'element_type'
// CHECK-APPEND-NEXT: CompoundStmt
// CHECK-APPEND-NEXT: BinaryOperator {{.*}} 'hlsl_device element_type' '='
-// CHECK-APPEND-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' prefix '*' cannot overflow
+// CHECK-APPEND-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' lvalue prefix '*' cannot overflow
// CHECK-APPEND-NEXT: CStyleCastExpr {{.*}} 'hlsl_device element_type *'
// CHECK-APPEND-NEXT: CallExpr
// CHECK-APPEND-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
@@ -409,7 +409,7 @@ RESOURCE<float> Buffer;
// CHECK-CONSUME: CXXMethodDecl {{.*}} Consume 'element_type ()'
// CHECK-CONSUME-NEXT: CompoundStmt
// CHECK-CONSUME-NEXT: ReturnStmt
-// CHECK-CONSUME-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' prefix '*' cannot overflow
+// CHECK-CONSUME-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' lvalue prefix '*' cannot overflow
// CHECK-CONSUME-NEXT: CStyleCastExpr {{.*}} 'hlsl_device element_type *'
// CHECK-CONSUME-NEXT: CallExpr
// CHECK-CONSUME-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
diff --git a/clang/test/AST/HLSL/TypedBuffers-AST.hlsl b/clang/test/AST/HLSL/TypedBuffers-AST.hlsl
index eb53ad5e9fd0e..c2144d230887b 100644
--- a/clang/test/AST/HLSL/TypedBuffers-AST.hlsl
+++ b/clang/test/AST/HLSL/TypedBuffers-AST.hlsl
@@ -166,7 +166,7 @@ RESOURCE<float> Buffer;
// CHECK-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
// CHECK-NEXT: CompoundStmt
// CHECK-NEXT: ReturnStmt
-// CHECK-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' prefix '*' cannot overflow
+// CHECK-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' lvalue prefix '*' cannot overflow
// CHECK-NEXT: CStyleCastExpr {{.*}} 'hlsl_device element_type *'
// CHECK-NEXT: CallExpr
// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
@@ -183,7 +183,7 @@ RESOURCE<float> Buffer;
// CHECK-UAV-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
// CHECK-UAV-NEXT: CompoundStmt
// CHECK-UAV-NEXT: ReturnStmt
-// CHECK-UAV-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' prefix '*' cannot overflow
+// CHECK-UAV-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' lvalue prefix '*' cannot overflow
// CHECK-UAV-NEXT: CStyleCastExpr {{.*}} 'hlsl_device element_type *'
// CHECK-UAV-NEXT: CallExpr
// CHECK-UAV-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
@@ -201,7 +201,7 @@ RESOURCE<float> Buffer;
// CHECK-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
// CHECK-NEXT: CompoundStmt
// CHECK-NEXT: ReturnStmt
-// CHECK-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' prefix '*' cannot overflow
+// CHECK-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' lvalue prefix '*' cannot overflow
// CHECK-NEXT: CStyleCastExpr {{.*}} 'hlsl_device element_type *'
// CHECK-NEXT: CallExpr
// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
>From d88f2e9e13ca69fd544286aca494f70f214ce4ee Mon Sep 17 00:00:00 2001
From: kmpeng <kaitlinpeng at microsoft.com>
Date: Wed, 14 Jan 2026 01:01:18 -0800
Subject: [PATCH 06/12] fix templated store
---
clang/include/clang/Basic/Builtins.td | 6 --
clang/lib/AST/ExprConstant.cpp | 5 --
clang/lib/CodeGen/CGHLSLBuiltins.cpp | 31 -----------
clang/lib/Sema/SemaHLSL.cpp | 33 +++++------
.../test/AST/HLSL/ByteAddressBuffers-AST.hlsl | 55 ++++++++++++-------
5 files changed, 50 insertions(+), 80 deletions(-)
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 4bd15d842cad0..dcf07d659cb15 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -5001,12 +5001,6 @@ def HLSLResourceLoadWithStatus : LangBuiltin<"HLSL_LANG"> {
let Prototype = "void(...)";
}
-def HLSLResourceStore : LangBuiltin<"HLSL_LANG"> {
- let Spellings = ["__builtin_hlsl_resource_store"];
- let Attributes = [NoThrow];
- let Prototype = "void(...)";
-}
-
def HLSLResourceUninitializedHandle : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_resource_uninitializedhandle"];
let Attributes = [NoThrow];
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 10743a6a82a0e..857688ed8039d 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -11974,11 +11974,6 @@ static std::optional<APValue> handleVectorUnaryOperator(ASTContext &Ctx,
bool VectorExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
Expr *SubExpr = E->getSubExpr();
- // solution #2?
- // auto Pointee = SubExpr->getType();
- // if (const auto *PT = SubExpr->getType()->getAs<clang::PointerType>())
- // Pointee = PT->getPointeeType();
- // const auto *VD = Pointee->castAs<VectorType>();
const auto *VD = SubExpr->getType()->castAs<VectorType>();
// This result element type differs in the case of negating a floating point
// vector, since the result type is the a vector of the equivilant sized
diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
index 238b93ebe8ff0..532fe0673423e 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -539,37 +539,6 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
return LoadedValue;
}
- case Builtin::BI__builtin_hlsl_resource_store: {
- Value *HandleOp = EmitScalarExpr(E->getArg(0));
- Value *IndexOp = EmitScalarExpr(E->getArg(1));
- RValue RVal = EmitAnyExpr(E->getArg(2));
- Value *ValueOp =
- RVal.isScalar()
- ? RVal.getScalarVal()
- : Builder.CreateLoad(RVal.getAggregateAddress(), "store_val");
-
- QualType HandleTy = E->getArg(0)->getType();
- const HLSLAttributedResourceType *RT =
- HandleTy->getAs<HLSLAttributedResourceType>();
- Intrinsic::ID IntrID = RT->getAttrs().RawBuffer
- ? llvm::Intrinsic::dx_resource_store_rawbuffer
- : llvm::Intrinsic::dx_resource_store_typedbuffer;
-
- SmallVector<Value *, 4> Args;
- Args.push_back(HandleOp);
- Args.push_back(IndexOp);
- if (RT->getAttrs().RawBuffer) {
- Value *Offset = Builder.getInt32(0);
- // Offset is poison for ByteAddressBuffer
- if (RT->getContainedType()->isChar8Type())
- Offset = llvm::PoisonValue::get(Builder.getInt32Ty());
- Args.push_back(Offset);
- }
- Args.push_back(ValueOp);
-
- return Builder.CreateIntrinsic(
- IntrID, {HandleOp->getType(), ValueOp->getType()}, Args);
- }
case Builtin::BI__builtin_hlsl_resource_uninitializedhandle: {
llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType());
return llvm::PoisonValue::get(HandleTy);
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index ebc3806121ae6..805008f1670a2 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3322,14 +3322,22 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
auto *ResourceTy =
TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
- QualType ContainedTy = ResourceTy->getContainedType();
- // ByteAddressBuffer uses FunctionDecl return type instead of contained
+ QualType ElementTy = ResourceTy->getContainedType();
+ // ByteAddressBuffer uses the FunctionDecl types instead of the contained
// type
- if (ResourceTy->getAttrs().RawBuffer && ContainedTy->isChar8Type()) {
- ContainedTy = dyn_cast<FunctionDecl>(SemaRef.CurContext)->getReturnType();
+ if (ResourceTy->getAttrs().RawBuffer && ElementTy->isChar8Type()) {
+ // Load method uses return type
+ FunctionDecl *FD = dyn_cast<FunctionDecl>(SemaRef.CurContext);
+ ElementTy = FD->getReturnType();
+ // Store method uses 2nd parameter type
+ if (ElementTy->isVoidType()) {
+ assert(FD->getNumParams() == 2 &&
+ "expected 2 parameters for Store method");
+ ElementTy = FD->getParamDecl(1)->getType();
+ }
}
auto ReturnType =
- SemaRef.Context.getAddrSpaceQualType(ContainedTy, LangAS::hlsl_device);
+ SemaRef.Context.getAddrSpaceQualType(ElementTy, LangAS::hlsl_device);
ReturnType = SemaRef.Context.getPointerType(ReturnType);
TheCall->setType(ReturnType);
TheCall->setValueKind(VK_LValue);
@@ -3349,8 +3357,8 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
auto *ResourceTy =
TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
QualType ReturnType = ResourceTy->getContainedType();
- // ByteAddressBuffer uses FunctionDecl return type instead of contained
- // type
+ // ByteAddressBuffer uses the FunctionDecl return type instead of the
+ // contained type
if (ResourceTy->getAttrs().RawBuffer && ReturnType->isChar8Type()) {
ReturnType = dyn_cast<FunctionDecl>(SemaRef.CurContext)->getReturnType();
}
@@ -3358,18 +3366,7 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
break;
}
- case Builtin::BI__builtin_hlsl_resource_store: {
- if (SemaRef.checkArgCount(TheCall, 3) ||
- CheckResourceHandle(&SemaRef, TheCall, 0) ||
- CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
- SemaRef.getASTContext().UnsignedIntTy))
- return true;
-
- // need to check anything for the 2nd parameter? not an array?
- TheCall->setType(SemaRef.Context.VoidTy);
- break;
- }
case Builtin::BI__builtin_hlsl_resource_uninitializedhandle: {
assert(TheCall->getNumArgs() == 1 && "expected 1 arg");
// Update return type to be the attributed resource type from arg0.
diff --git a/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl b/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
index 3a6d08b20e43c..aee1e0d8cda34 100644
--- a/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
+++ b/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
@@ -158,9 +158,10 @@ RESOURCE Buffer;
// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
// CHECK-LOAD-NEXT: CompoundStmt
// CHECK-LOAD-NEXT: ReturnStmt
-// CHECK-LOAD-NEXT: CallExpr {{.*}} 'unsigned int'
+// CHECK-LOAD-NEXT: UnaryOperator {{.*}} 'hlsl_device unsigned int' lvalue prefix '*' cannot overflow
+// CHECK-LOAD-NEXT: CallExpr {{.*}} 'hlsl_device unsigned int *'
// CHECK-LOAD-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_load' 'void (...) noexcept'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
@@ -184,9 +185,10 @@ RESOURCE Buffer;
// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
// CHECK-LOAD-NEXT: CompoundStmt
// CHECK-LOAD-NEXT: ReturnStmt
-// CHECK-LOAD-NEXT: CallExpr {{.*}} 'vector<unsigned int, 2>'
+// CHECK-LOAD-NEXT: UnaryOperator {{.*}} 'vector<unsigned int hlsl_device, 2>' lvalue prefix '*' cannot overflow
+// CHECK-LOAD-NEXT: CallExpr {{.*}} 'vector<unsigned int hlsl_device *, 2>'
// CHECK-LOAD-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_load' 'void (...) noexcept'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
@@ -210,9 +212,10 @@ RESOURCE Buffer;
// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
// CHECK-LOAD-NEXT: CompoundStmt
// CHECK-LOAD-NEXT: ReturnStmt
-// CHECK-LOAD-NEXT: CallExpr {{.*}} 'vector<unsigned int, 3>'
+// CHECK-LOAD-NEXT: UnaryOperator {{.*}} 'vector<unsigned int hlsl_device, 3>' lvalue prefix '*' cannot overflow
+// CHECK-LOAD-NEXT: CallExpr {{.*}} 'vector<unsigned int hlsl_device *, 3>'
// CHECK-LOAD-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_load' 'void (...) noexcept'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
@@ -236,9 +239,10 @@ RESOURCE Buffer;
// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
// CHECK-LOAD-NEXT: CompoundStmt
// CHECK-LOAD-NEXT: ReturnStmt
-// CHECK-LOAD-NEXT: CallExpr {{.*}} 'vector<unsigned int, 4>'
+// CHECK-LOAD-NEXT: UnaryOperator {{.*}} 'vector<unsigned int hlsl_device, 4>' lvalue prefix '*' cannot overflow
+// CHECK-LOAD-NEXT: CallExpr {{.*}} 'vector<unsigned int hlsl_device *, 4>'
// CHECK-LOAD-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_load' 'void (...) noexcept'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
@@ -262,9 +266,10 @@ RESOURCE Buffer;
// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
// CHECK-LOAD-NEXT: CompoundStmt
// CHECK-LOAD-NEXT: ReturnStmt
-// CHECK-LOAD-NEXT: CallExpr {{.*}} 'element_type'
+// CHECK-LOAD-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' lvalue prefix '*' cannot overflow
+// CHECK-LOAD-NEXT: CallExpr {{.*}} 'hlsl_device element_type *'
// CHECK-LOAD-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_byteaddressbuffer_load' 'void (...) noexcept'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
@@ -289,9 +294,11 @@ RESOURCE Buffer;
// CHECK-STORE-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
// CHECK-STORE-NEXT: ParmVarDecl {{.*}} Value 'unsigned int'
// CHECK-STORE-NEXT: CompoundStmt
-// CHECK-STORE-NEXT: CallExpr {{.*}} 'void'
+// CHECK-STORE-NEXT: BinaryOperator {{.*}} 'hlsl_device unsigned int' '='
+// CHECK-STORE-NEXT: UnaryOperator {{.*}} 'hlsl_device unsigned int' lvalue prefix '*' cannot overflow
+// CHECK-STORE-NEXT: CallExpr {{.*}} 'hlsl_device unsigned int *'
// CHECK-STORE-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
-// CHECK-STORE-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_store' 'void (...) noexcept'
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
// CHECK-STORE-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-STORE-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
@@ -302,9 +309,11 @@ RESOURCE Buffer;
// CHECK-STORE-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
// CHECK-STORE-NEXT: ParmVarDecl {{.*}} Value 'vector<unsigned int, 2>'
// CHECK-STORE-NEXT: CompoundStmt
-// CHECK-STORE-NEXT: CallExpr {{.*}} 'void'
+// CHECK-STORE-NEXT: BinaryOperator {{.*}} 'vector<unsigned int hlsl_device, 2>' '='
+// CHECK-STORE-NEXT: UnaryOperator {{.*}} 'vector<unsigned int hlsl_device, 2>' lvalue prefix '*' cannot overflow
+// CHECK-STORE-NEXT: CallExpr {{.*}} 'vector<unsigned int hlsl_device *, 2>'
// CHECK-STORE-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
-// CHECK-STORE-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_store' 'void (...) noexcept'
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
// CHECK-STORE-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-STORE-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
@@ -315,9 +324,11 @@ RESOURCE Buffer;
// CHECK-STORE-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
// CHECK-STORE-NEXT: ParmVarDecl {{.*}} Value 'vector<unsigned int, 3>'
// CHECK-STORE-NEXT: CompoundStmt
-// CHECK-STORE-NEXT: CallExpr {{.*}} 'void'
+// CHECK-STORE-NEXT: BinaryOperator {{.*}} 'vector<unsigned int hlsl_device, 3>' '='
+// CHECK-STORE-NEXT: UnaryOperator {{.*}} 'vector<unsigned int hlsl_device, 3>' lvalue prefix '*' cannot overflow
+// CHECK-STORE-NEXT: CallExpr {{.*}} 'vector<unsigned int hlsl_device *, 3>'
// CHECK-STORE-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
-// CHECK-STORE-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_store' 'void (...) noexcept'
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
// CHECK-STORE-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-STORE-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
@@ -328,9 +339,11 @@ RESOURCE Buffer;
// CHECK-STORE-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
// CHECK-STORE-NEXT: ParmVarDecl {{.*}} Value 'vector<unsigned int, 4>'
// CHECK-STORE-NEXT: CompoundStmt
-// CHECK-STORE-NEXT: CallExpr {{.*}} 'void'
+// CHECK-STORE-NEXT: BinaryOperator {{.*}} 'vector<unsigned int hlsl_device, 4>' '='
+// CHECK-STORE-NEXT: UnaryOperator {{.*}} 'vector<unsigned int hlsl_device, 4>' lvalue prefix '*' cannot overflow
+// CHECK-STORE-NEXT: CallExpr {{.*}} 'vector<unsigned int hlsl_device *, 4>'
// CHECK-STORE-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
-// CHECK-STORE-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_store' 'void (...) noexcept'
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
// CHECK-STORE-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-STORE-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
@@ -341,9 +354,11 @@ RESOURCE Buffer;
// CHECK-STORE-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
// CHECK-STORE-NEXT: ParmVarDecl {{.*}} Value 'element_type'
// CHECK-STORE-NEXT: CompoundStmt
-// CHECK-STORE-NEXT: CallExpr {{.*}} 'void'
+// CHECK-STORE-NEXT: BinaryOperator {{.*}} 'hlsl_device element_type' '='
+// CHECK-STORE-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' lvalue prefix '*' cannot overflow
+// CHECK-STORE-NEXT: CallExpr {{.*}} 'hlsl_device element_type *'
// CHECK-STORE-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
-// CHECK-STORE-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_store' 'void (...) noexcept'
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
// CHECK-STORE-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-STORE-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
>From b2f8d7007255925a09ded347be5ecce66b3f8785 Mon Sep 17 00:00:00 2001
From: kmpeng <kaitlinpeng at microsoft.com>
Date: Wed, 14 Jan 2026 15:05:10 -0800
Subject: [PATCH 07/12] finish tests, clean up code
---
clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 87 +++------
.../resources/ByteAddressBuffers-methods.hlsl | 174 +++++++++++++++---
2 files changed, 171 insertions(+), 90 deletions(-)
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index cc9e458cdf5de..2e6798efcf0ae 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -191,9 +191,6 @@ struct BuiltinTypeMethodBuilder {
BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, StringRef NameStr,
QualType ReturnTy, bool IsConst = false,
bool IsCtor = false, StorageClass SC = SC_None);
-
- // converttype maybe? - qualtype or template parameter index
-
BuiltinTypeMethodBuilder(const BuiltinTypeMethodBuilder &Other) = delete;
~BuiltinTypeMethodBuilder() { finalize(); }
@@ -1209,25 +1206,33 @@ BuiltinTypeDeclBuilder::addByteAddressBufferLoadMethods() {
using PH = BuiltinTypeMethodBuilder::PlaceHolder;
ASTContext &AST = SemaRef.getASTContext();
- // Add uint Load methods
auto addLoadMethod = [&](StringRef MethodName, QualType ReturnType) {
IdentifierInfo &II = AST.Idents.get(MethodName, tok::TokenKind::identifier);
DeclarationName Load(&II);
// Load without status
+ BuiltinTypeMethodBuilder MMB(*this, Load, ReturnType);
+ if (ReturnType->isDependentType()) {
+ ReturnType = MMB.addTemplateTypeParam("element_type");
+ MMB.ReturnTy = ReturnType; // Update return type to template parameter
+ }
QualType AddrSpaceElemTy =
AST.getAddrSpaceQualType(ReturnType, LangAS::hlsl_device);
- QualType ElemPtrTy = AST.getPointerType(AddrSpaceElemTy);
- BuiltinTypeMethodBuilder(*this, Load, ReturnType, /*IsConst=*/false)
- .addParam("Index", AST.UnsignedIntTy)
- .callBuiltin("__builtin_hlsl_resource_getpointer", ElemPtrTy,
- PH::Handle, PH::_0)
+
+ MMB.addParam("Index", AST.UnsignedIntTy)
+ .callBuiltin("__builtin_hlsl_resource_getpointer",
+ AST.getPointerType(AddrSpaceElemTy), PH::Handle, PH::_0)
.dereference(PH::LastStmt)
.finalize();
// Load with status
- BuiltinTypeMethodBuilder(*this, Load, ReturnType, /*IsConst=*/false)
- .addParam("Index", AST.UnsignedIntTy)
+ BuiltinTypeMethodBuilder MMB2(*this, Load, ReturnType);
+ if (ReturnType->isDependentType()) {
+ ReturnType = MMB2.addTemplateTypeParam("element_type");
+ MMB2.ReturnTy = ReturnType; // Update return type to template parameter
+ }
+
+ MMB2.addParam("Index", AST.UnsignedIntTy)
.addParam("Status", AST.UnsignedIntTy,
HLSLParamModifierAttr::Keyword_out)
.callBuiltin("__builtin_hlsl_resource_load_with_status", ReturnType,
@@ -1239,34 +1244,7 @@ BuiltinTypeDeclBuilder::addByteAddressBufferLoadMethods() {
addLoadMethod("Load2", AST.getExtVectorType(AST.UnsignedIntTy, 2));
addLoadMethod("Load3", AST.getExtVectorType(AST.UnsignedIntTy, 3));
addLoadMethod("Load4", AST.getExtVectorType(AST.UnsignedIntTy, 4));
-
- // Templated Load method
- IdentifierInfo &II = AST.Idents.get("Load", tok::TokenKind::identifier);
- DeclarationName Load(&II);
-
- BuiltinTypeMethodBuilder MMB(*this, Load, AST.UnsignedIntTy,
- /*IsConst=*/false);
- QualType ReturnType = MMB.addTemplateTypeParam("element_type");
- MMB.ReturnTy = ReturnType; // Update return type to template parameter
- QualType AddrSpaceElemTy =
- AST.getAddrSpaceQualType(ReturnType, LangAS::hlsl_device);
- QualType ElemPtrTy = AST.getPointerType(AddrSpaceElemTy);
- MMB.addParam("Index", AST.UnsignedIntTy)
- .callBuiltin("__builtin_hlsl_resource_getpointer", ElemPtrTy, PH::Handle,
- PH::_0)
- .dereference(PH::LastStmt)
- .finalize();
-
- // Templated Load with status method
- BuiltinTypeMethodBuilder MMB2(*this, Load, AST.UnsignedIntTy,
- /*IsConst=*/false);
- QualType ReturnType2 = MMB2.addTemplateTypeParam("element_type");
- MMB2.ReturnTy = ReturnType2; // Update return type to template parameter
- MMB2.addParam("Index", AST.UnsignedIntTy)
- .addParam("Status", AST.UnsignedIntTy, HLSLParamModifierAttr::Keyword_out)
- .callBuiltin("__builtin_hlsl_resource_load_with_status", ReturnType2,
- PH::Handle, PH::_0, PH::_1)
- .finalize();
+ addLoadMethod("Load", AST.DependentTy); // Templated version
return *this;
}
@@ -1283,14 +1261,17 @@ BuiltinTypeDeclBuilder::addByteAddressBufferStoreMethods() {
IdentifierInfo &II = AST.Idents.get(MethodName, tok::TokenKind::identifier);
DeclarationName Store(&II);
+ BuiltinTypeMethodBuilder MMB(*this, Store, AST.VoidTy);
+ if (ValueType->isDependentType()) {
+ ValueType = MMB.addTemplateTypeParam("element_type");
+ }
QualType AddrSpaceElemTy =
AST.getAddrSpaceQualType(ValueType, LangAS::hlsl_device);
- QualType ElemPtrTy = AST.getPointerType(AddrSpaceElemTy);
- BuiltinTypeMethodBuilder(*this, Store, AST.VoidTy, /*IsConst=*/false)
- .addParam("Index", AST.UnsignedIntTy)
+
+ MMB.addParam("Index", AST.UnsignedIntTy)
.addParam("Value", ValueType)
- .callBuiltin("__builtin_hlsl_resource_getpointer", ElemPtrTy,
- PH::Handle, PH::_0)
+ .callBuiltin("__builtin_hlsl_resource_getpointer",
+ AST.getPointerType(AddrSpaceElemTy), PH::Handle, PH::_0)
.dereference(PH::LastStmt)
.assign(PH::LastStmt, PH::_1)
.finalize();
@@ -1300,23 +1281,7 @@ BuiltinTypeDeclBuilder::addByteAddressBufferStoreMethods() {
addStoreMethod("Store2", AST.getExtVectorType(AST.UnsignedIntTy, 2));
addStoreMethod("Store3", AST.getExtVectorType(AST.UnsignedIntTy, 3));
addStoreMethod("Store4", AST.getExtVectorType(AST.UnsignedIntTy, 4));
-
- // Templated Store method
- IdentifierInfo &II = AST.Idents.get("Store", tok::TokenKind::identifier);
- DeclarationName Store(&II);
-
- BuiltinTypeMethodBuilder Builder(*this, Store, AST.VoidTy, /*IsConst=*/false);
- QualType ValueType = Builder.addTemplateTypeParam("element_type");
- QualType AddrSpaceElemTy =
- AST.getAddrSpaceQualType(ValueType, LangAS::hlsl_device);
- QualType ElemPtrTy = AST.getPointerType(AddrSpaceElemTy);
- Builder.addParam("Index", AST.UnsignedIntTy)
- .addParam("Value", ValueType)
- .callBuiltin("__builtin_hlsl_resource_getpointer", ElemPtrTy, PH::Handle,
- PH::_0)
- .dereference(PH::LastStmt)
- .assign(PH::LastStmt, PH::_1)
- .finalize();
+ addStoreMethod("Store", AST.DependentTy); // Templated version
return *this;
}
diff --git a/clang/test/CodeGenHLSL/resources/ByteAddressBuffers-methods.hlsl b/clang/test/CodeGenHLSL/resources/ByteAddressBuffers-methods.hlsl
index ba6f059c6346b..af0fc75df6e89 100644
--- a/clang/test/CodeGenHLSL/resources/ByteAddressBuffers-methods.hlsl
+++ b/clang/test/CodeGenHLSL/resources/ByteAddressBuffers-methods.hlsl
@@ -3,11 +3,6 @@
// NOTE: SPIRV codegen for resource methods is not yet implemented
-struct SmallStruct {
- int a;
- uint b;
-};
-
ByteAddressBuffer Buf : register(t0);
RWByteAddressBuffer RWBuf : register(u0);
@@ -17,45 +12,166 @@ RWByteAddressBuffer RWBuf : register(u0);
// DXIL: @Buf = internal global %"class.hlsl::ByteAddressBuffer" poison
// DXIL: @RWBuf = internal global %"class.hlsl::RWByteAddressBuffer" poison
-export uint TestLoad() {
- uint u = Buf.Load(0);
- uint2 v = Buf.Load2(0);
- float f = Buf.Load<float>(4);
- float4 g = Buf.Load<float4>(8);
- SmallStruct U9 = Buf.Load<SmallStruct>(0);
- return u;
+export float TestLoad() {
+ return Buf.Load(0) + RWBuf.Load4(4).w + Buf.Load<float>(20) + RWBuf.Load<float4>(24).w;
}
-// CHECK: define {{.*}} i32 @TestLoad()()
+// CHECK: define {{.*}} float @TestLoad()()
// CHECK: call {{.*}} i32 @hlsl::ByteAddressBuffer::Load(unsigned int)(ptr {{.*}} @Buf, i32 noundef 0)
-// CHECK: ret i32
-
-export uint TestLoadWithStatus() {
- uint s1, s2, s3;
- uint u = Buf.Load(0, s1);
- float f = Buf.Load<float>(4, s2);
- SmallStruct U9 = Buf.Load<SmallStruct>(0, s3);
- return u;
+// CHECK: call {{.*}} <4 x i32> @hlsl::RWByteAddressBuffer::Load4(unsigned int)(ptr {{.*}} @RWBuf, i32 noundef 4)
+// CHECK: call {{.*}} float @float hlsl::ByteAddressBuffer::Load<float>(unsigned int)(ptr {{.*}} @Buf, i32 noundef 20)
+// CHECK: call {{.*}} <4 x float> @float vector[4] hlsl::RWByteAddressBuffer::Load<float vector[4]>(unsigned int)(ptr {{.*}} @RWBuf, i32 noundef 24)
+// CHECK: add
+// CHECK: ret float
+
+// CHECK: define {{.*}} i32 @hlsl::ByteAddressBuffer::Load(unsigned int)(ptr {{.*}} %this, i32 noundef %Index)
+// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::ByteAddressBuffer", ptr %{{.*}}, i32 0, i32 0
+// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 0, 0), ptr %__handle
+// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
+// DXIL-NEXT: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_0_0t(target("dx.RawBuffer", i8, 0, 0) %[[HANDLE]], i32 %[[INDEX]])
+// CHECK-NEXT: %[[VAL:.*]] = load i32, ptr %[[PTR]]
+// CHECK-NEXT: ret i32 %[[VAL]]
+
+// CHECK: define {{.*}} <4 x i32> @hlsl::RWByteAddressBuffer::Load4(unsigned int)(ptr {{.*}} %this, i32 noundef %Index)
+// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RWByteAddressBuffer", ptr %{{.*}}, i32 0, i32 0
+// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 0), ptr %__handle
+// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
+// DXIL-NEXT: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t(target("dx.RawBuffer", i8, 1, 0) %[[HANDLE]], i32 %[[INDEX]])
+// CHECK-NEXT: %[[VEC:.*]] = load <4 x i32>, ptr %[[PTR]]
+// CHECK-NEXT: ret <4 x i32> %[[VEC]]
+
+// CHECK: define {{.*}} float @float hlsl::ByteAddressBuffer::Load<float>(unsigned int)(ptr {{.*}} %this, i32 noundef %Index)
+// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::ByteAddressBuffer", ptr %{{.*}}, i32 0, i32 0
+// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 0, 0), ptr %__handle
+// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
+// DXIL-NEXT: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_0_0t(target("dx.RawBuffer", i8, 0, 0) %[[HANDLE]], i32 %[[INDEX]])
+// CHECK-NEXT: %[[VAL:.*]] = load float, ptr %[[PTR]]
+// CHECK-NEXT: ret float %[[VAL]]
+
+// CHECK: define {{.*}} <4 x float> @float vector[4] hlsl::RWByteAddressBuffer::Load<float vector[4]>(unsigned int)(ptr {{.*}} %this, i32 noundef %Index)
+// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RWByteAddressBuffer", ptr %{{.*}}, i32 0, i32 0
+// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 0), ptr %__handle
+// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
+// DXIL-NEXT: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t(target("dx.RawBuffer", i8, 1, 0) %[[HANDLE]], i32 %[[INDEX]])
+// CHECK-NEXT: %[[VEC:.*]] = load <4 x float>, ptr %[[PTR]]
+// CHECK-NEXT: ret <4 x float> %[[VEC]]
+
+export float TestLoadWithStatus() {
+ uint s1, s2, s3, s4;
+ float ret = Buf.Load(0, s1) + RWBuf.Load4(4, s2).w + Buf.Load<float>(20, s3) + RWBuf.Load<float4>(24, s4).w;
+ ret += float(s1 + s2 + s3 + s4);
+ return ret;
}
-// CHECK: define {{.*}} i32 @TestLoadWithStatus()()
+// CHECK: define {{.*}} float @TestLoadWithStatus()()
// CHECK: call {{.*}} i32 @hlsl::ByteAddressBuffer::Load(unsigned int, unsigned int&)(ptr {{.*}} @Buf, i32 noundef 0, ptr {{.*}} %tmp)
-// CHECK: ret i32
+// CHECK: call {{.*}} <4 x i32> @hlsl::RWByteAddressBuffer::Load4(unsigned int, unsigned int&)(ptr {{.*}} @RWBuf, i32 noundef 4, ptr {{.*}} %tmp1)
+// CHECK: call {{.*}} float @float hlsl::ByteAddressBuffer::Load<float>(unsigned int, unsigned int&)(ptr {{.*}} @Buf, i32 noundef 20, ptr {{.*}} %tmp4)
+// CHECK: call {{.*}} <4 x float> @float vector[4] hlsl::RWByteAddressBuffer::Load<float vector[4]>(unsigned int, unsigned int&)(ptr {{.*}} @RWBuf, i32 noundef 24, ptr {{.*}} %tmp7)
+// CHECK: add
+// CHECK: ret float
+
+// CHECK: define {{.*}} i32 @hlsl::ByteAddressBuffer::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr {{.*}} %Status)
+// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::ByteAddressBuffer", ptr %{{.*}}, i32 0, i32 0
+// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 0, 0), ptr %__handle
+// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
+// CHECK-NEXT: %[[LOADED_STATUS_ADDR:.*]] = load ptr, ptr %Status.addr
+// DXIL-NEXT: %[[STRUCT:.*]] = call { i32, i1 } @llvm.dx.resource.load.rawbuffer.i32.tdx.RawBuffer_i8_0_0t(target("dx.RawBuffer", i8, 0, 0) %[[HANDLE]], i32 %[[INDEX]], i32 poison)
+// CHECK-NEXT: %[[VALUE:.*]] = extractvalue { i32, i1 } %[[STRUCT]], 0
+// CHECK-NEXT: %[[STATUS_TEMP:.*]] = extractvalue { i32, i1 } %[[STRUCT]], 1
+// CHECK-NEXT: %[[STATUS_EXT:.*]] = zext i1 %[[STATUS_TEMP]] to i32
+// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %[[LOADED_STATUS_ADDR]], align 4
+// CHECK-NEXT: ret i32 %[[VALUE]]
+
+// CHECK: define {{.*}} <4 x i32> @hlsl::RWByteAddressBuffer::Load4(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr {{.*}} %Status)
+// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RWByteAddressBuffer", ptr %{{.*}}, i32 0, i32 0
+// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 0), ptr %__handle
+// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
+// CHECK-NEXT: %[[LOADED_STATUS_ADDR:.*]] = load ptr, ptr %Status.addr
+// DXIL-NEXT: %[[STRUCT:.*]] = call { <4 x i32>, i1 } @llvm.dx.resource.load.rawbuffer.v4i32.tdx.RawBuffer_i8_1_0t(target("dx.RawBuffer", i8, 1, 0) %[[HANDLE]], i32 %[[INDEX]], i32 poison)
+// CHECK-NEXT: %[[VALUE:.*]] = extractvalue { <4 x i32>, i1 } %[[STRUCT]], 0
+// CHECK-NEXT: %[[STATUS_TEMP:.*]] = extractvalue { <4 x i32>, i1 } %[[STRUCT]], 1
+// CHECK-NEXT: %[[STATUS_EXT:.*]] = zext i1 %[[STATUS_TEMP]] to i32
+// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %[[LOADED_STATUS_ADDR]], align 4
+// CHECK-NEXT: ret <4 x i32> %[[VALUE]]
+
+// CHECK: define {{.*}} float @float hlsl::ByteAddressBuffer::Load<float>(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr {{.*}} %Status)
+// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::ByteAddressBuffer", ptr %{{.*}}, i32 0, i32 0
+// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 0, 0), ptr %__handle
+// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
+// CHECK-NEXT: %[[LOADED_STATUS_ADDR:.*]] = load ptr, ptr %Status.addr
+// DXIL-NEXT: %[[STRUCT:.*]] = call { float, i1 } @llvm.dx.resource.load.rawbuffer.f32.tdx.RawBuffer_i8_0_0t(target("dx.RawBuffer", i8, 0, 0) %[[HANDLE]], i32 %[[INDEX]], i32 poison)
+// CHECK-NEXT: %[[VALUE:.*]] = extractvalue { float, i1 } %[[STRUCT]], 0
+// CHECK-NEXT: %[[STATUS_TEMP:.*]] = extractvalue { float, i1 } %[[STRUCT]], 1
+// CHECK-NEXT: %[[STATUS_EXT:.*]] = zext i1 %[[STATUS_TEMP]] to i32
+// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %[[LOADED_STATUS_ADDR]], align 4
+// CHECK-NEXT: ret float %[[VALUE]]
+
+// CHECK: define {{.*}} <4 x float> @float vector[4] hlsl::RWByteAddressBuffer::Load<float vector[4]>(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr {{.*}} %Status)
+// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RWByteAddressBuffer", ptr %{{.*}}, i32 0, i32 0
+// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 0), ptr %__handle
+// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
+// CHECK-NEXT: %[[LOADED_STATUS_ADDR:.*]] = load ptr, ptr %Status.addr
+// DXIL-NEXT: %[[STRUCT:.*]] = call { <4 x float>, i1 } @llvm.dx.resource.load.rawbuffer.v4f32.tdx.RawBuffer_i8_1_0t(target("dx.RawBuffer", i8, 1, 0) %[[HANDLE]], i32 %[[INDEX]], i32 poison)
+// CHECK-NEXT: %[[VALUE:.*]] = extractvalue { <4 x float>, i1 } %[[STRUCT]], 0
+// CHECK-NEXT: %[[STATUS_TEMP:.*]] = extractvalue { <4 x float>, i1 } %[[STRUCT]], 1
+// CHECK-NEXT: %[[STATUS_EXT:.*]] = zext i1 %[[STATUS_TEMP]] to i32
+// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %[[LOADED_STATUS_ADDR]], align 4
+// CHECK-NEXT: ret <4 x float> %[[VALUE]]
export void TestStore() {
- uint u0;
- float f0;
- RWBuf.Store(0, u0);
- RWBuf.Store<float>(0, f0);
- SmallStruct TempStruct1;
- RWBuf.Store<SmallStruct>(144, TempStruct1);
+ uint4 a;
+ float4 b;
+ RWBuf.Store(0, a.x);
+ RWBuf.Store4(4, a);
+ RWBuf.Store<float>(20, b.x);
+ RWBuf.Store<float4>(24, b);
return;
}
// CHECK: define void @TestStore()()
// CHECK: call void @hlsl::RWByteAddressBuffer::Store(unsigned int, unsigned int)(ptr {{.*}} @RWBuf, i32 noundef 0, i32 noundef %{{.*}})
+// CHECK: call void @hlsl::RWByteAddressBuffer::Store4(unsigned int, unsigned int vector[4])(ptr {{.*}} @RWBuf, i32 noundef 4, <4 x i32> noundef %{{.*}})
+// CHECK: call void @void hlsl::RWByteAddressBuffer::Store<float>(unsigned int, float)(ptr {{.*}} @RWBuf, i32 noundef 20, float noundef {{.*}})
+// CHECK: call void @void hlsl::RWByteAddressBuffer::Store<float vector[4]>(unsigned int, float vector[4])(ptr {{.*}} @RWBuf, i32 noundef 24, <4 x float> noundef {{.*}})
// CHECK: ret void
+// CHECK: define {{.*}} void @hlsl::RWByteAddressBuffer::Store(unsigned int, unsigned int)(ptr {{.*}} %this, i32 noundef %Index, i32 noundef %Value)
+// CHECK: %[[VALUE:.*]] = load i32, ptr %Value.addr
+// CHECK-NEXT: %__handle = getelementptr inbounds nuw %"class.hlsl::RWByteAddressBuffer", ptr %{{.*}}, i32 0, i32 0
+// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 0), ptr %__handle
+// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
+// DXIL-NEXT: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t(target("dx.RawBuffer", i8, 1, 0) %[[HANDLE]], i32 %[[INDEX]])
+// CHECK-NEXT: store i32 %[[VALUE]], ptr %[[PTR]]
+// CHECK-NEXT: ret void
+
+// CHECK: define {{.*}} void @hlsl::RWByteAddressBuffer::Store4(unsigned int, unsigned int vector[4])(ptr {{.*}} %this, i32 noundef %Index, <4 x i32> noundef %Value)
+// CHECK: %[[VALUE:.*]] = load <4 x i32>, ptr %Value.addr
+// CHECK-NEXT: %__handle = getelementptr inbounds nuw %"class.hlsl::RWByteAddressBuffer", ptr %{{.*}}, i32 0, i32 0
+// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 0), ptr %__handle
+// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
+// DXIL-NEXT: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t(target("dx.RawBuffer", i8, 1, 0) %[[HANDLE]], i32 %[[INDEX]])
+// CHECK-NEXT: store <4 x i32> %[[VALUE]], ptr %[[PTR]]
+// CHECK-NEXT: ret void
+
+// CHECK: define {{.*}} void @void hlsl::RWByteAddressBuffer::Store<float>(unsigned int, float)(ptr {{.*}} %this, i32 noundef %Index, float noundef {{.*}} %Value)
+// CHECK: %[[VALUE:.*]] = load float, ptr %Value.addr
+// CHECK-NEXT: %__handle = getelementptr inbounds nuw %"class.hlsl::RWByteAddressBuffer", ptr %{{.*}}, i32 0, i32 0
+// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 0), ptr %__handle
+// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
+// DXIL-NEXT: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t(target("dx.RawBuffer", i8, 1, 0) %[[HANDLE]], i32 %[[INDEX]])
+// CHECK-NEXT: store float %[[VALUE]], ptr %[[PTR]]
+// CHECK-NEXT: ret void
+
+// CHECK: define {{.*}} void @void hlsl::RWByteAddressBuffer::Store<float vector[4]>(unsigned int, float vector[4])(ptr {{.*}} %this, i32 noundef %Index, <4 x float> noundef {{.*}} %Value)
+// CHECK: %[[VALUE:.*]] = load <4 x float>, ptr %Value.addr
+// CHECK-NEXT: %__handle = getelementptr inbounds nuw %"class.hlsl::RWByteAddressBuffer", ptr %{{.*}}, i32 0, i32 0
+// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 0), ptr %__handle
+// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
+// DXIL-NEXT: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t(target("dx.RawBuffer", i8, 1, 0) %[[HANDLE]], i32 %[[INDEX]])
+// CHECK-NEXT: store <4 x float> %[[VALUE]], ptr %[[PTR]]
+// CHECK-NEXT: ret void
+
export uint TestGetDimensions() {
uint dim1, dim2;
Buf.GetDimensions(dim1);
>From 7a83b89117d26865afffb32f92e2384ae6df3281 Mon Sep 17 00:00:00 2001
From: kmpeng <kaitlinpeng at microsoft.com>
Date: Wed, 14 Jan 2026 19:37:38 -0800
Subject: [PATCH 08/12] reject array types, add array error tests
---
clang/lib/Sema/SemaHLSL.cpp | 13 +++++-
.../SemaHLSL/BuiltIns/ByteAddressBuffers.hlsl | 44 +++++++++++++++++++
2 files changed, 56 insertions(+), 1 deletion(-)
create mode 100644 clang/test/SemaHLSL/BuiltIns/ByteAddressBuffers.hlsl
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 805008f1670a2..0a4cc563526eb 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3335,6 +3335,11 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
"expected 2 parameters for Store method");
ElementTy = FD->getParamDecl(1)->getType();
}
+
+ // Reject array types
+ if (ElementTy->isArrayType())
+ return SemaRef.Diag(FD->getPointOfInstantiation(),
+ diag::err_invalid_use_of_array_type);
}
auto ReturnType =
SemaRef.Context.getAddrSpaceQualType(ElementTy, LangAS::hlsl_device);
@@ -3360,7 +3365,13 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
// ByteAddressBuffer uses the FunctionDecl return type instead of the
// contained type
if (ResourceTy->getAttrs().RawBuffer && ReturnType->isChar8Type()) {
- ReturnType = dyn_cast<FunctionDecl>(SemaRef.CurContext)->getReturnType();
+ FunctionDecl *FD = dyn_cast<FunctionDecl>(SemaRef.CurContext);
+ ReturnType = FD->getReturnType();
+
+ // Reject array types
+ if (ReturnType->isArrayType())
+ return SemaRef.Diag(FD->getPointOfInstantiation(),
+ diag::err_invalid_use_of_array_type);
}
TheCall->setType(ReturnType);
diff --git a/clang/test/SemaHLSL/BuiltIns/ByteAddressBuffers.hlsl b/clang/test/SemaHLSL/BuiltIns/ByteAddressBuffers.hlsl
new file mode 100644
index 0000000000000..d7d48bf427ea7
--- /dev/null
+++ b/clang/test/SemaHLSL/BuiltIns/ByteAddressBuffers.hlsl
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library -x hlsl -fsyntax-only -verify %s
+
+ByteAddressBuffer Buf : register(t0);
+RWByteAddressBuffer RWBuf : register(u0);
+
+int test_load_uint_array()[4] {
+ return Buf.Load<uint[4]>(0);
+ // expected-error at -1 {{an array type is not allowed here}}
+ // expected-note at -2 {{in instantiation of function template specialization 'hlsl::ByteAddressBuffer::Load<unsigned int[4]>' requested here}}
+}
+
+float test_load_float_array()[2] {
+ return RWBuf.Load<float[2]>(0);
+ // expected-error at -1 {{an array type is not allowed here}}
+ // expected-note at -2 {{in instantiation of function template specialization 'hlsl::RWByteAddressBuffer::Load<float[2]>' requested here}}
+}
+
+int test_load_uint_array_with_status()[4] {
+ uint s1;
+ return RWBuf.Load<uint[4]>(0, s1);
+ // expected-error at -1 {{an array type is not allowed here}}
+ // expected-note at -2 {{in instantiation of function template specialization 'hlsl::RWByteAddressBuffer::Load<unsigned int[4]>' requested here}}
+}
+
+float test_load_float_array_with_status()[2] {
+ uint s1;
+ return Buf.Load<float[2]>(0, s1);
+ // expected-error at -1 {{an array type is not allowed here}}
+ // expected-note at -2 {{in instantiation of function template specialization 'hlsl::ByteAddressBuffer::Load<float[2]>' requested here}}
+}
+
+void test_store_uint_array() {
+ uint UIntArray[4];
+ RWBuf.Store<uint[4]>(0, UIntArray);
+ // expected-error at -1 {{an array type is not allowed here}}
+ // expected-note at -2 {{in instantiation of function template specialization 'hlsl::RWByteAddressBuffer::Store<unsigned int[4]>' requested here}}
+}
+
+void test_store_float_array() {
+ float FloatArray[2];
+ RWBuf.Store<float[2]>(0, FloatArray);
+ // expected-error at -1 {{an array type is not allowed here}}
+ // expected-note at -2 {{in instantiation of function template specialization 'hlsl::RWByteAddressBuffer::Store<float[2]>' requested here}}
+}
>From c422fa529e7a795bd706df2f896164b2f604b677 Mon Sep 17 00:00:00 2001
From: kmpeng <kaitlinpeng at microsoft.com>
Date: Thu, 15 Jan 2026 19:00:44 -0800
Subject: [PATCH 09/12] address PR comments
---
clang/lib/CodeGen/CGHLSLBuiltins.cpp | 2 +-
clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 11 +++++------
clang/lib/Sema/SemaHLSL.cpp | 12 ++++++++----
clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl | 5 +++++
4 files changed, 19 insertions(+), 11 deletions(-)
diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
index 532fe0673423e..981f67a042598 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -521,7 +521,7 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
if (RT->getAttrs().RawBuffer) {
Value *Offset = Builder.getInt32(0);
- // Offset is poison for ByteAddressBuffer
+ // The offset parameter needs to be poison for ByteAddressBuffer
if (RT->getContainedType()->isChar8Type())
Offset = llvm::PoisonValue::get(Builder.getInt32Ty());
Args.push_back(Offset);
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index 2e6798efcf0ae..27a5428d8bd26 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -1212,12 +1212,13 @@ BuiltinTypeDeclBuilder::addByteAddressBufferLoadMethods() {
// Load without status
BuiltinTypeMethodBuilder MMB(*this, Load, ReturnType);
+ QualType ElemTy = ReturnType;
if (ReturnType->isDependentType()) {
- ReturnType = MMB.addTemplateTypeParam("element_type");
- MMB.ReturnTy = ReturnType; // Update return type to template parameter
+ ElemTy = MMB.addTemplateTypeParam("element_type");
+ MMB.ReturnTy = ElemTy; // Update return type to template parameter
}
QualType AddrSpaceElemTy =
- AST.getAddrSpaceQualType(ReturnType, LangAS::hlsl_device);
+ AST.getAddrSpaceQualType(ElemTy, LangAS::hlsl_device);
MMB.addParam("Index", AST.UnsignedIntTy)
.callBuiltin("__builtin_hlsl_resource_getpointer",
@@ -1256,15 +1257,13 @@ BuiltinTypeDeclBuilder::addByteAddressBufferStoreMethods() {
using PH = BuiltinTypeMethodBuilder::PlaceHolder;
ASTContext &AST = SemaRef.getASTContext();
- // Helper to add uint Store methods
auto addStoreMethod = [&](StringRef MethodName, QualType ValueType) {
IdentifierInfo &II = AST.Idents.get(MethodName, tok::TokenKind::identifier);
DeclarationName Store(&II);
BuiltinTypeMethodBuilder MMB(*this, Store, AST.VoidTy);
- if (ValueType->isDependentType()) {
+ if (ValueType->isDependentType())
ValueType = MMB.addTemplateTypeParam("element_type");
- }
QualType AddrSpaceElemTy =
AST.getAddrSpaceQualType(ValueType, LangAS::hlsl_device);
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 0a4cc563526eb..360d8c218ec58 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3320,11 +3320,12 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
SemaRef.getASTContext().UnsignedIntTy))
return true;
+ // Figure out the return type of the intrinsic. For most resources it is the
+ // contained type. For ByteAddressBuffer it is determined by the type used
+ // on the FunctionDecl.
auto *ResourceTy =
TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
QualType ElementTy = ResourceTy->getContainedType();
- // ByteAddressBuffer uses the FunctionDecl types instead of the contained
- // type
if (ResourceTy->getAttrs().RawBuffer && ElementTy->isChar8Type()) {
// Load method uses return type
FunctionDecl *FD = dyn_cast<FunctionDecl>(SemaRef.CurContext);
@@ -3341,6 +3342,7 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
return SemaRef.Diag(FD->getPointOfInstantiation(),
diag::err_invalid_use_of_array_type);
}
+
auto ReturnType =
SemaRef.Context.getAddrSpaceQualType(ElementTy, LangAS::hlsl_device);
ReturnType = SemaRef.Context.getPointerType(ReturnType);
@@ -3359,11 +3361,12 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
CheckModifiableLValue(&SemaRef, TheCall, 2))
return true;
+ // Figure out the return type of the intrinsic. For most resources it is the
+ // contained type. For ByteAddressBuffer it is determined by the return
+ // value type.
auto *ResourceTy =
TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
QualType ReturnType = ResourceTy->getContainedType();
- // ByteAddressBuffer uses the FunctionDecl return type instead of the
- // contained type
if (ResourceTy->getAttrs().RawBuffer && ReturnType->isChar8Type()) {
FunctionDecl *FD = dyn_cast<FunctionDecl>(SemaRef.CurContext);
ReturnType = FD->getReturnType();
@@ -3373,6 +3376,7 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
return SemaRef.Diag(FD->getPointOfInstantiation(),
diag::err_invalid_use_of_array_type);
}
+
TheCall->setType(ReturnType);
break;
diff --git a/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl b/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
index aee1e0d8cda34..a762e181ee221 100644
--- a/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
+++ b/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
@@ -166,6 +166,7 @@ RESOURCE Buffer;
// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
+
// CHECK-LOAD: CXXMethodDecl {{.*}} Load 'unsigned int (unsigned int, out unsigned int)
// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Status 'unsigned int &__restrict'
@@ -193,6 +194,7 @@ RESOURCE Buffer;
// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
+
// CHECK-LOAD: CXXMethodDecl {{.*}} Load2 'vector<unsigned int (unsigned int, out unsigned int), 2>'
// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Status 'unsigned int &__restrict'
@@ -220,6 +222,7 @@ RESOURCE Buffer;
// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
+
// CHECK-LOAD: CXXMethodDecl {{.*}} Load3 'vector<unsigned int (unsigned int, out unsigned int), 3>'
// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Status 'unsigned int &__restrict'
@@ -247,6 +250,7 @@ RESOURCE Buffer;
// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
+
// CHECK-LOAD: CXXMethodDecl {{.*}} Load4 'vector<unsigned int (unsigned int, out unsigned int), 4>'
// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Status 'unsigned int &__restrict'
@@ -274,6 +278,7 @@ RESOURCE Buffer;
// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
+
// CHECK-LOAD: CXXMethodDecl {{.*}} Load 'element_type (unsigned int, out unsigned int)
// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Status 'unsigned int &__restrict'
>From b5bc6c66538e178014373f3a7a238e39e5bc96ff Mon Sep 17 00:00:00 2001
From: kmpeng <kaitlinpeng at microsoft.com>
Date: Tue, 20 Jan 2026 09:53:01 -0800
Subject: [PATCH 10/12] change parmvardecl declcontext
---
clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 3 +--
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 12 ++----------
2 files changed, 3 insertions(+), 12 deletions(-)
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index 27a5428d8bd26..a30a39c7ddb82 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -526,8 +526,7 @@ void BuiltinTypeMethodBuilder::createDecl() {
for (int I = 0, E = Params.size(); I != E; I++) {
Param &MP = Params[I];
ParmVarDecl *Parm = ParmVarDecl::Create(
- AST, Method->getDeclContext(), SourceLocation(), SourceLocation(),
- &MP.NameII, MP.Ty,
+ AST, Method, SourceLocation(), SourceLocation(), &MP.NameII, MP.Ty,
AST.getTrivialTypeSourceInfo(MP.Ty, SourceLocation()), SC_None,
nullptr);
if (MP.Modifier != HLSLParamModifierAttr::Keyword_in) {
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 348ac5e75af7c..2871f27a24658 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -6903,16 +6903,8 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
if (isa<ParmVarDecl>(D) && !ParentDependsOnArgs &&
!cast<ParmVarDecl>(D)->getType()->isInstantiationDependentType()) {
// Check if D belongs to a function template
- auto *PVD = cast<ParmVarDecl>(D);
- bool IsFromFunctionTemplate =
- llvm::any_of(ParentDC->decls(), [PVD](Decl *D) {
- if (auto *FTD = dyn_cast<FunctionTemplateDecl>(D))
- return llvm::is_contained(FTD->getTemplatedDecl()->parameters(),
- PVD);
- return false;
- });
-
- if (!IsFromFunctionTemplate)
+ auto *FD = dyn_cast<FunctionDecl>(ParentDC);
+ if (!FD || !FD->getDescribedFunctionTemplate())
return D;
}
if (isa<ParmVarDecl>(D) || isa<NonTypeTemplateParmDecl>(D) ||
>From fb1d8eb605659307b3b4a7e63d058d99e09dd1ab Mon Sep 17 00:00:00 2001
From: kmpeng <kaitlinpeng at microsoft.com>
Date: Tue, 20 Jan 2026 16:25:28 -0800
Subject: [PATCH 11/12] address Justin
---
clang/include/clang/AST/TypeBase.h | 2 +
clang/lib/CodeGen/CGHLSLBuiltins.cpp | 4 +-
clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 142 +++++++++---------
clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h | 6 +-
clang/lib/Sema/SemaHLSL.cpp | 4 +-
.../lib/Sema/SemaTemplateInstantiateDecl.cpp | 8 +-
6 files changed, 81 insertions(+), 85 deletions(-)
diff --git a/clang/include/clang/AST/TypeBase.h b/clang/include/clang/AST/TypeBase.h
index 279b75f14d7b8..2efca8a69ded1 100644
--- a/clang/include/clang/AST/TypeBase.h
+++ b/clang/include/clang/AST/TypeBase.h
@@ -6745,6 +6745,8 @@ class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode {
QualType getContainedType() const { return ContainedType; }
bool hasContainedType() const { return !ContainedType.isNull(); }
const Attributes &getAttrs() const { return Attrs; }
+ bool isRaw() const { return Attrs.RawBuffer; }
+ bool isStructured() const { return !ContainedType->isChar8Type(); }
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
index 981f67a042598..ee1714f568689 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -519,10 +519,10 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
Args.push_back(HandleOp);
Args.push_back(IndexOp);
- if (RT->getAttrs().RawBuffer) {
+ if (RT->isRaw()) {
Value *Offset = Builder.getInt32(0);
// The offset parameter needs to be poison for ByteAddressBuffer
- if (RT->getContainedType()->isChar8Type())
+ if (!RT->isStructured())
Offset = llvm::PoisonValue::get(Builder.getInt32Ty());
Args.push_back(Offset);
}
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index a30a39c7ddb82..e957566b52e45 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -468,7 +468,7 @@ QualType BuiltinTypeMethodBuilder::addTemplateTypeParam(StringRef Name) {
/* Typename */ true,
/* ParameterPack */ false,
/* HasTypeConstraint*/ false);
- TemplateParamDecls.emplace_back(Decl);
+ TemplateParamDecls.push_back(Decl);
return QualType(Decl->getTypeForDecl(), 0);
}
@@ -1178,9 +1178,11 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addArraySubscriptOperators() {
DeclarationName Subscript =
AST.DeclarationNames.getCXXOperatorName(OO_Subscript);
- addHandleAccessFunction(Subscript, /*IsConst=*/true, /*IsRef=*/true);
+ addHandleAccessFunction(Subscript, getHandleElementType(), /*IsConst=*/true,
+ /*IsRef=*/true);
if (getResourceAttrs().ResourceClass == llvm::dxil::ResourceClass::UAV)
- addHandleAccessFunction(Subscript, /*IsConst=*/false, /*IsRef=*/true);
+ addHandleAccessFunction(Subscript, getHandleElementType(),
+ /*IsConst=*/false, /*IsRef=*/true);
return *this;
}
@@ -1192,8 +1194,9 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addLoadMethods() {
IdentifierInfo &II = AST.Idents.get("Load", tok::TokenKind::identifier);
DeclarationName Load(&II);
// TODO: We also need versions with status for CheckAccessFullyMapped.
- addHandleAccessFunction(Load, /*IsConst=*/false, /*IsRef=*/false);
- addLoadWithStatusFunction(Load, /*IsConst=*/false);
+ addHandleAccessFunction(Load, getHandleElementType(), /*IsConst=*/false,
+ /*IsRef=*/false);
+ addLoadWithStatusFunction(Load, getHandleElementType(), /*IsConst=*/false);
return *this;
}
@@ -1202,50 +1205,22 @@ BuiltinTypeDeclBuilder &
BuiltinTypeDeclBuilder::addByteAddressBufferLoadMethods() {
assert(!Record->isCompleteDefinition() && "record is already complete");
- using PH = BuiltinTypeMethodBuilder::PlaceHolder;
ASTContext &AST = SemaRef.getASTContext();
- auto addLoadMethod = [&](StringRef MethodName, QualType ReturnType) {
+ auto AddLoads = [&](StringRef MethodName, QualType ReturnType) {
IdentifierInfo &II = AST.Idents.get(MethodName, tok::TokenKind::identifier);
DeclarationName Load(&II);
- // Load without status
- BuiltinTypeMethodBuilder MMB(*this, Load, ReturnType);
- QualType ElemTy = ReturnType;
- if (ReturnType->isDependentType()) {
- ElemTy = MMB.addTemplateTypeParam("element_type");
- MMB.ReturnTy = ElemTy; // Update return type to template parameter
- }
- QualType AddrSpaceElemTy =
- AST.getAddrSpaceQualType(ElemTy, LangAS::hlsl_device);
-
- MMB.addParam("Index", AST.UnsignedIntTy)
- .callBuiltin("__builtin_hlsl_resource_getpointer",
- AST.getPointerType(AddrSpaceElemTy), PH::Handle, PH::_0)
- .dereference(PH::LastStmt)
- .finalize();
-
- // Load with status
- BuiltinTypeMethodBuilder MMB2(*this, Load, ReturnType);
- if (ReturnType->isDependentType()) {
- ReturnType = MMB2.addTemplateTypeParam("element_type");
- MMB2.ReturnTy = ReturnType; // Update return type to template parameter
- }
-
- MMB2.addParam("Index", AST.UnsignedIntTy)
- .addParam("Status", AST.UnsignedIntTy,
- HLSLParamModifierAttr::Keyword_out)
- .callBuiltin("__builtin_hlsl_resource_load_with_status", ReturnType,
- PH::Handle, PH::_0, PH::_1)
- .finalize();
+ addHandleAccessFunction(Load, ReturnType, /*IsConst=*/false,
+ /*IsRef=*/false);
+ addLoadWithStatusFunction(Load, ReturnType, /*IsConst=*/false);
};
- addLoadMethod("Load", AST.UnsignedIntTy);
- addLoadMethod("Load2", AST.getExtVectorType(AST.UnsignedIntTy, 2));
- addLoadMethod("Load3", AST.getExtVectorType(AST.UnsignedIntTy, 3));
- addLoadMethod("Load4", AST.getExtVectorType(AST.UnsignedIntTy, 4));
- addLoadMethod("Load", AST.DependentTy); // Templated version
-
+ AddLoads("Load", AST.UnsignedIntTy);
+ AddLoads("Load2", AST.getExtVectorType(AST.UnsignedIntTy, 2));
+ AddLoads("Load3", AST.getExtVectorType(AST.UnsignedIntTy, 3));
+ AddLoads("Load4", AST.getExtVectorType(AST.UnsignedIntTy, 4));
+ AddLoads("Load", AST.DependentTy); // Templated version
return *this;
}
@@ -1253,33 +1228,20 @@ BuiltinTypeDeclBuilder &
BuiltinTypeDeclBuilder::addByteAddressBufferStoreMethods() {
assert(!Record->isCompleteDefinition() && "record is already complete");
- using PH = BuiltinTypeMethodBuilder::PlaceHolder;
ASTContext &AST = SemaRef.getASTContext();
- auto addStoreMethod = [&](StringRef MethodName, QualType ValueType) {
+ auto AddStore = [&](StringRef MethodName, QualType ValueType) {
IdentifierInfo &II = AST.Idents.get(MethodName, tok::TokenKind::identifier);
DeclarationName Store(&II);
- BuiltinTypeMethodBuilder MMB(*this, Store, AST.VoidTy);
- if (ValueType->isDependentType())
- ValueType = MMB.addTemplateTypeParam("element_type");
- QualType AddrSpaceElemTy =
- AST.getAddrSpaceQualType(ValueType, LangAS::hlsl_device);
-
- MMB.addParam("Index", AST.UnsignedIntTy)
- .addParam("Value", ValueType)
- .callBuiltin("__builtin_hlsl_resource_getpointer",
- AST.getPointerType(AddrSpaceElemTy), PH::Handle, PH::_0)
- .dereference(PH::LastStmt)
- .assign(PH::LastStmt, PH::_1)
- .finalize();
+ addStoreFunction(Store, ValueType, /*IsConst=*/false);
};
- addStoreMethod("Store", AST.UnsignedIntTy);
- addStoreMethod("Store2", AST.getExtVectorType(AST.UnsignedIntTy, 2));
- addStoreMethod("Store3", AST.getExtVectorType(AST.UnsignedIntTy, 3));
- addStoreMethod("Store4", AST.getExtVectorType(AST.UnsignedIntTy, 4));
- addStoreMethod("Store", AST.DependentTy); // Templated version
+ AddStore("Store", AST.UnsignedIntTy);
+ AddStore("Store2", AST.getExtVectorType(AST.UnsignedIntTy, 2));
+ AddStore("Store3", AST.getExtVectorType(AST.UnsignedIntTy, 3));
+ AddStore("Store4", AST.getExtVectorType(AST.UnsignedIntTy, 4));
+ AddStore("Store", AST.DependentTy); // Templated version
return *this;
}
@@ -1372,30 +1334,38 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDecrementCounterMethod() {
.finalize();
}
-BuiltinTypeDeclBuilder &
-BuiltinTypeDeclBuilder::addLoadWithStatusFunction(DeclarationName &Name,
- bool IsConst) {
+BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addLoadWithStatusFunction(
+ DeclarationName &Name, QualType ReturnTy, bool IsConst) {
assert(!Record->isCompleteDefinition() && "record is already complete");
ASTContext &AST = SemaRef.getASTContext();
using PH = BuiltinTypeMethodBuilder::PlaceHolder;
- QualType ReturnTy = getHandleElementType();
- return BuiltinTypeMethodBuilder(*this, Name, ReturnTy, IsConst)
- .addParam("Index", AST.UnsignedIntTy)
+ BuiltinTypeMethodBuilder MMB(*this, Name, ReturnTy, IsConst);
+
+ if (ReturnTy == AST.DependentTy) {
+ ReturnTy = MMB.addTemplateTypeParam("element_type");
+ MMB.ReturnTy = ReturnTy;
+ }
+
+ return MMB.addParam("Index", AST.UnsignedIntTy)
.addParam("Status", AST.UnsignedIntTy, HLSLParamModifierAttr::Keyword_out)
.callBuiltin("__builtin_hlsl_resource_load_with_status", ReturnTy,
PH::Handle, PH::_0, PH::_1)
.finalize();
}
-BuiltinTypeDeclBuilder &
-BuiltinTypeDeclBuilder::addHandleAccessFunction(DeclarationName &Name,
- bool IsConst, bool IsRef) {
+BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addHandleAccessFunction(
+ DeclarationName &Name, QualType ElemTy, bool IsConst, bool IsRef) {
assert(!Record->isCompleteDefinition() && "record is already complete");
ASTContext &AST = SemaRef.getASTContext();
using PH = BuiltinTypeMethodBuilder::PlaceHolder;
- QualType ElemTy = getHandleElementType();
+ // The empty QualType is a placeholder. The actual return type is set below.
+ BuiltinTypeMethodBuilder MMB(*this, Name, QualType(), IsConst);
+
+ if (ElemTy == AST.DependentTy) {
+ ElemTy = MMB.addTemplateTypeParam("element_type");
+ }
QualType AddrSpaceElemTy =
AST.getAddrSpaceQualType(ElemTy, LangAS::hlsl_device);
QualType ElemPtrTy = AST.getPointerType(AddrSpaceElemTy);
@@ -1411,12 +1381,36 @@ BuiltinTypeDeclBuilder::addHandleAccessFunction(DeclarationName &Name,
if (IsConst)
ReturnTy.addConst();
}
+ MMB.ReturnTy = ReturnTy;
+
+ return MMB.addParam("Index", AST.UnsignedIntTy)
+ .callBuiltin("__builtin_hlsl_resource_getpointer", ElemPtrTy, PH::Handle,
+ PH::_0)
+ .dereference(PH::LastStmt)
+ .finalize();
+}
+
+BuiltinTypeDeclBuilder &
+BuiltinTypeDeclBuilder::addStoreFunction(DeclarationName &Name,
+ QualType ValueTy, bool IsConst) {
+ assert(!Record->isCompleteDefinition() && "record is already complete");
+ ASTContext &AST = SemaRef.getASTContext();
+ using PH = BuiltinTypeMethodBuilder::PlaceHolder;
+
+ BuiltinTypeMethodBuilder MMB(*this, Name, AST.VoidTy, IsConst);
+
+ if (ValueTy == AST.DependentTy)
+ ValueTy = MMB.addTemplateTypeParam("element_type");
+ QualType AddrSpaceElemTy =
+ AST.getAddrSpaceQualType(ValueTy, LangAS::hlsl_device);
+ QualType ElemPtrTy = AST.getPointerType(AddrSpaceElemTy);
- return BuiltinTypeMethodBuilder(*this, Name, ReturnTy, IsConst)
- .addParam("Index", AST.UnsignedIntTy)
+ return MMB.addParam("Index", AST.UnsignedIntTy)
+ .addParam("Value", ValueTy)
.callBuiltin("__builtin_hlsl_resource_getpointer", ElemPtrTy, PH::Handle,
PH::_0)
.dereference(PH::LastStmt)
+ .assign(PH::LastStmt, PH::_1)
.finalize();
}
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
index 8309ba990fda0..76cded6a6e33c 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
@@ -92,9 +92,13 @@ class BuiltinTypeDeclBuilder {
BuiltinTypeDeclBuilder &addIncrementCounterMethod();
BuiltinTypeDeclBuilder &addDecrementCounterMethod();
BuiltinTypeDeclBuilder &addHandleAccessFunction(DeclarationName &Name,
- bool IsConst, bool IsRef);
+ QualType ElemTy, bool IsConst,
+ bool IsRef);
BuiltinTypeDeclBuilder &addLoadWithStatusFunction(DeclarationName &Name,
+ QualType ReturnTy,
bool IsConst);
+ BuiltinTypeDeclBuilder &addStoreFunction(DeclarationName &Name,
+ QualType ValueType, bool IsConst);
BuiltinTypeDeclBuilder &addAppendMethod();
BuiltinTypeDeclBuilder &addConsumeMethod();
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 360d8c218ec58..f4961c3e9e55a 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3326,7 +3326,7 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
auto *ResourceTy =
TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
QualType ElementTy = ResourceTy->getContainedType();
- if (ResourceTy->getAttrs().RawBuffer && ElementTy->isChar8Type()) {
+ if (ResourceTy->isRaw() && !ResourceTy->isStructured()) {
// Load method uses return type
FunctionDecl *FD = dyn_cast<FunctionDecl>(SemaRef.CurContext);
ElementTy = FD->getReturnType();
@@ -3367,7 +3367,7 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
auto *ResourceTy =
TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
QualType ReturnType = ResourceTy->getContainedType();
- if (ResourceTy->getAttrs().RawBuffer && ReturnType->isChar8Type()) {
+ if (ResourceTy->isRaw() && !ResourceTy->isStructured()) {
FunctionDecl *FD = dyn_cast<FunctionDecl>(SemaRef.CurContext);
ReturnType = FD->getReturnType();
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 2871f27a24658..e74c41517ecbf 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -6901,12 +6901,8 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
// whose type is not instantiation dependent, do nothing to the decl
// - otherwise find its instantiated decl.
if (isa<ParmVarDecl>(D) && !ParentDependsOnArgs &&
- !cast<ParmVarDecl>(D)->getType()->isInstantiationDependentType()) {
- // Check if D belongs to a function template
- auto *FD = dyn_cast<FunctionDecl>(ParentDC);
- if (!FD || !FD->getDescribedFunctionTemplate())
- return D;
- }
+ !cast<ParmVarDecl>(D)->getType()->isInstantiationDependentType())
+ return D;
if (isa<ParmVarDecl>(D) || isa<NonTypeTemplateParmDecl>(D) ||
isa<TemplateTypeParmDecl>(D) || isa<TemplateTemplateParmDecl>(D) ||
(ParentDependsOnArgs && (ParentDC->isFunctionOrMethod() ||
>From 42cb37f4068737b4f4cfc01a49682b682c9b4d3a Mon Sep 17 00:00:00 2001
From: kmpeng <kaitlinpeng at microsoft.com>
Date: Mon, 26 Jan 2026 23:01:28 -0800
Subject: [PATCH 12/12] create resource_getpointer_typed builtin for templated
load/stores
---
clang/include/clang/Basic/Builtins.td | 6 +++
clang/lib/CodeGen/CGHLSLBuiltins.cpp | 3 +-
clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 50 +++++++++++++------
clang/lib/Sema/SemaHLSL.cpp | 46 +++++++++--------
.../test/AST/HLSL/ByteAddressBuffers-AST.hlsl | 6 ++-
.../SemaHLSL/BuiltIns/ByteAddressBuffers.hlsl | 4 +-
6 files changed, 75 insertions(+), 40 deletions(-)
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index dcf07d659cb15..90d0483354e8e 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4995,6 +4995,12 @@ def HLSLResourceGetPointer : LangBuiltin<"HLSL_LANG"> {
let Prototype = "void(...)";
}
+def HLSLResourceGetPointerTyped : Builtin {
+ let Spellings = ["__builtin_hlsl_resource_getpointer_typed"];
+ let Attributes = [NoThrow];
+ let Prototype = "void(...)";
+}
+
def HLSLResourceLoadWithStatus : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_resource_load_with_status"];
let Attributes = [NoThrow];
diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
index ee1714f568689..cb633baec5380 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -484,7 +484,8 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
"hlsl.AddUint64");
return Result;
}
- case Builtin::BI__builtin_hlsl_resource_getpointer: {
+ case Builtin::BI__builtin_hlsl_resource_getpointer:
+ case Builtin::BI__builtin_hlsl_resource_getpointer_typed: {
Value *HandleOp = EmitScalarExpr(E->getArg(0));
Value *IndexOp = EmitScalarExpr(E->getArg(1));
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index e957566b52e45..b1f06ed2fda7a 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -178,6 +178,7 @@ struct BuiltinTypeMethodBuilder {
Expr *convertPlaceholder(PlaceHolder PH);
Expr *convertPlaceholder(LocalVar &Var);
Expr *convertPlaceholder(Expr *E) { return E; }
+ Expr *convertPlaceholder(QualType Ty);
public:
friend BuiltinTypeDeclBuilder;
@@ -425,6 +426,16 @@ Expr *BuiltinTypeMethodBuilder::convertPlaceholder(LocalVar &Var) {
VD->getType(), VK_LValue);
}
+// Converts a QualType to an Expr that carries type information through template
+// instantiation. Creates `Ty*()`, a value-initialized null pointer of type Ty*.
+Expr *BuiltinTypeMethodBuilder::convertPlaceholder(QualType Ty) {
+ ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
+ QualType PtrTy = AST.getPointerType(Ty);
+ return CXXUnresolvedConstructExpr::Create(
+ AST, PtrTy, AST.getTrivialTypeSourceInfo(PtrTy), SourceLocation(), {},
+ SourceLocation(), false);
+}
+
BuiltinTypeMethodBuilder::BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB,
StringRef NameStr,
QualType ReturnTy,
@@ -1359,13 +1370,13 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addHandleAccessFunction(
assert(!Record->isCompleteDefinition() && "record is already complete");
ASTContext &AST = SemaRef.getASTContext();
using PH = BuiltinTypeMethodBuilder::PlaceHolder;
+ bool IsTemplated = (ElemTy == AST.DependentTy);
// The empty QualType is a placeholder. The actual return type is set below.
BuiltinTypeMethodBuilder MMB(*this, Name, QualType(), IsConst);
- if (ElemTy == AST.DependentTy) {
+ if (IsTemplated)
ElemTy = MMB.addTemplateTypeParam("element_type");
- }
QualType AddrSpaceElemTy =
AST.getAddrSpaceQualType(ElemTy, LangAS::hlsl_device);
QualType ElemPtrTy = AST.getPointerType(AddrSpaceElemTy);
@@ -1383,11 +1394,16 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addHandleAccessFunction(
}
MMB.ReturnTy = ReturnTy;
- return MMB.addParam("Index", AST.UnsignedIntTy)
- .callBuiltin("__builtin_hlsl_resource_getpointer", ElemPtrTy, PH::Handle,
- PH::_0)
- .dereference(PH::LastStmt)
- .finalize();
+ MMB.addParam("Index", AST.UnsignedIntTy);
+
+ if (IsTemplated)
+ MMB.callBuiltin("__builtin_hlsl_resource_getpointer_typed", ElemPtrTy,
+ PH::Handle, PH::_0, ElemTy);
+ else
+ MMB.callBuiltin("__builtin_hlsl_resource_getpointer", ElemPtrTy, PH::Handle,
+ PH::_0);
+
+ return MMB.dereference(PH::LastStmt).finalize();
}
BuiltinTypeDeclBuilder &
@@ -1396,22 +1412,26 @@ BuiltinTypeDeclBuilder::addStoreFunction(DeclarationName &Name,
assert(!Record->isCompleteDefinition() && "record is already complete");
ASTContext &AST = SemaRef.getASTContext();
using PH = BuiltinTypeMethodBuilder::PlaceHolder;
+ bool IsTemplated = (ValueTy == AST.DependentTy);
BuiltinTypeMethodBuilder MMB(*this, Name, AST.VoidTy, IsConst);
- if (ValueTy == AST.DependentTy)
+ if (IsTemplated)
ValueTy = MMB.addTemplateTypeParam("element_type");
QualType AddrSpaceElemTy =
AST.getAddrSpaceQualType(ValueTy, LangAS::hlsl_device);
QualType ElemPtrTy = AST.getPointerType(AddrSpaceElemTy);
- return MMB.addParam("Index", AST.UnsignedIntTy)
- .addParam("Value", ValueTy)
- .callBuiltin("__builtin_hlsl_resource_getpointer", ElemPtrTy, PH::Handle,
- PH::_0)
- .dereference(PH::LastStmt)
- .assign(PH::LastStmt, PH::_1)
- .finalize();
+ MMB.addParam("Index", AST.UnsignedIntTy).addParam("Value", ValueTy);
+
+ if (IsTemplated)
+ MMB.callBuiltin("__builtin_hlsl_resource_getpointer_typed", ElemPtrTy,
+ PH::Handle, PH::_0, ValueTy);
+ else
+ MMB.callBuiltin("__builtin_hlsl_resource_getpointer", ElemPtrTy, PH::Handle,
+ PH::_0);
+
+ return MMB.dereference(PH::LastStmt).assign(PH::LastStmt, PH::_1).finalize();
}
BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addAppendMethod() {
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index f4961c3e9e55a..a09ff2eb99aa6 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3320,28 +3320,34 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
SemaRef.getASTContext().UnsignedIntTy))
return true;
- // Figure out the return type of the intrinsic. For most resources it is the
- // contained type. For ByteAddressBuffer it is determined by the type used
- // on the FunctionDecl.
auto *ResourceTy =
TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
- QualType ElementTy = ResourceTy->getContainedType();
- if (ResourceTy->isRaw() && !ResourceTy->isStructured()) {
- // Load method uses return type
- FunctionDecl *FD = dyn_cast<FunctionDecl>(SemaRef.CurContext);
- ElementTy = FD->getReturnType();
- // Store method uses 2nd parameter type
- if (ElementTy->isVoidType()) {
- assert(FD->getNumParams() == 2 &&
- "expected 2 parameters for Store method");
- ElementTy = FD->getParamDecl(1)->getType();
- }
+ QualType ContainedTy = ResourceTy->getContainedType();
+ auto ReturnType =
+ SemaRef.Context.getAddrSpaceQualType(ContainedTy, LangAS::hlsl_device);
+ ReturnType = SemaRef.Context.getPointerType(ReturnType);
+ TheCall->setType(ReturnType);
+ TheCall->setValueKind(VK_LValue);
- // Reject array types
- if (ElementTy->isArrayType())
- return SemaRef.Diag(FD->getPointOfInstantiation(),
- diag::err_invalid_use_of_array_type);
- }
+ break;
+ }
+ case Builtin::BI__builtin_hlsl_resource_getpointer_typed: {
+ if (SemaRef.checkArgCount(TheCall, 3) ||
+ CheckResourceHandle(&SemaRef, TheCall, 0) ||
+ CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
+ SemaRef.getASTContext().UnsignedIntTy))
+ return true;
+
+ QualType ElementTy = TheCall->getArg(2)->getType();
+ assert(ElementTy->isPointerType() &&
+ "expected pointer type for second argument");
+ ElementTy = ElementTy->getPointeeType();
+
+ // Reject array types
+ if (ElementTy->isArrayType())
+ return SemaRef.Diag(
+ cast<FunctionDecl>(SemaRef.CurContext)->getPointOfInstantiation(),
+ diag::err_invalid_use_of_array_type);
auto ReturnType =
SemaRef.Context.getAddrSpaceQualType(ElementTy, LangAS::hlsl_device);
@@ -3368,7 +3374,7 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
QualType ReturnType = ResourceTy->getContainedType();
if (ResourceTy->isRaw() && !ResourceTy->isStructured()) {
- FunctionDecl *FD = dyn_cast<FunctionDecl>(SemaRef.CurContext);
+ FunctionDecl *FD = cast<FunctionDecl>(SemaRef.CurContext);
ReturnType = FD->getReturnType();
// Reject array types
diff --git a/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl b/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
index a762e181ee221..317c895b9f840 100644
--- a/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
+++ b/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
@@ -273,10 +273,11 @@ RESOURCE Buffer;
// CHECK-LOAD-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' lvalue prefix '*' cannot overflow
// CHECK-LOAD-NEXT: CallExpr {{.*}} 'hlsl_device element_type *'
// CHECK-LOAD-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_getpointer_typed' 'void (...) noexcept'
// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
+// CHECK-LOAD-NEXT: CXXUnresolvedConstructExpr {{.*}} 'element_type *' 'element_type *'
// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
// CHECK-LOAD: CXXMethodDecl {{.*}} Load 'element_type (unsigned int, out unsigned int)
@@ -363,10 +364,11 @@ RESOURCE Buffer;
// CHECK-STORE-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' lvalue prefix '*' cannot overflow
// CHECK-STORE-NEXT: CallExpr {{.*}} 'hlsl_device element_type *'
// CHECK-STORE-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
-// CHECK-STORE-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
+// CHECK-STORE-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_getpointer_typed' 'void (...) noexcept'
// CHECK-STORE-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-STORE-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
+// CHECK-STORE-NEXT: CXXUnresolvedConstructExpr {{.*}} 'element_type *' 'element_type *'
// CHECK-STORE-NEXT: DeclRefExpr {{.*}} 'element_type' ParmVar {{.*}} 'Value' 'element_type'
// CHECK-STORE-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
diff --git a/clang/test/SemaHLSL/BuiltIns/ByteAddressBuffers.hlsl b/clang/test/SemaHLSL/BuiltIns/ByteAddressBuffers.hlsl
index d7d48bf427ea7..bd5759ddc0f04 100644
--- a/clang/test/SemaHLSL/BuiltIns/ByteAddressBuffers.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/ByteAddressBuffers.hlsl
@@ -3,7 +3,7 @@
ByteAddressBuffer Buf : register(t0);
RWByteAddressBuffer RWBuf : register(u0);
-int test_load_uint_array()[4] {
+uint test_load_uint_array()[4] {
return Buf.Load<uint[4]>(0);
// expected-error at -1 {{an array type is not allowed here}}
// expected-note at -2 {{in instantiation of function template specialization 'hlsl::ByteAddressBuffer::Load<unsigned int[4]>' requested here}}
@@ -15,7 +15,7 @@ float test_load_float_array()[2] {
// expected-note at -2 {{in instantiation of function template specialization 'hlsl::RWByteAddressBuffer::Load<float[2]>' requested here}}
}
-int test_load_uint_array_with_status()[4] {
+uint test_load_uint_array_with_status()[4] {
uint s1;
return RWBuf.Load<uint[4]>(0, s1);
// expected-error at -1 {{an array type is not allowed here}}
More information about the cfe-commits
mailing list