1 // Copyright 2020 The Tint Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "gmock/gmock.h"
16 #include "src/reader/spirv/function.h"
17 #include "src/reader/spirv/parser_impl_test_helper.h"
18 #include "src/reader/spirv/spirv_tools_helpers_test.h"
19
20 namespace tint {
21 namespace reader {
22 namespace spirv {
23 namespace {
24
25 using ::testing::Eq;
26 using ::testing::HasSubstr;
27
Preamble()28 std::string Preamble() {
29 return R"(
30 OpCapability Shader
31 OpMemoryModel Logical Simple
32 OpEntryPoint Fragment %100 "main"
33 OpExecutionMode %100 OriginUpperLeft
34 )";
35 }
36
CommonTypes()37 std::string CommonTypes() {
38 return R"(
39 %void = OpTypeVoid
40 %voidfn = OpTypeFunction %void
41
42 %bool = OpTypeBool
43 %uint = OpTypeInt 32 0
44 %int = OpTypeInt 32 1
45 %float = OpTypeFloat 32
46
47 %v2bool = OpTypeVector %bool 2
48 %v2uint = OpTypeVector %uint 2
49 %v2int = OpTypeVector %int 2
50 %v2float = OpTypeVector %float 2
51 )";
52 }
53
54 using SpvParserTestMiscInstruction = SpvParserTest;
55
TEST_F(SpvParserTestMiscInstruction,OpUndef_BeforeFunction_Scalar)56 TEST_F(SpvParserTestMiscInstruction, OpUndef_BeforeFunction_Scalar) {
57 const auto assembly = Preamble() + CommonTypes() + R"(
58 %1 = OpUndef %bool
59 %2 = OpUndef %uint
60 %3 = OpUndef %int
61 %4 = OpUndef %float
62
63 %100 = OpFunction %void None %voidfn
64 %entry = OpLabel
65 %11 = OpCopyObject %bool %1
66 %12 = OpCopyObject %uint %2
67 %13 = OpCopyObject %int %3
68 %14 = OpCopyObject %float %4
69 OpReturn
70 OpFunctionEnd
71 )";
72 auto p = parser(test::Assemble(assembly));
73 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
74 auto fe = p->function_emitter(100);
75 EXPECT_TRUE(fe.EmitBody()) << p->error();
76 auto ast_body = fe.ast_body();
77 EXPECT_THAT(test::ToString(p->program(), ast_body),
78 HasSubstr(R"(let x_11 : bool = false;
79 let x_12 : u32 = 0u;
80 let x_13 : i32 = 0;
81 let x_14 : f32 = 0.0;
82 )"));
83 }
84
TEST_F(SpvParserTestMiscInstruction,OpUndef_BeforeFunction_Vector)85 TEST_F(SpvParserTestMiscInstruction, OpUndef_BeforeFunction_Vector) {
86 const auto assembly = Preamble() + CommonTypes() + R"(
87 %4 = OpUndef %v2bool
88 %1 = OpUndef %v2uint
89 %2 = OpUndef %v2int
90 %3 = OpUndef %v2float
91
92 %100 = OpFunction %void None %voidfn
93 %entry = OpLabel
94
95 %14 = OpCopyObject %v2bool %4
96 %11 = OpCopyObject %v2uint %1
97 %12 = OpCopyObject %v2int %2
98 %13 = OpCopyObject %v2float %3
99 OpReturn
100 OpFunctionEnd
101 )";
102 auto p = parser(test::Assemble(assembly));
103 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
104 auto fe = p->function_emitter(100);
105 EXPECT_TRUE(fe.EmitBody()) << p->error();
106 auto ast_body = fe.ast_body();
107 EXPECT_THAT(test::ToString(p->program(), ast_body),
108 HasSubstr(R"(let x_14 : vec2<bool> = vec2<bool>(false, false);
109 let x_11 : vec2<u32> = vec2<u32>(0u, 0u);
110 let x_12 : vec2<i32> = vec2<i32>(0, 0);
111 let x_13 : vec2<f32> = vec2<f32>(0.0, 0.0);
112 )"));
113 }
114
TEST_F(SpvParserTestMiscInstruction,OpUndef_InFunction_Scalar)115 TEST_F(SpvParserTestMiscInstruction, OpUndef_InFunction_Scalar) {
116 const auto assembly = Preamble() + CommonTypes() + R"(
117 %100 = OpFunction %void None %voidfn
118 %entry = OpLabel
119 %1 = OpUndef %bool
120 %2 = OpUndef %uint
121 %3 = OpUndef %int
122 %4 = OpUndef %float
123
124 %11 = OpCopyObject %bool %1
125 %12 = OpCopyObject %uint %2
126 %13 = OpCopyObject %int %3
127 %14 = OpCopyObject %float %4
128 OpReturn
129 OpFunctionEnd
130 )";
131 auto p = parser(test::Assemble(assembly));
132 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
133 auto fe = p->function_emitter(100);
134 EXPECT_TRUE(fe.EmitBody()) << p->error();
135 auto ast_body = fe.ast_body();
136 EXPECT_THAT(test::ToString(p->program(), ast_body),
137 HasSubstr(R"(let x_11 : bool = false;
138 let x_12 : u32 = 0u;
139 let x_13 : i32 = 0;
140 let x_14 : f32 = 0.0;
141 )"));
142 }
143
TEST_F(SpvParserTestMiscInstruction,OpUndef_InFunction_Vector)144 TEST_F(SpvParserTestMiscInstruction, OpUndef_InFunction_Vector) {
145 const auto assembly = Preamble() + CommonTypes() + R"(
146 %100 = OpFunction %void None %voidfn
147 %entry = OpLabel
148 %1 = OpUndef %v2uint
149 %2 = OpUndef %v2int
150 %3 = OpUndef %v2float
151
152 %11 = OpCopyObject %v2uint %1
153 %12 = OpCopyObject %v2int %2
154 %13 = OpCopyObject %v2float %3
155 OpReturn
156 OpFunctionEnd
157 )";
158 auto p = parser(test::Assemble(assembly));
159 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
160 auto fe = p->function_emitter(100);
161 EXPECT_TRUE(fe.EmitBody()) << p->error();
162 auto ast_body = fe.ast_body();
163 EXPECT_THAT(test::ToString(p->program(), ast_body),
164 HasSubstr(R"(let x_11 : vec2<u32> = vec2<u32>(0u, 0u);
165 let x_12 : vec2<i32> = vec2<i32>(0, 0);
166 let x_13 : vec2<f32> = vec2<f32>(0.0, 0.0);
167 )"));
168 }
169
TEST_F(SpvParserTestMiscInstruction,OpUndef_InFunction_Matrix)170 TEST_F(SpvParserTestMiscInstruction, OpUndef_InFunction_Matrix) {
171 const auto assembly = Preamble() + CommonTypes() + R"(
172 %mat = OpTypeMatrix %v2float 2
173
174 %100 = OpFunction %void None %voidfn
175 %entry = OpLabel
176 %1 = OpUndef %mat
177
178 %11 = OpCopyObject %mat %1
179 OpReturn
180 OpFunctionEnd
181 )";
182 auto p = parser(test::Assemble(assembly));
183 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
184 auto fe = p->function_emitter(100);
185 EXPECT_TRUE(fe.EmitBody()) << p->error();
186 auto ast_body = fe.ast_body();
187 EXPECT_THAT(test::ToString(p->program(), ast_body),
188 HasSubstr("let x_11 : mat2x2<f32> = mat2x2<f32>("
189 "vec2<f32>(0.0, 0.0), "
190 "vec2<f32>(0.0, 0.0));"));
191 }
192
TEST_F(SpvParserTestMiscInstruction,OpUndef_InFunction_Array)193 TEST_F(SpvParserTestMiscInstruction, OpUndef_InFunction_Array) {
194 const auto assembly = Preamble() + CommonTypes() + R"(
195 %uint_2 = OpConstant %uint 2
196 %arr = OpTypeArray %uint %uint_2
197
198 %100 = OpFunction %void None %voidfn
199 %entry = OpLabel
200 %1 = OpUndef %arr
201
202 %11 = OpCopyObject %arr %1
203 OpReturn
204 OpFunctionEnd
205 )";
206 auto p = parser(test::Assemble(assembly));
207 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
208 auto fe = p->function_emitter(100);
209 EXPECT_TRUE(fe.EmitBody()) << p->error();
210 auto ast_body = fe.ast_body();
211 EXPECT_THAT(test::ToString(p->program(), ast_body),
212 HasSubstr("let x_11 : array<u32, 2u> = array<u32, 2u>(0u, 0u);"));
213 }
214
TEST_F(SpvParserTestMiscInstruction,OpUndef_InFunction_Struct)215 TEST_F(SpvParserTestMiscInstruction, OpUndef_InFunction_Struct) {
216 const auto assembly = Preamble() + CommonTypes() + R"(
217 %strct = OpTypeStruct %bool %uint %int %float
218
219 %100 = OpFunction %void None %voidfn
220 %entry = OpLabel
221 %1 = OpUndef %strct
222
223 %11 = OpCopyObject %strct %1
224 OpReturn
225 OpFunctionEnd
226 )";
227 auto p = parser(test::Assemble(assembly));
228 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
229 auto fe = p->function_emitter(100);
230 EXPECT_TRUE(fe.EmitBody()) << p->error();
231 auto ast_body = fe.ast_body();
232 EXPECT_THAT(test::ToString(p->program(), ast_body),
233 HasSubstr("let x_11 : S = S(false, 0u, 0, 0.0);"));
234 }
235
TEST_F(SpvParserTestMiscInstruction,OpNop)236 TEST_F(SpvParserTestMiscInstruction, OpNop) {
237 const auto assembly = Preamble() + CommonTypes() + R"(
238 %100 = OpFunction %void None %voidfn
239 %entry = OpLabel
240 OpNop
241 OpReturn
242 OpFunctionEnd
243 )";
244 auto p = parser(test::Assemble(assembly));
245 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
246 << p->error() << assembly;
247 auto fe = p->function_emitter(100);
248 EXPECT_TRUE(fe.EmitBody()) << p->error();
249 auto ast_body = fe.ast_body();
250 EXPECT_EQ(test::ToString(p->program(), ast_body), "return;\n");
251 }
252
253 // Test swizzle generation.
254
255 struct SwizzleCase {
256 uint32_t index;
257 std::string expected_expr;
258 std::string expected_error;
259 };
260 using SpvParserSwizzleTest =
261 SpvParserTestBase<::testing::TestWithParam<SwizzleCase>>;
262
TEST_P(SpvParserSwizzleTest,Sample)263 TEST_P(SpvParserSwizzleTest, Sample) {
264 // We need a function so we can get a FunctionEmitter.
265 const auto assembly = Preamble() + CommonTypes() + R"(
266 %100 = OpFunction %void None %voidfn
267 %entry = OpLabel
268 OpReturn
269 OpFunctionEnd
270 )";
271 auto p = parser(test::Assemble(assembly));
272 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
273 auto fe = p->function_emitter(100);
274
275 auto* result = fe.Swizzle(GetParam().index);
276 if (GetParam().expected_error.empty()) {
277 Program program(p->program());
278 EXPECT_TRUE(fe.success());
279 ASSERT_NE(result, nullptr);
280 auto got = test::ToString(program, result);
281 EXPECT_EQ(got, GetParam().expected_expr);
282 } else {
283 EXPECT_EQ(result, nullptr);
284 EXPECT_FALSE(fe.success());
285 EXPECT_EQ(p->error(), GetParam().expected_error);
286 }
287 }
288
289 INSTANTIATE_TEST_SUITE_P(
290 ValidIndex,
291 SpvParserSwizzleTest,
292 ::testing::ValuesIn(std::vector<SwizzleCase>{
293 {0, "x", ""},
294 {1, "y", ""},
295 {2, "z", ""},
296 {3, "w", ""},
297 {4, "", "vector component index is larger than 3: 4"},
298 {99999, "", "vector component index is larger than 3: 99999"}}));
299
TEST_F(SpvParserTest,ValueFromBlockNotInBlockOrder)300 TEST_F(SpvParserTest, ValueFromBlockNotInBlockOrder) {
301 // crbug.com/tint/804
302 const auto assembly = Preamble() + CommonTypes() + R"(
303 %float_42 = OpConstant %float 42.0
304 %cond = OpUndef %bool
305
306 %100 = OpFunction %void None %voidfn
307 %10 = OpLabel
308 OpBranch %30
309
310 ; unreachable
311 %20 = OpLabel
312 %499 = OpFAdd %float %float_42 %float_42
313 %500 = OpFAdd %float %499 %float_42
314 OpBranch %25
315
316 %25 = OpLabel
317 OpBranch %80
318
319
320 %30 = OpLabel
321 OpLoopMerge %90 %80 None
322 OpBranchConditional %cond %90 %40
323
324 %40 = OpLabel
325 OpBranch %90
326
327 %80 = OpLabel ; unreachable continue target
328 ; but "dominated" by %20 and %25
329 %81 = OpFMul %float %500 %float_42 ; %500 is defined in %20
330 OpBranch %30 ; backedge
331
332 %90 = OpLabel
333 OpReturn
334 OpFunctionEnd
335 )";
336 auto p = parser(test::Assemble(assembly));
337 ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
338 auto fe = p->function_emitter(100);
339 EXPECT_TRUE(fe.EmitBody()) << p->error();
340 auto ast_body = fe.ast_body();
341 const auto got = test::ToString(p->program(), ast_body);
342 EXPECT_THAT(got, HasSubstr("let x_81 : f32 = (0.0 * 42.0);"));
343 }
344
345 // TODO(dneto): OpSizeof : requires Kernel (OpenCL)
346
347 } // namespace
348 } // namespace spirv
349 } // namespace reader
350 } // namespace tint
351