Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -4934,6 +4934,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];
Expand Down
50 changes: 50 additions & 0 deletions clang/lib/CodeGen/CGHLSLBuiltins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,56 @@ 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 (since it's a reference)
LValue StatusLVal = EmitLValue(E->getArg(2));
Address StatusAddr = StatusLVal.getAddress();

QualType HandleTy = E->getArg(0)->getType();
const HLSLAttributedResourceType *RT =
HandleTy->getAs<HLSLAttributedResourceType>();
assert(RT && "Expected a resource type as first parameter");

Intrinsic::ID IntrID = RT->getAttrs().RawBuffer
? llvm::Intrinsic::dx_resource_load_rawbuffer
: llvm::Intrinsic::dx_resource_load_typedbuffer;

QualType BuiltinRetTy = E->getType();
llvm::Type *DataTy = ConvertType(BuiltinRetTy->getPointeeType());

llvm::Type *IntrinsicRetTy = llvm::StructType::get(
Builder.getContext(), {DataTy, Builder.getInt1Ty()});

SmallVector<Value *, 3> Args;
Args.push_back(HandleOp);
Args.push_back(IndexOp);

if (RT->getAttrs().RawBuffer) {
Args.push_back(Builder.getInt32(0)); // dummy offset
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it'd be clearer to introduce an extra variable to say what this argument is, instead of this comment. That is

Suggested change
Args.push_back(Builder.getInt32(0)); // dummy offset
Value *Offset = Builder.getInt32(0);
Args.push_back(Offset);

}

// Call the intrinsic (returns a struct)
Value *ResRet =
Builder.CreateIntrinsic(IntrinsicRetTy, 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());
return llvm::PoisonValue::get(HandleTy);
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Headers/hlsl/hlsl_intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -605,5 +605,7 @@ smoothstep(__detail::HLSL_FIXED_VECTOR<float, N> Min,
return __detail::smoothstep_vec_impl(Min, Max, X);
}

bool CheckAccessFullyMapped(uint Status) { return static_cast<bool>(Status); }

} // namespace hlsl
#endif //_HLSL_HLSL_INTRINSICS_H_
28 changes: 28 additions & 0 deletions clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -1232,6 +1233,33 @@ 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 ElemTy = getHandleElementType();
QualType AddrSpaceElemTy =
AST.getAddrSpaceQualType(ElemTy, LangAS::hlsl_device);
QualType ElemPtrTy = AST.getPointerType(AddrSpaceElemTy);
QualType ReturnTy;

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_load_with_status", ElemPtrTy,
PH::Handle, PH::_0, PH::_1)
.dereference(PH::LastStmt)
.finalize();
}

BuiltinTypeDeclBuilder &
BuiltinTypeDeclBuilder::addHandleAccessFunction(DeclarationName &Name,
bool IsConst, bool IsRef) {
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
21 changes: 21 additions & 0 deletions clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3010,6 +3010,27 @@ 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))
return true;

auto *ResourceTy =
TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
QualType ContainedTy = ResourceTy->getContainedType();
auto ReturnType =
SemaRef.Context.getAddrSpaceQualType(ContainedTy, LangAS::hlsl_device);
ReturnType = SemaRef.Context.getPointerType(ReturnType);
TheCall->setType(ReturnType);
TheCall->setValueKind(VK_LValue);

break;
}

