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:
David Neto 2018-06-19 09:54:33 -04:00
parent f80696eaf6
commit 8d65c89678
11 changed files with 317 additions and 102 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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) {

View File

@ -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) {

View File

@ -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

View File

@ -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) {

View File

@ -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) {

View File

@ -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}

View File

@ -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

View 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