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