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