• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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