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 "Annotation" section of the
16// SPIR-V spec.
17
18#include <sstream>
19#include <string>
20#include <tuple>
21#include <vector>
22
23#include "gmock/gmock.h"
24#include "source/util/string_utils.h"
25#include "test/test_fixture.h"
26#include "test/unit_spirv.h"
27
28namespace spvtools {
29namespace {
30
31using spvtest::EnumCase;
32using spvtest::MakeInstruction;
33using utils::MakeVector;
34using spvtest::TextToBinaryTest;
35using ::testing::Combine;
36using ::testing::Eq;
37using ::testing::Values;
38using ::testing::ValuesIn;
39
40// Test OpDecorate
41
42using OpDecorateSimpleTest =
43    spvtest::TextToBinaryTestBase<::testing::TestWithParam<
44        std::tuple<spv_target_env, EnumCase<spv::Decoration>>>>;
45
46TEST_P(OpDecorateSimpleTest, AnySimpleDecoration) {
47  // This string should assemble, but should not validate.
48  std::stringstream input;
49  input << "OpDecorate %1 " << std::get<1>(GetParam()).name();
50  for (auto operand : std::get<1>(GetParam()).operands())
51    input << " " << operand;
52  input << std::endl;
53  EXPECT_THAT(CompiledInstructions(input.str(), std::get<0>(GetParam())),
54              Eq(MakeInstruction(spv::Op::OpDecorate,
55                                 {1, uint32_t(std::get<1>(GetParam()).value())},
56                                 std::get<1>(GetParam()).operands())));
57  // Also check disassembly.
58  EXPECT_THAT(
59      EncodeAndDecodeSuccessfully(input.str(), SPV_BINARY_TO_TEXT_OPTION_NONE,
60                                  std::get<0>(GetParam())),
61      Eq(input.str()));
62}
63
64// Like above, but parameters to the decoration are IDs.
65using OpDecorateSimpleIdTest =
66    spvtest::TextToBinaryTestBase<::testing::TestWithParam<
67        std::tuple<spv_target_env, EnumCase<spv::Decoration>>>>;
68
69TEST_P(OpDecorateSimpleIdTest, AnySimpleDecoration) {
70  // This string should assemble, but should not validate.
71  std::stringstream input;
72  input << "OpDecorateId %1 " << std::get<1>(GetParam()).name();
73  for (auto operand : std::get<1>(GetParam()).operands())
74    input << " %" << operand;
75  input << std::endl;
76  EXPECT_THAT(CompiledInstructions(input.str(), std::get<0>(GetParam())),
77              Eq(MakeInstruction(spv::Op::OpDecorateId,
78                                 {1, uint32_t(std::get<1>(GetParam()).value())},
79                                 std::get<1>(GetParam()).operands())));
80  // Also check disassembly.
81  EXPECT_THAT(
82      EncodeAndDecodeSuccessfully(input.str(), SPV_BINARY_TO_TEXT_OPTION_NONE,
83                                  std::get<0>(GetParam())),
84      Eq(input.str()));
85}
86
87#define CASE(NAME) spv::Decoration::NAME, #NAME
88INSTANTIATE_TEST_SUITE_P(
89    TextToBinaryDecorateSimple, OpDecorateSimpleTest,
90    Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
91            ValuesIn(std::vector<EnumCase<spv::Decoration>>{
92                // The operand literal values are arbitrarily chosen,
93                // but there are the right number of them.
94                {CASE(RelaxedPrecision), {}},
95                {CASE(SpecId), {100}},
96                {CASE(Block), {}},
97                {CASE(BufferBlock), {}},
98                {CASE(RowMajor), {}},
99                {CASE(ColMajor), {}},
100                {CASE(ArrayStride), {4}},
101                {CASE(MatrixStride), {16}},
102                {CASE(GLSLShared), {}},
103                {CASE(GLSLPacked), {}},
104                {CASE(CPacked), {}},
105                // Placeholder line for enum value 12
106                {CASE(NoPerspective), {}},
107                {CASE(Flat), {}},
108                {CASE(Patch), {}},
109                {CASE(Centroid), {}},
110                {CASE(Sample), {}},
111                {CASE(Invariant), {}},
112                {CASE(Restrict), {}},
113                {CASE(Aliased), {}},
114                {CASE(Volatile), {}},
115                {CASE(Constant), {}},
116                {CASE(Coherent), {}},
117                {CASE(NonWritable), {}},
118                {CASE(NonReadable), {}},
119                {CASE(Uniform), {}},
120                {CASE(SaturatedConversion), {}},
121                {CASE(Stream), {2}},
122                {CASE(Location), {6}},
123                {CASE(Component), {3}},
124                {CASE(Index), {14}},
125                {CASE(Binding), {19}},
126                {CASE(DescriptorSet), {7}},
127                {CASE(Offset), {12}},
128                {CASE(XfbBuffer), {1}},
129                {CASE(XfbStride), {8}},
130                {CASE(NoContraction), {}},
131                {CASE(InputAttachmentIndex), {102}},
132                {CASE(Alignment), {16}},
133            })));
134
135INSTANTIATE_TEST_SUITE_P(TextToBinaryDecorateSimpleV11, OpDecorateSimpleTest,
136                         Combine(Values(SPV_ENV_UNIVERSAL_1_1),
137                                 Values(EnumCase<spv::Decoration>{
138                                     CASE(MaxByteOffset), {128}})));
139
140INSTANTIATE_TEST_SUITE_P(
141    TextToBinaryDecorateSimpleV14, OpDecorateSimpleTest,
142    Combine(Values(SPV_ENV_UNIVERSAL_1_4),
143            ValuesIn(std::vector<EnumCase<spv::Decoration>>{
144                {CASE(Uniform), {}},
145            })));
146
147INSTANTIATE_TEST_SUITE_P(
148    TextToBinaryDecorateSimpleIdV14, OpDecorateSimpleIdTest,
149    Combine(Values(SPV_ENV_UNIVERSAL_1_4),
150            ValuesIn(std::vector<EnumCase<spv::Decoration>>{
151                // In 1.4, UniformId decoration takes a
152                // scope Id.
153                {CASE(UniformId), {1}},
154            })));
155#undef CASE
156
157TEST_F(OpDecorateSimpleTest, WrongDecoration) {
158  EXPECT_THAT(CompileFailure("OpDecorate %1 xxyyzz"),
159              Eq("Invalid decoration 'xxyyzz'."));
160}
161
162TEST_F(OpDecorateSimpleTest, ExtraOperandsOnDecorationExpectingNone) {
163  EXPECT_THAT(CompileFailure("OpDecorate %1 RelaxedPrecision 99"),
164              Eq("Expected <opcode> or <result-id> at the beginning of an "
165                 "instruction, found '99'."));
166}
167
168TEST_F(OpDecorateSimpleTest, ExtraOperandsOnDecorationExpectingOne) {
169  EXPECT_THAT(CompileFailure("OpDecorate %1 SpecId 99 100"),
170              Eq("Expected <opcode> or <result-id> at the beginning of an "
171                 "instruction, found '100'."));
172}
173
174TEST_F(OpDecorateSimpleTest, ExtraOperandsOnDecorationExpectingTwo) {
175  EXPECT_THAT(
176      CompileFailure("OpDecorate %1 LinkageAttributes \"abc\" Import 42"),
177      Eq("Expected <opcode> or <result-id> at the beginning of an "
178         "instruction, found '42'."));
179}
180
181// A single test case for an enum decoration.
182struct DecorateEnumCase {
183  // Place the enum value first, so it's easier to read the binary dumps when
184  // the test fails.
185  uint32_t value;  // The value within the enum, e.g. Position
186  std::string name;
187  uint32_t enum_value;  // Which enum, e.g. BuiltIn
188  std::string enum_name;
189};
190
191using OpDecorateEnumTest =
192    spvtest::TextToBinaryTestBase<::testing::TestWithParam<DecorateEnumCase>>;
193
194TEST_P(OpDecorateEnumTest, AnyEnumDecoration) {
195  // This string should assemble, but should not validate.
196  const std::string input =
197      "OpDecorate %1 " + GetParam().enum_name + " " + GetParam().name;
198  EXPECT_THAT(CompiledInstructions(input),
199              Eq(MakeInstruction(spv::Op::OpDecorate, {1, GetParam().enum_value,
200                                                       GetParam().value})));
201}
202
203// Test OpDecorate BuiltIn.
204// clang-format off
205#define CASE(NAME) \
206  { uint32_t(spv::BuiltIn::NAME), #NAME, uint32_t(spv::Decoration::BuiltIn), "BuiltIn" }
207INSTANTIATE_TEST_SUITE_P(TextToBinaryDecorateBuiltIn, OpDecorateEnumTest,
208                        ::testing::ValuesIn(std::vector<DecorateEnumCase>{
209                            CASE(Position),
210                            CASE(PointSize),
211                            CASE(ClipDistance),
212                            CASE(CullDistance),
213                            CASE(VertexId),
214                            CASE(InstanceId),
215                            CASE(PrimitiveId),
216                            CASE(InvocationId),
217                            CASE(Layer),
218                            CASE(ViewportIndex),
219                            CASE(TessLevelOuter),
220                            CASE(TessLevelInner),
221                            CASE(TessCoord),
222                            CASE(PatchVertices),
223                            CASE(FragCoord),
224                            CASE(PointCoord),
225                            CASE(FrontFacing),
226                            CASE(SampleId),
227                            CASE(SamplePosition),
228                            CASE(SampleMask),
229                            // Value 21 intentionally missing.
230                            CASE(FragDepth),
231                            CASE(HelperInvocation),
232                            CASE(NumWorkgroups),
233                            CASE(WorkgroupSize),
234                            CASE(WorkgroupId),
235                            CASE(LocalInvocationId),
236                            CASE(GlobalInvocationId),
237                            CASE(LocalInvocationIndex),
238                            CASE(WorkDim),
239                            CASE(GlobalSize),
240                            CASE(EnqueuedWorkgroupSize),
241                            CASE(GlobalOffset),
242                            CASE(GlobalLinearId),
243                            // Value 35 intentionally missing.
244                            CASE(SubgroupSize),
245                            CASE(SubgroupMaxSize),
246                            CASE(NumSubgroups),
247                            CASE(NumEnqueuedSubgroups),
248                            CASE(SubgroupId),
249                            CASE(SubgroupLocalInvocationId),
250                            CASE(VertexIndex),
251                            CASE(InstanceIndex),
252                        }));
253#undef CASE
254// clang-format on
255
256TEST_F(OpDecorateEnumTest, WrongBuiltIn) {
257  EXPECT_THAT(CompileFailure("OpDecorate %1 BuiltIn xxyyzz"),
258              Eq("Invalid built-in 'xxyyzz'."));
259}
260
261// Test OpDecorate FuncParamAttr
262// clang-format off
263#define CASE(NAME) \
264  { uint32_t(spv::FunctionParameterAttribute::NAME), #NAME, uint32_t(spv::Decoration::FuncParamAttr), "FuncParamAttr" }
265INSTANTIATE_TEST_SUITE_P(TextToBinaryDecorateFuncParamAttr, OpDecorateEnumTest,
266                        ::testing::ValuesIn(std::vector<DecorateEnumCase>{
267                            CASE(Zext),
268                            CASE(Sext),
269                            CASE(ByVal),
270                            CASE(Sret),
271                            CASE(NoAlias),
272                            CASE(NoCapture),
273                            CASE(NoWrite),
274                            CASE(NoReadWrite),
275                      }));
276#undef CASE
277// clang-format on
278
279TEST_F(OpDecorateEnumTest, WrongFuncParamAttr) {
280  EXPECT_THAT(CompileFailure("OpDecorate %1 FuncParamAttr xxyyzz"),
281              Eq("Invalid function parameter attribute 'xxyyzz'."));
282}
283
284// Test OpDecorate FPRoundingMode
285// clang-format off
286#define CASE(NAME) \
287  { uint32_t(spv::FPRoundingMode::NAME), #NAME, uint32_t(spv::Decoration::FPRoundingMode), "FPRoundingMode" }
288INSTANTIATE_TEST_SUITE_P(TextToBinaryDecorateFPRoundingMode, OpDecorateEnumTest,
289                        ::testing::ValuesIn(std::vector<DecorateEnumCase>{
290                            CASE(RTE),
291                            CASE(RTZ),
292                            CASE(RTP),
293                            CASE(RTN),
294                      }));
295#undef CASE
296// clang-format on
297
298TEST_F(OpDecorateEnumTest, WrongFPRoundingMode) {
299  EXPECT_THAT(CompileFailure("OpDecorate %1 FPRoundingMode xxyyzz"),
300              Eq("Invalid floating-point rounding mode 'xxyyzz'."));
301}
302
303// Test OpDecorate FPFastMathMode.
304// These can by named enums for the single-bit masks.  However, we don't support
305// symbolic combinations of the masks.  Rather, they can use !<immediate>
306// syntax, e.g. !0x3
307
308// clang-format off
309#define CASE(ENUM,NAME) \
310  { uint32_t(spv::FPFastMathModeMask::ENUM), #NAME, uint32_t(spv::Decoration::FPFastMathMode), "FPFastMathMode" }
311INSTANTIATE_TEST_SUITE_P(TextToBinaryDecorateFPFastMathMode, OpDecorateEnumTest,
312                        ::testing::ValuesIn(std::vector<DecorateEnumCase>{
313                            CASE(MaskNone, None),
314                            CASE(NotNaN, NotNaN),
315                            CASE(NotInf, NotInf),
316                            CASE(NSZ, NSZ),
317                            CASE(AllowRecip, AllowRecip),
318                            CASE(Fast, Fast),
319                      }));
320#undef CASE
321// clang-format on
322
323TEST_F(OpDecorateEnumTest, CombinedFPFastMathMask) {
324  // Sample a single combination.  This ensures we've integrated
325  // the instruction parsing logic with spvTextParseMask.
326  const std::string input = "OpDecorate %1 FPFastMathMode NotNaN|NotInf|NSZ";
327  const uint32_t expected_enum = uint32_t(spv::Decoration::FPFastMathMode);
328  const uint32_t expected_mask = uint32_t(spv::FPFastMathModeMask::NotNaN) |
329                                 uint32_t(spv::FPFastMathModeMask::NotInf) |
330                                 uint32_t(spv::FPFastMathModeMask::NSZ);
331  EXPECT_THAT(CompiledInstructions(input),
332              Eq(MakeInstruction(spv::Op::OpDecorate,
333                                 {1, expected_enum, expected_mask})));
334}
335
336TEST_F(OpDecorateEnumTest, WrongFPFastMathMode) {
337  EXPECT_THAT(
338      CompileFailure("OpDecorate %1 FPFastMathMode NotNaN|xxyyzz"),
339      Eq("Invalid floating-point fast math mode operand 'NotNaN|xxyyzz'."));
340}
341
342// Test OpDecorate Linkage
343
344// A single test case for a linkage
345struct DecorateLinkageCase {
346  uint32_t linkage_type_value;
347  std::string linkage_type_name;
348  std::string external_name;
349};
350
351using OpDecorateLinkageTest = spvtest::TextToBinaryTestBase<
352    ::testing::TestWithParam<DecorateLinkageCase>>;
353
354TEST_P(OpDecorateLinkageTest, AnyLinkageDecoration) {
355  // This string should assemble, but should not validate.
356  const std::string input = "OpDecorate %1 LinkageAttributes \"" +
357                            GetParam().external_name + "\" " +
358                            GetParam().linkage_type_name;
359  std::vector<uint32_t> expected_operands{
360      1, uint32_t(spv::Decoration::LinkageAttributes)};
361  std::vector<uint32_t> encoded_external_name =
362      MakeVector(GetParam().external_name);
363  expected_operands.insert(expected_operands.end(),
364                           encoded_external_name.begin(),
365                           encoded_external_name.end());
366  expected_operands.push_back(GetParam().linkage_type_value);
367  EXPECT_THAT(CompiledInstructions(input),
368              Eq(MakeInstruction(spv::Op::OpDecorate, expected_operands)));
369}
370
371// clang-format off
372#define CASE(ENUM) uint32_t(spv::LinkageType::ENUM), #ENUM
373INSTANTIATE_TEST_SUITE_P(TextToBinaryDecorateLinkage, OpDecorateLinkageTest,
374                        ::testing::ValuesIn(std::vector<DecorateLinkageCase>{
375                            { CASE(Import), "a" },
376                            { CASE(Export), "foo" },
377                            { CASE(Import), "some kind of long name with spaces etc." },
378                            // TODO(dneto): utf-8, escaping, quoting cases.
379                      }));
380#undef CASE
381// clang-format on
382
383TEST_F(OpDecorateLinkageTest, WrongType) {
384  EXPECT_THAT(CompileFailure("OpDecorate %1 LinkageAttributes \"foo\" xxyyzz"),
385              Eq("Invalid linkage type 'xxyyzz'."));
386}
387
388// Test OpGroupMemberDecorate
389
390TEST_F(TextToBinaryTest, GroupMemberDecorateGoodOneTarget) {
391  EXPECT_THAT(CompiledInstructions("OpGroupMemberDecorate %group %id0 42"),
392              Eq(MakeInstruction(spv::Op::OpGroupMemberDecorate, {1, 2, 42})));
393}
394
395TEST_F(TextToBinaryTest, GroupMemberDecorateGoodTwoTargets) {
396  EXPECT_THAT(
397      CompiledInstructions("OpGroupMemberDecorate %group %id0 96 %id1 42"),
398      Eq(MakeInstruction(spv::Op::OpGroupMemberDecorate, {1, 2, 96, 3, 42})));
399}
400
401TEST_F(TextToBinaryTest, GroupMemberDecorateMissingGroupId) {
402  EXPECT_THAT(CompileFailure("OpGroupMemberDecorate"),
403              Eq("Expected operand for OpGroupMemberDecorate instruction, but "
404                 "found the end of the stream."));
405}
406
407TEST_F(TextToBinaryTest, GroupMemberDecorateInvalidGroupId) {
408  EXPECT_THAT(CompileFailure("OpGroupMemberDecorate 16"),
409              Eq("Expected id to start with %."));
410}
411
412TEST_F(TextToBinaryTest, GroupMemberDecorateInvalidTargetId) {
413  EXPECT_THAT(CompileFailure("OpGroupMemberDecorate %group 12"),
414              Eq("Expected id to start with %."));
415}
416
417TEST_F(TextToBinaryTest, GroupMemberDecorateMissingTargetMemberNumber) {
418  EXPECT_THAT(CompileFailure("OpGroupMemberDecorate %group %id0"),
419              Eq("Expected operand for OpGroupMemberDecorate instruction, but "
420                 "found the end of the stream."));
421}
422
423TEST_F(TextToBinaryTest, GroupMemberDecorateInvalidTargetMemberNumber) {
424  EXPECT_THAT(CompileFailure("OpGroupMemberDecorate %group %id0 %id1"),
425              Eq("Invalid unsigned integer literal: %id1"));
426}
427
428TEST_F(TextToBinaryTest, GroupMemberDecorateInvalidSecondTargetId) {
429  EXPECT_THAT(CompileFailure("OpGroupMemberDecorate %group %id1 42 12"),
430              Eq("Expected id to start with %."));
431}
432
433TEST_F(TextToBinaryTest, GroupMemberDecorateMissingSecondTargetMemberNumber) {
434  EXPECT_THAT(CompileFailure("OpGroupMemberDecorate %group %id0 42 %id1"),
435              Eq("Expected operand for OpGroupMemberDecorate instruction, but "
436                 "found the end of the stream."));
437}
438
439TEST_F(TextToBinaryTest, GroupMemberDecorateInvalidSecondTargetMemberNumber) {
440  EXPECT_THAT(CompileFailure("OpGroupMemberDecorate %group %id0 42 %id1 %id2"),
441              Eq("Invalid unsigned integer literal: %id2"));
442}
443
444// Test OpMemberDecorate
445
446using OpMemberDecorateSimpleTest =
447    spvtest::TextToBinaryTestBase<::testing::TestWithParam<
448        std::tuple<spv_target_env, EnumCase<spv::Decoration>>>>;
449
450TEST_P(OpMemberDecorateSimpleTest, AnySimpleDecoration) {
451  // This string should assemble, but should not validate.
452  std::stringstream input;
453  input << "OpMemberDecorate %1 42 " << std::get<1>(GetParam()).name();
454  for (auto operand : std::get<1>(GetParam()).operands())
455    input << " " << operand;
456  input << std::endl;
457  EXPECT_THAT(
458      CompiledInstructions(input.str(), std::get<0>(GetParam())),
459      Eq(MakeInstruction(spv::Op::OpMemberDecorate,
460                         {1, 42, uint32_t(std::get<1>(GetParam()).value())},
461                         std::get<1>(GetParam()).operands())));
462  // Also check disassembly.
463  EXPECT_THAT(
464      EncodeAndDecodeSuccessfully(input.str(), SPV_BINARY_TO_TEXT_OPTION_NONE,
465                                  std::get<0>(GetParam())),
466      Eq(input.str()));
467}
468
469#define CASE(NAME) spv::Decoration::NAME, #NAME
470INSTANTIATE_TEST_SUITE_P(
471    TextToBinaryDecorateSimple, OpMemberDecorateSimpleTest,
472    Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
473            ValuesIn(std::vector<EnumCase<spv::Decoration>>{
474                // The operand literal values are arbitrarily chosen,
475                // but there are the right number of them.
476                {CASE(RelaxedPrecision), {}},
477                {CASE(SpecId), {100}},
478                {CASE(Block), {}},
479                {CASE(BufferBlock), {}},
480                {CASE(RowMajor), {}},
481                {CASE(ColMajor), {}},
482                {CASE(ArrayStride), {4}},
483                {CASE(MatrixStride), {16}},
484                {CASE(GLSLShared), {}},
485                {CASE(GLSLPacked), {}},
486                {CASE(CPacked), {}},
487                // Placeholder line for enum value 12
488                {CASE(NoPerspective), {}},
489                {CASE(Flat), {}},
490                {CASE(Patch), {}},
491                {CASE(Centroid), {}},
492                {CASE(Sample), {}},
493                {CASE(Invariant), {}},
494                {CASE(Restrict), {}},
495                {CASE(Aliased), {}},
496                {CASE(Volatile), {}},
497                {CASE(Constant), {}},
498                {CASE(Coherent), {}},
499                {CASE(NonWritable), {}},
500                {CASE(NonReadable), {}},
501                {CASE(Uniform), {}},
502                {CASE(SaturatedConversion), {}},
503                {CASE(Stream), {2}},
504                {CASE(Location), {6}},
505                {CASE(Component), {3}},
506                {CASE(Index), {14}},
507                {CASE(Binding), {19}},
508                {CASE(DescriptorSet), {7}},
509                {CASE(Offset), {12}},
510                {CASE(XfbBuffer), {1}},
511                {CASE(XfbStride), {8}},
512                {CASE(NoContraction), {}},
513                {CASE(InputAttachmentIndex), {102}},
514                {CASE(Alignment), {16}},
515            })));
516
517INSTANTIATE_TEST_SUITE_P(
518    TextToBinaryDecorateSimpleV11, OpMemberDecorateSimpleTest,
519    Combine(Values(SPV_ENV_UNIVERSAL_1_1),
520            Values(EnumCase<spv::Decoration>{CASE(MaxByteOffset), {128}})));
521#undef CASE
522
523TEST_F(OpMemberDecorateSimpleTest, WrongDecoration) {
524  EXPECT_THAT(CompileFailure("OpMemberDecorate %1 9 xxyyzz"),
525              Eq("Invalid decoration 'xxyyzz'."));
526}
527
528TEST_F(OpMemberDecorateSimpleTest, ExtraOperandsOnDecorationExpectingNone) {
529  EXPECT_THAT(CompileFailure("OpMemberDecorate %1 12 RelaxedPrecision 99"),
530              Eq("Expected <opcode> or <result-id> at the beginning of an "
531                 "instruction, found '99'."));
532}
533
534TEST_F(OpMemberDecorateSimpleTest, ExtraOperandsOnDecorationExpectingOne) {
535  EXPECT_THAT(CompileFailure("OpMemberDecorate %1 0 SpecId 99 100"),
536              Eq("Expected <opcode> or <result-id> at the beginning of an "
537                 "instruction, found '100'."));
538}
539
540TEST_F(OpMemberDecorateSimpleTest, ExtraOperandsOnDecorationExpectingTwo) {
541  EXPECT_THAT(CompileFailure(
542                  "OpMemberDecorate %1 1 LinkageAttributes \"abc\" Import 42"),
543              Eq("Expected <opcode> or <result-id> at the beginning of an "
544                 "instruction, found '42'."));
545}
546
547// TODO(dneto): OpMemberDecorate cases for decorations with parameters which
548// are: not just lists of literal numbers.
549
550// TODO(dneto): OpDecorationGroup
551// TODO(dneto): OpGroupDecorate
552
553}  // namespace
554}  // namespace spvtools
555