• 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::HasSubstr;
26 
Preamble()27 std::string Preamble() {
28   return R"(
29   OpCapability Shader
30   OpMemoryModel Logical Simple
31   OpEntryPoint Fragment %100 "main"
32   OpExecutionMode %100 OriginUpperLeft
33 
34   %void = OpTypeVoid
35   %voidfn = OpTypeFunction %void
36 
37   %uint = OpTypeInt 32 0
38   %int = OpTypeInt 32 1
39   %float = OpTypeFloat 32
40 
41   %uint_10 = OpConstant %uint 10
42   %uint_20 = OpConstant %uint 20
43   %int_30 = OpConstant %int 30
44   %int_40 = OpConstant %int 40
45   %float_50 = OpConstant %float 50
46   %float_60 = OpConstant %float 60
47   %float_70 = OpConstant %float 70
48 
49   %ptr_uint = OpTypePointer Function %uint
50   %ptr_int = OpTypePointer Function %int
51   %ptr_float = OpTypePointer Function %float
52 
53   %v2uint = OpTypeVector %uint 2
54   %v2int = OpTypeVector %int 2
55   %v2float = OpTypeVector %float 2
56   %v3float = OpTypeVector %float 3
57 
58   %v2uint_10_20 = OpConstantComposite %v2uint %uint_10 %uint_20
59   %v2uint_20_10 = OpConstantComposite %v2uint %uint_20 %uint_10
60   %v2int_30_40 = OpConstantComposite %v2int %int_30 %int_40
61   %v2int_40_30 = OpConstantComposite %v2int %int_40 %int_30
62   %v2float_50_60 = OpConstantComposite %v2float %float_50 %float_60
63   %v2float_60_50 = OpConstantComposite %v2float %float_60 %float_50
64   %v3float_50_60_70 = OpConstantComposite %v3float %float_50 %float_60 %float_70
65   %v3float_60_70_50 = OpConstantComposite %v3float %float_60 %float_70 %float_50
66 
67   %m2v2float = OpTypeMatrix %v2float 2
68   %m2v3float = OpTypeMatrix %v3float 2
69   %m3v2float = OpTypeMatrix %v2float 3
70   %m2v2float_a = OpConstantComposite %m2v2float %v2float_50_60 %v2float_60_50
71   %m2v2float_b = OpConstantComposite %m2v2float %v2float_60_50 %v2float_50_60
72   %m3v2float_a = OpConstantComposite %m3v2float %v2float_50_60 %v2float_60_50 %v2float_50_60
73   %m2v3float_a = OpConstantComposite %m2v3float %v3float_50_60_70 %v3float_60_70_50
74 )";
75 }
76 
77 // Returns the AST dump for a given SPIR-V assembly constant.
AstFor(std::string assembly)78 std::string AstFor(std::string assembly) {
79   if (assembly == "v2uint_10_20") {
80     return "vec2<u32>(10u, 20u)";
81   }
82   if (assembly == "v2uint_20_10") {
83     return "vec2<u32>(20u, 10u)";
84   }
85   if (assembly == "v2int_30_40") {
86     return "vec2<i32>(30, 40)";
87   }
88   if (assembly == "v2int_40_30") {
89     return "vec2<i32>(40, 30)";
90   }
91   if (assembly == "cast_int_v2uint_10_20") {
92     return "bitcast<vec2<i32>>(vec2<u32>(10u, 20u))";
93   }
94   if (assembly == "cast_uint_v2int_40_30") {
95     return "bitcast<vec2<u32>>(vec2<i32>(40, 30))";
96   }
97   if (assembly == "v2float_50_60") {
98     return "vec2<f32>(50.0, 60.0)";
99   }
100   if (assembly == "v2float_60_50") {
101     return "vec2<f32>(60.0, 50.0)";
102   }
103   return "bad case";
104 }
105 
106 using SpvUnaryArithTest = SpvParserTestBase<::testing::Test>;
107 
TEST_F(SpvUnaryArithTest,SNegate_Int_Int)108 TEST_F(SpvUnaryArithTest, SNegate_Int_Int) {
109   const auto assembly = Preamble() + R"(
110      %100 = OpFunction %void None %voidfn
111      %entry = OpLabel
112      %1 = OpSNegate %int %int_30
113      OpReturn
114      OpFunctionEnd
115   )";
116   auto p = parser(test::Assemble(assembly));
117   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
118       << p->error() << "\n"
119       << assembly;
120   auto fe = p->function_emitter(100);
121   EXPECT_TRUE(fe.EmitBody()) << p->error();
122   auto ast_body = fe.ast_body();
123   EXPECT_THAT(test::ToString(p->program(), ast_body),
124               HasSubstr("let x_1 : i32 = -(30);"));
125 }
126 
TEST_F(SpvUnaryArithTest,SNegate_Int_Uint)127 TEST_F(SpvUnaryArithTest, SNegate_Int_Uint) {
128   const auto assembly = Preamble() + R"(
129      %100 = OpFunction %void None %voidfn
130      %entry = OpLabel
131      %1 = OpSNegate %int %uint_10
132      OpReturn
133      OpFunctionEnd
134   )";
135   auto p = parser(test::Assemble(assembly));
136   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
137       << p->error() << "\n"
138       << assembly;
139   auto fe = p->function_emitter(100);
140   EXPECT_TRUE(fe.EmitBody()) << p->error();
141   auto ast_body = fe.ast_body();
142   EXPECT_THAT(test::ToString(p->program(), ast_body),
143               HasSubstr("let x_1 : i32 = -(bitcast<i32>(10u));"));
144 }
145 
TEST_F(SpvUnaryArithTest,SNegate_Uint_Int)146 TEST_F(SpvUnaryArithTest, SNegate_Uint_Int) {
147   const auto assembly = Preamble() + R"(
148      %100 = OpFunction %void None %voidfn
149      %entry = OpLabel
150      %1 = OpSNegate %uint %int_30
151      OpReturn
152      OpFunctionEnd
153   )";
154   auto p = parser(test::Assemble(assembly));
155   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
156       << p->error() << "\n"
157       << assembly;
158   auto fe = p->function_emitter(100);
159   EXPECT_TRUE(fe.EmitBody()) << p->error();
160   auto ast_body = fe.ast_body();
161   EXPECT_THAT(test::ToString(p->program(), ast_body),
162               HasSubstr("let x_1 : u32 = bitcast<u32>(-(30));"));
163 }
164 
TEST_F(SpvUnaryArithTest,SNegate_Uint_Uint)165 TEST_F(SpvUnaryArithTest, SNegate_Uint_Uint) {
166   const auto assembly = Preamble() + R"(
167      %100 = OpFunction %void None %voidfn
168      %entry = OpLabel
169      %1 = OpSNegate %uint %uint_10
170      OpReturn
171      OpFunctionEnd
172   )";
173   auto p = parser(test::Assemble(assembly));
174   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
175       << p->error() << "\n"
176       << assembly;
177   auto fe = p->function_emitter(100);
178   EXPECT_TRUE(fe.EmitBody()) << p->error();
179   auto ast_body = fe.ast_body();
180   EXPECT_THAT(test::ToString(p->program(), ast_body),
181               HasSubstr("let x_1 : u32 = bitcast<u32>(-(bitcast<i32>(10u)));"));
182 }
183 
TEST_F(SpvUnaryArithTest,SNegate_SignedVec_SignedVec)184 TEST_F(SpvUnaryArithTest, SNegate_SignedVec_SignedVec) {
185   const auto assembly = Preamble() + R"(
186      %100 = OpFunction %void None %voidfn
187      %entry = OpLabel
188      %1 = OpSNegate %v2int %v2int_30_40
189      OpReturn
190      OpFunctionEnd
191   )";
192   auto p = parser(test::Assemble(assembly));
193   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
194       << p->error() << "\n"
195       << assembly;
196   auto fe = p->function_emitter(100);
197   EXPECT_TRUE(fe.EmitBody()) << p->error();
198   auto ast_body = fe.ast_body();
199   EXPECT_THAT(test::ToString(p->program(), ast_body),
200               HasSubstr("let x_1 : vec2<i32> = -(vec2<i32>(30, 40));"));
201 }
202 
TEST_F(SpvUnaryArithTest,SNegate_SignedVec_UnsignedVec)203 TEST_F(SpvUnaryArithTest, SNegate_SignedVec_UnsignedVec) {
204   const auto assembly = Preamble() + R"(
205      %100 = OpFunction %void None %voidfn
206      %entry = OpLabel
207      %1 = OpSNegate %v2int %v2uint_10_20
208      OpReturn
209      OpFunctionEnd
210   )";
211   auto p = parser(test::Assemble(assembly));
212   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
213       << p->error() << "\n"
214       << assembly;
215   auto fe = p->function_emitter(100);
216   EXPECT_TRUE(fe.EmitBody()) << p->error();
217   auto ast_body = fe.ast_body();
218   EXPECT_THAT(
219       test::ToString(p->program(), ast_body),
220       HasSubstr(
221           "let x_1 : vec2<i32> = -(bitcast<vec2<i32>>(vec2<u32>(10u, 20u)));"));
222 }
223 
TEST_F(SpvUnaryArithTest,SNegate_UnsignedVec_SignedVec)224 TEST_F(SpvUnaryArithTest, SNegate_UnsignedVec_SignedVec) {
225   const auto assembly = Preamble() + R"(
226      %100 = OpFunction %void None %voidfn
227      %entry = OpLabel
228      %1 = OpSNegate %v2uint %v2int_30_40
229      OpReturn
230      OpFunctionEnd
231   )";
232   auto p = parser(test::Assemble(assembly));
233   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
234       << p->error() << "\n"
235       << assembly;
236   auto fe = p->function_emitter(100);
237   EXPECT_TRUE(fe.EmitBody()) << p->error();
238   auto ast_body = fe.ast_body();
239   EXPECT_THAT(
240       test::ToString(p->program(), ast_body),
241       HasSubstr(
242           "let x_1 : vec2<u32> = bitcast<vec2<u32>>(-(vec2<i32>(30, 40)));"));
243 }
244 
TEST_F(SpvUnaryArithTest,SNegate_UnsignedVec_UnsignedVec)245 TEST_F(SpvUnaryArithTest, SNegate_UnsignedVec_UnsignedVec) {
246   const auto assembly = Preamble() + R"(
247      %100 = OpFunction %void None %voidfn
248      %entry = OpLabel
249      %1 = OpSNegate %v2uint %v2uint_10_20
250      OpReturn
251      OpFunctionEnd
252   )";
253   auto p = parser(test::Assemble(assembly));
254   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
255       << p->error() << "\n"
256       << assembly;
257   auto fe = p->function_emitter(100);
258   EXPECT_TRUE(fe.EmitBody()) << p->error();
259   auto ast_body = fe.ast_body();
260   EXPECT_THAT(
261       test::ToString(p->program(), ast_body),
262       HasSubstr(
263           R"(let x_1 : vec2<u32> = bitcast<vec2<u32>>(-(bitcast<vec2<i32>>(vec2<u32>(10u, 20u))));)"));
264 }
265 
TEST_F(SpvUnaryArithTest,FNegate_Scalar)266 TEST_F(SpvUnaryArithTest, FNegate_Scalar) {
267   const auto assembly = Preamble() + R"(
268      %100 = OpFunction %void None %voidfn
269      %entry = OpLabel
270      %1 = OpFNegate %float %float_50
271      OpReturn
272      OpFunctionEnd
273   )";
274   auto p = parser(test::Assemble(assembly));
275   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
276       << p->error() << "\n"
277       << assembly;
278   auto fe = p->function_emitter(100);
279   EXPECT_TRUE(fe.EmitBody()) << p->error();
280   auto ast_body = fe.ast_body();
281   EXPECT_THAT(test::ToString(p->program(), ast_body),
282               HasSubstr("let x_1 : f32 = -(50.0);"));
283 }
284 
TEST_F(SpvUnaryArithTest,FNegate_Vector)285 TEST_F(SpvUnaryArithTest, FNegate_Vector) {
286   const auto assembly = Preamble() + R"(
287      %100 = OpFunction %void None %voidfn
288      %entry = OpLabel
289      %1 = OpFNegate %v2float %v2float_50_60
290      OpReturn
291      OpFunctionEnd
292   )";
293   auto p = parser(test::Assemble(assembly));
294   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
295       << p->error() << "\n"
296       << assembly;
297   auto fe = p->function_emitter(100);
298   EXPECT_TRUE(fe.EmitBody()) << p->error();
299   auto ast_body = fe.ast_body();
300   EXPECT_THAT(test::ToString(p->program(), ast_body),
301               HasSubstr("let x_1 : vec2<f32> = -(vec2<f32>(50.0, 60.0));"));
302 }
303 
304 struct BinaryData {
305   const std::string res_type;
306   const std::string lhs;
307   const std::string op;
308   const std::string rhs;
309   const std::string ast_type;
310   const std::string ast_lhs;
311   const std::string ast_op;
312   const std::string ast_rhs;
313 };
operator <<(std::ostream & out,BinaryData data)314 inline std::ostream& operator<<(std::ostream& out, BinaryData data) {
315   out << "BinaryData{" << data.res_type << "," << data.lhs << "," << data.op
316       << "," << data.rhs << "," << data.ast_type << "," << data.ast_lhs << ","
317       << data.ast_op << "," << data.ast_rhs << "}";
318   return out;
319 }
320 
321 using SpvBinaryArithTest =
322     SpvParserTestBase<::testing::TestWithParam<BinaryData>>;
323 using SpvBinaryArithTestBasic = SpvParserTestBase<::testing::Test>;
324 
TEST_P(SpvBinaryArithTest,EmitExpression)325 TEST_P(SpvBinaryArithTest, EmitExpression) {
326   const auto assembly = Preamble() + R"(
327      %100 = OpFunction %void None %voidfn
328      %entry = OpLabel
329      %1 = )" + GetParam().op +
330                         " %" + GetParam().res_type + " %" + GetParam().lhs +
331                         " %" + GetParam().rhs + R"(
332      OpReturn
333      OpFunctionEnd
334   )";
335   auto p = parser(test::Assemble(assembly));
336   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
337       << p->error() << "\n"
338       << assembly;
339   auto fe = p->function_emitter(100);
340   EXPECT_TRUE(fe.EmitBody()) << p->error();
341   std::ostringstream ss;
342   ss << "let x_1 : " << GetParam().ast_type << " = (" << GetParam().ast_lhs
343      << " " << GetParam().ast_op << " " << GetParam().ast_rhs << ");";
344   auto ast_body = fe.ast_body();
345   auto got = test::ToString(p->program(), ast_body);
346   EXPECT_THAT(got, HasSubstr(ss.str())) << "got:\n" << got << assembly;
347 }
348 
349 // Use this when the result might have extra bitcasts on the outside.
350 struct BinaryDataGeneral {
351   const std::string res_type;
352   const std::string lhs;
353   const std::string op;
354   const std::string rhs;
355   const std::string wgsl_type;
356   const std::string expected;
357 };
operator <<(std::ostream & out,BinaryDataGeneral data)358 inline std::ostream& operator<<(std::ostream& out, BinaryDataGeneral data) {
359   out << "BinaryDataGeneral{" << data.res_type << "," << data.lhs << ","
360       << data.op << "," << data.rhs << "," << data.wgsl_type << ","
361       << data.expected << "}";
362   return out;
363 }
364 
365 using SpvBinaryArithGeneralTest =
366     SpvParserTestBase<::testing::TestWithParam<BinaryDataGeneral>>;
367 
TEST_P(SpvBinaryArithGeneralTest,EmitExpression)368 TEST_P(SpvBinaryArithGeneralTest, EmitExpression) {
369   const auto assembly = Preamble() + R"(
370      %100 = OpFunction %void None %voidfn
371      %entry = OpLabel
372      %1 = )" + GetParam().op +
373                         " %" + GetParam().res_type + " %" + GetParam().lhs +
374                         " %" + GetParam().rhs + R"(
375      OpReturn
376      OpFunctionEnd
377   )";
378   auto p = parser(test::Assemble(assembly));
379   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
380       << p->error() << "\n"
381       << assembly;
382   auto fe = p->function_emitter(100);
383   EXPECT_TRUE(fe.EmitBody()) << p->error();
384   std::ostringstream ss;
385   ss << "let x_1 : " << GetParam().wgsl_type << " = " << GetParam().expected
386      << ";";
387   auto ast_body = fe.ast_body();
388   auto got = test::ToString(p->program(), ast_body);
389   EXPECT_THAT(got, HasSubstr(ss.str())) << "got:\n" << got << assembly;
390 }
391 
392 INSTANTIATE_TEST_SUITE_P(
393     SpvParserTest_IAdd,
394     SpvBinaryArithTest,
395     ::testing::Values(
396         // Both uint
397         BinaryData{"uint", "uint_10", "OpIAdd", "uint_20", "u32", "10u", "+",
398                    "20u"},  // Both int
399         BinaryData{"int", "int_30", "OpIAdd", "int_40", "i32", "30", "+",
400                    "40"},  // Both v2uint
401         BinaryData{"v2uint", "v2uint_10_20", "OpIAdd", "v2uint_20_10",
402                    "vec2<u32>", AstFor("v2uint_10_20"), "+",
403                    AstFor("v2uint_20_10")},
404         // Both v2int
405         BinaryData{"v2int", "v2int_30_40", "OpIAdd", "v2int_40_30", "vec2<i32>",
406                    AstFor("v2int_30_40"), "+", AstFor("v2int_40_30")}));
407 
408 INSTANTIATE_TEST_SUITE_P(
409     SpvParserTest_IAdd_MixedSignedness,
410     SpvBinaryArithGeneralTest,
411     ::testing::Values(
412         // Mixed, uint <- int uint
413         BinaryDataGeneral{"uint", "int_30", "OpIAdd", "uint_10", "u32",
414                           "bitcast<u32>((30 + bitcast<i32>(10u)))"},
415         // Mixed, int <- int uint
416         BinaryDataGeneral{"int", "int_30", "OpIAdd", "uint_10", "i32",
417                           "(30 + bitcast<i32>(10u))"},
418         // Mixed, uint <- uint int
419         BinaryDataGeneral{"uint", "uint_10", "OpIAdd", "int_30", "u32",
420                           "(10u + bitcast<u32>(30))"},
421         // Mixed, int <- uint uint
422         BinaryDataGeneral{"int", "uint_20", "OpIAdd", "uint_10", "i32",
423                           "bitcast<i32>((20u + 10u))"},
424         // Mixed, returning v2uint
425         BinaryDataGeneral{
426             "v2uint", "v2int_30_40", "OpIAdd", "v2uint_10_20", "vec2<u32>",
427             R"(bitcast<vec2<u32>>((vec2<i32>(30, 40) + bitcast<vec2<i32>>(vec2<u32>(10u, 20u)))))"},
428         // Mixed, returning v2int
429         BinaryDataGeneral{
430             "v2int", "v2uint_10_20", "OpIAdd", "v2int_40_30", "vec2<i32>",
431             R"(bitcast<vec2<i32>>((vec2<u32>(10u, 20u) + bitcast<vec2<u32>>(vec2<i32>(40, 30)))))"}));
432 
433 INSTANTIATE_TEST_SUITE_P(
434     SpvParserTest_FAdd,
435     SpvBinaryArithTest,
436     ::testing::Values(
437         // Scalar float
438         BinaryData{"float", "float_50", "OpFAdd", "float_60", "f32", "50.0",
439                    "+", "60.0"},  // Vector float
440         BinaryData{"v2float", "v2float_50_60", "OpFAdd", "v2float_60_50",
441                    "vec2<f32>", AstFor("v2float_50_60"), "+",
442                    AstFor("v2float_60_50")}));
443 
444 INSTANTIATE_TEST_SUITE_P(
445     SpvParserTest_ISub,
446     SpvBinaryArithTest,
447     ::testing::Values(
448         // Both uint
449         BinaryData{"uint", "uint_10", "OpISub", "uint_20", "u32", "10u", "-",
450                    "20u"},  // Both int
451         BinaryData{"int", "int_30", "OpISub", "int_40", "i32", "30", "-",
452                    "40"},  // Both v2uint
453         BinaryData{"v2uint", "v2uint_10_20", "OpISub", "v2uint_20_10",
454                    "vec2<u32>", AstFor("v2uint_10_20"), "-",
455                    AstFor("v2uint_20_10")},
456         // Both v2int
457         BinaryData{"v2int", "v2int_30_40", "OpISub", "v2int_40_30", "vec2<i32>",
458                    AstFor("v2int_30_40"), "-", AstFor("v2int_40_30")}));
459 
460 INSTANTIATE_TEST_SUITE_P(
461     SpvParserTest_ISub_MixedSignedness,
462     SpvBinaryArithGeneralTest,
463     ::testing::Values(
464         // Mixed, uint <- int uint
465         BinaryDataGeneral{"uint", "int_30", "OpISub", "uint_10", "u32",
466                           R"(bitcast<u32>((30 - bitcast<i32>(10u))))"},
467         // Mixed, int <- int uint
468         BinaryDataGeneral{"int", "int_30", "OpISub", "uint_10", "i32",
469                           "(30 - bitcast<i32>(10u))"},
470         // Mixed, uint <- uint int
471         BinaryDataGeneral{"uint", "uint_10", "OpISub", "int_30", "u32",
472                           "(10u - bitcast<u32>(30))"},
473         // Mixed, int <- uint uint
474         BinaryDataGeneral{"int", "uint_20", "OpISub", "uint_10", "i32",
475                           "bitcast<i32>((20u - 10u))"},
476         // Mixed, returning v2uint
477         BinaryDataGeneral{
478             "v2uint", "v2int_30_40", "OpISub", "v2uint_10_20", "vec2<u32>",
479             R"(bitcast<vec2<u32>>((vec2<i32>(30, 40) - bitcast<vec2<i32>>(vec2<u32>(10u, 20u)))))"},
480         // Mixed, returning v2int
481         BinaryDataGeneral{
482             "v2int", "v2uint_10_20", "OpISub", "v2int_40_30", "vec2<i32>",
483             R"(bitcast<vec2<i32>>((vec2<u32>(10u, 20u) - bitcast<vec2<u32>>(vec2<i32>(40, 30)))))"}));
484 
485 INSTANTIATE_TEST_SUITE_P(
486     SpvParserTest_FSub,
487     SpvBinaryArithTest,
488     ::testing::Values(
489         // Scalar float
490         BinaryData{"float", "float_50", "OpFSub", "float_60", "f32", "50.0",
491                    "-", "60.0"},  // Vector float
492         BinaryData{"v2float", "v2float_50_60", "OpFSub", "v2float_60_50",
493                    "vec2<f32>", AstFor("v2float_50_60"), "-",
494                    AstFor("v2float_60_50")}));
495 
496 INSTANTIATE_TEST_SUITE_P(
497     SpvParserTest_IMul,
498     SpvBinaryArithTest,
499     ::testing::Values(
500         // Both uint
501         BinaryData{"uint", "uint_10", "OpIMul", "uint_20", "u32", "10u", "*",
502                    "20u"},  // Both int
503         BinaryData{"int", "int_30", "OpIMul", "int_40", "i32", "30", "*",
504                    "40"},  // Both v2uint
505         BinaryData{"v2uint", "v2uint_10_20", "OpIMul", "v2uint_20_10",
506                    "vec2<u32>", AstFor("v2uint_10_20"), "*",
507                    AstFor("v2uint_20_10")},
508         // Both v2int
509         BinaryData{"v2int", "v2int_30_40", "OpIMul", "v2int_40_30", "vec2<i32>",
510                    AstFor("v2int_30_40"), "*", AstFor("v2int_40_30")}));
511 
512 INSTANTIATE_TEST_SUITE_P(
513     SpvParserTest_IMul_MixedSignedness,
514     SpvBinaryArithGeneralTest,
515     ::testing::Values(
516         // Mixed, uint <- int uint
517         BinaryDataGeneral{"uint", "int_30", "OpIMul", "uint_10", "u32",
518                           "bitcast<u32>((30 * bitcast<i32>(10u)))"},
519         // Mixed, int <- int uint
520         BinaryDataGeneral{"int", "int_30", "OpIMul", "uint_10", "i32",
521                           "(30 * bitcast<i32>(10u))"},
522         // Mixed, uint <- uint int
523         BinaryDataGeneral{"uint", "uint_10", "OpIMul", "int_30", "u32",
524                           "(10u * bitcast<u32>(30))"},
525         // Mixed, int <- uint uint
526         BinaryDataGeneral{"int", "uint_20", "OpIMul", "uint_10", "i32",
527                           "bitcast<i32>((20u * 10u))"},
528         // Mixed, returning v2uint
529         BinaryDataGeneral{
530             "v2uint", "v2int_30_40", "OpIMul", "v2uint_10_20", "vec2<u32>",
531             R"(bitcast<vec2<u32>>((vec2<i32>(30, 40) * bitcast<vec2<i32>>(vec2<u32>(10u, 20u)))))"},
532         // Mixed, returning v2int
533         BinaryDataGeneral{
534             "v2int", "v2uint_10_20", "OpIMul", "v2int_40_30", "vec2<i32>",
535             R"(bitcast<vec2<i32>>((vec2<u32>(10u, 20u) * bitcast<vec2<u32>>(vec2<i32>(40, 30)))))"}));
536 
537 INSTANTIATE_TEST_SUITE_P(
538     SpvParserTest_FMul,
539     SpvBinaryArithTest,
540     ::testing::Values(
541         // Scalar float
542         BinaryData{"float", "float_50", "OpFMul", "float_60", "f32", "50.0",
543                    "*", "60.0"},  // Vector float
544         BinaryData{"v2float", "v2float_50_60", "OpFMul", "v2float_60_50",
545                    "vec2<f32>", AstFor("v2float_50_60"), "*",
546                    AstFor("v2float_60_50")}));
547 
548 INSTANTIATE_TEST_SUITE_P(
549     SpvParserTest_UDiv,
550     SpvBinaryArithTest,
551     ::testing::Values(
552         // Both uint
553         BinaryData{"uint", "uint_10", "OpUDiv", "uint_20", "u32", "10u", "/",
554                    "20u"},  // Both v2uint
555         BinaryData{"v2uint", "v2uint_10_20", "OpUDiv", "v2uint_20_10",
556                    "vec2<u32>", AstFor("v2uint_10_20"), "/",
557                    AstFor("v2uint_20_10")}));
558 
559 INSTANTIATE_TEST_SUITE_P(
560     SpvParserTest_SDiv,
561     SpvBinaryArithTest,
562     ::testing::Values(
563         // Both int
564         BinaryData{"int", "int_30", "OpSDiv", "int_40", "i32", "30", "/",
565                    "40"},  // Both v2int
566         BinaryData{"v2int", "v2int_30_40", "OpSDiv", "v2int_40_30", "vec2<i32>",
567                    AstFor("v2int_30_40"), "/", AstFor("v2int_40_30")}));
568 
569 INSTANTIATE_TEST_SUITE_P(
570     SpvParserTest_SDiv_MixedSignednessOperands,
571     SpvBinaryArithTest,
572     ::testing::Values(
573         // Mixed, returning int, second arg uint
574         BinaryData{"int", "int_30", "OpSDiv", "uint_10", "i32", "30", "/",
575                    "bitcast<i32>(10u)"},
576         // Mixed, returning int, first arg uint
577         BinaryData{"int", "uint_10", "OpSDiv", "int_30", "i32",
578                    "bitcast<i32>(10u)", "/",
579                    "30"},  // Mixed, returning v2int, first arg v2uint
580         BinaryData{"v2int", "v2uint_10_20", "OpSDiv", "v2int_30_40",
581                    "vec2<i32>", AstFor("cast_int_v2uint_10_20"), "/",
582                    AstFor("v2int_30_40")},
583         // Mixed, returning v2int, second arg v2uint
584         BinaryData{"v2int", "v2int_30_40", "OpSDiv", "v2uint_10_20",
585                    "vec2<i32>", AstFor("v2int_30_40"), "/",
586                    AstFor("cast_int_v2uint_10_20")}));
587 
TEST_F(SpvBinaryArithTestBasic,SDiv_Scalar_UnsignedResult)588 TEST_F(SpvBinaryArithTestBasic, SDiv_Scalar_UnsignedResult) {
589   // The WGSL signed division operator expects both operands to be signed
590   // and the result is signed as well.
591   // In this test SPIR-V demands an unsigned result, so we have to
592   // wrap the result with an as-cast.
593   const auto assembly = Preamble() + R"(
594      %100 = OpFunction %void None %voidfn
595      %entry = OpLabel
596      %1 = OpSDiv %uint %int_30 %int_40
597      OpReturn
598      OpFunctionEnd
599   )";
600   auto p = parser(test::Assemble(assembly));
601   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
602       << p->error() << "\n"
603       << assembly;
604   auto fe = p->function_emitter(100);
605   EXPECT_TRUE(fe.EmitBody()) << p->error();
606   auto ast_body = fe.ast_body();
607   EXPECT_THAT(test::ToString(p->program(), ast_body),
608               HasSubstr("let x_1 : u32 = bitcast<u32>((30 / 40));"));
609 }
610 
TEST_F(SpvBinaryArithTestBasic,SDiv_Vector_UnsignedResult)611 TEST_F(SpvBinaryArithTestBasic, SDiv_Vector_UnsignedResult) {
612   // The WGSL signed division operator expects both operands to be signed
613   // and the result is signed as well.
614   // In this test SPIR-V demands an unsigned result, so we have to
615   // wrap the result with an as-cast.
616   const auto assembly = Preamble() + R"(
617      %100 = OpFunction %void None %voidfn
618      %entry = OpLabel
619      %1 = OpSDiv %v2uint %v2int_30_40 %v2int_40_30
620      OpReturn
621      OpFunctionEnd
622   )";
623   auto p = parser(test::Assemble(assembly));
624   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
625       << p->error() << "\n"
626       << assembly;
627   auto fe = p->function_emitter(100);
628   EXPECT_TRUE(fe.EmitBody()) << p->error();
629   auto ast_body = fe.ast_body();
630   EXPECT_THAT(
631       test::ToString(p->program(), ast_body),
632       HasSubstr(
633           R"(let x_1 : vec2<u32> = bitcast<vec2<u32>>((vec2<i32>(30, 40) / vec2<i32>(40, 30)));)"));
634 }
635 
636 INSTANTIATE_TEST_SUITE_P(
637     SpvParserTest_FDiv,
638     SpvBinaryArithTest,
639     ::testing::Values(
640         // Scalar float
641         BinaryData{"float", "float_50", "OpFDiv", "float_60", "f32", "50.0",
642                    "/", "60.0"},  // Vector float
643         BinaryData{"v2float", "v2float_50_60", "OpFDiv", "v2float_60_50",
644                    "vec2<f32>", AstFor("v2float_50_60"), "/",
645                    AstFor("v2float_60_50")}));
646 
647 INSTANTIATE_TEST_SUITE_P(
648     SpvParserTest_UMod,
649     SpvBinaryArithTest,
650     ::testing::Values(
651         // Both uint
652         BinaryData{"uint", "uint_10", "OpUMod", "uint_20", "u32", "10u", "%",
653                    "20u"},  // Both v2uint
654         BinaryData{"v2uint", "v2uint_10_20", "OpUMod", "v2uint_20_10",
655                    "vec2<u32>", AstFor("v2uint_10_20"), "%",
656                    AstFor("v2uint_20_10")}));
657 
658 // Currently WGSL is missing a mapping for OpSRem
659 // https://github.com/gpuweb/gpuweb/issues/702
660 
661 INSTANTIATE_TEST_SUITE_P(
662     SpvParserTest_SMod,
663     SpvBinaryArithTest,
664     ::testing::Values(
665         // Both int
666         BinaryData{"int", "int_30", "OpSMod", "int_40", "i32", "30", "%",
667                    "40"},  // Both v2int
668         BinaryData{"v2int", "v2int_30_40", "OpSMod", "v2int_40_30", "vec2<i32>",
669                    AstFor("v2int_30_40"), "%", AstFor("v2int_40_30")}));
670 
671 INSTANTIATE_TEST_SUITE_P(
672     SpvParserTest_SMod_MixedSignednessOperands,
673     SpvBinaryArithTest,
674     ::testing::Values(
675         // Mixed, returning int, second arg uint
676         BinaryData{"int", "int_30", "OpSMod", "uint_10", "i32", "30", "%",
677                    "bitcast<i32>(10u)"},
678         // Mixed, returning int, first arg uint
679         BinaryData{"int", "uint_10", "OpSMod", "int_30", "i32",
680                    "bitcast<i32>(10u)", "%",
681                    "30"},  // Mixed, returning v2int, first arg v2uint
682         BinaryData{"v2int", "v2uint_10_20", "OpSMod", "v2int_30_40",
683                    "vec2<i32>", AstFor("cast_int_v2uint_10_20"), "%",
684                    AstFor("v2int_30_40")},
685         // Mixed, returning v2int, second arg v2uint
686         BinaryData{"v2int", "v2int_30_40", "OpSMod", "v2uint_10_20",
687                    "vec2<i32>", AstFor("v2int_30_40"), "%",
688                    AstFor("cast_int_v2uint_10_20")}));
689 
TEST_F(SpvBinaryArithTestBasic,SMod_Scalar_UnsignedResult)690 TEST_F(SpvBinaryArithTestBasic, SMod_Scalar_UnsignedResult) {
691   // The WGSL signed modulus operator expects both operands to be signed
692   // and the result is signed as well.
693   // In this test SPIR-V demands an unsigned result, so we have to
694   // wrap the result with an as-cast.
695   const auto assembly = Preamble() + R"(
696      %100 = OpFunction %void None %voidfn
697      %entry = OpLabel
698      %1 = OpSMod %uint %int_30 %int_40
699      OpReturn
700      OpFunctionEnd
701   )";
702   auto p = parser(test::Assemble(assembly));
703   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
704       << p->error() << "\n"
705       << assembly;
706   auto fe = p->function_emitter(100);
707   EXPECT_TRUE(fe.EmitBody()) << p->error();
708   auto ast_body = fe.ast_body();
709   EXPECT_THAT(test::ToString(p->program(), ast_body),
710               HasSubstr("let x_1 : u32 = bitcast<u32>((30 % 40));"));
711 }
712 
TEST_F(SpvBinaryArithTestBasic,SMod_Vector_UnsignedResult)713 TEST_F(SpvBinaryArithTestBasic, SMod_Vector_UnsignedResult) {
714   // The WGSL signed modulus operator expects both operands to be signed
715   // and the result is signed as well.
716   // In this test SPIR-V demands an unsigned result, so we have to
717   // wrap the result with an as-cast.
718   const auto assembly = Preamble() + R"(
719      %100 = OpFunction %void None %voidfn
720      %entry = OpLabel
721      %1 = OpSMod %v2uint %v2int_30_40 %v2int_40_30
722      OpReturn
723      OpFunctionEnd
724   )";
725   auto p = parser(test::Assemble(assembly));
726   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
727       << p->error() << "\n"
728       << assembly;
729   auto fe = p->function_emitter(100);
730   EXPECT_TRUE(fe.EmitBody()) << p->error();
731   auto ast_body = fe.ast_body();
732   EXPECT_THAT(
733       test::ToString(p->program(), ast_body),
734       HasSubstr(
735           R"(let x_1 : vec2<u32> = bitcast<vec2<u32>>((vec2<i32>(30, 40) % vec2<i32>(40, 30)));)"));
736 }
737 
738 INSTANTIATE_TEST_SUITE_P(
739     SpvParserTest_FRem,
740     SpvBinaryArithTest,
741     ::testing::Values(
742         // Scalar float
743         BinaryData{"float", "float_50", "OpFRem", "float_60", "f32", "50.0",
744                    "%", "60.0"},  // Vector float
745         BinaryData{"v2float", "v2float_50_60", "OpFRem", "v2float_60_50",
746                    "vec2<f32>", AstFor("v2float_50_60"), "%",
747                    AstFor("v2float_60_50")}));
748 
TEST_F(SpvBinaryArithTestBasic,FMod_Scalar)749 TEST_F(SpvBinaryArithTestBasic, FMod_Scalar) {
750   const auto assembly = Preamble() + R"(
751      %100 = OpFunction %void None %voidfn
752      %entry = OpLabel
753      %1 = OpFMod %float %float_50 %float_60
754      OpReturn
755      OpFunctionEnd
756   )";
757   auto p = parser(test::Assemble(assembly));
758   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
759       << p->error() << "\n"
760       << assembly;
761   auto fe = p->function_emitter(100);
762   EXPECT_TRUE(fe.EmitBody()) << p->error();
763   auto ast_body = fe.ast_body();
764   EXPECT_THAT(
765       test::ToString(p->program(), ast_body),
766       HasSubstr("let x_1 : f32 = (50.0 - (60.0 * floor((50.0 / 60.0))));"));
767 }
768 
TEST_F(SpvBinaryArithTestBasic,FMod_Vector)769 TEST_F(SpvBinaryArithTestBasic, FMod_Vector) {
770   const auto assembly = Preamble() + R"(
771      %100 = OpFunction %void None %voidfn
772      %entry = OpLabel
773      %1 = OpFMod %v2float %v2float_50_60 %v2float_60_50
774      OpReturn
775      OpFunctionEnd
776   )";
777   auto p = parser(test::Assemble(assembly));
778   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
779       << p->error() << "\n"
780       << assembly;
781   auto fe = p->function_emitter(100);
782   EXPECT_TRUE(fe.EmitBody()) << p->error();
783   auto ast_body = fe.ast_body();
784   EXPECT_THAT(
785       test::ToString(p->program(), ast_body),
786       HasSubstr(
787           R"(let x_1 : vec2<f32> = (vec2<f32>(50.0, 60.0) - (vec2<f32>(60.0, 50.0) * floor((vec2<f32>(50.0, 60.0) / vec2<f32>(60.0, 50.0)))));)"));
788 }
789 
TEST_F(SpvBinaryArithTestBasic,VectorTimesScalar)790 TEST_F(SpvBinaryArithTestBasic, VectorTimesScalar) {
791   const auto assembly = Preamble() + R"(
792      %100 = OpFunction %void None %voidfn
793      %entry = OpLabel
794      %1 = OpCopyObject %v2float %v2float_50_60
795      %2 = OpCopyObject %float %float_50
796      %10 = OpVectorTimesScalar %v2float %1 %2
797      OpReturn
798      OpFunctionEnd
799 )";
800   auto p = parser(test::Assemble(assembly));
801   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
802       << assembly << p->error();
803   auto fe = p->function_emitter(100);
804   EXPECT_TRUE(fe.EmitBody()) << p->error();
805   auto ast_body = fe.ast_body();
806   EXPECT_THAT(test::ToString(p->program(), ast_body),
807               HasSubstr("let x_10 : vec2<f32> = (x_1 * x_2);"));
808 }
809 
TEST_F(SpvBinaryArithTestBasic,MatrixTimesScalar)810 TEST_F(SpvBinaryArithTestBasic, MatrixTimesScalar) {
811   const auto assembly = Preamble() + R"(
812      %100 = OpFunction %void None %voidfn
813      %entry = OpLabel
814      %1 = OpCopyObject %m2v2float %m2v2float_a
815      %2 = OpCopyObject %float %float_50
816      %10 = OpMatrixTimesScalar %m2v2float %1 %2
817      OpReturn
818      OpFunctionEnd
819 )";
820   auto p = parser(test::Assemble(assembly));
821   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
822       << assembly << p->error();
823   auto fe = p->function_emitter(100);
824   EXPECT_TRUE(fe.EmitBody()) << p->error();
825   auto ast_body = fe.ast_body();
826   EXPECT_THAT(test::ToString(p->program(), ast_body),
827               HasSubstr("let x_10 : mat2x2<f32> = (x_1 * x_2);"));
828 }
829 
TEST_F(SpvBinaryArithTestBasic,VectorTimesMatrix)830 TEST_F(SpvBinaryArithTestBasic, VectorTimesMatrix) {
831   const auto assembly = Preamble() + R"(
832      %100 = OpFunction %void None %voidfn
833      %entry = OpLabel
834      %1 = OpCopyObject %m2v2float %m2v2float_a
835      %2 = OpCopyObject %v2float %v2float_50_60
836      %10 = OpMatrixTimesVector %v2float %1 %2
837      OpReturn
838      OpFunctionEnd
839 )";
840   auto p = parser(test::Assemble(assembly));
841   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
842       << assembly << p->error();
843   auto fe = p->function_emitter(100);
844   EXPECT_TRUE(fe.EmitBody()) << p->error();
845   auto ast_body = fe.ast_body();
846   EXPECT_THAT(test::ToString(p->program(), ast_body),
847               HasSubstr("let x_10 : vec2<f32> = (x_1 * x_2);"));
848 }
849 
TEST_F(SpvBinaryArithTestBasic,MatrixTimesVector)850 TEST_F(SpvBinaryArithTestBasic, MatrixTimesVector) {
851   const auto assembly = Preamble() + R"(
852      %100 = OpFunction %void None %voidfn
853      %entry = OpLabel
854      %1 = OpCopyObject %m2v2float %m2v2float_a
855      %2 = OpCopyObject %v2float %v2float_50_60
856      %10 = OpMatrixTimesVector %v2float %1 %2
857      OpReturn
858      OpFunctionEnd
859 )";
860   auto p = parser(test::Assemble(assembly));
861   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
862       << assembly << p->error();
863   auto fe = p->function_emitter(100);
864   EXPECT_TRUE(fe.EmitBody()) << p->error();
865   auto ast_body = fe.ast_body();
866   EXPECT_THAT(test::ToString(p->program(), ast_body),
867               HasSubstr("let x_10 : vec2<f32> = (x_1 * x_2);"));
868 }
869 
TEST_F(SpvBinaryArithTestBasic,MatrixTimesMatrix)870 TEST_F(SpvBinaryArithTestBasic, MatrixTimesMatrix) {
871   const auto assembly = Preamble() + R"(
872      %100 = OpFunction %void None %voidfn
873      %entry = OpLabel
874      %1 = OpCopyObject %m2v2float %m2v2float_a
875      %2 = OpCopyObject %m2v2float %m2v2float_b
876      %10 = OpMatrixTimesMatrix %m2v2float %1 %2
877      OpReturn
878      OpFunctionEnd
879 )";
880   auto p = parser(test::Assemble(assembly));
881   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
882       << assembly << p->error();
883   auto fe = p->function_emitter(100);
884   EXPECT_TRUE(fe.EmitBody()) << p->error();
885   auto ast_body = fe.ast_body();
886   EXPECT_THAT(test::ToString(p->program(), ast_body),
887               HasSubstr("let x_10 : mat2x2<f32> = (x_1 * x_2);"));
888 }
889 
TEST_F(SpvBinaryArithTestBasic,Dot)890 TEST_F(SpvBinaryArithTestBasic, Dot) {
891   const auto assembly = Preamble() + R"(
892      %100 = OpFunction %void None %voidfn
893      %entry = OpLabel
894      %1 = OpCopyObject %v2float %v2float_50_60
895      %2 = OpCopyObject %v2float %v2float_60_50
896      %3 = OpDot %float %1 %2
897      OpReturn
898      OpFunctionEnd
899 )";
900   auto p = parser(test::Assemble(assembly));
901   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
902       << assembly << p->error();
903   auto fe = p->function_emitter(100);
904   EXPECT_TRUE(fe.EmitBody()) << p->error();
905   auto ast_body = fe.ast_body();
906   EXPECT_THAT(test::ToString(p->program(), ast_body),
907               HasSubstr("let x_3 : f32 = dot(x_1, x_2);"));
908 }
909 
TEST_F(SpvBinaryArithTestBasic,OuterProduct)910 TEST_F(SpvBinaryArithTestBasic, OuterProduct) {
911   // OpOuterProduct is expanded to basic operations.
912   // The operands, even if used once, are given their own const definitions.
913   const auto assembly = Preamble() + R"(
914      %100 = OpFunction %void None %voidfn
915      %entry = OpLabel
916      %1 = OpFAdd %v3float %v3float_50_60_70 %v3float_50_60_70 ; column vector
917      %2 = OpFAdd %v2float %v2float_60_50 %v2float_50_60 ; row vector
918      %3 = OpOuterProduct %m2v3float %1 %2
919      OpReturn
920      OpFunctionEnd
921 )";
922   auto p = parser(test::Assemble(assembly));
923   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
924       << assembly << p->error();
925   auto fe = p->function_emitter(100);
926   EXPECT_TRUE(fe.EmitBody()) << p->error();
927   auto ast_body = fe.ast_body();
928   auto got = test::ToString(p->program(), ast_body);
929   EXPECT_THAT(
930       got,
931       HasSubstr(
932           "let x_3 : mat2x3<f32> = mat2x3<f32>("
933           "vec3<f32>((x_2.x * x_1.x), (x_2.x * x_1.y), (x_2.x * x_1.z)), "
934           "vec3<f32>((x_2.y * x_1.x), (x_2.y * x_1.y), (x_2.y * x_1.z)));"))
935       << got;
936 }
937 
938 struct IntrinsicData {
939   const std::string spirv;
940   const std::string wgsl;
941 };
operator <<(std::ostream & out,IntrinsicData data)942 inline std::ostream& operator<<(std::ostream& out, IntrinsicData data) {
943   out << "OpData{" << data.spirv << "," << data.wgsl << "}";
944   return out;
945 }
946 struct ArgAndTypeData {
947   const std::string spirv_type;
948   const std::string spirv_arg;
949   const std::string ast_type;
950 };
operator <<(std::ostream & out,ArgAndTypeData data)951 inline std::ostream& operator<<(std::ostream& out, ArgAndTypeData data) {
952   out << "ArgAndTypeData{" << data.spirv_type << "," << data.spirv_arg << ","
953       << data.ast_type << "}";
954   return out;
955 }
956 
957 using SpvBinaryDerivativeTest = SpvParserTestBase<
958     ::testing::TestWithParam<std::tuple<IntrinsicData, ArgAndTypeData>>>;
959 
TEST_P(SpvBinaryDerivativeTest,Derivatives)960 TEST_P(SpvBinaryDerivativeTest, Derivatives) {
961   auto& intrinsic = std::get<0>(GetParam());
962   auto& arg = std::get<1>(GetParam());
963 
964   const auto assembly = R"(
965      OpCapability DerivativeControl
966 )" + Preamble() + R"(
967      %100 = OpFunction %void None %voidfn
968      %entry = OpLabel
969      %1 = OpCopyObject %)" +
970                         arg.spirv_type + " %" + arg.spirv_arg + R"(
971      %2 = )" + intrinsic.spirv +
972                         " %" + arg.spirv_type + R"( %1
973      OpReturn
974      OpFunctionEnd
975 )";
976   auto p = parser(test::Assemble(assembly));
977   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
978       << assembly << p->error();
979   auto fe = p->function_emitter(100);
980   EXPECT_TRUE(fe.EmitBody()) << p->error();
981   auto ast_body = fe.ast_body();
982   EXPECT_THAT(test::ToString(p->program(), ast_body),
983               HasSubstr("let x_2 : " + arg.ast_type + " = " + intrinsic.wgsl +
984                         "(x_1);"));
985 }
986 
987 INSTANTIATE_TEST_SUITE_P(
988     SpvBinaryDerivativeTest,
989     SpvBinaryDerivativeTest,
990     testing::Combine(
991         ::testing::Values(IntrinsicData{"OpDPdx", "dpdx"},
992                           IntrinsicData{"OpDPdy", "dpdy"},
993                           IntrinsicData{"OpFwidth", "fwidth"},
994                           IntrinsicData{"OpDPdxFine", "dpdxFine"},
995                           IntrinsicData{"OpDPdyFine", "dpdyFine"},
996                           IntrinsicData{"OpFwidthFine", "fwidthFine"},
997                           IntrinsicData{"OpDPdxCoarse", "dpdxCoarse"},
998                           IntrinsicData{"OpDPdyCoarse", "dpdyCoarse"},
999                           IntrinsicData{"OpFwidthCoarse", "fwidthCoarse"}),
1000         ::testing::Values(
1001             ArgAndTypeData{"float", "float_50", "f32"},
1002             ArgAndTypeData{"v2float", "v2float_50_60", "vec2<f32>"},
1003             ArgAndTypeData{"v3float", "v3float_50_60_70", "vec3<f32>"})));
1004 
TEST_F(SpvUnaryArithTest,Transpose_2x2)1005 TEST_F(SpvUnaryArithTest, Transpose_2x2) {
1006   const auto assembly = Preamble() + R"(
1007      %100 = OpFunction %void None %voidfn
1008      %entry = OpLabel
1009      %1 = OpCopyObject %m2v2float %m2v2float_a
1010      %2 = OpTranspose %m2v2float %1
1011      OpReturn
1012      OpFunctionEnd
1013   )";
1014   auto p = parser(test::Assemble(assembly));
1015   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
1016       << p->error() << "\n"
1017       << assembly;
1018   auto fe = p->function_emitter(100);
1019   EXPECT_TRUE(fe.EmitBody()) << p->error();
1020   const auto* expected = "let x_2 : mat2x2<f32> = transpose(x_1);";
1021   auto ast_body = fe.ast_body();
1022   const auto got = test::ToString(p->program(), ast_body);
1023   EXPECT_THAT(got, HasSubstr(expected)) << got;
1024 }
1025 
TEST_F(SpvUnaryArithTest,Transpose_2x3)1026 TEST_F(SpvUnaryArithTest, Transpose_2x3) {
1027   const auto assembly = Preamble() + R"(
1028      %100 = OpFunction %void None %voidfn
1029      %entry = OpLabel
1030      %1 = OpCopyObject %m2v3float %m2v3float_a
1031      %2 = OpTranspose %m3v2float %1
1032      OpReturn
1033      OpFunctionEnd
1034   )";
1035   auto p = parser(test::Assemble(assembly));
1036   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
1037       << p->error() << "\n"
1038       << assembly;
1039   auto fe = p->function_emitter(100);
1040   EXPECT_TRUE(fe.EmitBody()) << p->error();
1041   // Note, in the AST dump mat_2_3 means 2 rows and 3 columns.
1042   // So the column vectors have 2 elements.
1043   // That is,   %m3v2float is __mat_2_3f32.
1044   const auto* expected = "let x_2 : mat3x2<f32> = transpose(x_1);";
1045   auto ast_body = fe.ast_body();
1046   const auto got = test::ToString(p->program(), ast_body);
1047   EXPECT_THAT(got, HasSubstr(expected)) << got;
1048 }
1049 
TEST_F(SpvUnaryArithTest,Transpose_3x2)1050 TEST_F(SpvUnaryArithTest, Transpose_3x2) {
1051   const auto assembly = Preamble() + R"(
1052      %100 = OpFunction %void None %voidfn
1053      %entry = OpLabel
1054      %1 = OpCopyObject %m3v2float %m3v2float_a
1055      %2 = OpTranspose %m2v3float %1
1056      OpReturn
1057      OpFunctionEnd
1058   )";
1059   auto p = parser(test::Assemble(assembly));
1060   ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
1061       << p->error() << "\n"
1062       << assembly;
1063   auto fe = p->function_emitter(100);
1064   EXPECT_TRUE(fe.EmitBody()) << p->error();
1065   const auto* expected = "let x_2 : mat2x3<f32> = transpose(x_1);";
1066   auto ast_body = fe.ast_body();
1067   const auto got = test::ToString(p->program(), ast_body);
1068   EXPECT_THAT(got, HasSubstr(expected)) << got;
1069 }
1070 
1071 // TODO(dneto): OpSRem. Missing from WGSL
1072 // https://github.com/gpuweb/gpuweb/issues/702
1073 
1074 // TODO(dneto): OpFRem. Missing from WGSL
1075 // https://github.com/gpuweb/gpuweb/issues/702
1076 
1077 // TODO(dneto): OpIAddCarry
1078 // TODO(dneto): OpISubBorrow
1079 // TODO(dneto): OpUMulExtended
1080 // TODO(dneto): OpSMulExtended
1081 
1082 }  // namespace
1083 }  // namespace spirv
1084 }  // namespace reader
1085 }  // namespace tint
1086