• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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