1 // Copyright (c) 2016 Google Inc.
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 "source/opt/module.h"
16
17 #include <memory>
18 #include <vector>
19
20 #include "gmock/gmock.h"
21 #include "gtest/gtest.h"
22 #include "source/opt/build_module.h"
23 #include "spirv-tools/libspirv.hpp"
24 #include "test/opt/module_utils.h"
25
26 namespace spvtools {
27 namespace opt {
28 namespace {
29
30 using ::testing::Eq;
31 using spvtest::GetIdBound;
32
TEST(ModuleTest,SetIdBound)33 TEST(ModuleTest, SetIdBound) {
34 Module m;
35 // It's initialized to 0.
36 EXPECT_EQ(0u, GetIdBound(m));
37
38 m.SetIdBound(19);
39 EXPECT_EQ(19u, GetIdBound(m));
40
41 m.SetIdBound(102);
42 EXPECT_EQ(102u, GetIdBound(m));
43 }
44
45 // Returns an IRContext owning the module formed by assembling the given text,
46 // then loading the result.
BuildModule(std::string text)47 inline std::unique_ptr<IRContext> BuildModule(std::string text) {
48 return spvtools::BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
49 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
50 }
51
TEST(ModuleTest,ComputeIdBound)52 TEST(ModuleTest, ComputeIdBound) {
53 // Empty module case.
54 EXPECT_EQ(1u, BuildModule("")->module()->ComputeIdBound());
55 // Sensitive to result id
56 EXPECT_EQ(2u, BuildModule("%void = OpTypeVoid")->module()->ComputeIdBound());
57 // Sensitive to type id
58 EXPECT_EQ(1000u,
59 BuildModule("%a = OpTypeArray !999 3")->module()->ComputeIdBound());
60 // Sensitive to a regular Id parameter
61 EXPECT_EQ(2000u,
62 BuildModule("OpDecorate !1999 0")->module()->ComputeIdBound());
63 // Sensitive to a scope Id parameter.
64 EXPECT_EQ(3000u,
65 BuildModule("%f = OpFunction %void None %fntype %a = OpLabel "
66 "OpMemoryBarrier !2999 %b\n")
67 ->module()
68 ->ComputeIdBound());
69 // Sensitive to a semantics Id parameter
70 EXPECT_EQ(4000u,
71 BuildModule("%f = OpFunction %void None %fntype %a = OpLabel "
72 "OpMemoryBarrier %b !3999\n")
73 ->module()
74 ->ComputeIdBound());
75 }
76
TEST(ModuleTest,OstreamOperator)77 TEST(ModuleTest, OstreamOperator) {
78 const std::string text = R"(OpCapability Shader
79 OpCapability Linkage
80 OpMemoryModel Logical GLSL450
81 OpName %7 "restrict"
82 OpDecorate %8 Restrict
83 %9 = OpTypeVoid
84 %10 = OpTypeInt 32 0
85 %11 = OpTypeStruct %10 %10
86 %12 = OpTypePointer Function %10
87 %13 = OpTypePointer Function %11
88 %14 = OpConstant %10 0
89 %15 = OpConstant %10 1
90 %7 = OpTypeFunction %9
91 %1 = OpFunction %9 None %7
92 %2 = OpLabel
93 %8 = OpVariable %13 Function
94 %3 = OpAccessChain %12 %8 %14
95 %4 = OpLoad %10 %3
96 %5 = OpAccessChain %12 %8 %15
97 %6 = OpLoad %10 %5
98 OpReturn
99 OpFunctionEnd)";
100
101 std::string s;
102 std::ostringstream str(s);
103 str << *BuildModule(text)->module();
104 EXPECT_EQ(text, str.str());
105 }
106
TEST(ModuleTest,OstreamOperatorInt64)107 TEST(ModuleTest, OstreamOperatorInt64) {
108 const std::string text = R"(OpCapability Shader
109 OpCapability Linkage
110 OpCapability Int64
111 OpMemoryModel Logical GLSL450
112 OpName %7 "restrict"
113 OpDecorate %5 Restrict
114 %9 = OpTypeVoid
115 %10 = OpTypeInt 64 0
116 %11 = OpTypeStruct %10 %10
117 %12 = OpTypePointer Function %10
118 %13 = OpTypePointer Function %11
119 %14 = OpConstant %10 0
120 %15 = OpConstant %10 1
121 %16 = OpConstant %10 4294967297
122 %7 = OpTypeFunction %9
123 %1 = OpFunction %9 None %7
124 %2 = OpLabel
125 %5 = OpVariable %12 Function
126 %6 = OpLoad %10 %5
127 OpSelectionMerge %3 None
128 OpSwitch %6 %3 4294967297 %4
129 %4 = OpLabel
130 OpBranch %3
131 %3 = OpLabel
132 OpReturn
133 OpFunctionEnd)";
134
135 std::string s;
136 std::ostringstream str(s);
137 str << *BuildModule(text)->module();
138 EXPECT_EQ(text, str.str());
139 }
140
TEST(ModuleTest,IdBoundTestAtLimit)141 TEST(ModuleTest, IdBoundTestAtLimit) {
142 const std::string text = R"(
143 OpCapability Shader
144 OpCapability Linkage
145 OpMemoryModel Logical GLSL450
146 %1 = OpTypeVoid
147 %2 = OpTypeFunction %1
148 %3 = OpFunction %1 None %2
149 %4 = OpLabel
150 OpReturn
151 OpFunctionEnd)";
152
153 std::unique_ptr<IRContext> context = BuildModule(text);
154 uint32_t current_bound = context->module()->id_bound();
155 context->set_max_id_bound(current_bound);
156 uint32_t next_id_bound = context->module()->TakeNextIdBound();
157 EXPECT_EQ(next_id_bound, 0);
158 EXPECT_EQ(current_bound, context->module()->id_bound());
159 next_id_bound = context->module()->TakeNextIdBound();
160 EXPECT_EQ(next_id_bound, 0);
161 }
162
TEST(ModuleTest,IdBoundTestBelowLimit)163 TEST(ModuleTest, IdBoundTestBelowLimit) {
164 const std::string text = R"(
165 OpCapability Shader
166 OpCapability Linkage
167 OpMemoryModel Logical GLSL450
168 %1 = OpTypeVoid
169 %2 = OpTypeFunction %1
170 %3 = OpFunction %1 None %2
171 %4 = OpLabel
172 OpReturn
173 OpFunctionEnd)";
174
175 std::unique_ptr<IRContext> context = BuildModule(text);
176 uint32_t current_bound = context->module()->id_bound();
177 context->set_max_id_bound(current_bound + 100);
178 uint32_t next_id_bound = context->module()->TakeNextIdBound();
179 EXPECT_EQ(next_id_bound, current_bound);
180 EXPECT_EQ(current_bound + 1, context->module()->id_bound());
181 next_id_bound = context->module()->TakeNextIdBound();
182 EXPECT_EQ(next_id_bound, current_bound + 1);
183 }
184
TEST(ModuleTest,IdBoundTestNearLimit)185 TEST(ModuleTest, IdBoundTestNearLimit) {
186 const std::string text = R"(
187 OpCapability Shader
188 OpCapability Linkage
189 OpMemoryModel Logical GLSL450
190 %1 = OpTypeVoid
191 %2 = OpTypeFunction %1
192 %3 = OpFunction %1 None %2
193 %4 = OpLabel
194 OpReturn
195 OpFunctionEnd)";
196
197 std::unique_ptr<IRContext> context = BuildModule(text);
198 uint32_t current_bound = context->module()->id_bound();
199 context->set_max_id_bound(current_bound + 1);
200 uint32_t next_id_bound = context->module()->TakeNextIdBound();
201 EXPECT_EQ(next_id_bound, current_bound);
202 EXPECT_EQ(current_bound + 1, context->module()->id_bound());
203 next_id_bound = context->module()->TakeNextIdBound();
204 EXPECT_EQ(next_id_bound, 0);
205 }
206
TEST(ModuleTest,IdBoundTestUIntMax)207 TEST(ModuleTest, IdBoundTestUIntMax) {
208 const std::string text = R"(
209 OpCapability Shader
210 OpCapability Linkage
211 OpMemoryModel Logical GLSL450
212 %1 = OpTypeVoid
213 %2 = OpTypeFunction %1
214 %3 = OpFunction %1 None %2
215 %4294967294 = OpLabel ; ID is UINT_MAX-1
216 OpReturn
217 OpFunctionEnd)";
218
219 std::unique_ptr<IRContext> context = BuildModule(text);
220 uint32_t current_bound = context->module()->id_bound();
221
222 // Expecting |BuildModule| to preserve the numeric ids.
223 EXPECT_EQ(current_bound, std::numeric_limits<uint32_t>::max());
224
225 context->set_max_id_bound(current_bound);
226 uint32_t next_id_bound = context->module()->TakeNextIdBound();
227 EXPECT_EQ(next_id_bound, 0);
228 EXPECT_EQ(current_bound, context->module()->id_bound());
229 }
230
231 // Tests that "text" does not change when it is assembled, converted into a
232 // module, converted back to a binary, and then disassembled.
AssembleAndDisassemble(const std::string & text)233 void AssembleAndDisassemble(const std::string& text) {
234 std::unique_ptr<IRContext> context = BuildModule(text);
235 std::vector<uint32_t> binary;
236
237 context->module()->ToBinary(&binary, false);
238
239 SpirvTools tools(SPV_ENV_UNIVERSAL_1_1);
240 std::string s;
241 tools.Disassemble(binary, &s);
242 EXPECT_EQ(s, text);
243 }
244
TEST(ModuleTest,TrailingOpLine)245 TEST(ModuleTest, TrailingOpLine) {
246 const std::string text = R"(OpCapability Shader
247 OpCapability Linkage
248 OpMemoryModel Logical GLSL450
249 %5 = OpString "file.ext"
250 %void = OpTypeVoid
251 %2 = OpTypeFunction %void
252 %3 = OpFunction %void None %2
253 %4 = OpLabel
254 OpReturn
255 OpFunctionEnd
256 OpLine %5 1 0
257 )";
258
259 AssembleAndDisassemble(text);
260 }
261
TEST(ModuleTest,TrailingOpNoLine)262 TEST(ModuleTest, TrailingOpNoLine) {
263 const std::string text = R"(OpCapability Shader
264 OpCapability Linkage
265 OpMemoryModel Logical GLSL450
266 %void = OpTypeVoid
267 %2 = OpTypeFunction %void
268 %3 = OpFunction %void None %2
269 %4 = OpLabel
270 OpReturn
271 OpFunctionEnd
272 OpNoLine
273 )";
274
275 AssembleAndDisassemble(text);
276 }
277
TEST(ModuleTest,MulitpleTrailingOpLine)278 TEST(ModuleTest, MulitpleTrailingOpLine) {
279 const std::string text = R"(OpCapability Shader
280 OpCapability Linkage
281 OpMemoryModel Logical GLSL450
282 %5 = OpString "file.ext"
283 %void = OpTypeVoid
284 %2 = OpTypeFunction %void
285 %3 = OpFunction %void None %2
286 %4 = OpLabel
287 OpReturn
288 OpFunctionEnd
289 OpLine %5 1 0
290 OpNoLine
291 OpLine %5 1 1
292 )";
293
294 AssembleAndDisassemble(text);
295 }
296
TEST(ModuleTest,NonSemanticInfoIteration)297 TEST(ModuleTest, NonSemanticInfoIteration) {
298 const std::string text = R"(
299 OpCapability Shader
300 OpCapability Linkage
301 OpExtension "SPV_KHR_non_semantic_info"
302 %1 = OpExtInstImport "NonSemantic.Test"
303 OpMemoryModel Logical GLSL450
304 %2 = OpTypeVoid
305 %3 = OpTypeFunction %2
306 %4 = OpExtInst %2 %1 1
307 %5 = OpFunction %2 None %3
308 %6 = OpLabel
309 %7 = OpExtInst %2 %1 1
310 OpReturn
311 OpFunctionEnd
312 %8 = OpExtInst %2 %1 1
313 %9 = OpFunction %2 None %3
314 %10 = OpLabel
315 %11 = OpExtInst %2 %1 1
316 OpReturn
317 OpFunctionEnd
318 %12 = OpExtInst %2 %1 1
319 )";
320
321 std::unique_ptr<IRContext> context = BuildModule(text);
322 std::unordered_set<uint32_t> non_semantic_ids;
323 context->module()->ForEachInst(
324 [&non_semantic_ids](const Instruction* inst) {
325 if (inst->opcode() == spv::Op::OpExtInst) {
326 non_semantic_ids.insert(inst->result_id());
327 }
328 },
329 false);
330
331 EXPECT_EQ(1, non_semantic_ids.count(4));
332 EXPECT_EQ(1, non_semantic_ids.count(7));
333 EXPECT_EQ(1, non_semantic_ids.count(8));
334 EXPECT_EQ(1, non_semantic_ids.count(11));
335 EXPECT_EQ(1, non_semantic_ids.count(12));
336 }
337 } // namespace
338 } // namespace opt
339 } // namespace spvtools
340