Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
51 changes: 51 additions & 0 deletions clang/lib/CodeGen/CGHLSLBuiltins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,57 @@ 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(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
: 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);
}

// 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
Copy link
Contributor

Choose a reason for hiding this comment

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

This comment just repeats what the code below says almost verbatim. The value of a comment here would be describing what the structure looks like or saying at a high level what we're doing here. Just listing the functions we're about to call isn't helpful.

I think the interesting thing to convey here is really "what does the intrinsic return and what do we need to do with it?", not "how do we extract values from some struct Value and zero-extend the result?".

Consider something like

The load intrinsics give us a (T value, i1 status) pair - shepherd these into the return value and out reference respectively.

Given this, hopefully the actual nuts and bolts of doing the operation are made obvious.

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");

Copy link
Contributor

Choose a reason for hiding this comment

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

Probably helps readability to get rid of the empty lines here - this is a block of tightly related code.

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
4 changes: 4 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,9 @@ 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);
}

} // namespace hlsl
#endif //_HLSL_HLSL_INTRINSICS_H_
29 changes: 27 additions & 2 deletions clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Copy link
Member

Choose a reason for hiding this comment

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

Can you please explain why is this change needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was originally needed to pass in a local variable to the callBuiltin function, but since your change no longer requires passing in a local variable, we don't need this change anymore.

Copy link
Contributor

Choose a reason for hiding this comment

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

We really should make this change anyway (maybe in a follow up?). The current logic here is incorrect, but it doesn't come up because we never pass a reference in to this function.

Copy link
Member

Choose a reason for hiding this comment

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

Agreed.

template <typename TLHS, typename TRHS>
BuiltinTypeMethodBuilder &assign(TLHS LHS, TRHS RHS);
template <typename T> BuiltinTypeMethodBuilder &dereference(T Ptr);
Expand Down Expand Up @@ -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{
Expand Down 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,30 @@ 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();
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)
Copy link
Member

Choose a reason for hiding this comment

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

I believe this should work:

Suggested change
.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)
.callBuiltin("__builtin_hlsl_resource_load_with_status", ReturnTy,
PH::Handle, PH::_0, PH::_1)

Copy link
Contributor

Choose a reason for hiding this comment

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

This plays pretty fast and loose with the types, but I guess it's okay in practice based on looking what gets generated in the tests. Note that with this AST we're explicitly passing in a uint to a bool parameter, which is generally pretty unsafe. I think it doesn't cause any problems because we're calling into a builtin and custom lowering everything anyway, so the issue gets papered over.

.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
17 changes: 17 additions & 0 deletions clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3010,6 +3010,23 @@ 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().BoolTy))
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: {
if (SemaRef.checkArgCount(TheCall, 1) ||
CheckResourceHandle(&SemaRef, TheCall, 0))
Expand Down
30 changes: 30 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,36 @@ 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: DeclStmt
// CHECK-LOAD-NEXT: VarDecl {{.*}} Result 'element_type'
// CHECK-LOAD-NEXT: DeclStmt
// CHECK-LOAD-NEXT: VarDecl {{.*}} StatusBool 'bool'
// CHECK-LOAD-NEXT: BinaryOperator {{.*}} 'element_type' '='
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'element_type' lvalue Var {{.*}} 'Result' 'element_type'
// CHECK-LOAD-NEXT: CallExpr {{.*}} 'element_type'
// CHECK-LOAD-NEXT: ImplicitCastExpr {{.*}} <BuiltinFnToFnPtr>
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_load_with_status' 'void (...) noexcept'
// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
// CHECK-LOAD-UAV-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-LOAD-SRV-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
// CHECK-LOAD-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue implicit this
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'bool' lvalue Var {{.*}} 'StatusBool' 'bool'
// CHECK-LOAD-NEXT: BinaryOperator {{.*}} 'unsigned int' '='
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Status' 'unsigned int &__restrict'
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'bool' lvalue Var {{.*}} 'StatusBool' 'bool'
// CHECK-LOAD-NEXT: ReturnStmt
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'element_type' lvalue Var {{.*}} 'Result' 'element_type'
// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline

// IncrementCounter method

// CHECK-COUNTER: CXXMethodDecl {{.*}} IncrementCounter 'unsigned int ()'
Expand Down
29 changes: 29 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,35 @@ 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: DeclStmt
// CHECK-NEXT: VarDecl {{.*}} Result 'element_type'
// CHECK-NEXT: DeclStmt
// CHECK-NEXT: VarDecl {{.*}} StatusBool 'bool'
// CHECK-NEXT: BinaryOperator {{.*}} 'element_type' '='
// CHECK-NEXT: DeclRefExpr {{.*}} 'element_type' lvalue Var {{.*}} 'Result' 'element_type'
// CHECK-NEXT: CallExpr {{.*}} 'element_type'
// CHECK-NEXT: ImplicitCastExpr {{.*}} <BuiltinFnToFnPtr>
// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_load_with_status' 'void (...) noexcept'
// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
// CHECK-UAV-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SRV-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue implicit this
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
// CHECK-NEXT: DeclRefExpr {{.*}} 'bool' lvalue Var {{.*}} 'StatusBool' 'bool'
// CHECK-NEXT: BinaryOperator {{.*}} 'unsigned int' '='
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Status' 'unsigned int &__restrict'
// CHECK-NEXT: DeclRefExpr {{.*}} 'bool' lvalue Var {{.*}} 'StatusBool' 'bool'
// CHECK-NEXT: ReturnStmt
// CHECK-NEXT: DeclRefExpr {{.*}} 'element_type' lvalue Var {{.*}} 'Result' 'element_type'
// CHECK-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline

// GetDimensions method

// 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,56 @@ 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 noalias noundef nonnull align 4 dereferenceable(4) %tmp)
// CHECK: call {{.*}} float @hlsl::StructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @SB1, i32 noundef 2, ptr noalias noundef nonnull align 4 dereferenceable(4) %tmp1)
// CHECK: add
// CHECK: ret float

// CHECK: define {{.*}} float @hlsl::RWStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr 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
// 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: define {{.*}} float @hlsl::StructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noalias noundef nonnull align 4 dereferenceable(4) %Status)
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::StructuredBuffer", ptr %{{.*}}, i32 0, i32 0
// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", float, 0, 0), ptr %__handle
// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
// 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;
SB1.GetDimensions(dim1, stride1);
Expand Down
49 changes: 49 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,55 @@ 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 noalias noundef nonnull align 4 dereferenceable(4) %tmp)
// CHECK: call {{.*}} <2 x i32> @hlsl::RasterizerOrderedStructuredBuffer<int vector[2]>::Load(unsigned int, unsigned int&)(ptr {{.*}} @ROSB2, i32 noundef 20, ptr noalias noundef nonnull align 4 dereferenceable(4) %tmp2)
// CHECK: ret

// CHECK: define {{.*}} float @hlsl::RasterizerOrderedStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %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
// 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: define {{.*}} <2 x i32> @hlsl::RasterizerOrderedStructuredBuffer<int vector[2]>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr noalias noundef nonnull align 4 dereferenceable(4) %Status)
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RasterizerOrderedStructuredBuffer.0", ptr {{.*}}, i32 0, i32 0
// CHECK-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", <2 x i32>, 1, 1), ptr %__handle
// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
// 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() {
uint dim1, dim2, stride1, stride2;
ROSB1.GetDimensions(dim1, stride1);
Expand Down
Loading
Loading