mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-12-26 17:51:02 +00:00
Add validation for Subgroup builtins (#2637)
Fixes #2611 * Validates builtins in the Vulkan environment: * NumSubgroups * SubgroupId * SubgroupEqMask * SubgroupGeMask * SubgroupGtMask * SubgroupLeMask * SubgroupLtMask * SubgroupLocalInvocationId * SubgroupSize
This commit is contained in:
parent
9c0830133b
commit
b4bf7bcf0a
@ -211,6 +211,17 @@ class BuiltInsValidator {
|
||||
spv_result_t ValidateSMBuiltinsAtDefinition(const Decoration& decoration,
|
||||
const Instruction& inst);
|
||||
|
||||
// Used for SubgroupEqMask, SubgroupGeMask, SubgroupGtMask, SubgroupLtMask,
|
||||
// SubgroupLeMask.
|
||||
spv_result_t ValidateI32Vec4InputAtDefinition(const Decoration& decoration,
|
||||
const Instruction& inst);
|
||||
// Used for SubgroupLocalInvocationId, SubgroupSize.
|
||||
spv_result_t ValidateI32InputAtDefinition(const Decoration& decoration,
|
||||
const Instruction& inst);
|
||||
// Used for SubgroupId, NumSubgroups.
|
||||
spv_result_t ValidateComputeI32InputAtDefinition(const Decoration& decoration,
|
||||
const Instruction& inst);
|
||||
|
||||
// The following section contains functions which are called when id defined
|
||||
// by |referenced_inst| is
|
||||
// 1. referenced by |referenced_from_inst|
|
||||
@ -333,6 +344,11 @@ class BuiltInsValidator {
|
||||
const Decoration& decoration, const Instruction& built_in_inst,
|
||||
const Instruction& referenced_inst,
|
||||
const Instruction& referenced_from_inst);
|
||||
// Used for SubgroupId and NumSubgroups.
|
||||
spv_result_t ValidateComputeI32InputAtReference(
|
||||
const Decoration& decoration, const Instruction& built_in_inst,
|
||||
const Instruction& referenced_inst,
|
||||
const Instruction& referenced_from_inst);
|
||||
|
||||
spv_result_t ValidateSMBuiltinsAtReference(
|
||||
const Decoration& decoration, const Instruction& built_in_inst,
|
||||
@ -2603,6 +2619,171 @@ spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference(
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
spv_result_t BuiltInsValidator::ValidateComputeI32InputAtDefinition(
|
||||
const Decoration& decoration, const Instruction& inst) {
|
||||
if (spvIsVulkanEnv(_.context()->target_env)) {
|
||||
if (decoration.struct_member_index() != Decoration::kInvalidMember) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
|
||||
<< "BuiltIn "
|
||||
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
|
||||
decoration.params()[0])
|
||||
<< " cannot be used as a member decoration ";
|
||||
}
|
||||
if (spv_result_t error = ValidateI32(
|
||||
decoration, inst,
|
||||
[this, &decoration,
|
||||
&inst](const std::string& message) -> spv_result_t {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
|
||||
<< "According to the "
|
||||
<< spvLogStringForEnv(_.context()->target_env)
|
||||
<< " spec BuiltIn "
|
||||
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
|
||||
decoration.params()[0])
|
||||
<< " variable needs to be a 32-bit int "
|
||||
"vector. "
|
||||
<< message;
|
||||
})) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
// Seed at reference checks with this built-in.
|
||||
return ValidateComputeI32InputAtReference(decoration, inst, inst, inst);
|
||||
}
|
||||
|
||||
spv_result_t BuiltInsValidator::ValidateComputeI32InputAtReference(
|
||||
const Decoration& decoration, const Instruction& built_in_inst,
|
||||
const Instruction& referenced_inst,
|
||||
const Instruction& referenced_from_inst) {
|
||||
if (spvIsVulkanEnv(_.context()->target_env)) {
|
||||
const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
|
||||
if (storage_class != SpvStorageClassMax &&
|
||||
storage_class != SpvStorageClassInput) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
|
||||
<< spvLogStringForEnv(_.context()->target_env)
|
||||
<< " spec allows BuiltIn "
|
||||
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
|
||||
decoration.params()[0])
|
||||
<< " to be only used for variables with Input storage class. "
|
||||
<< GetReferenceDesc(decoration, built_in_inst, referenced_inst,
|
||||
referenced_from_inst)
|
||||
<< " " << GetStorageClassDesc(referenced_from_inst);
|
||||
}
|
||||
|
||||
for (const SpvExecutionModel execution_model : execution_models_) {
|
||||
bool has_vulkan_model = execution_model == SpvExecutionModelGLCompute ||
|
||||
execution_model == SpvExecutionModelTaskNV ||
|
||||
execution_model == SpvExecutionModelMeshNV;
|
||||
if (spvIsVulkanEnv(_.context()->target_env) && !has_vulkan_model) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
|
||||
<< spvLogStringForEnv(_.context()->target_env)
|
||||
<< " spec allows BuiltIn "
|
||||
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
|
||||
decoration.params()[0])
|
||||
<< " to be used only with GLCompute execution model. "
|
||||
<< GetReferenceDesc(decoration, built_in_inst, referenced_inst,
|
||||
referenced_from_inst, execution_model);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (function_id_ == 0) {
|
||||
// Propagate this rule to all dependant ids in the global scope.
|
||||
id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
|
||||
std::bind(&BuiltInsValidator::ValidateComputeI32InputAtReference, this,
|
||||
decoration, built_in_inst, referenced_from_inst,
|
||||
std::placeholders::_1));
|
||||
}
|
||||
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
spv_result_t BuiltInsValidator::ValidateI32InputAtDefinition(
|
||||
const Decoration& decoration, const Instruction& inst) {
|
||||
if (spvIsVulkanEnv(_.context()->target_env)) {
|
||||
if (decoration.struct_member_index() != Decoration::kInvalidMember) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
|
||||
<< "BuiltIn "
|
||||
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
|
||||
decoration.params()[0])
|
||||
<< " cannot be used as a member decoration ";
|
||||
}
|
||||
if (spv_result_t error = ValidateI32(
|
||||
decoration, inst,
|
||||
[this, &decoration,
|
||||
&inst](const std::string& message) -> spv_result_t {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
|
||||
<< "According to the "
|
||||
<< spvLogStringForEnv(_.context()->target_env)
|
||||
<< " spec BuiltIn "
|
||||
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
|
||||
decoration.params()[0])
|
||||
<< " variable needs to be a 32-bit int. " << message;
|
||||
})) {
|
||||
return error;
|
||||
}
|
||||
|
||||
const SpvStorageClass storage_class = GetStorageClass(inst);
|
||||
if (storage_class != SpvStorageClassMax &&
|
||||
storage_class != SpvStorageClassInput) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
|
||||
<< spvLogStringForEnv(_.context()->target_env)
|
||||
<< " spec allows BuiltIn "
|
||||
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
|
||||
decoration.params()[0])
|
||||
<< " to be only used for variables with Input storage class. "
|
||||
<< GetReferenceDesc(decoration, inst, inst, inst) << " "
|
||||
<< GetStorageClassDesc(inst);
|
||||
}
|
||||
}
|
||||
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
spv_result_t BuiltInsValidator::ValidateI32Vec4InputAtDefinition(
|
||||
const Decoration& decoration, const Instruction& inst) {
|
||||
if (spvIsVulkanEnv(_.context()->target_env)) {
|
||||
if (decoration.struct_member_index() != Decoration::kInvalidMember) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
|
||||
<< "BuiltIn "
|
||||
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
|
||||
decoration.params()[0])
|
||||
<< " cannot be used as a member decoration ";
|
||||
}
|
||||
if (spv_result_t error = ValidateI32Vec(
|
||||
decoration, inst, 4,
|
||||
[this, &decoration,
|
||||
&inst](const std::string& message) -> spv_result_t {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
|
||||
<< "According to the "
|
||||
<< spvLogStringForEnv(_.context()->target_env)
|
||||
<< " spec BuiltIn "
|
||||
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
|
||||
decoration.params()[0])
|
||||
<< " variable needs to be a 4-component 32-bit int "
|
||||
"vector. "
|
||||
<< message;
|
||||
})) {
|
||||
return error;
|
||||
}
|
||||
|
||||
const SpvStorageClass storage_class = GetStorageClass(inst);
|
||||
if (storage_class != SpvStorageClassMax &&
|
||||
storage_class != SpvStorageClassInput) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
|
||||
<< spvLogStringForEnv(_.context()->target_env)
|
||||
<< " spec allows BuiltIn "
|
||||
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
|
||||
decoration.params()[0])
|
||||
<< " to be only used for variables with Input storage class. "
|
||||
<< GetReferenceDesc(decoration, inst, inst, inst) << " "
|
||||
<< GetStorageClassDesc(inst);
|
||||
}
|
||||
}
|
||||
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtDefinition(
|
||||
const Decoration& decoration, const Instruction& inst) {
|
||||
if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) {
|
||||
@ -2788,6 +2969,21 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
|
||||
case SpvBuiltInSamplePosition: {
|
||||
return ValidateSamplePositionAtDefinition(decoration, inst);
|
||||
}
|
||||
case SpvBuiltInSubgroupId:
|
||||
case SpvBuiltInNumSubgroups: {
|
||||
return ValidateComputeI32InputAtDefinition(decoration, inst);
|
||||
}
|
||||
case SpvBuiltInSubgroupLocalInvocationId:
|
||||
case SpvBuiltInSubgroupSize: {
|
||||
return ValidateI32InputAtDefinition(decoration, inst);
|
||||
}
|
||||
case SpvBuiltInSubgroupEqMask:
|
||||
case SpvBuiltInSubgroupGeMask:
|
||||
case SpvBuiltInSubgroupGtMask:
|
||||
case SpvBuiltInSubgroupLeMask:
|
||||
case SpvBuiltInSubgroupLtMask: {
|
||||
return ValidateI32Vec4InputAtDefinition(decoration, inst);
|
||||
}
|
||||
case SpvBuiltInTessCoord: {
|
||||
return ValidateTessCoordAtDefinition(decoration, inst);
|
||||
}
|
||||
@ -2821,17 +3017,8 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
|
||||
case SpvBuiltInEnqueuedWorkgroupSize:
|
||||
case SpvBuiltInGlobalOffset:
|
||||
case SpvBuiltInGlobalLinearId:
|
||||
case SpvBuiltInSubgroupSize:
|
||||
case SpvBuiltInSubgroupMaxSize:
|
||||
case SpvBuiltInNumSubgroups:
|
||||
case SpvBuiltInNumEnqueuedSubgroups:
|
||||
case SpvBuiltInSubgroupId:
|
||||
case SpvBuiltInSubgroupLocalInvocationId:
|
||||
case SpvBuiltInSubgroupEqMaskKHR:
|
||||
case SpvBuiltInSubgroupGeMaskKHR:
|
||||
case SpvBuiltInSubgroupGtMaskKHR:
|
||||
case SpvBuiltInSubgroupLeMaskKHR:
|
||||
case SpvBuiltInSubgroupLtMaskKHR:
|
||||
case SpvBuiltInBaseVertex:
|
||||
case SpvBuiltInBaseInstance:
|
||||
case SpvBuiltInDrawIndex:
|
||||
|
@ -52,6 +52,8 @@ using ::testing::Values;
|
||||
using ::testing::ValuesIn;
|
||||
|
||||
using ValidateBuiltIns = spvtest::ValidateBase<bool>;
|
||||
using ValidateVulkanSubgroupBuiltIns = spvtest::ValidateBase<
|
||||
std::tuple<const char*, const char*, const char*, const char*, TestResult>>;
|
||||
using ValidateVulkanCombineBuiltInExecutionModelDataTypeResult =
|
||||
spvtest::ValidateBase<std::tuple<const char*, const char*, const char*,
|
||||
const char*, TestResult>>;
|
||||
@ -3080,6 +3082,226 @@ TEST_F(ValidateBuiltIns, GetUnderlyingTypeNoAssert) {
|
||||
"type"));
|
||||
}
|
||||
|
||||
TEST_P(ValidateVulkanSubgroupBuiltIns, InMain) {
|
||||
const char* const built_in = std::get<0>(GetParam());
|
||||
const char* const execution_model = std::get<1>(GetParam());
|
||||
const char* const storage_class = std::get<2>(GetParam());
|
||||
const char* const data_type = std::get<3>(GetParam());
|
||||
const TestResult& test_result = std::get<4>(GetParam());
|
||||
|
||||
CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator();
|
||||
generator.capabilities_ += R"(
|
||||
OpCapability GroupNonUniformBallot
|
||||
)";
|
||||
|
||||
generator.before_types_ = "OpDecorate %built_in_var BuiltIn ";
|
||||
generator.before_types_ += built_in;
|
||||
generator.before_types_ += "\n";
|
||||
|
||||
std::ostringstream after_types;
|
||||
after_types << "%built_in_ptr = OpTypePointer " << storage_class << " "
|
||||
<< data_type << "\n";
|
||||
after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class;
|
||||
after_types << "\n";
|
||||
generator.after_types_ = after_types.str();
|
||||
|
||||
EntryPoint entry_point;
|
||||
entry_point.name = "main";
|
||||
entry_point.execution_model = execution_model;
|
||||
if (strncmp(storage_class, "Input", 5) == 0 ||
|
||||
strncmp(storage_class, "Output", 6) == 0) {
|
||||
entry_point.interfaces = "%built_in_var";
|
||||
}
|
||||
entry_point.body =
|
||||
std::string("%ld = OpLoad ") + data_type + " %built_in_var\n";
|
||||
|
||||
std::ostringstream execution_modes;
|
||||
if (0 == std::strcmp(execution_model, "Fragment")) {
|
||||
execution_modes << "OpExecutionMode %" << entry_point.name
|
||||
<< " OriginUpperLeft\n";
|
||||
if (0 == std::strcmp(built_in, "FragDepth")) {
|
||||
execution_modes << "OpExecutionMode %" << entry_point.name
|
||||
<< " DepthReplacing\n";
|
||||
}
|
||||
}
|
||||
if (0 == std::strcmp(execution_model, "Geometry")) {
|
||||
execution_modes << "OpExecutionMode %" << entry_point.name
|
||||
<< " InputPoints\n";
|
||||
execution_modes << "OpExecutionMode %" << entry_point.name
|
||||
<< " OutputPoints\n";
|
||||
}
|
||||
if (0 == std::strcmp(execution_model, "GLCompute")) {
|
||||
execution_modes << "OpExecutionMode %" << entry_point.name
|
||||
<< " LocalSize 1 1 1\n";
|
||||
}
|
||||
entry_point.execution_modes = execution_modes.str();
|
||||
|
||||
generator.entry_points_.push_back(std::move(entry_point));
|
||||
|
||||
CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_1);
|
||||
ASSERT_EQ(test_result.validation_result,
|
||||
ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
if (test_result.error_str) {
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str));
|
||||
}
|
||||
if (test_result.error_str2) {
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2));
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
SubgroupMaskNotVec4, ValidateVulkanSubgroupBuiltIns,
|
||||
Combine(Values("SubgroupEqMask", "SubgroupGeMask", "SubgroupGtMask",
|
||||
"SubgroupLeMask", "SubgroupLtMask"),
|
||||
Values("GLCompute"), Values("Input"), Values("%u32vec3"),
|
||||
Values(TestResult(SPV_ERROR_INVALID_DATA,
|
||||
"needs to be a 4-component 32-bit int vector"))));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
SubgroupMaskNotU32, ValidateVulkanSubgroupBuiltIns,
|
||||
Combine(Values("SubgroupEqMask", "SubgroupGeMask", "SubgroupGtMask",
|
||||
"SubgroupLeMask", "SubgroupLtMask"),
|
||||
Values("GLCompute"), Values("Input"), Values("%f32vec4"),
|
||||
Values(TestResult(SPV_ERROR_INVALID_DATA,
|
||||
"needs to be a 4-component 32-bit int vector"))));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
SubgroupMaskNotInput, ValidateVulkanSubgroupBuiltIns,
|
||||
Combine(Values("SubgroupEqMask", "SubgroupGeMask", "SubgroupGtMask",
|
||||
"SubgroupLeMask", "SubgroupLtMask"),
|
||||
Values("GLCompute"), Values("Output", "Workgroup", "Private"),
|
||||
Values("%u32vec4"),
|
||||
Values(TestResult(
|
||||
SPV_ERROR_INVALID_DATA,
|
||||
"to be only used for variables with Input storage class"))));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(SubgroupMaskOk, ValidateVulkanSubgroupBuiltIns,
|
||||
Combine(Values("SubgroupEqMask", "SubgroupGeMask",
|
||||
"SubgroupGtMask", "SubgroupLeMask",
|
||||
"SubgroupLtMask"),
|
||||
Values("GLCompute"), Values("Input"),
|
||||
Values("%u32vec4"),
|
||||
Values(TestResult(SPV_SUCCESS, ""))));
|
||||
|
||||
TEST_F(ValidateBuiltIns, SubgroupMaskMemberDecorate) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
OpCapability GroupNonUniformBallot
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %foo "foo"
|
||||
OpExecutionMode %foo LocalSize 1 1 1
|
||||
OpMemberDecorate %struct 0 BuiltIn SubgroupEqMask
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%struct = OpTypeStruct %int
|
||||
%void_fn = OpTypeFunction %void
|
||||
%foo = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(text, SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"BuiltIn SubgroupEqMask cannot be used as a member decoration"));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
SubgroupInvocationIdAndSizeNotU32, ValidateVulkanSubgroupBuiltIns,
|
||||
Combine(Values("SubgroupLocalInvocationId", "SubgroupSize"),
|
||||
Values("GLCompute"), Values("Input"), Values("%f32"),
|
||||
Values(TestResult(SPV_ERROR_INVALID_DATA,
|
||||
"needs to be a 32-bit int"))));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
SubgroupInvocationIdAndSizeNotInput, ValidateVulkanSubgroupBuiltIns,
|
||||
Combine(Values("SubgroupLocalInvocationId", "SubgroupSize"),
|
||||
Values("GLCompute"), Values("Output", "Workgroup", "Private"),
|
||||
Values("%u32"),
|
||||
Values(TestResult(
|
||||
SPV_ERROR_INVALID_DATA,
|
||||
"to be only used for variables with Input storage class"))));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
SubgroupInvocationIdAndSizeOk, ValidateVulkanSubgroupBuiltIns,
|
||||
Combine(Values("SubgroupLocalInvocationId", "SubgroupSize"),
|
||||
Values("GLCompute"), Values("Input"), Values("%u32"),
|
||||
Values(TestResult(SPV_SUCCESS, ""))));
|
||||
|
||||
TEST_F(ValidateBuiltIns, SubgroupSizeMemberDecorate) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
OpCapability GroupNonUniform
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %foo "foo"
|
||||
OpExecutionMode %foo LocalSize 1 1 1
|
||||
OpMemberDecorate %struct 0 BuiltIn SubgroupSize
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%struct = OpTypeStruct %int
|
||||
%void_fn = OpTypeFunction %void
|
||||
%foo = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(text, SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("BuiltIn SubgroupSize cannot be used as a member decoration"));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
SubgroupNumAndIdNotU32, ValidateVulkanSubgroupBuiltIns,
|
||||
Combine(Values("SubgroupId", "NumSubgroups"), Values("GLCompute"),
|
||||
Values("Input"), Values("%f32"),
|
||||
Values(TestResult(SPV_ERROR_INVALID_DATA,
|
||||
"needs to be a 32-bit int"))));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
SubgroupNumAndIdNotInput, ValidateVulkanSubgroupBuiltIns,
|
||||
Combine(Values("SubgroupId", "NumSubgroups"), Values("GLCompute"),
|
||||
Values("Output", "Workgroup", "Private"), Values("%u32"),
|
||||
Values(TestResult(
|
||||
SPV_ERROR_INVALID_DATA,
|
||||
"to be only used for variables with Input storage class"))));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(SubgroupNumAndIdOk, ValidateVulkanSubgroupBuiltIns,
|
||||
Combine(Values("SubgroupId", "NumSubgroups"),
|
||||
Values("GLCompute"), Values("Input"),
|
||||
Values("%u32"),
|
||||
Values(TestResult(SPV_SUCCESS, ""))));
|
||||
|
||||
TEST_F(ValidateBuiltIns, SubgroupIdMemberDecorate) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
OpCapability GroupNonUniform
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %foo "foo"
|
||||
OpExecutionMode %foo LocalSize 1 1 1
|
||||
OpMemberDecorate %struct 0 BuiltIn SubgroupId
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 0
|
||||
%struct = OpTypeStruct %int
|
||||
%void_fn = OpTypeFunction %void
|
||||
%foo = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
CompileSuccessfully(text, SPV_ENV_VULKAN_1_1);
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1));
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr("BuiltIn SubgroupId cannot be used as a member decoration"));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace val
|
||||
} // namespace spvtools
|
||||
|
Loading…
Reference in New Issue
Block a user