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