1 // Copyright (c) 2022 The Khronos Group 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 <string>
16 #include <vector>
17
18 #include "gmock/gmock.h"
19 #include "test/val/val_fixtures.h"
20
21 namespace spvtools {
22 namespace val {
23 namespace {
24
25 using ::testing::HasSubstr;
26 using ::testing::Values;
27 using ::testing::ValuesIn;
28
29 struct Case {
30 std::vector<std::string> caps;
31 bool shader;
32 std::string result_type;
33 std::string scope;
34 std::string delta;
35 std::string cluster_size;
36 std::string expected_error; // empty for no error.
37 };
38
operator <<(std::ostream & out,Case c)39 inline std::ostream& operator<<(std::ostream& out, Case c) {
40 out << "\nSPV_KHR_subgroup_rotate Case{{";
41 for (auto& cap : c.caps) {
42 out << cap;
43 }
44 out << "} ";
45 out << (c.shader ? "shader " : "kernel ");
46 out << c.result_type + " ";
47 out << c.scope + " ";
48 out << c.delta + " ";
49 out << c.cluster_size + " ";
50 out << "err'" << c.expected_error << "'";
51 out << "}";
52 return out;
53 }
54
AssemblyForCase(const Case & c)55 std::string AssemblyForCase(const Case& c) {
56 std::ostringstream ss;
57
58 if (c.shader) {
59 ss << "OpCapability Shader\n";
60 } else {
61 ss << "OpCapability Kernel\n";
62 ss << "OpCapability Addresses\n";
63 }
64 for (auto& cap : c.caps) {
65 ss << "OpCapability " << cap << "\n";
66 }
67 ss << "OpExtension \"SPV_KHR_subgroup_rotate\"\n";
68
69 if (c.shader) {
70 ss << "OpMemoryModel Logical GLSL450\n";
71 ss << "OpEntryPoint GLCompute %main \"main\"\n";
72 } else {
73 ss << "OpMemoryModel Physical32 OpenCL\n";
74 ss << "OpEntryPoint Kernel %main \"main\"\n";
75 }
76
77 ss << R"(
78 %void = OpTypeVoid
79 %void_fn = OpTypeFunction %void
80 %u32 = OpTypeInt 32 0
81 %float = OpTypeFloat 32
82 %ptr = OpTypePointer Function %u32
83 )";
84
85 if (c.shader) {
86 ss << "%i32 = OpTypeInt 32 1\n";
87 }
88
89 ss << R"(
90 %u32_0 = OpConstant %u32 0
91 %u32_1 = OpConstant %u32 1
92 %u32_15 = OpConstant %u32 15
93 %u32_16 = OpConstant %u32 16
94 %u32_undef = OpUndef %u32
95 %u32_spec_1 = OpSpecConstant %u32 1
96 %u32_spec_16 = OpSpecConstant %u32 16
97 %f32_1 = OpConstant %float 1.0
98 %subgroup = OpConstant %u32 3
99 %workgroup = OpConstant %u32 2
100 %invalid_scope = OpConstant %u32 1
101 %val = OpConstant %u32 42
102 )";
103
104 if (c.shader) {
105 ss << "%i32_1 = OpConstant %i32 1\n";
106 }
107
108 ss << R"(
109 %main = OpFunction %void None %void_fn
110 %entry = OpLabel
111 )";
112
113 ss << "%unused = OpGroupNonUniformRotateKHR ";
114 ss << c.result_type + " ";
115 ss << c.scope;
116 ss << " %val ";
117 ss << c.delta;
118 ss << " " + c.cluster_size;
119 ss << "\n";
120
121 ss << R"(
122 OpReturn
123 OpFunctionEnd
124 )";
125
126 return ss.str();
127 }
128
129 using ValidateSpvKHRSubgroupRotate = spvtest::ValidateBase<Case>;
130
TEST_P(ValidateSpvKHRSubgroupRotate,Base)131 TEST_P(ValidateSpvKHRSubgroupRotate, Base) {
132 const auto& c = GetParam();
133 const auto& assembly = AssemblyForCase(c);
134 CompileSuccessfully(assembly);
135 if (c.expected_error.empty()) {
136 EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString();
137 } else {
138 EXPECT_NE(SPV_SUCCESS, ValidateInstructions());
139 EXPECT_THAT(getDiagnosticString(), HasSubstr(c.expected_error));
140 }
141 }
142
143 INSTANTIATE_TEST_SUITE_P(
144 Valid, ValidateSpvKHRSubgroupRotate,
145 ::testing::Values(
146 Case{
147 {"GroupNonUniformRotateKHR"}, false, "%u32", "%subgroup", "%u32_1"},
148 Case{{"GroupNonUniformRotateKHR"}, true, "%u32", "%subgroup", "%u32_1"},
149 Case{{"GroupNonUniformRotateKHR"},
150 false,
151 "%u32",
152 "%subgroup",
153 "%u32_1",
154 "%u32_16"},
155 Case{{"GroupNonUniformRotateKHR"},
156 true,
157 "%u32",
158 "%subgroup",
159 "%u32_1",
160 "%u32_16"},
161 Case{{"GroupNonUniformRotateKHR"},
162 false,
163 "%u32",
164 "%subgroup",
165 "%u32_spec_1",
166 "%u32_16"},
167 Case{{"GroupNonUniformRotateKHR"},
168 true,
169 "%u32",
170 "%subgroup",
171 "%u32_1",
172 "%u32_spec_16"},
173 Case{{"GroupNonUniformRotateKHR"},
174 false,
175 "%u32",
176 "%workgroup",
177 "%u32_1"},
178 Case{
179 {"GroupNonUniformRotateKHR"}, true, "%u32", "%workgroup", "%u32_1"},
180 Case{{"GroupNonUniformRotateKHR"},
181 false,
182 "%u32",
183 "%workgroup",
184 "%u32_spec_1"},
185 Case{{"GroupNonUniformRotateKHR"},
186 true,
187 "%u32",
188 "%workgroup",
189 "%u32_spec_1"}));
190
191 INSTANTIATE_TEST_SUITE_P(
192 RequiresCapability, ValidateSpvKHRSubgroupRotate,
193 ::testing::Values(Case{{},
194 false,
195 "%u32",
196 "%subgroup",
197 "%u32_1",
198 "",
199 "Opcode GroupNonUniformRotateKHR requires one of "
200 "these capabilities: "
201 "GroupNonUniformRotateKHR"},
202 Case{{},
203 true,
204 "%u32",
205 "%subgroup",
206 "%u32_1",
207 "",
208 "Opcode GroupNonUniformRotateKHR requires one of "
209 "these capabilities: "
210 "GroupNonUniformRotateKHR"}));
211
TEST_F(ValidateSpvKHRSubgroupRotate,RequiresExtension)212 TEST_F(ValidateSpvKHRSubgroupRotate, RequiresExtension) {
213 const std::string str = R"(
214 OpCapability GroupNonUniformRotateKHR
215 )";
216 CompileSuccessfully(str.c_str());
217 EXPECT_NE(SPV_SUCCESS, ValidateInstructions());
218 EXPECT_THAT(
219 getDiagnosticString(),
220 HasSubstr(
221 "1st operand of Capability: operand GroupNonUniformRotateKHR(6026) "
222 "requires one of these extensions: SPV_KHR_subgroup_rotate"));
223 }
224
225 INSTANTIATE_TEST_SUITE_P(
226 InvalidExecutionScope, ValidateSpvKHRSubgroupRotate,
227 ::testing::Values(
228 Case{{"GroupNonUniformRotateKHR"},
229 false,
230 "%u32",
231 "%invalid_scope",
232 "%u32_1",
233 "",
234 "Execution scope is limited to Subgroup or Workgroup"},
235 Case{{"GroupNonUniformRotateKHR"},
236 true,
237 "%u32",
238 "%invalid_scope",
239 "%u32_1",
240 "",
241 "Execution scope is limited to Subgroup or Workgroup"}));
242
243 INSTANTIATE_TEST_SUITE_P(
244 InvalidResultType, ValidateSpvKHRSubgroupRotate,
245 ::testing::Values(Case{{"GroupNonUniformRotateKHR"},
246 false,
247 "%ptr",
248 "%subgroup",
249 "%u32_1",
250 "",
251 "Expected Result Type to be a scalar or vector of "
252 "floating-point, integer or boolean type"},
253 Case{{"GroupNonUniformRotateKHR"},
254 true,
255 "%ptr",
256 "%subgroup",
257 "%u32_1",
258 "",
259 "Expected Result Type to be a scalar or vector of "
260 "floating-point, integer or boolean type"}));
261
262 INSTANTIATE_TEST_SUITE_P(
263 MismatchedResultAndValueTypes, ValidateSpvKHRSubgroupRotate,
264 ::testing::Values(
265 Case{{"GroupNonUniformRotateKHR"},
266 false,
267 "%float",
268 "%subgroup",
269 "%u32_1",
270 "",
271 "Result Type must be the same as the type of Value"},
272 Case{{"GroupNonUniformRotateKHR"},
273 true,
274 "%float",
275 "%subgroup",
276 "%u32_1",
277 "",
278 "Result Type must be the same as the type of Value"}));
279
280 INSTANTIATE_TEST_SUITE_P(
281 InvalidDelta, ValidateSpvKHRSubgroupRotate,
282 ::testing::Values(Case{{"GroupNonUniformRotateKHR"},
283 false,
284 "%u32",
285 "%subgroup",
286 "%f32_1",
287 "",
288 "Delta must be a scalar of integer type, whose "
289 "Signedness operand is 0"},
290 Case{{"GroupNonUniformRotateKHR"},
291 true,
292 "%u32",
293 "%subgroup",
294 "%f32_1",
295 "",
296 "Delta must be a scalar of integer type, whose "
297 "Signedness operand is 0"},
298 Case{{"GroupNonUniformRotateKHR"},
299 true,
300 "%u32",
301 "%subgroup",
302 "%i32_1",
303 "",
304 "Delta must be a scalar of integer type, whose "
305 "Signedness operand is 0"}));
306
307 INSTANTIATE_TEST_SUITE_P(
308 InvalidClusterSize, ValidateSpvKHRSubgroupRotate,
309 ::testing::Values(
310 Case{{"GroupNonUniformRotateKHR"},
311 false,
312 "%u32",
313 "%subgroup",
314 "%u32_1",
315 "%f32_1",
316 "ClusterSize must be a scalar of integer type, whose Signedness "
317 "operand is 0"},
318 Case{{"GroupNonUniformRotateKHR"},
319 true,
320 "%u32",
321 "%subgroup",
322 "%u32_1",
323 "%i32_1",
324 "ClusterSize must be a scalar of integer type, whose Signedness "
325 "operand is 0"},
326 Case{{"GroupNonUniformRotateKHR"},
327 true,
328 "%u32",
329 "%subgroup",
330 "%u32_1",
331 "%u32_0",
332 "Behavior is undefined unless ClusterSize is at least 1 and a "
333 "power of 2"},
334 Case{{"GroupNonUniformRotateKHR"},
335 true,
336 "%u32",
337 "%subgroup",
338 "%u32_1",
339 "%u32_15",
340 "Behavior is undefined unless ClusterSize is at least 1 and a "
341 "power of 2"},
342 Case{{"GroupNonUniformRotateKHR"},
343 true,
344 "%u32",
345 "%subgroup",
346 "%u32_1",
347 "%u32_undef",
348 "ClusterSize must come from a constant instruction"}));
349
350 } // namespace
351 } // namespace val
352 } // namespace spvtools
353