• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Tint Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "gmock/gmock.h"
16 #include "src/reader/spirv/function.h"
17 #include "src/reader/spirv/parser_impl_test_helper.h"
18 #include "src/reader/spirv/spirv_tools_helpers_test.h"
19 
20 namespace tint {
21 namespace reader {
22 namespace spirv {
23 namespace {
24 
25 using ::testing::Eq;
26 using ::testing::HasSubstr;
27 
Preamble()28 std::string Preamble() {
29   return R"(
30    OpCapability Shader
31    OpMemoryModel Logical Simple
32    OpEntryPoint Fragment %100 "main"
33    OpExecutionMode %100 OriginUpperLeft
34 )";
35 }
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