From 99c97887389d5255905394052a766b7dee2129fd Mon Sep 17 00:00:00 2001 From: Joshua Batista Date: Thu, 30 Oct 2025 17:06:11 -0700 Subject: [PATCH 01/14] 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{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{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(); + 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::Load(unsigned int)(ptr {{.*}} @RWSB1, i32 noundef 1) +// CHECK: call {{.*}} float @hlsl::StructuredBuffer::Load(unsigned int)(ptr {{.*}} @SB1, i32 noundef 2) +// CHECK: add +// CHECK: ret float + +// CHECK: define {{.*}} float @hlsl::RWStructuredBuffer::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::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::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::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::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::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 Date: Tue, 4 Nov 2025 12:03:27 -0800 Subject: [PATCH 02/14] 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{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{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(); + 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 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::Load(unsigned int)(ptr {{.*}} @RWSB1, i32 noundef 1) -// CHECK: call {{.*}} float @hlsl::StructuredBuffer::Load(unsigned int)(ptr {{.*}} @SB1, i32 noundef 2) +// CHECK: define noundef nofpclass(nan inf) float @TestLoadWithStatus()() +// CHECK: call {{.*}} float @hlsl::RWStructuredBuffer::Load(unsigned int, unsigned int&)(ptr {{.*}} @RWSB1, i32 noundef 1, ptr noundef nonnull align 4 dereferenceable(4) %s1) +// CHECK: call {{.*}} float @hlsl::StructuredBuffer::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::Load(unsigned int)(ptr {{.*}} %this, i32 noundef %Index) +// CHECK: define {{.*}} float @hlsl::RWStructuredBuffer::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::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::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::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::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::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::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::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 Date: Thu, 6 Nov 2025 12:48:51 -0800 Subject: [PATCH 03/14] 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 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 Min, return __detail::smoothstep_vec_impl(Min, Max, X); } +bool CheckAccessFullyMapped(uint Status) { return static_cast(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 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 {{.*}} +// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '' 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]]' 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 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 {{.*}} +// CHECK-NEXT: DeclRefExpr {{.*}} '' 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]]' 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 Date: Mon, 10 Nov 2025 14:28:26 -0800 Subject: [PATCH 04/14] 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 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 BuiltinTypeMethodBuilder &callBuiltin(StringRef BuiltinName, - QualType ReturnType, Ts... ArgSpecs); + QualType ReturnType, Ts &&...ArgSpecs); template BuiltinTypeMethodBuilder &assign(TLHS LHS, TRHS RHS); template BuiltinTypeMethodBuilder &dereference(T Ptr); @@ -572,7 +572,7 @@ BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::returnThis() { template BuiltinTypeMethodBuilder & BuiltinTypeMethodBuilder::callBuiltin(StringRef BuiltinName, - QualType ReturnType, Ts... ArgSpecs) { + QualType ReturnType, Ts &&...ArgSpecs) { ensureCompleteDecl(); std::array 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(); - 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::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::Load(unsigned int, unsigned int&)(ptr {{.*}} @RWBuf, i32 noundef 2, ptr noundef nonnull align 4 dereferenceable(4) %s2) +// CHECK: call {{.*}} float @hlsl::Buffer::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::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::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noundef nonnull align 4 dereferenceable(4) %Status) +// CHECK: define {{.*}} float @hlsl::Buffer::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(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(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 Date: Mon, 10 Nov 2025 19:13:18 -0800 Subject: [PATCH 05/14] 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 Min, return __detail::smoothstep_vec_impl(Min, Max, X); } -bool CheckAccessFullyMapped(uint Status) { return static_cast(Status); } +inline bool CheckAccessFullyMapped(uint Status) { + return static_cast(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 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 {{.*}} // CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '' 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]]' 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 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 {{.*}} // CHECK-NEXT: DeclRefExpr {{.*}} '' 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]]' 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::Load(unsigned int, unsigned int&)(ptr {{.*}} @RWSB1, i32 noundef 1, ptr noundef nonnull align 4 dereferenceable(4) %s1) -// CHECK: call {{.*}} float @hlsl::StructuredBuffer::Load(unsigned int, unsigned int&)(ptr {{.*}} @SB1, i32 noundef 2, ptr noundef nonnull align 4 dereferenceable(4) %s2) +// CHECK: call {{.*}} float @hlsl::RWStructuredBuffer::Load(unsigned int, unsigned int&)(ptr {{.*}} @RWSB1, i32 noundef 1, ptr noalias noundef nonnull align 4 dereferenceable(4) %tmp) +// CHECK: call {{.*}} float @hlsl::StructuredBuffer::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::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noundef nonnull align 4 dereferenceable(4) %Status) +// CHECK: define {{.*}} float @hlsl::RWStructuredBuffer::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::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::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::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::Load(unsigned int, unsigned int&)(ptr {{.*}} @ROSB2, i32 noundef 20, ptr noundef nonnull align 4 dereferenceable(4) %status2) +// CHECK: call {{.*}} float @hlsl::RasterizerOrderedStructuredBuffer::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::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::Load(unsigned int, unsigned int&)(ptr {{.*}} %Index, ptr noundef nonnull align 4 dereferenceable(4) %Status) +// CHECK: define {{.*}} float @hlsl::RasterizerOrderedStructuredBuffer::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::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::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::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::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 Date: Tue, 11 Nov 2025 14:19:18 -0800 Subject: [PATCH 06/14] 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(); 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(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(&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(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 Date: Tue, 11 Nov 2025 14:20:51 -0800 Subject: [PATCH 07/14] 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 Date: Tue, 11 Nov 2025 17:15:51 -0800 Subject: [PATCH 08/14] 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(&I); - assert(II); +bool checkIfStatusIsExtracted(const Instruction *I) { + auto *II = dyn_cast(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(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(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 Date: Tue, 11 Nov 2025 17:31:37 -0800 Subject: [PATCH 09/14] 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(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(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(&I)) { + if (const auto *II = dyn_cast(&I)) { switch (II->getIntrinsicID()) { default: break; @@ -216,12 +214,12 @@ void ModuleShaderFlags::updateFunctionFlags(ComputedShaderFlags &CSF, DRTM[cast(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 Date: Tue, 11 Nov 2025 18:05:38 -0800 Subject: [PATCH 10/14] 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 Date: Thu, 20 Nov 2025 15:49:22 -0800 Subject: [PATCH 11/14] 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(); - 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 BuiltinTypeMethodBuilder &callBuiltin(StringRef BuiltinName, - QualType ReturnType, Ts &&...ArgSpecs); + QualType ReturnType, Ts... ArgSpecs); template BuiltinTypeMethodBuilder &assign(TLHS LHS, TRHS RHS); template BuiltinTypeMethodBuilder &dereference(T Ptr); @@ -572,7 +572,7 @@ BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::returnThis() { template BuiltinTypeMethodBuilder & BuiltinTypeMethodBuilder::callBuiltin(StringRef BuiltinName, - QualType ReturnType, Ts &&...ArgSpecs) { + QualType ReturnType, Ts... ArgSpecs) { ensureCompleteDecl(); std::array 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 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 {{.*}} // CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '' Function {{.*}} '__builtin_hlsl_resource_load_with_status' 'void (...) noexcept' @@ -348,12 +343,7 @@ RESOURCE Buffer; // CHECK-LOAD-SAME{LITERAL}: [[hlsl::contained_type(element_type)]] // CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' 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 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 {{.*}} +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' // CHECK-NEXT: DeclRefExpr {{.*}} '' 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 Buffer; // CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]] // CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' 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::Load(unsigned int, unsigned int&)(ptr {{.*}} @RWSB1, i32 noundef 1, ptr noalias noundef nonnull align 4 dereferenceable(4) %tmp) -// CHECK: call {{.*}} float @hlsl::StructuredBuffer::Load(unsigned int, unsigned int&)(ptr {{.*}} @SB1, i32 noundef 2, ptr noalias noundef nonnull align 4 dereferenceable(4) %tmp1) +// CHECK: call {{.*}} float @hlsl::RWStructuredBuffer::Load(unsigned int, unsigned int&)(ptr {{.*}} @RWSB1, i32 noundef 1, ptr {{.*}} %tmp) +// CHECK: call {{.*}} float @hlsl::StructuredBuffer::Load(unsigned int, unsigned int&)(ptr {{.*}} @SB1, i32 noundef 2, ptr {{.*}} %tmp1) // CHECK: add // CHECK: ret float -// CHECK: define {{.*}} float @hlsl::RWStructuredBuffer::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noalias noundef nonnull align 4 dereferenceable(4) %Status) +// CHECK: define {{.*}} float @hlsl::RWStructuredBuffer::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::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noalias noundef nonnull align 4 dereferenceable(4) %Status) +// CHECK: define {{.*}} float @hlsl::StructuredBuffer::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::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::Load(unsigned int, unsigned int&)(ptr {{.*}} @ROSB2, i32 noundef 20, ptr noalias noundef nonnull align 4 dereferenceable(4) %tmp2) +// CHECK: call {{.*}} float @hlsl::RasterizerOrderedStructuredBuffer::Load(unsigned int, unsigned int&)(ptr {{.*}} @ROSB1, i32 noundef 10, ptr {{.*}} %tmp) +// CHECK: call {{.*}} <2 x i32> @hlsl::RasterizerOrderedStructuredBuffer::Load(unsigned int, unsigned int&)(ptr {{.*}} @ROSB2, i32 noundef 20, ptr {{.*}} %tmp2) // CHECK: ret -// CHECK: define {{.*}} float @hlsl::RasterizerOrderedStructuredBuffer::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noalias noundef nonnull align 4 dereferenceable(4) %Status) +// CHECK: define {{.*}} float @hlsl::RasterizerOrderedStructuredBuffer::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::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::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::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::Load(unsigned int, unsigned int&)(ptr {{.*}} @RWBuf, i32 noundef 2, ptr noalias noundef nonnull align 4 dereferenceable(4) %tmp1) +// CHECK: call {{.*}} float @hlsl::Buffer::Load(unsigned int, unsigned int&)(ptr {{.*}} @Buf, i32 noundef 1, ptr {{.*}} %tmp) +// CHECK: call {{.*}} <4 x i32> @hlsl::RWBuffer::Load(unsigned int, unsigned int&)(ptr {{.*}} @RWBuf, i32 noundef 2, ptr {{.*}} %tmp1) // CHECK: add // CHECK: ret float -// CHECK: define {{.*}} float @hlsl::Buffer::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noalias noundef nonnull align 4 dereferenceable(4) %Status) +// CHECK: define {{.*}} float @hlsl::Buffer::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::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::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(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 Date: Thu, 20 Nov 2025 15:53:56 -0800 Subject: [PATCH 12/14] 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 Min, inline bool CheckAccessFullyMapped(uint Status) { return static_cast(Status); - + //===----------------------------------------------------------------------===// // fwidth builtin //===----------------------------------------------------------------------===// From 585246174b8236d0c7f79314a539ea267f4aad53 Mon Sep 17 00:00:00 2001 From: Joshua Batista Date: Thu, 20 Nov 2025 15:57:56 -0800 Subject: [PATCH 13/14] add missing { --- clang/lib/Headers/hlsl/hlsl_intrinsics.h | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index e657ae5e1efd0..a538be5ebd099 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -668,6 +668,7 @@ smoothstep(__detail::HLSL_FIXED_VECTOR Min, inline bool CheckAccessFullyMapped(uint Status) { return static_cast(Status); +} //===----------------------------------------------------------------------===// // fwidth builtin From 4fdb463006a69daa1489d1511bf6db9595b7e741 Mon Sep 17 00:00:00 2001 From: Joshua Batista Date: Thu, 20 Nov 2025 17:34:50 -0800 Subject: [PATCH 14/14] address some final nits --- clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp index 9c8f8f4c3ca0e..868f894a03c49 100644 --- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp +++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp @@ -202,7 +202,7 @@ struct BuiltinTypeMethodBuilder { BuiltinTypeMethodBuilder &declareLocalVar(LocalVar &Var); template BuiltinTypeMethodBuilder &callBuiltin(StringRef BuiltinName, - QualType ReturnType, Ts... ArgSpecs); + QualType ReturnType, Ts &&...ArgSpecs); template BuiltinTypeMethodBuilder &assign(TLHS LHS, TRHS RHS); template BuiltinTypeMethodBuilder &dereference(T Ptr); @@ -572,7 +572,7 @@ BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::returnThis() { template BuiltinTypeMethodBuilder & BuiltinTypeMethodBuilder::callBuiltin(StringRef BuiltinName, - QualType ReturnType, Ts... ArgSpecs) { + QualType ReturnType, Ts &&...ArgSpecs) { ensureCompleteDecl(); std::array Args{