blob: 04e22c84c6c3633bb9abb03acc467eff8961880e [file] [log] [blame]
// Copyright (c) 2016 Google 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 "gmock/gmock.h"
#include "TestFixture.h"
#include "UnitSPIRV.h"
#include "source/name_mapper.h"
using libspirv::NameMapper;
using libspirv::FriendlyNameMapper;
using spvtest::ScopedContext;
using ::testing::Eq;
namespace {
TEST(TrivialNameTest, Samples) {
auto mapper = libspirv::GetTrivialNameMapper();
EXPECT_EQ(mapper(1), "1");
EXPECT_EQ(mapper(1999), "1999");
EXPECT_EQ(mapper(1024), "1024");
}
// A test case for the name mappers that actually look at an assembled module.
struct NameIdCase {
std::string assembly; // Input assembly text
uint32_t id;
std::string expected_name;
};
using FriendlyNameTest =
spvtest::TextToBinaryTestBase<::testing::TestWithParam<NameIdCase>>;
TEST_P(FriendlyNameTest, SingleMapping) {
ScopedContext context(SPV_ENV_UNIVERSAL_1_1);
auto words = CompileSuccessfully(GetParam().assembly, SPV_ENV_UNIVERSAL_1_1);
auto friendly_mapper =
FriendlyNameMapper(context.context, words.data(), words.size());
NameMapper mapper = friendly_mapper.GetNameMapper();
EXPECT_THAT(mapper(GetParam().id), Eq(GetParam().expected_name))
<< GetParam().assembly << std::endl
<< " for id " << GetParam().id;
}
INSTANTIATE_TEST_CASE_P(ScalarType, FriendlyNameTest,
::testing::ValuesIn(std::vector<NameIdCase>{
{"%1 = OpTypeVoid", 1, "void"},
{"%1 = OpTypeBool", 1, "bool"},
{"%1 = OpTypeInt 8 0", 1, "uchar"},
{"%1 = OpTypeInt 8 1", 1, "char"},
{"%1 = OpTypeInt 16 0", 1, "ushort"},
{"%1 = OpTypeInt 16 1", 1, "short"},
{"%1 = OpTypeInt 32 0", 1, "uint"},
{"%1 = OpTypeInt 32 1", 1, "int"},
{"%1 = OpTypeInt 64 0", 1, "ulong"},
{"%1 = OpTypeInt 64 1", 1, "long"},
{"%1 = OpTypeInt 1 0", 1, "u1"},
{"%1 = OpTypeInt 1 1", 1, "i1"},
{"%1 = OpTypeInt 33 0", 1, "u33"},
{"%1 = OpTypeInt 33 1", 1, "i33"},
{"%1 = OpTypeFloat 16", 1, "half"},
{"%1 = OpTypeFloat 32", 1, "float"},
{"%1 = OpTypeFloat 64", 1, "double"},
{"%1 = OpTypeFloat 10", 1, "fp10"},
{"%1 = OpTypeFloat 55", 1, "fp55"},
}), );
INSTANTIATE_TEST_CASE_P(
VectorType, FriendlyNameTest,
::testing::ValuesIn(std::vector<NameIdCase>{
{"%1 = OpTypeBool %2 = OpTypeVector %1 1", 2, "v1bool"},
{"%1 = OpTypeBool %2 = OpTypeVector %1 2", 2, "v2bool"},
{"%1 = OpTypeBool %2 = OpTypeVector %1 3", 2, "v3bool"},
{"%1 = OpTypeBool %2 = OpTypeVector %1 4", 2, "v4bool"},
{"%1 = OpTypeInt 8 0 %2 = OpTypeVector %1 2", 2, "v2uchar"},
{"%1 = OpTypeInt 16 1 %2 = OpTypeVector %1 3", 2, "v3short"},
{"%1 = OpTypeInt 32 0 %2 = OpTypeVector %1 4", 2, "v4uint"},
{"%1 = OpTypeInt 64 1 %2 = OpTypeVector %1 3", 2, "v3long"},
{"%1 = OpTypeInt 20 0 %2 = OpTypeVector %1 4", 2, "v4u20"},
{"%1 = OpTypeInt 21 1 %2 = OpTypeVector %1 3", 2, "v3i21"},
{"%1 = OpTypeFloat 32 %2 = OpTypeVector %1 2", 2, "v2float"},
// OpName overrides the element name.
{"OpName %1 \"time\" %1 = OpTypeFloat 32 %2 = OpTypeVector %1 2", 2,
"v2time"},
}), );
INSTANTIATE_TEST_CASE_P(
MatrixType, FriendlyNameTest,
::testing::ValuesIn(std::vector<NameIdCase>{
{"%1 = OpTypeBool %2 = OpTypeVector %1 2 %3 = OpTypeMatrix %2 2", 3,
"mat2v2bool"},
{"%1 = OpTypeFloat 32 %2 = OpTypeVector %1 2 %3 = OpTypeMatrix %2 3", 3,
"mat3v2float"},
{"%1 = OpTypeFloat 32 %2 = OpTypeVector %1 2 %3 = OpTypeMatrix %2 4", 3,
"mat4v2float"},
{"OpName %1 \"time\" %1 = OpTypeFloat 32 %2 = OpTypeVector %1 2 %3 = "
"OpTypeMatrix %2 4",
3, "mat4v2time"},
{"OpName %2 \"lat_long\" %1 = OpTypeFloat 32 %2 = OpTypeVector %1 2 %3 "
"= OpTypeMatrix %2 4",
3, "mat4lat_long"},
}), );
INSTANTIATE_TEST_CASE_P(
OpName, FriendlyNameTest,
::testing::ValuesIn(std::vector<NameIdCase>{
{"OpName %1 \"abcdefg\"", 1, "abcdefg"},
{"OpName %1 \"Hello world!\"", 1, "Hello_world_"},
{"OpName %1 \"0123456789\"", 1, "0123456789"},
{"OpName %1 \"_\"", 1, "_"},
// An empty string is not valid for SPIR-V assembly IDs.
{"OpName %1 \"\"", 1, "_"},
// Test uniqueness when presented with things mapping to "_"
{"OpName %1 \"\" OpName %2 \"\"", 1, "_"},
{"OpName %1 \"\" OpName %2 \"\"", 2, "__0"},
{"OpName %1 \"\" OpName %2 \"\" OpName %3 \"_\"", 3, "__1"},
// Test uniqueness of names that are forced to be
// numbers.
{"OpName %1 \"2\" OpName %2 \"2\"", 1, "2"},
{"OpName %1 \"2\" OpName %2 \"2\"", 2, "2_0"},
// Test uniqueness in the face of forward references
// for Ids that don't already have friendly names.
// In particular, the first OpDecorate assigns the name, and
// the second one can't override it.
{"OpDecorate %1 Volatile OpDecorate %1 Restrict", 1, "1"},
// But a forced name can override the name that
// would have been assigned via the OpDecorate
// forward reference.
{"OpName %1 \"mememe\" OpDecorate %1 Volatile OpDecorate %1 Restrict",
1, "mememe"},
// OpName can override other inferences. We assume valid instruction
// ordering, where OpName precedes type definitions.
{"OpName %1 \"myfloat\" %1 = OpTypeFloat 32", 1, "myfloat"},
}), );
INSTANTIATE_TEST_CASE_P(
UniquenessHeuristic, FriendlyNameTest,
::testing::ValuesIn(std::vector<NameIdCase>{
{"%1 = OpTypeVoid %2 = OpTypeVoid %3 = OpTypeVoid", 1, "void"},
{"%1 = OpTypeVoid %2 = OpTypeVoid %3 = OpTypeVoid", 2, "void_0"},
{"%1 = OpTypeVoid %2 = OpTypeVoid %3 = OpTypeVoid", 3, "void_1"},
}), );
INSTANTIATE_TEST_CASE_P(Arrays, FriendlyNameTest,
::testing::ValuesIn(std::vector<NameIdCase>{
{"OpName %2 \"FortyTwo\" %1 = OpTypeFloat 32 "
"%2 = OpConstant %1 42 %3 = OpTypeArray %1 %2",
3, "_arr_float_FortyTwo"},
{"%1 = OpTypeInt 32 0 "
"%2 = OpTypeRuntimeArray %1",
2, "_runtimearr_uint"},
}), );
INSTANTIATE_TEST_CASE_P(Structs, FriendlyNameTest,
::testing::ValuesIn(std::vector<NameIdCase>{
{"%1 = OpTypeBool "
"%2 = OpTypeStruct %1 %1 %1",
2, "_struct_2"},
{"%1 = OpTypeBool "
"%2 = OpTypeStruct %1 %1 %1 "
"%3 = OpTypeStruct %2 %2",
3, "_struct_3"},
}), );
INSTANTIATE_TEST_CASE_P(
Pointer, FriendlyNameTest,
::testing::ValuesIn(std::vector<NameIdCase>{
{"%1 = OpTypeFloat 32 %2 = OpTypePointer Workgroup %1", 2,
"_ptr_Workgroup_float"},
{"%1 = OpTypeBool %2 = OpTypePointer Private %1", 2,
"_ptr_Private_bool"},
// OpTypeForwardPointer doesn't force generation of the name for its
// target type.
{"%1 = OpTypeBool OpTypeForwardPointer %2 Private %2 = OpTypePointer "
"Private %1",
2, "_ptr_Private_bool"},
}), );
INSTANTIATE_TEST_CASE_P(ExoticTypes, FriendlyNameTest,
::testing::ValuesIn(std::vector<NameIdCase>{
{"%1 = OpTypeEvent", 1, "Event"},
{"%1 = OpTypeDeviceEvent", 1, "DeviceEvent"},
{"%1 = OpTypeReserveId", 1, "ReserveId"},
{"%1 = OpTypeQueue", 1, "Queue"},
{"%1 = OpTypeOpaque \"hello world!\"", 1, "Opaque_hello_world_"},
{"%1 = OpTypePipe ReadOnly", 1, "PipeReadOnly"},
{"%1 = OpTypePipe WriteOnly", 1, "PipeWriteOnly"},
{"%1 = OpTypePipe ReadWrite", 1, "PipeReadWrite"},
{"%1 = OpTypePipeStorage", 1, "PipeStorage"},
{"%1 = OpTypeNamedBarrier", 1, "NamedBarrier"},
}), );
} // anonymous namespace