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