Skip to content

Commit 7f34d3a

Browse files
authored
[DirectX] Add support for typedBufferLoad and Store for RWBuffer<double2> and RWBuffer<double> (#139996)
typedBufferLoad of double/double2 is expanded to a typedBufferLoad of a <2 x i32>/<4 x i32> and asdouble typedBufferStore of a double/double2 is expanded to a splitdouble and a typedBufferStore of a <2 x i32>/<4 x i32> Add tests showing result of intrinsic expansion for typedBufferLoad and typedBufferStore Add tests showing dxil op lowering can handle typedBufferLoad and typedBufferStore where the target type doesn't match the typedBufferLoad and typedBufferStore type Closes #104423
1 parent 5301f4c commit 7f34d3a

File tree

5 files changed

+332
-0
lines changed

5 files changed

+332
-0
lines changed

llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,15 @@ static bool isIntrinsicExpansion(Function &F) {
7070
case Intrinsic::vector_reduce_add:
7171
case Intrinsic::vector_reduce_fadd:
7272
return true;
73+
case Intrinsic::dx_resource_load_typedbuffer:
74+
// We need to handle doubles and vector of doubles.
75+
return F.getReturnType()
76+
->getStructElementType(0)
77+
->getScalarType()
78+
->isDoubleTy();
79+
case Intrinsic::dx_resource_store_typedbuffer:
80+
// We need to handle doubles and vector of doubles.
81+
return F.getFunctionType()->getParamType(2)->getScalarType()->isDoubleTy();
7382
}
7483
return false;
7584
}
@@ -532,6 +541,110 @@ static Value *expandRadiansIntrinsic(CallInst *Orig) {
532541
return Builder.CreateFMul(X, PiOver180);
533542
}
534543

