Skip to content

Commit fea070b

Browse files
authored
[HLSL] Add Load overload with status (llvm#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: llvm#138910 Also only addresses the DXIL variant for the below issue: llvm#99204
1 parent 00fb67a commit fea070b

File tree

12 files changed

+272
-3
lines changed

12 files changed

+272
-3
lines changed

clang/include/clang/Basic/Builtins.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4946,6 +4946,12 @@ def HLSLResourceGetPointer : LangBuiltin<"HLSL_LANG"> {
49464946
let Prototype = "void(...)";
49474947
}
49484948

4949+
def HLSLResourceLoadWithStatus : LangBuiltin<"HLSL_LANG"> {
4950+
let Spellings = ["__builtin_hlsl_resource_load_with_status"];
4951+
let Attributes = [NoThrow];
4952+
let Prototype = "void(...)";
4953+
}
4954+
49494955
def HLSLResourceUninitializedHandle : LangBuiltin<"HLSL_LANG"> {
49504956
let Spellings = ["__builtin_hlsl_resource_uninitializedhandle"];
49514957
let Attributes = [NoThrow];

clang/lib/CodeGen/CGHLSLBuiltins.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,49 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
404404
RetTy, CGM.getHLSLRuntime().getCreateResourceGetPointerIntrinsic(),
405405
ArrayRef<Value *>{HandleOp, IndexOp});
406406
}
407+
case Builtin::BI__builtin_hlsl_resource_load_with_status: {
408+
Value *HandleOp = EmitScalarExpr(E->getArg(0));
409+
Value *IndexOp = EmitScalarExpr(E->getArg(1));
410+
411+
// Get the *address* of the status argument to write to it by reference
412+
LValue StatusLVal = EmitLValue(E->getArg(2));
413+
Address StatusAddr = StatusLVal.getAddress();
414+
415+
QualType HandleTy = E->getArg(0)->getType();
416+
const HLSLAttributedResourceType *RT =
417+
HandleTy->getAs<HLSLAttributedResourceType>();
418+
assert(CGM.getTarget().getTriple().getArch() == llvm::Triple::dxil &&
419+
"Only DXIL currently implements load with status");
420+
421+
Intrinsic::ID IntrID = RT->getAttrs().RawBuffer
422+
? llvm::Intrinsic::dx_resource_load_rawbuffer
423+
: llvm::Intrinsic::dx_resource_load_typedbuffer;
424+
425+
llvm::Type *DataTy = ConvertType(E->getType());
426+
llvm::Type *RetTy = llvm::StructType::get(Builder.getContext(),
427+
{DataTy, Builder.getInt1Ty()});
428+
429+
SmallVector<Value *, 3> Args;
430+
Args.push_back(HandleOp);
431+
Args.push_back(IndexOp);
432+
433+
if (RT->getAttrs().RawBuffer) {
434+
Value *Offset = Builder.getInt32(0);
435+
Args.push_back(Offset);
436+
}
437+
438+
// The load intrinsics give us a (T value, i1 status) pair -
439+
// shepherd these into the return value and out reference respectively.
440+
Value *ResRet =
441+
Builder.CreateIntrinsic(RetTy, IntrID, Args, {}, "ld.struct");
442+
Value *LoadedValue = Builder.CreateExtractValue(ResRet, {0}, "ld.value");
443+
Value *StatusBit = Builder.CreateExtractValue(ResRet, {1}, "ld.status");
444+
Value *ExtendedStatus =
445+
Builder.CreateZExt(StatusBit, Builder.getInt32Ty(), "ld.status.ext");
446+
Builder.CreateStore(ExtendedStatus, StatusAddr);
447+
448+
return LoadedValue;
449+
}
407450
case Builtin::BI__builtin_hlsl_resource_uninitializedhandle: {
408451
llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType());
409452
return llvm::PoisonValue::get(HandleTy);

clang/lib/Headers/hlsl/hlsl_intrinsics.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,10 @@ smoothstep(__detail::HLSL_FIXED_VECTOR<float, N> Min,
666666
return __detail::smoothstep_vec_impl(Min, Max, X);
667667
}
668668

669+
inline bool CheckAccessFullyMapped(uint Status) {
670+
return static_cast<bool>(Status);
671+
}
672+
669673
//===----------------------------------------------------------------------===//
670674
// fwidth builtin
671675
//===----------------------------------------------------------------------===//

clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ struct BuiltinTypeMethodBuilder {
202202
BuiltinTypeMethodBuilder &declareLocalVar(LocalVar &Var);
203203
template <typename... Ts>
204204
BuiltinTypeMethodBuilder &callBuiltin(StringRef BuiltinName,
205-
QualType ReturnType, Ts... ArgSpecs);
205+
QualType ReturnType, Ts &&...ArgSpecs);
206206
template <typename TLHS, typename TRHS>
207207
BuiltinTypeMethodBuilder &assign(TLHS LHS, TRHS RHS);
208208
template <typename T> BuiltinTypeMethodBuilder &dereference(T Ptr);
@@ -572,7 +572,7 @@ BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::returnThis() {
572572
template <typename... Ts>
573573
BuiltinTypeMethodBuilder &
574574
BuiltinTypeMethodBuilder::callBuiltin(StringRef BuiltinName,
575-
QualType ReturnType, Ts... ArgSpecs) {
575+
QualType ReturnType, Ts &&...ArgSpecs) {
576576
ensureCompleteDecl();
577577

578578
std::array<Expr *, sizeof...(ArgSpecs)> Args{
@@ -1140,6 +1140,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addLoadMethods() {
11401140
DeclarationName Load(&II);
11411141
// TODO: We also need versions with status for CheckAccessFullyMapped.
11421142
addHandleAccessFunction(Load, /*IsConst=*/false, /*IsRef=*/false);
1143+
addLoadWithStatusFunction(Load, /*IsConst=*/false);
11431144

11441145
return *this;
11451146
}
@@ -1232,6 +1233,22 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDecrementCounterMethod() {
12321233
.finalize();
12331234
}
12341235

1236+
BuiltinTypeDeclBuilder &
1237+
BuiltinTypeDeclBuilder::addLoadWithStatusFunction(DeclarationName &Name,
1238+
bool IsConst) {
1239+
assert(!Record->isCompleteDefinition() && "record is already complete");
1240+
ASTContext &AST = SemaRef.getASTContext();
1241+
using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1242+
1243+
QualType ReturnTy = getHandleElementType();
1244+
return BuiltinTypeMethodBuilder(*this, Name, ReturnTy, IsConst)
1245+
.addParam("Index", AST.UnsignedIntTy)
1246+
.addParam("Status", AST.UnsignedIntTy, HLSLParamModifierAttr::Keyword_out)
1247+
.callBuiltin("__builtin_hlsl_resource_load_with_status", ReturnTy,
1248+
PH::Handle, PH::_0, PH::_1)
1249+
.finalize();
1250+
}
1251+
12351252
BuiltinTypeDeclBuilder &
12361253
BuiltinTypeDeclBuilder::addHandleAccessFunction(DeclarationName &Name,
12371254
bool IsConst, bool IsRef) {

clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ class BuiltinTypeDeclBuilder {
9191
BuiltinTypeDeclBuilder &addDecrementCounterMethod();
9292
BuiltinTypeDeclBuilder &addHandleAccessFunction(DeclarationName &Name,
9393
bool IsConst, bool IsRef);
94+
BuiltinTypeDeclBuilder &addLoadWithStatusFunction(DeclarationName &Name,
95+
bool IsConst);
9496
BuiltinTypeDeclBuilder &addAppendMethod();
9597
BuiltinTypeDeclBuilder &addConsumeMethod();
9698

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3057,6 +3057,24 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
30573057

30583058
break;
30593059
}
3060+
case Builtin::BI__builtin_hlsl_resource_load_with_status: {
3061+
if (SemaRef.checkArgCount(TheCall, 3) ||
3062+
CheckResourceHandle(&SemaRef, TheCall, 0) ||
3063+
CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
3064+
SemaRef.getASTContext().UnsignedIntTy) ||
3065+
CheckArgTypeMatches(&SemaRef, TheCall->getArg(2),
3066+
SemaRef.getASTContext().UnsignedIntTy) ||
3067+
CheckModifiableLValue(&SemaRef, TheCall, 2))
3068+
return true;
3069+
3070+
auto *ResourceTy =
3071+
TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
3072+
QualType ReturnType = ResourceTy->getContainedType();
3073+
TheCall->setType(ReturnType);
3074+
3075+
break;
3076+
}
3077+
30603078
case Builtin::BI__builtin_hlsl_resource_uninitializedhandle: {
30613079
assert(TheCall->getNumArgs() == 1 && "expected 1 arg");
30623080
// Update return type to be the attributed resource type from arg0.

clang/test/AST/HLSL/StructuredBuffers-AST.hlsl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,26 @@ RESOURCE<float> Buffer;
326326
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
327327
// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
328328

329+
// Load with status method
330+
331+
// CHECK-LOAD: CXXMethodDecl {{.*}} Load 'element_type (unsigned int, out unsigned int)'
332+
// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
333+
// CHECK-LOAD-NEXT: ParmVarDecl {{.*}} Status 'unsigned int &__restrict'
334+
// CHECK-LOAD-NEXT: HLSLParamModifierAttr {{.*}} out
335+
// CHECK-LOAD-NEXT: CompoundStmt
336+
// CHECK-LOAD-NEXT: ReturnStmt
337+
// CHECK-LOAD-NEXT: CallExpr {{.*}} 'element_type'
338+
// CHECK-LOAD-NEXT: ImplicitCastExpr {{.*}} <BuiltinFnToFnPtr>
339+
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_load_with_status' 'void (...) noexcept'
340+
// CHECK-LOAD-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
341+
// CHECK-LOAD-UAV-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
342+
// CHECK-LOAD-SRV-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
343+
// CHECK-LOAD-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
344+
// CHECK-LOAD-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue implicit this
345+
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
346+
// CHECK-LOAD-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Status' 'unsigned int &__restrict'
347+
// CHECK-LOAD-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
348+
329349
// IncrementCounter method
330350

331351
// CHECK-COUNTER: CXXMethodDecl {{.*}} IncrementCounter 'unsigned int ()'

clang/test/AST/HLSL/TypedBuffers-AST.hlsl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,25 @@ RESOURCE<float> Buffer;
214214
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
215215
// CHECK-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
216216

217+
// Load with status method
218+
// CHECK: CXXMethodDecl {{.*}} Load 'element_type (unsigned int, out unsigned int)'
219+
// CHECK-NEXT: ParmVarDecl {{.*}} Index 'unsigned int'
220+
// CHECK-NEXT: ParmVarDecl {{.*}} Status 'unsigned int &__restrict'
221+
// CHECK-NEXT: HLSLParamModifierAttr {{.*}} out
222+
// CHECK-NEXT: CompoundStmt
223+
// CHECK-NEXT: ReturnStmt
224+
// CHECK-NEXT: CallExpr {{.*}} 'element_type'
225+
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
226+
// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_load_with_status' 'void (...) noexcept'
227+
// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t
228+
// CHECK-UAV-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
229+
// CHECK-SRV-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
230+
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
231+
// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]<element_type>' lvalue implicit this
232+
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int'
233+
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Status' 'unsigned int &__restrict'
234+
// CHECK-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline
235+
217236
// GetDimensions method
218237

219238
// CHECK-NEXT: CXXMethodDecl {{.*}} GetDimensions 'void (out unsigned int)'

clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-lib.hlsl

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,44 @@ export float TestLoad() {
104104
// CHECK-NEXT: %[[VAL:.*]] = load float, ptr %[[PTR]]
105105
// CHECK-NEXT: ret float %[[VAL]]
106106

107+
export float TestLoadWithStatus() {
108+
uint s1;
109+
uint s2;
110+
float ret = RWSB1.Load(1, s1) + SB1.Load(2, s2);
111+
ret += float(s1 + s2);
112+
return ret;
113+
}
114+
115+
// CHECK: define noundef nofpclass(nan inf) float @TestLoadWithStatus()()
116+
// CHECK: call {{.*}} float @hlsl::RWStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @RWSB1, i32 noundef 1, ptr {{.*}} %tmp)
117+
// CHECK: call {{.*}} float @hlsl::StructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @SB1, i32 noundef 2, ptr {{.*}} %tmp1)
118+
// CHECK: add
119+
// CHECK: ret float
120+
121+
// CHECK: define {{.*}} float @hlsl::RWStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr {{.*}} %Status)
122+
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RWStructuredBuffer", ptr %{{.*}}, i32 0, i32 0
123+
// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", float, 1, 0), ptr %__handle
124+
// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
125+
// CHECK-NEXT: %[[LOADED_STATUS_ADDR:.*]] = load ptr, ptr %Status.addr
126+
// 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)
127+
// CHECK-NEXT: %[[VALUE:.*]] = extractvalue { float, i1 } %[[STRUCT]], 0
128+
// CHECK-NEXT: %[[STATUS_TEMP:.*]] = extractvalue { float, i1 } %[[STRUCT]], 1
129+
// CHECK-NEXT: %[[STATUS_EXT:.*]] = zext i1 %[[STATUS_TEMP]] to i32
130+
// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %[[LOADED_STATUS_ADDR]], align 4
131+
// CHECK-NEXT: ret float %[[VALUE]]
132+
133+
// CHECK: define {{.*}} float @hlsl::StructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr {{.*}} %Status)
134+
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::StructuredBuffer", ptr %{{.*}}, i32 0, i32 0
135+
// DXIL-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", float, 0, 0), ptr %__handle
136+
// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
137+
// CHECK-NEXT: %[[LOADED_STATUS_ADDR:.*]] = load ptr, ptr %Status.addr, align 4
138+
// 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)
139+
// CHECK-NEXT: %[[VALUE:.*]] = extractvalue { float, i1 } %[[STRUCT]], 0
140+
// CHECK-NEXT: %[[STATUS_TEMP:.*]] = extractvalue { float, i1 } %[[STRUCT]], 1
141+
// CHECK-NEXT: %[[STATUS_EXT:.*]] = zext i1 %[[STATUS_TEMP]] to i32
142+
// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %[[LOADED_STATUS_ADDR]], align 4
143+
// CHECK-NEXT: ret float %[[VALUE]]
144+
107145
export uint TestGetDimensions() {
108146
uint dim1, dim2, dim3, stride1, stride2, stride3;
109147
SB1.GetDimensions(dim1, stride1);

clang/test/CodeGenHLSL/resources/StructuredBuffers-methods-ps.hlsl

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,43 @@ export float TestLoad() {
6565
// CHECK-NEXT: %[[VAL:.*]] = load <2 x i32>, ptr %[[BUFPTR]]
6666
// CHECK-NEXT: ret <2 x i32> %[[VAL]]
6767

68+
export float TestLoadWithStatus() {
69+
uint status;
70+
uint status2;
71+
float val = ROSB1.Load(10, status).x + ROSB2.Load(20, status2).x;
72+
return val + float(status + status2);
73+
}
74+
75+
// CHECK: define {{.*}} float @TestLoadWithStatus()()
76+
// CHECK: call {{.*}} float @hlsl::RasterizerOrderedStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} @ROSB1, i32 noundef 10, ptr {{.*}} %tmp)
77+
// CHECK: call {{.*}} <2 x i32> @hlsl::RasterizerOrderedStructuredBuffer<int vector[2]>::Load(unsigned int, unsigned int&)(ptr {{.*}} @ROSB2, i32 noundef 20, ptr {{.*}} %tmp2)
78+
// CHECK: ret
79+
80+
// CHECK: define {{.*}} float @hlsl::RasterizerOrderedStructuredBuffer<float>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr {{.*}} %Status)
81+
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RasterizerOrderedStructuredBuffer", ptr {{.*}}, i32 0, i32 0
82+
// CHECK-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", float, 1, 1), ptr %__handle
83+
// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
84+
// CHECK-NEXT: %[[LOADED_STATUS_ADDR:.*]] = load ptr, ptr %Status.addr, align 4
85+
// 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)
86+
// CHECK-NEXT: %[[VALUE:.*]] = extractvalue { float, i1 } %[[STRUCT]], 0
87+
// CHECK-NEXT: %[[STATUS_TEMP:.*]] = extractvalue { float, i1 } %[[STRUCT]], 1
88+
// CHECK-NEXT: %[[STATUS_EXT:.*]] = zext i1 %[[STATUS_TEMP]] to i32
89+
// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %[[LOADED_STATUS_ADDR]], align 4
90+
// CHECK-NEXT: ret float %[[VALUE]]
91+
92+
// CHECK: define {{.*}} <2 x i32> @hlsl::RasterizerOrderedStructuredBuffer<int vector[2]>::Load(unsigned int, unsigned int&)(ptr {{.*}} %this, i32 noundef %Index, ptr {{.*}} %Status)
93+
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RasterizerOrderedStructuredBuffer.0", ptr {{.*}}, i32 0, i32 0
94+
// CHECK-NEXT: %[[HANDLE:.*]] = load target("dx.RawBuffer", <2 x i32>, 1, 1), ptr %__handle
95+
// CHECK-NEXT: %[[INDEX:.*]] = load i32, ptr %Index.addr
96+
// CHECK-NEXT: %[[LOADED_STATUS_ADDR:.*]] = load ptr, ptr %Status.addr, align 4
97+
// 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)
98+
// CHECK-NEXT: %[[VALUE:.*]] = extractvalue { <2 x i32>, i1 } %[[STRUCT]], 0
99+
// CHECK-NEXT: %[[STATUS_TEMP:.*]] = extractvalue { <2 x i32>, i1 } %[[STRUCT]], 1
100+
// CHECK-NEXT: %[[STATUS_EXT:.*]] = zext i1 %[[STATUS_TEMP]] to i32
101+
// CHECK-NEXT: store i32 %[[STATUS_EXT]], ptr %[[LOADED_STATUS_ADDR]], align 4
102+
// CHECK-NEXT: ret <2 x i32> %[[VALUE]]
103+
104+
68105
export uint TestGetDimensions() {
69106
uint dim1, dim2, stride1, stride2;
70107
ROSB1.GetDimensions(dim1, stride1);

0 commit comments

Comments
 (0)