case Builtin::BI__builtin_hlsl_resource_uninitializedhandle: {
if (SemaRef.checkArgCount(TheCall, 1) ||
CheckResourceHandle(&SemaRef, TheCall, 0))
Expand Down
21 changes: 21 additions & 0 deletions clang/test/AST/HLSL/StructuredBuffers-AST.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,27 @@ RESOURCE<float> Buffer;
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline

// Load with status method

// CHECK-LOAD: CXXMethodDecl {{.*}} Load 'element_type (unsigned int, unsigned int &)'
// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Status 'unsigned int &'
// CHECK-LOAD-NEXT: CompoundStmt
// CHECK-LOAD-NEXT: ReturnStmt
// CHECK-LOAD-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' prefix '*' cannot overflow
// CHECK-LOAD-NEXT: CallExpr {{.*}} 'hlsl_device element_type *'
// CHECK-LOAD-NEXT: ImplicitCastExpr {{.*}} <BuiltinFnToFnPtr>
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_load_with_status' 'void (...) noexcept'
// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
// CHECK-LOAD-UAV-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-LOAD-SRV-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
// CHECK-LOAD-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
// CHECK-LOAD-SAME: lvalue .__handle {{.*}}
// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue implicit this
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Status' 'unsigned int &'
// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline

// IncrementCounter method

// CHECK-COUNTER: CXXMethodDecl {{.*}} IncrementCounter 'unsigned int ()'
Expand Down
20 changes: 20 additions & 0 deletions clang/test/AST/HLSL/TypedBuffers-AST.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,26 @@ RESOURCE<float> Buffer;
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
// CHECK-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline

// Load with status method
// CHECK-NEXT: CXXMethodDecl {{.*}} Load 'element_type (unsigned int, unsigned int &)'
// CHECK-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
// CHECK-NEXT: ParmVarDecl {{.*}} Status 'unsigned int &'
// CHECK-NEXT: CompoundStmt
// CHECK-NEXT: ReturnStmt
// CHECK-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' prefix '*' cannot overflow
// CHECK-NEXT: CallExpr {{.*}} 'hlsl_device element_type *'
// CHECK-NEXT: ImplicitCastExpr {{.*}} <BuiltinFnToFnPtr>
// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_load_with_status' 'void (...) noexcept'
// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
// CHECK-UAV-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SRV-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
// CHECK-SAME: lvalue .__handle {{.*}}
// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue implicit this
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Status' 'unsigned int &'
// CHECK-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline

// GetDimensions method

// CHECK-NEXT: CXXMethodDecl {{.*}} GetDimensions 'void (out unsigned int)'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,46 @@ 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 noundef nonnull align 4 dereferenceable(4) %s1)
// CHECK: call {{.*}} float @hlsl::StructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @SB1, i32 noundef 2, ptr noundef nonnull align 4 dereferenceable(4) %s2)
// CHECK: add
// CHECK: ret float

// CHECK: define {{.*}} float @hlsl::RWStructuredBuffer<float>::Load(unsigned int, 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
// CHECK-NEXT: %[[STATUS:.*]] = load ptr, ptr %Status.addr,
// DXIL-NEXT: %[[STRUCT:.*]] = call { ptr, i1 } @llvm.dx.resource.load.rawbuffer.p0.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %[[HANDLE]], i32 %[[INDEX]], i32 0)
// CHECK-NEXT: %[[VALUE:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 0
// CHECK-NEXT: %[[STATUS_TEMP:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 1
// CHECK-NEXT: %[[STATUS_EXT:.*]] = zext i1 %[[STATUS_TEMP]] to i32
// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %2, align 4
// CHECK-NEXT: %[[RETVAL:.*]] = load float, ptr %[[VALUE]]
// CHECK-NEXT: ret float %[[RETVAL]]

// CHECK: define {{.*}} float @hlsl::StructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noundef nonnull align 4 dereferenceable(4) %Status)
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::StructuredBuffer", ptr %{{.*}}, i32 0, i32 0
// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", float, 0, 0), ptr %__handle
// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
// 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;
SB1.GetDimensions(dim1, stride1);
Expand Down
39 changes: 39 additions & 0 deletions clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-ps.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,45 @@ export float TestLoad() {
// CHECK-NEXT: %[[VAL:.*]] = load <2 x i32>, ptr %[[BUFPTR]]
// CHECK-NEXT: ret <2 x i32> %[[VAL]]

export float TestLoadWithStatus() {
uint status;
uint status2;
float val = ROSB1.Load(10, status).x + ROSB2.Load(20, status2).x;
return val + float(status + status2);
}

// CHECK: define {{.*}} float @TestLoadWithStatus()()
// CHECK: call {{.*}} float @hlsl::RasterizerOrderedStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @ROSB1, i32 noundef 10, ptr noundef nonnull align 4 dereferenceable(4) %status)
// CHECK: call {{.*}} <2 x i32> @hlsl::RasterizerOrderedStructuredBuffer<int vector[2]>::Load(unsigned int, unsigned int&)(ptr {{.*}} @ROSB2, i32 noundef 20, ptr noundef nonnull align 4 dereferenceable(4) %status2)
// CHECK: ret

// CHECK: define {{.*}} float @hlsl::RasterizerOrderedStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %Index, ptr noundef nonnull align 4 dereferenceable(4) %Status)
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RasterizerOrderedStructuredBuffer", ptr {{.*}}, i32 0, i32 0
// CHECK-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", float, 1, 1), ptr %__handle
// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
// CHECK-NEXT: %[[STATUS:.*]] = load ptr, ptr %Status.addr,
// DXIL-NEXT: %[[STRUCT:.*]] = call { ptr, i1 } @llvm.dx.resource.load.rawbuffer.p0.tdx.RawBuffer_f32_1_1t(target("dx.RawBuffer", float, 1, 1) %[[HANDLE]], i32 %[[INDEX]], i32 0)
// CHECK-NEXT: %[[VALUE:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 0
// CHECK-NEXT: %[[STATUS_TEMP:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 1
// CHECK-NEXT: %[[STATUS_EXT:.*]] = zext i1 %[[STATUS_TEMP]] to i32
// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %2, align 4
// CHECK-NEXT: %[[RETVAL:.*]] = load float, ptr %[[VALUE]]
// CHECK-NEXT: ret float %[[RETVAL]]

// CHECK: define {{.*}} <2 x i32> @hlsl::RasterizerOrderedStructuredBuffer<int vector[2]>::Load(unsigned int, unsigned int&)(ptr {{.*}} %Index, ptr noundef nonnull align 4 dereferenceable(4) %Status)
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RasterizerOrderedStructuredBuffer.0", ptr {{.*}}, i32 0, i32 0
// CHECK-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", <2 x i32>, 1, 1), ptr %__handle
// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
// CHECK-NEXT: %[[STATUS_HANDLE:.*]] = load ptr, ptr %Status.addr, align 4, !nonnull !3, !align !4
// 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() {
uint dim1, dim2, stride1, stride2;
ROSB1.GetDimensions(dim1, stride1);
Expand Down
40 changes: 40 additions & 0 deletions clang/test/CodeGenHLSL/resources/TypedBuffers-methods.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,46 @@ export float TestLoad() {
// CHECK-NEXT: %[[VEC:.*]] = load <4 x i32>, ptr %[[PTR]]
// CHECK-NEXT: ret <4 x i32> %[[VEC]]

export float TestLoadWithStatus() {
uint s1;
uint s2;
float ret = Buf.Load(1, s1) + float(RWBuf.Load(2, s2).y);
ret += float(s1 + s2);
return ret;
}

// CHECK: define noundef nofpclass(nan inf) float @TestLoadWithStatus()()
// CHECK: call {{.*}} float @hlsl::Buffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @Buf, i32 noundef 1, ptr noundef nonnull align 4 dereferenceable(4) %s1)
// CHECK: call {{.*}} <4 x i32> @hlsl::RWBuffer<unsigned int vector[4]>::Load(unsigned int, unsigned int&)(ptr {{.*}} @RWBuf, i32 noundef 2, ptr noundef nonnull align 4 dereferenceable(4) %s2)
// CHECK: add
// CHECK: ret float

// CHECK: define {{.*}} float @hlsl::Buffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noundef nonnull align 4 dereferenceable(4) %Status)
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::Buffer", ptr %{{.*}}, i32 0, i32 0
// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.TypedBuffer", float, 0, 0, 0), ptr %__handle
// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
// CHECK-NEXT: %[[STATUS:.*]] = load ptr, ptr %Status.addr,
// DXIL-NEXT: %[[STRUCT:.*]] = call { ptr, i1 } @llvm.dx.resource.load.typedbuffer.p0.tdx.TypedBuffer_f32_0_0_0t(target("dx.TypedBuffer", float, 0, 0, 0) %[[HANDLE]], i32 %[[INDEX]])
// CHECK-NEXT: %[[VALUE:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 0
// CHECK-NEXT: %[[STATUS_TEMP:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 1
// CHECK-NEXT: %[[STATUS_EXT:.*]] = zext i1 %[[STATUS_TEMP]] to i32
// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %2, align 4
// CHECK-NEXT: %[[RETVAL:.*]] = load float, ptr %[[VALUE]]
// CHECK-NEXT: ret float %[[RETVAL]]

// CHECK: define {{.*}} <4 x i32> @hlsl::RWBuffer<unsigned int vector[4]>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noundef nonnull align 4 dereferenceable(4) %Status)
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RWBuffer", ptr %{{.*}}, i32 0, i32 0
// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.TypedBuffer", <4 x i32>, 1, 0, 0), ptr %__handle
// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
// CHECK-NEXT: %[[STATUS_HANDLE:.*]] = load ptr, ptr %Status.addr, align 4, !nonnull !3, !align !4
// DXIL-NEXT: %[[STRUCT:.*]] = call { ptr, i1 } @llvm.dx.resource.load.typedbuffer.p0.tdx.TypedBuffer_v4i32_1_0_0t(target("dx.TypedBuffer", <4 x i32>, 1, 0, 0) %0, i32 %1)
// CHECK-NEXT: %[[VALUE:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 0
// CHECK-NEXT: %[[STATUS:.*]] = extractvalue { ptr, i1 } %[[STRUCT]], 1
// CHECK-NEXT: %[[STATUS_EXT:.*]] = zext i1 %[[STATUS]] to i32
// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %2, align 4
// CHECK-NEXT: %[[RETVAL:.*]] = load <4 x i32>, ptr %[[VALUE]]
// CHECK-NEXT: ret <4 x i32> %[[RETVAL]]

export uint TestGetDimensions() {
uint dim1, dim2;
Buf.GetDimensions(dim1);
Expand Down
4 changes: 4 additions & 0 deletions llvm/include/llvm/IR/IntrinsicsDirectX.td
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ 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]>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We never generate this.


def int_dx_resource_nonuniformindex
: DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem]>;

Expand Down
3 changes: 3 additions & 0 deletions llvm/include/llvm/IR/IntrinsicsSPIRV.td
Original file line number Diff line number Diff line change
Expand Up @@ -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_load_with_status
: DefaultAttrsIntrinsic<[llvm_anyptr_ty], [llvm_any_ty, llvm_i32_ty, llvm_i32_ty],
[IntrNoMem]>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I opened #166954 to track the implementing this in the SPIR-V backend.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we aren't actually generating this ever, and the logic for DirectX has special handling depending on the resource type, it's probably best not to define this intrinsic at this point. @bob80905 was there an existing issue to support Load(int, out uint) and CheckAccessFullyMapped in SPIR-V, or should we use #166954 (in which case we need to add some detail there)?


def int_spv_resource_nonuniformindex
: DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem]>;
Expand Down
Loading
Loading