Author: Joshua Batista
Date: 2025-11-21T10:11:38-08:00
New Revision: fea070b610e0dc08447be60db7f13c150b2892d5

URL: 
https://github.com/llvm/llvm-project/commit/fea070b610e0dc08447be60db7f13c150b2892d5
DIFF: 
https://github.com/llvm/llvm-project/commit/fea070b610e0dc08447be60db7f13c150b2892d5.diff

LOG: [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

Added: 
    

Modified: 
    clang/include/clang/Basic/Builtins.td
    clang/lib/CodeGen/CGHLSLBuiltins.cpp
    clang/lib/Headers/hlsl/hlsl_intrinsics.h
    clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
    clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
    clang/lib/Sema/SemaHLSL.cpp
    clang/test/AST/HLSL/StructuredBuffers-AST.hlsl
    clang/test/AST/HLSL/TypedBuffers-AST.hlsl
    clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-lib.hlsl
    clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-ps.hlsl
    clang/test/CodeGenHLSL/resources/TypedBuffers-methods.hlsl
    llvm/lib/Target/DirectX/DXILShaderFlags.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/Builtins.td 
b/clang/include/clang/Basic/Builtins.td
index 502382a069856..7530aebdcb581 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 12d9a98915ce3..5ae3fed099cd4 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 c26c8bb5261d4..a538be5ebd099 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 066acf6f01a90..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 <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;
 }
@@ -1232,6 +1233,22 @@ BuiltinTypeDeclBuilder 
&BuiltinTypeDeclBuilder::addDecrementCounterMethod() {
       .finalize();
 }
 
+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) {

diff  --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h 
b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
index 95e3a6c4fb2f1..47c8b0e225612 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
@@ -91,6 +91,8 @@ class BuiltinTypeDeclBuilder {
   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 c5666941fd36a..0a164a7b5bbbd 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 538eb5256f8d5..eb65a28dba6ff 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 4b66faa79662a..762386c622dad 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 1f248d0560006..54c386cab537b 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 25fa75965d686..157bae2e08a78 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 fdc1ef08b7c2c..499f5b1ca54ef 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);

diff  --git a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp 
b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
index ce6e8121b9d94..e0049dc75c0db 100644
--- a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
+++ b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
@@ -100,6 +100,26 @@ static bool checkWaveOps(Intrinsic::ID IID) {
   }
 }
 
+// Checks to see if the status bit from a load with status
+// 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");
+  for (const User *U : II.users()) {
+    if (const ExtractValueInst *EVI = dyn_cast<ExtractValueInst>(U)) {
+      // Resource load operations return a {result, status} pair.
+      // Check if we extract the status
+      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.
@@ -164,7 +184,7 @@ void 
ModuleShaderFlags::updateFunctionFlags(ComputedShaderFlags &CSF,
     }
   }
 
-  if (auto *II = dyn_cast<IntrinsicInst>(&I)) {
+  if (const auto *II = dyn_cast<IntrinsicInst>(&I)) {
     switch (II->getIntrinsicID()) {
     default:
       break;
@@ -192,6 +212,13 @@ void 
ModuleShaderFlags::updateFunctionFlags(ComputedShaderFlags &CSF,
           DRTM[cast<TargetExtType>(II->getArgOperand(0)->getType())];
       if (RTI.isTyped())
         CSF.TypedUAVLoadAdditionalFormats |= RTI.getTyped().ElementCount > 1;
+      if (!CSF.TiledResources && checkIfStatusIsExtracted(*II))
+        CSF.TiledResources = true;
+      break;
+    }
+    case Intrinsic::dx_resource_load_rawbuffer: {
+      if (!CSF.TiledResources && checkIfStatusIsExtracted(*II))
+        CSF.TiledResources = true;
       break;
     }
     }


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to