mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2025-01-13 09:50:06 +00:00
Basic validation for Component decorations (#2679)
* Add basic validation for Component decoration * Add validator tests for Component decoration
This commit is contained in:
parent
69b9459925
commit
7c294608ca
@ -1393,6 +1393,81 @@ spv_result_t CheckIntegerWrapDecoration(ValidationState_t& vstate,
|
|||||||
<< spvOpcodeString(inst.opcode());
|
<< spvOpcodeString(inst.opcode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns SPV_SUCCESS if validation rules are satisfied for the Component
|
||||||
|
// decoration. Otherwise emits a diagnostic and returns something other than
|
||||||
|
// SPV_SUCCESS.
|
||||||
|
spv_result_t CheckComponentDecoration(ValidationState_t& vstate,
|
||||||
|
const Instruction& inst,
|
||||||
|
const Decoration& decoration) {
|
||||||
|
assert(inst.id() && "Parser ensures the target of the decoration has an ID");
|
||||||
|
|
||||||
|
uint32_t type_id;
|
||||||
|
if (decoration.struct_member_index() == Decoration::kInvalidMember) {
|
||||||
|
// The target must be a memory object declaration.
|
||||||
|
const auto opcode = inst.opcode();
|
||||||
|
if (opcode != SpvOpVariable && opcode != SpvOpFunctionParameter) {
|
||||||
|
return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
|
||||||
|
<< "Target of Component decoration must be a memory object "
|
||||||
|
"declaration (a variable or a function parameter)";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only valid for the Input and Output Storage Classes.
|
||||||
|
const auto storage_class = opcode == SpvOpVariable
|
||||||
|
? inst.GetOperandAs<SpvStorageClass>(2)
|
||||||
|
: SpvStorageClassMax;
|
||||||
|
if (storage_class != SpvStorageClassInput &&
|
||||||
|
storage_class != SpvStorageClassOutput &&
|
||||||
|
storage_class != SpvStorageClassMax) {
|
||||||
|
return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
|
||||||
|
<< "Target of Component decoration is invalid: must point to a "
|
||||||
|
"Storage Class of Input(1) or Output(3). Found Storage "
|
||||||
|
"Class "
|
||||||
|
<< storage_class;
|
||||||
|
}
|
||||||
|
|
||||||
|
type_id = inst.type_id();
|
||||||
|
if (vstate.IsPointerType(type_id)) {
|
||||||
|
const auto pointer = vstate.FindDef(type_id);
|
||||||
|
type_id = pointer->GetOperandAs<uint32_t>(2);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (inst.opcode() != SpvOpTypeStruct) {
|
||||||
|
return vstate.diag(SPV_ERROR_INVALID_DATA, &inst)
|
||||||
|
<< "Attempted to get underlying data type via member index for "
|
||||||
|
"non-struct type.";
|
||||||
|
}
|
||||||
|
type_id = inst.word(decoration.struct_member_index() + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spvIsVulkanEnv(vstate.context()->target_env)) {
|
||||||
|
if (!vstate.IsIntScalarOrVectorType(type_id) &&
|
||||||
|
!vstate.IsFloatScalarOrVectorType(type_id)) {
|
||||||
|
return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
|
||||||
|
<< "Component decoration specified for type "
|
||||||
|
<< vstate.getIdName(type_id) << " that is not a scalar or vector";
|
||||||
|
}
|
||||||
|
|
||||||
|
// For 16-, and 32-bit types, it is invalid if this sequence of components
|
||||||
|
// gets larger than 3.
|
||||||
|
const auto bit_width = vstate.GetBitWidth(type_id);
|
||||||
|
if (bit_width == 16 || bit_width == 32) {
|
||||||
|
assert(decoration.params().size() == 1 &&
|
||||||
|
"Grammar ensures Component has one parameter");
|
||||||
|
|
||||||
|
const auto component = decoration.params()[0];
|
||||||
|
const auto last_component = component + vstate.GetDimension(type_id) - 1;
|
||||||
|
if (last_component > 3) {
|
||||||
|
return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
|
||||||
|
<< "Sequence of components starting with " << component
|
||||||
|
<< " and ending with " << last_component
|
||||||
|
<< " gets larger than 3";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SPV_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
#define PASS_OR_BAIL_AT_LINE(X, LINE) \
|
#define PASS_OR_BAIL_AT_LINE(X, LINE) \
|
||||||
{ \
|
{ \
|
||||||
spv_result_t e##LINE = (X); \
|
spv_result_t e##LINE = (X); \
|
||||||
@ -1421,6 +1496,9 @@ spv_result_t CheckDecorationsFromDecoration(ValidationState_t& vstate) {
|
|||||||
|
|
||||||
for (const auto& decoration : decorations) {
|
for (const auto& decoration : decorations) {
|
||||||
switch (decoration.dec_type()) {
|
switch (decoration.dec_type()) {
|
||||||
|
case SpvDecorationComponent:
|
||||||
|
PASS_OR_BAIL(CheckComponentDecoration(vstate, *inst, decoration));
|
||||||
|
break;
|
||||||
case SpvDecorationFPRoundingMode:
|
case SpvDecorationFPRoundingMode:
|
||||||
if (is_shader)
|
if (is_shader)
|
||||||
PASS_OR_BAIL(CheckFPRoundingModeForShaders(vstate, *inst));
|
PASS_OR_BAIL(CheckFPRoundingModeForShaders(vstate, *inst));
|
||||||
|
@ -1168,8 +1168,10 @@ std::make_pair(std::string(kOpenCLMemoryModel) +
|
|||||||
ShaderDependencies()),
|
ShaderDependencies()),
|
||||||
std::make_pair(std::string(kOpenCLMemoryModel) +
|
std::make_pair(std::string(kOpenCLMemoryModel) +
|
||||||
"OpEntryPoint Kernel %func \"compute\" \n"
|
"OpEntryPoint Kernel %func \"compute\" \n"
|
||||||
"OpDecorate %intt Component 0\n"
|
"OpDecorate %var Component 0\n"
|
||||||
"%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid),
|
"%intt = OpTypeInt 32 0\n"
|
||||||
|
"%ptr = OpTypePointer Input %intt\n"
|
||||||
|
"%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid),
|
||||||
ShaderDependencies()),
|
ShaderDependencies()),
|
||||||
std::make_pair(std::string(kOpenCLMemoryModel) +
|
std::make_pair(std::string(kOpenCLMemoryModel) +
|
||||||
"OpEntryPoint Kernel %func \"compute\" \n"
|
"OpEntryPoint Kernel %func \"compute\" \n"
|
||||||
|
@ -6400,6 +6400,314 @@ OpDecorate %1 BufferBlock
|
|||||||
"requires SPIR-V version 1.3 or earlier"));
|
"requires SPIR-V version 1.3 or earlier"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Component
|
||||||
|
|
||||||
|
TEST_F(ValidateDecorations, ComponentDecorationBadTarget) {
|
||||||
|
std::string spirv = R"(
|
||||||
|
OpCapability Shader
|
||||||
|
OpMemoryModel Logical GLSL450
|
||||||
|
OpEntryPoint Vertex %main "main"
|
||||||
|
OpDecorate %t Component 0
|
||||||
|
%void = OpTypeVoid
|
||||||
|
%3 = OpTypeFunction %void
|
||||||
|
%float = OpTypeFloat 32
|
||||||
|
%t = OpTypeVector %float 2
|
||||||
|
%main = OpFunction %void None %3
|
||||||
|
%5 = OpLabel
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
|
)";
|
||||||
|
|
||||||
|
CompileSuccessfully(spirv);
|
||||||
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
|
||||||
|
EXPECT_THAT(getDiagnosticString(),
|
||||||
|
HasSubstr("Target of Component decoration must be "
|
||||||
|
"a memory object declaration"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateDecorations, ComponentDecorationBadStorageClass) {
|
||||||
|
std::string spirv = R"(
|
||||||
|
OpCapability Shader
|
||||||
|
OpMemoryModel Logical GLSL450
|
||||||
|
OpEntryPoint Vertex %main "main"
|
||||||
|
OpDecorate %v Component 0
|
||||||
|
%void = OpTypeVoid
|
||||||
|
%3 = OpTypeFunction %void
|
||||||
|
%float = OpTypeFloat 32
|
||||||
|
%t = OpTypeVector %float 2
|
||||||
|
%ptr_private = OpTypePointer Private %t
|
||||||
|
%v = OpVariable %ptr_private Private
|
||||||
|
%main = OpFunction %void None %3
|
||||||
|
%5 = OpLabel
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
|
)";
|
||||||
|
|
||||||
|
CompileSuccessfully(spirv);
|
||||||
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
|
||||||
|
EXPECT_THAT(getDiagnosticString(),
|
||||||
|
HasSubstr("Target of Component decoration is invalid: must "
|
||||||
|
"point to a Storage Class of Input(1) or Output(3)"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateDecorations, ComponentDecorationBadTypeVulkan) {
|
||||||
|
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||||
|
std::string spirv = R"(
|
||||||
|
OpCapability Shader
|
||||||
|
OpCapability Matrix
|
||||||
|
OpMemoryModel Logical GLSL450
|
||||||
|
OpEntryPoint Vertex %main "main"
|
||||||
|
OpDecorate %v Component 0
|
||||||
|
%void = OpTypeVoid
|
||||||
|
%3 = OpTypeFunction %void
|
||||||
|
%float = OpTypeFloat 32
|
||||||
|
%vtype = OpTypeVector %float 4
|
||||||
|
%t = OpTypeMatrix %vtype 4
|
||||||
|
%ptr_input = OpTypePointer Input %t
|
||||||
|
%v = OpVariable %ptr_input Input
|
||||||
|
%main = OpFunction %void None %3
|
||||||
|
%5 = OpLabel
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
|
)";
|
||||||
|
|
||||||
|
CompileSuccessfully(spirv, env);
|
||||||
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
|
||||||
|
EXPECT_THAT(getDiagnosticString(),
|
||||||
|
HasSubstr("Component decoration specified for type"));
|
||||||
|
EXPECT_THAT(getDiagnosticString(), HasSubstr("is not a scalar or vector"));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ShaderWithComponentDecoration(const std::string& type,
|
||||||
|
const std::string& decoration) {
|
||||||
|
return R"(
|
||||||
|
OpCapability Shader
|
||||||
|
OpMemoryModel Logical GLSL450
|
||||||
|
OpEntryPoint Fragment %main "main" %entryPointOutput
|
||||||
|
OpExecutionMode %main OriginUpperLeft
|
||||||
|
OpDecorate %entryPointOutput Location 0
|
||||||
|
OpDecorate %entryPointOutput )" +
|
||||||
|
decoration + R"(
|
||||||
|
%void = OpTypeVoid
|
||||||
|
%3 = OpTypeFunction %void
|
||||||
|
%float = OpTypeFloat 32
|
||||||
|
%vtype = )" + type + R"(
|
||||||
|
%float_0 = OpConstant %float 0
|
||||||
|
%_ptr_Output_vtype = OpTypePointer Output %vtype
|
||||||
|
%entryPointOutput = OpVariable %_ptr_Output_vtype Output
|
||||||
|
%main = OpFunction %void None %3
|
||||||
|
%5 = OpLabel
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
|
)";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateDecorations, ComponentDecorationIntGood0Vulkan) {
|
||||||
|
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||||
|
std::string spirv =
|
||||||
|
ShaderWithComponentDecoration("OpTypeInt 32 0", "Component 0");
|
||||||
|
|
||||||
|
CompileSuccessfully(spirv, env);
|
||||||
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
|
||||||
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateDecorations, ComponentDecorationIntGood1Vulkan) {
|
||||||
|
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||||
|
std::string spirv =
|
||||||
|
ShaderWithComponentDecoration("OpTypeInt 32 0", "Component 1");
|
||||||
|
|
||||||
|
CompileSuccessfully(spirv, env);
|
||||||
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
|
||||||
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateDecorations, ComponentDecorationIntGood2Vulkan) {
|
||||||
|
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||||
|
std::string spirv =
|
||||||
|
ShaderWithComponentDecoration("OpTypeInt 32 0", "Component 2");
|
||||||
|
|
||||||
|
CompileSuccessfully(spirv, env);
|
||||||
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
|
||||||
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateDecorations, ComponentDecorationIntGood3Vulkan) {
|
||||||
|
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||||
|
std::string spirv =
|
||||||
|
ShaderWithComponentDecoration("OpTypeInt 32 0", "Component 3");
|
||||||
|
|
||||||
|
CompileSuccessfully(spirv, env);
|
||||||
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
|
||||||
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateDecorations, ComponentDecorationIntBad4Vulkan) {
|
||||||
|
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||||
|
std::string spirv =
|
||||||
|
ShaderWithComponentDecoration("OpTypeInt 32 0", "Component 4");
|
||||||
|
|
||||||
|
CompileSuccessfully(spirv, env);
|
||||||
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
|
||||||
|
EXPECT_THAT(getDiagnosticString(),
|
||||||
|
HasSubstr("Sequence of components starting with 4 "
|
||||||
|
"and ending with 4 gets larger than 3"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateDecorations, ComponentDecorationVector3GoodVulkan) {
|
||||||
|
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||||
|
std::string spirv =
|
||||||
|
ShaderWithComponentDecoration("OpTypeVector %float 3", "Component 1");
|
||||||
|
|
||||||
|
CompileSuccessfully(spirv, env);
|
||||||
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
|
||||||
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateDecorations, ComponentDecorationVector4GoodVulkan) {
|
||||||
|
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||||
|
std::string spirv =
|
||||||
|
ShaderWithComponentDecoration("OpTypeVector %float 4", "Component 0");
|
||||||
|
|
||||||
|
CompileSuccessfully(spirv, env);
|
||||||
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env));
|
||||||
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateDecorations, ComponentDecorationVector4Bad1Vulkan) {
|
||||||
|
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||||
|
std::string spirv =
|
||||||
|
ShaderWithComponentDecoration("OpTypeVector %float 4", "Component 1");
|
||||||
|
|
||||||
|
CompileSuccessfully(spirv, env);
|
||||||
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
|
||||||
|
EXPECT_THAT(getDiagnosticString(),
|
||||||
|
HasSubstr("Sequence of components starting with 1 "
|
||||||
|
"and ending with 4 gets larger than 3"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateDecorations, ComponentDecorationVector4Bad3Vulkan) {
|
||||||
|
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||||
|
std::string spirv =
|
||||||
|
ShaderWithComponentDecoration("OpTypeVector %float 4", "Component 3");
|
||||||
|
|
||||||
|
CompileSuccessfully(spirv, env);
|
||||||
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
|
||||||
|
EXPECT_THAT(getDiagnosticString(),
|
||||||
|
HasSubstr("Sequence of components starting with 3 "
|
||||||
|
"and ending with 6 gets larger than 3"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateDecorations, ComponentDecorationBlockGood) {
|
||||||
|
std::string spirv = R"(
|
||||||
|
OpCapability Shader
|
||||||
|
OpMemoryModel Logical GLSL450
|
||||||
|
OpEntryPoint Fragment %4 "main" %9 %12
|
||||||
|
OpExecutionMode %4 OriginUpperLeft
|
||||||
|
OpDecorate %9 Location 0
|
||||||
|
OpMemberDecorate %block 0 Location 2
|
||||||
|
OpMemberDecorate %block 0 Component 1
|
||||||
|
OpDecorate %block Block
|
||||||
|
%2 = OpTypeVoid
|
||||||
|
%3 = OpTypeFunction %2
|
||||||
|
%float = OpTypeFloat 32
|
||||||
|
%vec3 = OpTypeVector %float 3
|
||||||
|
%8 = OpTypePointer Output %vec3
|
||||||
|
%9 = OpVariable %8 Output
|
||||||
|
%block = OpTypeStruct %vec3
|
||||||
|
%11 = OpTypePointer Input %block
|
||||||
|
%12 = OpVariable %11 Input
|
||||||
|
%int = OpTypeInt 32 1
|
||||||
|
%14 = OpConstant %int 0
|
||||||
|
%15 = OpTypePointer Input %vec3
|
||||||
|
%4 = OpFunction %2 None %3
|
||||||
|
%5 = OpLabel
|
||||||
|
%16 = OpAccessChain %15 %12 %14
|
||||||
|
%17 = OpLoad %vec3 %16
|
||||||
|
OpStore %9 %17
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
|
)";
|
||||||
|
|
||||||
|
CompileSuccessfully(spirv);
|
||||||
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
|
||||||
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateDecorations, ComponentDecorationBlockBadVulkan) {
|
||||||
|
const spv_target_env env = SPV_ENV_VULKAN_1_0;
|
||||||
|
std::string spirv = R"(
|
||||||
|
OpCapability Shader
|
||||||
|
OpMemoryModel Logical GLSL450
|
||||||
|
OpEntryPoint Fragment %4 "main" %9 %12
|
||||||
|
OpExecutionMode %4 OriginUpperLeft
|
||||||
|
OpDecorate %9 Location 0
|
||||||
|
OpMemberDecorate %block 0 Location 2
|
||||||
|
OpMemberDecorate %block 0 Component 2
|
||||||
|
OpDecorate %block Block
|
||||||
|
%2 = OpTypeVoid
|
||||||
|
%3 = OpTypeFunction %2
|
||||||
|
%float = OpTypeFloat 32
|
||||||
|
%vec3 = OpTypeVector %float 3
|
||||||
|
%8 = OpTypePointer Output %vec3
|
||||||
|
%9 = OpVariable %8 Output
|
||||||
|
%block = OpTypeStruct %vec3
|
||||||
|
%11 = OpTypePointer Input %block
|
||||||
|
%12 = OpVariable %11 Input
|
||||||
|
%int = OpTypeInt 32 1
|
||||||
|
%14 = OpConstant %int 0
|
||||||
|
%15 = OpTypePointer Input %vec3
|
||||||
|
%4 = OpFunction %2 None %3
|
||||||
|
%5 = OpLabel
|
||||||
|
%16 = OpAccessChain %15 %12 %14
|
||||||
|
%17 = OpLoad %vec3 %16
|
||||||
|
OpStore %9 %17
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
|
)";
|
||||||
|
|
||||||
|
CompileSuccessfully(spirv, env);
|
||||||
|
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env));
|
||||||
|
EXPECT_THAT(getDiagnosticString(),
|
||||||
|
HasSubstr("Sequence of components starting with 2 "
|
||||||
|
"and ending with 4 gets larger than 3"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateDecorations, ComponentDecorationFunctionParameter) {
|
||||||
|
std::string spirv = R"(
|
||||||
|
OpCapability Shader
|
||||||
|
OpMemoryModel Logical GLSL450
|
||||||
|
OpEntryPoint Vertex %main "main"
|
||||||
|
|
||||||
|
OpDecorate %param_f Component 0
|
||||||
|
|
||||||
|
%void = OpTypeVoid
|
||||||
|
%void_fn = OpTypeFunction %void
|
||||||
|
%float = OpTypeFloat 32
|
||||||
|
%float_0 = OpConstant %float 0
|
||||||
|
%int = OpTypeInt 32 0
|
||||||
|
%int_2 = OpConstant %int 2
|
||||||
|
%struct_b = OpTypeStruct %float
|
||||||
|
|
||||||
|
%extra_fn = OpTypeFunction %void %float
|
||||||
|
|
||||||
|
%helper = OpFunction %void None %extra_fn
|
||||||
|
%param_f = OpFunctionParameter %float
|
||||||
|
%helper_label = OpLabel
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
|
|
||||||
|
%main = OpFunction %void None %void_fn
|
||||||
|
%label = OpLabel
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
|
)";
|
||||||
|
|
||||||
|
CompileSuccessfully(spirv);
|
||||||
|
EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
|
||||||
|
EXPECT_THAT(getDiagnosticString(), Eq(""));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace val
|
} // namespace val
|
||||||
} // namespace spvtools
|
} // namespace spvtools
|
||||||
|
Loading…
Reference in New Issue
Block a user