544+
static bool expandTypedBufferLoadIntrinsic(CallInst *Orig) {
545+
IRBuilder<> Builder(Orig);
546+
547+
Type *BufferTy = Orig->getType()->getStructElementType(0);
548+
assert(BufferTy->getScalarType()->isDoubleTy() &&
549+
"Only expand double or double2");
550+
551+
unsigned ExtractNum = 2;
552+
if (auto *VT = dyn_cast<FixedVectorType>(BufferTy)) {
553+
assert(VT->getNumElements() == 2 &&
554+
"TypedBufferLoad double vector has wrong size");
555+
ExtractNum = 4;
556+
}
557+
558+
Type *Ty = VectorType::get(Builder.getInt32Ty(), ExtractNum, false);
559+
560+
Type *LoadType = StructType::get(Ty, Builder.getInt1Ty());
561+
CallInst *Load =
562+
Builder.CreateIntrinsic(LoadType, Intrinsic::dx_resource_load_typedbuffer,
563+
{Orig->getOperand(0), Orig->getOperand(1)});
564+
565+
// extract the buffer load's result
566+
Value *Extract = Builder.CreateExtractValue(Load, {0});
567+
568+
SmallVector<Value *> ExtractElements;
569+
for (unsigned I = 0; I < ExtractNum; ++I)
570+
ExtractElements.push_back(
571+
Builder.CreateExtractElement(Extract, Builder.getInt32(I)));
572+
573+
// combine into double(s)
574+
Value *Result = PoisonValue::get(BufferTy);
575+
for (unsigned I = 0; I < ExtractNum; I += 2) {
576+
Value *Dbl =
577+
Builder.CreateIntrinsic(Builder.getDoubleTy(), Intrinsic::dx_asdouble,
578+
{ExtractElements[I], ExtractElements[I + 1]});
579+
if (ExtractNum == 4)
580+
Result =
581+
Builder.CreateInsertElement(Result, Dbl, Builder.getInt32(I / 2));
582+
else
583+
Result = Dbl;
584+
}
585+
586+
Value *CheckBit = nullptr;
587+
for (User *U : make_early_inc_range(Orig->users())) {
588+
auto *EVI = cast<ExtractValueInst>(U);
589+
ArrayRef<unsigned> Indices = EVI->getIndices();
590+
assert(Indices.size() == 1);
591+
592+
if (Indices[0] == 0) {
593+
// Use of the value(s)
594+
EVI->replaceAllUsesWith(Result);
595+
} else {
596+
// Use of the check bit
597+
assert(Indices[0] == 1 && "Unexpected type for typedbufferload");
598+
if (!CheckBit)
599+
CheckBit = Builder.CreateExtractValue(Load, {1});
600+
EVI->replaceAllUsesWith(CheckBit);
601+
}
602+
EVI->eraseFromParent();
603+
}
604+
Orig->eraseFromParent();
605+
return true;
606+
}
607+
608+
static bool expandTypedBufferStoreIntrinsic(CallInst *Orig) {
609+
IRBuilder<> Builder(Orig);
610+
611+
Type *BufferTy = Orig->getFunctionType()->getParamType(2);
612+
assert(BufferTy->getScalarType()->isDoubleTy() &&
613+
"Only expand double or double2");
614+
615+
unsigned ExtractNum = 2;
616+
if (auto *VT = dyn_cast<FixedVectorType>(BufferTy)) {
617+
assert(VT->getNumElements() == 2 &&
618+
"TypedBufferStore double vector has wrong size");
619+
ExtractNum = 4;
620+
}
621+
622+
Type *SplitElementTy = Builder.getInt32Ty();
623+
if (ExtractNum == 4)
624+
SplitElementTy = VectorType::get(SplitElementTy, 2, false);
625+
626+
// split our double(s)
627+
auto *SplitTy = llvm::StructType::get(SplitElementTy, SplitElementTy);
628+
Value *Split = Builder.CreateIntrinsic(SplitTy, Intrinsic::dx_splitdouble,
629+
Orig->getOperand(2));
630+
// create our vector
631+
Value *LowBits = Builder.CreateExtractValue(Split, 0);
632+
Value *HighBits = Builder.CreateExtractValue(Split, 1);
633+
Value *Val;
634+
if (ExtractNum == 2) {
635+
Val = PoisonValue::get(VectorType::get(SplitElementTy, 2, false));
636+
Val = Builder.CreateInsertElement(Val, LowBits, Builder.getInt32(0));
637+
Val = Builder.CreateInsertElement(Val, HighBits, Builder.getInt32(1));
638+
} else
639+
Val = Builder.CreateShuffleVector(LowBits, HighBits, {0, 2, 1, 3});
640+
641+
Builder.CreateIntrinsic(Builder.getVoidTy(),
642+
Intrinsic::dx_resource_store_typedbuffer,
643+
{Orig->getOperand(0), Orig->getOperand(1), Val});
644+
Orig->eraseFromParent();
645+
return true;
646+
}
647+
535648
static Intrinsic::ID getMaxForClamp(Intrinsic::ID ClampIntrinsic) {
536649
if (ClampIntrinsic == Intrinsic::dx_uclamp)
537650
return Intrinsic::umax;
@@ -660,6 +773,14 @@ static bool expandIntrinsic(Function &F, CallInst *Orig) {
660773
case Intrinsic::dx_radians:
661774
Result = expandRadiansIntrinsic(Orig);
662775
break;
776+
case Intrinsic::dx_resource_load_typedbuffer:
777+
if (expandTypedBufferLoadIntrinsic(Orig))
778+
return true;
779+
break;
780+
case Intrinsic::dx_resource_store_typedbuffer:
781+
if (expandTypedBufferStoreIntrinsic(Orig))
782+
return true;
783+
break;
663784
case Intrinsic::usub_sat:
664785
Result = expandUsubSat(Orig);
665786
break;

llvm/test/CodeGen/DirectX/BufferLoad.ll

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,4 +197,36 @@ define void @loadv4i16() {
197197
ret void
198198
}
199199

200+
define void @loadf64() {
201+
; show dxil op lower can handle typedbuffer load where target is double but load type is <2 x i32>
202+
; CHECK: [[B1:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, %dx.types.ResBind { i32 1, i32 1, i32 0, i8 1 }, i32 1, i1 false) #0
203+
%buffer = call target("dx.TypedBuffer", double, 1, 0, 0)
204+
@llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f64_1_0_0t(
205+
i32 0, i32 1, i32 1, i32 0, i1 false, ptr null)
206+
207+
; CHECK: [[BA:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[B1]], %dx.types.ResourceProperties { i32 4106, i32 266 }) #0
208+
%load = call { <2 x i32>, i1 } @llvm.dx.resource.load.typedbuffer(
209+
target("dx.TypedBuffer", double, 1, 0, 0) %buffer, i32 0)
210+
211+
; CHECK: call %dx.types.ResRet.i32 @dx.op.bufferLoad.i32(i32 68, %dx.types.Handle [[BA]], i32 0, i32 undef) #1
212+
%val = extractvalue { <2 x i32>, i1 } %load, 0
213+
ret void
214+
}
215+
216+
define void @loadv2f64() {
217+
; show dxil op lower can handle typedbuffer load where target is double2 but load type is <4 x i32>
218+
; CHECK: [[B1:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, %dx.types.ResBind { i32 1, i32 1, i32 0, i8 1 }, i32 1, i1 false) #0
219+
%buffer = call target("dx.TypedBuffer", <2 x double>, 1, 0, 0)
220+
@llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_v2f64_1_0_0t(
221+
i32 0, i32 1, i32 1, i32 0, i1 false, ptr null)
222+
223+
; CHECK: [[BA:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[B1]], %dx.types.ResourceProperties { i32 4106, i32 522 }) #0
224+
%load = call { <4 x i32>, i1 } @llvm.dx.resource.load.typedbuffer(
225+
target("dx.TypedBuffer", <2 x double>, 1, 0, 0) %buffer, i32 0)
226+
227+
; CHECK: call %dx.types.ResRet.i32 @dx.op.bufferLoad.i32(i32 68, %dx.types.Handle [[BA]], i32 0, i32 undef) #1
228+
%val = extractvalue { <4 x i32>, i1 } %load, 0
229+
ret void
230+
}
231+
200232
; CHECK: attributes #[[#ATTR]] = {{{.*}} memory(read) {{.*}}}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
; RUN: opt -S -dxil-intrinsic-expansion %s | FileCheck %s
2+
3+
target triple = "dxil-pc-shadermodel6.6-compute"
4+
5+
define void @loadf64() {
6+
; check the handle from binding is unchanged
7+
; CHECK: [[B:%.*]] = call target("dx.TypedBuffer", double, 1, 0, 0)
8+
; CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f64_1_0_0t(
9+
; CHECK-SAME: i32 0, i32 1, i32 1, i32 0, i1 false, ptr null)
10+
%buffer = call target("dx.TypedBuffer", double, 1, 0, 0)
11+
@llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f64_1_0_0t(
12+
i32 0, i32 1, i32 1, i32 0, i1 false, ptr null)
13+
14+
; check we load an <2 x i32> instead of a double
15+
; CHECK-NOT: call {double, i1} @llvm.dx.resource.load.typedbuffer
16+
; CHECK: [[L0:%.*]] = call { <2 x i32>, i1 }
17+
; CHECK-SAME: @llvm.dx.resource.load.typedbuffer.v2i32.tdx.TypedBuffer_f64_1_0_0t(
18+
; CHECK-SAME: target("dx.TypedBuffer", double, 1, 0, 0) [[B]], i32 0)
19+
%load0 = call {double, i1} @llvm.dx.resource.load.typedbuffer(
20+
target("dx.TypedBuffer", double, 1, 0, 0) %buffer, i32 0)
21+
22+
; check we extract the two i32 and construct a double
23+
; CHECK: [[D0:%.*]] = extractvalue { <2 x i32>, i1 } [[L0]], 0
24+
; CHECK: [[Lo:%.*]] = extractelement <2 x i32> [[D0]], i32 0
25+
; CHECK: [[Hi:%.*]] = extractelement <2 x i32> [[D0]], i32 1
26+
; CHECK: [[DBL:%.*]] = call double @llvm.dx.asdouble.i32(i32 [[Lo]], i32 [[Hi]])
27+
; CHECK-NOT: extractvalue { double, i1 }
28+
%data0 = extractvalue {double, i1} %load0, 0
29+
ret void
30+
}
31+
32+
define void @loadv2f64() {
33+
; check the handle from binding is unchanged
34+
; CHECK: [[B:%.*]] = call target("dx.TypedBuffer", <2 x double>, 1, 0, 0)
35+
; CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_v2f64_1_0_0t(
36+
; CHECK-SAME: i32 0, i32 1, i32 1, i32 0, i1 false, ptr null)
37+
%buffer = call target("dx.TypedBuffer", <2 x double>, 1, 0, 0)
38+
@llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_v2f64_1_0_0t(
39+
i32 0, i32 1, i32 1, i32 0, i1 false, ptr null)
40+
41+
; check we load an <4 x i32> instead of a double2
42+
; CHECK: [[L0:%.*]] = call { <4 x i32>, i1 }
43+
; CHECK-SAME: @llvm.dx.resource.load.typedbuffer.v4i32.tdx.TypedBuffer_v2f64_1_0_0t(
44+
; CHECK-SAME: target("dx.TypedBuffer", <2 x double>, 1, 0, 0) [[B]], i32 0)
45+
%load0 = call { <2 x double>, i1 } @llvm.dx.resource.load.typedbuffer(
46+
target("dx.TypedBuffer", <2 x double>, 1, 0, 0) %buffer, i32 0)
47+
48+
; check we extract the 4 i32 and construct a <2 x double>
49+
; CHECK: [[D0:%.*]] = extractvalue { <4 x i32>, i1 } [[L0]], 0
50+
; CHECK: [[Lo1:%.*]] = extractelement <4 x i32> [[D0]], i32 0
51+
; CHECK: [[Hi1:%.*]] = extractelement <4 x i32> [[D0]], i32 1
52+
; CHECK: [[Lo2:%.*]] = extractelement <4 x i32> [[D0]], i32 2
53+
; CHECK: [[Hi2:%.*]] = extractelement <4 x i32> [[D0]], i32 3
54+
; CHECK: [[Dbl1:%.*]] = call double @llvm.dx.asdouble.i32(i32 [[Lo1]], i32 [[Hi1]])
55+
; CHECK: [[Vec:%.*]] = insertelement <2 x double> poison, double [[Dbl1]], i32 0
56+
; CHECK: [[Dbl2:%.*]] = call double @llvm.dx.asdouble.i32(i32 [[Lo2]], i32 [[Hi2]])
57+
; CHECK: [[Vec2:%.*]] = insertelement <2 x double> [[Vec]], double [[Dbl2]], i32 1
58+
; CHECK-NOT: extractvalue { <2 x double>, i1 }
59+
%data0 = extractvalue { <2 x double>, i1 } %load0, 0
60+
ret void
61+
}
62+
63+
; show we properly handle extracting the check bit
64+
define void @loadf64WithCheckBit() {
65+
; check the handle from binding is unchanged
66+
; CHECK: [[B:%.*]] = call target("dx.TypedBuffer", double, 1, 0, 0)
67+
; CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f64_1_0_0t(
68+
; CHECK-SAME: i32 0, i32 1, i32 1, i32 0, i1 false, ptr null)
69+
%buffer = call target("dx.TypedBuffer", double, 1, 0, 0)
70+
@llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f64_1_0_0t(
71+
i32 0, i32 1, i32 1, i32 0, i1 false, ptr null)
72+
73+
; check we load an <2 x i32> instead of a double
74+
; CHECK-NOT: call {double, i1} @llvm.dx.resource.load.typedbuffer
75+
; CHECK: [[L0:%.*]] = call { <2 x i32>, i1 }
76+
; CHECK-SAME: @llvm.dx.resource.load.typedbuffer.v2i32.tdx.TypedBuffer_f64_1_0_0t(
77+
; CHECK-SAME: target("dx.TypedBuffer", double, 1, 0, 0) [[B]], i32 0)
78+
%load0 = call {double, i1} @llvm.dx.resource.load.typedbuffer(
79+
target("dx.TypedBuffer", double, 1, 0, 0) %buffer, i32 0)
80+
81+
; check we extract the two i32 and construct a double
82+
; CHECK: [[D0:%.*]] = extractvalue { <2 x i32>, i1 } [[L0]], 0
83+
; CHECK: [[Lo:%.*]] = extractelement <2 x i32> [[D0]], i32 0
84+
; CHECK: [[Hi:%.*]] = extractelement <2 x i32> [[D0]], i32 1
85+
; CHECK: [[DBL:%.*]] = call double @llvm.dx.asdouble.i32(i32 [[Lo]], i32 [[Hi]])
86+
%data0 = extractvalue {double, i1} %load0, 0
87+
; CHECK: extractvalue { <2 x i32>, i1 } [[L0]], 1
88+
; CHECK-NOT: extractvalue { double, i1 }
89+
%cb = extractvalue {double, i1} %load0, 1
90+
ret void
91+
}

llvm/test/CodeGen/DirectX/BufferStore.ll

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,3 +161,44 @@ define void @store_scalarized_floats(float %data0, float %data1, float %data2, f
161161

162162
ret void
163163
}
164+
165+
define void @storef64(<2 x i32> %0) {
166+
; CHECK: [[B1:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217,
167+
; CHECK: [[BA:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[B1]]
168+
169+
%buffer = tail call target("dx.TypedBuffer", double, 1, 0, 0)
170+
@llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f64_1_0_0t(
171+
i32 0, i32 0, i32 1, i32 0, i1 false, ptr null)
172+
173+
; The temporary casts should all have been cleaned up
174+
; CHECK-NOT: %dx.resource.casthandle
175+
176+
; CHECK: [[D0:%.*]] = extractelement <2 x i32> %0, i32 0
177+
; CHECK: [[D1:%.*]] = extractelement <2 x i32> %0, i32 1
178+
; CHECK: call void @dx.op.bufferStore.i32(i32 69, %dx.types.Handle [[BA]], i32 0, i32 undef, i32 %2, i32 %3, i32 %2, i32 %2, i8 15)
179+
call void @llvm.dx.resource.store.typedbuffer(
180+
target("dx.TypedBuffer", double, 1, 0, 0) %buffer, i32 0, <2 x i32> %0)
181+
ret void
182+
}
183+
184+
define void @storev2f64(<4 x i32> %0) {
185+
; CHECK: [[B1:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217,
186+
; CHECK: [[BA:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[B1]]
187+
188+
%buffer = tail call target("dx.TypedBuffer", <2 x double>, 1, 0, 0)
189+
@llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_v2f64_1_0_0t(
190+
i32 0, i32 0, i32 1, i32 0, i1 false, ptr null)
191+
192+
; The temporary casts should all have been cleaned up
193+
; CHECK-NOT: %dx.resource.casthandle
194+
195+
; CHECK: [[D0:%.*]] = extractelement <4 x i32> %0, i32 0
196+
; CHECK: [[D1:%.*]] = extractelement <4 x i32> %0, i32 1
197+
; CHECK: [[D2:%.*]] = extractelement <4 x i32> %0, i32 2
198+
; CHECK: [[D3:%.*]] = extractelement <4 x i32> %0, i32 3
199+
; CHECK: call void @dx.op.bufferStore.i32(i32 69, %dx.types.Handle [[BA]], i32 0, i32 undef, i32 [[D0]], i32 [[D1]], i32 [[D2]], i32 [[D3]], i8 15)
200+
call void @llvm.dx.resource.store.typedbuffer(
201+
target("dx.TypedBuffer", <2 x double>, 1, 0, 0) %buffer, i32 0,
202+
<4 x i32> %0)
203+
ret void
204+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
; RUN: opt -S -dxil-intrinsic-expansion %s | FileCheck %s
2+
3+
target triple = "dxil-pc-shadermodel6.6-compute"
4+
5+
define void @storef64(double %0) {
6+
; CHECK: [[B:%.*]] = tail call target("dx.TypedBuffer", double, 1, 0, 0)
7+
; CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f64_1_0_0t(
8+
; CHECK-SAME: i32 0, i32 0, i32 1, i32 0, i1 false, ptr null)
9+
%buffer = tail call target("dx.TypedBuffer", double, 1, 0, 0)
10+
@llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f64_1_0_0t(
11+
i32 0, i32 0, i32 1, i32 0, i1 false, ptr null)
12+
13+
; check we split the double and store the lo and hi bits
14+
; CHECK: [[SD:%.*]] = call { i32, i32 } @llvm.dx.splitdouble.i32(double %0)
15+
; CHECK: [[Lo:%.*]] = extractvalue { i32, i32 } [[SD]], 0
16+
; CHECK: [[Hi:%.*]] = extractvalue { i32, i32 } [[SD]], 1
17+
; CHECK: [[Vec1:%.*]] = insertelement <2 x i32> poison, i32 [[Lo]], i32 0
18+
; CHECK: [[Vec2:%.*]] = insertelement <2 x i32> [[Vec1]], i32 [[Hi]], i32 1
19+
; CHECK: call void @llvm.dx.resource.store.typedbuffer.tdx.TypedBuffer_f64_1_0_0t.v2i32(
20+
; CHECK-SAME: target("dx.TypedBuffer", double, 1, 0, 0) [[B]], i32 0, <2 x i32> [[Vec2]])
21+
call void @llvm.dx.resource.store.typedbuffer(
22+
target("dx.TypedBuffer", double, 1, 0, 0) %buffer, i32 0,
23+
double %0)
24+
ret void
25+
}
26+
27+
28+
define void @storev2f64(<2 x double> %0) {
29+
; CHECK: [[B:%.*]] = tail call target("dx.TypedBuffer", <2 x double>, 1, 0, 0)
30+
; CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_v2f64_1_0_0t(
31+
; CHECK-SAME: i32 0, i32 0, i32 1, i32 0, i1 false, ptr null)
32+
%buffer = tail call target("dx.TypedBuffer", <2 x double>, 1, 0, 0)
33+
@llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_v2f64_1_0_0t(
34+
i32 0, i32 0, i32 1, i32 0, i1 false, ptr null)
35+
36+
; CHECK: [[SD:%.*]] = call { <2 x i32>, <2 x i32> }
37+
; CHECK-SAME: @llvm.dx.splitdouble.v2i32(<2 x double> %0)
38+
; CHECK: [[Lo:%.*]] = extractvalue { <2 x i32>, <2 x i32> } [[SD]], 0
39+
; CHECK: [[Hi:%.*]] = extractvalue { <2 x i32>, <2 x i32> } [[SD]], 1
40+
; CHECK: [[Vec:%.*]] = shufflevector <2 x i32> [[Lo]], <2 x i32> [[Hi]], <4 x i32> <i32 0, i32 2, i32 1, i32 3>
41+
; CHECK: call void @llvm.dx.resource.store.typedbuffer.tdx.TypedBuffer_v2f64_1_0_0t.v4i32(
42+
; CHECK-SAME: target("dx.TypedBuffer", <2 x double>, 1, 0, 0) [[B]], i32 0, <4 x i32> [[Vec]])
43+
call void @llvm.dx.resource.store.typedbuffer(
44+
target("dx.TypedBuffer", <2 x double>, 1, 0, 0) %buffer, i32 0,
45+
<2 x double> %0)
46+
ret void
47+
}

0 commit comments

Comments
 (0)