| // 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. |
| |
| #include <vector> |
| |
| #include "gmock/gmock.h" |
| #include "source/operand.h" |
| #include "test/unit_spirv.h" |
| |
| namespace spvtools { |
| namespace { |
| |
| using ::testing::Eq; |
| |
| TEST(OperandPattern, InitiallyEmpty) { |
| spv_operand_pattern_t empty; |
| EXPECT_THAT(empty, Eq(spv_operand_pattern_t{})); |
| EXPECT_EQ(0u, empty.size()); |
| EXPECT_TRUE(empty.empty()); |
| } |
| |
| TEST(OperandPattern, PushBacksAreOnTheRight) { |
| spv_operand_pattern_t pattern; |
| |
| pattern.push_back(SPV_OPERAND_TYPE_ID); |
| EXPECT_THAT(pattern, Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_ID})); |
| EXPECT_EQ(1u, pattern.size()); |
| EXPECT_TRUE(!pattern.empty()); |
| EXPECT_EQ(SPV_OPERAND_TYPE_ID, pattern.back()); |
| |
| pattern.push_back(SPV_OPERAND_TYPE_NONE); |
| EXPECT_THAT(pattern, Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_ID, |
| SPV_OPERAND_TYPE_NONE})); |
| EXPECT_EQ(2u, pattern.size()); |
| EXPECT_TRUE(!pattern.empty()); |
| EXPECT_EQ(SPV_OPERAND_TYPE_NONE, pattern.back()); |
| } |
| |
| TEST(OperandPattern, PopBacksAreOnTheRight) { |
| spv_operand_pattern_t pattern{SPV_OPERAND_TYPE_ID, |
| SPV_OPERAND_TYPE_LITERAL_INTEGER}; |
| |
| pattern.pop_back(); |
| EXPECT_THAT(pattern, Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_ID})); |
| |
| pattern.pop_back(); |
| EXPECT_THAT(pattern, Eq(spv_operand_pattern_t{})); |
| } |
| |
| // A test case for typed mask expansion |
| struct MaskExpansionCase { |
| spv_operand_type_t type; |
| uint32_t mask; |
| spv_operand_pattern_t initial; |
| spv_operand_pattern_t expected; |
| }; |
| |
| using MaskExpansionTest = ::testing::TestWithParam<MaskExpansionCase>; |
| |
| TEST_P(MaskExpansionTest, Sample) { |
| spv_operand_table operandTable = nullptr; |
| auto env = SPV_ENV_UNIVERSAL_1_0; |
| ASSERT_EQ(SPV_SUCCESS, spvOperandTableGet(&operandTable, env)); |
| |
| spv_operand_pattern_t pattern(GetParam().initial); |
| spvPushOperandTypesForMask(env, operandTable, GetParam().type, |
| GetParam().mask, &pattern); |
| EXPECT_THAT(pattern, Eq(GetParam().expected)); |
| } |
| |
| // These macros let us write non-trivial examples without too much text. |
| #define PREFIX0 SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE |
| #define PREFIX1 \ |
| SPV_OPERAND_TYPE_STORAGE_CLASS, SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE, \ |
| SPV_OPERAND_TYPE_ID |
| INSTANTIATE_TEST_CASE_P( |
| OperandPattern, MaskExpansionTest, |
| ::testing::ValuesIn(std::vector<MaskExpansionCase>{ |
| // No bits means no change. |
| {SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS, 0, {PREFIX0}, {PREFIX0}}, |
| // Unknown bits means no change. Use all bits that aren't in the |
| // grammar. |
| // The last mask enum is 0x20 |
| {SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS, |
| 0xffffffc0, |
| {PREFIX1}, |
| {PREFIX1}}, |
| // Volatile has no operands. |
| {SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS, |
| SpvMemoryAccessVolatileMask, |
| {PREFIX0}, |
| {PREFIX0}}, |
| // Aligned has one literal number operand. |
| {SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS, |
| SpvMemoryAccessAlignedMask, |
| {PREFIX1}, |
| {PREFIX1, SPV_OPERAND_TYPE_LITERAL_INTEGER}}, |
| // Volatile with Aligned still has just one literal number operand. |
| {SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS, |
| SpvMemoryAccessVolatileMask | SpvMemoryAccessAlignedMask, |
| {PREFIX1}, |
| {PREFIX1, SPV_OPERAND_TYPE_LITERAL_INTEGER}}, |
| }), ); |
| #undef PREFIX0 |
| #undef PREFIX1 |
| |
| // Returns a vector of all operand types that can be used in a pattern. |
| std::vector<spv_operand_type_t> allOperandTypes() { |
| std::vector<spv_operand_type_t> result; |
| for (int i = 0; i < SPV_OPERAND_TYPE_NUM_OPERAND_TYPES; i++) { |
| result.push_back(spv_operand_type_t(i)); |
| } |
| return result; |
| } |
| |
| using MatchableOperandExpansionTest = |
| ::testing::TestWithParam<spv_operand_type_t>; |
| |
| TEST_P(MatchableOperandExpansionTest, MatchableOperandsDontExpand) { |
| const spv_operand_type_t type = GetParam(); |
| if (!spvOperandIsVariable(type)) { |
| spv_operand_pattern_t pattern; |
| const bool did_expand = spvExpandOperandSequenceOnce(type, &pattern); |
| EXPECT_FALSE(did_expand); |
| EXPECT_THAT(pattern, Eq(spv_operand_pattern_t{})); |
| } |
| } |
| |
| INSTANTIATE_TEST_CASE_P(MatchableOperandExpansion, |
| MatchableOperandExpansionTest, |
| ::testing::ValuesIn(allOperandTypes()), ); |
| |
| using VariableOperandExpansionTest = |
| ::testing::TestWithParam<spv_operand_type_t>; |
| |
| TEST_P(VariableOperandExpansionTest, NonMatchableOperandsExpand) { |
| const spv_operand_type_t type = GetParam(); |
| if (spvOperandIsVariable(type)) { |
| spv_operand_pattern_t pattern; |
| const bool did_expand = spvExpandOperandSequenceOnce(type, &pattern); |
| EXPECT_TRUE(did_expand); |
| EXPECT_FALSE(pattern.empty()); |
| // For the existing rules, the first expansion of a zero-or-more operand |
| // type yields a matchable operand type. This isn't strictly necessary. |
| EXPECT_FALSE(spvOperandIsVariable(pattern.back())); |
| } |
| } |
| |
| INSTANTIATE_TEST_CASE_P(NonMatchableOperandExpansion, |
| VariableOperandExpansionTest, |
| ::testing::ValuesIn(allOperandTypes()), ); |
| |
| TEST(AlternatePatternFollowingImmediate, Empty) { |
| EXPECT_THAT(spvAlternatePatternFollowingImmediate({}), |
| Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV})); |
| } |
| |
| TEST(AlternatePatternFollowingImmediate, SingleElement) { |
| // Spot-check a random selection of types. |
| EXPECT_THAT(spvAlternatePatternFollowingImmediate( |
| {SPV_OPERAND_TYPE_VARIABLE_ID_LITERAL_INTEGER}), |
| Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV})); |
| EXPECT_THAT( |
| spvAlternatePatternFollowingImmediate({SPV_OPERAND_TYPE_CAPABILITY}), |
| Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV})); |
| EXPECT_THAT( |
| spvAlternatePatternFollowingImmediate({SPV_OPERAND_TYPE_LOOP_CONTROL}), |
| Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV})); |
| EXPECT_THAT(spvAlternatePatternFollowingImmediate( |
| {SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER}), |
| Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV})); |
| EXPECT_THAT(spvAlternatePatternFollowingImmediate({SPV_OPERAND_TYPE_ID}), |
| Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV})); |
| } |
| |
| TEST(AlternatePatternFollowingImmediate, SingleResultId) { |
| EXPECT_THAT( |
| spvAlternatePatternFollowingImmediate({SPV_OPERAND_TYPE_RESULT_ID}), |
| Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV, |
| SPV_OPERAND_TYPE_RESULT_ID})); |
| } |
| |
| TEST(AlternatePatternFollowingImmediate, MultipleNonResultIds) { |
| EXPECT_THAT( |
| spvAlternatePatternFollowingImmediate( |
| {SPV_OPERAND_TYPE_VARIABLE_ID_LITERAL_INTEGER, |
| SPV_OPERAND_TYPE_CAPABILITY, SPV_OPERAND_TYPE_LOOP_CONTROL, |
| SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID}), |
| Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV})); |
| } |
| |
| TEST(AlternatePatternFollowingImmediate, ResultIdFront) { |
| EXPECT_THAT(spvAlternatePatternFollowingImmediate( |
| {SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}), |
| Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV, |
| SPV_OPERAND_TYPE_RESULT_ID, |
| SPV_OPERAND_TYPE_OPTIONAL_CIV})); |
| EXPECT_THAT( |
| spvAlternatePatternFollowingImmediate({SPV_OPERAND_TYPE_RESULT_ID, |
| SPV_OPERAND_TYPE_FP_ROUNDING_MODE, |
| SPV_OPERAND_TYPE_ID}), |
| Eq(spv_operand_pattern_t{ |
| SPV_OPERAND_TYPE_OPTIONAL_CIV, SPV_OPERAND_TYPE_RESULT_ID, |
| SPV_OPERAND_TYPE_OPTIONAL_CIV, SPV_OPERAND_TYPE_OPTIONAL_CIV})); |
| EXPECT_THAT( |
| spvAlternatePatternFollowingImmediate( |
| {SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_DIMENSIONALITY, |
| SPV_OPERAND_TYPE_LINKAGE_TYPE, |
| SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE, |
| SPV_OPERAND_TYPE_FP_ROUNDING_MODE, SPV_OPERAND_TYPE_ID, |
| SPV_OPERAND_TYPE_VARIABLE_ID}), |
| Eq(spv_operand_pattern_t{ |
| SPV_OPERAND_TYPE_OPTIONAL_CIV, SPV_OPERAND_TYPE_RESULT_ID, |
| SPV_OPERAND_TYPE_OPTIONAL_CIV, SPV_OPERAND_TYPE_OPTIONAL_CIV, |
| SPV_OPERAND_TYPE_OPTIONAL_CIV, SPV_OPERAND_TYPE_OPTIONAL_CIV, |
| SPV_OPERAND_TYPE_OPTIONAL_CIV, SPV_OPERAND_TYPE_OPTIONAL_CIV})); |
| } |
| |
| TEST(AlternatePatternFollowingImmediate, ResultIdMiddle) { |
| EXPECT_THAT(spvAlternatePatternFollowingImmediate( |
| {SPV_OPERAND_TYPE_FP_ROUNDING_MODE, |
| SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}), |
| Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV, |
| SPV_OPERAND_TYPE_RESULT_ID, |
| SPV_OPERAND_TYPE_OPTIONAL_CIV})); |
| EXPECT_THAT( |
| spvAlternatePatternFollowingImmediate( |
| {SPV_OPERAND_TYPE_DIMENSIONALITY, SPV_OPERAND_TYPE_LINKAGE_TYPE, |
| SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE, |
| SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_FP_ROUNDING_MODE, |
| SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID}), |
| Eq(spv_operand_pattern_t{ |
| SPV_OPERAND_TYPE_OPTIONAL_CIV, SPV_OPERAND_TYPE_RESULT_ID, |
| SPV_OPERAND_TYPE_OPTIONAL_CIV, SPV_OPERAND_TYPE_OPTIONAL_CIV, |
| SPV_OPERAND_TYPE_OPTIONAL_CIV})); |
| } |
| |
| TEST(AlternatePatternFollowingImmediate, ResultIdBack) { |
| EXPECT_THAT(spvAlternatePatternFollowingImmediate( |
| {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID}), |
| Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV, |
| SPV_OPERAND_TYPE_RESULT_ID})); |
| EXPECT_THAT(spvAlternatePatternFollowingImmediate( |
| {SPV_OPERAND_TYPE_FP_ROUNDING_MODE, SPV_OPERAND_TYPE_ID, |
| SPV_OPERAND_TYPE_RESULT_ID}), |
| Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV, |
| SPV_OPERAND_TYPE_RESULT_ID})); |
| EXPECT_THAT( |
| spvAlternatePatternFollowingImmediate( |
| {SPV_OPERAND_TYPE_DIMENSIONALITY, SPV_OPERAND_TYPE_LINKAGE_TYPE, |
| SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE, |
| SPV_OPERAND_TYPE_FP_ROUNDING_MODE, SPV_OPERAND_TYPE_ID, |
| SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_RESULT_ID}), |
| Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV, |
| SPV_OPERAND_TYPE_RESULT_ID})); |
| } |
| |
| } // namespace |
| } // namespace spvtools |