1 // Copyright 2020 The Tint Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "gmock/gmock.h"
16 #include "src/reader/spirv/function.h"
17 #include "src/reader/spirv/parser_impl_test_helper.h"
18 #include "src/reader/spirv/spirv_tools_helpers_test.h"
19
20 namespace tint {
21 namespace reader {
22 namespace spirv {
23 namespace {
24
25 using ::testing::Eq;
26 using ::testing::HasSubstr;
27
Preamble()28 std::string Preamble() {
29 return R"(
30 OpCapability Shader
31 OpMemoryModel Logical Simple
32 OpEntryPoint Fragment %100 "main"
33 OpExecutionMode %100 OriginUpperLeft
34
35 %void = OpTypeVoid
36 %voidfn = OpTypeFunction %void
37
38 %bool = OpTypeBool
39 %uint = OpTypeInt 32 0
40 %int = OpTypeInt 32 1
41 %float = OpTypeFloat 32
42
43 %true = OpConstantTrue %bool
44 %false = OpConstantFalse %bool
45 %v2bool = OpTypeVector %bool 2
46 %v2bool_t_f = OpConstantComposite %v2bool %true %false
47
48 %uint_10 = OpConstant %uint 10
49 %uint_20 = OpConstant %uint 20
50 %int_30 = OpConstant %int 30
51 %int_40 = OpConstant %int 40
52 %float_50 = OpConstant %float 50
53 %float_60 = OpConstant %float 60
54
55 %ptr_uint = OpTypePointer Function %uint
56 %ptr_int = OpTypePointer Function %int
57 %ptr_float = OpTypePointer Function %float
58
59 %v2uint = OpTypeVector %uint 2
60 %v2int = OpTypeVector %int 2
61 %v2float = OpTypeVector %float 2
62
63 %v2uint_10_20 = OpConstantComposite %v2uint %uint_10 %uint_20
64 %v2uint_20_10 = OpConstantComposite %v2uint %uint_20 %uint_10
65 %v2int_30_40 = OpConstantComposite %v2int %int_30 %int_40
66 %v2int_40_30 = OpConstantComposite %v2int %int_40 %int_30
67 %v2float_50_60 = OpConstantComposite %v2float %float_50 %float_60
68 %v2float_60_50 = OpConstantComposite %v2float %float_60 %float_50
69 )";
70 }
71
72 using SpvUnaryConversionTest = SpvParserTestBase<::testing::Test>;
73
TEST_F(SpvUnaryConversionTest,Bitcast_Scalar)74 TEST_F(SpvUnaryConversionTest, Bitcast_Scalar) {
75 const auto assembly = Preamble() + R"(
76 %100 = OpFunction %void None %voidfn
77 %entry = OpLabel
78 %1 = OpBitcast %uint %float_50
79 OpReturn
80 OpFunctionEnd
81 )";
82 auto p = parser(test::Assemble(assembly));
83 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
84 auto fe = p->function_emitter(100);
85 EXPECT_TRUE(fe.EmitBody()) << p->error();
86 auto ast_body = fe.ast_body();
87 EXPECT_THAT(test::ToString(p->program(), ast_body),
88 HasSubstr("let x_1 : u32 = bitcast<u32>(50.0);"));
89 }
90
TEST_F(SpvUnaryConversionTest,Bitcast_Vector)91 TEST_F(SpvUnaryConversionTest, Bitcast_Vector) {
92 const auto assembly = Preamble() + R"(
93 %100 = OpFunction %void None %voidfn
94 %entry = OpLabel
95 %1 = OpBitcast %v2float %v2uint_10_20
96 OpReturn
97 OpFunctionEnd
98 )";
99 auto p = parser(test::Assemble(assembly));
100 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
101 auto fe = p->function_emitter(100);
102 EXPECT_TRUE(fe.EmitBody()) << p->error();
103 auto ast_body = fe.ast_body();
104 EXPECT_THAT(
105 test::ToString(p->program(), ast_body),
106 HasSubstr(
107 "let x_1 : vec2<f32> = bitcast<vec2<f32>>(vec2<u32>(10u, 20u));"));
108 }
109
TEST_F(SpvUnaryConversionTest,ConvertSToF_BadArg)110 TEST_F(SpvUnaryConversionTest, ConvertSToF_BadArg) {
111 const auto assembly = Preamble() + R"(
112 %100 = OpFunction %void None %voidfn
113 %entry = OpLabel
114 %1 = OpConvertSToF %float %void
115 OpReturn
116 OpFunctionEnd
117 )";
118 auto p = parser(test::Assemble(assembly));
119 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
120 auto fe = p->function_emitter(100);
121 EXPECT_FALSE(fe.EmitBody());
122 EXPECT_THAT(p->error(),
123 HasSubstr("unhandled expression for ID 2\n%2 = OpTypeVoid"));
124 }
125
TEST_F(SpvUnaryConversionTest,ConvertUToF_BadArg)126 TEST_F(SpvUnaryConversionTest, ConvertUToF_BadArg) {
127 const auto assembly = Preamble() + R"(
128 %100 = OpFunction %void None %voidfn
129 %entry = OpLabel
130 %1 = OpConvertUToF %float %void
131 OpReturn
132 OpFunctionEnd
133 )";
134 auto p = parser(test::Assemble(assembly));
135 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
136 auto fe = p->function_emitter(100);
137 EXPECT_FALSE(fe.EmitBody());
138 EXPECT_THAT(p->error(),
139 HasSubstr("unhandled expression for ID 2\n%2 = OpTypeVoid"));
140 }
141
TEST_F(SpvUnaryConversionTest,ConvertFToS_BadArg)142 TEST_F(SpvUnaryConversionTest, ConvertFToS_BadArg) {
143 const auto assembly = Preamble() + R"(
144 %100 = OpFunction %void None %voidfn
145 %entry = OpLabel
146 %1 = OpConvertFToS %float %void
147 OpReturn
148 OpFunctionEnd
149 )";
150 auto p = parser(test::Assemble(assembly));
151 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
152 auto fe = p->function_emitter(100);
153 EXPECT_FALSE(fe.EmitBody());
154 EXPECT_THAT(p->error(),
155 HasSubstr("unhandled expression for ID 2\n%2 = OpTypeVoid"));
156 }
157
TEST_F(SpvUnaryConversionTest,ConvertFToU_BadArg)158 TEST_F(SpvUnaryConversionTest, ConvertFToU_BadArg) {
159 const auto assembly = Preamble() + R"(
160 %100 = OpFunction %void None %voidfn
161 %entry = OpLabel
162 %1 = OpConvertFToU %float %void
163 OpReturn
164 OpFunctionEnd
165 )";
166 auto p = parser(test::Assemble(assembly));
167 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
168 auto fe = p->function_emitter(100);
169 EXPECT_FALSE(fe.EmitBody());
170 EXPECT_THAT(p->error(),
171 HasSubstr("unhandled expression for ID 2\n%2 = OpTypeVoid"));
172 }
173
TEST_F(SpvUnaryConversionTest,ConvertSToF_Scalar_BadArgType)174 TEST_F(SpvUnaryConversionTest, ConvertSToF_Scalar_BadArgType) {
175 const auto assembly = Preamble() + R"(
176 %100 = OpFunction %void None %voidfn
177 %entry = OpLabel
178 %1 = OpConvertSToF %float %false
179 OpReturn
180 OpFunctionEnd
181 )";
182 auto p = parser(test::Assemble(assembly));
183 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
184 auto fe = p->function_emitter(100);
185 EXPECT_FALSE(fe.EmitBody());
186 EXPECT_THAT(p->error(),
187 HasSubstr("operand for conversion to floating point must be "
188 "integral scalar or vector"));
189 }
190
TEST_F(SpvUnaryConversionTest,ConvertSToF_Vector_BadArgType)191 TEST_F(SpvUnaryConversionTest, ConvertSToF_Vector_BadArgType) {
192 const auto assembly = Preamble() + R"(
193 %100 = OpFunction %void None %voidfn
194 %entry = OpLabel
195 %1 = OpConvertSToF %v2float %v2bool_t_f
196 OpReturn
197 OpFunctionEnd
198 )";
199 auto p = parser(test::Assemble(assembly));
200 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
201 auto fe = p->function_emitter(100);
202 EXPECT_FALSE(fe.EmitBody());
203 EXPECT_THAT(
204 p->error(),
205 HasSubstr("operand for conversion to floating point must be integral "
206 "scalar or vector"));
207 }
208
TEST_F(SpvUnaryConversionTest,ConvertSToF_Scalar_FromSigned)209 TEST_F(SpvUnaryConversionTest, ConvertSToF_Scalar_FromSigned) {
210 const auto assembly = Preamble() + R"(
211 %100 = OpFunction %void None %voidfn
212 %entry = OpLabel
213 %30 = OpCopyObject %int %int_30
214 %1 = OpConvertSToF %float %30
215 OpReturn
216 OpFunctionEnd
217 )";
218 auto p = parser(test::Assemble(assembly));
219 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
220 auto fe = p->function_emitter(100);
221 EXPECT_TRUE(fe.EmitBody()) << p->error();
222 auto ast_body = fe.ast_body();
223 EXPECT_THAT(test::ToString(p->program(), ast_body),
224 HasSubstr("let x_1 : f32 = f32(x_30);"));
225 }
226
TEST_F(SpvUnaryConversionTest,ConvertSToF_Scalar_FromUnsigned)227 TEST_F(SpvUnaryConversionTest, ConvertSToF_Scalar_FromUnsigned) {
228 const auto assembly = Preamble() + R"(
229 %100 = OpFunction %void None %voidfn
230 %entry = OpLabel
231 %30 = OpCopyObject %uint %uint_10
232 %1 = OpConvertSToF %float %30
233 OpReturn
234 OpFunctionEnd
235 )";
236 auto p = parser(test::Assemble(assembly));
237 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
238 auto fe = p->function_emitter(100);
239 EXPECT_TRUE(fe.EmitBody()) << p->error();
240 auto ast_body = fe.ast_body();
241 EXPECT_THAT(test::ToString(p->program(), ast_body),
242 HasSubstr("let x_1 : f32 = f32(bitcast<i32>(x_30));"));
243 }
244
TEST_F(SpvUnaryConversionTest,ConvertSToF_Vector_FromSigned)245 TEST_F(SpvUnaryConversionTest, ConvertSToF_Vector_FromSigned) {
246 const auto assembly = Preamble() + R"(
247 %100 = OpFunction %void None %voidfn
248 %entry = OpLabel
249 %30 = OpCopyObject %v2int %v2int_30_40
250 %1 = OpConvertSToF %v2float %30
251 OpReturn
252 OpFunctionEnd
253 )";
254 auto p = parser(test::Assemble(assembly));
255 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
256 auto fe = p->function_emitter(100);
257 EXPECT_TRUE(fe.EmitBody()) << p->error();
258 auto ast_body = fe.ast_body();
259 EXPECT_THAT(test::ToString(p->program(), ast_body),
260 HasSubstr("let x_1 : vec2<f32> = vec2<f32>(x_30);"));
261 }
262
TEST_F(SpvUnaryConversionTest,ConvertSToF_Vector_FromUnsigned)263 TEST_F(SpvUnaryConversionTest, ConvertSToF_Vector_FromUnsigned) {
264 const auto assembly = Preamble() + R"(
265 %100 = OpFunction %void None %voidfn
266 %entry = OpLabel
267 %30 = OpCopyObject %v2uint %v2uint_10_20
268 %1 = OpConvertSToF %v2float %30
269 OpReturn
270 OpFunctionEnd
271 )";
272 auto p = parser(test::Assemble(assembly));
273 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
274 auto fe = p->function_emitter(100);
275 EXPECT_TRUE(fe.EmitBody()) << p->error();
276 auto ast_body = fe.ast_body();
277 EXPECT_THAT(
278 test::ToString(p->program(), ast_body),
279 HasSubstr("let x_1 : vec2<f32> = vec2<f32>(bitcast<vec2<i32>>(x_30));"));
280 }
281
TEST_F(SpvUnaryConversionTest,ConvertUToF_Scalar_BadArgType)282 TEST_F(SpvUnaryConversionTest, ConvertUToF_Scalar_BadArgType) {
283 const auto assembly = Preamble() + R"(
284 %100 = OpFunction %void None %voidfn
285 %entry = OpLabel
286 %1 = OpConvertUToF %float %false
287 OpReturn
288 OpFunctionEnd
289 )";
290 auto p = parser(test::Assemble(assembly));
291 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
292 auto fe = p->function_emitter(100);
293 EXPECT_FALSE(fe.EmitBody());
294 EXPECT_THAT(p->error(),
295 HasSubstr("operand for conversion to floating point must be "
296 "integral scalar or vector"));
297 }
298
TEST_F(SpvUnaryConversionTest,ConvertUToF_Vector_BadArgType)299 TEST_F(SpvUnaryConversionTest, ConvertUToF_Vector_BadArgType) {
300 const auto assembly = Preamble() + R"(
301 %100 = OpFunction %void None %voidfn
302 %entry = OpLabel
303 %1 = OpConvertUToF %v2float %v2bool_t_f
304 OpReturn
305 OpFunctionEnd
306 )";
307 auto p = parser(test::Assemble(assembly));
308 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
309 auto fe = p->function_emitter(100);
310 EXPECT_FALSE(fe.EmitBody());
311 EXPECT_THAT(
312 p->error(),
313 HasSubstr("operand for conversion to floating point must be integral "
314 "scalar or vector"));
315 }
316
TEST_F(SpvUnaryConversionTest,ConvertUToF_Scalar_FromSigned)317 TEST_F(SpvUnaryConversionTest, ConvertUToF_Scalar_FromSigned) {
318 const auto assembly = Preamble() + R"(
319 %100 = OpFunction %void None %voidfn
320 %entry = OpLabel
321 %30 = OpCopyObject %int %int_30
322 %1 = OpConvertUToF %float %30
323 OpReturn
324 OpFunctionEnd
325 )";
326 auto p = parser(test::Assemble(assembly));
327 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
328 auto fe = p->function_emitter(100);
329 EXPECT_TRUE(fe.EmitBody()) << p->error();
330 auto ast_body = fe.ast_body();
331 EXPECT_THAT(test::ToString(p->program(), ast_body),
332 HasSubstr("let x_1 : f32 = f32(bitcast<u32>(x_30));"));
333 }
334
TEST_F(SpvUnaryConversionTest,ConvertUToF_Scalar_FromUnsigned)335 TEST_F(SpvUnaryConversionTest, ConvertUToF_Scalar_FromUnsigned) {
336 const auto assembly = Preamble() + R"(
337 %100 = OpFunction %void None %voidfn
338 %entry = OpLabel
339 %30 = OpCopyObject %uint %uint_10
340 %1 = OpConvertUToF %float %30
341 OpReturn
342 OpFunctionEnd
343 )";
344 auto p = parser(test::Assemble(assembly));
345 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
346 auto fe = p->function_emitter(100);
347 EXPECT_TRUE(fe.EmitBody()) << p->error();
348 auto ast_body = fe.ast_body();
349 EXPECT_THAT(test::ToString(p->program(), ast_body),
350 HasSubstr("let x_1 : f32 = f32(x_30);"));
351 }
352
TEST_F(SpvUnaryConversionTest,ConvertUToF_Vector_FromSigned)353 TEST_F(SpvUnaryConversionTest, ConvertUToF_Vector_FromSigned) {
354 const auto assembly = Preamble() + R"(
355 %100 = OpFunction %void None %voidfn
356 %entry = OpLabel
357 %30 = OpCopyObject %v2int %v2int_30_40
358 %1 = OpConvertUToF %v2float %30
359 OpReturn
360 OpFunctionEnd
361 )";
362 auto p = parser(test::Assemble(assembly));
363 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
364 auto fe = p->function_emitter(100);
365 EXPECT_TRUE(fe.EmitBody()) << p->error();
366 auto ast_body = fe.ast_body();
367 EXPECT_THAT(
368 test::ToString(p->program(), ast_body),
369 HasSubstr("let x_1 : vec2<f32> = vec2<f32>(bitcast<vec2<u32>>(x_30));"));
370 }
371
TEST_F(SpvUnaryConversionTest,ConvertUToF_Vector_FromUnsigned)372 TEST_F(SpvUnaryConversionTest, ConvertUToF_Vector_FromUnsigned) {
373 const auto assembly = Preamble() + R"(
374 %100 = OpFunction %void None %voidfn
375 %entry = OpLabel
376 %30 = OpCopyObject %v2uint %v2uint_10_20
377 %1 = OpConvertUToF %v2float %30
378 OpReturn
379 OpFunctionEnd
380 )";
381 auto p = parser(test::Assemble(assembly));
382 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
383 auto fe = p->function_emitter(100);
384 EXPECT_TRUE(fe.EmitBody()) << p->error();
385 auto ast_body = fe.ast_body();
386 EXPECT_THAT(test::ToString(p->program(), ast_body),
387 HasSubstr("let x_1 : vec2<f32> = vec2<f32>(x_30);"));
388 }
389
TEST_F(SpvUnaryConversionTest,ConvertFToS_Scalar_BadArgType)390 TEST_F(SpvUnaryConversionTest, ConvertFToS_Scalar_BadArgType) {
391 const auto assembly = Preamble() + R"(
392 %100 = OpFunction %void None %voidfn
393 %entry = OpLabel
394 %1 = OpConvertFToS %int %uint_10
395 OpReturn
396 OpFunctionEnd
397 )";
398 auto p = parser(test::Assemble(assembly));
399 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
400 auto fe = p->function_emitter(100);
401 EXPECT_FALSE(fe.EmitBody());
402 EXPECT_THAT(
403 p->error(),
404 HasSubstr("operand for conversion to signed integer must be floating "
405 "point scalar or vector"));
406 }
407
TEST_F(SpvUnaryConversionTest,ConvertFToS_Vector_BadArgType)408 TEST_F(SpvUnaryConversionTest, ConvertFToS_Vector_BadArgType) {
409 const auto assembly = Preamble() + R"(
410 %100 = OpFunction %void None %voidfn
411 %entry = OpLabel
412 %1 = OpConvertFToS %v2float %v2bool_t_f
413 OpReturn
414 OpFunctionEnd
415 )";
416 auto p = parser(test::Assemble(assembly));
417 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
418 auto fe = p->function_emitter(100);
419 EXPECT_FALSE(fe.EmitBody());
420 EXPECT_THAT(
421 p->error(),
422 HasSubstr("operand for conversion to signed integer must be floating "
423 "point scalar or vector"));
424 }
425
TEST_F(SpvUnaryConversionTest,ConvertFToS_Scalar_ToSigned)426 TEST_F(SpvUnaryConversionTest, ConvertFToS_Scalar_ToSigned) {
427 const auto assembly = Preamble() + R"(
428 %100 = OpFunction %void None %voidfn
429 %entry = OpLabel
430 %30 = OpCopyObject %float %float_50
431 %1 = OpConvertFToS %int %30
432 OpReturn
433 OpFunctionEnd
434 )";
435 auto p = parser(test::Assemble(assembly));
436 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
437 auto fe = p->function_emitter(100);
438 EXPECT_TRUE(fe.EmitBody()) << p->error();
439 auto ast_body = fe.ast_body();
440 EXPECT_THAT(test::ToString(p->program(), ast_body),
441 HasSubstr("let x_1 : i32 = i32(x_30);"));
442 }
443
TEST_F(SpvUnaryConversionTest,ConvertFToS_Scalar_ToUnsigned)444 TEST_F(SpvUnaryConversionTest, ConvertFToS_Scalar_ToUnsigned) {
445 const auto assembly = Preamble() + R"(
446 %100 = OpFunction %void None %voidfn
447 %entry = OpLabel
448 %30 = OpCopyObject %float %float_50
449 %1 = OpConvertFToS %uint %30
450 OpReturn
451 OpFunctionEnd
452 )";
453 auto p = parser(test::Assemble(assembly));
454 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
455 auto fe = p->function_emitter(100);
456 EXPECT_TRUE(fe.EmitBody()) << p->error();
457 auto ast_body = fe.ast_body();
458 EXPECT_THAT(test::ToString(p->program(), ast_body),
459 HasSubstr("let x_1 : u32 = bitcast<u32>(i32(x_30));"));
460 }
461
TEST_F(SpvUnaryConversionTest,ConvertFToS_Vector_ToSigned)462 TEST_F(SpvUnaryConversionTest, ConvertFToS_Vector_ToSigned) {
463 const auto assembly = Preamble() + R"(
464 %100 = OpFunction %void None %voidfn
465 %entry = OpLabel
466 %30 = OpCopyObject %v2float %v2float_50_60
467 %1 = OpConvertFToS %v2int %30
468 OpReturn
469 OpFunctionEnd
470 )";
471 auto p = parser(test::Assemble(assembly));
472 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
473 auto fe = p->function_emitter(100);
474 EXPECT_TRUE(fe.EmitBody()) << p->error();
475 auto ast_body = fe.ast_body();
476 EXPECT_THAT(test::ToString(p->program(), ast_body),
477 HasSubstr("let x_1 : vec2<i32> = vec2<i32>(x_30);"));
478 }
479
TEST_F(SpvUnaryConversionTest,ConvertFToS_Vector_ToUnsigned)480 TEST_F(SpvUnaryConversionTest, ConvertFToS_Vector_ToUnsigned) {
481 const auto assembly = Preamble() + R"(
482 %100 = OpFunction %void None %voidfn
483 %entry = OpLabel
484 %30 = OpCopyObject %v2float %v2float_50_60
485 %1 = OpConvertFToS %v2uint %30
486 OpReturn
487 OpFunctionEnd
488 )";
489 auto p = parser(test::Assemble(assembly));
490 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
491 auto fe = p->function_emitter(100);
492 EXPECT_TRUE(fe.EmitBody()) << p->error();
493 auto ast_body = fe.ast_body();
494 EXPECT_THAT(
495 test::ToString(p->program(), ast_body),
496 HasSubstr("let x_1 : vec2<u32> = bitcast<vec2<u32>>(vec2<i32>(x_30));"));
497 }
498
TEST_F(SpvUnaryConversionTest,ConvertFToU_Scalar_BadArgType)499 TEST_F(SpvUnaryConversionTest, ConvertFToU_Scalar_BadArgType) {
500 const auto assembly = Preamble() + R"(
501 %100 = OpFunction %void None %voidfn
502 %entry = OpLabel
503 %1 = OpConvertFToU %int %uint_10
504 OpReturn
505 OpFunctionEnd
506 )";
507 auto p = parser(test::Assemble(assembly));
508 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
509 auto fe = p->function_emitter(100);
510 EXPECT_FALSE(fe.EmitBody());
511 EXPECT_THAT(
512 p->error(),
513 HasSubstr("operand for conversion to unsigned integer must be floating "
514 "point scalar or vector"));
515 }
516
TEST_F(SpvUnaryConversionTest,ConvertFToU_Vector_BadArgType)517 TEST_F(SpvUnaryConversionTest, ConvertFToU_Vector_BadArgType) {
518 const auto assembly = Preamble() + R"(
519 %100 = OpFunction %void None %voidfn
520 %entry = OpLabel
521 %1 = OpConvertFToU %v2float %v2bool_t_f
522 OpReturn
523 OpFunctionEnd
524 )";
525 auto p = parser(test::Assemble(assembly));
526 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
527 auto fe = p->function_emitter(100);
528 EXPECT_FALSE(fe.EmitBody());
529 EXPECT_THAT(
530 p->error(),
531 HasSubstr("operand for conversion to unsigned integer must be floating "
532 "point scalar or vector"));
533 }
534
TEST_F(SpvUnaryConversionTest,ConvertFToU_Scalar_ToSigned_IsError)535 TEST_F(SpvUnaryConversionTest, ConvertFToU_Scalar_ToSigned_IsError) {
536 const auto assembly = Preamble() + R"(
537 %100 = OpFunction %void None %voidfn
538 %entry = OpLabel
539 %30 = OpCopyObject %float %float_50
540 %1 = OpConvertFToU %int %30
541 OpReturn
542 OpFunctionEnd
543 )";
544 auto p = parser(test::Assemble(assembly));
545 EXPECT_FALSE(p->Parse());
546 EXPECT_FALSE(p->success());
547 EXPECT_THAT(p->error(), HasSubstr("Expected unsigned int scalar or vector "
548 "type as Result Type: ConvertFToU"));
549 }
550
TEST_F(SpvUnaryConversionTest,ConvertFToU_Scalar_ToUnsigned)551 TEST_F(SpvUnaryConversionTest, ConvertFToU_Scalar_ToUnsigned) {
552 const auto assembly = Preamble() + R"(
553 %100 = OpFunction %void None %voidfn
554 %entry = OpLabel
555 %30 = OpCopyObject %float %float_50
556 %1 = OpConvertFToU %uint %30
557 OpReturn
558 OpFunctionEnd
559 )";
560 auto p = parser(test::Assemble(assembly));
561 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
562 auto fe = p->function_emitter(100);
563 EXPECT_TRUE(fe.EmitBody()) << p->error();
564 auto ast_body = fe.ast_body();
565 EXPECT_THAT(test::ToString(p->program(), ast_body),
566 HasSubstr("let x_1 : u32 = u32(x_30);"));
567 }
568
TEST_F(SpvUnaryConversionTest,ConvertFToU_Vector_ToSigned_IsError)569 TEST_F(SpvUnaryConversionTest, ConvertFToU_Vector_ToSigned_IsError) {
570 const auto assembly = Preamble() + R"(
571 %100 = OpFunction %void None %voidfn
572 %entry = OpLabel
573 %30 = OpCopyObject %v2float %v2float_50_60
574 %1 = OpConvertFToU %v2int %30
575 OpReturn
576 OpFunctionEnd
577 )";
578 auto p = parser(test::Assemble(assembly));
579 EXPECT_FALSE(p->Parse());
580 EXPECT_FALSE(p->success());
581 EXPECT_THAT(p->error(), HasSubstr("Expected unsigned int scalar or vector "
582 "type as Result Type: ConvertFToU"));
583 }
584
TEST_F(SpvUnaryConversionTest,ConvertFToU_Vector_ToUnsigned)585 TEST_F(SpvUnaryConversionTest, ConvertFToU_Vector_ToUnsigned) {
586 const auto assembly = Preamble() + R"(
587 %100 = OpFunction %void None %voidfn
588 %entry = OpLabel
589 %30 = OpCopyObject %v2float %v2float_50_60
590 %1 = OpConvertFToU %v2uint %30
591 OpReturn
592 OpFunctionEnd
593 )";
594 auto p = parser(test::Assemble(assembly));
595 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
596 auto fe = p->function_emitter(100);
597 EXPECT_TRUE(fe.EmitBody()) << p->error();
598 auto ast_body = fe.ast_body();
599 EXPECT_THAT(test::ToString(p->program(), ast_body),
600 HasSubstr("let x_1 : vec2<u32> = vec2<u32>(x_30);"));
601 }
602
TEST_F(SpvUnaryConversionTest,ConvertFToU_HoistedValue)603 TEST_F(SpvUnaryConversionTest, ConvertFToU_HoistedValue) {
604 // From crbug.com/tint/804
605 const auto assembly = Preamble() + R"(
606
607 %100 = OpFunction %void None %voidfn
608 %10 = OpLabel
609 OpBranch %30
610
611 %30 = OpLabel
612 OpLoopMerge %90 %80 None
613 OpBranchConditional %true %90 %40
614
615 %40 = OpLabel
616 OpSelectionMerge %50 None
617 OpBranchConditional %true %45 %50
618
619 %45 = OpLabel
620 ; This value is hoisted
621 %600 = OpCopyObject %float %float_50
622 OpBranch %50
623
624 %50 = OpLabel
625 OpBranch %90
626
627 %80 = OpLabel ; unreachable continue target
628 %82 = OpConvertFToU %uint %600
629 OpBranch %30 ; backedge
630
631 %90 = OpLabel
632 OpReturn
633 OpFunctionEnd
634
635 )";
636 auto p = parser(test::Assemble(assembly));
637 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
638 auto fe = p->function_emitter(100);
639 EXPECT_TRUE(fe.EmitBody()) << p->error();
640 auto ast_body = fe.ast_body();
641 EXPECT_THAT(test::ToString(p->program(), ast_body),
642 HasSubstr("let x_82 : u32 = u32(x_600);"));
643 }
644
645 // TODO(dneto): OpSConvert // only if multiple widths
646 // TODO(dneto): OpUConvert // only if multiple widths
647 // TODO(dneto): OpFConvert // only if multiple widths
648 // TODO(dneto): OpQuantizeToF16 // only if f16 supported
649 // TODO(dneto): OpSatConvertSToU // Kernel (OpenCL), not in WebGPU
650 // TODO(dneto): OpSatConvertUToS // Kernel (OpenCL), not in WebGPU
651
652 } // namespace
653 } // namespace spirv
654 } // namespace reader
655 } // namespace tint
656