blob: 406da0939f9352b78cbf5181e2e14b52018ece86 [file] [log] [blame]
Chris Forbescc5697f2019-01-30 11:54:08 -08001// 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"
Ben Claytond552f632019-11-18 11:18:41 +000024#include "source/opt/pass.h"
Chris Forbescc5697f2019-01-30 11:54:08 -080025#include "spirv-tools/libspirv.hpp"
26#include "test/opt/module_utils.h"
27
28namespace spvtools {
29namespace opt {
30namespace {
31
32using ::testing::Eq;
33using spvtest::GetIdBound;
34
35TEST(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.
49inline 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
54TEST(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
79TEST(ModuleTest, OstreamOperator) {
80 const std::string text = R"(OpCapability Shader
81OpCapability Linkage
82OpMemoryModel Logical GLSL450
83OpName %7 "restrict"
84OpDecorate %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
100OpReturn
101OpFunctionEnd)";
102
103 std::string s;
104 std::ostringstream str(s);
105 str << *BuildModule(text)->module();
106 EXPECT_EQ(text, str.str());
107}
108
109TEST(ModuleTest, OstreamOperatorInt64) {
110 const std::string text = R"(OpCapability Shader
111OpCapability Linkage
112OpCapability Int64
113OpMemoryModel Logical GLSL450
114OpName %7 "restrict"
115OpDecorate %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
129OpSelectionMerge %3 None
130OpSwitch %6 %3 4294967297 %4
131%4 = OpLabel
132OpBranch %3
133%3 = OpLabel
134OpReturn
135OpFunctionEnd)";
136
137 std::string s;
138 std::ostringstream str(s);
139 str << *BuildModule(text)->module();
140 EXPECT_EQ(text, str.str());
141}
142
143TEST(ModuleTest, IdBoundTestAtLimit) {
144 const std::string text = R"(
145OpCapability Shader
146OpCapability Linkage
147OpMemoryModel Logical GLSL450
148%1 = OpTypeVoid
149%2 = OpTypeFunction %1
150%3 = OpFunction %1 None %2
151%4 = OpLabel
152OpReturn
153OpFunctionEnd)";
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
165TEST(ModuleTest, IdBoundTestBelowLimit) {
166 const std::string text = R"(
167OpCapability Shader
168OpCapability Linkage
169OpMemoryModel Logical GLSL450
170%1 = OpTypeVoid
171%2 = OpTypeFunction %1
172%3 = OpFunction %1 None %2
173%4 = OpLabel
174OpReturn
175OpFunctionEnd)";
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
187TEST(ModuleTest, IdBoundTestNearLimit) {
188 const std::string text = R"(
189OpCapability Shader
190OpCapability Linkage
191OpMemoryModel Logical GLSL450
192%1 = OpTypeVoid
193%2 = OpTypeFunction %1
194%3 = OpFunction %1 None %2
195%4 = OpLabel
196OpReturn
197OpFunctionEnd)";
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
209TEST(ModuleTest, IdBoundTestUIntMax) {
210 const std::string text = R"(
211OpCapability Shader
212OpCapability Linkage
213OpMemoryModel Logical GLSL450
214%1 = OpTypeVoid
215%2 = OpTypeFunction %1
216%3 = OpFunction %1 None %2
217%4294967294 = OpLabel ; ID is UINT_MAX-1
218OpReturn
219OpFunctionEnd)";
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}
Ben Claytond552f632019-11-18 11:18:41 +0000232
233// Tests that "text" does not change when it is assembled, converted into a
234// module, converted back to a binary, and then disassembled.
235void 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
247TEST(ModuleTest, TrailingOpLine) {
248 const std::string text = R"(OpCapability Shader
249OpCapability Linkage
250OpMemoryModel Logical GLSL450
251%5 = OpString "file.ext"
252%void = OpTypeVoid
253%2 = OpTypeFunction %void
254%3 = OpFunction %void None %2
255%4 = OpLabel
256OpReturn
257OpFunctionEnd
258OpLine %5 1 0
259)";
260
261 AssembleAndDisassemble(text);
262}
263
264TEST(ModuleTest, TrailingOpNoLine) {
265 const std::string text = R"(OpCapability Shader
266OpCapability Linkage
267OpMemoryModel Logical GLSL450
268%void = OpTypeVoid
269%2 = OpTypeFunction %void
270%3 = OpFunction %void None %2
271%4 = OpLabel
272OpReturn
273OpFunctionEnd
274OpNoLine
275)";
276
277 AssembleAndDisassemble(text);
278}
279
280TEST(ModuleTest, MulitpleTrailingOpLine) {
281 const std::string text = R"(OpCapability Shader
282OpCapability Linkage
283OpMemoryModel Logical GLSL450
284%5 = OpString "file.ext"
285%void = OpTypeVoid
286%2 = OpTypeFunction %void
287%3 = OpFunction %void None %2
288%4 = OpLabel
289OpReturn
290OpFunctionEnd
291OpLine %5 1 0
292OpNoLine
293OpLine %5 1 1
294)";
295
296 AssembleAndDisassemble(text);
297}
Chris Forbescc5697f2019-01-30 11:54:08 -0800298} // namespace
299} // namespace opt
300} // namespace spvtools