1 // Copyright (c) 2015-2016 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 // Assembler tests for instructions in the "Group Instrucions" section of the
16 // SPIR-V spec.
17
18 #include <cstdint>
19 #include <limits>
20 #include <string>
21 #include <vector>
22
23 #include "gmock/gmock.h"
24 #include "test/test_fixture.h"
25 #include "test/unit_spirv.h"
26
27 namespace spvtools {
28 namespace {
29
30 using spvtest::Concatenate;
31 using spvtest::EnumCase;
32 using spvtest::MakeInstruction;
33 using ::testing::Eq;
34
35 // Test Sampler Addressing Mode enum values
36
37 using SamplerAddressingModeTest = spvtest::TextToBinaryTestBase<
38 ::testing::TestWithParam<EnumCase<SpvSamplerAddressingMode>>>;
39
TEST_P(SamplerAddressingModeTest,AnySamplerAddressingMode)40 TEST_P(SamplerAddressingModeTest, AnySamplerAddressingMode) {
41 const std::string input =
42 "%result = OpConstantSampler %type " + GetParam().name() + " 0 Nearest";
43 EXPECT_THAT(CompiledInstructions(input),
44 Eq(MakeInstruction(SpvOpConstantSampler,
45 {1, 2, GetParam().value(), 0, 0})));
46 }
47
48 // clang-format off
49 #define CASE(NAME) { SpvSamplerAddressingMode##NAME, #NAME }
50 INSTANTIATE_TEST_CASE_P(
51 TextToBinarySamplerAddressingMode, SamplerAddressingModeTest,
52 ::testing::ValuesIn(std::vector<EnumCase<SpvSamplerAddressingMode>>{
53 CASE(None),
54 CASE(ClampToEdge),
55 CASE(Clamp),
56 CASE(Repeat),
57 CASE(RepeatMirrored),
58 }),);
59 #undef CASE
60 // clang-format on
61
TEST_F(SamplerAddressingModeTest,WrongMode)62 TEST_F(SamplerAddressingModeTest, WrongMode) {
63 EXPECT_THAT(CompileFailure("%r = OpConstantSampler %t xxyyzz 0 Nearest"),
64 Eq("Invalid sampler addressing mode 'xxyyzz'."));
65 }
66
67 // Test Sampler Filter Mode enum values
68
69 using SamplerFilterModeTest = spvtest::TextToBinaryTestBase<
70 ::testing::TestWithParam<EnumCase<SpvSamplerFilterMode>>>;
71
TEST_P(SamplerFilterModeTest,AnySamplerFilterMode)72 TEST_P(SamplerFilterModeTest, AnySamplerFilterMode) {
73 const std::string input =
74 "%result = OpConstantSampler %type Clamp 0 " + GetParam().name();
75 EXPECT_THAT(CompiledInstructions(input),
76 Eq(MakeInstruction(SpvOpConstantSampler,
77 {1, 2, 2, 0, GetParam().value()})));
78 }
79
80 // clang-format off
81 #define CASE(NAME) { SpvSamplerFilterMode##NAME, #NAME}
82 INSTANTIATE_TEST_CASE_P(
83 TextToBinarySamplerFilterMode, SamplerFilterModeTest,
84 ::testing::ValuesIn(std::vector<EnumCase<SpvSamplerFilterMode>>{
85 CASE(Nearest),
86 CASE(Linear),
87 }),);
88 #undef CASE
89 // clang-format on
90
TEST_F(SamplerFilterModeTest,WrongMode)91 TEST_F(SamplerFilterModeTest, WrongMode) {
92 EXPECT_THAT(CompileFailure("%r = OpConstantSampler %t Clamp 0 xxyyzz"),
93 Eq("Invalid sampler filter mode 'xxyyzz'."));
94 }
95
96 struct ConstantTestCase {
97 std::string constant_type;
98 std::string constant_value;
99 std::vector<uint32_t> expected_instructions;
100 };
101
102 using OpConstantValidTest =
103 spvtest::TextToBinaryTestBase<::testing::TestWithParam<ConstantTestCase>>;
104
TEST_P(OpConstantValidTest,ValidTypes)105 TEST_P(OpConstantValidTest, ValidTypes) {
106 const std::string input = "%1 = " + GetParam().constant_type +
107 "\n"
108 "%2 = OpConstant %1 " +
109 GetParam().constant_value + "\n";
110 std::vector<uint32_t> instructions;
111 EXPECT_THAT(CompiledInstructions(input), Eq(GetParam().expected_instructions))
112 << " type: " << GetParam().constant_type
113 << " literal: " << GetParam().constant_value;
114 }
115
116 // clang-format off
117 INSTANTIATE_TEST_CASE_P(
118 TextToBinaryOpConstantValid, OpConstantValidTest,
119 ::testing::ValuesIn(std::vector<ConstantTestCase>{
120 // Check 16 bits
121 {"OpTypeInt 16 0", "0x1234",
122 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 16, 0}),
123 MakeInstruction(SpvOpConstant, {1, 2, 0x1234})})},
124 {"OpTypeInt 16 0", "0x8000",
125 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 16, 0}),
126 MakeInstruction(SpvOpConstant, {1, 2, 0x8000})})},
127 {"OpTypeInt 16 0", "0",
128 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 16, 0}),
129 MakeInstruction(SpvOpConstant, {1, 2, 0})})},
130 {"OpTypeInt 16 0", "65535",
131 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 16, 0}),
132 MakeInstruction(SpvOpConstant, {1, 2, 65535})})},
133 {"OpTypeInt 16 0", "0xffff",
134 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 16, 0}),
135 MakeInstruction(SpvOpConstant, {1, 2, 65535})})},
136 {"OpTypeInt 16 1", "0x8000", // Test sign extension.
137 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 16, 1}),
138 MakeInstruction(SpvOpConstant, {1, 2, 0xffff8000})})},
139 {"OpTypeInt 16 1", "-32",
140 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 16, 1}),
141 MakeInstruction(SpvOpConstant, {1, 2, uint32_t(-32)})})},
142 {"OpTypeInt 16 1", "0",
143 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 16, 1}),
144 MakeInstruction(SpvOpConstant, {1, 2, 0})})},
145 {"OpTypeInt 16 1", "-0",
146 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 16, 1}),
147 MakeInstruction(SpvOpConstant, {1, 2, 0})})},
148 {"OpTypeInt 16 1", "-0x0",
149 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 16, 1}),
150 MakeInstruction(SpvOpConstant, {1, 2, 0})})},
151 {"OpTypeInt 16 1", "-32768",
152 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 16, 1}),
153 MakeInstruction(SpvOpConstant, {1, 2, uint32_t(-32768)})})},
154 // Check 32 bits
155 {"OpTypeInt 32 0", "42",
156 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 32, 0}),
157 MakeInstruction(SpvOpConstant, {1, 2, 42})})},
158 {"OpTypeInt 32 1", "-32",
159 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 32, 1}),
160 MakeInstruction(SpvOpConstant, {1, 2, uint32_t(-32)})})},
161 {"OpTypeInt 32 1", "0",
162 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 32, 1}),
163 MakeInstruction(SpvOpConstant, {1, 2, 0})})},
164 {"OpTypeInt 32 1", "-0",
165 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 32, 1}),
166 MakeInstruction(SpvOpConstant, {1, 2, 0})})},
167 {"OpTypeInt 32 1", "-0x0",
168 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 32, 1}),
169 MakeInstruction(SpvOpConstant, {1, 2, 0})})},
170 {"OpTypeInt 32 1", "-0x001",
171 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 32, 1}),
172 MakeInstruction(SpvOpConstant, {1, 2, uint32_t(-1)})})},
173 {"OpTypeInt 32 1", "2147483647",
174 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 32, 1}),
175 MakeInstruction(SpvOpConstant, {1, 2, 0x7fffffffu})})},
176 {"OpTypeInt 32 1", "-2147483648",
177 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 32, 1}),
178 MakeInstruction(SpvOpConstant, {1, 2, 0x80000000u})})},
179 {"OpTypeFloat 32", "1.0",
180 Concatenate({MakeInstruction(SpvOpTypeFloat, {1, 32}),
181 MakeInstruction(SpvOpConstant, {1, 2, 0x3f800000})})},
182 {"OpTypeFloat 32", "10.0",
183 Concatenate({MakeInstruction(SpvOpTypeFloat, {1, 32}),
184 MakeInstruction(SpvOpConstant, {1, 2, 0x41200000})})},
185 {"OpTypeFloat 32", "-0x1p+128", // -infinity
186 Concatenate({MakeInstruction(SpvOpTypeFloat, {1, 32}),
187 MakeInstruction(SpvOpConstant, {1, 2, 0xFF800000})})},
188 {"OpTypeFloat 32", "0x1p+128", // +infinity
189 Concatenate({MakeInstruction(SpvOpTypeFloat, {1, 32}),
190 MakeInstruction(SpvOpConstant, {1, 2, 0x7F800000})})},
191 {"OpTypeFloat 32", "-0x1.8p+128", // A -NaN
192 Concatenate({MakeInstruction(SpvOpTypeFloat, {1, 32}),
193 MakeInstruction(SpvOpConstant, {1, 2, 0xFFC00000})})},
194 {"OpTypeFloat 32", "-0x1.0002p+128", // A +NaN
195 Concatenate({MakeInstruction(SpvOpTypeFloat, {1, 32}),
196 MakeInstruction(SpvOpConstant, {1, 2, 0xFF800100})})},
197 // Check 48 bits
198 {"OpTypeInt 48 0", "0x1234",
199 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 48, 0}),
200 MakeInstruction(SpvOpConstant, {1, 2, 0x1234, 0})})},
201 {"OpTypeInt 48 0", "0x800000000001",
202 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 48, 0}),
203 MakeInstruction(SpvOpConstant, {1, 2, 1, 0x00008000})})},
204 {"OpTypeInt 48 1", "0x800000000000", // Test sign extension.
205 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 48, 1}),
206 MakeInstruction(SpvOpConstant, {1, 2, 0, 0xffff8000})})},
207 {"OpTypeInt 48 1", "-32",
208 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 48, 1}),
209 MakeInstruction(SpvOpConstant, {1, 2, uint32_t(-32), uint32_t(-1)})})},
210 // Check 64 bits
211 {"OpTypeInt 64 0", "0x1234",
212 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 64, 0}),
213 MakeInstruction(SpvOpConstant, {1, 2, 0x1234, 0})})},
214 {"OpTypeInt 64 0", "18446744073709551615",
215 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 64, 0}),
216 MakeInstruction(SpvOpConstant, {1, 2, 0xffffffffu, 0xffffffffu})})},
217 {"OpTypeInt 64 0", "0xffffffffffffffff",
218 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 64, 0}),
219 MakeInstruction(SpvOpConstant, {1, 2, 0xffffffffu, 0xffffffffu})})},
220 {"OpTypeInt 64 1", "0x1234",
221 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 64, 1}),
222 MakeInstruction(SpvOpConstant, {1, 2, 0x1234, 0})})},
223 {"OpTypeInt 64 1", "-42",
224 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 64, 1}),
225 MakeInstruction(SpvOpConstant, {1, 2, uint32_t(-42), uint32_t(-1)})})},
226 {"OpTypeInt 64 1", "-0x01",
227 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 64, 1}),
228 MakeInstruction(SpvOpConstant, {1, 2, 0xffffffffu, 0xffffffffu})})},
229 {"OpTypeInt 64 1", "9223372036854775807",
230 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 64, 1}),
231 MakeInstruction(SpvOpConstant, {1, 2, 0xffffffffu, 0x7fffffffu})})},
232 {"OpTypeInt 64 1", "0x7fffffff",
233 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 64, 1}),
234 MakeInstruction(SpvOpConstant, {1, 2, 0x7fffffffu, 0})})},
235 }),);
236 // clang-format on
237
238 // A test case for checking OpConstant with invalid literals with a leading
239 // minus.
240 struct InvalidLeadingMinusCase {
241 std::string type;
242 std::string literal;
243 };
244
245 using OpConstantInvalidLeadingMinusTest = spvtest::TextToBinaryTestBase<
246 ::testing::TestWithParam<InvalidLeadingMinusCase>>;
247
TEST_P(OpConstantInvalidLeadingMinusTest,InvalidCase)248 TEST_P(OpConstantInvalidLeadingMinusTest, InvalidCase) {
249 const std::string input = "%1 = " + GetParam().type +
250 "\n"
251 "%2 = OpConstant %1 " +
252 GetParam().literal;
253 EXPECT_THAT(CompileFailure(input),
254 Eq("Cannot put a negative number in an unsigned literal"));
255 }
256
257 // clang-format off
258 INSTANTIATE_TEST_CASE_P(
259 TextToBinaryOpConstantInvalidLeadingMinus, OpConstantInvalidLeadingMinusTest,
260 ::testing::ValuesIn(std::vector<InvalidLeadingMinusCase>{
261 {"OpTypeInt 16 0", "-0"},
262 {"OpTypeInt 16 0", "-0x0"},
263 {"OpTypeInt 16 0", "-1"},
264 {"OpTypeInt 32 0", "-0"},
265 {"OpTypeInt 32 0", "-0x0"},
266 {"OpTypeInt 32 0", "-1"},
267 {"OpTypeInt 64 0", "-0"},
268 {"OpTypeInt 64 0", "-0x0"},
269 {"OpTypeInt 64 0", "-1"},
270 }),);
271 // clang-format on
272
273 // A test case for invalid floating point literals.
274 struct InvalidFloatConstantCase {
275 uint32_t width;
276 std::string literal;
277 };
278
279 using OpConstantInvalidFloatConstant = spvtest::TextToBinaryTestBase<
280 ::testing::TestWithParam<InvalidFloatConstantCase>>;
281
TEST_P(OpConstantInvalidFloatConstant,Samples)282 TEST_P(OpConstantInvalidFloatConstant, Samples) {
283 // Check both kinds of instructions that take literal floats.
284 for (const auto& instruction : {"OpConstant", "OpSpecConstant"}) {
285 std::stringstream input;
286 input << "%1 = OpTypeFloat " << GetParam().width << "\n"
287 << "%2 = " << instruction << " %1 " << GetParam().literal;
288 std::stringstream expected_error;
289 expected_error << "Invalid " << GetParam().width
290 << "-bit float literal: " << GetParam().literal;
291 EXPECT_THAT(CompileFailure(input.str()), Eq(expected_error.str()));
292 }
293 }
294
295 // clang-format off
296 INSTANTIATE_TEST_CASE_P(
297 TextToBinaryInvalidFloatConstant, OpConstantInvalidFloatConstant,
298 ::testing::ValuesIn(std::vector<InvalidFloatConstantCase>{
299 {16, "abc"},
300 {16, "--1"},
301 {16, "-+1"},
302 {16, "+-1"},
303 {16, "++1"},
304 {16, "1e30"}, // Overflow is an error for 16-bit floats.
305 {16, "-1e30"},
306 {16, "1e40"},
307 {16, "-1e40"},
308 {16, "1e400"},
309 {16, "-1e400"},
310 {32, "abc"},
311 {32, "--1"},
312 {32, "-+1"},
313 {32, "+-1"},
314 {32, "++1"},
315 {32, "1e40"}, // Overflow is an error for 32-bit floats.
316 {32, "-1e40"},
317 {32, "1e400"},
318 {32, "-1e400"},
319 {64, "abc"},
320 {64, "--1"},
321 {64, "-+1"},
322 {64, "+-1"},
323 {64, "++1"},
324 {32, "1e400"}, // Overflow is an error for 64-bit floats.
325 {32, "-1e400"},
326 }),);
327 // clang-format on
328
329 using OpConstantInvalidTypeTest =
330 spvtest::TextToBinaryTestBase<::testing::TestWithParam<std::string>>;
331
TEST_P(OpConstantInvalidTypeTest,InvalidTypes)332 TEST_P(OpConstantInvalidTypeTest, InvalidTypes) {
333 const std::string input = "%1 = " + GetParam() +
334 "\n"
335 "%2 = OpConstant %1 0\n";
336 EXPECT_THAT(
337 CompileFailure(input),
338 Eq("Type for Constant must be a scalar floating point or integer type"));
339 }
340
341 // clang-format off
342 INSTANTIATE_TEST_CASE_P(
343 TextToBinaryOpConstantInvalidValidType, OpConstantInvalidTypeTest,
344 ::testing::ValuesIn(std::vector<std::string>{
345 {"OpTypeVoid",
346 "OpTypeBool",
347 "OpTypeVector %a 32",
348 "OpTypeMatrix %a 32",
349 "OpTypeImage %a 1D 0 0 0 0 Unknown",
350 "OpTypeSampler",
351 "OpTypeSampledImage %a",
352 "OpTypeArray %a %b",
353 "OpTypeRuntimeArray %a",
354 "OpTypeStruct %a",
355 "OpTypeOpaque \"Foo\"",
356 "OpTypePointer UniformConstant %a",
357 "OpTypeFunction %a %b",
358 "OpTypeEvent",
359 "OpTypeDeviceEvent",
360 "OpTypeReserveId",
361 "OpTypeQueue",
362 "OpTypePipe ReadOnly",
363 "OpTypeForwardPointer %a UniformConstant",
364 // At least one thing that isn't a type at all
365 "OpNot %a %b"
366 },
367 }),);
368 // clang-format on
369
370 using OpSpecConstantValidTest =
371 spvtest::TextToBinaryTestBase<::testing::TestWithParam<ConstantTestCase>>;
372
TEST_P(OpSpecConstantValidTest,ValidTypes)373 TEST_P(OpSpecConstantValidTest, ValidTypes) {
374 const std::string input = "%1 = " + GetParam().constant_type +
375 "\n"
376 "%2 = OpSpecConstant %1 " +
377 GetParam().constant_value + "\n";
378 std::vector<uint32_t> instructions;
379 EXPECT_THAT(CompiledInstructions(input),
380 Eq(GetParam().expected_instructions));
381 }
382
383 // clang-format off
384 INSTANTIATE_TEST_CASE_P(
385 TextToBinaryOpSpecConstantValid, OpSpecConstantValidTest,
386 ::testing::ValuesIn(std::vector<ConstantTestCase>{
387 // Check 16 bits
388 {"OpTypeInt 16 0", "0x1234",
389 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 16, 0}),
390 MakeInstruction(SpvOpSpecConstant, {1, 2, 0x1234})})},
391 {"OpTypeInt 16 0", "0x8000",
392 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 16, 0}),
393 MakeInstruction(SpvOpSpecConstant, {1, 2, 0x8000})})},
394 {"OpTypeInt 16 1", "0x8000", // Test sign extension.
395 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 16, 1}),
396 MakeInstruction(SpvOpSpecConstant, {1, 2, 0xffff8000})})},
397 {"OpTypeInt 16 1", "-32",
398 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 16, 1}),
399 MakeInstruction(SpvOpSpecConstant, {1, 2, uint32_t(-32)})})},
400 // Check 32 bits
401 {"OpTypeInt 32 0", "42",
402 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 32, 0}),
403 MakeInstruction(SpvOpSpecConstant, {1, 2, 42})})},
404 {"OpTypeInt 32 1", "-32",
405 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 32, 1}),
406 MakeInstruction(SpvOpSpecConstant, {1, 2, uint32_t(-32)})})},
407 {"OpTypeFloat 32", "1.0",
408 Concatenate({MakeInstruction(SpvOpTypeFloat, {1, 32}),
409 MakeInstruction(SpvOpSpecConstant, {1, 2, 0x3f800000})})},
410 {"OpTypeFloat 32", "10.0",
411 Concatenate({MakeInstruction(SpvOpTypeFloat, {1, 32}),
412 MakeInstruction(SpvOpSpecConstant, {1, 2, 0x41200000})})},
413 // Check 48 bits
414 {"OpTypeInt 48 0", "0x1234",
415 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 48, 0}),
416 MakeInstruction(SpvOpSpecConstant, {1, 2, 0x1234, 0})})},
417 {"OpTypeInt 48 0", "0x800000000001",
418 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 48, 0}),
419 MakeInstruction(SpvOpSpecConstant, {1, 2, 1, 0x00008000})})},
420 {"OpTypeInt 48 1", "0x800000000000", // Test sign extension.
421 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 48, 1}),
422 MakeInstruction(SpvOpSpecConstant, {1, 2, 0, 0xffff8000})})},
423 {"OpTypeInt 48 1", "-32",
424 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 48, 1}),
425 MakeInstruction(SpvOpSpecConstant, {1, 2, uint32_t(-32), uint32_t(-1)})})},
426 // Check 64 bits
427 {"OpTypeInt 64 0", "0x1234",
428 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 64, 0}),
429 MakeInstruction(SpvOpSpecConstant, {1, 2, 0x1234, 0})})},
430 {"OpTypeInt 64 1", "0x1234",
431 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 64, 1}),
432 MakeInstruction(SpvOpSpecConstant, {1, 2, 0x1234, 0})})},
433 {"OpTypeInt 64 1", "-42",
434 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 64, 1}),
435 MakeInstruction(SpvOpSpecConstant, {1, 2, uint32_t(-42), uint32_t(-1)})})},
436 }),);
437 // clang-format on
438
439 using OpSpecConstantInvalidTypeTest =
440 spvtest::TextToBinaryTestBase<::testing::TestWithParam<std::string>>;
441
TEST_P(OpSpecConstantInvalidTypeTest,InvalidTypes)442 TEST_P(OpSpecConstantInvalidTypeTest, InvalidTypes) {
443 const std::string input = "%1 = " + GetParam() +
444 "\n"
445 "%2 = OpSpecConstant %1 0\n";
446 EXPECT_THAT(CompileFailure(input),
447 Eq("Type for SpecConstant must be a scalar floating point or "
448 "integer type"));
449 }
450
451 // clang-format off
452 INSTANTIATE_TEST_CASE_P(
453 TextToBinaryOpSpecConstantInvalidValidType, OpSpecConstantInvalidTypeTest,
454 ::testing::ValuesIn(std::vector<std::string>{
455 {"OpTypeVoid",
456 "OpTypeBool",
457 "OpTypeVector %a 32",
458 "OpTypeMatrix %a 32",
459 "OpTypeImage %a 1D 0 0 0 0 Unknown",
460 "OpTypeSampler",
461 "OpTypeSampledImage %a",
462 "OpTypeArray %a %b",
463 "OpTypeRuntimeArray %a",
464 "OpTypeStruct %a",
465 "OpTypeOpaque \"Foo\"",
466 "OpTypePointer UniformConstant %a",
467 "OpTypeFunction %a %b",
468 "OpTypeEvent",
469 "OpTypeDeviceEvent",
470 "OpTypeReserveId",
471 "OpTypeQueue",
472 "OpTypePipe ReadOnly",
473 "OpTypeForwardPointer %a UniformConstant",
474 // At least one thing that isn't a type at all
475 "OpNot %a %b"
476 },
477 }),);
478 // clang-format on
479
480 const int64_t kMaxUnsigned48Bit = (int64_t(1) << 48) - 1;
481 const int64_t kMaxSigned48Bit = (int64_t(1) << 47) - 1;
482 const int64_t kMinSigned48Bit = -kMaxSigned48Bit - 1;
483
484 INSTANTIATE_TEST_CASE_P(
485 OpConstantRoundTrip, RoundTripTest,
486 ::testing::ValuesIn(std::vector<std::string>{
487 // 16 bit
488 "%1 = OpTypeInt 16 0\n%2 = OpConstant %1 0\n",
489 "%1 = OpTypeInt 16 0\n%2 = OpConstant %1 65535\n",
490 "%1 = OpTypeInt 16 1\n%2 = OpConstant %1 -32768\n",
491 "%1 = OpTypeInt 16 1\n%2 = OpConstant %1 32767\n",
492 "%1 = OpTypeInt 32 0\n%2 = OpConstant %1 0\n",
493 // 32 bit
494 std::string("%1 = OpTypeInt 32 0\n%2 = OpConstant %1 0\n"),
495 std::string("%1 = OpTypeInt 32 0\n%2 = OpConstant %1 ") +
496 std::to_string(std::numeric_limits<uint32_t>::max()) + "\n",
497 std::string("%1 = OpTypeInt 32 1\n%2 = OpConstant %1 ") +
498 std::to_string(std::numeric_limits<int32_t>::max()) + "\n",
499 std::string("%1 = OpTypeInt 32 1\n%2 = OpConstant %1 ") +
500 std::to_string(std::numeric_limits<int32_t>::min()) + "\n",
501 // 48 bit
502 std::string("%1 = OpTypeInt 48 0\n%2 = OpConstant %1 0\n"),
503 std::string("%1 = OpTypeInt 48 0\n%2 = OpConstant %1 ") +
504 std::to_string(kMaxUnsigned48Bit) + "\n",
505 std::string("%1 = OpTypeInt 48 1\n%2 = OpConstant %1 ") +
506 std::to_string(kMaxSigned48Bit) + "\n",
507 std::string("%1 = OpTypeInt 48 1\n%2 = OpConstant %1 ") +
508 std::to_string(kMinSigned48Bit) + "\n",
509 // 64 bit
510 std::string("%1 = OpTypeInt 64 0\n%2 = OpConstant %1 0\n"),
511 std::string("%1 = OpTypeInt 64 0\n%2 = OpConstant %1 ") +
512 std::to_string(std::numeric_limits<uint64_t>::max()) + "\n",
513 std::string("%1 = OpTypeInt 64 1\n%2 = OpConstant %1 ") +
514 std::to_string(std::numeric_limits<int64_t>::max()) + "\n",
515 std::string("%1 = OpTypeInt 64 1\n%2 = OpConstant %1 ") +
516 std::to_string(std::numeric_limits<int64_t>::min()) + "\n",
517 // 32-bit float
518 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 0\n",
519 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 13.5\n",
520 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 -12.5\n",
521 // 64-bit float
522 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0\n",
523 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 1.79767e+308\n",
524 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -1.79767e+308\n",
525 }), );
526
527 INSTANTIATE_TEST_CASE_P(
528 OpConstantHalfRoundTrip, RoundTripTest,
529 ::testing::ValuesIn(std::vector<std::string>{
530 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x0p+0\n",
531 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x0p+0\n",
532 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1p+0\n",
533 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1.1p+0\n",
534 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1.01p-1\n",
535 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1.8p+1\n",
536 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1.ffcp+1\n",
537 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1p+0\n",
538 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1.1p+0\n",
539 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1.01p-1\n",
540 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1.8p+1\n",
541 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1.ffcp+1\n",
542
543 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1p-16\n", // some denorms
544 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1p-24\n",
545 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1p-24\n",
546
547 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1p+16\n", // +inf
548 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1p+16\n", // -inf
549 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1.01p+16\n", // -inf
550 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1.01p+16\n", // nan
551 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1.11p+16\n", // nan
552 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1.ffp+16\n", // nan
553 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1.ffcp+16\n", // nan
554 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1.004p+16\n", // nan
555 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1.01p+16\n", // -nan
556 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1.11p+16\n", // -nan
557 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1.ffp+16\n", // -nan
558 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1.ffcp+16\n", // -nan
559 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1.004p+16\n", // -nan
560 }), );
561
562 // clang-format off
563 // (Clang-format really wants to break up these strings across lines.
564 INSTANTIATE_TEST_CASE_P(
565 OpConstantRoundTripNonFinite, RoundTripTest,
566 ::testing::ValuesIn(std::vector<std::string>{
567 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1p+128\n", // -inf
568 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 0x1p+128\n", // inf
569 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1.8p+128\n", // -nan
570 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1.0002p+128\n", // -nan
571 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1.0018p+128\n", // -nan
572 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1.01ep+128\n", // -nan
573 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1.fffffep+128\n", // -nan
574 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 0x1.8p+128\n", // +nan
575 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 0x1.0002p+128\n", // +nan
576 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 0x1.0018p+128\n", // +nan
577 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 0x1.01ep+128\n", // +nan
578 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 0x1.fffffep+128\n", // +nan
579 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1p+1024\n", // -inf
580 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1p+1024\n", // +inf
581 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1.8p+1024\n", // -nan
582 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1.0fp+1024\n", // -nan
583 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1.0000000000001p+1024\n", // -nan
584 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1.00003p+1024\n", // -nan
585 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1.fffffffffffffp+1024\n", // -nan
586 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1.8p+1024\n", // +nan
587 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1.0fp+1024\n", // +nan
588 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1.0000000000001p+1024\n", // -nan
589 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1.00003p+1024\n", // -nan
590 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1.fffffffffffffp+1024\n", // -nan
591 }),);
592 // clang-format on
593
594 INSTANTIATE_TEST_CASE_P(
595 OpSpecConstantRoundTrip, RoundTripTest,
596 ::testing::ValuesIn(std::vector<std::string>{
597 // 16 bit
598 "%1 = OpTypeInt 16 0\n%2 = OpSpecConstant %1 0\n",
599 "%1 = OpTypeInt 16 0\n%2 = OpSpecConstant %1 65535\n",
600 "%1 = OpTypeInt 16 1\n%2 = OpSpecConstant %1 -32768\n",
601 "%1 = OpTypeInt 16 1\n%2 = OpSpecConstant %1 32767\n",
602 "%1 = OpTypeInt 32 0\n%2 = OpSpecConstant %1 0\n",
603 // 32 bit
604 std::string("%1 = OpTypeInt 32 0\n%2 = OpSpecConstant %1 0\n"),
605 std::string("%1 = OpTypeInt 32 0\n%2 = OpSpecConstant %1 ") +
606 std::to_string(std::numeric_limits<uint32_t>::max()) + "\n",
607 std::string("%1 = OpTypeInt 32 1\n%2 = OpSpecConstant %1 ") +
608 std::to_string(std::numeric_limits<int32_t>::max()) + "\n",
609 std::string("%1 = OpTypeInt 32 1\n%2 = OpSpecConstant %1 ") +
610 std::to_string(std::numeric_limits<int32_t>::min()) + "\n",
611 // 48 bit
612 std::string("%1 = OpTypeInt 48 0\n%2 = OpSpecConstant %1 0\n"),
613 std::string("%1 = OpTypeInt 48 0\n%2 = OpSpecConstant %1 ") +
614 std::to_string(kMaxUnsigned48Bit) + "\n",
615 std::string("%1 = OpTypeInt 48 1\n%2 = OpSpecConstant %1 ") +
616 std::to_string(kMaxSigned48Bit) + "\n",
617 std::string("%1 = OpTypeInt 48 1\n%2 = OpSpecConstant %1 ") +
618 std::to_string(kMinSigned48Bit) + "\n",
619 // 64 bit
620 std::string("%1 = OpTypeInt 64 0\n%2 = OpSpecConstant %1 0\n"),
621 std::string("%1 = OpTypeInt 64 0\n%2 = OpSpecConstant %1 ") +
622 std::to_string(std::numeric_limits<uint64_t>::max()) + "\n",
623 std::string("%1 = OpTypeInt 64 1\n%2 = OpSpecConstant %1 ") +
624 std::to_string(std::numeric_limits<int64_t>::max()) + "\n",
625 std::string("%1 = OpTypeInt 64 1\n%2 = OpSpecConstant %1 ") +
626 std::to_string(std::numeric_limits<int64_t>::min()) + "\n",
627 // 32-bit float
628 "%1 = OpTypeFloat 32\n%2 = OpSpecConstant %1 0\n",
629 "%1 = OpTypeFloat 32\n%2 = OpSpecConstant %1 13.5\n",
630 "%1 = OpTypeFloat 32\n%2 = OpSpecConstant %1 -12.5\n",
631 // 64-bit float
632 "%1 = OpTypeFloat 64\n%2 = OpSpecConstant %1 0\n",
633 "%1 = OpTypeFloat 64\n%2 = OpSpecConstant %1 1.79767e+308\n",
634 "%1 = OpTypeFloat 64\n%2 = OpSpecConstant %1 -1.79767e+308\n",
635 }), );
636
637 // Test OpSpecConstantOp
638
639 using OpSpecConstantOpTestWithIds =
640 spvtest::TextToBinaryTestBase<::testing::TestWithParam<EnumCase<SpvOp>>>;
641
642 // The operands to the OpSpecConstantOp opcode are all Ids.
TEST_P(OpSpecConstantOpTestWithIds,Assembly)643 TEST_P(OpSpecConstantOpTestWithIds, Assembly) {
644 std::stringstream input;
645 input << "%2 = OpSpecConstantOp %1 " << GetParam().name();
646 for (auto id : GetParam().operands()) input << " %" << id;
647 input << "\n";
648
649 EXPECT_THAT(CompiledInstructions(input.str()),
650 Eq(MakeInstruction(SpvOpSpecConstantOp,
651 {1, 2, uint32_t(GetParam().value())},
652 GetParam().operands())));
653
654 // Check the disassembler as well.
655 EXPECT_THAT(EncodeAndDecodeSuccessfully(input.str()), input.str());
656 }
657
658 // clang-format off
659 #define CASE1(NAME) { SpvOp##NAME, #NAME, {3} }
660 #define CASE2(NAME) { SpvOp##NAME, #NAME, {3, 4} }
661 #define CASE3(NAME) { SpvOp##NAME, #NAME, {3, 4, 5} }
662 #define CASE4(NAME) { SpvOp##NAME, #NAME, {3, 4, 5, 6} }
663 #define CASE5(NAME) { SpvOp##NAME, #NAME, {3, 4, 5, 6, 7} }
664 #define CASE6(NAME) { SpvOp##NAME, #NAME, {3, 4, 5, 6, 7, 8} }
665 INSTANTIATE_TEST_CASE_P(
666 TextToBinaryOpSpecConstantOp, OpSpecConstantOpTestWithIds,
667 ::testing::ValuesIn(std::vector<EnumCase<SpvOp>>{
668 // Conversion
669 CASE1(SConvert),
670 CASE1(FConvert),
671 CASE1(ConvertFToS),
672 CASE1(ConvertSToF),
673 CASE1(ConvertFToU),
674 CASE1(ConvertUToF),
675 CASE1(UConvert),
676 CASE1(ConvertPtrToU),
677 CASE1(ConvertUToPtr),
678 CASE1(GenericCastToPtr),
679 CASE1(PtrCastToGeneric),
680 CASE1(Bitcast),
681 CASE1(QuantizeToF16),
682 // Arithmetic
683 CASE1(SNegate),
684 CASE1(Not),
685 CASE2(IAdd),
686 CASE2(ISub),
687 CASE2(IMul),
688 CASE2(UDiv),
689 CASE2(SDiv),
690 CASE2(UMod),
691 CASE2(SRem),
692 CASE2(SMod),
693 CASE2(ShiftRightLogical),
694 CASE2(ShiftRightArithmetic),
695 CASE2(ShiftLeftLogical),
696 CASE2(BitwiseOr),
697 CASE2(BitwiseAnd),
698 CASE2(BitwiseXor),
699 CASE1(FNegate),
700 CASE2(FAdd),
701 CASE2(FSub),
702 CASE2(FMul),
703 CASE2(FDiv),
704 CASE2(FRem),
705 CASE2(FMod),
706 // Composite operations use literal numbers. So they're in another test.
707 // Logical
708 CASE2(LogicalOr),
709 CASE2(LogicalAnd),
710 CASE1(LogicalNot),
711 CASE2(LogicalEqual),
712 CASE2(LogicalNotEqual),
713 CASE3(Select),
714 // Comparison
715 CASE2(IEqual),
716 CASE2(INotEqual), // Allowed in 1.0 Rev 7
717 CASE2(ULessThan),
718 CASE2(SLessThan),
719 CASE2(UGreaterThan),
720 CASE2(SGreaterThan),
721 CASE2(ULessThanEqual),
722 CASE2(SLessThanEqual),
723 CASE2(UGreaterThanEqual),
724 CASE2(SGreaterThanEqual),
725 // Memory
726 // For AccessChain, there is a base Id, then a sequence of index Ids.
727 // Having no index Ids is a corner case.
728 CASE1(AccessChain),
729 CASE2(AccessChain),
730 CASE6(AccessChain),
731 CASE1(InBoundsAccessChain),
732 CASE2(InBoundsAccessChain),
733 CASE6(InBoundsAccessChain),
734 // PtrAccessChain also has an element Id.
735 CASE2(PtrAccessChain),
736 CASE3(PtrAccessChain),
737 CASE6(PtrAccessChain),
738 CASE2(InBoundsPtrAccessChain),
739 CASE3(InBoundsPtrAccessChain),
740 CASE6(InBoundsPtrAccessChain),
741 }),);
742 #undef CASE1
743 #undef CASE2
744 #undef CASE3
745 #undef CASE4
746 #undef CASE5
747 #undef CASE6
748 // clang-format on
749
750 using OpSpecConstantOpTestWithTwoIdsThenLiteralNumbers =
751 spvtest::TextToBinaryTestBase<::testing::TestWithParam<EnumCase<SpvOp>>>;
752
753 // The operands to the OpSpecConstantOp opcode are two Ids followed by a
754 // sequence of literal numbers.
TEST_P(OpSpecConstantOpTestWithTwoIdsThenLiteralNumbers,Assembly)755 TEST_P(OpSpecConstantOpTestWithTwoIdsThenLiteralNumbers, Assembly) {
756 std::stringstream input;
757 input << "%2 = OpSpecConstantOp %1 " << GetParam().name() << " %3 %4";
758 for (auto number : GetParam().operands()) input << " " << number;
759 input << "\n";
760
761 EXPECT_THAT(CompiledInstructions(input.str()),
762 Eq(MakeInstruction(SpvOpSpecConstantOp,
763 {1, 2, uint32_t(GetParam().value()), 3, 4},
764 GetParam().operands())));
765
766 // Check the disassembler as well.
767 EXPECT_THAT(EncodeAndDecodeSuccessfully(input.str()), input.str());
768 }
769
770 #define CASE(NAME) SpvOp##NAME, #NAME
771 INSTANTIATE_TEST_CASE_P(
772 TextToBinaryOpSpecConstantOp,
773 OpSpecConstantOpTestWithTwoIdsThenLiteralNumbers,
774 ::testing::ValuesIn(std::vector<EnumCase<SpvOp>>{
775 // For VectorShuffle, there are two vector operands, and at least
776 // two selector Ids. OpenCL can have up to 16-element vectors.
777 {CASE(VectorShuffle), {0, 0}},
778 {CASE(VectorShuffle), {4, 3, 2, 1}},
779 {CASE(VectorShuffle), {0, 2, 4, 6, 1, 3, 5, 7}},
780 {CASE(VectorShuffle),
781 {15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}},
782 // For CompositeInsert, there is an object to insert, the target
783 // composite, and then literal indices.
784 {CASE(CompositeInsert), {0}},
785 {CASE(CompositeInsert), {4, 3, 99, 1}},
786 }), );
787
788 using OpSpecConstantOpTestWithOneIdThenLiteralNumbers =
789 spvtest::TextToBinaryTestBase<::testing::TestWithParam<EnumCase<SpvOp>>>;
790
791 // The operands to the OpSpecConstantOp opcode are one Id followed by a
792 // sequence of literal numbers.
TEST_P(OpSpecConstantOpTestWithOneIdThenLiteralNumbers,Assembly)793 TEST_P(OpSpecConstantOpTestWithOneIdThenLiteralNumbers, Assembly) {
794 std::stringstream input;
795 input << "%2 = OpSpecConstantOp %1 " << GetParam().name() << " %3";
796 for (auto number : GetParam().operands()) input << " " << number;
797 input << "\n";
798
799 EXPECT_THAT(CompiledInstructions(input.str()),
800 Eq(MakeInstruction(SpvOpSpecConstantOp,
801 {1, 2, uint32_t(GetParam().value()), 3},
802 GetParam().operands())));
803
804 // Check the disassembler as well.
805 EXPECT_THAT(EncodeAndDecodeSuccessfully(input.str()), input.str());
806 }
807
808 #define CASE(NAME) SpvOp##NAME, #NAME
809 INSTANTIATE_TEST_CASE_P(
810 TextToBinaryOpSpecConstantOp,
811 OpSpecConstantOpTestWithOneIdThenLiteralNumbers,
812 ::testing::ValuesIn(std::vector<EnumCase<SpvOp>>{
813 // For CompositeExtract, the universal limit permits up to 255 literal
814 // indices. Let's only test a few.
815 {CASE(CompositeExtract), {0}},
816 {CASE(CompositeExtract), {0, 99, 42, 16, 17, 12, 19}},
817 }), );
818
819 // TODO(dneto): OpConstantTrue
820 // TODO(dneto): OpConstantFalse
821 // TODO(dneto): OpConstantComposite
822 // TODO(dneto): OpConstantSampler: other variations Param is 0 or 1
823 // TODO(dneto): OpConstantNull
824 // TODO(dneto): OpSpecConstantTrue
825 // TODO(dneto): OpSpecConstantFalse
826 // TODO(dneto): OpSpecConstantComposite
827 // TODO(dneto): Negative tests for OpSpecConstantOp
828
829 } // namespace
830 } // namespace spvtools
831