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_SUITE_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_SUITE_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_SUITE_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_SUITE_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_SUITE_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>>;
TEST_P(OpConstantInvalidTypeTest,InvalidTypes)331 TEST_P(OpConstantInvalidTypeTest, InvalidTypes) {
332 const std::string input = "%1 = " + GetParam() +
333 "\n"
334 "%2 = OpConstant %1 0\n";
335 EXPECT_THAT(
336 CompileFailure(input),
337 Eq("Type for Constant must be a scalar floating point or integer type"));
338 }
339
340 // clang-format off
341 INSTANTIATE_TEST_SUITE_P(
342 TextToBinaryOpConstantInvalidValidType, OpConstantInvalidTypeTest,
343 ::testing::ValuesIn(std::vector<std::string>{
344 {"OpTypeVoid",
345 "OpTypeBool",
346 "OpTypeVector %a 32",
347 "OpTypeMatrix %a 32",
348 "OpTypeImage %a 1D 0 0 0 0 Unknown",
349 "OpTypeSampler",
350 "OpTypeSampledImage %a",
351 "OpTypeArray %a %b",
352 "OpTypeRuntimeArray %a",
353 "OpTypeStruct %a",
354 "OpTypeOpaque \"Foo\"",
355 "OpTypePointer UniformConstant %a",
356 "OpTypeFunction %a %b",
357 "OpTypeEvent",
358 "OpTypeDeviceEvent",
359 "OpTypeReserveId",
360 "OpTypeQueue",
361 "OpTypePipe ReadOnly",
362
363 // Skip OpTypeForwardPointer doesn't even produce a result ID.
364 // The assembler errors out if we try to check it in this scenario.
365
366 // Try at least one thing that isn't a type at all
367 "OpNot %a %b"
368 },
369 }));
370 // clang-format on
371
372 using OpSpecConstantValidTest =
373 spvtest::TextToBinaryTestBase<::testing::TestWithParam<ConstantTestCase>>;
374
TEST_P(OpSpecConstantValidTest,ValidTypes)375 TEST_P(OpSpecConstantValidTest, ValidTypes) {
376 const std::string input = "%1 = " + GetParam().constant_type +
377 "\n"
378 "%2 = OpSpecConstant %1 " +
379 GetParam().constant_value + "\n";
380 std::vector<uint32_t> instructions;
381 EXPECT_THAT(CompiledInstructions(input),
382 Eq(GetParam().expected_instructions));
383 }
384
385 // clang-format off
386 INSTANTIATE_TEST_SUITE_P(
387 TextToBinaryOpSpecConstantValid, OpSpecConstantValidTest,
388 ::testing::ValuesIn(std::vector<ConstantTestCase>{
389 // Check 16 bits
390 {"OpTypeInt 16 0", "0x1234",
391 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 16, 0}),
392 MakeInstruction(SpvOpSpecConstant, {1, 2, 0x1234})})},
393 {"OpTypeInt 16 0", "0x8000",
394 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 16, 0}),
395 MakeInstruction(SpvOpSpecConstant, {1, 2, 0x8000})})},
396 {"OpTypeInt 16 1", "0x8000", // Test sign extension.
397 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 16, 1}),
398 MakeInstruction(SpvOpSpecConstant, {1, 2, 0xffff8000})})},
399 {"OpTypeInt 16 1", "-32",
400 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 16, 1}),
401 MakeInstruction(SpvOpSpecConstant, {1, 2, uint32_t(-32)})})},
402 // Check 32 bits
403 {"OpTypeInt 32 0", "42",
404 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 32, 0}),
405 MakeInstruction(SpvOpSpecConstant, {1, 2, 42})})},
406 {"OpTypeInt 32 1", "-32",
407 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 32, 1}),
408 MakeInstruction(SpvOpSpecConstant, {1, 2, uint32_t(-32)})})},
409 {"OpTypeFloat 32", "1.0",
410 Concatenate({MakeInstruction(SpvOpTypeFloat, {1, 32}),
411 MakeInstruction(SpvOpSpecConstant, {1, 2, 0x3f800000})})},
412 {"OpTypeFloat 32", "10.0",
413 Concatenate({MakeInstruction(SpvOpTypeFloat, {1, 32}),
414 MakeInstruction(SpvOpSpecConstant, {1, 2, 0x41200000})})},
415 // Check 48 bits
416 {"OpTypeInt 48 0", "0x1234",
417 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 48, 0}),
418 MakeInstruction(SpvOpSpecConstant, {1, 2, 0x1234, 0})})},
419 {"OpTypeInt 48 0", "0x800000000001",
420 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 48, 0}),
421 MakeInstruction(SpvOpSpecConstant, {1, 2, 1, 0x00008000})})},
422 {"OpTypeInt 48 1", "0x800000000000", // Test sign extension.
423 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 48, 1}),
424 MakeInstruction(SpvOpSpecConstant, {1, 2, 0, 0xffff8000})})},
425 {"OpTypeInt 48 1", "-32",
426 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 48, 1}),
427 MakeInstruction(SpvOpSpecConstant, {1, 2, uint32_t(-32), uint32_t(-1)})})},
428 // Check 64 bits
429 {"OpTypeInt 64 0", "0x1234",
430 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 64, 0}),
431 MakeInstruction(SpvOpSpecConstant, {1, 2, 0x1234, 0})})},
432 {"OpTypeInt 64 1", "0x1234",
433 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 64, 1}),
434 MakeInstruction(SpvOpSpecConstant, {1, 2, 0x1234, 0})})},
435 {"OpTypeInt 64 1", "-42",
436 Concatenate({MakeInstruction(SpvOpTypeInt, {1, 64, 1}),
437 MakeInstruction(SpvOpSpecConstant, {1, 2, uint32_t(-42), uint32_t(-1)})})},
438 }));
439 // clang-format on
440
441 using OpSpecConstantInvalidTypeTest =
442 spvtest::TextToBinaryTestBase<::testing::TestWithParam<std::string>>;
443
TEST_P(OpSpecConstantInvalidTypeTest,InvalidTypes)444 TEST_P(OpSpecConstantInvalidTypeTest, InvalidTypes) {
445 const std::string input = "%1 = " + GetParam() +
446 "\n"
447 "%2 = OpSpecConstant %1 0\n";
448 EXPECT_THAT(CompileFailure(input),
449 Eq("Type for SpecConstant must be a scalar floating point or "
450 "integer type"));
451 }
452
453 // clang-format off
454 INSTANTIATE_TEST_SUITE_P(
455 TextToBinaryOpSpecConstantInvalidValidType, OpSpecConstantInvalidTypeTest,
456 ::testing::ValuesIn(std::vector<std::string>{
457 {"OpTypeVoid",
458 "OpTypeBool",
459 "OpTypeVector %a 32",
460 "OpTypeMatrix %a 32",
461 "OpTypeImage %a 1D 0 0 0 0 Unknown",
462 "OpTypeSampler",
463 "OpTypeSampledImage %a",
464 "OpTypeArray %a %b",
465 "OpTypeRuntimeArray %a",
466 "OpTypeStruct %a",
467 "OpTypeOpaque \"Foo\"",
468 "OpTypePointer UniformConstant %a",
469 "OpTypeFunction %a %b",
470 "OpTypeEvent",
471 "OpTypeDeviceEvent",
472 "OpTypeReserveId",
473 "OpTypeQueue",
474 "OpTypePipe ReadOnly",
475
476 // Skip testing OpTypeForwardPointer because it doesn't even produce a result ID.
477
478 // Try at least one thing that isn't a type at all
479 "OpNot %a %b"
480 },
481 }));
482 // clang-format on
483
484 const int64_t kMaxUnsigned48Bit = (int64_t(1) << 48) - 1;
485 const int64_t kMaxSigned48Bit = (int64_t(1) << 47) - 1;
486 const int64_t kMinSigned48Bit = -kMaxSigned48Bit - 1;
487
488 using ConstantRoundTripTest = RoundTripTest;
489
TEST_P(ConstantRoundTripTest,DisassemblyEqualsAssemblyInput)490 TEST_P(ConstantRoundTripTest, DisassemblyEqualsAssemblyInput) {
491 const std::string assembly = GetParam();
492 EXPECT_THAT(EncodeAndDecodeSuccessfully(assembly), Eq(assembly)) << assembly;
493 }
494
495 INSTANTIATE_TEST_SUITE_P(
496 OpConstantRoundTrip, ConstantRoundTripTest,
497 ::testing::ValuesIn(std::vector<std::string>{
498 // 16 bit
499 "%1 = OpTypeInt 16 0\n%2 = OpConstant %1 0\n",
500 "%1 = OpTypeInt 16 0\n%2 = OpConstant %1 65535\n",
501 "%1 = OpTypeInt 16 1\n%2 = OpConstant %1 -32768\n",
502 "%1 = OpTypeInt 16 1\n%2 = OpConstant %1 32767\n",
503 "%1 = OpTypeInt 32 0\n%2 = OpConstant %1 0\n",
504 // 32 bit
505 std::string("%1 = OpTypeInt 32 0\n%2 = OpConstant %1 0\n"),
506 std::string("%1 = OpTypeInt 32 0\n%2 = OpConstant %1 ") +
507 std::to_string(std::numeric_limits<uint32_t>::max()) + "\n",
508 std::string("%1 = OpTypeInt 32 1\n%2 = OpConstant %1 ") +
509 std::to_string(std::numeric_limits<int32_t>::max()) + "\n",
510 std::string("%1 = OpTypeInt 32 1\n%2 = OpConstant %1 ") +
511 std::to_string(std::numeric_limits<int32_t>::min()) + "\n",
512 // 48 bit
513 std::string("%1 = OpTypeInt 48 0\n%2 = OpConstant %1 0\n"),
514 std::string("%1 = OpTypeInt 48 0\n%2 = OpConstant %1 ") +
515 std::to_string(kMaxUnsigned48Bit) + "\n",
516 std::string("%1 = OpTypeInt 48 1\n%2 = OpConstant %1 ") +
517 std::to_string(kMaxSigned48Bit) + "\n",
518 std::string("%1 = OpTypeInt 48 1\n%2 = OpConstant %1 ") +
519 std::to_string(kMinSigned48Bit) + "\n",
520 // 64 bit
521 std::string("%1 = OpTypeInt 64 0\n%2 = OpConstant %1 0\n"),
522 std::string("%1 = OpTypeInt 64 0\n%2 = OpConstant %1 ") +
523 std::to_string(std::numeric_limits<uint64_t>::max()) + "\n",
524 std::string("%1 = OpTypeInt 64 1\n%2 = OpConstant %1 ") +
525 std::to_string(std::numeric_limits<int64_t>::max()) + "\n",
526 std::string("%1 = OpTypeInt 64 1\n%2 = OpConstant %1 ") +
527 std::to_string(std::numeric_limits<int64_t>::min()) + "\n",
528 // 32-bit float
529 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 0\n",
530 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 13.5\n",
531 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 -12.5\n",
532 // 64-bit float
533 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0\n",
534 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 1.79767e+308\n",
535 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -1.79767e+308\n",
536 }));
537
538 INSTANTIATE_TEST_SUITE_P(
539 OpConstantHalfRoundTrip, ConstantRoundTripTest,
540 ::testing::ValuesIn(std::vector<std::string>{
541 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x0p+0\n",
542 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x0p+0\n",
543 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1p+0\n",
544 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1.1p+0\n",
545 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1.01p-1\n",
546 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1.8p+1\n",
547 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1.ffcp+1\n",
548 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1p+0\n",
549 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1.1p+0\n",
550 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1.01p-1\n",
551 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1.8p+1\n",
552 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1.ffcp+1\n",
553
554 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1p-16\n", // some denorms
555 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1p-24\n",
556 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1p-24\n",
557
558 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1p+16\n", // +inf
559 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1p+16\n", // -inf
560 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1.01p+16\n", // -inf
561 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1.01p+16\n", // nan
562 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1.11p+16\n", // nan
563 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1.ffp+16\n", // nan
564 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1.ffcp+16\n", // nan
565 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1.004p+16\n", // nan
566 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1.01p+16\n", // -nan
567 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1.11p+16\n", // -nan
568 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1.ffp+16\n", // -nan
569 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1.ffcp+16\n", // -nan
570 "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1.004p+16\n", // -nan
571 }));
572
573 // clang-format off
574 // (Clang-format really wants to break up these strings across lines.
575 INSTANTIATE_TEST_SUITE_P(
576 OpConstantRoundTripNonFinite, ConstantRoundTripTest,
577 ::testing::ValuesIn(std::vector<std::string>{
578 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1p+128\n", // -inf
579 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 0x1p+128\n", // inf
580 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1.8p+128\n", // -nan
581 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1.0002p+128\n", // -nan
582 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1.0018p+128\n", // -nan
583 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1.01ep+128\n", // -nan
584 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1.fffffep+128\n", // -nan
585 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 0x1.8p+128\n", // +nan
586 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 0x1.0002p+128\n", // +nan
587 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 0x1.0018p+128\n", // +nan
588 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 0x1.01ep+128\n", // +nan
589 "%1 = OpTypeFloat 32\n%2 = OpConstant %1 0x1.fffffep+128\n", // +nan
590 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1p+1024\n", // -inf
591 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1p+1024\n", // +inf
592 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1.8p+1024\n", // -nan
593 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1.0fp+1024\n", // -nan
594 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1.0000000000001p+1024\n", // -nan
595 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1.00003p+1024\n", // -nan
596 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1.fffffffffffffp+1024\n", // -nan
597 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1.8p+1024\n", // +nan
598 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1.0fp+1024\n", // +nan
599 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1.0000000000001p+1024\n", // -nan
600 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1.00003p+1024\n", // -nan
601 "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1.fffffffffffffp+1024\n", // -nan
602 }));
603 // clang-format on
604
605 INSTANTIATE_TEST_SUITE_P(
606 OpSpecConstantRoundTrip, ConstantRoundTripTest,
607 ::testing::ValuesIn(std::vector<std::string>{
608 // 16 bit
609 "%1 = OpTypeInt 16 0\n%2 = OpSpecConstant %1 0\n",
610 "%1 = OpTypeInt 16 0\n%2 = OpSpecConstant %1 65535\n",
611 "%1 = OpTypeInt 16 1\n%2 = OpSpecConstant %1 -32768\n",
612 "%1 = OpTypeInt 16 1\n%2 = OpSpecConstant %1 32767\n",
613 "%1 = OpTypeInt 32 0\n%2 = OpSpecConstant %1 0\n",
614 // 32 bit
615 std::string("%1 = OpTypeInt 32 0\n%2 = OpSpecConstant %1 0\n"),
616 std::string("%1 = OpTypeInt 32 0\n%2 = OpSpecConstant %1 ") +
617 std::to_string(std::numeric_limits<uint32_t>::max()) + "\n",
618 std::string("%1 = OpTypeInt 32 1\n%2 = OpSpecConstant %1 ") +
619 std::to_string(std::numeric_limits<int32_t>::max()) + "\n",
620 std::string("%1 = OpTypeInt 32 1\n%2 = OpSpecConstant %1 ") +
621 std::to_string(std::numeric_limits<int32_t>::min()) + "\n",
622 // 48 bit
623 std::string("%1 = OpTypeInt 48 0\n%2 = OpSpecConstant %1 0\n"),
624 std::string("%1 = OpTypeInt 48 0\n%2 = OpSpecConstant %1 ") +
625 std::to_string(kMaxUnsigned48Bit) + "\n",
626 std::string("%1 = OpTypeInt 48 1\n%2 = OpSpecConstant %1 ") +
627 std::to_string(kMaxSigned48Bit) + "\n",
628 std::string("%1 = OpTypeInt 48 1\n%2 = OpSpecConstant %1 ") +
629 std::to_string(kMinSigned48Bit) + "\n",
630 // 64 bit
631 std::string("%1 = OpTypeInt 64 0\n%2 = OpSpecConstant %1 0\n"),
632 std::string("%1 = OpTypeInt 64 0\n%2 = OpSpecConstant %1 ") +
633 std::to_string(std::numeric_limits<uint64_t>::max()) + "\n",
634 std::string("%1 = OpTypeInt 64 1\n%2 = OpSpecConstant %1 ") +
635 std::to_string(std::numeric_limits<int64_t>::max()) + "\n",
636 std::string("%1 = OpTypeInt 64 1\n%2 = OpSpecConstant %1 ") +
637 std::to_string(std::numeric_limits<int64_t>::min()) + "\n",
638 // 32-bit float
639 "%1 = OpTypeFloat 32\n%2 = OpSpecConstant %1 0\n",
640 "%1 = OpTypeFloat 32\n%2 = OpSpecConstant %1 13.5\n",
641 "%1 = OpTypeFloat 32\n%2 = OpSpecConstant %1 -12.5\n",
642 // 64-bit float
643 "%1 = OpTypeFloat 64\n%2 = OpSpecConstant %1 0\n",
644 "%1 = OpTypeFloat 64\n%2 = OpSpecConstant %1 1.79767e+308\n",
645 "%1 = OpTypeFloat 64\n%2 = OpSpecConstant %1 -1.79767e+308\n",
646 }));
647
648 // Test OpSpecConstantOp
649
650 using OpSpecConstantOpTestWithIds =
651 spvtest::TextToBinaryTestBase<::testing::TestWithParam<EnumCase<SpvOp>>>;
652
653 // The operands to the OpSpecConstantOp opcode are all Ids.
TEST_P(OpSpecConstantOpTestWithIds,Assembly)654 TEST_P(OpSpecConstantOpTestWithIds, Assembly) {
655 std::stringstream input;
656 input << "%2 = OpSpecConstantOp %1 " << GetParam().name();
657 for (auto id : GetParam().operands()) input << " %" << id;
658 input << "\n";
659
660 EXPECT_THAT(CompiledInstructions(input.str()),
661 Eq(MakeInstruction(SpvOpSpecConstantOp,
662 {1, 2, uint32_t(GetParam().value())},
663 GetParam().operands())));
664
665 // Check the disassembler as well.
666 EXPECT_THAT(EncodeAndDecodeSuccessfully(input.str()), input.str());
667 }
668
669 // clang-format off
670 #define CASE1(NAME) { SpvOp##NAME, #NAME, {3} }
671 #define CASE2(NAME) { SpvOp##NAME, #NAME, {3, 4} }
672 #define CASE3(NAME) { SpvOp##NAME, #NAME, {3, 4, 5} }
673 #define CASE4(NAME) { SpvOp##NAME, #NAME, {3, 4, 5, 6} }
674 #define CASE5(NAME) { SpvOp##NAME, #NAME, {3, 4, 5, 6, 7} }
675 #define CASE6(NAME) { SpvOp##NAME, #NAME, {3, 4, 5, 6, 7, 8} }
676 INSTANTIATE_TEST_SUITE_P(
677 TextToBinaryOpSpecConstantOp, OpSpecConstantOpTestWithIds,
678 ::testing::ValuesIn(std::vector<EnumCase<SpvOp>>{
679 // Conversion
680 CASE1(SConvert),
681 CASE1(FConvert),
682 CASE1(ConvertFToS),
683 CASE1(ConvertSToF),
684 CASE1(ConvertFToU),
685 CASE1(ConvertUToF),
686 CASE1(UConvert),
687 CASE1(ConvertPtrToU),
688 CASE1(ConvertUToPtr),
689 CASE1(GenericCastToPtr),
690 CASE1(PtrCastToGeneric),
691 CASE1(Bitcast),
692 CASE1(QuantizeToF16),
693 // Arithmetic
694 CASE1(SNegate),
695 CASE1(Not),
696 CASE2(IAdd),
697 CASE2(ISub),
698 CASE2(IMul),
699 CASE2(UDiv),
700 CASE2(SDiv),
701 CASE2(UMod),
702 CASE2(SRem),
703 CASE2(SMod),
704 CASE2(ShiftRightLogical),
705 CASE2(ShiftRightArithmetic),
706 CASE2(ShiftLeftLogical),
707 CASE2(BitwiseOr),
708 CASE2(BitwiseAnd),
709 CASE2(BitwiseXor),
710 CASE1(FNegate),
711 CASE2(FAdd),
712 CASE2(FSub),
713 CASE2(FMul),
714 CASE2(FDiv),
715 CASE2(FRem),
716 CASE2(FMod),
717 // Composite operations use literal numbers. So they're in another test.
718 // Logical
719 CASE2(LogicalOr),
720 CASE2(LogicalAnd),
721 CASE1(LogicalNot),
722 CASE2(LogicalEqual),
723 CASE2(LogicalNotEqual),
724 CASE3(Select),
725 // Comparison
726 CASE2(IEqual),
727 CASE2(INotEqual), // Allowed in 1.0 Rev 7
728 CASE2(ULessThan),
729 CASE2(SLessThan),
730 CASE2(UGreaterThan),
731 CASE2(SGreaterThan),
732 CASE2(ULessThanEqual),
733 CASE2(SLessThanEqual),
734 CASE2(UGreaterThanEqual),
735 CASE2(SGreaterThanEqual),
736 // Memory
737 // For AccessChain, there is a base Id, then a sequence of index Ids.
738 // Having no index Ids is a corner case.
739 CASE1(AccessChain),
740 CASE2(AccessChain),
741 CASE6(AccessChain),
742 CASE1(InBoundsAccessChain),
743 CASE2(InBoundsAccessChain),
744 CASE6(InBoundsAccessChain),
745 // PtrAccessChain also has an element Id.
746 CASE2(PtrAccessChain),
747 CASE3(PtrAccessChain),
748 CASE6(PtrAccessChain),
749 CASE2(InBoundsPtrAccessChain),
750 CASE3(InBoundsPtrAccessChain),
751 CASE6(InBoundsPtrAccessChain),
752 }));
753 #undef CASE1
754 #undef CASE2
755 #undef CASE3
756 #undef CASE4
757 #undef CASE5
758 #undef CASE6
759 // clang-format on
760
761 using OpSpecConstantOpTestWithTwoIdsThenLiteralNumbers =
762 spvtest::TextToBinaryTestBase<::testing::TestWithParam<EnumCase<SpvOp>>>;
763
764 // The operands to the OpSpecConstantOp opcode are two Ids followed by a
765 // sequence of literal numbers.
TEST_P(OpSpecConstantOpTestWithTwoIdsThenLiteralNumbers,Assembly)766 TEST_P(OpSpecConstantOpTestWithTwoIdsThenLiteralNumbers, Assembly) {
767 std::stringstream input;
768 input << "%2 = OpSpecConstantOp %1 " << GetParam().name() << " %3 %4";
769 for (auto number : GetParam().operands()) input << " " << number;
770 input << "\n";
771
772 EXPECT_THAT(CompiledInstructions(input.str()),
773 Eq(MakeInstruction(SpvOpSpecConstantOp,
774 {1, 2, uint32_t(GetParam().value()), 3, 4},
775 GetParam().operands())));
776
777 // Check the disassembler as well.
778 EXPECT_THAT(EncodeAndDecodeSuccessfully(input.str()), input.str());
779 }
780
781 #define CASE(NAME) SpvOp##NAME, #NAME
782 INSTANTIATE_TEST_SUITE_P(
783 TextToBinaryOpSpecConstantOp,
784 OpSpecConstantOpTestWithTwoIdsThenLiteralNumbers,
785 ::testing::ValuesIn(std::vector<EnumCase<SpvOp>>{
786 // For VectorShuffle, there are two vector operands, and at least
787 // two selector Ids. OpenCL can have up to 16-element vectors.
788 {CASE(VectorShuffle), {0, 0}},
789 {CASE(VectorShuffle), {4, 3, 2, 1}},
790 {CASE(VectorShuffle), {0, 2, 4, 6, 1, 3, 5, 7}},
791 {CASE(VectorShuffle),
792 {15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}},
793 // For CompositeInsert, there is an object to insert, the target
794 // composite, and then literal indices.
795 {CASE(CompositeInsert), {0}},
796 {CASE(CompositeInsert), {4, 3, 99, 1}},
797 }));
798
799 using OpSpecConstantOpTestWithOneIdThenLiteralNumbers =
800 spvtest::TextToBinaryTestBase<::testing::TestWithParam<EnumCase<SpvOp>>>;
801
802 // The operands to the OpSpecConstantOp opcode are one Id followed by a
803 // sequence of literal numbers.
TEST_P(OpSpecConstantOpTestWithOneIdThenLiteralNumbers,Assembly)804 TEST_P(OpSpecConstantOpTestWithOneIdThenLiteralNumbers, Assembly) {
805 std::stringstream input;
806 input << "%2 = OpSpecConstantOp %1 " << GetParam().name() << " %3";
807 for (auto number : GetParam().operands()) input << " " << number;
808 input << "\n";
809
810 EXPECT_THAT(CompiledInstructions(input.str()),
811 Eq(MakeInstruction(SpvOpSpecConstantOp,
812 {1, 2, uint32_t(GetParam().value()), 3},
813 GetParam().operands())));
814
815 // Check the disassembler as well.
816 EXPECT_THAT(EncodeAndDecodeSuccessfully(input.str()), input.str());
817 }
818
819 #define CASE(NAME) SpvOp##NAME, #NAME
820 INSTANTIATE_TEST_SUITE_P(
821 TextToBinaryOpSpecConstantOp,
822 OpSpecConstantOpTestWithOneIdThenLiteralNumbers,
823 ::testing::ValuesIn(std::vector<EnumCase<SpvOp>>{
824 // For CompositeExtract, the universal limit permits up to 255 literal
825 // indices. Let's only test a few.
826 {CASE(CompositeExtract), {0}},
827 {CASE(CompositeExtract), {0, 99, 42, 16, 17, 12, 19}},
828 }));
829
830 // TODO(dneto): OpConstantTrue
831 // TODO(dneto): OpConstantFalse
832 // TODO(dneto): OpConstantComposite
833 // TODO(dneto): OpConstantSampler: other variations Param is 0 or 1
834 // TODO(dneto): OpConstantNull
835 // TODO(dneto): OpSpecConstantTrue
836 // TODO(dneto): OpSpecConstantFalse
837 // TODO(dneto): OpSpecConstantComposite
838 // TODO(dneto): Negative tests for OpSpecConstantOp
839
840 } // namespace
841 } // namespace spvtools
842