#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;
using OpDecorateSimpleTest =
spvtest::TextToBinaryTestBase<::testing::TestWithParam<
std::tuple<spv_target_env, EnumCase<spv::Decoration>>>>;
TEST_P(OpDecorateSimpleTest, AnySimpleDecoration) {
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(spv::Op::OpDecorate,
{1, uint32_t(std::get<1>(GetParam()).value())},
std::get<1>(GetParam()).operands())));
EXPECT_THAT(EncodeAndDecodeSuccessfully(
input.str(), SPV_BINARY_TO_TEXT_OPTION_NONE,
SPV_TEXT_TO_BINARY_OPTION_NONE, std::get<0>(GetParam())),
Eq(input.str()));
}
using OpDecorateSimpleIdTest =
spvtest::TextToBinaryTestBase<::testing::TestWithParam<
std::tuple<spv_target_env, EnumCase<spv::Decoration>>>>;
TEST_P(OpDecorateSimpleIdTest, AnySimpleDecoration) {
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(spv::Op::OpDecorateId,
{1, uint32_t(std::get<1>(GetParam()).value())},
std::get<1>(GetParam()).operands())));
EXPECT_THAT(EncodeAndDecodeSuccessfully(
input.str(), SPV_BINARY_TO_TEXT_OPTION_NONE,
SPV_TEXT_TO_BINARY_OPTION_NONE, std::get<0>(GetParam())),
Eq(input.str()));
}
#define CASE(NAME) spv::Decoration::NAME, #NAME
INSTANTIATE_TEST_SUITE_P(
TextToBinaryDecorateSimple, OpDecorateSimpleTest,
Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
ValuesIn(std::vector<EnumCase<spv::Decoration>>{
{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), {}},
{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<spv::Decoration>{
CASE(MaxByteOffset), {128}})));
INSTANTIATE_TEST_SUITE_P(
TextToBinaryDecorateSimpleV14, OpDecorateSimpleTest,
Combine(Values(SPV_ENV_UNIVERSAL_1_4),
ValuesIn(std::vector<EnumCase<spv::Decoration>>{
{CASE(Uniform), {}},
})));
INSTANTIATE_TEST_SUITE_P(
TextToBinaryDecorateSimpleIdV14, OpDecorateSimpleIdTest,
Combine(Values(SPV_ENV_UNIVERSAL_1_4),
ValuesIn(std::vector<EnumCase<spv::Decoration>>{
{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'."));
}
struct DecorateEnumCase {
uint32_t value; std::string name;
uint32_t enum_value; std::string enum_name;
};
using OpDecorateEnumTest =
spvtest::TextToBinaryTestBase<::testing::TestWithParam<DecorateEnumCase>>;
TEST_P(OpDecorateEnumTest, AnyEnumDecoration) {
const std::string input =
"OpDecorate %1 " + GetParam().enum_name + " " + GetParam().name;
EXPECT_THAT(CompiledInstructions(input),
Eq(MakeInstruction(spv::Op::OpDecorate, {1, GetParam().enum_value,
GetParam().value})));
}
#define CASE(NAME) \
{ uint32_t(spv::BuiltIn::NAME), #NAME, uint32_t(spv::Decoration::BuiltIn), "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),
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),
CASE(SubgroupSize),
CASE(SubgroupMaxSize),
CASE(NumSubgroups),
CASE(NumEnqueuedSubgroups),
CASE(SubgroupId),
CASE(SubgroupLocalInvocationId),
CASE(VertexIndex),
CASE(InstanceIndex),
}));
#undef CASE
TEST_F(OpDecorateEnumTest, WrongBuiltIn) {
EXPECT_THAT(CompileFailure("OpDecorate %1 BuiltIn xxyyzz"),
Eq("Invalid built-in 'xxyyzz'."));
}
#define CASE(NAME) \
{ uint32_t(spv::FunctionParameterAttribute::NAME), #NAME, uint32_t(spv::Decoration::FuncParamAttr), "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
TEST_F(OpDecorateEnumTest, WrongFuncParamAttr) {
EXPECT_THAT(CompileFailure("OpDecorate %1 FuncParamAttr xxyyzz"),
Eq("Invalid function parameter attribute 'xxyyzz'."));
}
#define CASE(NAME) \
{ uint32_t(spv::FPRoundingMode::NAME), #NAME, uint32_t(spv::Decoration::FPRoundingMode), "FPRoundingMode" }
INSTANTIATE_TEST_SUITE_P(TextToBinaryDecorateFPRoundingMode, OpDecorateEnumTest,
::testing::ValuesIn(std::vector<DecorateEnumCase>{
CASE(RTE),
CASE(RTZ),
CASE(RTP),
CASE(RTN),
}));
#undef CASE
TEST_F(OpDecorateEnumTest, WrongFPRoundingMode) {
EXPECT_THAT(CompileFailure("OpDecorate %1 FPRoundingMode xxyyzz"),
Eq("Invalid floating-point rounding mode 'xxyyzz'."));
}
#define CASE(ENUM,NAME) \
{ uint32_t(spv::FPFastMathModeMask::ENUM), #NAME, uint32_t(spv::Decoration::FPFastMathMode), "FPFastMathMode" }
INSTANTIATE_TEST_SUITE_P(TextToBinaryDecorateFPFastMathMode, OpDecorateEnumTest,
::testing::ValuesIn(std::vector<DecorateEnumCase>{
CASE(MaskNone, None),
CASE(NotNaN, NotNaN),
CASE(NotInf, NotInf),
CASE(NSZ, NSZ),
CASE(AllowRecip, AllowRecip),
CASE(Fast, Fast),
}));
#undef CASE
TEST_F(OpDecorateEnumTest, CombinedFPFastMathMask) {
const std::string input = "OpDecorate %1 FPFastMathMode NotNaN|NotInf|NSZ";
const uint32_t expected_enum = uint32_t(spv::Decoration::FPFastMathMode);
const uint32_t expected_mask = uint32_t(spv::FPFastMathModeMask::NotNaN) |
uint32_t(spv::FPFastMathModeMask::NotInf) |
uint32_t(spv::FPFastMathModeMask::NSZ);
EXPECT_THAT(CompiledInstructions(input),
Eq(MakeInstruction(spv::Op::OpDecorate,
{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'."));
}
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) {
const std::string input = "OpDecorate %1 LinkageAttributes \"" +
GetParam().external_name + "\" " +
GetParam().linkage_type_name;
std::vector<uint32_t> expected_operands{
1, uint32_t(spv::Decoration::LinkageAttributes)};
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(spv::Op::OpDecorate, expected_operands)));
}
#define CASE(ENUM) uint32_t(spv::LinkageType::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." },
}));
#undef CASE
TEST_F(OpDecorateLinkageTest, WrongType) {
EXPECT_THAT(CompileFailure("OpDecorate %1 LinkageAttributes \"foo\" xxyyzz"),
Eq("Invalid linkage type 'xxyyzz'."));
}
TEST_F(TextToBinaryTest, GroupMemberDecorateGoodOneTarget) {
EXPECT_THAT(CompiledInstructions("OpGroupMemberDecorate %group %id0 42"),
Eq(MakeInstruction(spv::Op::OpGroupMemberDecorate, {1, 2, 42})));
}
TEST_F(TextToBinaryTest, GroupMemberDecorateGoodTwoTargets) {
EXPECT_THAT(
CompiledInstructions("OpGroupMemberDecorate %group %id0 96 %id1 42"),
Eq(MakeInstruction(spv::Op::OpGroupMemberDecorate, {1, 2, 96, 3, 42})));
}
TEST_F(TextToBinaryTest, GroupMemberDecorateMissingGroupId) {
EXPECT_THAT(CompileFailure("OpGroupMemberDecorate"),
Eq("Expected operand for OpGroupMemberDecorate instruction, but "
"found the end of the 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 for OpGroupMemberDecorate instruction, but "
"found the end of the 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 for OpGroupMemberDecorate instruction, but "
"found the end of the stream."));
}
TEST_F(TextToBinaryTest, GroupMemberDecorateInvalidSecondTargetMemberNumber) {
EXPECT_THAT(CompileFailure("OpGroupMemberDecorate %group %id0 42 %id1 %id2"),
Eq("Invalid unsigned integer literal: %id2"));
}
using OpMemberDecorateSimpleTest =
spvtest::TextToBinaryTestBase<::testing::TestWithParam<
std::tuple<spv_target_env, EnumCase<spv::Decoration>>>>;
TEST_P(OpMemberDecorateSimpleTest, AnySimpleDecoration) {
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(spv::Op::OpMemberDecorate,
{1, 42, uint32_t(std::get<1>(GetParam()).value())},
std::get<1>(GetParam()).operands())));
EXPECT_THAT(EncodeAndDecodeSuccessfully(
input.str(), SPV_BINARY_TO_TEXT_OPTION_NONE,
SPV_TEXT_TO_BINARY_OPTION_NONE, std::get<0>(GetParam())),
Eq(input.str()));
}
#define CASE(NAME) spv::Decoration::NAME, #NAME
INSTANTIATE_TEST_SUITE_P(
TextToBinaryDecorateSimple, OpMemberDecorateSimpleTest,
Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
ValuesIn(std::vector<EnumCase<spv::Decoration>>{
{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), {}},
{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<spv::Decoration>{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'."));
}
} }