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 "spirv-tools/libspirv.hpp"
25 #include "test/opt/module_utils.h"
26 
27 namespace spvtools {
28 namespace opt {
29 namespace {
30 
31 using ::testing::Eq;
32 using spvtest::GetIdBound;
33 
TEST(ModuleTest,SetIdBound)34 TEST(ModuleTest, SetIdBound) {
35   Module m;
36   // It's initialized to 0.
37   EXPECT_EQ(0u, GetIdBound(m));
38 
39   m.SetIdBound(19);
40   EXPECT_EQ(19u, GetIdBound(m));
41 
42   m.SetIdBound(102);
43   EXPECT_EQ(102u, GetIdBound(m));
44 }
45 
46 // Returns an IRContext owning the module formed by assembling the given text,
47 // then loading the result.
BuildModule(std::string text)48 inline std::unique_ptr<IRContext> BuildModule(std::string text) {
49   return spvtools::BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
50                                SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
51 }
52 
TEST(ModuleTest,ComputeIdBound)53 TEST(ModuleTest, ComputeIdBound) {
54   // Emtpy module case.
55   EXPECT_EQ(1u, BuildModule("")->module()->ComputeIdBound());
56   // Sensitive to result id
57   EXPECT_EQ(2u, BuildModule("%void = OpTypeVoid")->module()->ComputeIdBound());
58   // Sensitive to type id
59   EXPECT_EQ(1000u,
60             BuildModule("%a = OpTypeArray !999 3")->module()->ComputeIdBound());
61   // Sensitive to a regular Id parameter
62   EXPECT_EQ(2000u,
63             BuildModule("OpDecorate !1999 0")->module()->ComputeIdBound());
64   // Sensitive to a scope Id parameter.
65   EXPECT_EQ(3000u,
66             BuildModule("%f = OpFunction %void None %fntype %a = OpLabel "
67                         "OpMemoryBarrier !2999 %b\n")
68                 ->module()
69                 ->ComputeIdBound());
70   // Sensitive to a semantics Id parameter
71   EXPECT_EQ(4000u,
72             BuildModule("%f = OpFunction %void None %fntype %a = OpLabel "
73                         "OpMemoryBarrier %b !3999\n")
74                 ->module()
75                 ->ComputeIdBound());
76 }
77 
TEST(ModuleTest,OstreamOperator)78 TEST(ModuleTest, OstreamOperator) {
79   const std::string text = R"(OpCapability Shader
80 OpCapability Linkage
81 OpMemoryModel Logical GLSL450
82 OpName %7 "restrict"
83 OpDecorate %8 Restrict
84 %9 = OpTypeVoid
85 %10 = OpTypeInt 32 0
86 %11 = OpTypeStruct %10 %10
87 %12 = OpTypePointer Function %10
88 %13 = OpTypePointer Function %11
89 %14 = OpConstant %10 0
90 %15 = OpConstant %10 1
91 %7 = OpTypeFunction %9
92 %1 = OpFunction %9 None %7
93 %2 = OpLabel
94 %8 = OpVariable %13 Function
95 %3 = OpAccessChain %12 %8 %14
96 %4 = OpLoad %10 %3
97 %5 = OpAccessChain %12 %8 %15
98 %6 = OpLoad %10 %5
99 OpReturn
100 OpFunctionEnd)";
101 
102   std::string s;
103   std::ostringstream str(s);
104   str << *BuildModule(text)->module();
105   EXPECT_EQ(text, str.str());
106 }
107 
TEST(ModuleTest,OstreamOperatorInt64)108 TEST(ModuleTest, OstreamOperatorInt64) {
109   const std::string text = R"(OpCapability Shader
110 OpCapability Linkage
111 OpCapability Int64
112 OpMemoryModel Logical GLSL450
113 OpName %7 "restrict"
114 OpDecorate %5 Restrict
115 %9 = OpTypeVoid
116 %10 = OpTypeInt 64 0
117 %11 = OpTypeStruct %10 %10
118 %12 = OpTypePointer Function %10
119 %13 = OpTypePointer Function %11
120 %14 = OpConstant %10 0
121 %15 = OpConstant %10 1
122 %16 = OpConstant %10 4294967297
123 %7 = OpTypeFunction %9
124 %1 = OpFunction %9 None %7
125 %2 = OpLabel
126 %5 = OpVariable %12 Function
127 %6 = OpLoad %10 %5
128 OpSelectionMerge %3 None
129 OpSwitch %6 %3 4294967297 %4
130 %4 = OpLabel
131 OpBranch %3
132 %3 = OpLabel
133 OpReturn
134 OpFunctionEnd)";
135 
136   std::string s;
137   std::ostringstream str(s);
138   str << *BuildModule(text)->module();
139   EXPECT_EQ(text, str.str());
140 }
141 
TEST(ModuleTest,IdBoundTestAtLimit)142 TEST(ModuleTest, IdBoundTestAtLimit) {
143   const std::string text = R"(
144 OpCapability Shader
145 OpCapability Linkage
146 OpMemoryModel Logical GLSL450
147 %1 = OpTypeVoid
148 %2 = OpTypeFunction %1
149 %3 = OpFunction %1 None %2
150 %4 = OpLabel
151 OpReturn
152 OpFunctionEnd)";
153 
154   std::unique_ptr<IRContext> context = BuildModule(text);
155   uint32_t current_bound = context->module()->id_bound();
156   context->set_max_id_bound(current_bound);
157   uint32_t next_id_bound = context->module()->TakeNextIdBound();
158   EXPECT_EQ(next_id_bound, 0);
159   EXPECT_EQ(current_bound, context->module()->id_bound());
160   next_id_bound = context->module()->TakeNextIdBound();
161   EXPECT_EQ(next_id_bound, 0);
162 }
163 
TEST(ModuleTest,IdBoundTestBelowLimit)164 TEST(ModuleTest, IdBoundTestBelowLimit) {
165   const std::string text = R"(
166 OpCapability Shader
167 OpCapability Linkage
168 OpMemoryModel Logical GLSL450
169 %1 = OpTypeVoid
170 %2 = OpTypeFunction %1
171 %3 = OpFunction %1 None %2
172 %4 = OpLabel
173 OpReturn
174 OpFunctionEnd)";
175 
176   std::unique_ptr<IRContext> context = BuildModule(text);
177   uint32_t current_bound = context->module()->id_bound();
178   context->set_max_id_bound(current_bound + 100);
179   uint32_t next_id_bound = context->module()->TakeNextIdBound();
180   EXPECT_EQ(next_id_bound, current_bound);
181   EXPECT_EQ(current_bound + 1, context->module()->id_bound());
182   next_id_bound = context->module()->TakeNextIdBound();
183   EXPECT_EQ(next_id_bound, current_bound + 1);
184 }
185 
TEST(ModuleTest,IdBoundTestNearLimit)186 TEST(ModuleTest, IdBoundTestNearLimit) {
187   const std::string text = R"(
188 OpCapability Shader
189 OpCapability Linkage
190 OpMemoryModel Logical GLSL450
191 %1 = OpTypeVoid
192 %2 = OpTypeFunction %1
193 %3 = OpFunction %1 None %2
194 %4 = OpLabel
195 OpReturn
196 OpFunctionEnd)";
197 
198   std::unique_ptr<IRContext> context = BuildModule(text);
199   uint32_t current_bound = context->module()->id_bound();
200   context->set_max_id_bound(current_bound + 1);
201   uint32_t next_id_bound = context->module()->TakeNextIdBound();
202   EXPECT_EQ(next_id_bound, current_bound);
203   EXPECT_EQ(current_bound + 1, context->module()->id_bound());
204   next_id_bound = context->module()->TakeNextIdBound();
205   EXPECT_EQ(next_id_bound, 0);
206 }
207 
TEST(ModuleTest,IdBoundTestUIntMax)208 TEST(ModuleTest, IdBoundTestUIntMax) {
209   const std::string text = R"(
210 OpCapability Shader
211 OpCapability Linkage
212 OpMemoryModel Logical GLSL450
213 %1 = OpTypeVoid
214 %2 = OpTypeFunction %1
215 %3 = OpFunction %1 None %2
216 %4294967294 = OpLabel ; ID is UINT_MAX-1
217 OpReturn
218 OpFunctionEnd)";
219 
220   std::unique_ptr<IRContext> context = BuildModule(text);
221   uint32_t current_bound = context->module()->id_bound();
222 
223   // Expecting |BuildModule| to preserve the numeric ids.
224   EXPECT_EQ(current_bound, std::numeric_limits<uint32_t>::max());
225 
226   context->set_max_id_bound(current_bound);
227   uint32_t next_id_bound = context->module()->TakeNextIdBound();
228   EXPECT_EQ(next_id_bound, 0);
229   EXPECT_EQ(current_bound, context->module()->id_bound());
230 }
231 }  // namespace
232 }  // namespace opt
233 }  // namespace spvtools
234