mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-25 13:00:04 +00:00
d35a78db57
Fixes #4960 * Switches to using enum classes with an underlying type to avoid undefined behaviour
278 lines
11 KiB
C++
278 lines
11 KiB
C++
// 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_SUITE_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 used mask bits are:
|
|
// 1 through...
|
|
// 0x20 SpvMemoryAccessNonPrivatePointerMask
|
|
// also
|
|
// 0x10000 SpvMemoryAccessAliasScopeINTELMaskShift
|
|
// 0x20000 SpvMemoryAccessNoAliasINTELMaskMask
|
|
{SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS,
|
|
0xffffffc0 ^ (0x10000) ^ (0x20000),
|
|
{PREFIX1},
|
|
{PREFIX1}},
|
|
// Volatile has no operands.
|
|
{SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS,
|
|
uint32_t(spv::MemoryAccessMask::Volatile),
|
|
{PREFIX0},
|
|
{PREFIX0}},
|
|
// Aligned has one literal number operand.
|
|
{SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS,
|
|
uint32_t(spv::MemoryAccessMask::Aligned),
|
|
{PREFIX1},
|
|
{PREFIX1, SPV_OPERAND_TYPE_LITERAL_INTEGER}},
|
|
// Volatile with Aligned still has just one literal number operand.
|
|
{SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS,
|
|
uint32_t(spv::MemoryAccessMask::Volatile |
|
|
spv::MemoryAccessMask::Aligned),
|
|
{PREFIX1},
|
|
{PREFIX1, SPV_OPERAND_TYPE_LITERAL_INTEGER}},
|
|
// Newer masks are not tested
|
|
}));
|
|
#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_SUITE_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_SUITE_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
|