| // Copyright (c) 2015-2016 The Khronos Group Inc. | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| // Assembler tests for instructions in the "Annotation" section of the | |
| // SPIR-V spec. | |
| #include <sstream> | |
| #include <string> | |
| #include <tuple> | |
| #include <vector> | |
| #include "gmock/gmock.h" | |
| #include "source/util/string_utils.h" | |
| #include "test/test_fixture.h" | |
| #include "test/unit_spirv.h" | |
| namespace spvtools { | |
| namespace { | |
| using spvtest::EnumCase; | |
| using spvtest::MakeInstruction; | |
| using utils::MakeVector; | |
| using spvtest::TextToBinaryTest; | |
| using ::testing::Combine; | |
| using ::testing::Eq; | |
| using ::testing::Values; | |
| using ::testing::ValuesIn; | |
| // Test OpDecorate | |
| using OpDecorateSimpleTest = | |
| spvtest::TextToBinaryTestBase<::testing::TestWithParam< | |
| std::tuple<spv_target_env, EnumCase<SpvDecoration>>>>; | |
| TEST_P(OpDecorateSimpleTest, AnySimpleDecoration) { | |
| // This string should assemble, but should not validate. | |
| std::stringstream input; | |
| input << "OpDecorate %1 " << std::get<1>(GetParam()).name(); | |
| for (auto operand : std::get<1>(GetParam()).operands()) | |
| input << " " << operand; | |
| input << std::endl; | |
| EXPECT_THAT(CompiledInstructions(input.str(), std::get<0>(GetParam())), | |
| Eq(MakeInstruction(SpvOpDecorate, | |
| {1, uint32_t(std::get<1>(GetParam()).value())}, | |
| std::get<1>(GetParam()).operands()))); | |
| // Also check disassembly. | |
| EXPECT_THAT( | |
| EncodeAndDecodeSuccessfully(input.str(), SPV_BINARY_TO_TEXT_OPTION_NONE, | |
| std::get<0>(GetParam())), | |
| Eq(input.str())); | |
| } | |
| // Like above, but parameters to the decoration are IDs. | |
| using OpDecorateSimpleIdTest = | |
| spvtest::TextToBinaryTestBase<::testing::TestWithParam< | |
| std::tuple<spv_target_env, EnumCase<SpvDecoration>>>>; | |
| TEST_P(OpDecorateSimpleIdTest, AnySimpleDecoration) { | |
| // This string should assemble, but should not validate. | |
| std::stringstream input; | |
| input << "OpDecorateId %1 " << std::get<1>(GetParam()).name(); | |
| for (auto operand : std::get<1>(GetParam()).operands()) | |
| input << " %" << operand; | |
| input << std::endl; | |
| EXPECT_THAT(CompiledInstructions(input.str(), std::get<0>(GetParam())), | |
| Eq(MakeInstruction(SpvOpDecorateId, | |
| {1, uint32_t(std::get<1>(GetParam()).value())}, | |
| std::get<1>(GetParam()).operands()))); | |
| // Also check disassembly. | |
| EXPECT_THAT( | |
| EncodeAndDecodeSuccessfully(input.str(), SPV_BINARY_TO_TEXT_OPTION_NONE, | |
| std::get<0>(GetParam())), | |
| Eq(input.str())); | |
| } | |
| #define CASE(NAME) SpvDecoration##NAME, #NAME | |
| INSTANTIATE_TEST_SUITE_P( | |
| TextToBinaryDecorateSimple, OpDecorateSimpleTest, | |
| Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), | |
| ValuesIn(std::vector<EnumCase<SpvDecoration>>{ | |
| // The operand literal values are arbitrarily chosen, | |
| // but there are the right number of them. | |
| {CASE(RelaxedPrecision), {}}, | |
| {CASE(SpecId), {100}}, | |
| {CASE(Block), {}}, | |
| {CASE(BufferBlock), {}}, | |
| {CASE(RowMajor), {}}, | |
| {CASE(ColMajor), {}}, | |
| {CASE(ArrayStride), {4}}, | |
| {CASE(MatrixStride), {16}}, | |
| {CASE(GLSLShared), {}}, | |
| {CASE(GLSLPacked), {}}, | |
| {CASE(CPacked), {}}, | |
| // Placeholder line for enum value 12 | |
| {CASE(NoPerspective), {}}, | |
| {CASE(Flat), {}}, | |
| {CASE(Patch), {}}, | |
| {CASE(Centroid), {}}, | |
| {CASE(Sample), {}}, | |
| {CASE(Invariant), {}}, | |
| {CASE(Restrict), {}}, | |
| {CASE(Aliased), {}}, | |
| {CASE(Volatile), {}}, | |
| {CASE(Constant), {}}, | |
| {CASE(Coherent), {}}, | |
| {CASE(NonWritable), {}}, | |
| {CASE(NonReadable), {}}, | |
| {CASE(Uniform), {}}, | |
| {CASE(SaturatedConversion), {}}, | |
| {CASE(Stream), {2}}, | |
| {CASE(Location), {6}}, | |
| {CASE(Component), {3}}, | |
| {CASE(Index), {14}}, | |
| {CASE(Binding), {19}}, | |
| {CASE(DescriptorSet), {7}}, | |
| {CASE(Offset), {12}}, | |
| {CASE(XfbBuffer), {1}}, | |
| {CASE(XfbStride), {8}}, | |
| {CASE(NoContraction), {}}, | |
| {CASE(InputAttachmentIndex), {102}}, | |
| {CASE(Alignment), {16}}, | |
| }))); | |
| INSTANTIATE_TEST_SUITE_P(TextToBinaryDecorateSimpleV11, OpDecorateSimpleTest, | |
| Combine(Values(SPV_ENV_UNIVERSAL_1_1), | |
| Values(EnumCase<SpvDecoration>{ | |
| CASE(MaxByteOffset), {128}}))); | |
| INSTANTIATE_TEST_SUITE_P(TextToBinaryDecorateSimpleV14, OpDecorateSimpleTest, | |
| Combine(Values(SPV_ENV_UNIVERSAL_1_4), | |
| ValuesIn(std::vector<EnumCase<SpvDecoration>>{ | |
| {CASE(Uniform), {}}, | |
| }))); | |
| INSTANTIATE_TEST_SUITE_P(TextToBinaryDecorateSimpleIdV14, | |
| OpDecorateSimpleIdTest, | |
| Combine(Values(SPV_ENV_UNIVERSAL_1_4), | |
| ValuesIn(std::vector<EnumCase<SpvDecoration>>{ | |
| // In 1.4, UniformId decoration takes a | |
| // scope Id. | |
| {CASE(UniformId), {1}}, | |
| }))); | |
| #undef CASE | |
| TEST_F(OpDecorateSimpleTest, WrongDecoration) { | |
| EXPECT_THAT(CompileFailure("OpDecorate %1 xxyyzz"), | |
| Eq("Invalid decoration 'xxyyzz'.")); | |
| } | |
| TEST_F(OpDecorateSimpleTest, ExtraOperandsOnDecorationExpectingNone) { | |
| EXPECT_THAT(CompileFailure("OpDecorate %1 RelaxedPrecision 99"), | |
| Eq("Expected <opcode> or <result-id> at the beginning of an " | |
| "instruction, found '99'.")); | |
| } | |
| TEST_F(OpDecorateSimpleTest, ExtraOperandsOnDecorationExpectingOne) { | |
| EXPECT_THAT(CompileFailure("OpDecorate %1 SpecId 99 100"), | |
| Eq("Expected <opcode> or <result-id> at the beginning of an " | |
| "instruction, found '100'.")); | |
| } | |
| TEST_F(OpDecorateSimpleTest, ExtraOperandsOnDecorationExpectingTwo) { | |
| EXPECT_THAT( | |
| CompileFailure("OpDecorate %1 LinkageAttributes \"abc\" Import 42"), | |
| Eq("Expected <opcode> or <result-id> at the beginning of an " | |
| "instruction, found '42'.")); | |
| } | |
| // A single test case for an enum decoration. | |
| struct DecorateEnumCase { | |
| // Place the enum value first, so it's easier to read the binary dumps when | |
| // the test fails. | |
| uint32_t value; // The value within the enum, e.g. Position | |
| std::string name; | |
| uint32_t enum_value; // Which enum, e.g. BuiltIn | |
| std::string enum_name; | |
| }; | |
| using OpDecorateEnumTest = | |
| spvtest::TextToBinaryTestBase<::testing::TestWithParam<DecorateEnumCase>>; | |
| TEST_P(OpDecorateEnumTest, AnyEnumDecoration) { | |
| // This string should assemble, but should not validate. | |
| const std::string input = | |
| "OpDecorate %1 " + GetParam().enum_name + " " + GetParam().name; | |
| EXPECT_THAT(CompiledInstructions(input), | |
| Eq(MakeInstruction(SpvOpDecorate, {1, GetParam().enum_value, | |
| GetParam().value}))); | |
| } | |
| // Test OpDecorate BuiltIn. | |
| // clang-format off | |
| #define CASE(NAME) \ | |
| { SpvBuiltIn##NAME, #NAME, SpvDecorationBuiltIn, "BuiltIn" } | |
| INSTANTIATE_TEST_SUITE_P(TextToBinaryDecorateBuiltIn, OpDecorateEnumTest, | |
| ::testing::ValuesIn(std::vector<DecorateEnumCase>{ | |
| CASE(Position), | |
| CASE(PointSize), | |
| CASE(ClipDistance), | |
| CASE(CullDistance), | |
| CASE(VertexId), | |
| CASE(InstanceId), | |
| CASE(PrimitiveId), | |
| CASE(InvocationId), | |
| CASE(Layer), | |
| CASE(ViewportIndex), | |
| CASE(TessLevelOuter), | |
| CASE(TessLevelInner), | |
| CASE(TessCoord), | |
| CASE(PatchVertices), | |
| CASE(FragCoord), | |
| CASE(PointCoord), | |
| CASE(FrontFacing), | |
| CASE(SampleId), | |
| CASE(SamplePosition), | |
| CASE(SampleMask), | |
| // Value 21 intentionally missing. | |
| CASE(FragDepth), | |
| CASE(HelperInvocation), | |
| CASE(NumWorkgroups), | |
| CASE(WorkgroupSize), | |
| CASE(WorkgroupId), | |
| CASE(LocalInvocationId), | |
| CASE(GlobalInvocationId), | |
| CASE(LocalInvocationIndex), | |
| CASE(WorkDim), | |
| CASE(GlobalSize), | |
| CASE(EnqueuedWorkgroupSize), | |
| CASE(GlobalOffset), | |
| CASE(GlobalLinearId), | |
| // Value 35 intentionally missing. | |
| CASE(SubgroupSize), | |
| CASE(SubgroupMaxSize), | |
| CASE(NumSubgroups), | |
| CASE(NumEnqueuedSubgroups), | |
| CASE(SubgroupId), | |
| CASE(SubgroupLocalInvocationId), | |
| CASE(VertexIndex), | |
| CASE(InstanceIndex), | |
| })); | |
| #undef CASE | |
| // clang-format on | |
| TEST_F(OpDecorateEnumTest, WrongBuiltIn) { | |
| EXPECT_THAT(CompileFailure("OpDecorate %1 BuiltIn xxyyzz"), | |
| Eq("Invalid built-in 'xxyyzz'.")); | |
| } | |
| // Test OpDecorate FuncParamAttr | |
| // clang-format off | |
| #define CASE(NAME) \ | |
| { SpvFunctionParameterAttribute##NAME, #NAME, SpvDecorationFuncParamAttr, "FuncParamAttr" } | |
| INSTANTIATE_TEST_SUITE_P(TextToBinaryDecorateFuncParamAttr, OpDecorateEnumTest, | |
| ::testing::ValuesIn(std::vector<DecorateEnumCase>{ | |
| CASE(Zext), | |
| CASE(Sext), | |
| CASE(ByVal), | |
| CASE(Sret), | |
| CASE(NoAlias), | |
| CASE(NoCapture), | |
| CASE(NoWrite), | |
| CASE(NoReadWrite), | |
| })); | |
| #undef CASE | |
| // clang-format on | |
| TEST_F(OpDecorateEnumTest, WrongFuncParamAttr) { | |
| EXPECT_THAT(CompileFailure("OpDecorate %1 FuncParamAttr xxyyzz"), | |
| Eq("Invalid function parameter attribute 'xxyyzz'.")); | |
| } | |
| // Test OpDecorate FPRoundingMode | |
| // clang-format off | |
| #define CASE(NAME) \ | |
| { SpvFPRoundingMode##NAME, #NAME, SpvDecorationFPRoundingMode, "FPRoundingMode" } | |
| INSTANTIATE_TEST_SUITE_P(TextToBinaryDecorateFPRoundingMode, OpDecorateEnumTest, | |
| ::testing::ValuesIn(std::vector<DecorateEnumCase>{ | |
| CASE(RTE), | |
| CASE(RTZ), | |
| CASE(RTP), | |
| CASE(RTN), | |
| })); | |
| #undef CASE | |
| // clang-format on | |
| TEST_F(OpDecorateEnumTest, WrongFPRoundingMode) { | |
| EXPECT_THAT(CompileFailure("OpDecorate %1 FPRoundingMode xxyyzz"), | |
| Eq("Invalid floating-point rounding mode 'xxyyzz'.")); | |
| } | |
| // Test OpDecorate FPFastMathMode. | |
| // These can by named enums for the single-bit masks. However, we don't support | |
| // symbolic combinations of the masks. Rather, they can use !<immediate> | |
| // syntax, e.g. !0x3 | |
| // clang-format off | |
| #define CASE(ENUM,NAME) \ | |
| { SpvFPFastMathMode##ENUM, #NAME, SpvDecorationFPFastMathMode, "FPFastMathMode" } | |
| INSTANTIATE_TEST_SUITE_P(TextToBinaryDecorateFPFastMathMode, OpDecorateEnumTest, | |
| ::testing::ValuesIn(std::vector<DecorateEnumCase>{ | |
| CASE(MaskNone, None), | |
| CASE(NotNaNMask, NotNaN), | |
| CASE(NotInfMask, NotInf), | |
| CASE(NSZMask, NSZ), | |
| CASE(AllowRecipMask, AllowRecip), | |
| CASE(FastMask, Fast), | |
| })); | |
| #undef CASE | |
| // clang-format on | |
| TEST_F(OpDecorateEnumTest, CombinedFPFastMathMask) { | |
| // Sample a single combination. This ensures we've integrated | |
| // the instruction parsing logic with spvTextParseMask. | |
| const std::string input = "OpDecorate %1 FPFastMathMode NotNaN|NotInf|NSZ"; | |
| const uint32_t expected_enum = SpvDecorationFPFastMathMode; | |
| const uint32_t expected_mask = SpvFPFastMathModeNotNaNMask | | |
| SpvFPFastMathModeNotInfMask | | |
| SpvFPFastMathModeNSZMask; | |
| EXPECT_THAT( | |
| CompiledInstructions(input), | |
| Eq(MakeInstruction(SpvOpDecorate, {1, expected_enum, expected_mask}))); | |
| } | |
| TEST_F(OpDecorateEnumTest, WrongFPFastMathMode) { | |
| EXPECT_THAT( | |
| CompileFailure("OpDecorate %1 FPFastMathMode NotNaN|xxyyzz"), | |
| Eq("Invalid floating-point fast math mode operand 'NotNaN|xxyyzz'.")); | |
| } | |
| // Test OpDecorate Linkage | |
| // A single test case for a linkage | |
| struct DecorateLinkageCase { | |
| uint32_t linkage_type_value; | |
| std::string linkage_type_name; | |
| std::string external_name; | |
| }; | |
| using OpDecorateLinkageTest = spvtest::TextToBinaryTestBase< | |
| ::testing::TestWithParam<DecorateLinkageCase>>; | |
| TEST_P(OpDecorateLinkageTest, AnyLinkageDecoration) { | |
| // This string should assemble, but should not validate. | |
| const std::string input = "OpDecorate %1 LinkageAttributes \"" + | |
| GetParam().external_name + "\" " + | |
| GetParam().linkage_type_name; | |
| std::vector<uint32_t> expected_operands{1, SpvDecorationLinkageAttributes}; | |
| std::vector<uint32_t> encoded_external_name = | |
| MakeVector(GetParam().external_name); | |
| expected_operands.insert(expected_operands.end(), | |
| encoded_external_name.begin(), | |
| encoded_external_name.end()); | |
| expected_operands.push_back(GetParam().linkage_type_value); | |
| EXPECT_THAT(CompiledInstructions(input), | |
| Eq(MakeInstruction(SpvOpDecorate, expected_operands))); | |
| } | |
| // clang-format off | |
| #define CASE(ENUM) SpvLinkageType##ENUM, #ENUM | |
| INSTANTIATE_TEST_SUITE_P(TextToBinaryDecorateLinkage, OpDecorateLinkageTest, | |
| ::testing::ValuesIn(std::vector<DecorateLinkageCase>{ | |
| { CASE(Import), "a" }, | |
| { CASE(Export), "foo" }, | |
| { CASE(Import), "some kind of long name with spaces etc." }, | |
| // TODO(dneto): utf-8, escaping, quoting cases. | |
| })); | |
| #undef CASE | |
| // clang-format on | |
| TEST_F(OpDecorateLinkageTest, WrongType) { | |
| EXPECT_THAT(CompileFailure("OpDecorate %1 LinkageAttributes \"foo\" xxyyzz"), | |
| Eq("Invalid linkage type 'xxyyzz'.")); | |
| } | |
| // Test OpGroupMemberDecorate | |
| TEST_F(TextToBinaryTest, GroupMemberDecorateGoodOneTarget) { | |
| EXPECT_THAT(CompiledInstructions("OpGroupMemberDecorate %group %id0 42"), | |
| Eq(MakeInstruction(SpvOpGroupMemberDecorate, {1, 2, 42}))); | |
| } | |
| TEST_F(TextToBinaryTest, GroupMemberDecorateGoodTwoTargets) { | |
| EXPECT_THAT( | |
| CompiledInstructions("OpGroupMemberDecorate %group %id0 96 %id1 42"), | |
| Eq(MakeInstruction(SpvOpGroupMemberDecorate, {1, 2, 96, 3, 42}))); | |
| } | |
| TEST_F(TextToBinaryTest, GroupMemberDecorateMissingGroupId) { | |
| EXPECT_THAT(CompileFailure("OpGroupMemberDecorate"), | |
| Eq("Expected operand, found end of stream.")); | |
| } | |
| TEST_F(TextToBinaryTest, GroupMemberDecorateInvalidGroupId) { | |
| EXPECT_THAT(CompileFailure("OpGroupMemberDecorate 16"), | |
| Eq("Expected id to start with %.")); | |
| } | |
| TEST_F(TextToBinaryTest, GroupMemberDecorateInvalidTargetId) { | |
| EXPECT_THAT(CompileFailure("OpGroupMemberDecorate %group 12"), | |
| Eq("Expected id to start with %.")); | |
| } | |
| TEST_F(TextToBinaryTest, GroupMemberDecorateMissingTargetMemberNumber) { | |
| EXPECT_THAT(CompileFailure("OpGroupMemberDecorate %group %id0"), | |
| Eq("Expected operand, found end of stream.")); | |
| } | |
| TEST_F(TextToBinaryTest, GroupMemberDecorateInvalidTargetMemberNumber) { | |
| EXPECT_THAT(CompileFailure("OpGroupMemberDecorate %group %id0 %id1"), | |
| Eq("Invalid unsigned integer literal: %id1")); | |
| } | |
| TEST_F(TextToBinaryTest, GroupMemberDecorateInvalidSecondTargetId) { | |
| EXPECT_THAT(CompileFailure("OpGroupMemberDecorate %group %id1 42 12"), | |
| Eq("Expected id to start with %.")); | |
| } | |
| TEST_F(TextToBinaryTest, GroupMemberDecorateMissingSecondTargetMemberNumber) { | |
| EXPECT_THAT(CompileFailure("OpGroupMemberDecorate %group %id0 42 %id1"), | |
| Eq("Expected operand, found end of stream.")); | |
| } | |
| TEST_F(TextToBinaryTest, GroupMemberDecorateInvalidSecondTargetMemberNumber) { | |
| EXPECT_THAT(CompileFailure("OpGroupMemberDecorate %group %id0 42 %id1 %id2"), | |
| Eq("Invalid unsigned integer literal: %id2")); | |
| } | |
| // Test OpMemberDecorate | |
| using OpMemberDecorateSimpleTest = | |
| spvtest::TextToBinaryTestBase<::testing::TestWithParam< | |
| std::tuple<spv_target_env, EnumCase<SpvDecoration>>>>; | |
| TEST_P(OpMemberDecorateSimpleTest, AnySimpleDecoration) { | |
| // This string should assemble, but should not validate. | |
| std::stringstream input; | |
| input << "OpMemberDecorate %1 42 " << std::get<1>(GetParam()).name(); | |
| for (auto operand : std::get<1>(GetParam()).operands()) | |
| input << " " << operand; | |
| input << std::endl; | |
| EXPECT_THAT( | |
| CompiledInstructions(input.str(), std::get<0>(GetParam())), | |
| Eq(MakeInstruction(SpvOpMemberDecorate, | |
| {1, 42, uint32_t(std::get<1>(GetParam()).value())}, | |
| std::get<1>(GetParam()).operands()))); | |
| // Also check disassembly. | |
| EXPECT_THAT( | |
| EncodeAndDecodeSuccessfully(input.str(), SPV_BINARY_TO_TEXT_OPTION_NONE, | |
| std::get<0>(GetParam())), | |
| Eq(input.str())); | |
| } | |
| #define CASE(NAME) SpvDecoration##NAME, #NAME | |
| INSTANTIATE_TEST_SUITE_P( | |
| TextToBinaryDecorateSimple, OpMemberDecorateSimpleTest, | |
| Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), | |
| ValuesIn(std::vector<EnumCase<SpvDecoration>>{ | |
| // The operand literal values are arbitrarily chosen, | |
| // but there are the right number of them. | |
| {CASE(RelaxedPrecision), {}}, | |
| {CASE(SpecId), {100}}, | |
| {CASE(Block), {}}, | |
| {CASE(BufferBlock), {}}, | |
| {CASE(RowMajor), {}}, | |
| {CASE(ColMajor), {}}, | |
| {CASE(ArrayStride), {4}}, | |
| {CASE(MatrixStride), {16}}, | |
| {CASE(GLSLShared), {}}, | |
| {CASE(GLSLPacked), {}}, | |
| {CASE(CPacked), {}}, | |
| // Placeholder line for enum value 12 | |
| {CASE(NoPerspective), {}}, | |
| {CASE(Flat), {}}, | |
| {CASE(Patch), {}}, | |
| {CASE(Centroid), {}}, | |
| {CASE(Sample), {}}, | |
| {CASE(Invariant), {}}, | |
| {CASE(Restrict), {}}, | |
| {CASE(Aliased), {}}, | |
| {CASE(Volatile), {}}, | |
| {CASE(Constant), {}}, | |
| {CASE(Coherent), {}}, | |
| {CASE(NonWritable), {}}, | |
| {CASE(NonReadable), {}}, | |
| {CASE(Uniform), {}}, | |
| {CASE(SaturatedConversion), {}}, | |
| {CASE(Stream), {2}}, | |
| {CASE(Location), {6}}, | |
| {CASE(Component), {3}}, | |
| {CASE(Index), {14}}, | |
| {CASE(Binding), {19}}, | |
| {CASE(DescriptorSet), {7}}, | |
| {CASE(Offset), {12}}, | |
| {CASE(XfbBuffer), {1}}, | |
| {CASE(XfbStride), {8}}, | |
| {CASE(NoContraction), {}}, | |
| {CASE(InputAttachmentIndex), {102}}, | |
| {CASE(Alignment), {16}}, | |
| }))); | |
| INSTANTIATE_TEST_SUITE_P( | |
| TextToBinaryDecorateSimpleV11, OpMemberDecorateSimpleTest, | |
| Combine(Values(SPV_ENV_UNIVERSAL_1_1), | |
| Values(EnumCase<SpvDecoration>{CASE(MaxByteOffset), {128}}))); | |
| #undef CASE | |
| TEST_F(OpMemberDecorateSimpleTest, WrongDecoration) { | |
| EXPECT_THAT(CompileFailure("OpMemberDecorate %1 9 xxyyzz"), | |
| Eq("Invalid decoration 'xxyyzz'.")); | |
| } | |
| TEST_F(OpMemberDecorateSimpleTest, ExtraOperandsOnDecorationExpectingNone) { | |
| EXPECT_THAT(CompileFailure("OpMemberDecorate %1 12 RelaxedPrecision 99"), | |
| Eq("Expected <opcode> or <result-id> at the beginning of an " | |
| "instruction, found '99'.")); | |
| } | |
| TEST_F(OpMemberDecorateSimpleTest, ExtraOperandsOnDecorationExpectingOne) { | |
| EXPECT_THAT(CompileFailure("OpMemberDecorate %1 0 SpecId 99 100"), | |
| Eq("Expected <opcode> or <result-id> at the beginning of an " | |
| "instruction, found '100'.")); | |
| } | |
| TEST_F(OpMemberDecorateSimpleTest, ExtraOperandsOnDecorationExpectingTwo) { | |
| EXPECT_THAT(CompileFailure( | |
| "OpMemberDecorate %1 1 LinkageAttributes \"abc\" Import 42"), | |
| Eq("Expected <opcode> or <result-id> at the beginning of an " | |
| "instruction, found '42'.")); | |
| } | |
| // TODO(dneto): OpMemberDecorate cases for decorations with parameters which | |
| // are: not just lists of literal numbers. | |
| // TODO(dneto): OpDecorationGroup | |
| // TODO(dneto): OpGroupDecorate | |
| } // namespace | |
| } // namespace spvtools |