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,FunctionVar_NoStorageClass)25 TEST_F(BuilderTest, FunctionVar_NoStorageClass) {
26 auto* v = Var("var", ty.f32(), ast::StorageClass::kFunction);
27 WrapInFunction(v);
28
29 spirv::Builder& b = Build();
30
31 b.push_function(Function{});
32 EXPECT_TRUE(b.GenerateFunctionVariable(v)) << b.error();
33 EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var"
34 )");
35 EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
36 %2 = OpTypePointer Function %3
37 %4 = OpConstantNull %3
38 )");
39
40 const auto& func = b.functions()[0];
41 EXPECT_EQ(DumpInstructions(func.variables()),
42 R"(%1 = OpVariable %2 Function %4
43 )");
44 }
45
TEST_F(BuilderTest,FunctionVar_WithConstantConstructor)46 TEST_F(BuilderTest, FunctionVar_WithConstantConstructor) {
47 auto* init = vec3<f32>(1.f, 1.f, 3.f);
48 auto* v = Var("var", ty.vec3<f32>(), ast::StorageClass::kFunction, init);
49 WrapInFunction(v);
50
51 spirv::Builder& b = Build();
52
53 b.push_function(Function{});
54 EXPECT_TRUE(b.GenerateFunctionVariable(v)) << b.error();
55 ASSERT_FALSE(b.has_error()) << b.error();
56
57 EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %6 "var"
58 )");
59 EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
60 %1 = OpTypeVector %2 3
61 %3 = OpConstant %2 1
62 %4 = OpConstant %2 3
63 %5 = OpConstantComposite %1 %3 %3 %4
64 %7 = OpTypePointer Function %1
65 %8 = OpConstantNull %1
66 )");
67 EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
68 R"(%6 = OpVariable %7 Function %8
69 )");
70 EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
71 R"(OpStore %6 %5
72 )");
73 }
74
TEST_F(BuilderTest,FunctionVar_WithNonConstantConstructor)75 TEST_F(BuilderTest, FunctionVar_WithNonConstantConstructor) {
76 auto* init = vec2<f32>(1.f, Add(3.f, 3.f));
77
78 auto* v = Var("var", ty.vec2<f32>(), ast::StorageClass::kNone, init);
79 WrapInFunction(v);
80
81 spirv::Builder& b = Build();
82
83 b.push_function(Function{});
84 EXPECT_TRUE(b.GenerateFunctionVariable(v)) << b.error();
85 ASSERT_FALSE(b.has_error()) << b.error();
86
87 EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %7 "var"
88 )");
89 EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
90 %1 = OpTypeVector %2 2
91 %3 = OpConstant %2 1
92 %4 = OpConstant %2 3
93 %8 = OpTypePointer Function %1
94 %9 = OpConstantNull %1
95 )");
96 EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
97 R"(%7 = OpVariable %8 Function %9
98 )");
99 EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
100 R"(%5 = OpFAdd %2 %4 %4
101 %6 = OpCompositeConstruct %1 %3 %5
102 OpStore %7 %6
103 )");
104 }
105
TEST_F(BuilderTest,FunctionVar_WithNonConstantConstructorLoadedFromVar)106 TEST_F(BuilderTest, FunctionVar_WithNonConstantConstructorLoadedFromVar) {
107 // var v : f32 = 1.0;
108 // var v2 : f32 = v; // Should generate the load and store automatically.
109
110 auto* v = Var("v", ty.f32(), ast::StorageClass::kNone, Expr(1.f));
111
112 auto* v2 = Var("v2", ty.f32(), ast::StorageClass::kNone, Expr("v"));
113 WrapInFunction(v, v2);
114
115 spirv::Builder& b = Build();
116
117 b.push_function(Function{});
118 EXPECT_TRUE(b.GenerateFunctionVariable(v)) << b.error();
119 EXPECT_TRUE(b.GenerateFunctionVariable(v2)) << b.error();
120 ASSERT_FALSE(b.has_error()) << b.error();
121
122 EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %3 "v"
123 OpName %7 "v2"
124 )");
125 EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
126 %2 = OpConstant %1 1
127 %4 = OpTypePointer Function %1
128 %5 = OpConstantNull %1
129 )");
130 EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
131 R"(%3 = OpVariable %4 Function %5
132 %7 = OpVariable %4 Function %5
133 )");
134 EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
135 R"(OpStore %3 %2
136 %6 = OpLoad %1 %3
137 OpStore %7 %6
138 )");
139 }
140
TEST_F(BuilderTest,FunctionVar_ConstWithVarInitializer)141 TEST_F(BuilderTest, FunctionVar_ConstWithVarInitializer) {
142 // var v : f32 = 1.0;
143 // let v2 : f32 = v; // Should generate the load
144
145 auto* v = Var("v", ty.f32(), ast::StorageClass::kNone, Expr(1.f));
146
147 auto* v2 = Var("v2", ty.f32(), ast::StorageClass::kNone, Expr("v"));
148 WrapInFunction(v, v2);
149
150 spirv::Builder& b = Build();
151
152 b.push_function(Function{});
153 EXPECT_TRUE(b.GenerateFunctionVariable(v)) << b.error();
154 EXPECT_TRUE(b.GenerateFunctionVariable(v2)) << b.error();
155 ASSERT_FALSE(b.has_error()) << b.error();
156
157 EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %3 "v"
158 OpName %7 "v2"
159 )");
160 EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
161 %2 = OpConstant %1 1
162 %4 = OpTypePointer Function %1
163 %5 = OpConstantNull %1
164 )");
165 EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
166 R"(%3 = OpVariable %4 Function %5
167 %7 = OpVariable %4 Function %5
168 )");
169 EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
170 R"(OpStore %3 %2
171 %6 = OpLoad %1 %3
172 OpStore %7 %6
173 )");
174 }
175
TEST_F(BuilderTest,FunctionVar_Const)176 TEST_F(BuilderTest, FunctionVar_Const) {
177 auto* init = vec3<f32>(1.f, 1.f, 3.f);
178
179 auto* v = Const("var", ty.vec3<f32>(), init);
180
181 WrapInFunction(v);
182
183 spirv::Builder& b = Build();
184
185 EXPECT_TRUE(b.GenerateFunctionVariable(v)) << b.error();
186 ASSERT_FALSE(b.has_error()) << b.error();
187
188 EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
189 %1 = OpTypeVector %2 3
190 %3 = OpConstant %2 1
191 %4 = OpConstant %2 3
192 %5 = OpConstantComposite %1 %3 %3 %4
193 )");
194 }
195
196 } // namespace
197 } // namespace spirv
198 } // namespace writer
199 } // namespace tint
200