• 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 "src/writer/spirv/spv_dump.h"
16 #include "src/writer/spirv/test_helper.h"
17 
18 namespace tint {
19 namespace writer {
20 namespace spirv {
21 namespace {
22 
23 using BuilderTest = TestHelper;
24 
TEST_F(BuilderTest,Assign_Var)25 TEST_F(BuilderTest, Assign_Var) {
26   auto* v = Global("var", ty.f32(), ast::StorageClass::kPrivate);
27 
28   auto* assign = Assign("var", 1.f);
29 
30   WrapInFunction(assign);
31 
32   spirv::Builder& b = Build();
33 
34   b.push_function(Function{});
35   EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
36   ASSERT_FALSE(b.has_error()) << b.error();
37 
38   EXPECT_TRUE(b.GenerateAssignStatement(assign)) << b.error();
39   EXPECT_FALSE(b.has_error());
40 
41   EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
42 %2 = OpTypePointer Private %3
43 %4 = OpConstantNull %3
44 %1 = OpVariable %2 Private %4
45 %5 = OpConstant %3 1
46 )");
47 
48   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
49             R"(OpStore %1 %5
50 )");
51 }
52 
TEST_F(BuilderTest,Assign_Var_OutsideFunction_IsError)53 TEST_F(BuilderTest, Assign_Var_OutsideFunction_IsError) {
54   auto* v = Global("var", ty.f32(), ast::StorageClass::kPrivate);
55 
56   auto* assign = Assign("var", Expr(1.f));
57 
58   WrapInFunction(assign);
59 
60   spirv::Builder& b = Build();
61 
62   EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
63   ASSERT_FALSE(b.has_error()) << b.error();
64 
65   EXPECT_FALSE(b.GenerateAssignStatement(assign)) << b.error();
66   EXPECT_TRUE(b.has_error());
67   EXPECT_EQ(b.error(),
68             "Internal error: trying to add SPIR-V instruction 62 outside a "
69             "function");
70 }
71 
TEST_F(BuilderTest,Assign_Var_ZeroConstructor)72 TEST_F(BuilderTest, Assign_Var_ZeroConstructor) {
73   auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
74 
75   auto* val = vec3<f32>();
76   auto* assign = Assign("var", val);
77 
78   WrapInFunction(assign);
79 
80   spirv::Builder& b = Build();
81 
82   b.push_function(Function{});
83   EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
84   ASSERT_FALSE(b.has_error()) << b.error();
85 
86   EXPECT_TRUE(b.GenerateAssignStatement(assign)) << b.error();
87   EXPECT_FALSE(b.has_error());
88 
89   EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
90 %3 = OpTypeVector %4 3
91 %2 = OpTypePointer Private %3
92 %5 = OpConstantNull %3
93 %1 = OpVariable %2 Private %5
94 )");
95 
96   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
97             R"(OpStore %1 %5
98 )");
99 }
100 
TEST_F(BuilderTest,Assign_Var_Complex_ConstructorWithExtract)101 TEST_F(BuilderTest, Assign_Var_Complex_ConstructorWithExtract) {
102   auto* init = vec3<f32>(vec2<f32>(1.f, 2.f), 3.f);
103 
104   auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
105 
106   auto* assign = Assign("var", init);
107 
108   WrapInFunction(assign);
109 
110   spirv::Builder& b = Build();
111 
112   b.push_function(Function{});
113   EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
114   ASSERT_FALSE(b.has_error()) << b.error();
115 
116   EXPECT_TRUE(b.GenerateAssignStatement(assign)) << b.error();
117   EXPECT_FALSE(b.has_error());
118 
119   EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
120 %3 = OpTypeVector %4 3
121 %2 = OpTypePointer Private %3
122 %5 = OpConstantNull %3
123 %1 = OpVariable %2 Private %5
124 %6 = OpTypeVector %4 2
125 %7 = OpConstant %4 1
126 %8 = OpConstant %4 2
127 %9 = OpConstantComposite %6 %7 %8
128 %12 = OpConstant %4 3
129 )");
130   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
131             R"(%10 = OpCompositeExtract %4 %9 0
132 %11 = OpCompositeExtract %4 %9 1
133 %13 = OpCompositeConstruct %3 %10 %11 %12
134 OpStore %1 %13
135 )");
136 }
137 
TEST_F(BuilderTest,Assign_Var_Complex_Constructor)138 TEST_F(BuilderTest, Assign_Var_Complex_Constructor) {
139   auto* init = vec3<f32>(1.f, 2.f, 3.f);
140 
141   auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
142 
143   auto* assign = Assign("var", init);
144 
145   WrapInFunction(assign);
146 
147   spirv::Builder& b = Build();
148 
149   b.push_function(Function{});
150   EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
151   ASSERT_FALSE(b.has_error()) << b.error();
152 
153   EXPECT_TRUE(b.GenerateAssignStatement(assign)) << b.error();
154   EXPECT_FALSE(b.has_error());
155 
156   EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
157 %3 = OpTypeVector %4 3
158 %2 = OpTypePointer Private %3
159 %5 = OpConstantNull %3
160 %1 = OpVariable %2 Private %5
161 %6 = OpConstant %4 1
162 %7 = OpConstant %4 2
163 %8 = OpConstant %4 3
164 %9 = OpConstantComposite %3 %6 %7 %8
165 )");
166   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
167             R"(OpStore %1 %9
168 )");
169 }
170 
TEST_F(BuilderTest,Assign_StructMember)171 TEST_F(BuilderTest, Assign_StructMember) {
172   // my_struct {
173   //   a : f32
174   //   b : f32
175   // }
176   // var ident : my_struct
177   // ident.b = 4.0;
178 
179   auto* s = Structure("my_struct", {
180                                        Member("a", ty.f32()),
181                                        Member("b", ty.f32()),
182                                    });
183 
184   auto* v = Var("ident", ty.Of(s));
185 
186   auto* assign = Assign(MemberAccessor("ident", "b"), Expr(4.f));
187 
188   WrapInFunction(v, assign);
189 
190   spirv::Builder& b = Build();
191 
192   b.push_function(Function{});
193   EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
194   ASSERT_FALSE(b.has_error()) << b.error();
195 
196   EXPECT_TRUE(b.GenerateAssignStatement(assign)) << b.error();
197   EXPECT_FALSE(b.has_error());
198 
199   EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
200 %3 = OpTypeStruct %4 %4
201 %2 = OpTypePointer Function %3
202 %1 = OpVariable %2 Function
203 %5 = OpTypeInt 32 0
204 %6 = OpConstant %5 1
205 %7 = OpTypePointer Function %4
206 %9 = OpConstant %4 4
207 )");
208 
209   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
210             R"(%8 = OpAccessChain %7 %1 %6
211 OpStore %8 %9
212 )");
213 }
214 
TEST_F(BuilderTest,Assign_Vector)215 TEST_F(BuilderTest, Assign_Vector) {
216   auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
217 
218   auto* val = vec3<f32>(1.f, 1.f, 3.f);
219   auto* assign = Assign("var", val);
220 
221   WrapInFunction(assign);
222 
223   spirv::Builder& b = Build();
224 
225   b.push_function(Function{});
226   EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
227   ASSERT_FALSE(b.has_error()) << b.error();
228 
229   EXPECT_TRUE(b.GenerateAssignStatement(assign)) << b.error();
230   EXPECT_FALSE(b.has_error());
231 
232   EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
233 %3 = OpTypeVector %4 3
234 %2 = OpTypePointer Private %3
235 %5 = OpConstantNull %3
236 %1 = OpVariable %2 Private %5
237 %6 = OpConstant %4 1
238 %7 = OpConstant %4 3
239 %8 = OpConstantComposite %3 %6 %6 %7
240 )");
241 
242   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
243             R"(OpStore %1 %8
244 )");
245 }
246 
TEST_F(BuilderTest,Assign_Vector_MemberByName)247 TEST_F(BuilderTest, Assign_Vector_MemberByName) {
248   // var.y = 1
249 
250   auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
251 
252   auto* assign = Assign(MemberAccessor("var", "y"), Expr(1.f));
253 
254   WrapInFunction(assign);
255 
256   spirv::Builder& b = Build();
257 
258   b.push_function(Function{});
259   EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
260   ASSERT_FALSE(b.has_error()) << b.error();
261 
262   EXPECT_TRUE(b.GenerateAssignStatement(assign)) << b.error();
263   EXPECT_FALSE(b.has_error());
264 
265   EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
266 %3 = OpTypeVector %4 3
267 %2 = OpTypePointer Private %3
268 %5 = OpConstantNull %3
269 %1 = OpVariable %2 Private %5
270 %6 = OpTypeInt 32 0
271 %7 = OpConstant %6 1
272 %8 = OpTypePointer Private %4
273 %10 = OpConstant %4 1
274 )");
275 
276   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
277             R"(%9 = OpAccessChain %8 %1 %7
278 OpStore %9 %10
279 )");
280 }
281 
TEST_F(BuilderTest,Assign_Vector_MemberByIndex)282 TEST_F(BuilderTest, Assign_Vector_MemberByIndex) {
283   // var[1] = 1
284 
285   auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
286 
287   auto* assign = Assign(IndexAccessor("var", 1), Expr(1.f));
288 
289   WrapInFunction(assign);
290 
291   spirv::Builder& b = Build();
292 
293   b.push_function(Function{});
294   EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
295   ASSERT_FALSE(b.has_error()) << b.error();
296 
297   EXPECT_TRUE(b.GenerateAssignStatement(assign)) << b.error();
298   EXPECT_FALSE(b.has_error());
299 
300   EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
301 %3 = OpTypeVector %4 3
302 %2 = OpTypePointer Private %3
303 %5 = OpConstantNull %3
304 %1 = OpVariable %2 Private %5
305 %6 = OpTypeInt 32 1
306 %7 = OpConstant %6 1
307 %8 = OpTypePointer Private %4
308 %10 = OpConstant %4 1
309 )");
310 
311   EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
312             R"(%9 = OpAccessChain %8 %1 %7
313 OpStore %9 %10
314 )");
315 }
316 
317 }  // namespace
318 }  // namespace spirv
319 }  // namespace writer
320 }  // namespace tint
321