[clang] [llvm] [HLSL] Add load overload with status (PR #166449)
Joshua Batista via llvm-commits
llvm-commits at lists.llvm.org
Thu Nov 20 15:54:16 PST 2025
https://github.com/bob80905 updated https://github.com/llvm/llvm-project/pull/166449
>From 99c97887389d5255905394052a766b7dee2129fd Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Thu, 30 Oct 2025 17:06:11 -0700
Subject: [PATCH 01/12] as far as I can go without adding CAFM
---
clang/include/clang/Basic/Builtins.td | 6 ++++
clang/lib/CodeGen/CGHLSLBuiltins.cpp | 11 ++++++
clang/lib/CodeGen/CGHLSLRuntime.h | 2 ++
clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 36 +++++++++++++++++++
clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h | 3 ++
clang/lib/Sema/SemaHLSL.cpp | 21 +++++++++++
.../StructuredBuffers-methods-lib.hlsl | 30 ++++++++++++++++
.../StructuredBuffers-methods-ps.hlsl | 33 +++++++++++++++++
llvm/include/llvm/IR/IntrinsicsDirectX.td | 4 +++
llvm/include/llvm/IR/IntrinsicsSPIRV.td | 3 ++
llvm/lib/Target/DirectX/DXILOpLowering.cpp | 11 ++++++
11 files changed, 160 insertions(+)
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 2b400b012d6ed..58f4b2ec0fb94 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4934,6 +4934,12 @@ def HLSLResourceGetPointer : LangBuiltin<"HLSL_LANG"> {
let Prototype = "void(...)";
}
+def HLSLResourceGetPointerWithStatus : LangBuiltin<"HLSL_LANG"> {
+ let Spellings = ["__builtin_hlsl_resource_getpointer_with_status"];
+ 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 fbf4a5722caed..69f9877a2bc1c 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -353,6 +353,17 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
RetTy, CGM.getHLSLRuntime().getCreateResourceGetPointerIntrinsic(),
ArrayRef<Value *>{HandleOp, IndexOp});
}
+ case Builtin::BI__builtin_hlsl_resource_getpointer_with_status: {
+ Value *HandleOp = EmitScalarExpr(E->getArg(0));
+ Value *IndexOp = EmitScalarExpr(E->getArg(1));
+ Value *StatusOp = EmitScalarExpr(E->getArg(2));
+
+ llvm::Type *RetTy = ConvertType(E->getType());
+ return Builder.CreateIntrinsic(
+ RetTy,
+ CGM.getHLSLRuntime().getCreateResourceGetPointerWithStatusIntrinsic(),
+ ArrayRef<Value *>{HandleOp, IndexOp, StatusOp});
+ }
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/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index d35df524fdc84..f965390d1e6fb 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -126,6 +126,8 @@ class CGHLSLRuntime {
GENERATE_HLSL_INTRINSIC_FUNCTION(CreateResourceGetPointer,
resource_getpointer)
+ GENERATE_HLSL_INTRINSIC_FUNCTION(CreateResourceGetPointerWithStatus,
+ resource_getpointer_with_status)
GENERATE_HLSL_INTRINSIC_FUNCTION(CreateHandleFromBinding,
resource_handlefrombinding)
GENERATE_HLSL_INTRINSIC_FUNCTION(CreateHandleFromImplicitBinding,
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index 066acf6f01a90..e3fbf11d862ae 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -1140,6 +1140,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addLoadMethods() {
DeclarationName Load(&II);
// TODO: We also need versions with status for CheckAccessFullyMapped.
addHandleAccessFunction(Load, /*IsConst=*/false, /*IsRef=*/false);
+ addHandleAccessFunctionWithStatus(Load, /*IsConst=*/false, /*IsRef=*/false);
return *this;
}
@@ -1232,6 +1233,41 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDecrementCounterMethod() {
.finalize();
}
+BuiltinTypeDeclBuilder &
+BuiltinTypeDeclBuilder::addHandleAccessFunctionWithStatus(DeclarationName &Name,
+ bool IsConst,
+ bool IsRef) {
+ assert(!Record->isCompleteDefinition() && "record is already complete");
+ ASTContext &AST = SemaRef.getASTContext();
+ using PH = BuiltinTypeMethodBuilder::PlaceHolder;
+
+ QualType ElemTy = getHandleElementType();
+ QualType AddrSpaceElemTy =
+ AST.getAddrSpaceQualType(ElemTy, LangAS::hlsl_device);
+ QualType ElemPtrTy = AST.getPointerType(AddrSpaceElemTy);
+ QualType ReturnTy;
+
+ if (IsRef) {
+ ReturnTy = AddrSpaceElemTy;
+ if (IsConst)
+ ReturnTy.addConst();
+ ReturnTy = AST.getLValueReferenceType(ReturnTy);
+ } else {
+ ReturnTy = ElemTy;
+ if (IsConst)
+ ReturnTy.addConst();
+ }
+
+ QualType StatusRefTy = AST.getLValueReferenceType(AST.UnsignedIntTy);
+ return BuiltinTypeMethodBuilder(*this, Name, ReturnTy, IsConst)
+ .addParam("Index", AST.UnsignedIntTy)
+ .addParam("Status", StatusRefTy)
+ .callBuiltin("__builtin_hlsl_resource_getpointer_with_status", ElemPtrTy,
+ PH::Handle, PH::_0, PH::_1)
+ .dereference(PH::LastStmt)
+ .finalize();
+}
+
BuiltinTypeDeclBuilder &
BuiltinTypeDeclBuilder::addHandleAccessFunction(DeclarationName &Name,
bool IsConst, bool IsRef) {
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
index 95e3a6c4fb2f1..07305ad19dc5d 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
@@ -91,6 +91,9 @@ class BuiltinTypeDeclBuilder {
BuiltinTypeDeclBuilder &addDecrementCounterMethod();
BuiltinTypeDeclBuilder &addHandleAccessFunction(DeclarationName &Name,
bool IsConst, bool IsRef);
+ BuiltinTypeDeclBuilder &
+ addHandleAccessFunctionWithStatus(DeclarationName &Name, bool IsConst,
+ bool IsRef);
BuiltinTypeDeclBuilder &addAppendMethod();
BuiltinTypeDeclBuilder &addConsumeMethod();
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 94a490a8f68dc..2e402deb25a01 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3010,6 +3010,27 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
break;
}
+ case Builtin::BI__builtin_hlsl_resource_getpointer_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))
+ return true;
+
+ auto *ResourceTy =
+ TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
+ QualType ContainedTy = ResourceTy->getContainedType();
+ auto ReturnType =
+ SemaRef.Context.getAddrSpaceQualType(ContainedTy, LangAS::hlsl_device);
+ ReturnType = SemaRef.Context.getPointerType(ReturnType);
+ TheCall->setType(ReturnType);
+ TheCall->setValueKind(VK_LValue);
+
+ break;
+ }
+
case Builtin::BI__builtin_hlsl_resource_uninitializedhandle: {
if (SemaRef.checkArgCount(TheCall, 1) ||
CheckResourceHandle(&SemaRef, TheCall, 0))
diff --git a/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-lib.hlsl b/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-lib.hlsl
index 1f248d0560006..f7d7371650320 100644
--- a/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-lib.hlsl
+++ b/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-lib.hlsl
@@ -104,6 +104,36 @@ export float TestLoad() {
// CHECK-NEXT: %[[VAL:.*]] = load float, ptr %[[PTR]]
// CHECK-NEXT: ret float %[[VAL]]
+export float TestLoadWithStatus() {
+ uint s1;
+ uint s2;
+ float ret = RWSB1.Load(1, s) + SB1.Load(2, s2);
+ ret += float(s1 + s2);
+ return ret;
+}
+
+// CHECK: define noundef nofpclass(nan inf) float @TestLoad()()
+// CHECK: call {{.*}} float @hlsl::RWStructuredBuffer<float>::Load(unsigned int)(ptr {{.*}} @RWSB1, i32 noundef 1)
+// CHECK: call {{.*}} float @hlsl::StructuredBuffer<float>::Load(unsigned int)(ptr {{.*}} @SB1, i32 noundef 2)
+// CHECK: add
+// CHECK: ret float
+
+// CHECK: define {{.*}} float @hlsl::RWStructuredBuffer<float>::Load(unsigned int)(ptr {{.*}} %this, i32 noundef %Index)
+// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RWStructuredBuffer", ptr %{{.*}}, i32 0, i32 0
+// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", float, 1, 0), ptr %__handle
+// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
+// DXIL-NEXT: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %[[HANDLE]], i32 %[[INDEX]])
+// CHECK-NEXT: %[[VAL:.*]] = load float, ptr %[[PTR]]
+// CHECK-NEXT: ret float %[[VAL]]
+
+// CHECK: define {{.*}} float @hlsl::StructuredBuffer<float>::Load(unsigned int)(ptr {{.*}} %this, i32 noundef %Index)
+// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::StructuredBuffer", ptr %{{.*}}, i32 0, i32 0
+// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", float, 0, 0), ptr %__handle
+// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
+// DXIL-NEXT: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f32_0_0t(target("dx.RawBuffer", float, 0, 0) %[[HANDLE]], i32 %[[INDEX]])
+// CHECK-NEXT: %[[VAL:.*]] = load float, ptr %[[PTR]]
+// CHECK-NEXT: ret float %[[VAL]]
+
export uint TestGetDimensions() {
uint dim1, dim2, dim3, stride1, stride2, stride3;
SB1.GetDimensions(dim1, stride1);
diff --git a/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-ps.hlsl b/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-ps.hlsl
index 25fa75965d686..2c90604ef7ce2 100644
--- a/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-ps.hlsl
+++ b/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-ps.hlsl
@@ -65,6 +65,39 @@ export float TestLoad() {
// CHECK-NEXT: %[[VAL:.*]] = load <2 x i32>, ptr %[[BUFPTR]]
// CHECK-NEXT: ret <2 x i32> %[[VAL]]
+export float TestLoadWithStatus() {
+ uint status;
+ uint status2;
+ float val = ROSB1.Load(10, status).x + ROSB2.Load(20, status2).x;
+ return val + float(status + status2);
+}
+
+// CHECK: define {{.*}} float @TestLoadWithStatus()()
+// CHECK: call {{.*}} float @hlsl::RasterizerOrderedStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @ROSB1, i32 noundef 10, ptr noundef nonnull align 4 dereferenceable(4) %status)
+// CHECK: call {{.*}} <2 x i32> @hlsl::RasterizerOrderedStructuredBuffer<int vector[2]>::Load(unsigned int, unsigned int&)(ptr {{.*}} @ROSB2, i32 noundef 20, ptr noundef nonnull align 4 dereferenceable(4) %status2)
+// CHECK: ret
+
+// CHECK: define {{.*}} float @hlsl::RasterizerOrderedStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %Index, ptr noundef nonnull align 4 dereferenceable(4) %Status)
+// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RasterizerOrderedStructuredBuffer", ptr {{.*}}, i32 0, i32 0
+// CHECK-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", float, 1, 1), ptr %__handle
+// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
+// CHECK-NEXT: %[[STATUS_HANDLE:.*]] = load ptr, ptr %Status.addr, align 4, !nonnull !3, !align !4
+// CHECK-NEXT: %[[STATUS:.*]] = load i32, ptr %[[STATUS_HANDLE]], align 4
+// DXIL-NEXT: %[[BUFPTR:.*]] = call ptr @llvm.dx.resource.getpointer.with.status.p0.tdx.RawBuffer_f32_1_1t(target("dx.RawBuffer", float, 1, 1) %[[HANDLE]], i32 %[[INDEX]], i32 %[[STATUS]])
+// CHECK-NEXT: %[[VAL:.*]] = load float, ptr %[[BUFPTR]]
+// CHECK-NEXT: ret float %[[VAL]]
+
+// CHECK: define {{.*}} <2 x i32> @hlsl::RasterizerOrderedStructuredBuffer<int vector[2]>::Load(unsigned int, unsigned int&)(ptr {{.*}} %Index, ptr noundef nonnull align 4 dereferenceable(4) %Status)
+// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RasterizerOrderedStructuredBuffer.0", ptr {{.*}}, i32 0, i32 0
+// CHECK-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", <2 x i32>, 1, 1), ptr %__handle
+// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
+// CHECK-NEXT: %[[STATUS_HANDLE:.*]] = load ptr, ptr %Status.addr, align 4, !nonnull !3, !align !4
+// CHECK-NEXT: %[[STATUS:.*]] = load i32, ptr %[[STATUS_HANDLE]], align 4
+// DXIL-NEXT: %[[BUFPTR:.*]] = call ptr @llvm.dx.resource.getpointer.with.status.p0.tdx.RawBuffer_v2i32_1_1t(target("dx.RawBuffer", <2 x i32>, 1, 1) %[[HANDLE]], i32 %[[INDEX]], i32 %[[STATUS]])
+// CHECK-NEXT: %[[VAL:.*]] = load <2 x i32>, ptr %[[BUFPTR]]
+// CHECK-NEXT: ret <2 x i32> %[[VAL]]
+
+
export uint TestGetDimensions() {
uint dim1, dim2, stride1, stride2;
ROSB1.GetDimensions(dim1, stride1);
diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td
index d6b85630eb979..3dfefc8a0eda5 100644
--- a/llvm/include/llvm/IR/IntrinsicsDirectX.td
+++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td
@@ -40,6 +40,10 @@ def int_dx_resource_getpointer
: DefaultAttrsIntrinsic<[llvm_anyptr_ty], [llvm_any_ty, llvm_i32_ty],
[IntrNoMem]>;
+def int_dx_resource_getpointer_with_status
+ : DefaultAttrsIntrinsic<[llvm_anyptr_ty], [llvm_any_ty, llvm_i32_ty, llvm_i32_ty],
+ [IntrNoMem]>;
+
def int_dx_resource_nonuniformindex
: DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem]>;
diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
index bc51fb639fd75..36d7aa24d864e 100644
--- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td
+++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
@@ -175,6 +175,9 @@ def int_spv_rsqrt : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty]
def int_spv_resource_getpointer
: DefaultAttrsIntrinsic<[llvm_anyptr_ty], [llvm_any_ty, llvm_i32_ty],
[IntrNoMem]>;
+ def int_spv_resource_getpointer_with_status
+ : DefaultAttrsIntrinsic<[llvm_anyptr_ty], [llvm_any_ty, llvm_i32_ty, llvm_i32_ty],
+ [IntrNoMem]>;
def int_spv_resource_nonuniformindex
: DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem]>;
diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
index 8720460cceb20..f46e066c2dbb3 100644
--- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp
+++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
@@ -657,6 +657,14 @@ class OpLowerer {
return false;
}
+ [[nodiscard]] bool lowerGetPointerWithStatus(Function &F) {
+ // These should have already been handled in DXILResourceAccess, so we can
+ // just clean up the dead prototype.
+ assert(F.user_empty() && "getpointer operations should have been removed");
+ F.eraseFromParent();
+ return false;
+ }
+
[[nodiscard]] bool lowerBufferStore(Function &F, bool IsRaw) {
const DataLayout &DL = F.getDataLayout();
IRBuilder<> &IRB = OpBuilder.getIRB();
@@ -933,6 +941,9 @@ class OpLowerer {
case Intrinsic::dx_resource_getpointer:
HasErrors |= lowerGetPointer(F);
break;
+ case Intrinsic::dx_resource_getpointer_with_status:
+ HasErrors |= lowerGetPointerWithStatus(F);
+ break;
case Intrinsic::dx_resource_nonuniformindex:
assert(!CleanupNURI &&
"overloaded llvm.dx.resource.nonuniformindex intrinsics?");
>From 06ad11a6df118dbbcf9441a63a3eca0750fe0c0c Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Tue, 4 Nov 2025 12:03:27 -0800
Subject: [PATCH 02/12] works without cafm
---
clang/include/clang/Basic/Builtins.td | 4 +-
clang/lib/CodeGen/CGHLSLBuiltins.cpp | 51 ++++++++++++++++---
clang/lib/CodeGen/CGHLSLRuntime.h | 5 +-
clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 9 ++--
clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h | 5 +-
clang/lib/Sema/SemaHLSL.cpp | 2 +-
.../StructuredBuffers-methods-lib.hlsl | 36 ++++++++-----
.../StructuredBuffers-methods-ps.hlsl | 24 +++++----
.../resources/TypedBuffers-methods.hlsl | 40 +++++++++++++++
llvm/include/llvm/IR/IntrinsicsDirectX.td | 2 +-
llvm/include/llvm/IR/IntrinsicsSPIRV.td | 2 +-
llvm/lib/Target/DirectX/DXILOpLowering.cpp | 6 +--
12 files changed, 139 insertions(+), 47 deletions(-)
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 58f4b2ec0fb94..f2b4c54a5ba6b 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4934,8 +4934,8 @@ def HLSLResourceGetPointer : LangBuiltin<"HLSL_LANG"> {
let Prototype = "void(...)";
}
-def HLSLResourceGetPointerWithStatus : LangBuiltin<"HLSL_LANG"> {
- let Spellings = ["__builtin_hlsl_resource_getpointer_with_status"];
+def HLSLResourceLoadWithStatus : LangBuiltin<"HLSL_LANG"> {
+ let Spellings = ["__builtin_hlsl_resource_load_with_status"];
let Attributes = [NoThrow];
let Prototype = "void(...)";
}
diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
index 69f9877a2bc1c..607cf523ddf78 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -353,16 +353,53 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
RetTy, CGM.getHLSLRuntime().getCreateResourceGetPointerIntrinsic(),
ArrayRef<Value *>{HandleOp, IndexOp});
}
- case Builtin::BI__builtin_hlsl_resource_getpointer_with_status: {
+ case Builtin::BI__builtin_hlsl_resource_load_with_status: {
Value *HandleOp = EmitScalarExpr(E->getArg(0));
Value *IndexOp = EmitScalarExpr(E->getArg(1));
- Value *StatusOp = EmitScalarExpr(E->getArg(2));
- llvm::Type *RetTy = ConvertType(E->getType());
- return Builder.CreateIntrinsic(
- RetTy,
- CGM.getHLSLRuntime().getCreateResourceGetPointerWithStatusIntrinsic(),
- ArrayRef<Value *>{HandleOp, IndexOp, StatusOp});
+ // Get the *address* of the status argument (since it's a reference)
+ LValue StatusLVal = EmitLValue(E->getArg(2));
+ Address StatusAddr = StatusLVal.getAddress();
+
+ QualType HandleTy = E->getArg(0)->getType();
+ const HLSLAttributedResourceType *RT =
+ HandleTy->getAs<HLSLAttributedResourceType>();
+ assert(RT && "Expected a resource type as first parameter");
+
+ Intrinsic::ID IntrID = RT->getAttrs().RawBuffer
+ ? llvm::Intrinsic::dx_resource_load_rawbuffer
+ : llvm::Intrinsic::dx_resource_load_typedbuffer;
+
+ llvm::Type *DataTy = ConvertType(E->getType());
+ llvm::Type *RetTy = llvm::StructType::get(Builder.getContext(),
+ {DataTy, Builder.getInt1Ty()});
+
+ SmallVector<Value *, 3> Args;
+ Args.push_back(HandleOp);
+ Args.push_back(IndexOp);
+
+ if (RT->getAttrs().RawBuffer) {
+ Args.push_back(Builder.getInt32(0)); // dummy offset
+ }
+
+ // Call the intrinsic (returns a struct)
+ Value *ResRet =
+ Builder.CreateIntrinsic(RetTy, IntrID, Args, {}, "ld.struct");
+
+ // Extract the loaded data (first element of the struct)
+ Value *LoadedValue = Builder.CreateExtractValue(ResRet, {0}, "ld.value");
+
+ // Extract the status bit (second element of the struct)
+ Value *StatusBit = Builder.CreateExtractValue(ResRet, {1}, "ld.status");
+
+ // Extend the status bit to a 32-bit integer
+ Value *ExtendedStatus =
+ Builder.CreateZExt(StatusBit, Builder.getInt32Ty(), "ld.status.ext");
+
+ // Store the extended status into the user's reference variable
+ Builder.CreateStore(ExtendedStatus, StatusAddr);
+
+ return LoadedValue;
}
case Builtin::BI__builtin_hlsl_resource_uninitializedhandle: {
llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType());
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index f965390d1e6fb..f6c654bd61ff5 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -126,8 +126,9 @@ class CGHLSLRuntime {
GENERATE_HLSL_INTRINSIC_FUNCTION(CreateResourceGetPointer,
resource_getpointer)
- GENERATE_HLSL_INTRINSIC_FUNCTION(CreateResourceGetPointerWithStatus,
- resource_getpointer_with_status)
+
+ GENERATE_HLSL_INTRINSIC_FUNCTION(CreateResourceLoadTypedBuffer,
+ resource_load_typedbuffer)
GENERATE_HLSL_INTRINSIC_FUNCTION(CreateHandleFromBinding,
resource_handlefrombinding)
GENERATE_HLSL_INTRINSIC_FUNCTION(CreateHandleFromImplicitBinding,
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index e3fbf11d862ae..bdbc2d4ce87b3 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -1140,7 +1140,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addLoadMethods() {
DeclarationName Load(&II);
// TODO: We also need versions with status for CheckAccessFullyMapped.
addHandleAccessFunction(Load, /*IsConst=*/false, /*IsRef=*/false);
- addHandleAccessFunctionWithStatus(Load, /*IsConst=*/false, /*IsRef=*/false);
+ addLoadWithStatusFunction(Load, /*IsConst=*/false, /*IsRef=*/false);
return *this;
}
@@ -1234,9 +1234,8 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDecrementCounterMethod() {
}
BuiltinTypeDeclBuilder &
-BuiltinTypeDeclBuilder::addHandleAccessFunctionWithStatus(DeclarationName &Name,
- bool IsConst,
- bool IsRef) {
+BuiltinTypeDeclBuilder::addLoadWithStatusFunction(DeclarationName &Name,
+ bool IsConst, bool IsRef) {
assert(!Record->isCompleteDefinition() && "record is already complete");
ASTContext &AST = SemaRef.getASTContext();
using PH = BuiltinTypeMethodBuilder::PlaceHolder;
@@ -1262,7 +1261,7 @@ BuiltinTypeDeclBuilder::addHandleAccessFunctionWithStatus(DeclarationName &Name,
return BuiltinTypeMethodBuilder(*this, Name, ReturnTy, IsConst)
.addParam("Index", AST.UnsignedIntTy)
.addParam("Status", StatusRefTy)
- .callBuiltin("__builtin_hlsl_resource_getpointer_with_status", ElemPtrTy,
+ .callBuiltin("__builtin_hlsl_resource_load_with_status", ElemPtrTy,
PH::Handle, PH::_0, PH::_1)
.dereference(PH::LastStmt)
.finalize();
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
index 07305ad19dc5d..4941b8b7952a2 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
@@ -91,9 +91,8 @@ class BuiltinTypeDeclBuilder {
BuiltinTypeDeclBuilder &addDecrementCounterMethod();
BuiltinTypeDeclBuilder &addHandleAccessFunction(DeclarationName &Name,
bool IsConst, bool IsRef);
- BuiltinTypeDeclBuilder &
- addHandleAccessFunctionWithStatus(DeclarationName &Name, bool IsConst,
- bool IsRef);
+ BuiltinTypeDeclBuilder &addLoadWithStatusFunction(DeclarationName &Name,
+ bool IsConst, bool IsRef);
BuiltinTypeDeclBuilder &addAppendMethod();
BuiltinTypeDeclBuilder &addConsumeMethod();
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 2e402deb25a01..f95a647b5679f 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3010,7 +3010,7 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
break;
}
- case Builtin::BI__builtin_hlsl_resource_getpointer_with_status: {
+ case Builtin::BI__builtin_hlsl_resource_load_with_status: {
if (SemaRef.checkArgCount(TheCall, 3) ||
CheckResourceHandle(&SemaRef, TheCall, 0) ||
CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
diff --git a/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-lib.hlsl b/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-lib.hlsl
index f7d7371650320..969586055b1d5 100644
--- a/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-lib.hlsl
+++ b/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-lib.hlsl
@@ -107,32 +107,42 @@ export float TestLoad() {
export float TestLoadWithStatus() {
uint s1;
uint s2;
- float ret = RWSB1.Load(1, s) + SB1.Load(2, s2);
+ float ret = RWSB1.Load(1, s1) + SB1.Load(2, s2);
ret += float(s1 + s2);
return ret;
}
-// CHECK: define noundef nofpclass(nan inf) float @TestLoad()()
-// CHECK: call {{.*}} float @hlsl::RWStructuredBuffer<float>::Load(unsigned int)(ptr {{.*}} @RWSB1, i32 noundef 1)
-// CHECK: call {{.*}} float @hlsl::StructuredBuffer<float>::Load(unsigned int)(ptr {{.*}} @SB1, i32 noundef 2)
+// CHECK: define noundef nofpclass(nan inf) float @TestLoadWithStatus()()
+// CHECK: call {{.*}} float @hlsl::RWStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @RWSB1, i32 noundef 1, ptr noundef nonnull align 4 dereferenceable(4) %s1)
+// CHECK: call {{.*}} float @hlsl::StructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @SB1, i32 noundef 2, ptr noundef nonnull align 4 dereferenceable(4) %s2)
// CHECK: add
// CHECK: ret float
-// CHECK: define {{.*}} float @hlsl::RWStructuredBuffer<float>::Load(unsigned int)(ptr {{.*}} %this, i32 noundef %Index)
+// CHECK: define {{.*}} float @hlsl::RWStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noundef nonnull align 4 dereferenceable(4) %Status)
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RWStructuredBuffer", ptr %{{.*}}, i32 0, i32 0
// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", float, 1, 0), ptr %__handle
// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
-// DXIL-NEXT: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %[[HANDLE]], i32 %[[INDEX]])
-// CHECK-NEXT: %[[VAL:.*]] = load float, ptr %[[PTR]]
-// CHECK-NEXT: ret float %[[VAL]]
-
-// CHECK: define {{.*}} float @hlsl::StructuredBuffer<float>::Load(unsigned int)(ptr {{.*}} %this, i32 noundef %Index)
+// CHECK-NEXT: %[[STATUS:.*]] = load ptr, ptr %Status.addr,
+// DXIL-NEXT: %[[STRUCT:.*]] = call { ptr, i1 } @llvm.dx.resource.load.rawbuffer.p0.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %[[HANDLE]], i32 %[[INDEX]], i32 0)
+// CHECK-NEXT: %[[VALUE:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 0
+// CHECK-NEXT: %[[STATUS_TEMP:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 1
+// CHECK-NEXT: %[[STATUS_EXT:.*]] = zext i1 %[[STATUS_TEMP]] to i32
+// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %2, align 4
+// CHECK-NEXT: %[[RETVAL:.*]] = load float, ptr %[[VALUE]]
+// CHECK-NEXT: ret float %[[RETVAL]]
+
+// CHECK: define {{.*}} float @hlsl::StructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noundef nonnull align 4 dereferenceable(4) %Status)
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::StructuredBuffer", ptr %{{.*}}, i32 0, i32 0
// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", float, 0, 0), ptr %__handle
// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
-// DXIL-NEXT: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f32_0_0t(target("dx.RawBuffer", float, 0, 0) %[[HANDLE]], i32 %[[INDEX]])
-// CHECK-NEXT: %[[VAL:.*]] = load float, ptr %[[PTR]]
-// CHECK-NEXT: ret float %[[VAL]]
+// CHECK-NEXT: %[[STATUS_HANDLE:.*]] = load ptr, ptr %Status.addr, align 4, !nonnull !3, !align !4
+// DXIL-NEXT: %[[STRUCT:.*]] = call { ptr, i1 } @llvm.dx.resource.load.rawbuffer.p0.tdx.RawBuffer_f32_0_0t(target("dx.RawBuffer", float, 0, 0) %0, i32 %1, i32 0)
+// CHECK-NEXT: %[[VALUE:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 0
+// CHECK-NEXT: %[[STATUS:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 1
+// CHECK-NEXT: %[[STATUS_EXT:.*]] = zext i1 %[[STATUS]] to i32
+// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %2, align 4
+// CHECK-NEXT: %[[RETVAL:.*]] = load float, ptr %[[VALUE]]
+// CHECK-NEXT: ret float %[[RETVAL]]
export uint TestGetDimensions() {
uint dim1, dim2, dim3, stride1, stride2, stride3;
diff --git a/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-ps.hlsl b/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-ps.hlsl
index 2c90604ef7ce2..38bb5ae7bb871 100644
--- a/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-ps.hlsl
+++ b/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-ps.hlsl
@@ -81,21 +81,27 @@ export float TestLoadWithStatus() {
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RasterizerOrderedStructuredBuffer", ptr {{.*}}, i32 0, i32 0
// CHECK-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", float, 1, 1), ptr %__handle
// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
-// CHECK-NEXT: %[[STATUS_HANDLE:.*]] = load ptr, ptr %Status.addr, align 4, !nonnull !3, !align !4
-// CHECK-NEXT: %[[STATUS:.*]] = load i32, ptr %[[STATUS_HANDLE]], align 4
-// DXIL-NEXT: %[[BUFPTR:.*]] = call ptr @llvm.dx.resource.getpointer.with.status.p0.tdx.RawBuffer_f32_1_1t(target("dx.RawBuffer", float, 1, 1) %[[HANDLE]], i32 %[[INDEX]], i32 %[[STATUS]])
-// CHECK-NEXT: %[[VAL:.*]] = load float, ptr %[[BUFPTR]]
-// CHECK-NEXT: ret float %[[VAL]]
+// CHECK-NEXT: %[[STATUS:.*]] = load ptr, ptr %Status.addr,
+// DXIL-NEXT: %[[STRUCT:.*]] = call { ptr, i1 } @llvm.dx.resource.load.rawbuffer.p0.tdx.RawBuffer_f32_1_1t(target("dx.RawBuffer", float, 1, 1) %[[HANDLE]], i32 %[[INDEX]], i32 0)
+// CHECK-NEXT: %[[VALUE:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 0
+// CHECK-NEXT: %[[STATUS_TEMP:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 1
+// CHECK-NEXT: %[[STATUS_EXT:.*]] = zext i1 %[[STATUS_TEMP]] to i32
+// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %2, align 4
+// CHECK-NEXT: %[[RETVAL:.*]] = load float, ptr %[[VALUE]]
+// CHECK-NEXT: ret float %[[RETVAL]]
// CHECK: define {{.*}} <2 x i32> @hlsl::RasterizerOrderedStructuredBuffer<int vector[2]>::Load(unsigned int, unsigned int&)(ptr {{.*}} %Index, ptr noundef nonnull align 4 dereferenceable(4) %Status)
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RasterizerOrderedStructuredBuffer.0", ptr {{.*}}, i32 0, i32 0
// CHECK-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", <2 x i32>, 1, 1), ptr %__handle
// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
// CHECK-NEXT: %[[STATUS_HANDLE:.*]] = load ptr, ptr %Status.addr, align 4, !nonnull !3, !align !4
-// CHECK-NEXT: %[[STATUS:.*]] = load i32, ptr %[[STATUS_HANDLE]], align 4
-// DXIL-NEXT: %[[BUFPTR:.*]] = call ptr @llvm.dx.resource.getpointer.with.status.p0.tdx.RawBuffer_v2i32_1_1t(target("dx.RawBuffer", <2 x i32>, 1, 1) %[[HANDLE]], i32 %[[INDEX]], i32 %[[STATUS]])
-// CHECK-NEXT: %[[VAL:.*]] = load <2 x i32>, ptr %[[BUFPTR]]
-// CHECK-NEXT: ret <2 x i32> %[[VAL]]
+// DXIL-NEXT: %[[STRUCT:.*]] = call { ptr, i1 } @llvm.dx.resource.load.rawbuffer.p0.tdx.RawBuffer_v2i32_1_1t(target("dx.RawBuffer", <2 x i32>, 1, 1) %0, i32 %1, i32 0)
+// CHECK-NEXT: %[[VALUE:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 0
+// CHECK-NEXT: %[[STATUS:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 1
+// CHECK-NEXT: %[[STATUS_EXT:.*]] = zext i1 %[[STATUS]] to i32
+// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %2, align 4
+// CHECK-NEXT: %[[RETVAL:.*]] = load <2 x i32>, ptr %[[VALUE]]
+// CHECK-NEXT: ret <2 x i32> %[[RETVAL]]
export uint TestGetDimensions() {
diff --git a/clang/test/CodeGenHLSL/resources/TypedBuffers-methods.hlsl b/clang/test/CodeGenHLSL/resources/TypedBuffers-methods.hlsl
index fdc1ef08b7c2c..c884b857f59bf 100644
--- a/clang/test/CodeGenHLSL/resources/TypedBuffers-methods.hlsl
+++ b/clang/test/CodeGenHLSL/resources/TypedBuffers-methods.hlsl
@@ -38,6 +38,46 @@ export float TestLoad() {
// CHECK-NEXT: %[[VEC:.*]] = load <4 x i32>, ptr %[[PTR]]
// CHECK-NEXT: ret <4 x i32> %[[VEC]]
+export float TestLoadWithStatus() {
+ uint s1;
+ uint s2;
+ float ret = Buf.Load(1, s1) + float(RWBuf.Load(2, s2).y);
+ ret += float(s1 + s2);
+ return ret;
+}
+
+// CHECK: define noundef nofpclass(nan inf) float @TestLoadWithStatus()()
+// CHECK: call {{.*}} float @hlsl::Buffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @Buf, i32 noundef 1, ptr noundef nonnull align 4 dereferenceable(4) %s1)
+// CHECK: call {{.*}} <4 x i32> @hlsl::RWBuffer<unsigned int vector[4]>::Load(unsigned int, unsigned int&)(ptr {{.*}} @RWBuf, i32 noundef 2, ptr noundef nonnull align 4 dereferenceable(4) %s2)
+// CHECK: add
+// CHECK: ret float
+
+// CHECK: define {{.*}} float @hlsl::Buffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noundef nonnull align 4 dereferenceable(4) %Status)
+// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::Buffer", ptr %{{.*}}, i32 0, i32 0
+// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.TypedBuffer", float, 0, 0, 0), ptr %__handle
+// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
+// CHECK-NEXT: %[[STATUS:.*]] = load ptr, ptr %Status.addr,
+// DXIL-NEXT: %[[STRUCT:.*]] = call { ptr, i1 } @llvm.dx.resource.load.typedbuffer.p0.tdx.TypedBuffer_f32_0_0_0t(target("dx.TypedBuffer", float, 0, 0, 0) %[[HANDLE]], i32 %[[INDEX]])
+// CHECK-NEXT: %[[VALUE:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 0
+// CHECK-NEXT: %[[STATUS_TEMP:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 1
+// CHECK-NEXT: %[[STATUS_EXT:.*]] = zext i1 %[[STATUS_TEMP]] to i32
+// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %2, align 4
+// CHECK-NEXT: %[[RETVAL:.*]] = load float, ptr %[[VALUE]]
+// CHECK-NEXT: ret float %[[RETVAL]]
+
+// CHECK: define {{.*}} <4 x i32> @hlsl::RWBuffer<unsigned int vector[4]>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noundef nonnull align 4 dereferenceable(4) %Status)
+// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RWBuffer", ptr %{{.*}}, i32 0, i32 0
+// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.TypedBuffer", <4 x i32>, 1, 0, 0), ptr %__handle
+// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
+// CHECK-NEXT: %[[STATUS_HANDLE:.*]] = load ptr, ptr %Status.addr, align 4, !nonnull !3, !align !4
+// DXIL-NEXT: %[[STRUCT:.*]] = call { ptr, i1 } @llvm.dx.resource.load.typedbuffer.p0.tdx.TypedBuffer_v4i32_1_0_0t(target("dx.TypedBuffer", <4 x i32>, 1, 0, 0) %0, i32 %1)
+// CHECK-NEXT: %[[VALUE:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 0
+// CHECK-NEXT: %[[STATUS:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 1
+// CHECK-NEXT: %[[STATUS_EXT:.*]] = zext i1 %[[STATUS]] to i32
+// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %2, align 4
+// CHECK-NEXT: %[[RETVAL:.*]] = load <4 x i32>, ptr %[[VALUE]]
+// CHECK-NEXT: ret <4 x i32> %[[RETVAL]]
+
export uint TestGetDimensions() {
uint dim1, dim2;
Buf.GetDimensions(dim1);
diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td
index 3dfefc8a0eda5..6c2d4e33881ee 100644
--- a/llvm/include/llvm/IR/IntrinsicsDirectX.td
+++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td
@@ -40,7 +40,7 @@ def int_dx_resource_getpointer
: DefaultAttrsIntrinsic<[llvm_anyptr_ty], [llvm_any_ty, llvm_i32_ty],
[IntrNoMem]>;
-def int_dx_resource_getpointer_with_status
+def int_dx_resource_load_with_status
: DefaultAttrsIntrinsic<[llvm_anyptr_ty], [llvm_any_ty, llvm_i32_ty, llvm_i32_ty],
[IntrNoMem]>;
diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
index 36d7aa24d864e..53ec4c3f5274d 100644
--- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td
+++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
@@ -175,7 +175,7 @@ def int_spv_rsqrt : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty]
def int_spv_resource_getpointer
: DefaultAttrsIntrinsic<[llvm_anyptr_ty], [llvm_any_ty, llvm_i32_ty],
[IntrNoMem]>;
- def int_spv_resource_getpointer_with_status
+ def int_spv_resource_load_with_status
: DefaultAttrsIntrinsic<[llvm_anyptr_ty], [llvm_any_ty, llvm_i32_ty, llvm_i32_ty],
[IntrNoMem]>;
diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
index f46e066c2dbb3..bb1cc4f098b6e 100644
--- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp
+++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
@@ -657,7 +657,7 @@ class OpLowerer {
return false;
}
- [[nodiscard]] bool lowerGetPointerWithStatus(Function &F) {
+ [[nodiscard]] bool lowerLoadWithStatus(Function &F) {
// These should have already been handled in DXILResourceAccess, so we can
// just clean up the dead prototype.
assert(F.user_empty() && "getpointer operations should have been removed");
@@ -941,8 +941,8 @@ class OpLowerer {
case Intrinsic::dx_resource_getpointer:
HasErrors |= lowerGetPointer(F);
break;
- case Intrinsic::dx_resource_getpointer_with_status:
- HasErrors |= lowerGetPointerWithStatus(F);
+ case Intrinsic::dx_resource_load_with_status:
+ HasErrors |= lowerLoadWithStatus(F);
break;
case Intrinsic::dx_resource_nonuniformindex:
assert(!CleanupNURI &&
>From ec4e3a94c44b2b36f80137ad7528f75315991bb4 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Thu, 6 Nov 2025 12:48:51 -0800
Subject: [PATCH 03/12] furthest checkpoint yet
---
clang/lib/CodeGen/CGHLSLBuiltins.cpp | 10 +++++----
clang/lib/CodeGen/CGHLSLRuntime.h | 3 ---
clang/lib/Headers/hlsl/hlsl_intrinsics.h | 2 ++
clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 17 +++++----------
clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h | 2 +-
.../test/AST/HLSL/StructuredBuffers-AST.hlsl | 21 +++++++++++++++++++
clang/test/AST/HLSL/TypedBuffers-AST.hlsl | 20 ++++++++++++++++++
7 files changed, 55 insertions(+), 20 deletions(-)
diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
index 607cf523ddf78..a7aed9229f2c9 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -370,9 +370,11 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
? llvm::Intrinsic::dx_resource_load_rawbuffer
: llvm::Intrinsic::dx_resource_load_typedbuffer;
- llvm::Type *DataTy = ConvertType(E->getType());
- llvm::Type *RetTy = llvm::StructType::get(Builder.getContext(),
- {DataTy, Builder.getInt1Ty()});
+ QualType BuiltinRetTy = E->getType();
+ llvm::Type *DataTy = ConvertType(BuiltinRetTy->getPointeeType());
+
+ llvm::Type *IntrinsicRetTy = llvm::StructType::get(
+ Builder.getContext(), {DataTy, Builder.getInt1Ty()});
SmallVector<Value *, 3> Args;
Args.push_back(HandleOp);
@@ -384,7 +386,7 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
// Call the intrinsic (returns a struct)
Value *ResRet =
- Builder.CreateIntrinsic(RetTy, IntrID, Args, {}, "ld.struct");
+ Builder.CreateIntrinsic(IntrinsicRetTy, IntrID, Args, {}, "ld.struct");
// Extract the loaded data (first element of the struct)
Value *LoadedValue = Builder.CreateExtractValue(ResRet, {0}, "ld.value");
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index f6c654bd61ff5..d35df524fdc84 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -126,9 +126,6 @@ class CGHLSLRuntime {
GENERATE_HLSL_INTRINSIC_FUNCTION(CreateResourceGetPointer,
resource_getpointer)
-
- GENERATE_HLSL_INTRINSIC_FUNCTION(CreateResourceLoadTypedBuffer,
- resource_load_typedbuffer)
GENERATE_HLSL_INTRINSIC_FUNCTION(CreateHandleFromBinding,
resource_handlefrombinding)
GENERATE_HLSL_INTRINSIC_FUNCTION(CreateHandleFromImplicitBinding,
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index 5ba5bfb9abde0..6663ae9e0d762 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -605,5 +605,7 @@ smoothstep(__detail::HLSL_FIXED_VECTOR<float, N> Min,
return __detail::smoothstep_vec_impl(Min, Max, X);
}
+bool CheckAccessFullyMapped(uint Status) { return static_cast<bool>(Status); }
+
} // namespace hlsl
#endif //_HLSL_HLSL_INTRINSICS_H_
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index bdbc2d4ce87b3..ced93c5b220b5 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -1140,7 +1140,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addLoadMethods() {
DeclarationName Load(&II);
// TODO: We also need versions with status for CheckAccessFullyMapped.
addHandleAccessFunction(Load, /*IsConst=*/false, /*IsRef=*/false);
- addLoadWithStatusFunction(Load, /*IsConst=*/false, /*IsRef=*/false);
+ addLoadWithStatusFunction(Load, /*IsConst=*/false);
return *this;
}
@@ -1235,7 +1235,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDecrementCounterMethod() {
BuiltinTypeDeclBuilder &
BuiltinTypeDeclBuilder::addLoadWithStatusFunction(DeclarationName &Name,
- bool IsConst, bool IsRef) {
+ bool IsConst) {
assert(!Record->isCompleteDefinition() && "record is already complete");
ASTContext &AST = SemaRef.getASTContext();
using PH = BuiltinTypeMethodBuilder::PlaceHolder;
@@ -1246,16 +1246,9 @@ BuiltinTypeDeclBuilder::addLoadWithStatusFunction(DeclarationName &Name,
QualType ElemPtrTy = AST.getPointerType(AddrSpaceElemTy);
QualType ReturnTy;
- if (IsRef) {
- ReturnTy = AddrSpaceElemTy;
- if (IsConst)
- ReturnTy.addConst();
- ReturnTy = AST.getLValueReferenceType(ReturnTy);
- } else {
- ReturnTy = ElemTy;
- if (IsConst)
- ReturnTy.addConst();
- }
+ ReturnTy = ElemTy;
+ if (IsConst)
+ ReturnTy.addConst();
QualType StatusRefTy = AST.getLValueReferenceType(AST.UnsignedIntTy);
return BuiltinTypeMethodBuilder(*this, Name, ReturnTy, IsConst)
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
index 4941b8b7952a2..47c8b0e225612 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
@@ -92,7 +92,7 @@ class BuiltinTypeDeclBuilder {
BuiltinTypeDeclBuilder &addHandleAccessFunction(DeclarationName &Name,
bool IsConst, bool IsRef);
BuiltinTypeDeclBuilder &addLoadWithStatusFunction(DeclarationName &Name,
- bool IsConst, bool IsRef);
+ bool IsConst);
BuiltinTypeDeclBuilder &addAppendMethod();
BuiltinTypeDeclBuilder &addConsumeMethod();
diff --git a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl
index 7a8c57c59643d..8f8208c40bc33 100644
--- a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl
+++ b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl
@@ -326,6 +326,27 @@ RESOURCE<float> Buffer;
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
+// Load with status method
+
+// CHECK-LOAD: CXXMethodDecl {{.*}} Load 'element_type (unsigned int, unsigned int &)'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Status 'unsigned int &'
+// CHECK-LOAD-NEXT: CompoundStmt
+// CHECK-LOAD-NEXT: ReturnStmt
+// CHECK-LOAD-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' 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_load_with_status' 'void (...) noexcept'
+// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-LOAD-UAV-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
+// CHECK-LOAD-SRV-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
+// CHECK-LOAD-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
+// CHECK-LOAD-SAME: lvalue .__handle {{.*}}
+// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue implicit this
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Status' 'unsigned int &'
+// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
+
// IncrementCounter method
// CHECK-COUNTER: CXXMethodDecl {{.*}} IncrementCounter 'unsigned int ()'
diff --git a/clang/test/AST/HLSL/TypedBuffers-AST.hlsl b/clang/test/AST/HLSL/TypedBuffers-AST.hlsl
index 14e274d3855ed..bd81b87b72e9c 100644
--- a/clang/test/AST/HLSL/TypedBuffers-AST.hlsl
+++ b/clang/test/AST/HLSL/TypedBuffers-AST.hlsl
@@ -214,6 +214,26 @@ RESOURCE<float> Buffer;
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
// CHECK-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
+// Load with status method
+// CHECK-NEXT: CXXMethodDecl {{.*}} Load 'element_type (unsigned int, unsigned int &)'
+// CHECK-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
+// CHECK-NEXT: ParmVarDecl {{.*}} Status 'unsigned int &'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' prefix '*' cannot overflow
+// CHECK-NEXT: CallExpr {{.*}} 'hlsl_device element_type *'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} <BuiltinFnToFnPtr>
+// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_load_with_status' 'void (...) noexcept'
+// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
+// CHECK-UAV-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
+// CHECK-SRV-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
+// CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
+// CHECK-SAME: lvalue .__handle {{.*}}
+// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue implicit this
+// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Status' 'unsigned int &'
+// CHECK-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
+
// GetDimensions method
// CHECK-NEXT: CXXMethodDecl {{.*}} GetDimensions 'void (out unsigned int)'
>From 2a49c36987b1e4af875c8da9bed6c865c00e8da0 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Mon, 10 Nov 2025 14:28:26 -0800
Subject: [PATCH 04/12] fix up function definition, add TiledResources shader
flag
---
clang/lib/CodeGen/CGHLSLBuiltins.cpp | 12 ++++----
clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 29 +++++++++----------
clang/lib/Sema/SemaHLSL.cpp | 8 ++---
.../resources/TypedBuffers-methods.hlsl | 6 ++--
llvm/lib/Target/DirectX/DXILShaderFlags.cpp | 28 ++++++++++++++++++
5 files changed, 51 insertions(+), 32 deletions(-)
diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
index a7aed9229f2c9..6256b3d3d3760 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -357,7 +357,7 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
Value *HandleOp = EmitScalarExpr(E->getArg(0));
Value *IndexOp = EmitScalarExpr(E->getArg(1));
- // Get the *address* of the status argument (since it's a reference)
+ // Get the *address* of the status argument to write to it by reference
LValue StatusLVal = EmitLValue(E->getArg(2));
Address StatusAddr = StatusLVal.getAddress();
@@ -370,11 +370,9 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
? llvm::Intrinsic::dx_resource_load_rawbuffer
: llvm::Intrinsic::dx_resource_load_typedbuffer;
- QualType BuiltinRetTy = E->getType();
- llvm::Type *DataTy = ConvertType(BuiltinRetTy->getPointeeType());
-
- llvm::Type *IntrinsicRetTy = llvm::StructType::get(
- Builder.getContext(), {DataTy, Builder.getInt1Ty()});
+ llvm::Type *DataTy = ConvertType(E->getType());
+ llvm::Type *RetTy = llvm::StructType::get(Builder.getContext(),
+ {DataTy, Builder.getInt1Ty()});
SmallVector<Value *, 3> Args;
Args.push_back(HandleOp);
@@ -386,7 +384,7 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
// Call the intrinsic (returns a struct)
Value *ResRet =
- Builder.CreateIntrinsic(IntrinsicRetTy, IntrID, Args, {}, "ld.struct");
+ Builder.CreateIntrinsic(RetTy, IntrID, Args, {}, "ld.struct");
// Extract the loaded data (first element of the struct)
Value *LoadedValue = Builder.CreateExtractValue(ResRet, {0}, "ld.value");
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index ced93c5b220b5..284d5ff0177e9 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -202,7 +202,7 @@ struct BuiltinTypeMethodBuilder {
BuiltinTypeMethodBuilder &declareLocalVar(LocalVar &Var);
template <typename... Ts>
BuiltinTypeMethodBuilder &callBuiltin(StringRef BuiltinName,
- QualType ReturnType, Ts... ArgSpecs);
+ QualType ReturnType, Ts &&...ArgSpecs);
template <typename TLHS, typename TRHS>
BuiltinTypeMethodBuilder &assign(TLHS LHS, TRHS RHS);
template <typename T> BuiltinTypeMethodBuilder &dereference(T Ptr);
@@ -572,7 +572,7 @@ BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::returnThis() {
template <typename... Ts>
BuiltinTypeMethodBuilder &
BuiltinTypeMethodBuilder::callBuiltin(StringRef BuiltinName,
- QualType ReturnType, Ts... ArgSpecs) {
+ QualType ReturnType, Ts &&...ArgSpecs) {
ensureCompleteDecl();
std::array<Expr *, sizeof...(ArgSpecs)> Args{
@@ -1240,23 +1240,20 @@ BuiltinTypeDeclBuilder::addLoadWithStatusFunction(DeclarationName &Name,
ASTContext &AST = SemaRef.getASTContext();
using PH = BuiltinTypeMethodBuilder::PlaceHolder;
- QualType ElemTy = getHandleElementType();
- QualType AddrSpaceElemTy =
- AST.getAddrSpaceQualType(ElemTy, LangAS::hlsl_device);
- QualType ElemPtrTy = AST.getPointerType(AddrSpaceElemTy);
- QualType ReturnTy;
-
- ReturnTy = ElemTy;
- if (IsConst)
- ReturnTy.addConst();
+ QualType ReturnTy = getHandleElementType();
+ BuiltinTypeMethodBuilder::LocalVar ResultVar("Result", ReturnTy);
+ BuiltinTypeMethodBuilder::LocalVar StatusVar("StatusBool", AST.BoolTy);
- QualType StatusRefTy = AST.getLValueReferenceType(AST.UnsignedIntTy);
return BuiltinTypeMethodBuilder(*this, Name, ReturnTy, IsConst)
.addParam("Index", AST.UnsignedIntTy)
- .addParam("Status", StatusRefTy)
- .callBuiltin("__builtin_hlsl_resource_load_with_status", ElemPtrTy,
- PH::Handle, PH::_0, PH::_1)
- .dereference(PH::LastStmt)
+ .addParam("Status", AST.UnsignedIntTy, HLSLParamModifierAttr::Keyword_out)
+ .declareLocalVar(ResultVar)
+ .declareLocalVar(StatusVar)
+ .callBuiltin("__builtin_hlsl_resource_load_with_status", ReturnTy,
+ PH::Handle, PH::_0, StatusVar)
+ .assign(ResultVar, PH::LastStmt)
+ .assign(PH::_1, StatusVar)
+ .returnValue(ResultVar)
.finalize();
}
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index f95a647b5679f..8cc737d83376c 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3016,17 +3016,13 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
SemaRef.getASTContext().UnsignedIntTy) ||
CheckArgTypeMatches(&SemaRef, TheCall->getArg(2),
- SemaRef.getASTContext().UnsignedIntTy))
+ SemaRef.getASTContext().BoolTy))
return true;
auto *ResourceTy =
TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
- QualType ContainedTy = ResourceTy->getContainedType();
- auto ReturnType =
- SemaRef.Context.getAddrSpaceQualType(ContainedTy, LangAS::hlsl_device);
- ReturnType = SemaRef.Context.getPointerType(ReturnType);
+ QualType ReturnType = ResourceTy->getContainedType();
TheCall->setType(ReturnType);
- TheCall->setValueKind(VK_LValue);
break;
}
diff --git a/clang/test/CodeGenHLSL/resources/TypedBuffers-methods.hlsl b/clang/test/CodeGenHLSL/resources/TypedBuffers-methods.hlsl
index c884b857f59bf..5960a1c406fc4 100644
--- a/clang/test/CodeGenHLSL/resources/TypedBuffers-methods.hlsl
+++ b/clang/test/CodeGenHLSL/resources/TypedBuffers-methods.hlsl
@@ -47,12 +47,12 @@ export float TestLoadWithStatus() {
}
// CHECK: define noundef nofpclass(nan inf) float @TestLoadWithStatus()()
-// CHECK: call {{.*}} float @hlsl::Buffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @Buf, i32 noundef 1, ptr noundef nonnull align 4 dereferenceable(4) %s1)
-// CHECK: call {{.*}} <4 x i32> @hlsl::RWBuffer<unsigned int vector[4]>::Load(unsigned int, unsigned int&)(ptr {{.*}} @RWBuf, i32 noundef 2, ptr noundef nonnull align 4 dereferenceable(4) %s2)
+// CHECK: call {{.*}} float @hlsl::Buffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @Buf, i32 noundef 1, ptr noalias noundef nonnull align 4 dereferenceable(4) %tmp)
+// CHECK: call {{.*}} <4 x i32> @hlsl::RWBuffer<unsigned int vector[4]>::Load(unsigned int, unsigned int&)(ptr {{.*}} @RWBuf, i32 noundef 2, ptr noalias noundef nonnull align 4 dereferenceable(4) %tmp1)
// CHECK: add
// CHECK: ret float
-// CHECK: define {{.*}} float @hlsl::Buffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noundef nonnull align 4 dereferenceable(4) %Status)
+// CHECK: define {{.*}} float @hlsl::Buffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noalias noundef nonnull align 4 dereferenceable(4) %Status)
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::Buffer", ptr %{{.*}}, i32 0, i32 0
// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.TypedBuffer", float, 0, 0, 0), ptr %__handle
// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
diff --git a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
index ce6e8121b9d94..4b08b019e52f0 100644
--- a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
+++ b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
@@ -100,6 +100,27 @@ static bool checkWaveOps(Intrinsic::ID IID) {
}
}
+// Checks to see if the status bit from a load with status
+// instruction is ever extracted.
+// This is our proof that the module requires TiledResources
+// to be set, as if check access fully mapped was used.
+bool checkIfStatusIsExtracted(const Instruction &I) {
+ // Iterate over all uses of the instruction
+ for (const Use &U : I.uses()) {
+ const User *UserInst = U.getUser();
+
+ // Check if the user is an ExtractValue instruction
+ if (const ExtractValueInst *EVI = dyn_cast<ExtractValueInst>(UserInst)) {
+ // ExtractValueInst has a list of indices; check if it extracts index 1
+ if (EVI->getNumIndices() == 1 && EVI->getIndices()[0] == 1) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
/// Update the shader flags mask based on the given instruction.
/// \param CSF Shader flags mask to update.
/// \param I Instruction to check.
@@ -192,6 +213,13 @@ void ModuleShaderFlags::updateFunctionFlags(ComputedShaderFlags &CSF,
DRTM[cast<TargetExtType>(II->getArgOperand(0)->getType())];
if (RTI.isTyped())
CSF.TypedUAVLoadAdditionalFormats |= RTI.getTyped().ElementCount > 1;
+ if (!CSF.TiledResources && checkIfStatusIsExtracted(I))
+ CSF.TiledResources = true;
+ break;
+ }
+ case Intrinsic::dx_resource_load_rawbuffer: {
+ if (!CSF.TiledResources && checkIfStatusIsExtracted(I))
+ CSF.TiledResources = true;
break;
}
}
>From 0d0b79f224b13585c385d82736c6f737837c9106 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Mon, 10 Nov 2025 19:13:18 -0800
Subject: [PATCH 05/12] update tests, make checkaccess inline so it doesn't get
auto-emitted into every IR output
---
clang/lib/Headers/hlsl/hlsl_intrinsics.h | 4 +-
.../test/AST/HLSL/StructuredBuffers-AST.hlsl | 23 ++++++---
clang/test/AST/HLSL/TypedBuffers-AST.hlsl | 23 ++++++---
.../StructuredBuffers-methods-lib.hlsl | 50 +++++++++++--------
.../StructuredBuffers-methods-ps.hlsl | 50 +++++++++++--------
.../resources/TypedBuffers-methods.hlsl | 44 +++++++++-------
6 files changed, 122 insertions(+), 72 deletions(-)
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index 6663ae9e0d762..c6bb4d2ca8cc5 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -605,7 +605,9 @@ smoothstep(__detail::HLSL_FIXED_VECTOR<float, N> Min,
return __detail::smoothstep_vec_impl(Min, Max, X);
}
-bool CheckAccessFullyMapped(uint Status) { return static_cast<bool>(Status); }
+inline bool CheckAccessFullyMapped(uint Status) {
+ return static_cast<bool>(Status);
+}
} // namespace hlsl
#endif //_HLSL_HLSL_INTRINSICS_H_
diff --git a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl
index 8f8208c40bc33..b7111fe53eb23 100644
--- a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl
+++ b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl
@@ -328,23 +328,32 @@ RESOURCE<float> Buffer;
// Load with status method
-// CHECK-LOAD: CXXMethodDecl {{.*}} Load 'element_type (unsigned int, unsigned int &)'
+// 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 &'
+// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Status 'unsigned int &__restrict'
+// CHECK-LOAD-NEXT: HLSLParamModifierAttr {{.*}} out
// CHECK-LOAD-NEXT: CompoundStmt
-// CHECK-LOAD-NEXT: ReturnStmt
-// CHECK-LOAD-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' prefix '*' cannot overflow
-// CHECK-LOAD-NEXT: CallExpr {{.*}} 'hlsl_device element_type *'
+// CHECK-LOAD-NEXT: DeclStmt
+// CHECK-LOAD-NEXT: VarDecl {{.*}} Result 'element_type'
+// CHECK-LOAD-NEXT: DeclStmt
+// CHECK-LOAD-NEXT: VarDecl {{.*}} StatusBool 'bool'
+// CHECK-LOAD-NEXT: BinaryOperator {{.*}} 'element_type' '='
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'element_type' lvalue Var {{.*}} 'Result' 'element_type'
+// CHECK-LOAD-NEXT: CallExpr {{.*}} 'element_type'
// CHECK-LOAD-NEXT: ImplicitCastExpr {{.*}} <BuiltinFnToFnPtr>
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_load_with_status' 'void (...) noexcept'
// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
// CHECK-LOAD-UAV-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-LOAD-SRV-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
// CHECK-LOAD-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
-// CHECK-LOAD-SAME: lvalue .__handle {{.*}}
// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue implicit this
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Status' 'unsigned int &'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'bool' lvalue Var {{.*}} 'StatusBool' 'bool'
+// CHECK-LOAD-NEXT: BinaryOperator {{.*}} 'unsigned int' '='
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Status' 'unsigned int &__restrict'
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'bool' lvalue Var {{.*}} 'StatusBool' 'bool'
+// CHECK-LOAD-NEXT: ReturnStmt
+// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'element_type' lvalue Var {{.*}} 'Result' 'element_type'
// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
// IncrementCounter method
diff --git a/clang/test/AST/HLSL/TypedBuffers-AST.hlsl b/clang/test/AST/HLSL/TypedBuffers-AST.hlsl
index bd81b87b72e9c..8fb30eea7eb5b 100644
--- a/clang/test/AST/HLSL/TypedBuffers-AST.hlsl
+++ b/clang/test/AST/HLSL/TypedBuffers-AST.hlsl
@@ -215,23 +215,32 @@ RESOURCE<float> Buffer;
// CHECK-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
// Load with status method
-// CHECK-NEXT: CXXMethodDecl {{.*}} Load 'element_type (unsigned int, unsigned int &)'
+// CHECK: CXXMethodDecl {{.*}} Load 'element_type (unsigned int, out unsigned int)'
// CHECK-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
-// CHECK-NEXT: ParmVarDecl {{.*}} Status 'unsigned int &'
+// CHECK-NEXT: ParmVarDecl {{.*}} Status 'unsigned int &__restrict'
+// CHECK-NEXT: HLSLParamModifierAttr {{.*}} out
// CHECK-NEXT: CompoundStmt
-// CHECK-NEXT: ReturnStmt
-// CHECK-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' prefix '*' cannot overflow
-// CHECK-NEXT: CallExpr {{.*}} 'hlsl_device element_type *'
+// CHECK-NEXT: DeclStmt
+// CHECK-NEXT: VarDecl {{.*}} Result 'element_type'
+// CHECK-NEXT: DeclStmt
+// CHECK-NEXT: VarDecl {{.*}} StatusBool 'bool'
+// CHECK-NEXT: BinaryOperator {{.*}} 'element_type' '='
+// CHECK-NEXT: DeclRefExpr {{.*}} 'element_type' lvalue Var {{.*}} 'Result' 'element_type'
+// CHECK-NEXT: CallExpr {{.*}} 'element_type'
// CHECK-NEXT: ImplicitCastExpr {{.*}} <BuiltinFnToFnPtr>
// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_load_with_status' 'void (...) noexcept'
// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
// CHECK-UAV-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SRV-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
-// CHECK-SAME: lvalue .__handle {{.*}}
// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue implicit this
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
-// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Status' 'unsigned int &'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'bool' lvalue Var {{.*}} 'StatusBool' 'bool'
+// CHECK-NEXT: BinaryOperator {{.*}} 'unsigned int' '='
+// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Status' 'unsigned int &__restrict'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'bool' lvalue Var {{.*}} 'StatusBool' 'bool'
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: DeclRefExpr {{.*}} 'element_type' lvalue Var {{.*}} 'Result' 'element_type'
// CHECK-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
// GetDimensions method
diff --git a/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-lib.hlsl b/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-lib.hlsl
index 969586055b1d5..2c48cf7e35346 100644
--- a/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-lib.hlsl
+++ b/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-lib.hlsl
@@ -113,36 +113,46 @@ export float TestLoadWithStatus() {
}
// CHECK: define noundef nofpclass(nan inf) float @TestLoadWithStatus()()
-// CHECK: call {{.*}} float @hlsl::RWStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @RWSB1, i32 noundef 1, ptr noundef nonnull align 4 dereferenceable(4) %s1)
-// CHECK: call {{.*}} float @hlsl::StructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @SB1, i32 noundef 2, ptr noundef nonnull align 4 dereferenceable(4) %s2)
+// CHECK: call {{.*}} float @hlsl::RWStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @RWSB1, i32 noundef 1, ptr noalias noundef nonnull align 4 dereferenceable(4) %tmp)
+// CHECK: call {{.*}} float @hlsl::StructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @SB1, i32 noundef 2, ptr noalias noundef nonnull align 4 dereferenceable(4) %tmp1)
// CHECK: add
// CHECK: ret float
-// CHECK: define {{.*}} float @hlsl::RWStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noundef nonnull align 4 dereferenceable(4) %Status)
+// CHECK: define {{.*}} float @hlsl::RWStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noalias noundef nonnull align 4 dereferenceable(4) %Status)
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RWStructuredBuffer", ptr %{{.*}}, i32 0, i32 0
// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", float, 1, 0), ptr %__handle
// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
-// CHECK-NEXT: %[[STATUS:.*]] = load ptr, ptr %Status.addr,
-// DXIL-NEXT: %[[STRUCT:.*]] = call { ptr, i1 } @llvm.dx.resource.load.rawbuffer.p0.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %[[HANDLE]], i32 %[[INDEX]], i32 0)
-// CHECK-NEXT: %[[VALUE:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 0
-// CHECK-NEXT: %[[STATUS_TEMP:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 1
+// DXIL-NEXT: %[[STRUCT:.*]] = call { float, i1 } @llvm.dx.resource.load.rawbuffer.f32.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %[[HANDLE]], i32 %[[INDEX]], i32 0)
+// 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 %2, align 4
-// CHECK-NEXT: %[[RETVAL:.*]] = load float, ptr %[[VALUE]]
-// CHECK-NEXT: ret float %[[RETVAL]]
-
-// CHECK: define {{.*}} float @hlsl::StructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noundef nonnull align 4 dereferenceable(4) %Status)
+// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %StatusBool, align 4
+// CHECK-NEXT: store float %ld.value, ptr %Result, align 4
+// CHECK-NEXT: %[[STATUS_INT:.*]] = load i32, ptr %StatusBool, align 4
+// CHECK-NEXT: %[[LOADED_VALUE:.*]] = trunc i32 %[[STATUS_INT]] to i1
+// CHECK-NEXT: %[[ZEXT_VALUE:.*]] = zext i1 %[[LOADED_VALUE]] to i32
+// CHECK-NEXT: %[[LOADED_STATUS_ADDR:.*]] = load ptr, ptr %Status.addr, align 4
+// CHECK-NEXT: store i32 %[[ZEXT_VALUE]], ptr %[[LOADED_STATUS_ADDR]], align 4
+// CHECK-NEXT: %[[RETURN_VALUE:.*]] = load float, ptr %Result, align 4
+// CHECK-NEXT: ret float %[[RETURN_VALUE]]
+
+// CHECK: define {{.*}} float @hlsl::StructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noalias noundef nonnull align 4 dereferenceable(4) %Status)
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::StructuredBuffer", ptr %{{.*}}, i32 0, i32 0
// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", float, 0, 0), ptr %__handle
// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
-// CHECK-NEXT: %[[STATUS_HANDLE:.*]] = load ptr, ptr %Status.addr, align 4, !nonnull !3, !align !4
-// DXIL-NEXT: %[[STRUCT:.*]] = call { ptr, i1 } @llvm.dx.resource.load.rawbuffer.p0.tdx.RawBuffer_f32_0_0t(target("dx.RawBuffer", float, 0, 0) %0, i32 %1, i32 0)
-// CHECK-NEXT: %[[VALUE:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 0
-// CHECK-NEXT: %[[STATUS:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 1
-// CHECK-NEXT: %[[STATUS_EXT:.*]] = zext i1 %[[STATUS]] to i32
-// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %2, align 4
-// CHECK-NEXT: %[[RETVAL:.*]] = load float, ptr %[[VALUE]]
-// CHECK-NEXT: ret float %[[RETVAL]]
+// DXIL-NEXT: %[[STRUCT:.*]] = call { float, i1 } @llvm.dx.resource.load.rawbuffer.f32.tdx.RawBuffer_f32_0_0t(target("dx.RawBuffer", float, 0, 0) %[[HANDLE]], i32 %[[INDEX]], i32 0)
+// 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 %StatusBool, align 4
+// CHECK-NEXT: store float %ld.value, ptr %Result, align 4
+// CHECK-NEXT: %[[STATUS_INT:.*]] = load i32, ptr %StatusBool, align 4
+// CHECK-NEXT: %[[LOADED_VALUE:.*]] = trunc i32 %[[STATUS_INT]] to i1
+// CHECK-NEXT: %[[ZEXT_VALUE:.*]] = zext i1 %[[LOADED_VALUE]] to i32
+// CHECK-NEXT: %[[LOADED_STATUS_ADDR:.*]] = load ptr, ptr %Status.addr, align 4
+// CHECK-NEXT: store i32 %[[ZEXT_VALUE]], ptr %[[LOADED_STATUS_ADDR]], align 4
+// CHECK-NEXT: %[[RETURN_VALUE:.*]] = load float, ptr %Result, align 4
+// CHECK-NEXT: ret float %[[RETURN_VALUE]]
export uint TestGetDimensions() {
uint dim1, dim2, dim3, stride1, stride2, stride3;
diff --git a/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-ps.hlsl b/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-ps.hlsl
index 38bb5ae7bb871..58c18940b81ca 100644
--- a/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-ps.hlsl
+++ b/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-ps.hlsl
@@ -73,35 +73,45 @@ export float TestLoadWithStatus() {
}
// CHECK: define {{.*}} float @TestLoadWithStatus()()
-// CHECK: call {{.*}} float @hlsl::RasterizerOrderedStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @ROSB1, i32 noundef 10, ptr noundef nonnull align 4 dereferenceable(4) %status)
-// CHECK: call {{.*}} <2 x i32> @hlsl::RasterizerOrderedStructuredBuffer<int vector[2]>::Load(unsigned int, unsigned int&)(ptr {{.*}} @ROSB2, i32 noundef 20, ptr noundef nonnull align 4 dereferenceable(4) %status2)
+// CHECK: call {{.*}} float @hlsl::RasterizerOrderedStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @ROSB1, i32 noundef 10, ptr noalias noundef nonnull align 4 dereferenceable(4) %tmp)
+// CHECK: call {{.*}} <2 x i32> @hlsl::RasterizerOrderedStructuredBuffer<int vector[2]>::Load(unsigned int, unsigned int&)(ptr {{.*}} @ROSB2, i32 noundef 20, ptr noalias noundef nonnull align 4 dereferenceable(4) %tmp2)
// CHECK: ret
-// CHECK: define {{.*}} float @hlsl::RasterizerOrderedStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %Index, ptr noundef nonnull align 4 dereferenceable(4) %Status)
+// CHECK: define {{.*}} float @hlsl::RasterizerOrderedStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noalias noundef nonnull align 4 dereferenceable(4) %Status)
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RasterizerOrderedStructuredBuffer", ptr {{.*}}, i32 0, i32 0
// CHECK-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", float, 1, 1), ptr %__handle
// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
-// CHECK-NEXT: %[[STATUS:.*]] = load ptr, ptr %Status.addr,
-// DXIL-NEXT: %[[STRUCT:.*]] = call { ptr, i1 } @llvm.dx.resource.load.rawbuffer.p0.tdx.RawBuffer_f32_1_1t(target("dx.RawBuffer", float, 1, 1) %[[HANDLE]], i32 %[[INDEX]], i32 0)
-// CHECK-NEXT: %[[VALUE:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 0
-// CHECK-NEXT: %[[STATUS_TEMP:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 1
+// DXIL-NEXT: %[[STRUCT:.*]] = call { float, i1 } @llvm.dx.resource.load.rawbuffer.f32.tdx.RawBuffer_f32_1_1t(target("dx.RawBuffer", float, 1, 1) %[[HANDLE]], i32 %[[INDEX]], i32 0)
+// 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 %2, align 4
-// CHECK-NEXT: %[[RETVAL:.*]] = load float, ptr %[[VALUE]]
-// CHECK-NEXT: ret float %[[RETVAL]]
-
-// CHECK: define {{.*}} <2 x i32> @hlsl::RasterizerOrderedStructuredBuffer<int vector[2]>::Load(unsigned int, unsigned int&)(ptr {{.*}} %Index, ptr noundef nonnull align 4 dereferenceable(4) %Status)
+// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %StatusBool, align 4
+// CHECK-NEXT: store float %ld.value, ptr %Result, align 4
+// CHECK-NEXT: %[[STATUS_INT:.*]] = load i32, ptr %StatusBool, align 4
+// CHECK-NEXT: %[[LOADED_VALUE:.*]] = trunc i32 %[[STATUS_INT]] to i1
+// CHECK-NEXT: %[[ZEXT_VALUE:.*]] = zext i1 %[[LOADED_VALUE]] to i32
+// CHECK-NEXT: %[[LOADED_STATUS_ADDR:.*]] = load ptr, ptr %Status.addr, align 4
+// CHECK-NEXT: store i32 %[[ZEXT_VALUE]], ptr %[[LOADED_STATUS_ADDR]], align 4
+// CHECK-NEXT: %[[RETURN_VALUE:.*]] = load float, ptr %Result, align 4
+// CHECK-NEXT: ret float %[[RETURN_VALUE]]
+
+// CHECK: define {{.*}} <2 x i32> @hlsl::RasterizerOrderedStructuredBuffer<int vector[2]>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noalias noundef nonnull align 4 dereferenceable(4) %Status)
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RasterizerOrderedStructuredBuffer.0", ptr {{.*}}, i32 0, i32 0
// CHECK-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", <2 x i32>, 1, 1), ptr %__handle
// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
-// CHECK-NEXT: %[[STATUS_HANDLE:.*]] = load ptr, ptr %Status.addr, align 4, !nonnull !3, !align !4
-// DXIL-NEXT: %[[STRUCT:.*]] = call { ptr, i1 } @llvm.dx.resource.load.rawbuffer.p0.tdx.RawBuffer_v2i32_1_1t(target("dx.RawBuffer", <2 x i32>, 1, 1) %0, i32 %1, i32 0)
-// CHECK-NEXT: %[[VALUE:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 0
-// CHECK-NEXT: %[[STATUS:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 1
-// CHECK-NEXT: %[[STATUS_EXT:.*]] = zext i1 %[[STATUS]] to i32
-// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %2, align 4
-// CHECK-NEXT: %[[RETVAL:.*]] = load <2 x i32>, ptr %[[VALUE]]
-// CHECK-NEXT: ret <2 x i32> %[[RETVAL]]
+// DXIL-NEXT: %[[STRUCT:.*]] = call { <2 x i32>, i1 } @llvm.dx.resource.load.rawbuffer.v2i32.tdx.RawBuffer_v2i32_1_1t(target("dx.RawBuffer", <2 x i32>, 1, 1) %[[HANDLE]], i32 %[[INDEX]], i32 0)
+// CHECK-NEXT: %[[VALUE:.*]] = extractvalue { <2 x i32>, i1 } %[[STRUCT]], 0
+// CHECK-NEXT: %[[STATUS_TEMP:.*]] = extractvalue { <2 x i32>, i1 } %[[STRUCT]], 1
+// CHECK-NEXT: %[[STATUS_EXT:.*]] = zext i1 %[[STATUS_TEMP]] to i32
+// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %StatusBool, align 4
+// CHECK-NEXT: store <2 x i32> %ld.value, ptr %Result, align 8
+// CHECK-NEXT: %[[STATUS_INT:.*]] = load i32, ptr %StatusBool, align 4
+// CHECK-NEXT: %[[LOADED_VALUE:.*]] = trunc i32 %[[STATUS_INT]] to i1
+// CHECK-NEXT: %[[ZEXT_VALUE:.*]] = zext i1 %[[LOADED_VALUE]] to i32
+// CHECK-NEXT: %[[LOADED_STATUS_ADDR:.*]] = load ptr, ptr %Status.addr, align 4
+// CHECK-NEXT: store i32 %[[ZEXT_VALUE]], ptr %[[LOADED_STATUS_ADDR]], align 4
+// CHECK-NEXT: %[[RETURN_VALUE:.*]] = load <2 x i32>, ptr %Result, align 8
+// CHECK-NEXT: ret <2 x i32> %[[RETURN_VALUE]]
export uint TestGetDimensions() {
diff --git a/clang/test/CodeGenHLSL/resources/TypedBuffers-methods.hlsl b/clang/test/CodeGenHLSL/resources/TypedBuffers-methods.hlsl
index 5960a1c406fc4..5d28a01d4839f 100644
--- a/clang/test/CodeGenHLSL/resources/TypedBuffers-methods.hlsl
+++ b/clang/test/CodeGenHLSL/resources/TypedBuffers-methods.hlsl
@@ -56,27 +56,37 @@ export float TestLoadWithStatus() {
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::Buffer", ptr %{{.*}}, i32 0, i32 0
// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.TypedBuffer", float, 0, 0, 0), ptr %__handle
// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
-// CHECK-NEXT: %[[STATUS:.*]] = load ptr, ptr %Status.addr,
-// DXIL-NEXT: %[[STRUCT:.*]] = call { ptr, i1 } @llvm.dx.resource.load.typedbuffer.p0.tdx.TypedBuffer_f32_0_0_0t(target("dx.TypedBuffer", float, 0, 0, 0) %[[HANDLE]], i32 %[[INDEX]])
-// CHECK-NEXT: %[[VALUE:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 0
-// CHECK-NEXT: %[[STATUS_TEMP:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 1
+// DXIL-NEXT: %[[STRUCT:.*]] = call { float, i1 } @llvm.dx.resource.load.typedbuffer.f32.tdx.TypedBuffer_f32_0_0_0t(target("dx.TypedBuffer", float, 0, 0, 0) %[[HANDLE]], i32 %[[INDEX]])
+// 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 %2, align 4
-// CHECK-NEXT: %[[RETVAL:.*]] = load float, ptr %[[VALUE]]
-// CHECK-NEXT: ret float %[[RETVAL]]
-
-// CHECK: define {{.*}} <4 x i32> @hlsl::RWBuffer<unsigned int vector[4]>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noundef nonnull align 4 dereferenceable(4) %Status)
+// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %StatusBool, align 4
+// CHECK-NEXT: store float %ld.value, ptr %Result, align 4
+// CHECK-NEXT: %[[STATUS_INT:.*]] = load i32, ptr %StatusBool, align 4
+// CHECK-NEXT: %[[LOADED_VALUE:.*]] = trunc i32 %[[STATUS_INT]] to i1
+// CHECK-NEXT: %[[ZEXT_VALUE:.*]] = zext i1 %[[LOADED_VALUE]] to i32
+// CHECK-NEXT: %[[LOADED_STATUS_ADDR:.*]] = load ptr, ptr %Status.addr, align 4
+// CHECK-NEXT: store i32 %[[ZEXT_VALUE]], ptr %[[LOADED_STATUS_ADDR]], align 4
+// CHECK-NEXT: %[[RETURN_VALUE:.*]] = load float, ptr %Result, align 4
+// CHECK-NEXT: ret float %[[RETURN_VALUE]]
+
+// CHECK: define {{.*}} <4 x i32> @hlsl::RWBuffer<unsigned int vector[4]>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noalias noundef nonnull align 4 dereferenceable(4) %Status)
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RWBuffer", ptr %{{.*}}, i32 0, i32 0
// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.TypedBuffer", <4 x i32>, 1, 0, 0), ptr %__handle
// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
-// CHECK-NEXT: %[[STATUS_HANDLE:.*]] = load ptr, ptr %Status.addr, align 4, !nonnull !3, !align !4
-// DXIL-NEXT: %[[STRUCT:.*]] = call { ptr, i1 } @llvm.dx.resource.load.typedbuffer.p0.tdx.TypedBuffer_v4i32_1_0_0t(target("dx.TypedBuffer", <4 x i32>, 1, 0, 0) %0, i32 %1)
-// CHECK-NEXT: %[[VALUE:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 0
-// CHECK-NEXT: %[[STATUS:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 1
-// CHECK-NEXT: %[[STATUS_EXT:.*]] = zext i1 %[[STATUS]] to i32
-// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %2, align 4
-// CHECK-NEXT: %[[RETVAL:.*]] = load <4 x i32>, ptr %[[VALUE]]
-// CHECK-NEXT: ret <4 x i32> %[[RETVAL]]
+// DXIL-NEXT: %[[STRUCT:.*]] = call { <4 x i32>, i1 } @llvm.dx.resource.load.typedbuffer.v4i32.tdx.TypedBuffer_v4i32_1_0_0t(target("dx.TypedBuffer", <4 x i32>, 1, 0, 0) %[[HANDLE]], i32 %[[INDEX]])
+// 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 %StatusBool, align 4
+// CHECK-NEXT: store <4 x i32> %ld.value, ptr %Result, align 16
+// CHECK-NEXT: %[[STATUS_INT:.*]] = load i32, ptr %StatusBool, align 4
+// CHECK-NEXT: %[[LOADED_VALUE:.*]] = trunc i32 %[[STATUS_INT]] to i1
+// CHECK-NEXT: %[[ZEXT_VALUE:.*]] = zext i1 %[[LOADED_VALUE]] to i32
+// CHECK-NEXT: %[[LOADED_STATUS_ADDR:.*]] = load ptr, ptr %Status.addr, align 4
+// CHECK-NEXT: store i32 %[[ZEXT_VALUE]], ptr %[[LOADED_STATUS_ADDR]], align 4
+// CHECK-NEXT: %[[RETURN_VALUE:.*]] = load <4 x i32>, ptr %Result, align 16
+// CHECK-NEXT: ret <4 x i32> %[[RETURN_VALUE]]
export uint TestGetDimensions() {
uint dim1, dim2;
>From 8cc846b73a6900cf18a835cd59a484d4742e4d95 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Tue, 11 Nov 2025 14:19:18 -0800
Subject: [PATCH 06/12] address Justin
---
clang/lib/CodeGen/CGHLSLBuiltins.cpp | 15 +++++++++------
llvm/include/llvm/IR/IntrinsicsDirectX.td | 4 ----
llvm/lib/Target/DirectX/DXILOpLowering.cpp | 11 -----------
llvm/lib/Target/DirectX/DXILShaderFlags.cpp | 19 ++++++++++---------
4 files changed, 19 insertions(+), 30 deletions(-)
diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
index 6256b3d3d3760..1084016465a65 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -365,6 +365,8 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
const HLSLAttributedResourceType *RT =
HandleTy->getAs<HLSLAttributedResourceType>();
assert(RT && "Expected a resource type as first parameter");
+ assert(CGM.getTarget().getTriple().getArch() == llvm::Triple::dxil &&
+ "Only DXIL currently implements load with status");
Intrinsic::ID IntrID = RT->getAttrs().RawBuffer
? llvm::Intrinsic::dx_resource_load_rawbuffer
@@ -379,24 +381,25 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
Args.push_back(IndexOp);
if (RT->getAttrs().RawBuffer) {
- Args.push_back(Builder.getInt32(0)); // dummy offset
+ Value *Offset = Builder.getInt32(0);
+ Args.push_back(Offset);
}
- // Call the intrinsic (returns a struct)
+ // Call the intrinsic (returns a struct),
+ // Extract the loaded value and status bit (elements within the struct)
+ // Extend the status bit to a 32-bit integer
+ // Store the extended status into the user's reference variable
+ // Return the loaded value
Value *ResRet =
Builder.CreateIntrinsic(RetTy, IntrID, Args, {}, "ld.struct");
- // Extract the loaded data (first element of the struct)
Value *LoadedValue = Builder.CreateExtractValue(ResRet, {0}, "ld.value");
- // Extract the status bit (second element of the struct)
Value *StatusBit = Builder.CreateExtractValue(ResRet, {1}, "ld.status");
- // Extend the status bit to a 32-bit integer
Value *ExtendedStatus =
Builder.CreateZExt(StatusBit, Builder.getInt32Ty(), "ld.status.ext");
- // Store the extended status into the user's reference variable
Builder.CreateStore(ExtendedStatus, StatusAddr);
return LoadedValue;
diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td
index 6c2d4e33881ee..d6b85630eb979 100644
--- a/llvm/include/llvm/IR/IntrinsicsDirectX.td
+++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td
@@ -40,10 +40,6 @@ def int_dx_resource_getpointer
: DefaultAttrsIntrinsic<[llvm_anyptr_ty], [llvm_any_ty, llvm_i32_ty],
[IntrNoMem]>;
-def int_dx_resource_load_with_status
- : DefaultAttrsIntrinsic<[llvm_anyptr_ty], [llvm_any_ty, llvm_i32_ty, llvm_i32_ty],
- [IntrNoMem]>;
-
def int_dx_resource_nonuniformindex
: DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem]>;
diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
index bb1cc4f098b6e..8720460cceb20 100644
--- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp
+++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
@@ -657,14 +657,6 @@ class OpLowerer {
return false;
}
- [[nodiscard]] bool lowerLoadWithStatus(Function &F) {
- // These should have already been handled in DXILResourceAccess, so we can
- // just clean up the dead prototype.
- assert(F.user_empty() && "getpointer operations should have been removed");
- F.eraseFromParent();
- return false;
- }
-
[[nodiscard]] bool lowerBufferStore(Function &F, bool IsRaw) {
const DataLayout &DL = F.getDataLayout();
IRBuilder<> &IRB = OpBuilder.getIRB();
@@ -941,9 +933,6 @@ class OpLowerer {
case Intrinsic::dx_resource_getpointer:
HasErrors |= lowerGetPointer(F);
break;
- case Intrinsic::dx_resource_load_with_status:
- HasErrors |= lowerLoadWithStatus(F);
- break;
case Intrinsic::dx_resource_nonuniformindex:
assert(!CleanupNURI &&
"overloaded llvm.dx.resource.nonuniformindex intrinsics?");
diff --git a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
index 4b08b019e52f0..f99fcdef646ea 100644
--- a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
+++ b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
@@ -105,16 +105,17 @@ static bool checkWaveOps(Intrinsic::ID IID) {
// This is our proof that the module requires TiledResources
// to be set, as if check access fully mapped was used.
bool checkIfStatusIsExtracted(const Instruction &I) {
- // Iterate over all uses of the instruction
- for (const Use &U : I.uses()) {
- const User *UserInst = U.getUser();
-
- // Check if the user is an ExtractValue instruction
- if (const ExtractValueInst *EVI = dyn_cast<ExtractValueInst>(UserInst)) {
- // ExtractValueInst has a list of indices; check if it extracts index 1
- if (EVI->getNumIndices() == 1 && EVI->getIndices()[0] == 1) {
+ auto *II = dyn_cast<IntrinsicInst>(&I);
+ assert(II);
+ auto IID = II->getIntrinsicID();
+ assert(IID == Intrinsic::dx_resource_load_typedbuffer ||
+ IID == Intrinsic::dx_resource_load_rawbuffer);
+ for (const User *U : I.users()) {
+ if (const ExtractValueInst *EVI = dyn_cast<ExtractValueInst>(U)) {
+ // Resource load operations return a {result, status} pair
+ // check if we extract the status
+ if (EVI->getNumIndices() == 1 && EVI->getIndices()[0] == 1)
return true;
- }
}
}
>From 673c1a534f4e6bb7f263e005e8e3653d020fdf26 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Tue, 11 Nov 2025 14:20:51 -0800
Subject: [PATCH 07/12] remove spirv intrinsic
---
llvm/include/llvm/IR/IntrinsicsSPIRV.td | 3 ---
1 file changed, 3 deletions(-)
diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
index 53ec4c3f5274d..bc51fb639fd75 100644
--- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td
+++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
@@ -175,9 +175,6 @@ def int_spv_rsqrt : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty]
def int_spv_resource_getpointer
: DefaultAttrsIntrinsic<[llvm_anyptr_ty], [llvm_any_ty, llvm_i32_ty],
[IntrNoMem]>;
- def int_spv_resource_load_with_status
- : DefaultAttrsIntrinsic<[llvm_anyptr_ty], [llvm_any_ty, llvm_i32_ty, llvm_i32_ty],
- [IntrNoMem]>;
def int_spv_resource_nonuniformindex
: DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem]>;
>From 3f124bad68b7e5638f8e1e0623d100d7330359f6 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Tue, 11 Nov 2025 17:15:51 -0800
Subject: [PATCH 08/12] address Justin
---
clang/lib/CodeGen/CGHLSLBuiltins.cpp | 11 ++---------
llvm/lib/Target/DirectX/DXILShaderFlags.cpp | 16 +++++++++-------
2 files changed, 11 insertions(+), 16 deletions(-)
diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
index 1084016465a65..df9b488f6f580 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -385,21 +385,14 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
Args.push_back(Offset);
}
- // Call the intrinsic (returns a struct),
- // Extract the loaded value and status bit (elements within the struct)
- // Extend the status bit to a 32-bit integer
- // Store the extended status into the user's reference variable
- // Return the loaded value
+ // 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, IntrID, 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;
diff --git a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
index f99fcdef646ea..805225f0f7f9d 100644
--- a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
+++ b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
@@ -104,13 +104,15 @@ static bool checkWaveOps(Intrinsic::ID IID) {
// instruction is ever extracted.
// This is our proof that the module requires TiledResources
// to be set, as if check access fully mapped was used.
-bool checkIfStatusIsExtracted(const Instruction &I) {
- auto *II = dyn_cast<IntrinsicInst>(&I);
- assert(II);
+bool checkIfStatusIsExtracted(const Instruction *I) {
+ auto *II = dyn_cast<IntrinsicInst>(I);
+ assert(II && "intrinsic instruction expected in checkIfStatusIsExtracted");
auto IID = II->getIntrinsicID();
assert(IID == Intrinsic::dx_resource_load_typedbuffer ||
- IID == Intrinsic::dx_resource_load_rawbuffer);
- for (const User *U : I.users()) {
+ IID == Intrinsic::dx_resource_load_rawbuffer &&
+ "unexpected intrinsic ID, only dx_resource_load_typedbuffer and "
+ "dx_resource_load_rawbuffer are expected");
+ for (const User *U : I->users()) {
if (const ExtractValueInst *EVI = dyn_cast<ExtractValueInst>(U)) {
// Resource load operations return a {result, status} pair
// check if we extract the status
@@ -214,12 +216,12 @@ void ModuleShaderFlags::updateFunctionFlags(ComputedShaderFlags &CSF,
DRTM[cast<TargetExtType>(II->getArgOperand(0)->getType())];
if (RTI.isTyped())
CSF.TypedUAVLoadAdditionalFormats |= RTI.getTyped().ElementCount > 1;
- if (!CSF.TiledResources && checkIfStatusIsExtracted(I))
+ if (!CSF.TiledResources && checkIfStatusIsExtracted(&I))
CSF.TiledResources = true;
break;
}
case Intrinsic::dx_resource_load_rawbuffer: {
- if (!CSF.TiledResources && checkIfStatusIsExtracted(I))
+ if (!CSF.TiledResources && checkIfStatusIsExtracted(&I))
CSF.TiledResources = true;
break;
}
>From 5bbfc7f309a301d28038e8cb90ed8b2d5d0744f1 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Tue, 11 Nov 2025 17:31:37 -0800
Subject: [PATCH 09/12] a further simplification
---
llvm/lib/Target/DirectX/DXILShaderFlags.cpp | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
index 805225f0f7f9d..04b8f1c6fdd5d 100644
--- a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
+++ b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
@@ -104,15 +104,13 @@ static bool checkWaveOps(Intrinsic::ID IID) {
// instruction is ever extracted.
// This is our proof that the module requires TiledResources
// to be set, as if check access fully mapped was used.
-bool checkIfStatusIsExtracted(const Instruction *I) {
- auto *II = dyn_cast<IntrinsicInst>(I);
- assert(II && "intrinsic instruction expected in checkIfStatusIsExtracted");
- auto IID = II->getIntrinsicID();
+bool checkIfStatusIsExtracted(const IntrinsicInst &II) {
+ auto IID = II.getIntrinsicID();
assert(IID == Intrinsic::dx_resource_load_typedbuffer ||
IID == Intrinsic::dx_resource_load_rawbuffer &&
"unexpected intrinsic ID, only dx_resource_load_typedbuffer and "
"dx_resource_load_rawbuffer are expected");
- for (const User *U : I->users()) {
+ for (const User *U : II.users()) {
if (const ExtractValueInst *EVI = dyn_cast<ExtractValueInst>(U)) {
// Resource load operations return a {result, status} pair
// check if we extract the status
@@ -188,7 +186,7 @@ void ModuleShaderFlags::updateFunctionFlags(ComputedShaderFlags &CSF,
}
}
- if (auto *II = dyn_cast<IntrinsicInst>(&I)) {
+ if (const auto *II = dyn_cast<IntrinsicInst>(&I)) {
switch (II->getIntrinsicID()) {
default:
break;
@@ -216,12 +214,12 @@ void ModuleShaderFlags::updateFunctionFlags(ComputedShaderFlags &CSF,
DRTM[cast<TargetExtType>(II->getArgOperand(0)->getType())];
if (RTI.isTyped())
CSF.TypedUAVLoadAdditionalFormats |= RTI.getTyped().ElementCount > 1;
- if (!CSF.TiledResources && checkIfStatusIsExtracted(&I))
+ if (!CSF.TiledResources && checkIfStatusIsExtracted(*II))
CSF.TiledResources = true;
break;
}
case Intrinsic::dx_resource_load_rawbuffer: {
- if (!CSF.TiledResources && checkIfStatusIsExtracted(&I))
+ if (!CSF.TiledResources && checkIfStatusIsExtracted(*II))
CSF.TiledResources = true;
break;
}
>From cc885d0e3057bb66cf0f8d051e394d3b9db07da9 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Tue, 11 Nov 2025 18:05:38 -0800
Subject: [PATCH 10/12] one more nit
---
llvm/lib/Target/DirectX/DXILShaderFlags.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
index 04b8f1c6fdd5d..2eafacfc9e2c8 100644
--- a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
+++ b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
@@ -105,7 +105,7 @@ static bool checkWaveOps(Intrinsic::ID IID) {
// This is our proof that the module requires TiledResources
// to be set, as if check access fully mapped was used.
bool checkIfStatusIsExtracted(const IntrinsicInst &II) {
- auto IID = II.getIntrinsicID();
+ [[maybe_unused]] Intrinsic::ID IID = II.getIntrinsicID();
assert(IID == Intrinsic::dx_resource_load_typedbuffer ||
IID == Intrinsic::dx_resource_load_rawbuffer &&
"unexpected intrinsic ID, only dx_resource_load_typedbuffer and "
>From 84d5ca1f4785f45f88a6b9cbcadc662637cd0e36 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Thu, 20 Nov 2025 15:49:22 -0800
Subject: [PATCH 11/12] address Helena
---
clang/lib/CodeGen/CGHLSLBuiltins.cpp | 1 -
clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 14 ++------
clang/lib/Sema/SemaHLSL.cpp | 3 +-
.../test/AST/HLSL/StructuredBuffers-AST.hlsl | 12 +------
clang/test/AST/HLSL/TypedBuffers-AST.hlsl | 14 ++------
.../StructuredBuffers-methods-lib.hlsl | 32 ++++++-----------
.../StructuredBuffers-methods-ps.hlsl | 32 ++++++-----------
.../resources/TypedBuffers-methods.hlsl | 34 ++++++-------------
llvm/lib/Target/DirectX/DXILShaderFlags.cpp | 12 +++----
9 files changed, 44 insertions(+), 110 deletions(-)
diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
index df9b488f6f580..a3e54f5ef2ada 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -364,7 +364,6 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
QualType HandleTy = E->getArg(0)->getType();
const HLSLAttributedResourceType *RT =
HandleTy->getAs<HLSLAttributedResourceType>();
- assert(RT && "Expected a resource type as first parameter");
assert(CGM.getTarget().getTriple().getArch() == llvm::Triple::dxil &&
"Only DXIL currently implements load with status");
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index 284d5ff0177e9..9c8f8f4c3ca0e 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -202,7 +202,7 @@ struct BuiltinTypeMethodBuilder {
BuiltinTypeMethodBuilder &declareLocalVar(LocalVar &Var);
template <typename... Ts>
BuiltinTypeMethodBuilder &callBuiltin(StringRef BuiltinName,
- QualType ReturnType, Ts &&...ArgSpecs);
+ QualType ReturnType, Ts... ArgSpecs);
template <typename TLHS, typename TRHS>
BuiltinTypeMethodBuilder &assign(TLHS LHS, TRHS RHS);
template <typename T> BuiltinTypeMethodBuilder &dereference(T Ptr);
@@ -572,7 +572,7 @@ BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::returnThis() {
template <typename... Ts>
BuiltinTypeMethodBuilder &
BuiltinTypeMethodBuilder::callBuiltin(StringRef BuiltinName,
- QualType ReturnType, Ts &&...ArgSpecs) {
+ QualType ReturnType, Ts... ArgSpecs) {
ensureCompleteDecl();
std::array<Expr *, sizeof...(ArgSpecs)> Args{
@@ -1241,19 +1241,11 @@ BuiltinTypeDeclBuilder::addLoadWithStatusFunction(DeclarationName &Name,
using PH = BuiltinTypeMethodBuilder::PlaceHolder;
QualType ReturnTy = getHandleElementType();
- BuiltinTypeMethodBuilder::LocalVar ResultVar("Result", ReturnTy);
- BuiltinTypeMethodBuilder::LocalVar StatusVar("StatusBool", AST.BoolTy);
-
return BuiltinTypeMethodBuilder(*this, Name, ReturnTy, IsConst)
.addParam("Index", AST.UnsignedIntTy)
.addParam("Status", AST.UnsignedIntTy, HLSLParamModifierAttr::Keyword_out)
- .declareLocalVar(ResultVar)
- .declareLocalVar(StatusVar)
.callBuiltin("__builtin_hlsl_resource_load_with_status", ReturnTy,
- PH::Handle, PH::_0, StatusVar)
- .assign(ResultVar, PH::LastStmt)
- .assign(PH::_1, StatusVar)
- .returnValue(ResultVar)
+ PH::Handle, PH::_0, PH::_1)
.finalize();
}
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 8cc737d83376c..d4c304e5b3c91 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3016,7 +3016,8 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
SemaRef.getASTContext().UnsignedIntTy) ||
CheckArgTypeMatches(&SemaRef, TheCall->getArg(2),
- SemaRef.getASTContext().BoolTy))
+ SemaRef.getASTContext().UnsignedIntTy) ||
+ CheckModifiableLValue(&SemaRef, TheCall, 2))
return true;
auto *ResourceTy =
diff --git a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl
index b7111fe53eb23..96d510810e090 100644
--- a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl
+++ b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl
@@ -333,12 +333,7 @@ RESOURCE<float> Buffer;
// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Status 'unsigned int &__restrict'
// CHECK-LOAD-NEXT: HLSLParamModifierAttr {{.*}} out
// CHECK-LOAD-NEXT: CompoundStmt
-// CHECK-LOAD-NEXT: DeclStmt
-// CHECK-LOAD-NEXT: VarDecl {{.*}} Result 'element_type'
-// CHECK-LOAD-NEXT: DeclStmt
-// CHECK-LOAD-NEXT: VarDecl {{.*}} StatusBool 'bool'
-// CHECK-LOAD-NEXT: BinaryOperator {{.*}} 'element_type' '='
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'element_type' lvalue Var {{.*}} 'Result' 'element_type'
+// CHECK-LOAD-NEXT: ReturnStmt
// CHECK-LOAD-NEXT: CallExpr {{.*}} 'element_type'
// CHECK-LOAD-NEXT: ImplicitCastExpr {{.*}} <BuiltinFnToFnPtr>
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_load_with_status' 'void (...) noexcept'
@@ -348,12 +343,7 @@ RESOURCE<float> Buffer;
// CHECK-LOAD-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue implicit this
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'bool' lvalue Var {{.*}} 'StatusBool' 'bool'
-// CHECK-LOAD-NEXT: BinaryOperator {{.*}} 'unsigned int' '='
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Status' 'unsigned int &__restrict'
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'bool' lvalue Var {{.*}} 'StatusBool' 'bool'
-// CHECK-LOAD-NEXT: ReturnStmt
-// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'element_type' lvalue Var {{.*}} 'Result' 'element_type'
// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
// IncrementCounter method
diff --git a/clang/test/AST/HLSL/TypedBuffers-AST.hlsl b/clang/test/AST/HLSL/TypedBuffers-AST.hlsl
index 8fb30eea7eb5b..71348f5b61b5d 100644
--- a/clang/test/AST/HLSL/TypedBuffers-AST.hlsl
+++ b/clang/test/AST/HLSL/TypedBuffers-AST.hlsl
@@ -220,14 +220,9 @@ RESOURCE<float> Buffer;
// CHECK-NEXT: ParmVarDecl {{.*}} Status 'unsigned int &__restrict'
// CHECK-NEXT: HLSLParamModifierAttr {{.*}} out
// CHECK-NEXT: CompoundStmt
-// CHECK-NEXT: DeclStmt
-// CHECK-NEXT: VarDecl {{.*}} Result 'element_type'
-// CHECK-NEXT: DeclStmt
-// CHECK-NEXT: VarDecl {{.*}} StatusBool 'bool'
-// CHECK-NEXT: BinaryOperator {{.*}} 'element_type' '='
-// CHECK-NEXT: DeclRefExpr {{.*}} 'element_type' lvalue Var {{.*}} 'Result' 'element_type'
+// CHECK-NEXT: ReturnStmt
// CHECK-NEXT: CallExpr {{.*}} 'element_type'
-// CHECK-NEXT: ImplicitCastExpr {{.*}} <BuiltinFnToFnPtr>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_load_with_status' 'void (...) noexcept'
// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
// CHECK-UAV-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
@@ -235,12 +230,7 @@ RESOURCE<float> Buffer;
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue implicit this
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
-// CHECK-NEXT: DeclRefExpr {{.*}} 'bool' lvalue Var {{.*}} 'StatusBool' 'bool'
-// CHECK-NEXT: BinaryOperator {{.*}} 'unsigned int' '='
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Status' 'unsigned int &__restrict'
-// CHECK-NEXT: DeclRefExpr {{.*}} 'bool' lvalue Var {{.*}} 'StatusBool' 'bool'
-// CHECK-NEXT: ReturnStmt
-// CHECK-NEXT: DeclRefExpr {{.*}} 'element_type' lvalue Var {{.*}} 'Result' 'element_type'
// CHECK-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
// GetDimensions method
diff --git a/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-lib.hlsl b/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-lib.hlsl
index 2c48cf7e35346..54c386cab537b 100644
--- a/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-lib.hlsl
+++ b/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-lib.hlsl
@@ -113,46 +113,34 @@ export float TestLoadWithStatus() {
}
// CHECK: define noundef nofpclass(nan inf) float @TestLoadWithStatus()()
-// CHECK: call {{.*}} float @hlsl::RWStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @RWSB1, i32 noundef 1, ptr noalias noundef nonnull align 4 dereferenceable(4) %tmp)
-// CHECK: call {{.*}} float @hlsl::StructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @SB1, i32 noundef 2, ptr noalias noundef nonnull align 4 dereferenceable(4) %tmp1)
+// CHECK: call {{.*}} float @hlsl::RWStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @RWSB1, i32 noundef 1, ptr {{.*}} %tmp)
+// CHECK: call {{.*}} float @hlsl::StructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @SB1, i32 noundef 2, ptr {{.*}} %tmp1)
// CHECK: add
// CHECK: ret float
-// CHECK: define {{.*}} float @hlsl::RWStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noalias noundef nonnull align 4 dereferenceable(4) %Status)
+// CHECK: define {{.*}} float @hlsl::RWStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr {{.*}} %Status)
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RWStructuredBuffer", ptr %{{.*}}, i32 0, i32 0
// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", float, 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 { float, i1 } @llvm.dx.resource.load.rawbuffer.f32.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %[[HANDLE]], i32 %[[INDEX]], i32 0)
// 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 %StatusBool, align 4
-// CHECK-NEXT: store float %ld.value, ptr %Result, align 4
-// CHECK-NEXT: %[[STATUS_INT:.*]] = load i32, ptr %StatusBool, align 4
-// CHECK-NEXT: %[[LOADED_VALUE:.*]] = trunc i32 %[[STATUS_INT]] to i1
-// CHECK-NEXT: %[[ZEXT_VALUE:.*]] = zext i1 %[[LOADED_VALUE]] to i32
-// CHECK-NEXT: %[[LOADED_STATUS_ADDR:.*]] = load ptr, ptr %Status.addr, align 4
-// CHECK-NEXT: store i32 %[[ZEXT_VALUE]], ptr %[[LOADED_STATUS_ADDR]], align 4
-// CHECK-NEXT: %[[RETURN_VALUE:.*]] = load float, ptr %Result, align 4
-// CHECK-NEXT: ret float %[[RETURN_VALUE]]
+// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %[[LOADED_STATUS_ADDR]], align 4
+// CHECK-NEXT: ret float %[[VALUE]]
-// CHECK: define {{.*}} float @hlsl::StructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noalias noundef nonnull align 4 dereferenceable(4) %Status)
+// CHECK: define {{.*}} float @hlsl::StructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr {{.*}} %Status)
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::StructuredBuffer", ptr %{{.*}}, i32 0, i32 0
// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", float, 0, 0), ptr %__handle
// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
+// CHECK-NEXT: %[[LOADED_STATUS_ADDR:.*]] = load ptr, ptr %Status.addr, align 4
// DXIL-NEXT: %[[STRUCT:.*]] = call { float, i1 } @llvm.dx.resource.load.rawbuffer.f32.tdx.RawBuffer_f32_0_0t(target("dx.RawBuffer", float, 0, 0) %[[HANDLE]], i32 %[[INDEX]], i32 0)
// 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 %StatusBool, align 4
-// CHECK-NEXT: store float %ld.value, ptr %Result, align 4
-// CHECK-NEXT: %[[STATUS_INT:.*]] = load i32, ptr %StatusBool, align 4
-// CHECK-NEXT: %[[LOADED_VALUE:.*]] = trunc i32 %[[STATUS_INT]] to i1
-// CHECK-NEXT: %[[ZEXT_VALUE:.*]] = zext i1 %[[LOADED_VALUE]] to i32
-// CHECK-NEXT: %[[LOADED_STATUS_ADDR:.*]] = load ptr, ptr %Status.addr, align 4
-// CHECK-NEXT: store i32 %[[ZEXT_VALUE]], ptr %[[LOADED_STATUS_ADDR]], align 4
-// CHECK-NEXT: %[[RETURN_VALUE:.*]] = load float, ptr %Result, align 4
-// CHECK-NEXT: ret float %[[RETURN_VALUE]]
+// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %[[LOADED_STATUS_ADDR]], align 4
+// CHECK-NEXT: ret float %[[VALUE]]
export uint TestGetDimensions() {
uint dim1, dim2, dim3, stride1, stride2, stride3;
diff --git a/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-ps.hlsl b/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-ps.hlsl
index 58c18940b81ca..157bae2e08a78 100644
--- a/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-ps.hlsl
+++ b/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-ps.hlsl
@@ -73,45 +73,33 @@ export float TestLoadWithStatus() {
}
// CHECK: define {{.*}} float @TestLoadWithStatus()()
-// CHECK: call {{.*}} float @hlsl::RasterizerOrderedStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @ROSB1, i32 noundef 10, ptr noalias noundef nonnull align 4 dereferenceable(4) %tmp)
-// CHECK: call {{.*}} <2 x i32> @hlsl::RasterizerOrderedStructuredBuffer<int vector[2]>::Load(unsigned int, unsigned int&)(ptr {{.*}} @ROSB2, i32 noundef 20, ptr noalias noundef nonnull align 4 dereferenceable(4) %tmp2)
+// CHECK: call {{.*}} float @hlsl::RasterizerOrderedStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @ROSB1, i32 noundef 10, ptr {{.*}} %tmp)
+// CHECK: call {{.*}} <2 x i32> @hlsl::RasterizerOrderedStructuredBuffer<int vector[2]>::Load(unsigned int, unsigned int&)(ptr {{.*}} @ROSB2, i32 noundef 20, ptr {{.*}} %tmp2)
// CHECK: ret
-// CHECK: define {{.*}} float @hlsl::RasterizerOrderedStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noalias noundef nonnull align 4 dereferenceable(4) %Status)
+// CHECK: define {{.*}} float @hlsl::RasterizerOrderedStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr {{.*}} %Status)
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RasterizerOrderedStructuredBuffer", ptr {{.*}}, i32 0, i32 0
// CHECK-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", float, 1, 1), ptr %__handle
// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
+// CHECK-NEXT: %[[LOADED_STATUS_ADDR:.*]] = load ptr, ptr %Status.addr, align 4
// DXIL-NEXT: %[[STRUCT:.*]] = call { float, i1 } @llvm.dx.resource.load.rawbuffer.f32.tdx.RawBuffer_f32_1_1t(target("dx.RawBuffer", float, 1, 1) %[[HANDLE]], i32 %[[INDEX]], i32 0)
// 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 %StatusBool, align 4
-// CHECK-NEXT: store float %ld.value, ptr %Result, align 4
-// CHECK-NEXT: %[[STATUS_INT:.*]] = load i32, ptr %StatusBool, align 4
-// CHECK-NEXT: %[[LOADED_VALUE:.*]] = trunc i32 %[[STATUS_INT]] to i1
-// CHECK-NEXT: %[[ZEXT_VALUE:.*]] = zext i1 %[[LOADED_VALUE]] to i32
-// CHECK-NEXT: %[[LOADED_STATUS_ADDR:.*]] = load ptr, ptr %Status.addr, align 4
-// CHECK-NEXT: store i32 %[[ZEXT_VALUE]], ptr %[[LOADED_STATUS_ADDR]], align 4
-// CHECK-NEXT: %[[RETURN_VALUE:.*]] = load float, ptr %Result, align 4
-// CHECK-NEXT: ret float %[[RETURN_VALUE]]
+// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %[[LOADED_STATUS_ADDR]], align 4
+// CHECK-NEXT: ret float %[[VALUE]]
-// CHECK: define {{.*}} <2 x i32> @hlsl::RasterizerOrderedStructuredBuffer<int vector[2]>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noalias noundef nonnull align 4 dereferenceable(4) %Status)
+// CHECK: define {{.*}} <2 x i32> @hlsl::RasterizerOrderedStructuredBuffer<int vector[2]>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr {{.*}} %Status)
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RasterizerOrderedStructuredBuffer.0", ptr {{.*}}, i32 0, i32 0
// CHECK-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", <2 x i32>, 1, 1), ptr %__handle
// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
+// CHECK-NEXT: %[[LOADED_STATUS_ADDR:.*]] = load ptr, ptr %Status.addr, align 4
// DXIL-NEXT: %[[STRUCT:.*]] = call { <2 x i32>, i1 } @llvm.dx.resource.load.rawbuffer.v2i32.tdx.RawBuffer_v2i32_1_1t(target("dx.RawBuffer", <2 x i32>, 1, 1) %[[HANDLE]], i32 %[[INDEX]], i32 0)
// CHECK-NEXT: %[[VALUE:.*]] = extractvalue { <2 x i32>, i1 } %[[STRUCT]], 0
// CHECK-NEXT: %[[STATUS_TEMP:.*]] = extractvalue { <2 x i32>, i1 } %[[STRUCT]], 1
// CHECK-NEXT: %[[STATUS_EXT:.*]] = zext i1 %[[STATUS_TEMP]] to i32
-// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %StatusBool, align 4
-// CHECK-NEXT: store <2 x i32> %ld.value, ptr %Result, align 8
-// CHECK-NEXT: %[[STATUS_INT:.*]] = load i32, ptr %StatusBool, align 4
-// CHECK-NEXT: %[[LOADED_VALUE:.*]] = trunc i32 %[[STATUS_INT]] to i1
-// CHECK-NEXT: %[[ZEXT_VALUE:.*]] = zext i1 %[[LOADED_VALUE]] to i32
-// CHECK-NEXT: %[[LOADED_STATUS_ADDR:.*]] = load ptr, ptr %Status.addr, align 4
-// CHECK-NEXT: store i32 %[[ZEXT_VALUE]], ptr %[[LOADED_STATUS_ADDR]], align 4
-// CHECK-NEXT: %[[RETURN_VALUE:.*]] = load <2 x i32>, ptr %Result, align 8
-// CHECK-NEXT: ret <2 x i32> %[[RETURN_VALUE]]
+// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %[[LOADED_STATUS_ADDR]], align 4
+// CHECK-NEXT: ret <2 x i32> %[[VALUE]]
export uint TestGetDimensions() {
diff --git a/clang/test/CodeGenHLSL/resources/TypedBuffers-methods.hlsl b/clang/test/CodeGenHLSL/resources/TypedBuffers-methods.hlsl
index 5d28a01d4839f..499f5b1ca54ef 100644
--- a/clang/test/CodeGenHLSL/resources/TypedBuffers-methods.hlsl
+++ b/clang/test/CodeGenHLSL/resources/TypedBuffers-methods.hlsl
@@ -47,46 +47,34 @@ export float TestLoadWithStatus() {
}
// CHECK: define noundef nofpclass(nan inf) float @TestLoadWithStatus()()
-// CHECK: call {{.*}} float @hlsl::Buffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @Buf, i32 noundef 1, ptr noalias noundef nonnull align 4 dereferenceable(4) %tmp)
-// CHECK: call {{.*}} <4 x i32> @hlsl::RWBuffer<unsigned int vector[4]>::Load(unsigned int, unsigned int&)(ptr {{.*}} @RWBuf, i32 noundef 2, ptr noalias noundef nonnull align 4 dereferenceable(4) %tmp1)
+// CHECK: call {{.*}} float @hlsl::Buffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @Buf, i32 noundef 1, ptr {{.*}} %tmp)
+// CHECK: call {{.*}} <4 x i32> @hlsl::RWBuffer<unsigned int vector[4]>::Load(unsigned int, unsigned int&)(ptr {{.*}} @RWBuf, i32 noundef 2, ptr {{.*}} %tmp1)
// CHECK: add
// CHECK: ret float
-// CHECK: define {{.*}} float @hlsl::Buffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noalias noundef nonnull align 4 dereferenceable(4) %Status)
+// CHECK: define {{.*}} float @hlsl::Buffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr {{.*}} %Status)
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::Buffer", ptr %{{.*}}, i32 0, i32 0
// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.TypedBuffer", float, 0, 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.typedbuffer.f32.tdx.TypedBuffer_f32_0_0_0t(target("dx.TypedBuffer", float, 0, 0, 0) %[[HANDLE]], i32 %[[INDEX]])
// 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 %StatusBool, align 4
-// CHECK-NEXT: store float %ld.value, ptr %Result, align 4
-// CHECK-NEXT: %[[STATUS_INT:.*]] = load i32, ptr %StatusBool, align 4
-// CHECK-NEXT: %[[LOADED_VALUE:.*]] = trunc i32 %[[STATUS_INT]] to i1
-// CHECK-NEXT: %[[ZEXT_VALUE:.*]] = zext i1 %[[LOADED_VALUE]] to i32
-// CHECK-NEXT: %[[LOADED_STATUS_ADDR:.*]] = load ptr, ptr %Status.addr, align 4
-// CHECK-NEXT: store i32 %[[ZEXT_VALUE]], ptr %[[LOADED_STATUS_ADDR]], align 4
-// CHECK-NEXT: %[[RETURN_VALUE:.*]] = load float, ptr %Result, align 4
-// CHECK-NEXT: ret float %[[RETURN_VALUE]]
-
-// CHECK: define {{.*}} <4 x i32> @hlsl::RWBuffer<unsigned int vector[4]>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noalias noundef nonnull align 4 dereferenceable(4) %Status)
+// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %[[LOADED_STATUS_ADDR]], align 4
+// CHECK-NEXT: ret float %[[VALUE]]
+
+// CHECK: define {{.*}} <4 x i32> @hlsl::RWBuffer<unsigned int vector[4]>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr {{.*}} %Status)
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RWBuffer", ptr %{{.*}}, i32 0, i32 0
// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.TypedBuffer", <4 x i32>, 1, 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 { <4 x i32>, i1 } @llvm.dx.resource.load.typedbuffer.v4i32.tdx.TypedBuffer_v4i32_1_0_0t(target("dx.TypedBuffer", <4 x i32>, 1, 0, 0) %[[HANDLE]], i32 %[[INDEX]])
// 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 %StatusBool, align 4
-// CHECK-NEXT: store <4 x i32> %ld.value, ptr %Result, align 16
-// CHECK-NEXT: %[[STATUS_INT:.*]] = load i32, ptr %StatusBool, align 4
-// CHECK-NEXT: %[[LOADED_VALUE:.*]] = trunc i32 %[[STATUS_INT]] to i1
-// CHECK-NEXT: %[[ZEXT_VALUE:.*]] = zext i1 %[[LOADED_VALUE]] to i32
-// CHECK-NEXT: %[[LOADED_STATUS_ADDR:.*]] = load ptr, ptr %Status.addr, align 4
-// CHECK-NEXT: store i32 %[[ZEXT_VALUE]], ptr %[[LOADED_STATUS_ADDR]], align 4
-// CHECK-NEXT: %[[RETURN_VALUE:.*]] = load <4 x i32>, ptr %Result, align 16
-// CHECK-NEXT: ret <4 x i32> %[[RETURN_VALUE]]
+// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %[[LOADED_STATUS_ADDR]], align 4
+// CHECK-NEXT: ret <4 x i32> %[[VALUE]]
export uint TestGetDimensions() {
uint dim1, dim2;
diff --git a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
index 2eafacfc9e2c8..e0049dc75c0db 100644
--- a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
+++ b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
@@ -101,19 +101,17 @@ static bool checkWaveOps(Intrinsic::ID IID) {
}
// Checks to see if the status bit from a load with status
-// instruction is ever extracted.
-// This is our proof that the module requires TiledResources
-// to be set, as if check access fully mapped was used.
+// instruction is ever extracted. If it is, the module needs
+// to have the TiledResources shader flag set.
bool checkIfStatusIsExtracted(const IntrinsicInst &II) {
[[maybe_unused]] Intrinsic::ID IID = II.getIntrinsicID();
assert(IID == Intrinsic::dx_resource_load_typedbuffer ||
IID == Intrinsic::dx_resource_load_rawbuffer &&
- "unexpected intrinsic ID, only dx_resource_load_typedbuffer and "
- "dx_resource_load_rawbuffer are expected");
+ "unexpected intrinsic ID");
for (const User *U : II.users()) {
if (const ExtractValueInst *EVI = dyn_cast<ExtractValueInst>(U)) {
- // Resource load operations return a {result, status} pair
- // check if we extract the status
+ // Resource load operations return a {result, status} pair.
+ // Check if we extract the status
if (EVI->getNumIndices() == 1 && EVI->getIndices()[0] == 1)
return true;
}
>From 48957a361362240febe6f34a46b581608c7412fb Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Thu, 20 Nov 2025 15:53:56 -0800
Subject: [PATCH 12/12] formatting
---
clang/lib/Headers/hlsl/hlsl_intrinsics.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index e92f999fb54d0..e657ae5e1efd0 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -668,7 +668,7 @@ smoothstep(__detail::HLSL_FIXED_VECTOR<float, N> Min,
inline bool CheckAccessFullyMapped(uint Status) {
return static_cast<bool>(Status);
-
+
//===----------------------------------------------------------------------===//
// fwidth builtin
//===----------------------------------------------------------------------===//
More information about the llvm-commits
mailing list