[clang] Implement `ByteAddressBuffer` Load/Store methods (PR #176058)
Kaitlin Peng via cfe-commits
cfe-commits at lists.llvm.org
Tue Jan 20 09:53:21 PST 2026
https://github.com/kmpeng updated https://github.com/llvm/llvm-project/pull/176058
>From 0189a078898dd3639f779e5166f9b09813e347a3 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/10] 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 7a639c858d21f..92e6c0bb77ac3 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4977,6 +4977,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 1b6c3714f7821..0ae3dfa6a2997 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -447,6 +447,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 868f894a03c49..2d149de61aac3 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,
@@ -449,6 +455,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");
@@ -747,7 +769,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;
}
@@ -1145,6 +1182,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 f15b274a65a53..8a4f9becf4440 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3334,7 +3334,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 2713cc19ea2be..f2f52945f72f0 100644
--- a/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
+++ b/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
@@ -142,9 +142,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 af8ba042d25863c7b2b6151fa437fe18b2c1578b 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/10] 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 0ae3dfa6a2997..9c753dd0aedc4 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -495,7 +495,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 2d149de61aac3..2b014a86b0e6e 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -1216,20 +1216,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;
}
@@ -1259,19 +1268,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 8a4f9becf4440..17b756830560b 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3341,10 +3341,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;
}
@@ -3358,10 +3356,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;
}
@@ -3372,8 +3368,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 f2f52945f72f0..d97c28275579d 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 \
@@ -142,12 +142,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 3e692ae8bf06249333d365469922b7e9cd317f00 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/10] 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 92e6c0bb77ac3..9d708b2980dfe 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4983,14 +4983,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 9c753dd0aedc4..c3337ada45ee0 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -400,6 +400,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});
@@ -432,6 +436,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);
}
@@ -449,65 +456,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 2b014a86b0e6e..c1d4e9299a502 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -1189,25 +1189,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();
};
@@ -1224,20 +1224,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;
@@ -1256,10 +1270,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();
};
@@ -1273,11 +1287,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 17b756830560b..704579394b4cc 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3309,6 +3309,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);
@@ -3330,6 +3335,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;
@@ -3346,22 +3356,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 d97c28275579d..7c2c51a895071 100644
--- a/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
+++ b/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
@@ -145,7 +145,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'
@@ -153,25 +153,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>'
@@ -179,25 +179,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>'
@@ -205,25 +205,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>'
@@ -231,25 +231,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'
@@ -257,87 +257,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 9f52ba82dd996a2ff654c7326a6ac74fa3caeca0 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/10] 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 9d708b2980dfe..344ff56f21a43 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4977,12 +4977,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 2a228d2896730..99bcf9c51e4dc 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 c3337ada45ee0..9ac87c6a3f12e 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -400,10 +400,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});
@@ -454,21 +450,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 c1d4e9299a502..9d2885c4c2e00 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -637,7 +637,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;
@@ -1195,10 +1196,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
@@ -1224,25 +1229,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 704579394b4cc..c3728d79dd662 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3309,11 +3309,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);
@@ -3335,7 +3335,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();
@@ -3344,18 +3344,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 3186e233cd3cf55c5e90dbcb72636f28bdf1c865 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/10] 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 9d2885c4c2e00..2a08bbfcf16ee 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -637,8 +637,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;
@@ -1264,11 +1263,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();
};
@@ -1283,10 +1287,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 eb65a28dba6ff..4a3df5de59fa2 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: CallExpr {{.*}} 'hlsl_device element_type *'
// CHECK-SUBSCRIPT-NEXT: ImplicitCastExpr {{.*}} <BuiltinFnToFnPtr>
// 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: CallExpr {{.*}} 'hlsl_device element_type *'
// CHECK-SUBSCRIPT-UAV-NEXT: ImplicitCastExpr {{.*}} <BuiltinFnToFnPtr>
// 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: CallExpr {{.*}} 'hlsl_device element_type *'
// CHECK-LOAD-NEXT: ImplicitCastExpr {{.*}} <BuiltinFnToFnPtr>
// 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: CallExpr {{.*}} 'hlsl_device element_type *'
// CHECK-APPEND-NEXT: ImplicitCastExpr {{.*}} <BuiltinFnToFnPtr>
// 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: CallExpr {{.*}} 'hlsl_device element_type *'
// CHECK-CONSUME-NEXT: ImplicitCastExpr {{.*}} <BuiltinFnToFnPtr>
// 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 762386c622dad..9a4a3e137e0c4 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: CallExpr {{.*}} 'hlsl_device element_type *'
// CHECK-NEXT: ImplicitCastExpr {{.*}} <BuiltinFnToFnPtr>
// 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: CallExpr {{.*}} 'hlsl_device element_type *'
// CHECK-UAV-NEXT: ImplicitCastExpr {{.*}} <BuiltinFnToFnPtr>
// 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: CallExpr {{.*}} 'hlsl_device element_type *'
// CHECK-NEXT: ImplicitCastExpr {{.*}} <BuiltinFnToFnPtr>
// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
>From dbb45a3e6d130864ba6ded3d2e85e862ce27b0cb 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/10] 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 344ff56f21a43..7a639c858d21f 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4977,12 +4977,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 99bcf9c51e4dc..2a228d2896730 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 9ac87c6a3f12e..98708f23a35e6 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -450,37 +450,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 c3728d79dd662..a705e5d9792f3 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3308,14 +3308,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);
@@ -3335,8 +3343,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();
}
@@ -3344,18 +3352,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 7c2c51a895071..212c8b0cbbb39 100644
--- a/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
+++ b/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
@@ -148,9 +148,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'
@@ -174,9 +175,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'
@@ -200,9 +202,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'
@@ -226,9 +229,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'
@@ -252,9 +256,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'
@@ -279,9 +284,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'
@@ -292,9 +299,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'
@@ -305,9 +314,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'
@@ -318,9 +329,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'
@@ -331,9 +344,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 f3bc01e2aee9489f7621461bdd25c824b66fe0d8 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/10] 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 2a08bbfcf16ee..fea27d487526c 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(); }
@@ -1189,25 +1186,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,
@@ -1219,34 +1224,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;
}
@@ -1263,14 +1241,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();
@@ -1280,23 +1261,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 a6aa781d5c59105a14afc544c338a60b7eef00ff 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/10] 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 a705e5d9792f3..f13026737ade7 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3321,6 +3321,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);
@@ -3346,7 +3351,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 432b9f83da82885723a35fe9c45ead3397021bda 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/10] 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 98708f23a35e6..cd0e057ce0658 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -432,7 +432,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 fea27d487526c..90465f0710fdb 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -1192,12 +1192,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",
@@ -1236,15 +1237,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 f13026737ade7..a4d8548f8af31 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3306,11 +3306,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);
@@ -3327,6 +3328,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);
@@ -3345,11 +3347,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();
@@ -3359,6 +3362,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 212c8b0cbbb39..c4496f099ef86 100644
--- a/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
+++ b/clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
@@ -156,6 +156,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'
@@ -183,6 +184,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'
@@ -210,6 +212,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'
@@ -237,6 +240,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'
@@ -264,6 +268,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 ef8d7b2a520eb628284c63a5f5bded27fc21fe03 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/10] 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 90465f0710fdb..4cc68f8c1f14f 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -522,8 +522,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) ||
More information about the cfe-commits
mailing list