mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-12-24 00:40:14 +00:00
Instruction lookup succeeds if it's enabled by a capability
Also add a corresponding check for capabilities in the validator. Update previously existing test cases where an instruction used to fail assembling because of a version check, but now they succeed because the instruction is also guarded by a capability. Now it should assemble. Add tests to ensure that capabilities are checked appropriately. The explicitly reserved instructions OpImageSparseSampleProj* now assemble, but they fail validation. Fixes #1624
This commit is contained in:
parent
f80696eaf6
commit
8d65c89678
@ -108,7 +108,7 @@ spv_result_t spvOpcodeTableNameLookup(spv_target_env env,
|
||||
// is indeed requested in the SPIR-V code; checking that should be
|
||||
// validator's work.
|
||||
if ((spvVersionForTargetEnv(env) >= entry.minVersion ||
|
||||
entry.numExtensions > 0u) &&
|
||||
entry.numExtensions > 0u || entry.numCapabilities > 0u) &&
|
||||
nameLength == strlen(entry.name) &&
|
||||
!strncmp(name, entry.name, nameLength)) {
|
||||
// NOTE: Found out Opcode!
|
||||
@ -153,7 +153,7 @@ spv_result_t spvOpcodeTableValueLookup(spv_target_env env,
|
||||
// is indeed requested in the SPIR-V code; checking that should be
|
||||
// validator's work.
|
||||
if (spvVersionForTargetEnv(env) >= it->minVersion ||
|
||||
it->numExtensions > 0u) {
|
||||
it->numExtensions > 0u || it->numCapabilities > 0u) {
|
||||
*pEntry = it;
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
@ -187,6 +187,30 @@ ExtensionSet RequiredExtensions(const ValidationState_t& state,
|
||||
|
||||
namespace libspirv {
|
||||
|
||||
// Return SPV_ERROR_INVALID_BINARY and emit a diagnostic if the instruction
|
||||
// is explicitly reserved in the SPIR-V core spec. Otherwise return
|
||||
// SPV_SUCCESS.
|
||||
spv_result_t ReservedCheck(ValidationState_t& _,
|
||||
const spv_parsed_instruction_t* inst) {
|
||||
const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
|
||||
switch (opcode) {
|
||||
// These instructions are enabled by a capability, but should never
|
||||
// be used anyway.
|
||||
case SpvOpImageSparseSampleProjImplicitLod:
|
||||
case SpvOpImageSparseSampleProjExplicitLod:
|
||||
case SpvOpImageSparseSampleProjDrefImplicitLod:
|
||||
case SpvOpImageSparseSampleProjDrefExplicitLod: {
|
||||
spv_opcode_desc inst_desc;
|
||||
_.grammar().lookupOpcode(opcode, &inst_desc);
|
||||
return _.diag(SPV_ERROR_INVALID_BINARY)
|
||||
<< "Invalid Opcode name 'Op" << inst_desc->name << "'";
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
spv_result_t CapabilityCheck(ValidationState_t& _,
|
||||
const spv_parsed_instruction_t* inst) {
|
||||
const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
|
||||
@ -246,6 +270,8 @@ spv_result_t ExtensionCheck(ValidationState_t& _,
|
||||
}
|
||||
|
||||
// Checks that the instruction can be used in this target environment.
|
||||
// Assumes that CapabilityCheck has checked direct capability dependencies
|
||||
// for the opcode.
|
||||
spv_result_t VersionCheck(ValidationState_t& _,
|
||||
const spv_parsed_instruction_t* inst) {
|
||||
const auto opcode = static_cast<SpvOp>(inst->opcode);
|
||||
@ -256,6 +282,12 @@ spv_result_t VersionCheck(ValidationState_t& _,
|
||||
|
||||
const auto min_version = inst_desc->minVersion;
|
||||
|
||||
if (inst_desc->numCapabilities > 0u) {
|
||||
// We already checked that the direct capability dependency has been
|
||||
// satisfied. We don't need to check any further.
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
ExtensionSet exts(inst_desc->numExtensions, inst_desc->extensions);
|
||||
if (exts.IsEmpty()) {
|
||||
// If no extensions can enable this instruction, then emit error messages
|
||||
@ -549,6 +581,7 @@ spv_result_t InstructionPass(ValidationState_t& _,
|
||||
RegisterDecorations(_, inst);
|
||||
|
||||
if (auto error = ExtensionCheck(_, inst)) return error;
|
||||
if (auto error = ReservedCheck(_, inst)) return error;
|
||||
if (auto error = CapabilityCheck(_, inst)) return error;
|
||||
if (auto error = LimitCheckIdBound(_, inst)) return error;
|
||||
if (auto error = LimitCheckStruct(_, inst)) return error;
|
||||
|
@ -87,28 +87,6 @@ TEST(CppInterface, AssembleOverloads) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CppInterface, AssembleWithWrongTargetEnv) {
|
||||
const std::string input_text = "%r = OpSizeOf %type %pointer";
|
||||
SpirvTools t(SPV_ENV_UNIVERSAL_1_0);
|
||||
int invocation_count = 0;
|
||||
t.SetMessageConsumer(
|
||||
[&invocation_count](spv_message_level_t level, const char* source,
|
||||
const spv_position_t& position, const char* message) {
|
||||
++invocation_count;
|
||||
EXPECT_EQ(SPV_MSG_ERROR, level);
|
||||
EXPECT_STREQ("input", source);
|
||||
EXPECT_EQ(0u, position.line);
|
||||
EXPECT_EQ(5u, position.column);
|
||||
EXPECT_EQ(5u, position.index);
|
||||
EXPECT_STREQ("Invalid Opcode name 'OpSizeOf'", message);
|
||||
});
|
||||
|
||||
std::vector<uint32_t> binary = {42, 42};
|
||||
EXPECT_FALSE(t.Assemble(input_text, &binary));
|
||||
EXPECT_THAT(binary, ContainerEq(std::vector<uint32_t>{42, 42}));
|
||||
EXPECT_EQ(1, invocation_count);
|
||||
}
|
||||
|
||||
TEST(CppInterface, DisassembleEmptyModule) {
|
||||
std::string text(10, 'x');
|
||||
SpirvTools t(SPV_ENV_UNIVERSAL_1_1);
|
||||
@ -148,31 +126,6 @@ TEST(CppInterface, DisassembleOverloads) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CppInterface, DisassembleWithWrongTargetEnv) {
|
||||
const std::string input_text = "%r = OpSizeOf %type %pointer";
|
||||
SpirvTools t11(SPV_ENV_UNIVERSAL_1_1);
|
||||
SpirvTools t10(SPV_ENV_UNIVERSAL_1_0);
|
||||
int invocation_count = 0;
|
||||
t10.SetMessageConsumer(
|
||||
[&invocation_count](spv_message_level_t level, const char* source,
|
||||
const spv_position_t& position, const char* message) {
|
||||
++invocation_count;
|
||||
EXPECT_EQ(SPV_MSG_ERROR, level);
|
||||
EXPECT_STREQ("input", source);
|
||||
EXPECT_EQ(0u, position.line);
|
||||
EXPECT_EQ(0u, position.column);
|
||||
EXPECT_EQ(5u, position.index);
|
||||
EXPECT_STREQ("Invalid opcode: 321", message);
|
||||
});
|
||||
|
||||
std::vector<uint32_t> binary;
|
||||
EXPECT_TRUE(t11.Assemble(input_text, &binary));
|
||||
|
||||
std::string output_text(10, 'x');
|
||||
EXPECT_FALSE(t10.Disassemble(binary, &output_text));
|
||||
EXPECT_EQ("xxxxxxxxxx", output_text); // The original string is unmodified.
|
||||
}
|
||||
|
||||
TEST(CppInterface, SuccessfulValidation) {
|
||||
const std::string input_text = R"(
|
||||
OpCapability Shader
|
||||
|
@ -78,10 +78,14 @@ TEST_F(OpMemoryBarrier, BadInvalidMemorySemanticsId) {
|
||||
|
||||
using NamedMemoryBarrierTest = spvtest::TextToBinaryTest;
|
||||
|
||||
TEST_F(NamedMemoryBarrierTest, OpcodeUnrecognizedInV10) {
|
||||
EXPECT_THAT(CompileFailure("OpMemoryNamedBarrier %bar %scope %semantics",
|
||||
SPV_ENV_UNIVERSAL_1_0),
|
||||
Eq("Invalid Opcode name 'OpMemoryNamedBarrier'"));
|
||||
// OpMemoryNamedBarrier is not in 1.0, but it is enabled by a capability.
|
||||
// We should be able to assemble it. Validation checks are in another test
|
||||
// file.
|
||||
TEST_F(NamedMemoryBarrierTest, OpcodeAssemblesInV10) {
|
||||
EXPECT_THAT(
|
||||
CompiledInstructions("OpMemoryNamedBarrier %bar %scope %semantics",
|
||||
SPV_ENV_UNIVERSAL_1_0),
|
||||
ElementsAre(spvOpcodeMake(4, SpvOpMemoryNamedBarrier), _, _, _));
|
||||
}
|
||||
|
||||
TEST_F(NamedMemoryBarrierTest, ArgumentCount) {
|
||||
@ -114,9 +118,10 @@ TEST_F(NamedMemoryBarrierTest, ArgumentTypes) {
|
||||
|
||||
using TypeNamedBarrierTest = spvtest::TextToBinaryTest;
|
||||
|
||||
TEST_F(TypeNamedBarrierTest, OpcodeUnrecognizedInV10) {
|
||||
EXPECT_THAT(CompileFailure("%t = OpTypeNamedBarrier", SPV_ENV_UNIVERSAL_1_0),
|
||||
Eq("Invalid Opcode name 'OpTypeNamedBarrier'"));
|
||||
TEST_F(TypeNamedBarrierTest, OpcodeAssemblesInV10) {
|
||||
EXPECT_THAT(
|
||||
CompiledInstructions("%t = OpTypeNamedBarrier", SPV_ENV_UNIVERSAL_1_0),
|
||||
ElementsAre(spvOpcodeMake(2, SpvOpTypeNamedBarrier), _));
|
||||
}
|
||||
|
||||
TEST_F(TypeNamedBarrierTest, ArgumentCount) {
|
||||
@ -134,10 +139,11 @@ TEST_F(TypeNamedBarrierTest, ArgumentCount) {
|
||||
|
||||
using NamedBarrierInitializeTest = spvtest::TextToBinaryTest;
|
||||
|
||||
TEST_F(NamedBarrierInitializeTest, OpcodeUnrecognizedInV10) {
|
||||
EXPECT_THAT(CompileFailure("%bar = OpNamedBarrierInitialize %type %count",
|
||||
SPV_ENV_UNIVERSAL_1_0),
|
||||
Eq("Invalid Opcode name 'OpNamedBarrierInitialize'"));
|
||||
TEST_F(NamedBarrierInitializeTest, OpcodeAssemblesInV10) {
|
||||
EXPECT_THAT(
|
||||
CompiledInstructions("%bar = OpNamedBarrierInitialize %type %count",
|
||||
SPV_ENV_UNIVERSAL_1_0),
|
||||
ElementsAre(spvOpcodeMake(4, SpvOpNamedBarrierInitialize), _, _, _));
|
||||
}
|
||||
|
||||
TEST_F(NamedBarrierInitializeTest, ArgumentCount) {
|
||||
|
@ -22,9 +22,12 @@ using ::testing::Eq;
|
||||
|
||||
using OpTypePipeStorageTest = spvtest::TextToBinaryTest;
|
||||
|
||||
TEST_F(OpTypePipeStorageTest, OpcodeUnrecognizedInV10) {
|
||||
EXPECT_THAT(CompileFailure("%res = OpTypePipeStorage", SPV_ENV_UNIVERSAL_1_0),
|
||||
Eq("Invalid Opcode name 'OpTypePipeStorage'"));
|
||||
// It can assemble, but should not validate. Validation checks for version
|
||||
// and capability are in another test file.
|
||||
TEST_F(OpTypePipeStorageTest, OpcodeAssemblesInV10) {
|
||||
EXPECT_THAT(
|
||||
CompiledInstructions("%res = OpTypePipeStorage", SPV_ENV_UNIVERSAL_1_0),
|
||||
Eq(MakeInstruction(SpvOpTypePipeStorage, {1})));
|
||||
}
|
||||
|
||||
TEST_F(OpTypePipeStorageTest, ArgumentCount) {
|
||||
@ -42,10 +45,10 @@ TEST_F(OpTypePipeStorageTest, ArgumentCount) {
|
||||
|
||||
using OpConstantPipeStorageTest = spvtest::TextToBinaryTest;
|
||||
|
||||
TEST_F(OpConstantPipeStorageTest, OpcodeUnrecognizedInV10) {
|
||||
EXPECT_THAT(CompileFailure("%1 = OpConstantPipeStorage %2 3 4 5",
|
||||
SPV_ENV_UNIVERSAL_1_0),
|
||||
Eq("Invalid Opcode name 'OpConstantPipeStorage'"));
|
||||
TEST_F(OpConstantPipeStorageTest, OpcodeAssemblesInV10) {
|
||||
EXPECT_THAT(CompiledInstructions("%1 = OpConstantPipeStorage %2 3 4 5",
|
||||
SPV_ENV_UNIVERSAL_1_0),
|
||||
Eq(MakeInstruction(SpvOpConstantPipeStorage, {1, 2, 3, 4, 5})));
|
||||
}
|
||||
|
||||
TEST_F(OpConstantPipeStorageTest, ArgumentCount) {
|
||||
@ -84,10 +87,10 @@ TEST_F(OpConstantPipeStorageTest, ArgumentTypes) {
|
||||
|
||||
using OpCreatePipeFromPipeStorageTest = spvtest::TextToBinaryTest;
|
||||
|
||||
TEST_F(OpCreatePipeFromPipeStorageTest, OpcodeUnrecognizedInV10) {
|
||||
EXPECT_THAT(CompileFailure("%1 = OpCreatePipeFromPipeStorage %2 %3",
|
||||
SPV_ENV_UNIVERSAL_1_0),
|
||||
Eq("Invalid Opcode name 'OpCreatePipeFromPipeStorage'"));
|
||||
TEST_F(OpCreatePipeFromPipeStorageTest, OpcodeAssemblesInV10) {
|
||||
EXPECT_THAT(CompiledInstructions("%1 = OpCreatePipeFromPipeStorage %2 %3",
|
||||
SPV_ENV_UNIVERSAL_1_0),
|
||||
Eq(MakeInstruction(SpvOpCreatePipeFromPipeStorage, {1, 2, 3})));
|
||||
}
|
||||
|
||||
TEST_F(OpCreatePipeFromPipeStorageTest, ArgumentCount) {
|
||||
|
@ -21,37 +21,40 @@
|
||||
|
||||
namespace {
|
||||
|
||||
using ::spvtest::MakeInstruction;
|
||||
using ::testing::Eq;
|
||||
|
||||
using ReservedSamplingInstTest = spvtest::TextToBinaryTest;
|
||||
using ReservedSamplingInstTest = RoundTripTest;
|
||||
|
||||
TEST_F(ReservedSamplingInstTest, OpImageSparseSampleProjImplicitLod) {
|
||||
const std::string input = "OpImageSparseSampleProjImplicitLod %1 %2 %3\n";
|
||||
EXPECT_THAT(CompileFailure(input),
|
||||
Eq("Invalid Opcode name 'OpImageSparseSampleProjImplicitLod'"));
|
||||
std::string input = "%2 = OpImageSparseSampleProjImplicitLod %1 %3 %4\n";
|
||||
EXPECT_THAT(
|
||||
CompiledInstructions(input, SPV_ENV_UNIVERSAL_1_0),
|
||||
Eq(MakeInstruction(SpvOpImageSparseSampleProjImplicitLod, {1, 2, 3, 4})));
|
||||
}
|
||||
|
||||
TEST_F(ReservedSamplingInstTest, OpImageSparseSampleProjExplicitLod) {
|
||||
const std::string input =
|
||||
"OpImageSparseSampleProjExplicitLod %1 %2 %3 Lod %4\n";
|
||||
EXPECT_THAT(CompileFailure(input),
|
||||
Eq("Invalid Opcode name 'OpImageSparseSampleProjExplicitLod'"));
|
||||
std::string input =
|
||||
"%2 = OpImageSparseSampleProjExplicitLod %1 %3 %4 Lod %5\n";
|
||||
EXPECT_THAT(CompiledInstructions(input, SPV_ENV_UNIVERSAL_1_0),
|
||||
Eq(MakeInstruction(SpvOpImageSparseSampleProjExplicitLod,
|
||||
{1, 2, 3, 4, SpvImageOperandsLodMask, 5})));
|
||||
}
|
||||
|
||||
TEST_F(ReservedSamplingInstTest, OpImageSparseSampleProjDrefImplicitLod) {
|
||||
const std::string input =
|
||||
"OpImageSparseSampleProjDrefImplicitLod %1 %2 %3 %4\n";
|
||||
EXPECT_THAT(
|
||||
CompileFailure(input),
|
||||
Eq("Invalid Opcode name 'OpImageSparseSampleProjDrefImplicitLod'"));
|
||||
std::string input =
|
||||
"%2 = OpImageSparseSampleProjDrefImplicitLod %1 %3 %4 %5\n";
|
||||
EXPECT_THAT(CompiledInstructions(input, SPV_ENV_UNIVERSAL_1_0),
|
||||
Eq(MakeInstruction(SpvOpImageSparseSampleProjDrefImplicitLod,
|
||||
{1, 2, 3, 4, 5})));
|
||||
}
|
||||
|
||||
TEST_F(ReservedSamplingInstTest, OpImageSparseSampleProjDrefExplicitLod) {
|
||||
const std::string input =
|
||||
"OpImageSparseSampleProjDrefExplicitLod %1 %2 %3 %4 Lod %5\n";
|
||||
EXPECT_THAT(
|
||||
CompileFailure(input),
|
||||
Eq("Invalid Opcode name 'OpImageSparseSampleProjDrefExplicitLod'"));
|
||||
std::string input =
|
||||
"%2 = OpImageSparseSampleProjDrefExplicitLod %1 %3 %4 %5 Lod %6\n";
|
||||
EXPECT_THAT(CompiledInstructions(input, SPV_ENV_UNIVERSAL_1_0),
|
||||
Eq(MakeInstruction(SpvOpImageSparseSampleProjDrefExplicitLod,
|
||||
{1, 2, 3, 4, 5, SpvImageOperandsLodMask, 6})));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -28,12 +28,15 @@ using ::testing::Eq;
|
||||
|
||||
using OpGetKernelLocalSizeForSubgroupCountTest = spvtest::TextToBinaryTest;
|
||||
|
||||
TEST_F(OpGetKernelLocalSizeForSubgroupCountTest, OpcodeUnrecognizedInV10) {
|
||||
// We should be able to assemble it. Validation checks are in another test
|
||||
// file.
|
||||
TEST_F(OpGetKernelLocalSizeForSubgroupCountTest, OpcodeAssemblesInV10) {
|
||||
EXPECT_THAT(
|
||||
CompileFailure("%res = OpGetKernelLocalSizeForSubgroupCount %type "
|
||||
"%sgcount %invoke %param %param_size %param_align",
|
||||
SPV_ENV_UNIVERSAL_1_0),
|
||||
Eq("Invalid Opcode name 'OpGetKernelLocalSizeForSubgroupCount'"));
|
||||
CompiledInstructions("%res = OpGetKernelLocalSizeForSubgroupCount %type "
|
||||
"%sgcount %invoke %param %param_size %param_align",
|
||||
SPV_ENV_UNIVERSAL_1_0),
|
||||
Eq(MakeInstruction(SpvOpGetKernelLocalSizeForSubgroupCount,
|
||||
{1, 2, 3, 4, 5, 6, 7})));
|
||||
}
|
||||
|
||||
TEST_F(OpGetKernelLocalSizeForSubgroupCountTest, ArgumentCount) {
|
||||
@ -75,11 +78,12 @@ TEST_F(OpGetKernelLocalSizeForSubgroupCountTest, ArgumentTypes) {
|
||||
|
||||
using OpGetKernelMaxNumSubgroupsTest = spvtest::TextToBinaryTest;
|
||||
|
||||
TEST_F(OpGetKernelMaxNumSubgroupsTest, OpcodeUnrecognizedInV10) {
|
||||
EXPECT_THAT(CompileFailure("%res = OpGetKernelLocalSizeForSubgroupCount "
|
||||
"%type %invoke %param %param_size %param_align",
|
||||
SPV_ENV_UNIVERSAL_1_0),
|
||||
Eq("Invalid Opcode name 'OpGetKernelLocalSizeForSubgroupCount'"));
|
||||
TEST_F(OpGetKernelMaxNumSubgroupsTest, OpcodeAssemblesInV10) {
|
||||
EXPECT_THAT(
|
||||
CompiledInstructions("%res = OpGetKernelMaxNumSubgroups %type "
|
||||
"%invoke %param %param_size %param_align",
|
||||
SPV_ENV_UNIVERSAL_1_0),
|
||||
Eq(MakeInstruction(SpvOpGetKernelMaxNumSubgroups, {1, 2, 3, 4, 5, 6})));
|
||||
}
|
||||
|
||||
TEST_F(OpGetKernelMaxNumSubgroupsTest, ArgumentCount) {
|
||||
|
@ -235,9 +235,12 @@ TEST_F(OpTypeForwardPointerTest, WrongClass) {
|
||||
|
||||
using OpSizeOfTest = spvtest::TextToBinaryTest;
|
||||
|
||||
TEST_F(OpSizeOfTest, OpcodeUnrecognizedInV10) {
|
||||
EXPECT_THAT(CompileFailure("%1 = OpSizeOf %2 %3", SPV_ENV_UNIVERSAL_1_0),
|
||||
Eq("Invalid Opcode name 'OpSizeOf'"));
|
||||
// We should be able to assemble it. Validation checks are in another test
|
||||
// file.
|
||||
TEST_F(OpSizeOfTest, OpcodeAssemblesInV10) {
|
||||
EXPECT_THAT(
|
||||
CompiledInstructions("%1 = OpSizeOf %2 %3", SPV_ENV_UNIVERSAL_1_0),
|
||||
Eq(MakeInstruction(SpvOpSizeOf, {1, 2, 3})));
|
||||
}
|
||||
|
||||
TEST_F(OpSizeOfTest, ArgumentCount) {
|
||||
|
@ -33,6 +33,7 @@ add_spvtools_unittest(TARGET val_abcde
|
||||
val_data_test.cpp
|
||||
val_decoration_test.cpp
|
||||
val_derivatives_test.cpp
|
||||
val_explicit_reserved_test.cpp
|
||||
val_extensions_test.cpp
|
||||
val_ext_inst_test.cpp
|
||||
${VAL_TEST_COMMON_SRCS}
|
||||
|
@ -1965,6 +1965,10 @@ OpMemoryModel Physical64 OpenCL
|
||||
"Embedded Profile"));
|
||||
}
|
||||
|
||||
// Three tests to check enablement of an enum (a decoration) which is not
|
||||
// in core, and is directly enabled by a capability, but not directly enabled
|
||||
// by an extension. See https://github.com/KhronosGroup/SPIRV-Tools/issues/1596
|
||||
|
||||
TEST_F(ValidateCapability, DecorationFromExtensionMissingEnabledByCapability) {
|
||||
// Decoration ViewportRelativeNV is enabled by ShaderViewportMaskNV, which in
|
||||
// turn is enabled by SPV_NV_viewport_array2.
|
||||
@ -2017,4 +2021,92 @@ OpDecorate %void ViewportRelativeNV
|
||||
<< getDiagnosticString();
|
||||
}
|
||||
|
||||
// Three tests to check enablement of an instruction which is not in core, and
|
||||
// is directly enabled by a capability, but not directly enabled by an
|
||||
// extension. See https://github.com/KhronosGroup/SPIRV-Tools/issues/1624
|
||||
// Instruction OpSubgroupShuffleINTEL is enabled by SubgroupShuffleINTEL, which
|
||||
// in turn is enabled by SPV_INTEL_subgroups.
|
||||
|
||||
TEST_F(ValidateCapability, InstructionFromExtensionMissingEnabledByCapability) {
|
||||
// Decoration ViewportRelativeNV is enabled by ShaderViewportMaskNV, which in
|
||||
// turn is enabled by SPV_NV_viewport_array2.
|
||||
const std::string spirv = R"(
|
||||
OpCapability Kernel
|
||||
OpCapability Addresses
|
||||
; OpCapability SubgroupShuffleINTEL
|
||||
OpExtension "SPV_INTEL_subgroups"
|
||||
OpMemoryModel Physical32 OpenCL
|
||||
OpEntryPoint Kernel %main "main"
|
||||
%void = OpTypeVoid
|
||||
%uint = OpTypeInt 32 0
|
||||
%voidfn = OpTypeFunction %void
|
||||
%zero = OpConstant %uint 0
|
||||
%main = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
%foo = OpSubgroupShuffleINTEL %uint %zero %zero
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_0);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY,
|
||||
ValidateInstructions(SPV_ENV_UNIVERSAL_1_0));
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("Opcode SubgroupShuffleINTEL requires one of these "
|
||||
"capabilities: SubgroupShuffleINTEL"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateCapability,
|
||||
InstructionEnablingCapabilityEnabledByMissingExtension) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Kernel
|
||||
OpCapability Addresses
|
||||
OpCapability SubgroupShuffleINTEL
|
||||
; OpExtension "SPV_INTEL_subgroups"
|
||||
OpMemoryModel Physical32 OpenCL
|
||||
OpEntryPoint Kernel %main "main"
|
||||
%void = OpTypeVoid
|
||||
%uint = OpTypeInt 32 0
|
||||
%voidfn = OpTypeFunction %void
|
||||
%zero = OpConstant %uint 0
|
||||
%main = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
%foo = OpSubgroupShuffleINTEL %uint %zero %zero
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_0);
|
||||
EXPECT_EQ(SPV_ERROR_MISSING_EXTENSION,
|
||||
ValidateInstructions(SPV_ENV_UNIVERSAL_1_0));
|
||||
EXPECT_THAT(getDiagnosticString(),
|
||||
HasSubstr("operand 5568 requires one of these extensions: "
|
||||
"SPV_INTEL_subgroups"));
|
||||
}
|
||||
|
||||
TEST_F(ValidateCapability,
|
||||
InstructionEnabledByCapabilityEnabledByPresentExtension) {
|
||||
const std::string spirv = R"(
|
||||
OpCapability Kernel
|
||||
OpCapability Addresses
|
||||
OpCapability SubgroupShuffleINTEL
|
||||
OpExtension "SPV_INTEL_subgroups"
|
||||
OpMemoryModel Physical32 OpenCL
|
||||
OpEntryPoint Kernel %main "main"
|
||||
%void = OpTypeVoid
|
||||
%uint = OpTypeInt 32 0
|
||||
%voidfn = OpTypeFunction %void
|
||||
%zero = OpConstant %uint 0
|
||||
%main = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
%foo = OpSubgroupShuffleINTEL %uint %zero %zero
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_0);
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_0))
|
||||
<< getDiagnosticString();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
117
test/val/val_explicit_reserved_test.cpp
Normal file
117
test/val/val_explicit_reserved_test.cpp
Normal file
@ -0,0 +1,117 @@
|
||||
// Copyright (c) 2018 Google LLC.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// Validation tests for illegal instructions
|
||||
|
||||
#include "unit_spirv.h"
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "val_fixtures.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using ::testing::Eq;
|
||||
using ::testing::HasSubstr;
|
||||
|
||||
using ReservedSamplingInstTest = spvtest::ValidateBase<std::string>;
|
||||
|
||||
// Generate a shader for use with validation tests for sparse sampling
|
||||
// instructions.
|
||||
std::string ShaderAssembly(const std::string& instruction_under_test) {
|
||||
std::ostringstream os;
|
||||
os << R"( OpCapability Shader
|
||||
OpCapability SparseResidency
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %1 "main"
|
||||
OpExecutionMode %1 OriginUpperLeft
|
||||
OpSource GLSL 450
|
||||
OpDecorate %2 DescriptorSet 0
|
||||
OpDecorate %2 Binding 0
|
||||
%void = OpTypeVoid
|
||||
%4 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
%float_0 = OpConstant %float 0
|
||||
%8 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
|
||||
%9 = OpTypeImage %float 2D 0 0 0 1 Unknown
|
||||
%10 = OpTypeSampledImage %9
|
||||
%_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10
|
||||
%2 = OpVariable %_ptr_UniformConstant_10 UniformConstant
|
||||
%v2float = OpTypeVector %float 2
|
||||
%13 = OpConstantComposite %v2float %float_0 %float_0
|
||||
%int = OpTypeInt 32 1
|
||||
%_struct_15 = OpTypeStruct %int %v4float
|
||||
%1 = OpFunction %void None %4
|
||||
%16 = OpLabel
|
||||
%17 = OpLoad %10 %2
|
||||
)" << instruction_under_test
|
||||
<< R"(
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
return os.str();
|
||||
}
|
||||
|
||||
TEST_F(ReservedSamplingInstTest, OpImageSparseSampleProjImplicitLod) {
|
||||
const std::string input = ShaderAssembly(
|
||||
"%result = OpImageSparseSampleProjImplicitLod %_struct_15 %17 %13");
|
||||
CompileSuccessfully(input);
|
||||
|
||||
EXPECT_THAT(ValidateInstructions(), Eq(SPV_ERROR_INVALID_BINARY));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("Invalid Opcode name 'OpImageSparseSampleProjImplicitLod'"));
|
||||
}
|
||||
|
||||
TEST_F(ReservedSamplingInstTest, OpImageSparseSampleProjExplicitLod) {
|
||||
const std::string input = ShaderAssembly(
|
||||
"%result = OpImageSparseSampleProjExplicitLod %_struct_15 %17 %13 Lod "
|
||||
"%float_0\n");
|
||||
CompileSuccessfully(input);
|
||||
|
||||
EXPECT_THAT(ValidateInstructions(), Eq(SPV_ERROR_INVALID_BINARY));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("Invalid Opcode name 'OpImageSparseSampleProjExplicitLod'"));
|
||||
}
|
||||
|
||||
TEST_F(ReservedSamplingInstTest, OpImageSparseSampleProjDrefImplicitLod) {
|
||||
const std::string input = ShaderAssembly(
|
||||
"%result = OpImageSparseSampleProjDrefImplicitLod %_struct_15 %17 %13 "
|
||||
"%float_0\n");
|
||||
CompileSuccessfully(input);
|
||||
|
||||
EXPECT_THAT(ValidateInstructions(), Eq(SPV_ERROR_INVALID_BINARY));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"Invalid Opcode name 'OpImageSparseSampleProjDrefImplicitLod'"));
|
||||
}
|
||||
|
||||
TEST_F(ReservedSamplingInstTest, OpImageSparseSampleProjDrefExplicitLod) {
|
||||
const std::string input = ShaderAssembly(
|
||||
"%result = OpImageSparseSampleProjDrefExplicitLod %_struct_15 %17 %13 "
|
||||
"%float_0 Lod "
|
||||
"%float_0\n");
|
||||
CompileSuccessfully(input);
|
||||
|
||||
EXPECT_THAT(ValidateInstructions(), Eq(SPV_ERROR_INVALID_BINARY));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"Invalid Opcode name 'OpImageSparseSampleProjDrefExplicitLod'"));
|
||||
}
|
||||
|
||||
} // namespace
|
Loading…
Reference in New Issue
Block a user