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