Skip to content

Commit 5704c47

Browse files
[SPIR-V] Handle vectors passed to asuint (microsoft#6953)
`asuint` should be able to take vectors in addition to scalar values. Previously, it would be lowered as a bitcast from the input value to a vector of uints with a width of 2, which is not large enough if the input value is larger than a scalar value. In order to handle, for example, an input value that is a `double4`, we instead perform a component-wise bitcast. Fixes microsoft#6735
1 parent 6a7eae1 commit 5704c47

File tree

3 files changed

+276
-18
lines changed

3 files changed

+276
-18
lines changed

tools/clang/lib/SPIRV/SpirvEmitter.cpp

Lines changed: 103 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11419,6 +11419,78 @@ SpirvEmitter::processIntrinsicAllOrAny(const CallExpr *callExpr,
1141911419
return nullptr;
1142011420
}
1142111421

11422+
void SpirvEmitter::splitDouble(SpirvInstruction *value, SourceLocation loc,
11423+
SourceRange range, SpirvInstruction *&lowbits,
11424+
SpirvInstruction *&highbits) {
11425+
const QualType uintType = astContext.UnsignedIntTy;
11426+
const QualType uintVec2Type = astContext.getExtVectorType(uintType, 2);
11427+
11428+
SpirvInstruction *uints = spvBuilder.createUnaryOp(
11429+
spv::Op::OpBitcast, uintVec2Type, value, loc, range);
11430+
11431+
lowbits = spvBuilder.createCompositeExtract(uintType, uints, {0}, loc, range);
11432+
highbits =
11433+
spvBuilder.createCompositeExtract(uintType, uints, {1}, loc, range);
11434+
}
11435+
11436+
void SpirvEmitter::splitDoubleVector(QualType elemType, uint32_t count,
11437+
QualType outputType,
11438+
SpirvInstruction *value,
11439+
SourceLocation loc, SourceRange range,
11440+
SpirvInstruction *&lowbits,
11441+
SpirvInstruction *&highbits) {
11442+
llvm::SmallVector<SpirvInstruction *, 4> lowElems;
11443+
llvm::SmallVector<SpirvInstruction *, 4> highElems;
11444+
11445+
for (uint32_t i = 0; i < count; ++i) {
11446+
SpirvInstruction *elem =
11447+
spvBuilder.createCompositeExtract(elemType, value, {i}, loc, range);
11448+
SpirvInstruction *lowbitsResult = nullptr;
11449+
SpirvInstruction *highbitsResult = nullptr;
11450+
splitDouble(elem, loc, range, lowbitsResult, highbitsResult);
11451+
lowElems.push_back(lowbitsResult);
11452+
highElems.push_back(highbitsResult);
11453+
}
11454+
11455+
lowbits =
11456+
spvBuilder.createCompositeConstruct(outputType, lowElems, loc, range);
11457+
highbits =
11458+
spvBuilder.createCompositeConstruct(outputType, highElems, loc, range);
11459+
}
11460+
11461+
void SpirvEmitter::splitDoubleMatrix(QualType elemType, uint32_t rowCount,
11462+
uint32_t colCount, QualType outputType,
11463+
SpirvInstruction *value,
11464+
SourceLocation loc, SourceRange range,
11465+
SpirvInstruction *&lowbits,
11466+
SpirvInstruction *&highbits) {
11467+
11468+
llvm::SmallVector<SpirvInstruction *, 4> lowElems;
11469+
llvm::SmallVector<SpirvInstruction *, 4> highElems;
11470+
11471+
QualType colType = astContext.getExtVectorType(elemType, colCount);
11472+
11473+
const QualType uintType = astContext.UnsignedIntTy;
11474+
const QualType outputColType =
11475+
astContext.getExtVectorType(uintType, colCount);
11476+
11477+
for (uint32_t i = 0; i < rowCount; ++i) {
11478+
SpirvInstruction *column =
11479+
spvBuilder.createCompositeExtract(colType, value, {i}, loc, range);
11480+
SpirvInstruction *lowbitsResult = nullptr;
11481+
SpirvInstruction *highbitsResult = nullptr;
11482+
splitDoubleVector(elemType, colCount, outputColType, column, loc, range,
11483+
lowbitsResult, highbitsResult);
11484+
lowElems.push_back(lowbitsResult);
11485+
highElems.push_back(highbitsResult);
11486+
}
11487+
11488+
lowbits =
11489+
spvBuilder.createCompositeConstruct(outputType, lowElems, loc, range);
11490+
highbits =
11491+
spvBuilder.createCompositeConstruct(outputType, highElems, loc, range);
11492+
}
11493+
1142211494
SpirvInstruction *
1142311495
SpirvEmitter::processIntrinsicAsType(const CallExpr *callExpr) {
1142411496
// This function handles the following intrinsics:
@@ -11523,23 +11595,37 @@ SpirvEmitter::processIntrinsicAsType(const CallExpr *callExpr) {
1152311595
}
1152411596
case 3: {
1152511597
// Handling Method 6.
11526-
auto *value = doExpr(arg0);
11527-
auto *lowbits = doExpr(callExpr->getArg(1));
11528-
auto *highbits = doExpr(callExpr->getArg(2));
11529-
const auto uintType = astContext.UnsignedIntTy;
11530-
const auto uintVec2Type = astContext.getExtVectorType(uintType, 2);
11531-
auto *vecResult = spvBuilder.createUnaryOp(spv::Op::OpBitcast, uintVec2Type,
11532-
value, loc, range);
11533-
spvBuilder.createStore(
11534-
lowbits,
11535-
spvBuilder.createCompositeExtract(uintType, vecResult, {0},
11536-
arg0->getLocStart(), range),
11537-
loc, range);
11538-
spvBuilder.createStore(
11539-
highbits,
11540-
spvBuilder.createCompositeExtract(uintType, vecResult, {1},
11541-
arg0->getLocStart(), range),
11542-
loc, range);
11598+
const Expr *arg1 = callExpr->getArg(1);
11599+
const Expr *arg2 = callExpr->getArg(2);
11600+
11601+
SpirvInstruction *value = doExpr(arg0);
11602+
SpirvInstruction *lowbits = doExpr(arg1);
11603+
SpirvInstruction *highbits = doExpr(arg2);
11604+
11605+
QualType elemType = QualType();
11606+
uint32_t rowCount = 0;
11607+
uint32_t colCount = 0;
11608+
11609+
SpirvInstruction *lowbitsResult = nullptr;
11610+
SpirvInstruction *highbitsResult = nullptr;
11611+
11612+
if (isScalarType(argType)) {
11613+
splitDouble(value, loc, range, lowbitsResult, highbitsResult);
11614+
} else if (isVectorType(argType, &elemType, &rowCount)) {
11615+
splitDoubleVector(elemType, rowCount, arg1->getType(), value, loc, range,
11616+
lowbitsResult, highbitsResult);
11617+
} else if (isMxNMatrix(argType, &elemType, &rowCount, &colCount)) {
11618+
splitDoubleMatrix(elemType, rowCount, colCount, arg1->getType(), value,
11619+
loc, range, lowbitsResult, highbitsResult);
11620+
} else {
11621+
llvm_unreachable(
11622+
"unexpected argument type is not scalar, vector, or matrix");
11623+
return nullptr;
11624+
}
11625+
11626+
spvBuilder.createStore(lowbits, lowbitsResult, loc, range);
11627+
spvBuilder.createStore(highbits, highbitsResult, loc, range);
11628+
1154311629
return nullptr;
1154411630
}
1154511631
default:

tools/clang/lib/SPIRV/SpirvEmitter.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1312,6 +1312,45 @@ class SpirvEmitter : public ASTConsumer {
13121312
/// the Vulkan memory model capability has been added to the module.
13131313
bool UpgradeToVulkanMemoryModelIfNeeded(std::vector<uint32_t> *module);
13141314

1315+
// Splits the `value`, which must be a 64-bit scalar, into two 32-bit wide
1316+
// uints, stored in `lowbits` and `highbits`.
1317+
void splitDouble(SpirvInstruction *value, SourceLocation loc,
1318+
SourceRange range, SpirvInstruction *&lowbits,
1319+
SpirvInstruction *&highbits);
1320+
1321+
// Splits the value, which must be a vector with element type `elemType` and
1322+
// size `count`, into two composite values of size `count` and type
1323+
// `outputType`. The elements are split component-wise: the vector
1324+
// {0x0123456789abcdef, 0x0123456789abcdef} is split into `lowbits`
1325+
// {0x89abcdef, 0x89abcdef} and and `highbits` {0x01234567, 0x01234567}.
1326+
void splitDoubleVector(QualType elemType, uint32_t count, QualType outputType,
1327+
SpirvInstruction *value, SourceLocation loc,
1328+
SourceRange range, SpirvInstruction *&lowbits,
1329+
SpirvInstruction *&highbits);
1330+
1331+
// Splits the value, which must be a matrix with element type `elemType` and
1332+
// dimensions `rowCount` and `colCount`, into two composite values of
1333+
// dimensions `rowCount` and `colCount`. The elements are split
1334+
// component-wise: the matrix
1335+
//
1336+
// { 0x0123456789abcdef, 0x0123456789abcdef,
1337+
// 0x0123456789abcdef, 0x0123456789abcdef }
1338+
//
1339+
// is split into `lowbits`
1340+
//
1341+
// { 0x89abcdef, 0x89abcdef,
1342+
// 0x89abcdef, 0x89abcdef }
1343+
//
1344+
// and `highbits`
1345+
//
1346+
// { 0x012345678, 0x012345678,
1347+
// 0x012345678, 0x012345678 }.
1348+
void splitDoubleMatrix(QualType elemType, uint32_t rowCount,
1349+
uint32_t colCount, QualType outputType,
1350+
SpirvInstruction *value, SourceLocation loc,
1351+
SourceRange range, SpirvInstruction *&lowbits,
1352+
SpirvInstruction *&highbits);
1353+
13151354
public:
13161355
/// \brief Wrapper method to create a fatal error message and report it
13171356
/// in the diagnostic engine associated with this consumer.

tools/clang/test/CodeGenSPIRV/intrinsics.asuint.hlsl

Lines changed: 134 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,141 @@ void main() {
7979
// CHECK-NEXT: [[value:%[0-9]+]] = OpLoad %double %value
8080
// CHECK-NEXT: [[resultVec:%[0-9]+]] = OpBitcast %v2uint [[value]]
8181
// CHECK-NEXT: [[resultVec0:%[0-9]+]] = OpCompositeExtract %uint [[resultVec]] 0
82-
// CHECK-NEXT: OpStore %lowbits [[resultVec0]]
8382
// CHECK-NEXT: [[resultVec1:%[0-9]+]] = OpCompositeExtract %uint [[resultVec]] 1
83+
// CHECK-NEXT: OpStore %lowbits [[resultVec0]]
8484
// CHECK-NEXT: OpStore %highbits [[resultVec1]]
8585
asuint(value, lowbits, highbits);
86+
87+
double3 value3;
88+
uint3 lowbits3;
89+
uint3 highbits3;
90+
// CHECK-NEXT: [[value:%[0-9]+]] = OpLoad %v3double %value3
91+
// CHECK-NEXT: [[value0:%[0-9]+]] = OpCompositeExtract %double [[value]] 0
92+
// CHECK-NEXT: [[resultVec0:%[0-9]+]] = OpBitcast %v2uint [[value0]]
93+
// CHECK-NEXT: [[low0:%[0-9]+]] = OpCompositeExtract %uint [[resultVec0]] 0
94+
// CHECK-NEXT: [[high0:%[0-9]+]] = OpCompositeExtract %uint [[resultVec0]] 1
95+
// CHECK-NEXT: [[value1:%[0-9]+]] = OpCompositeExtract %double [[value]] 1
96+
// CHECK-NEXT: [[resultVec1:%[0-9]+]] = OpBitcast %v2uint [[value1]]
97+
// CHECK-NEXT: [[low1:%[0-9]+]] = OpCompositeExtract %uint [[resultVec1]] 0
98+
// CHECK-NEXT: [[high1:%[0-9]+]] = OpCompositeExtract %uint [[resultVec1]] 1
99+
// CHECK-NEXT: [[value2:%[0-9]+]] = OpCompositeExtract %double [[value]] 2
100+
// CHECK-NEXT: [[resultVec2:%[0-9]+]] = OpBitcast %v2uint [[value2]]
101+
// CHECK-NEXT: [[low2:%[0-9]+]] = OpCompositeExtract %uint [[resultVec2]] 0
102+
// CHECK-NEXT: [[high2:%[0-9]+]] = OpCompositeExtract %uint [[resultVec2]] 1
103+
// CHECK-NEXT: [[low:%[0-9]+]] = OpCompositeConstruct %v3uint [[low0]] [[low1]] [[low2]]
104+
// CHECK-NEXT: [[high:%[0-9]+]] = OpCompositeConstruct %v3uint [[high0]] [[high1]] [[high2]]
105+
// CHECK-NEXT: OpStore %lowbits3 [[low]]
106+
// CHECK-NEXT: OpStore %highbits3 [[high]]
107+
asuint(value3, lowbits3, highbits3);
108+
109+
double2x2 value2x2;
110+
uint2x2 lowbits2x2;
111+
uint2x2 highbits2x2;
112+
// CHECK-NEXT: [[value:%[0-9]+]] = OpLoad %mat2v2double %value2x2
113+
// CHECK-NEXT: [[row0:%[0-9]+]] = OpCompositeExtract %v2double [[value]] 0
114+
// CHECK-NEXT: [[value0:%[0-9]+]] = OpCompositeExtract %double [[row0]] 0
115+
// CHECK-NEXT: [[resultVec0:%[0-9]+]] = OpBitcast %v2uint [[value0]]
116+
// CHECK-NEXT: [[low0:%[0-9]+]] = OpCompositeExtract %uint [[resultVec0]] 0
117+
// CHECK-NEXT: [[high0:%[0-9]+]] = OpCompositeExtract %uint [[resultVec0]] 1
118+
// CHECK-NEXT: [[value1:%[0-9]+]] = OpCompositeExtract %double [[row0]] 1
119+
// CHECK-NEXT: [[resultVec1:%[0-9]+]] = OpBitcast %v2uint [[value1]]
120+
// CHECK-NEXT: [[low1:%[0-9]+]] = OpCompositeExtract %uint [[resultVec1]] 0
121+
// CHECK-NEXT: [[high1:%[0-9]+]] = OpCompositeExtract %uint [[resultVec1]] 1
122+
// CHECK-NEXT: [[lowRow0:%[0-9]+]] = OpCompositeConstruct %v2uint [[low0]] [[low1]]
123+
// CHECK-NEXT: [[highRow0:%[0-9]+]] = OpCompositeConstruct %v2uint [[high0]] [[high1]]
124+
// CHECK-NEXT: [[row1:%[0-9]+]] = OpCompositeExtract %v2double [[value]] 1
125+
// CHECK-NEXT: [[value2:%[0-9]+]] = OpCompositeExtract %double [[row1]] 0
126+
// CHECK-NEXT: [[resultVec2:%[0-9]+]] = OpBitcast %v2uint [[value2]]
127+
// CHECK-NEXT: [[low2:%[0-9]+]] = OpCompositeExtract %uint [[resultVec2]] 0
128+
// CHECK-NEXT: [[high2:%[0-9]+]] = OpCompositeExtract %uint [[resultVec2]] 1
129+
// CHECK-NEXT: [[value3:%[0-9]+]] = OpCompositeExtract %double [[row1]] 1
130+
// CHECK-NEXT: [[resultVec3:%[0-9]+]] = OpBitcast %v2uint [[value3]]
131+
// CHECK-NEXT: [[low3:%[0-9]+]] = OpCompositeExtract %uint [[resultVec3]] 0
132+
// CHECK-NEXT: [[high3:%[0-9]+]] = OpCompositeExtract %uint [[resultVec3]] 1
133+
// CHECK-NEXT: [[lowRow1:%[0-9]+]] = OpCompositeConstruct %v2uint [[low2]] [[low3]]
134+
// CHECK-NEXT: [[highRow1:%[0-9]+]] = OpCompositeConstruct %v2uint [[high2]] [[high3]]
135+
// CHECK-NEXT: [[low:%[0-9]+]] = OpCompositeConstruct %_arr_v2uint_uint_2 [[lowRow0]] [[lowRow1]]
136+
// CHECK-NEXT: [[high:%[0-9]+]] = OpCompositeConstruct %_arr_v2uint_uint_2 [[highRow0]] [[highRow1]]
137+
// CHECK-NEXT: OpStore %lowbits2x2 [[low]]
138+
// CHECK-NEXT: OpStore %highbits2x2 [[high]]
139+
asuint(value2x2, lowbits2x2, highbits2x2);
140+
141+
double3x2 value3x2;
142+
uint3x2 lowbits3x2;
143+
uint3x2 highbits3x2;
144+
// CHECK-NEXT: [[value:%[0-9]+]] = OpLoad %mat3v2double %value3x2
145+
// CHECK-NEXT: [[row0:%[0-9]+]] = OpCompositeExtract %v2double [[value]] 0
146+
// CHECK-NEXT: [[value0:%[0-9]+]] = OpCompositeExtract %double [[row0]] 0
147+
// CHECK-NEXT: [[resultVec0:%[0-9]+]] = OpBitcast %v2uint [[value0]]
148+
// CHECK-NEXT: [[low0:%[0-9]+]] = OpCompositeExtract %uint [[resultVec0]] 0
149+
// CHECK-NEXT: [[high0:%[0-9]+]] = OpCompositeExtract %uint [[resultVec0]] 1
150+
// CHECK-NEXT: [[value1:%[0-9]+]] = OpCompositeExtract %double [[row0]] 1
151+
// CHECK-NEXT: [[resultVec1:%[0-9]+]] = OpBitcast %v2uint [[value1]]
152+
// CHECK-NEXT: [[low1:%[0-9]+]] = OpCompositeExtract %uint [[resultVec1]] 0
153+
// CHECK-NEXT: [[high1:%[0-9]+]] = OpCompositeExtract %uint [[resultVec1]] 1
154+
// CHECK-NEXT: [[lowRow0:%[0-9]+]] = OpCompositeConstruct %v2uint [[low0]] [[low1]]
155+
// CHECK-NEXT: [[highRow0:%[0-9]+]] = OpCompositeConstruct %v2uint [[high0]] [[high1]]
156+
// CHECK-NEXT: [[row1:%[0-9]+]] = OpCompositeExtract %v2double [[value]] 1
157+
// CHECK-NEXT: [[value2:%[0-9]+]] = OpCompositeExtract %double [[row1]] 0
158+
// CHECK-NEXT: [[resultVec2:%[0-9]+]] = OpBitcast %v2uint [[value2]]
159+
// CHECK-NEXT: [[low2:%[0-9]+]] = OpCompositeExtract %uint [[resultVec2]] 0
160+
// CHECK-NEXT: [[high2:%[0-9]+]] = OpCompositeExtract %uint [[resultVec2]] 1
161+
// CHECK-NEXT: [[value3:%[0-9]+]] = OpCompositeExtract %double [[row1]] 1
162+
// CHECK-NEXT: [[resultVec3:%[0-9]+]] = OpBitcast %v2uint [[value3]]
163+
// CHECK-NEXT: [[low3:%[0-9]+]] = OpCompositeExtract %uint [[resultVec3]] 0
164+
// CHECK-NEXT: [[high3:%[0-9]+]] = OpCompositeExtract %uint [[resultVec3]] 1
165+
// CHECK-NEXT: [[lowRow1:%[0-9]+]] = OpCompositeConstruct %v2uint [[low2]] [[low3]]
166+
// CHECK-NEXT: [[highRow1:%[0-9]+]] = OpCompositeConstruct %v2uint [[high2]] [[high3]]
167+
// CHECK-NEXT: [[row2:%[0-9]+]] = OpCompositeExtract %v2double [[value]] 2
168+
// CHECK-NEXT: [[value4:%[0-9]+]] = OpCompositeExtract %double [[row2]] 0
169+
// CHECK-NEXT: [[resultVec4:%[0-9]+]] = OpBitcast %v2uint [[value4]]
170+
// CHECK-NEXT: [[low4:%[0-9]+]] = OpCompositeExtract %uint [[resultVec4]] 0
171+
// CHECK-NEXT: [[high4:%[0-9]+]] = OpCompositeExtract %uint [[resultVec4]] 1
172+
// CHECK-NEXT: [[value5:%[0-9]+]] = OpCompositeExtract %double [[row2]] 1
173+
// CHECK-NEXT: [[resultVec5:%[0-9]+]] = OpBitcast %v2uint [[value5]]
174+
// CHECK-NEXT: [[low5:%[0-9]+]] = OpCompositeExtract %uint [[resultVec5]] 0
175+
// CHECK-NEXT: [[high5:%[0-9]+]] = OpCompositeExtract %uint [[resultVec5]] 1
176+
// CHECK-NEXT: [[lowRow2:%[0-9]+]] = OpCompositeConstruct %v2uint [[low4]] [[low5]]
177+
// CHECK-NEXT: [[highRow2:%[0-9]+]] = OpCompositeConstruct %v2uint [[high4]] [[high5]]
178+
// CHECK-NEXT: [[low:%[0-9]+]] = OpCompositeConstruct %_arr_v2uint_uint_3 [[lowRow0]] [[lowRow1]] [[lowRow2]]
179+
// CHECK-NEXT: [[high:%[0-9]+]] = OpCompositeConstruct %_arr_v2uint_uint_3 [[highRow0]] [[highRow1]] [[highRow2]]
180+
// CHECK-NEXT: OpStore %lowbits3x2 [[low]]
181+
// CHECK-NEXT: OpStore %highbits3x2 [[high]]
182+
asuint(value3x2, lowbits3x2, highbits3x2);
183+
184+
double2x1 value2x1;
185+
uint2x1 lowbits2x1;
186+
uint2x1 highbits2x1;
187+
// CHECK-NEXT: [[value:%[0-9]+]] = OpLoad %v2double %value2x1
188+
// CHECK-NEXT: [[value0:%[0-9]+]] = OpCompositeExtract %double [[value]] 0
189+
// CHECK-NEXT: [[resultVec0:%[0-9]+]] = OpBitcast %v2uint [[value0]]
190+
// CHECK-NEXT: [[low0:%[0-9]+]] = OpCompositeExtract %uint [[resultVec0]] 0
191+
// CHECK-NEXT: [[high0:%[0-9]+]] = OpCompositeExtract %uint [[resultVec0]] 1
192+
// CHECK-NEXT: [[value1:%[0-9]+]] = OpCompositeExtract %double [[value]] 1
193+
// CHECK-NEXT: [[resultVec1:%[0-9]+]] = OpBitcast %v2uint [[value1]]
194+
// CHECK-NEXT: [[low1:%[0-9]+]] = OpCompositeExtract %uint [[resultVec1]] 0
195+
// CHECK-NEXT: [[high1:%[0-9]+]] = OpCompositeExtract %uint [[resultVec1]] 1
196+
// CHECK-NEXT: [[low:%[0-9]+]] = OpCompositeConstruct %v2uint [[low0]] [[low1]]
197+
// CHECK-NEXT: [[high:%[0-9]+]] = OpCompositeConstruct %v2uint [[high0]] [[high1]]
198+
// CHECK-NEXT: OpStore %lowbits2x1 [[low]]
199+
// CHECK-NEXT: OpStore %highbits2x1 [[high]]
200+
asuint(value2x1, lowbits2x1, highbits2x1);
201+
202+
double1x2 value1x2;
203+
uint1x2 lowbits1x2;
204+
uint1x2 highbits1x2;
205+
// CHECK-NEXT: [[value:%[0-9]+]] = OpLoad %v2double %value1x2
206+
// CHECK-NEXT: [[value0:%[0-9]+]] = OpCompositeExtract %double [[value]] 0
207+
// CHECK-NEXT: [[resultVec0:%[0-9]+]] = OpBitcast %v2uint [[value0]]
208+
// CHECK-NEXT: [[low0:%[0-9]+]] = OpCompositeExtract %uint [[resultVec0]] 0
209+
// CHECK-NEXT: [[high0:%[0-9]+]] = OpCompositeExtract %uint [[resultVec0]] 1
210+
// CHECK-NEXT: [[value1:%[0-9]+]] = OpCompositeExtract %double [[value]] 1
211+
// CHECK-NEXT: [[resultVec1:%[0-9]+]] = OpBitcast %v2uint [[value1]]
212+
// CHECK-NEXT: [[low1:%[0-9]+]] = OpCompositeExtract %uint [[resultVec1]] 0
213+
// CHECK-NEXT: [[high1:%[0-9]+]] = OpCompositeExtract %uint [[resultVec1]] 1
214+
// CHECK-NEXT: [[low:%[0-9]+]] = OpCompositeConstruct %v2uint [[low0]] [[low1]]
215+
// CHECK-NEXT: [[high:%[0-9]+]] = OpCompositeConstruct %v2uint [[high0]] [[high1]]
216+
// CHECK-NEXT: OpStore %lowbits1x2 [[low]]
217+
// CHECK-NEXT: OpStore %highbits1x2 [[high]]
218+
asuint(value1x2, lowbits1x2, highbits1x2);
86219
}

0 commit comments

Comments
 (0)