diff options
| author | Joshua Batista <jbatista@microsoft.com> | 2025-11-21 10:11:38 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-11-21 10:11:38 -0800 |
| commit | fea070b610e0dc08447be60db7f13c150b2892d5 (patch) | |
| tree | 079ed6e67f87ee9cef12ba83d0add01f9ce5696d /clang | |
| parent | 00fb67af95635009f1539c88e8706665f4a2d017 (diff) | |
[HLSL] Add Load overload with status (#166449)
This PR adds a Load method for resources, which takes an additional
parameter by reference, status. It fills the status parameter with a 1
or 0, depending on whether or not the resource access was mapped.
CheckAccessFullyMapped is also added as an intrinsic, and called in the
production of this status bit.
Only addresses DXIL for the below issue:
https://github.com/llvm/llvm-project/issues/138910
Also only addresses the DXIL variant for the below issue:
https://github.com/llvm/llvm-project/issues/99204
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/include/clang/Basic/Builtins.td | 6 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CGHLSLBuiltins.cpp | 43 | ||||
| -rw-r--r-- | clang/lib/Headers/hlsl/hlsl_intrinsics.h | 4 | ||||
| -rw-r--r-- | clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 21 | ||||
| -rw-r--r-- | clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h | 2 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaHLSL.cpp | 18 | ||||
| -rw-r--r-- | clang/test/AST/HLSL/StructuredBuffers-AST.hlsl | 20 | ||||
| -rw-r--r-- | clang/test/AST/HLSL/TypedBuffers-AST.hlsl | 19 | ||||
| -rw-r--r-- | clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-lib.hlsl | 38 | ||||
| -rw-r--r-- | clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-ps.hlsl | 37 | ||||
| -rw-r--r-- | clang/test/CodeGenHLSL/resources/TypedBuffers-methods.hlsl | 38 |
11 files changed, 244 insertions, 2 deletions
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 502382a06985..7530aebdcb58 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4946,6 +4946,12 @@ def HLSLResourceGetPointer : LangBuiltin<"HLSL_LANG"> { let Prototype = "void(...)"; } +def HLSLResourceLoadWithStatus : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_resource_load_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 12d9a98915ce..5ae3fed099cd 100644 --- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp +++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp @@ -404,6 +404,49 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, RetTy, CGM.getHLSLRuntime().getCreateResourceGetPointerIntrinsic(), ArrayRef<Value *>{HandleOp, IndexOp}); } + case Builtin::BI__builtin_hlsl_resource_load_with_status: { + Value *HandleOp = EmitScalarExpr(E->getArg(0)); + Value *IndexOp = EmitScalarExpr(E->getArg(1)); + + // Get the *address* of the status argument to write to it by reference + LValue StatusLVal = EmitLValue(E->getArg(2)); + Address StatusAddr = StatusLVal.getAddress(); + + QualType HandleTy = E->getArg(0)->getType(); + const HLSLAttributedResourceType *RT = + HandleTy->getAs<HLSLAttributedResourceType>(); + 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 + : llvm::Intrinsic::dx_resource_load_typedbuffer; + + llvm::Type *DataTy = ConvertType(E->getType()); + llvm::Type *RetTy = llvm::StructType::get(Builder.getContext(), + {DataTy, Builder.getInt1Ty()}); + + SmallVector<Value *, 3> Args; + Args.push_back(HandleOp); + Args.push_back(IndexOp); + + if (RT->getAttrs().RawBuffer) { + Value *Offset = Builder.getInt32(0); + Args.push_back(Offset); + } + + // 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; + } 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/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index c26c8bb5261d..a538be5ebd09 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -666,6 +666,10 @@ smoothstep(__detail::HLSL_FIXED_VECTOR<float, N> Min, return __detail::smoothstep_vec_impl(Min, Max, X); } +inline bool CheckAccessFullyMapped(uint Status) { + return static_cast<bool>(Status); +} + //===----------------------------------------------------------------------===// // fwidth builtin //===----------------------------------------------------------------------===// diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp index 066acf6f01a9..868f894a03c4 100644 --- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp +++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp @@ -202,7 +202,7 @@ public: BuiltinTypeMethodBuilder &declareLocalVar(LocalVar &Var); template <typename... Ts> BuiltinTypeMethodBuilder &callBuiltin(StringRef BuiltinName, - QualType ReturnType, Ts... ArgSpecs); + QualType ReturnType, Ts &&...ArgSpecs); template <typename TLHS, typename TRHS> BuiltinTypeMethodBuilder &assign(TLHS LHS, TRHS RHS); template <typename T> BuiltinTypeMethodBuilder &dereference(T Ptr); @@ -572,7 +572,7 @@ BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::returnThis() { template <typename... Ts> BuiltinTypeMethodBuilder & BuiltinTypeMethodBuilder::callBuiltin(StringRef BuiltinName, - QualType ReturnType, Ts... ArgSpecs) { + QualType ReturnType, Ts &&...ArgSpecs) { ensureCompleteDecl(); std::array<Expr *, sizeof...(ArgSpecs)> Args{ @@ -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); + addLoadWithStatusFunction(Load, /*IsConst=*/false); return *this; } @@ -1233,6 +1234,22 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDecrementCounterMethod() { } BuiltinTypeDeclBuilder & +BuiltinTypeDeclBuilder::addLoadWithStatusFunction(DeclarationName &Name, + bool IsConst) { + assert(!Record->isCompleteDefinition() && "record is already complete"); + ASTContext &AST = SemaRef.getASTContext(); + using PH = BuiltinTypeMethodBuilder::PlaceHolder; + + QualType ReturnTy = getHandleElementType(); + return BuiltinTypeMethodBuilder(*this, Name, ReturnTy, IsConst) + .addParam("Index", AST.UnsignedIntTy) + .addParam("Status", AST.UnsignedIntTy, HLSLParamModifierAttr::Keyword_out) + .callBuiltin("__builtin_hlsl_resource_load_with_status", ReturnTy, + PH::Handle, PH::_0, PH::_1) + .finalize(); +} + +BuiltinTypeDeclBuilder & BuiltinTypeDeclBuilder::addHandleAccessFunction(DeclarationName &Name, bool IsConst, bool IsRef) { assert(!Record->isCompleteDefinition() && "record is already complete"); diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h index 95e3a6c4fb2f..47c8b0e22561 100644 --- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h +++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h @@ -91,6 +91,8 @@ public: BuiltinTypeDeclBuilder &addDecrementCounterMethod(); BuiltinTypeDeclBuilder &addHandleAccessFunction(DeclarationName &Name, bool IsConst, bool IsRef); + BuiltinTypeDeclBuilder &addLoadWithStatusFunction(DeclarationName &Name, + bool IsConst); BuiltinTypeDeclBuilder &addAppendMethod(); BuiltinTypeDeclBuilder &addConsumeMethod(); diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index c5666941fd36..0a164a7b5bbb 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -3057,6 +3057,24 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { break; } + case Builtin::BI__builtin_hlsl_resource_load_with_status: { + if (SemaRef.checkArgCount(TheCall, 3) || + CheckResourceHandle(&SemaRef, TheCall, 0) || + CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), + SemaRef.getASTContext().UnsignedIntTy) || + CheckArgTypeMatches(&SemaRef, TheCall->getArg(2), + SemaRef.getASTContext().UnsignedIntTy) || + CheckModifiableLValue(&SemaRef, TheCall, 2)) + return true; + + auto *ResourceTy = + TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>(); + QualType ReturnType = ResourceTy->getContainedType(); + TheCall->setType(ReturnType); + + break; + } + case Builtin::BI__builtin_hlsl_resource_uninitializedhandle: { assert(TheCall->getNumArgs() == 1 && "expected 1 arg"); // Update return type to be the attributed resource type from arg0. diff --git a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl index 538eb5256f8d..eb65a28dba6f 100644 --- a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl +++ b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl @@ -326,6 +326,26 @@ RESOURCE<float> Buffer; // CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int' // CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline +// Load with status method + +// CHECK-LOAD: CXXMethodDecl {{.*}} Load 'element_type (unsigned int, out unsigned int)' +// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Index 'unsigned int' +// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Status 'unsigned int &__restrict' +// CHECK-LOAD-NEXT: HLSLParamModifierAttr {{.*}} out +// CHECK-LOAD-NEXT: CompoundStmt +// CHECK-LOAD-NEXT: ReturnStmt +// CHECK-LOAD-NEXT: CallExpr {{.*}} 'element_type' +// CHECK-LOAD-NEXT: ImplicitCastExpr {{.*}} <BuiltinFnToFnPtr> +// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_load_with_status' 'void (...) noexcept' +// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t +// CHECK-LOAD-UAV-SAME{LITERAL}: [[hlsl::resource_class(UAV)]] +// CHECK-LOAD-SRV-SAME{LITERAL}: [[hlsl::resource_class(SRV)]] +// CHECK-LOAD-SAME{LITERAL}: [[hlsl::contained_type(element_type)]] +// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue implicit this +// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int' +// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Status' 'unsigned int &__restrict' +// 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 4b66faa79662..762386c622da 100644 --- a/clang/test/AST/HLSL/TypedBuffers-AST.hlsl +++ b/clang/test/AST/HLSL/TypedBuffers-AST.hlsl @@ -214,6 +214,25 @@ RESOURCE<float> Buffer; // CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int' // CHECK-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline +// Load with status method +// CHECK: CXXMethodDecl {{.*}} Load 'element_type (unsigned int, out unsigned int)' +// CHECK-NEXT: ParmVarDecl {{.*}} Index 'unsigned int' +// CHECK-NEXT: ParmVarDecl {{.*}} Status 'unsigned int &__restrict' +// CHECK-NEXT: HLSLParamModifierAttr {{.*}} out +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: ReturnStmt +// CHECK-NEXT: CallExpr {{.*}} 'element_type' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr> +// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_load_with_status' 'void (...) noexcept' +// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t +// CHECK-UAV-SAME{LITERAL}: [[hlsl::resource_class(UAV)]] +// CHECK-SRV-SAME{LITERAL}: [[hlsl::resource_class(SRV)]] +// CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]] +// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue implicit this +// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int' +// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Status' 'unsigned int &__restrict' +// CHECK-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline + // GetDimensions method // CHECK-NEXT: CXXMethodDecl {{.*}} GetDimensions 'void (out unsigned int)' diff --git a/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-lib.hlsl b/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-lib.hlsl index 1f248d056000..54c386cab537 100644 --- a/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-lib.hlsl +++ b/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-lib.hlsl @@ -104,6 +104,44 @@ 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, s1) + SB1.Load(2, s2); + ret += float(s1 + s2); + return ret; +} + +// CHECK: define noundef nofpclass(nan inf) float @TestLoadWithStatus()() +// CHECK: call {{.*}} float @hlsl::RWStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @RWSB1, i32 noundef 1, ptr {{.*}} %tmp) +// CHECK: call {{.*}} float @hlsl::StructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @SB1, i32 noundef 2, ptr {{.*}} %tmp1) +// CHECK: add +// CHECK: ret float + +// CHECK: define {{.*}} float @hlsl::RWStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr {{.*}} %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 %[[LOADED_STATUS_ADDR]], align 4 +// CHECK-NEXT: ret float %[[VALUE]] + +// CHECK: define {{.*}} float @hlsl::StructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr {{.*}} %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 %[[LOADED_STATUS_ADDR]], align 4 +// CHECK-NEXT: ret float %[[VALUE]] + 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 25fa75965d68..157bae2e08a7 100644 --- a/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-ps.hlsl +++ b/clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-ps.hlsl @@ -65,6 +65,43 @@ export float TestLoad() { // CHECK-NEXT: %[[VAL:.*]] = load <2 x i32>, ptr %[[BUFPTR]] // CHECK-NEXT: ret <2 x i32> %[[VAL]] +export float TestLoadWithStatus() { + uint status; + uint status2; + float val = ROSB1.Load(10, status).x + ROSB2.Load(20, status2).x; + return val + float(status + status2); +} + +// CHECK: define {{.*}} float @TestLoadWithStatus()() +// CHECK: call {{.*}} float @hlsl::RasterizerOrderedStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @ROSB1, i32 noundef 10, ptr {{.*}} %tmp) +// CHECK: call {{.*}} <2 x i32> @hlsl::RasterizerOrderedStructuredBuffer<int vector[2]>::Load(unsigned int, unsigned int&)(ptr {{.*}} @ROSB2, i32 noundef 20, ptr {{.*}} %tmp2) +// CHECK: ret + +// CHECK: define {{.*}} float @hlsl::RasterizerOrderedStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr {{.*}} %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 %[[LOADED_STATUS_ADDR]], align 4 +// CHECK-NEXT: ret float %[[VALUE]] + +// CHECK: define {{.*}} <2 x i32> @hlsl::RasterizerOrderedStructuredBuffer<int vector[2]>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr {{.*}} %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 %[[LOADED_STATUS_ADDR]], align 4 +// CHECK-NEXT: ret <2 x i32> %[[VALUE]] + + export uint TestGetDimensions() { uint dim1, dim2, stride1, stride2; ROSB1.GetDimensions(dim1, stride1); diff --git a/clang/test/CodeGenHLSL/resources/TypedBuffers-methods.hlsl b/clang/test/CodeGenHLSL/resources/TypedBuffers-methods.hlsl index fdc1ef08b7c2..499f5b1ca54e 100644 --- a/clang/test/CodeGenHLSL/resources/TypedBuffers-methods.hlsl +++ b/clang/test/CodeGenHLSL/resources/TypedBuffers-methods.hlsl @@ -38,6 +38,44 @@ export float TestLoad() { // CHECK-NEXT: %[[VEC:.*]] = load <4 x i32>, ptr %[[PTR]] // CHECK-NEXT: ret <4 x i32> %[[VEC]] +export float TestLoadWithStatus() { + uint s1; + uint s2; + float ret = Buf.Load(1, s1) + float(RWBuf.Load(2, s2).y); + ret += float(s1 + s2); + return ret; +} + +// CHECK: define noundef nofpclass(nan inf) float @TestLoadWithStatus()() +// CHECK: call {{.*}} float @hlsl::Buffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @Buf, i32 noundef 1, ptr {{.*}} %tmp) +// CHECK: call {{.*}} <4 x i32> @hlsl::RWBuffer<unsigned int vector[4]>::Load(unsigned int, unsigned int&)(ptr {{.*}} @RWBuf, i32 noundef 2, ptr {{.*}} %tmp1) +// CHECK: add +// CHECK: ret float + +// CHECK: define {{.*}} float @hlsl::Buffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr {{.*}} %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 %[[LOADED_STATUS_ADDR]], align 4 +// CHECK-NEXT: ret float %[[VALUE]] + +// CHECK: define {{.*}} <4 x i32> @hlsl::RWBuffer<unsigned int vector[4]>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr {{.*}} %Status) +// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RWBuffer", ptr %{{.*}}, i32 0, i32 0 +// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.TypedBuffer", <4 x i32>, 1, 0, 0), ptr %__handle +// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr +// CHECK-NEXT: %[[LOADED_STATUS_ADDR:.*]] = load ptr, ptr %Status.addr +// DXIL-NEXT: %[[STRUCT:.*]] = call { <4 x i32>, i1 } @llvm.dx.resource.load.typedbuffer.v4i32.tdx.TypedBuffer_v4i32_1_0_0t(target("dx.TypedBuffer", <4 x i32>, 1, 0, 0) %[[HANDLE]], i32 %[[INDEX]]) +// CHECK-NEXT: %[[VALUE:.*]] = extractvalue { <4 x i32>, i1 } %[[STRUCT]], 0 +// CHECK-NEXT: %[[STATUS_TEMP:.*]] = extractvalue { <4 x i32>, i1 } %[[STRUCT]], 1 +// CHECK-NEXT: %[[STATUS_EXT:.*]] = zext i1 %[[STATUS_TEMP]] to i32 +// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %[[LOADED_STATUS_ADDR]], align 4 +// CHECK-NEXT: ret <4 x i32> %[[VALUE]] + export uint TestGetDimensions() { uint dim1, dim2; Buf.GetDimensions(dim1); |
