blob: 9db49d9ced85d241ee2744abd4e1ff6f9974c339 [file] [log] [blame]
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001// 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/tint/reader/spirv/function.h"
17#include "src/tint/reader/spirv/parser_impl_test_helper.h"
18#include "src/tint/reader/spirv/spirv_tools_helpers_test.h"
19
dan sinclair258cbaf2022-04-07 19:01:25 +000020namespace tint::reader::spirv {
Ryan Harrisondbc13af2022-02-21 15:19:07 +000021namespace {
22
23using ::testing::HasSubstr;
24
25std::string Preamble() {
dan sinclair41e4d9a2022-05-01 14:40:55 +000026 return R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +000027 OpCapability Shader
28 OpMemoryModel Logical Simple
29 OpEntryPoint Fragment %100 "main"
30 OpExecutionMode %100 OriginUpperLeft
31
32 %void = OpTypeVoid
33 %voidfn = OpTypeFunction %void
34
35 %uint = OpTypeInt 32 0
36 %int = OpTypeInt 32 1
37 %float = OpTypeFloat 32
38
39 %uint_10 = OpConstant %uint 10
40 %uint_20 = OpConstant %uint 20
41 %int_30 = OpConstant %int 30
42 %int_40 = OpConstant %int 40
43 %float_50 = OpConstant %float 50
44 %float_60 = OpConstant %float 60
45 %float_70 = OpConstant %float 70
46
47 %ptr_uint = OpTypePointer Function %uint
48 %ptr_int = OpTypePointer Function %int
49 %ptr_float = OpTypePointer Function %float
50
51 %v2uint = OpTypeVector %uint 2
52 %v2int = OpTypeVector %int 2
53 %v2float = OpTypeVector %float 2
54 %v3float = OpTypeVector %float 3
55
56 %v2uint_10_20 = OpConstantComposite %v2uint %uint_10 %uint_20
57 %v2uint_20_10 = OpConstantComposite %v2uint %uint_20 %uint_10
58 %v2int_30_40 = OpConstantComposite %v2int %int_30 %int_40
59 %v2int_40_30 = OpConstantComposite %v2int %int_40 %int_30
60 %v2float_50_60 = OpConstantComposite %v2float %float_50 %float_60
61 %v2float_60_50 = OpConstantComposite %v2float %float_60 %float_50
62 %v3float_50_60_70 = OpConstantComposite %v3float %float_50 %float_60 %float_70
63 %v3float_60_70_50 = OpConstantComposite %v3float %float_60 %float_70 %float_50
64
65 %m2v2float = OpTypeMatrix %v2float 2
66 %m2v3float = OpTypeMatrix %v3float 2
67 %m3v2float = OpTypeMatrix %v2float 3
68 %m2v2float_a = OpConstantComposite %m2v2float %v2float_50_60 %v2float_60_50
69 %m2v2float_b = OpConstantComposite %m2v2float %v2float_60_50 %v2float_50_60
70 %m3v2float_a = OpConstantComposite %m3v2float %v2float_50_60 %v2float_60_50 %v2float_50_60
71 %m2v3float_a = OpConstantComposite %m2v3float %v3float_50_60_70 %v3float_60_70_50
72)";
73}
74
75// Returns the AST dump for a given SPIR-V assembly constant.
76std::string AstFor(std::string assembly) {
dan sinclair41e4d9a2022-05-01 14:40:55 +000077 if (assembly == "v2uint_10_20") {
78 return "vec2<u32>(10u, 20u)";
79 }
80 if (assembly == "v2uint_20_10") {
81 return "vec2<u32>(20u, 10u)";
82 }
83 if (assembly == "v2int_30_40") {
Ben Clayton06496d42022-05-04 22:25:19 +000084 return "vec2<i32>(30i, 40i)";
dan sinclair41e4d9a2022-05-01 14:40:55 +000085 }
86 if (assembly == "v2int_40_30") {
Ben Clayton06496d42022-05-04 22:25:19 +000087 return "vec2<i32>(40i, 30i)";
dan sinclair41e4d9a2022-05-01 14:40:55 +000088 }
89 if (assembly == "cast_int_v2uint_10_20") {
90 return "bitcast<vec2<i32>>(vec2<u32>(10u, 20u))";
91 }
92 if (assembly == "cast_uint_v2int_40_30") {
Ben Clayton06496d42022-05-04 22:25:19 +000093 return "bitcast<vec2<u32>>(vec2<i32>(40i, 30i))";
dan sinclair41e4d9a2022-05-01 14:40:55 +000094 }
95 if (assembly == "v2float_50_60") {
96 return "vec2<f32>(50.0, 60.0)";
97 }
98 if (assembly == "v2float_60_50") {
99 return "vec2<f32>(60.0, 50.0)";
100 }
101 return "bad case";
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000102}
103
104using SpvUnaryArithTest = SpvParserTestBase<::testing::Test>;
105
106TEST_F(SpvUnaryArithTest, SNegate_Int_Int) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000107 const auto assembly = Preamble() + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000108 %100 = OpFunction %void None %voidfn
109 %entry = OpLabel
110 %1 = OpSNegate %int %int_30
111 OpReturn
112 OpFunctionEnd
113 )";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000114 auto p = parser(test::Assemble(assembly));
115 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
116 auto fe = p->function_emitter(100);
117 EXPECT_TRUE(fe.EmitBody()) << p->error();
118 auto ast_body = fe.ast_body();
Ben Clayton06496d42022-05-04 22:25:19 +0000119 EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("let x_1 : i32 = -(30i);"));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000120}
121
122TEST_F(SpvUnaryArithTest, SNegate_Int_Uint) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000123 const auto assembly = Preamble() + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000124 %100 = OpFunction %void None %voidfn
125 %entry = OpLabel
126 %1 = OpSNegate %int %uint_10
127 OpReturn
128 OpFunctionEnd
129 )";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000130 auto p = parser(test::Assemble(assembly));
131 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
132 auto fe = p->function_emitter(100);
133 EXPECT_TRUE(fe.EmitBody()) << p->error();
134 auto ast_body = fe.ast_body();
135 EXPECT_THAT(test::ToString(p->program(), ast_body),
136 HasSubstr("let x_1 : i32 = -(bitcast<i32>(10u));"));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000137}
138
139TEST_F(SpvUnaryArithTest, SNegate_Uint_Int) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000140 const auto assembly = Preamble() + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000141 %100 = OpFunction %void None %voidfn
142 %entry = OpLabel
143 %1 = OpSNegate %uint %int_30
144 OpReturn
145 OpFunctionEnd
146 )";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000147 auto p = parser(test::Assemble(assembly));
148 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
149 auto fe = p->function_emitter(100);
150 EXPECT_TRUE(fe.EmitBody()) << p->error();
151 auto ast_body = fe.ast_body();
152 EXPECT_THAT(test::ToString(p->program(), ast_body),
Ben Clayton06496d42022-05-04 22:25:19 +0000153 HasSubstr("let x_1 : u32 = bitcast<u32>(-(30i));"));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000154}
155
156TEST_F(SpvUnaryArithTest, SNegate_Uint_Uint) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000157 const auto assembly = Preamble() + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000158 %100 = OpFunction %void None %voidfn
159 %entry = OpLabel
160 %1 = OpSNegate %uint %uint_10
161 OpReturn
162 OpFunctionEnd
163 )";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000164 auto p = parser(test::Assemble(assembly));
165 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
166 auto fe = p->function_emitter(100);
167 EXPECT_TRUE(fe.EmitBody()) << p->error();
168 auto ast_body = fe.ast_body();
169 EXPECT_THAT(test::ToString(p->program(), ast_body),
170 HasSubstr("let x_1 : u32 = bitcast<u32>(-(bitcast<i32>(10u)));"));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000171}
172
173TEST_F(SpvUnaryArithTest, SNegate_SignedVec_SignedVec) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000174 const auto assembly = Preamble() + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000175 %100 = OpFunction %void None %voidfn
176 %entry = OpLabel
177 %1 = OpSNegate %v2int %v2int_30_40
178 OpReturn
179 OpFunctionEnd
180 )";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000181 auto p = parser(test::Assemble(assembly));
182 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
183 auto fe = p->function_emitter(100);
184 EXPECT_TRUE(fe.EmitBody()) << p->error();
185 auto ast_body = fe.ast_body();
186 EXPECT_THAT(test::ToString(p->program(), ast_body),
Ben Clayton06496d42022-05-04 22:25:19 +0000187 HasSubstr("let x_1 : vec2<i32> = -(vec2<i32>(30i, 40i));"));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000188}
189
190TEST_F(SpvUnaryArithTest, SNegate_SignedVec_UnsignedVec) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000191 const auto assembly = Preamble() + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000192 %100 = OpFunction %void None %voidfn
193 %entry = OpLabel
194 %1 = OpSNegate %v2int %v2uint_10_20
195 OpReturn
196 OpFunctionEnd
197 )";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000198 auto p = parser(test::Assemble(assembly));
199 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
200 auto fe = p->function_emitter(100);
201 EXPECT_TRUE(fe.EmitBody()) << p->error();
202 auto ast_body = fe.ast_body();
203 EXPECT_THAT(test::ToString(p->program(), ast_body),
204 HasSubstr("let x_1 : vec2<i32> = -(bitcast<vec2<i32>>(vec2<u32>(10u, 20u)));"));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000205}
206
207TEST_F(SpvUnaryArithTest, SNegate_UnsignedVec_SignedVec) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000208 const auto assembly = Preamble() + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000209 %100 = OpFunction %void None %voidfn
210 %entry = OpLabel
211 %1 = OpSNegate %v2uint %v2int_30_40
212 OpReturn
213 OpFunctionEnd
214 )";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000215 auto p = parser(test::Assemble(assembly));
216 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
217 auto fe = p->function_emitter(100);
218 EXPECT_TRUE(fe.EmitBody()) << p->error();
219 auto ast_body = fe.ast_body();
220 EXPECT_THAT(test::ToString(p->program(), ast_body),
Ben Clayton06496d42022-05-04 22:25:19 +0000221 HasSubstr("let x_1 : vec2<u32> = bitcast<vec2<u32>>(-(vec2<i32>(30i, 40i)));"));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000222}
223
224TEST_F(SpvUnaryArithTest, SNegate_UnsignedVec_UnsignedVec) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000225 const auto assembly = Preamble() + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000226 %100 = OpFunction %void None %voidfn
227 %entry = OpLabel
228 %1 = OpSNegate %v2uint %v2uint_10_20
229 OpReturn
230 OpFunctionEnd
231 )";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000232 auto p = parser(test::Assemble(assembly));
233 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
234 auto fe = p->function_emitter(100);
235 EXPECT_TRUE(fe.EmitBody()) << p->error();
236 auto ast_body = fe.ast_body();
237 EXPECT_THAT(
238 test::ToString(p->program(), ast_body),
239 HasSubstr(
240 R"(let x_1 : vec2<u32> = bitcast<vec2<u32>>(-(bitcast<vec2<i32>>(vec2<u32>(10u, 20u))));)"));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000241}
242
243TEST_F(SpvUnaryArithTest, FNegate_Scalar) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000244 const auto assembly = Preamble() + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000245 %100 = OpFunction %void None %voidfn
246 %entry = OpLabel
247 %1 = OpFNegate %float %float_50
248 OpReturn
249 OpFunctionEnd
250 )";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000251 auto p = parser(test::Assemble(assembly));
252 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
253 auto fe = p->function_emitter(100);
254 EXPECT_TRUE(fe.EmitBody()) << p->error();
255 auto ast_body = fe.ast_body();
256 EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("let x_1 : f32 = -(50.0);"));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000257}
258
259TEST_F(SpvUnaryArithTest, FNegate_Vector) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000260 const auto assembly = Preamble() + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000261 %100 = OpFunction %void None %voidfn
262 %entry = OpLabel
263 %1 = OpFNegate %v2float %v2float_50_60
264 OpReturn
265 OpFunctionEnd
266 )";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000267 auto p = parser(test::Assemble(assembly));
268 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
269 auto fe = p->function_emitter(100);
270 EXPECT_TRUE(fe.EmitBody()) << p->error();
271 auto ast_body = fe.ast_body();
272 EXPECT_THAT(test::ToString(p->program(), ast_body),
273 HasSubstr("let x_1 : vec2<f32> = -(vec2<f32>(50.0, 60.0));"));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000274}
275
276struct BinaryData {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000277 const std::string res_type;
278 const std::string lhs;
279 const std::string op;
280 const std::string rhs;
281 const std::string ast_type;
282 const std::string ast_lhs;
283 const std::string ast_op;
284 const std::string ast_rhs;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000285};
286inline std::ostream& operator<<(std::ostream& out, BinaryData data) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000287 out << "BinaryData{" << data.res_type << "," << data.lhs << "," << data.op << "," << data.rhs
288 << "," << data.ast_type << "," << data.ast_lhs << "," << data.ast_op << "," << data.ast_rhs
289 << "}";
290 return out;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000291}
292
dan sinclair41e4d9a2022-05-01 14:40:55 +0000293using SpvBinaryArithTest = SpvParserTestBase<::testing::TestWithParam<BinaryData>>;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000294using SpvBinaryArithTestBasic = SpvParserTestBase<::testing::Test>;
295
296TEST_P(SpvBinaryArithTest, EmitExpression) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000297 const auto assembly = Preamble() + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000298 %100 = OpFunction %void None %voidfn
299 %entry = OpLabel
300 %1 = )" + GetParam().op +
dan sinclair41e4d9a2022-05-01 14:40:55 +0000301 " %" + GetParam().res_type + " %" + GetParam().lhs + " %" +
302 GetParam().rhs + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000303 OpReturn
304 OpFunctionEnd
305 )";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000306 auto p = parser(test::Assemble(assembly));
307 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
308 auto fe = p->function_emitter(100);
309 EXPECT_TRUE(fe.EmitBody()) << p->error();
310 std::ostringstream ss;
311 ss << "let x_1 : " << GetParam().ast_type << " = (" << GetParam().ast_lhs << " "
312 << GetParam().ast_op << " " << GetParam().ast_rhs << ");";
313 auto ast_body = fe.ast_body();
314 auto got = test::ToString(p->program(), ast_body);
315 EXPECT_THAT(got, HasSubstr(ss.str())) << "got:\n" << got << assembly;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000316}
317
318// Use this when the result might have extra bitcasts on the outside.
319struct BinaryDataGeneral {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000320 const std::string res_type;
321 const std::string lhs;
322 const std::string op;
323 const std::string rhs;
324 const std::string wgsl_type;
325 const std::string expected;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000326};
327inline std::ostream& operator<<(std::ostream& out, BinaryDataGeneral data) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000328 out << "BinaryDataGeneral{" << data.res_type << "," << data.lhs << "," << data.op << ","
329 << data.rhs << "," << data.wgsl_type << "," << data.expected << "}";
330 return out;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000331}
332
dan sinclair41e4d9a2022-05-01 14:40:55 +0000333using SpvBinaryArithGeneralTest = SpvParserTestBase<::testing::TestWithParam<BinaryDataGeneral>>;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000334
335TEST_P(SpvBinaryArithGeneralTest, EmitExpression) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000336 const auto assembly = Preamble() + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000337 %100 = OpFunction %void None %voidfn
338 %entry = OpLabel
339 %1 = )" + GetParam().op +
dan sinclair41e4d9a2022-05-01 14:40:55 +0000340 " %" + GetParam().res_type + " %" + GetParam().lhs + " %" +
341 GetParam().rhs + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000342 OpReturn
343 OpFunctionEnd
344 )";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000345 auto p = parser(test::Assemble(assembly));
346 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
347 auto fe = p->function_emitter(100);
348 EXPECT_TRUE(fe.EmitBody()) << p->error();
349 std::ostringstream ss;
350 ss << "let x_1 : " << GetParam().wgsl_type << " = " << GetParam().expected << ";";
351 auto ast_body = fe.ast_body();
352 auto got = test::ToString(p->program(), ast_body);
353 EXPECT_THAT(got, HasSubstr(ss.str())) << "got:\n" << got << assembly;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000354}
355
356INSTANTIATE_TEST_SUITE_P(
357 SpvParserTest_IAdd,
358 SpvBinaryArithTest,
359 ::testing::Values(
360 // Both uint
dan sinclair41e4d9a2022-05-01 14:40:55 +0000361 BinaryData{"uint", "uint_10", "OpIAdd", "uint_20", "u32", "10u", "+", "20u"}, // Both int
Ben Clayton06496d42022-05-04 22:25:19 +0000362 BinaryData{"int", "int_30", "OpIAdd", "int_40", "i32", "30i", "+", "40i"}, // Both v2uint
dan sinclair41e4d9a2022-05-01 14:40:55 +0000363 BinaryData{"v2uint", "v2uint_10_20", "OpIAdd", "v2uint_20_10", "vec2<u32>",
364 AstFor("v2uint_10_20"), "+", AstFor("v2uint_20_10")},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000365 // Both v2int
366 BinaryData{"v2int", "v2int_30_40", "OpIAdd", "v2int_40_30", "vec2<i32>",
367 AstFor("v2int_30_40"), "+", AstFor("v2int_40_30")}));
368
369INSTANTIATE_TEST_SUITE_P(
370 SpvParserTest_IAdd_MixedSignedness,
371 SpvBinaryArithGeneralTest,
372 ::testing::Values(
373 // Mixed, uint <- int uint
374 BinaryDataGeneral{"uint", "int_30", "OpIAdd", "uint_10", "u32",
Ben Clayton06496d42022-05-04 22:25:19 +0000375 "bitcast<u32>((30i + bitcast<i32>(10u)))"},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000376 // Mixed, int <- int uint
Ben Clayton06496d42022-05-04 22:25:19 +0000377 BinaryDataGeneral{"int", "int_30", "OpIAdd", "uint_10", "i32", "(30i + bitcast<i32>(10u))"},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000378 // Mixed, uint <- uint int
Ben Clayton06496d42022-05-04 22:25:19 +0000379 BinaryDataGeneral{"uint", "uint_10", "OpIAdd", "int_30", "u32",
380 "(10u + bitcast<u32>(30i))"},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000381 // Mixed, int <- uint uint
382 BinaryDataGeneral{"int", "uint_20", "OpIAdd", "uint_10", "i32",
383 "bitcast<i32>((20u + 10u))"},
384 // Mixed, returning v2uint
385 BinaryDataGeneral{
386 "v2uint", "v2int_30_40", "OpIAdd", "v2uint_10_20", "vec2<u32>",
Ben Clayton06496d42022-05-04 22:25:19 +0000387 R"(bitcast<vec2<u32>>((vec2<i32>(30i, 40i) + bitcast<vec2<i32>>(vec2<u32>(10u, 20u)))))"},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000388 // Mixed, returning v2int
389 BinaryDataGeneral{
390 "v2int", "v2uint_10_20", "OpIAdd", "v2int_40_30", "vec2<i32>",
Ben Clayton06496d42022-05-04 22:25:19 +0000391 R"(bitcast<vec2<i32>>((vec2<u32>(10u, 20u) + bitcast<vec2<u32>>(vec2<i32>(40i, 30i)))))"}));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000392
dan sinclair41e4d9a2022-05-01 14:40:55 +0000393INSTANTIATE_TEST_SUITE_P(SpvParserTest_FAdd,
394 SpvBinaryArithTest,
395 ::testing::Values(
396 // Scalar float
397 BinaryData{"float", "float_50", "OpFAdd", "float_60", "f32", "50.0",
398 "+", "60.0"}, // Vector float
399 BinaryData{"v2float", "v2float_50_60", "OpFAdd", "v2float_60_50",
400 "vec2<f32>", AstFor("v2float_50_60"), "+",
401 AstFor("v2float_60_50")}));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000402
403INSTANTIATE_TEST_SUITE_P(
404 SpvParserTest_ISub,
405 SpvBinaryArithTest,
406 ::testing::Values(
407 // Both uint
dan sinclair41e4d9a2022-05-01 14:40:55 +0000408 BinaryData{"uint", "uint_10", "OpISub", "uint_20", "u32", "10u", "-", "20u"}, // Both int
Ben Clayton06496d42022-05-04 22:25:19 +0000409 BinaryData{"int", "int_30", "OpISub", "int_40", "i32", "30i", "-", "40i"}, // Both v2uint
dan sinclair41e4d9a2022-05-01 14:40:55 +0000410 BinaryData{"v2uint", "v2uint_10_20", "OpISub", "v2uint_20_10", "vec2<u32>",
411 AstFor("v2uint_10_20"), "-", AstFor("v2uint_20_10")},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000412 // Both v2int
413 BinaryData{"v2int", "v2int_30_40", "OpISub", "v2int_40_30", "vec2<i32>",
414 AstFor("v2int_30_40"), "-", AstFor("v2int_40_30")}));
415
416INSTANTIATE_TEST_SUITE_P(
417 SpvParserTest_ISub_MixedSignedness,
418 SpvBinaryArithGeneralTest,
419 ::testing::Values(
420 // Mixed, uint <- int uint
421 BinaryDataGeneral{"uint", "int_30", "OpISub", "uint_10", "u32",
Ben Clayton06496d42022-05-04 22:25:19 +0000422 R"(bitcast<u32>((30i - bitcast<i32>(10u))))"},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000423 // Mixed, int <- int uint
Ben Clayton06496d42022-05-04 22:25:19 +0000424 BinaryDataGeneral{"int", "int_30", "OpISub", "uint_10", "i32", "(30i - bitcast<i32>(10u))"},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000425 // Mixed, uint <- uint int
Ben Clayton06496d42022-05-04 22:25:19 +0000426 BinaryDataGeneral{"uint", "uint_10", "OpISub", "int_30", "u32",
427 "(10u - bitcast<u32>(30i))"},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000428 // Mixed, int <- uint uint
429 BinaryDataGeneral{"int", "uint_20", "OpISub", "uint_10", "i32",
430 "bitcast<i32>((20u - 10u))"},
431 // Mixed, returning v2uint
432 BinaryDataGeneral{
433 "v2uint", "v2int_30_40", "OpISub", "v2uint_10_20", "vec2<u32>",
Ben Clayton06496d42022-05-04 22:25:19 +0000434 R"(bitcast<vec2<u32>>((vec2<i32>(30i, 40i) - bitcast<vec2<i32>>(vec2<u32>(10u, 20u)))))"},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000435 // Mixed, returning v2int
436 BinaryDataGeneral{
437 "v2int", "v2uint_10_20", "OpISub", "v2int_40_30", "vec2<i32>",
Ben Clayton06496d42022-05-04 22:25:19 +0000438 R"(bitcast<vec2<i32>>((vec2<u32>(10u, 20u) - bitcast<vec2<u32>>(vec2<i32>(40i, 30i)))))"}));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000439
dan sinclair41e4d9a2022-05-01 14:40:55 +0000440INSTANTIATE_TEST_SUITE_P(SpvParserTest_FSub,
441 SpvBinaryArithTest,
442 ::testing::Values(
443 // Scalar float
444 BinaryData{"float", "float_50", "OpFSub", "float_60", "f32", "50.0",
445 "-", "60.0"}, // Vector float
446 BinaryData{"v2float", "v2float_50_60", "OpFSub", "v2float_60_50",
447 "vec2<f32>", AstFor("v2float_50_60"), "-",
448 AstFor("v2float_60_50")}));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000449
450INSTANTIATE_TEST_SUITE_P(
451 SpvParserTest_IMul,
452 SpvBinaryArithTest,
453 ::testing::Values(
454 // Both uint
dan sinclair41e4d9a2022-05-01 14:40:55 +0000455 BinaryData{"uint", "uint_10", "OpIMul", "uint_20", "u32", "10u", "*", "20u"}, // Both int
Ben Clayton06496d42022-05-04 22:25:19 +0000456 BinaryData{"int", "int_30", "OpIMul", "int_40", "i32", "30i", "*", "40i"}, // Both v2uint
dan sinclair41e4d9a2022-05-01 14:40:55 +0000457 BinaryData{"v2uint", "v2uint_10_20", "OpIMul", "v2uint_20_10", "vec2<u32>",
458 AstFor("v2uint_10_20"), "*", AstFor("v2uint_20_10")},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000459 // Both v2int
460 BinaryData{"v2int", "v2int_30_40", "OpIMul", "v2int_40_30", "vec2<i32>",
461 AstFor("v2int_30_40"), "*", AstFor("v2int_40_30")}));
462
463INSTANTIATE_TEST_SUITE_P(
464 SpvParserTest_IMul_MixedSignedness,
465 SpvBinaryArithGeneralTest,
466 ::testing::Values(
467 // Mixed, uint <- int uint
468 BinaryDataGeneral{"uint", "int_30", "OpIMul", "uint_10", "u32",
Ben Clayton06496d42022-05-04 22:25:19 +0000469 "bitcast<u32>((30i * bitcast<i32>(10u)))"},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000470 // Mixed, int <- int uint
Ben Clayton06496d42022-05-04 22:25:19 +0000471 BinaryDataGeneral{"int", "int_30", "OpIMul", "uint_10", "i32", "(30i * bitcast<i32>(10u))"},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000472 // Mixed, uint <- uint int
Ben Clayton06496d42022-05-04 22:25:19 +0000473 BinaryDataGeneral{"uint", "uint_10", "OpIMul", "int_30", "u32",
474 "(10u * bitcast<u32>(30i))"},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000475 // Mixed, int <- uint uint
476 BinaryDataGeneral{"int", "uint_20", "OpIMul", "uint_10", "i32",
477 "bitcast<i32>((20u * 10u))"},
478 // Mixed, returning v2uint
479 BinaryDataGeneral{
480 "v2uint", "v2int_30_40", "OpIMul", "v2uint_10_20", "vec2<u32>",
Ben Clayton06496d42022-05-04 22:25:19 +0000481 R"(bitcast<vec2<u32>>((vec2<i32>(30i, 40i) * bitcast<vec2<i32>>(vec2<u32>(10u, 20u)))))"},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000482 // Mixed, returning v2int
483 BinaryDataGeneral{
484 "v2int", "v2uint_10_20", "OpIMul", "v2int_40_30", "vec2<i32>",
Ben Clayton06496d42022-05-04 22:25:19 +0000485 R"(bitcast<vec2<i32>>((vec2<u32>(10u, 20u) * bitcast<vec2<u32>>(vec2<i32>(40i, 30i)))))"}));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000486
dan sinclair41e4d9a2022-05-01 14:40:55 +0000487INSTANTIATE_TEST_SUITE_P(SpvParserTest_FMul,
488 SpvBinaryArithTest,
489 ::testing::Values(
490 // Scalar float
491 BinaryData{"float", "float_50", "OpFMul", "float_60", "f32", "50.0",
492 "*", "60.0"}, // Vector float
493 BinaryData{"v2float", "v2float_50_60", "OpFMul", "v2float_60_50",
494 "vec2<f32>", AstFor("v2float_50_60"), "*",
495 AstFor("v2float_60_50")}));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000496
dan sinclair41e4d9a2022-05-01 14:40:55 +0000497INSTANTIATE_TEST_SUITE_P(SpvParserTest_UDiv,
498 SpvBinaryArithTest,
499 ::testing::Values(
500 // Both uint
501 BinaryData{"uint", "uint_10", "OpUDiv", "uint_20", "u32", "10u", "/",
502 "20u"}, // Both v2uint
503 BinaryData{"v2uint", "v2uint_10_20", "OpUDiv", "v2uint_20_10",
504 "vec2<u32>", AstFor("v2uint_10_20"), "/",
505 AstFor("v2uint_20_10")}));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000506
507INSTANTIATE_TEST_SUITE_P(
508 SpvParserTest_SDiv,
509 SpvBinaryArithTest,
510 ::testing::Values(
511 // Both int
Ben Clayton06496d42022-05-04 22:25:19 +0000512 BinaryData{"int", "int_30", "OpSDiv", "int_40", "i32", "30i", "/", "40i"}, // Both v2int
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000513 BinaryData{"v2int", "v2int_30_40", "OpSDiv", "v2int_40_30", "vec2<i32>",
514 AstFor("v2int_30_40"), "/", AstFor("v2int_40_30")}));
515
516INSTANTIATE_TEST_SUITE_P(
517 SpvParserTest_SDiv_MixedSignednessOperands,
518 SpvBinaryArithTest,
519 ::testing::Values(
520 // Mixed, returning int, second arg uint
Ben Clayton06496d42022-05-04 22:25:19 +0000521 BinaryData{"int", "int_30", "OpSDiv", "uint_10", "i32", "30i", "/", "bitcast<i32>(10u)"},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000522 // Mixed, returning int, first arg uint
dan sinclair41e4d9a2022-05-01 14:40:55 +0000523 BinaryData{"int", "uint_10", "OpSDiv", "int_30", "i32", "bitcast<i32>(10u)", "/",
Ben Clayton06496d42022-05-04 22:25:19 +0000524 "30i"}, // Mixed, returning v2int, first arg v2uint
dan sinclair41e4d9a2022-05-01 14:40:55 +0000525 BinaryData{"v2int", "v2uint_10_20", "OpSDiv", "v2int_30_40", "vec2<i32>",
526 AstFor("cast_int_v2uint_10_20"), "/", AstFor("v2int_30_40")},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000527 // Mixed, returning v2int, second arg v2uint
dan sinclair41e4d9a2022-05-01 14:40:55 +0000528 BinaryData{"v2int", "v2int_30_40", "OpSDiv", "v2uint_10_20", "vec2<i32>",
529 AstFor("v2int_30_40"), "/", AstFor("cast_int_v2uint_10_20")}));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000530
531TEST_F(SpvBinaryArithTestBasic, SDiv_Scalar_UnsignedResult) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000532 // The WGSL signed division operator expects both operands to be signed
533 // and the result is signed as well.
534 // In this test SPIR-V demands an unsigned result, so we have to
535 // wrap the result with an as-cast.
536 const auto assembly = Preamble() + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000537 %100 = OpFunction %void None %voidfn
538 %entry = OpLabel
539 %1 = OpSDiv %uint %int_30 %int_40
540 OpReturn
541 OpFunctionEnd
542 )";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000543 auto p = parser(test::Assemble(assembly));
544 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
545 auto fe = p->function_emitter(100);
546 EXPECT_TRUE(fe.EmitBody()) << p->error();
547 auto ast_body = fe.ast_body();
548 EXPECT_THAT(test::ToString(p->program(), ast_body),
Ben Clayton06496d42022-05-04 22:25:19 +0000549 HasSubstr("let x_1 : u32 = bitcast<u32>((30i / 40i));"));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000550}
551
552TEST_F(SpvBinaryArithTestBasic, SDiv_Vector_UnsignedResult) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000553 // The WGSL signed division operator expects both operands to be signed
554 // and the result is signed as well.
555 // In this test SPIR-V demands an unsigned result, so we have to
556 // wrap the result with an as-cast.
557 const auto assembly = Preamble() + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000558 %100 = OpFunction %void None %voidfn
559 %entry = OpLabel
560 %1 = OpSDiv %v2uint %v2int_30_40 %v2int_40_30
561 OpReturn
562 OpFunctionEnd
563 )";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000564 auto p = parser(test::Assemble(assembly));
565 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
566 auto fe = p->function_emitter(100);
567 EXPECT_TRUE(fe.EmitBody()) << p->error();
568 auto ast_body = fe.ast_body();
569 EXPECT_THAT(
570 test::ToString(p->program(), ast_body),
571 HasSubstr(
Ben Clayton06496d42022-05-04 22:25:19 +0000572 R"(let x_1 : vec2<u32> = bitcast<vec2<u32>>((vec2<i32>(30i, 40i) / vec2<i32>(40i, 30i)));)"));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000573}
574
dan sinclair41e4d9a2022-05-01 14:40:55 +0000575INSTANTIATE_TEST_SUITE_P(SpvParserTest_FDiv,
576 SpvBinaryArithTest,
577 ::testing::Values(
578 // Scalar float
579 BinaryData{"float", "float_50", "OpFDiv", "float_60", "f32", "50.0",
580 "/", "60.0"}, // Vector float
581 BinaryData{"v2float", "v2float_50_60", "OpFDiv", "v2float_60_50",
582 "vec2<f32>", AstFor("v2float_50_60"), "/",
583 AstFor("v2float_60_50")}));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000584
dan sinclair41e4d9a2022-05-01 14:40:55 +0000585INSTANTIATE_TEST_SUITE_P(SpvParserTest_UMod,
586 SpvBinaryArithTest,
587 ::testing::Values(
588 // Both uint
589 BinaryData{"uint", "uint_10", "OpUMod", "uint_20", "u32", "10u", "%",
590 "20u"}, // Both v2uint
591 BinaryData{"v2uint", "v2uint_10_20", "OpUMod", "v2uint_20_10",
592 "vec2<u32>", AstFor("v2uint_10_20"), "%",
593 AstFor("v2uint_20_10")}));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000594
595// Currently WGSL is missing a mapping for OpSRem
596// https://github.com/gpuweb/gpuweb/issues/702
597
598INSTANTIATE_TEST_SUITE_P(
599 SpvParserTest_SMod,
600 SpvBinaryArithTest,
601 ::testing::Values(
602 // Both int
Ben Clayton06496d42022-05-04 22:25:19 +0000603 BinaryData{"int", "int_30", "OpSMod", "int_40", "i32", "30i", "%", "40i"}, // Both v2int
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000604 BinaryData{"v2int", "v2int_30_40", "OpSMod", "v2int_40_30", "vec2<i32>",
605 AstFor("v2int_30_40"), "%", AstFor("v2int_40_30")}));
606
607INSTANTIATE_TEST_SUITE_P(
608 SpvParserTest_SMod_MixedSignednessOperands,
609 SpvBinaryArithTest,
610 ::testing::Values(
611 // Mixed, returning int, second arg uint
Ben Clayton06496d42022-05-04 22:25:19 +0000612 BinaryData{"int", "int_30", "OpSMod", "uint_10", "i32", "30i", "%", "bitcast<i32>(10u)"},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000613 // Mixed, returning int, first arg uint
dan sinclair41e4d9a2022-05-01 14:40:55 +0000614 BinaryData{"int", "uint_10", "OpSMod", "int_30", "i32", "bitcast<i32>(10u)", "%",
Ben Clayton06496d42022-05-04 22:25:19 +0000615 "30i"}, // Mixed, returning v2int, first arg v2uint
dan sinclair41e4d9a2022-05-01 14:40:55 +0000616 BinaryData{"v2int", "v2uint_10_20", "OpSMod", "v2int_30_40", "vec2<i32>",
617 AstFor("cast_int_v2uint_10_20"), "%", AstFor("v2int_30_40")},
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000618 // Mixed, returning v2int, second arg v2uint
dan sinclair41e4d9a2022-05-01 14:40:55 +0000619 BinaryData{"v2int", "v2int_30_40", "OpSMod", "v2uint_10_20", "vec2<i32>",
620 AstFor("v2int_30_40"), "%", AstFor("cast_int_v2uint_10_20")}));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000621
622TEST_F(SpvBinaryArithTestBasic, SMod_Scalar_UnsignedResult) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000623 // The WGSL signed modulus operator expects both operands to be signed
624 // and the result is signed as well.
625 // In this test SPIR-V demands an unsigned result, so we have to
626 // wrap the result with an as-cast.
627 const auto assembly = Preamble() + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000628 %100 = OpFunction %void None %voidfn
629 %entry = OpLabel
630 %1 = OpSMod %uint %int_30 %int_40
631 OpReturn
632 OpFunctionEnd
633 )";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000634 auto p = parser(test::Assemble(assembly));
635 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
636 auto fe = p->function_emitter(100);
637 EXPECT_TRUE(fe.EmitBody()) << p->error();
638 auto ast_body = fe.ast_body();
639 EXPECT_THAT(test::ToString(p->program(), ast_body),
Ben Clayton06496d42022-05-04 22:25:19 +0000640 HasSubstr("let x_1 : u32 = bitcast<u32>((30i % 40i));"));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000641}
642
643TEST_F(SpvBinaryArithTestBasic, SMod_Vector_UnsignedResult) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000644 // The WGSL signed modulus operator expects both operands to be signed
645 // and the result is signed as well.
646 // In this test SPIR-V demands an unsigned result, so we have to
647 // wrap the result with an as-cast.
648 const auto assembly = Preamble() + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000649 %100 = OpFunction %void None %voidfn
650 %entry = OpLabel
651 %1 = OpSMod %v2uint %v2int_30_40 %v2int_40_30
652 OpReturn
653 OpFunctionEnd
654 )";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000655 auto p = parser(test::Assemble(assembly));
656 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
657 auto fe = p->function_emitter(100);
658 EXPECT_TRUE(fe.EmitBody()) << p->error();
659 auto ast_body = fe.ast_body();
660 EXPECT_THAT(
661 test::ToString(p->program(), ast_body),
662 HasSubstr(
Ben Clayton06496d42022-05-04 22:25:19 +0000663 R"(let x_1 : vec2<u32> = bitcast<vec2<u32>>((vec2<i32>(30i, 40i) % vec2<i32>(40i, 30i)));)"));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000664}
665
dan sinclair41e4d9a2022-05-01 14:40:55 +0000666INSTANTIATE_TEST_SUITE_P(SpvParserTest_FRem,
667 SpvBinaryArithTest,
668 ::testing::Values(
669 // Scalar float
670 BinaryData{"float", "float_50", "OpFRem", "float_60", "f32", "50.0",
671 "%", "60.0"}, // Vector float
672 BinaryData{"v2float", "v2float_50_60", "OpFRem", "v2float_60_50",
673 "vec2<f32>", AstFor("v2float_50_60"), "%",
674 AstFor("v2float_60_50")}));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000675
676TEST_F(SpvBinaryArithTestBasic, FMod_Scalar) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000677 const auto assembly = Preamble() + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000678 %100 = OpFunction %void None %voidfn
679 %entry = OpLabel
680 %1 = OpFMod %float %float_50 %float_60
681 OpReturn
682 OpFunctionEnd
683 )";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000684 auto p = parser(test::Assemble(assembly));
685 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
686 auto fe = p->function_emitter(100);
687 EXPECT_TRUE(fe.EmitBody()) << p->error();
688 auto ast_body = fe.ast_body();
689 EXPECT_THAT(test::ToString(p->program(), ast_body),
690 HasSubstr("let x_1 : f32 = (50.0 - (60.0 * floor((50.0 / 60.0))));"));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000691}
692
693TEST_F(SpvBinaryArithTestBasic, FMod_Vector) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000694 const auto assembly = Preamble() + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000695 %100 = OpFunction %void None %voidfn
696 %entry = OpLabel
697 %1 = OpFMod %v2float %v2float_50_60 %v2float_60_50
698 OpReturn
699 OpFunctionEnd
700 )";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000701 auto p = parser(test::Assemble(assembly));
702 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
703 auto fe = p->function_emitter(100);
704 EXPECT_TRUE(fe.EmitBody()) << p->error();
705 auto ast_body = fe.ast_body();
706 EXPECT_THAT(
707 test::ToString(p->program(), ast_body),
708 HasSubstr(
709 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)))));)"));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000710}
711
712TEST_F(SpvBinaryArithTestBasic, VectorTimesScalar) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000713 const auto assembly = Preamble() + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000714 %100 = OpFunction %void None %voidfn
715 %entry = OpLabel
716 %1 = OpCopyObject %v2float %v2float_50_60
717 %2 = OpCopyObject %float %float_50
718 %10 = OpVectorTimesScalar %v2float %1 %2
719 OpReturn
720 OpFunctionEnd
721)";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000722 auto p = parser(test::Assemble(assembly));
723 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
724 auto fe = p->function_emitter(100);
725 EXPECT_TRUE(fe.EmitBody()) << p->error();
726 auto ast_body = fe.ast_body();
727 EXPECT_THAT(test::ToString(p->program(), ast_body),
728 HasSubstr("let x_10 : vec2<f32> = (x_1 * x_2);"));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000729}
730
731TEST_F(SpvBinaryArithTestBasic, MatrixTimesScalar) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000732 const auto assembly = Preamble() + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000733 %100 = OpFunction %void None %voidfn
734 %entry = OpLabel
735 %1 = OpCopyObject %m2v2float %m2v2float_a
736 %2 = OpCopyObject %float %float_50
737 %10 = OpMatrixTimesScalar %m2v2float %1 %2
738 OpReturn
739 OpFunctionEnd
740)";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000741 auto p = parser(test::Assemble(assembly));
742 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
743 auto fe = p->function_emitter(100);
744 EXPECT_TRUE(fe.EmitBody()) << p->error();
745 auto ast_body = fe.ast_body();
746 EXPECT_THAT(test::ToString(p->program(), ast_body),
747 HasSubstr("let x_10 : mat2x2<f32> = (x_1 * x_2);"));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000748}
749
750TEST_F(SpvBinaryArithTestBasic, VectorTimesMatrix) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000751 const auto assembly = Preamble() + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000752 %100 = OpFunction %void None %voidfn
753 %entry = OpLabel
754 %1 = OpCopyObject %m2v2float %m2v2float_a
755 %2 = OpCopyObject %v2float %v2float_50_60
756 %10 = OpMatrixTimesVector %v2float %1 %2
757 OpReturn
758 OpFunctionEnd
759)";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000760 auto p = parser(test::Assemble(assembly));
761 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
762 auto fe = p->function_emitter(100);
763 EXPECT_TRUE(fe.EmitBody()) << p->error();
764 auto ast_body = fe.ast_body();
765 EXPECT_THAT(test::ToString(p->program(), ast_body),
766 HasSubstr("let x_10 : vec2<f32> = (x_1 * x_2);"));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000767}
768
769TEST_F(SpvBinaryArithTestBasic, MatrixTimesVector) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000770 const auto assembly = Preamble() + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000771 %100 = OpFunction %void None %voidfn
772 %entry = OpLabel
773 %1 = OpCopyObject %m2v2float %m2v2float_a
774 %2 = OpCopyObject %v2float %v2float_50_60
775 %10 = OpMatrixTimesVector %v2float %1 %2
776 OpReturn
777 OpFunctionEnd
778)";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000779 auto p = parser(test::Assemble(assembly));
780 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
781 auto fe = p->function_emitter(100);
782 EXPECT_TRUE(fe.EmitBody()) << p->error();
783 auto ast_body = fe.ast_body();
784 EXPECT_THAT(test::ToString(p->program(), ast_body),
785 HasSubstr("let x_10 : vec2<f32> = (x_1 * x_2);"));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000786}
787
788TEST_F(SpvBinaryArithTestBasic, MatrixTimesMatrix) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000789 const auto assembly = Preamble() + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000790 %100 = OpFunction %void None %voidfn
791 %entry = OpLabel
792 %1 = OpCopyObject %m2v2float %m2v2float_a
793 %2 = OpCopyObject %m2v2float %m2v2float_b
794 %10 = OpMatrixTimesMatrix %m2v2float %1 %2
795 OpReturn
796 OpFunctionEnd
797)";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000798 auto p = parser(test::Assemble(assembly));
799 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
800 auto fe = p->function_emitter(100);
801 EXPECT_TRUE(fe.EmitBody()) << p->error();
802 auto ast_body = fe.ast_body();
803 EXPECT_THAT(test::ToString(p->program(), ast_body),
804 HasSubstr("let x_10 : mat2x2<f32> = (x_1 * x_2);"));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000805}
806
807TEST_F(SpvBinaryArithTestBasic, Dot) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000808 const auto assembly = Preamble() + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000809 %100 = OpFunction %void None %voidfn
810 %entry = OpLabel
811 %1 = OpCopyObject %v2float %v2float_50_60
812 %2 = OpCopyObject %v2float %v2float_60_50
813 %3 = OpDot %float %1 %2
814 OpReturn
815 OpFunctionEnd
816)";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000817 auto p = parser(test::Assemble(assembly));
818 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
819 auto fe = p->function_emitter(100);
820 EXPECT_TRUE(fe.EmitBody()) << p->error();
821 auto ast_body = fe.ast_body();
822 EXPECT_THAT(test::ToString(p->program(), ast_body),
823 HasSubstr("let x_3 : f32 = dot(x_1, x_2);"));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000824}
825
826TEST_F(SpvBinaryArithTestBasic, OuterProduct) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000827 // OpOuterProduct is expanded to basic operations.
828 // The operands, even if used once, are given their own const definitions.
829 const auto assembly = Preamble() + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000830 %100 = OpFunction %void None %voidfn
831 %entry = OpLabel
832 %1 = OpFAdd %v3float %v3float_50_60_70 %v3float_50_60_70 ; column vector
833 %2 = OpFAdd %v2float %v2float_60_50 %v2float_50_60 ; row vector
834 %3 = OpOuterProduct %m2v3float %1 %2
835 OpReturn
836 OpFunctionEnd
837)";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000838 auto p = parser(test::Assemble(assembly));
839 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
840 auto fe = p->function_emitter(100);
841 EXPECT_TRUE(fe.EmitBody()) << p->error();
842 auto ast_body = fe.ast_body();
843 auto got = test::ToString(p->program(), ast_body);
844 EXPECT_THAT(got, HasSubstr("let x_3 : mat2x3<f32> = mat2x3<f32>("
845 "vec3<f32>((x_2.x * x_1.x), (x_2.x * x_1.y), (x_2.x * x_1.z)), "
846 "vec3<f32>((x_2.y * x_1.x), (x_2.y * x_1.y), (x_2.y * x_1.z)));"))
847 << got;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000848}
849
850struct BuiltinData {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000851 const std::string spirv;
852 const std::string wgsl;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000853};
854inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000855 out << "OpData{" << data.spirv << "," << data.wgsl << "}";
856 return out;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000857}
858struct ArgAndTypeData {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000859 const std::string spirv_type;
860 const std::string spirv_arg;
861 const std::string ast_type;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000862};
863inline std::ostream& operator<<(std::ostream& out, ArgAndTypeData data) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000864 out << "ArgAndTypeData{" << data.spirv_type << "," << data.spirv_arg << "," << data.ast_type
865 << "}";
866 return out;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000867}
868
dan sinclair41e4d9a2022-05-01 14:40:55 +0000869using SpvBinaryDerivativeTest =
870 SpvParserTestBase<::testing::TestWithParam<std::tuple<BuiltinData, ArgAndTypeData>>>;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000871
872TEST_P(SpvBinaryDerivativeTest, Derivatives) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000873 auto& builtin = std::get<0>(GetParam());
874 auto& arg = std::get<1>(GetParam());
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000875
dan sinclair41e4d9a2022-05-01 14:40:55 +0000876 const auto assembly = R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000877 OpCapability DerivativeControl
878)" + Preamble() + R"(
879 %100 = OpFunction %void None %voidfn
880 %entry = OpLabel
881 %1 = OpCopyObject %)" +
dan sinclair41e4d9a2022-05-01 14:40:55 +0000882 arg.spirv_type + " %" + arg.spirv_arg + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000883 %2 = )" + builtin.spirv +
dan sinclair41e4d9a2022-05-01 14:40:55 +0000884 " %" + arg.spirv_type + R"( %1
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000885 OpReturn
886 OpFunctionEnd
887)";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000888 auto p = parser(test::Assemble(assembly));
889 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
890 auto fe = p->function_emitter(100);
891 EXPECT_TRUE(fe.EmitBody()) << p->error();
892 auto ast_body = fe.ast_body();
893 EXPECT_THAT(test::ToString(p->program(), ast_body),
894 HasSubstr("let x_2 : " + arg.ast_type + " = " + builtin.wgsl + "(x_1);"));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000895}
896
897INSTANTIATE_TEST_SUITE_P(
898 SpvBinaryDerivativeTest,
899 SpvBinaryDerivativeTest,
dan sinclair41e4d9a2022-05-01 14:40:55 +0000900 testing::Combine(::testing::Values(BuiltinData{"OpDPdx", "dpdx"},
901 BuiltinData{"OpDPdy", "dpdy"},
902 BuiltinData{"OpFwidth", "fwidth"},
903 BuiltinData{"OpDPdxFine", "dpdxFine"},
904 BuiltinData{"OpDPdyFine", "dpdyFine"},
905 BuiltinData{"OpFwidthFine", "fwidthFine"},
906 BuiltinData{"OpDPdxCoarse", "dpdxCoarse"},
907 BuiltinData{"OpDPdyCoarse", "dpdyCoarse"},
908 BuiltinData{"OpFwidthCoarse", "fwidthCoarse"}),
909 ::testing::Values(ArgAndTypeData{"float", "float_50", "f32"},
910 ArgAndTypeData{"v2float", "v2float_50_60", "vec2<f32>"},
911 ArgAndTypeData{"v3float", "v3float_50_60_70",
912 "vec3<f32>"})));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000913
914TEST_F(SpvUnaryArithTest, Transpose_2x2) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000915 const auto assembly = Preamble() + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000916 %100 = OpFunction %void None %voidfn
917 %entry = OpLabel
918 %1 = OpCopyObject %m2v2float %m2v2float_a
919 %2 = OpTranspose %m2v2float %1
920 OpReturn
921 OpFunctionEnd
922 )";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000923 auto p = parser(test::Assemble(assembly));
924 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
925 auto fe = p->function_emitter(100);
926 EXPECT_TRUE(fe.EmitBody()) << p->error();
927 const auto* expected = "let x_2 : mat2x2<f32> = transpose(x_1);";
928 auto ast_body = fe.ast_body();
929 const auto got = test::ToString(p->program(), ast_body);
930 EXPECT_THAT(got, HasSubstr(expected)) << got;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000931}
932
933TEST_F(SpvUnaryArithTest, Transpose_2x3) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000934 const auto assembly = Preamble() + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000935 %100 = OpFunction %void None %voidfn
936 %entry = OpLabel
937 %1 = OpCopyObject %m2v3float %m2v3float_a
938 %2 = OpTranspose %m3v2float %1
939 OpReturn
940 OpFunctionEnd
941 )";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000942 auto p = parser(test::Assemble(assembly));
943 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
944 auto fe = p->function_emitter(100);
945 EXPECT_TRUE(fe.EmitBody()) << p->error();
946 // Note, in the AST dump mat_2_3 means 2 rows and 3 columns.
947 // So the column vectors have 2 elements.
948 // That is, %m3v2float is __mat_2_3f32.
949 const auto* expected = "let x_2 : mat3x2<f32> = transpose(x_1);";
950 auto ast_body = fe.ast_body();
951 const auto got = test::ToString(p->program(), ast_body);
952 EXPECT_THAT(got, HasSubstr(expected)) << got;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000953}
954
955TEST_F(SpvUnaryArithTest, Transpose_3x2) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000956 const auto assembly = Preamble() + R"(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000957 %100 = OpFunction %void None %voidfn
958 %entry = OpLabel
959 %1 = OpCopyObject %m3v2float %m3v2float_a
960 %2 = OpTranspose %m2v3float %1
961 OpReturn
962 OpFunctionEnd
963 )";
dan sinclair41e4d9a2022-05-01 14:40:55 +0000964 auto p = parser(test::Assemble(assembly));
965 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
966 auto fe = p->function_emitter(100);
967 EXPECT_TRUE(fe.EmitBody()) << p->error();
968 const auto* expected = "let x_2 : mat2x3<f32> = transpose(x_1);";
969 auto ast_body = fe.ast_body();
970 const auto got = test::ToString(p->program(), ast_body);
971 EXPECT_THAT(got, HasSubstr(expected)) << got;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000972}
973
974// TODO(dneto): OpSRem. Missing from WGSL
975// https://github.com/gpuweb/gpuweb/issues/702
976
977// TODO(dneto): OpFRem. Missing from WGSL
978// https://github.com/gpuweb/gpuweb/issues/702
979
980// TODO(dneto): OpIAddCarry
981// TODO(dneto): OpISubBorrow
982// TODO(dneto): OpUMulExtended
983// TODO(dneto): OpSMulExtended
984
985} // namespace
dan sinclair258cbaf2022-04-07 19:01:25 +0000986} // namespace tint::reader::spirv