mirror of
https://gitee.com/openharmony/third_party_spirv-tools
synced 2024-11-27 01:21:25 +00:00
Add support for SPV_KHR_subgroup_rotate (#4786)
- Add assembler/disassembler support - Add validator support Signed-off-by: Kevin Petit <kevin.petit@arm.com> Change-Id: Iffcedd5d5e636a0e128a5906ffe634dd85727de1
This commit is contained in:
parent
2c7fb9707b
commit
7014be600c
@ -528,6 +528,7 @@ bool spvOpcodeIsNonUniformGroupOperation(SpvOp opcode) {
|
||||
case SpvOpGroupNonUniformLogicalXor:
|
||||
case SpvOpGroupNonUniformQuadBroadcast:
|
||||
case SpvOpGroupNonUniformQuadSwap:
|
||||
case SpvOpGroupNonUniformRotateKHR:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
@ -63,6 +63,59 @@ spv_result_t ValidateGroupNonUniformBallotBitCount(ValidationState_t& _,
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
spv_result_t ValidateGroupNonUniformRotateKHR(ValidationState_t& _,
|
||||
const Instruction* inst) {
|
||||
// Scope is already checked by ValidateExecutionScope() above.
|
||||
const uint32_t result_type = inst->type_id();
|
||||
if (!_.IsIntScalarOrVectorType(result_type) &&
|
||||
!_.IsFloatScalarOrVectorType(result_type) &&
|
||||
!_.IsBoolScalarOrVectorType(result_type)) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Expected Result Type to be a scalar or vector of "
|
||||
"floating-point, integer or boolean type.";
|
||||
}
|
||||
|
||||
const uint32_t value_type = _.GetTypeId(inst->GetOperandAs<uint32_t>(3));
|
||||
if (value_type != result_type) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Result Type must be the same as the type of Value.";
|
||||
}
|
||||
|
||||
const uint32_t delta_type = _.GetTypeId(inst->GetOperandAs<uint32_t>(4));
|
||||
if (!_.IsUnsignedIntScalarType(delta_type)) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "Delta must be a scalar of integer type, whose Signedness "
|
||||
"operand is 0.";
|
||||
}
|
||||
|
||||
if (inst->words().size() > 6) {
|
||||
const uint32_t cluster_size_op_id = inst->GetOperandAs<uint32_t>(5);
|
||||
const uint32_t cluster_size_type = _.GetTypeId(cluster_size_op_id);
|
||||
if (!_.IsUnsignedIntScalarType(cluster_size_type)) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "ClusterSize must be a scalar of integer type, whose "
|
||||
"Signedness operand is 0.";
|
||||
}
|
||||
|
||||
uint64_t cluster_size;
|
||||
if (!_.GetConstantValUint64(cluster_size_op_id, &cluster_size)) {
|
||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||
<< "ClusterSize must come from a constant instruction.";
|
||||
}
|
||||
|
||||
if ((cluster_size == 0) || ((cluster_size & (cluster_size - 1)) != 0)) {
|
||||
return _.diag(SPV_WARNING, inst)
|
||||
<< "Behavior is undefined unless ClusterSize is at least 1 and a "
|
||||
"power of 2.";
|
||||
}
|
||||
|
||||
// TODO(kpet) Warn about undefined behavior when ClusterSize is greater than
|
||||
// the declared SubGroupSize
|
||||
}
|
||||
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Validates correctness of non-uniform group instructions.
|
||||
@ -79,6 +132,8 @@ spv_result_t NonUniformPass(ValidationState_t& _, const Instruction* inst) {
|
||||
switch (opcode) {
|
||||
case SpvOpGroupNonUniformBallotBitCount:
|
||||
return ValidateGroupNonUniformBallotBitCount(_, inst);
|
||||
case SpvOpGroupNonUniformRotateKHR:
|
||||
return ValidateGroupNonUniformRotateKHR(_, inst);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1075,5 +1075,27 @@ INSTANTIATE_TEST_SUITE_P(
|
||||
{1, 2, 3, SpvGroupOperationReduce, 4})},
|
||||
})));
|
||||
|
||||
// SPV_KHR_subgroup_rotate
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
SPV_KHR_subgroup_rotate, ExtensionRoundTripTest,
|
||||
Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_6,
|
||||
SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_2,
|
||||
SPV_ENV_VULKAN_1_3, SPV_ENV_OPENCL_2_1),
|
||||
ValuesIn(std::vector<AssemblyCase>{
|
||||
{"OpExtension \"SPV_KHR_subgroup_rotate\"\n",
|
||||
MakeInstruction(SpvOpExtension,
|
||||
MakeVector("SPV_KHR_subgroup_rotate"))},
|
||||
{"OpCapability GroupNonUniformRotateKHR\n",
|
||||
MakeInstruction(SpvOpCapability,
|
||||
{SpvCapabilityGroupNonUniformRotateKHR})},
|
||||
{"%2 = OpGroupNonUniformRotateKHR %1 %3 %4 %5\n",
|
||||
MakeInstruction(SpvOpGroupNonUniformRotateKHR,
|
||||
{1, 2, 3, 4, 5})},
|
||||
{"%2 = OpGroupNonUniformRotateKHR %1 %3 %4 %5 %6\n",
|
||||
MakeInstruction(SpvOpGroupNonUniformRotateKHR,
|
||||
{1, 2, 3, 4, 5, 6})},
|
||||
})));
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
|
@ -45,6 +45,7 @@ add_spvtools_unittest(TARGET val_abcde
|
||||
val_extension_spv_khr_integer_dot_product.cpp
|
||||
val_extension_spv_khr_bit_instructions.cpp
|
||||
val_extension_spv_khr_terminate_invocation.cpp
|
||||
val_extension_spv_khr_subgroup_rotate.cpp
|
||||
val_ext_inst_test.cpp
|
||||
val_ext_inst_debug_test.cpp
|
||||
${VAL_TEST_COMMON_SRCS}
|
||||
|
352
test/val/val_extension_spv_khr_subgroup_rotate.cpp
Normal file
352
test/val/val_extension_spv_khr_subgroup_rotate.cpp
Normal file
@ -0,0 +1,352 @@
|
||||
// Copyright (c) 2022 The Khronos Group Inc.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "test/val/val_fixtures.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace val {
|
||||
namespace {
|
||||
|
||||
using ::testing::HasSubstr;
|
||||
using ::testing::Values;
|
||||
using ::testing::ValuesIn;
|
||||
|
||||
struct Case {
|
||||
std::vector<std::string> caps;
|
||||
bool shader;
|
||||
std::string result_type;
|
||||
std::string scope;
|
||||
std::string delta;
|
||||
std::string cluster_size;
|
||||
std::string expected_error; // empty for no error.
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, Case c) {
|
||||
out << "\nSPV_KHR_subgroup_rotate Case{{";
|
||||
for (auto& cap : c.caps) {
|
||||
out << cap;
|
||||
}
|
||||
out << "} ";
|
||||
out << (c.shader ? "shader " : "kernel ");
|
||||
out << c.result_type + " ";
|
||||
out << c.scope + " ";
|
||||
out << c.delta + " ";
|
||||
out << c.cluster_size + " ";
|
||||
out << "err'" << c.expected_error << "'";
|
||||
out << "}";
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string AssemblyForCase(const Case& c) {
|
||||
std::ostringstream ss;
|
||||
|
||||
if (c.shader) {
|
||||
ss << "OpCapability Shader\n";
|
||||
} else {
|
||||
ss << "OpCapability Kernel\n";
|
||||
ss << "OpCapability Addresses\n";
|
||||
}
|
||||
for (auto& cap : c.caps) {
|
||||
ss << "OpCapability " << cap << "\n";
|
||||
}
|
||||
ss << "OpExtension \"SPV_KHR_subgroup_rotate\"\n";
|
||||
|
||||
if (c.shader) {
|
||||
ss << "OpMemoryModel Logical GLSL450\n";
|
||||
ss << "OpEntryPoint GLCompute %main \"main\"\n";
|
||||
} else {
|
||||
ss << "OpMemoryModel Physical32 OpenCL\n";
|
||||
ss << "OpEntryPoint Kernel %main \"main\"\n";
|
||||
}
|
||||
|
||||
ss << R"(
|
||||
%void = OpTypeVoid
|
||||
%void_fn = OpTypeFunction %void
|
||||
%u32 = OpTypeInt 32 0
|
||||
%float = OpTypeFloat 32
|
||||
%ptr = OpTypePointer Function %u32
|
||||
)";
|
||||
|
||||
if (c.shader) {
|
||||
ss << "%i32 = OpTypeInt 32 1\n";
|
||||
}
|
||||
|
||||
ss << R"(
|
||||
%u32_0 = OpConstant %u32 0
|
||||
%u32_1 = OpConstant %u32 1
|
||||
%u32_15 = OpConstant %u32 15
|
||||
%u32_16 = OpConstant %u32 16
|
||||
%u32_undef = OpUndef %u32
|
||||
%u32_spec_1 = OpSpecConstant %u32 1
|
||||
%u32_spec_16 = OpSpecConstant %u32 16
|
||||
%f32_1 = OpConstant %float 1.0
|
||||
%subgroup = OpConstant %u32 3
|
||||
%workgroup = OpConstant %u32 2
|
||||
%invalid_scope = OpConstant %u32 1
|
||||
%val = OpConstant %u32 42
|
||||
)";
|
||||
|
||||
if (c.shader) {
|
||||
ss << "%i32_1 = OpConstant %i32 1\n";
|
||||
}
|
||||
|
||||
ss << R"(
|
||||
%main = OpFunction %void None %void_fn
|
||||
%entry = OpLabel
|
||||
)";
|
||||
|
||||
ss << "%unused = OpGroupNonUniformRotateKHR ";
|
||||
ss << c.result_type + " ";
|
||||
ss << c.scope;
|
||||
ss << " %val ";
|
||||
ss << c.delta;
|
||||
ss << " " + c.cluster_size;
|
||||
ss << "\n";
|
||||
|
||||
ss << R"(
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
using ValidateSpvKHRSubgroupRotate = spvtest::ValidateBase<Case>;
|
||||
|
||||
TEST_P(ValidateSpvKHRSubgroupRotate, Base) {
|
||||
const auto& c = GetParam();
|
||||
const auto& assembly = AssemblyForCase(c);
|
||||
CompileSuccessfully(assembly);
|
||||
if (c.expected_error.empty()) {
|
||||
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString();
|
||||
} else {
|
||||
EXPECT_NE(SPV_SUCCESS, ValidateInstructions());
|
||||
EXPECT_THAT(getDiagnosticString(), HasSubstr(c.expected_error));
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
Valid, ValidateSpvKHRSubgroupRotate,
|
||||
::testing::Values(
|
||||
Case{
|
||||
{"GroupNonUniformRotateKHR"}, false, "%u32", "%subgroup", "%u32_1"},
|
||||
Case{{"GroupNonUniformRotateKHR"}, true, "%u32", "%subgroup", "%u32_1"},
|
||||
Case{{"GroupNonUniformRotateKHR"},
|
||||
false,
|
||||
"%u32",
|
||||
"%subgroup",
|
||||
"%u32_1",
|
||||
"%u32_16"},
|
||||
Case{{"GroupNonUniformRotateKHR"},
|
||||
true,
|
||||
"%u32",
|
||||
"%subgroup",
|
||||
"%u32_1",
|
||||
"%u32_16"},
|
||||
Case{{"GroupNonUniformRotateKHR"},
|
||||
false,
|
||||
"%u32",
|
||||
"%subgroup",
|
||||
"%u32_spec_1",
|
||||
"%u32_16"},
|
||||
Case{{"GroupNonUniformRotateKHR"},
|
||||
true,
|
||||
"%u32",
|
||||
"%subgroup",
|
||||
"%u32_1",
|
||||
"%u32_spec_16"},
|
||||
Case{{"GroupNonUniformRotateKHR"},
|
||||
false,
|
||||
"%u32",
|
||||
"%workgroup",
|
||||
"%u32_1"},
|
||||
Case{
|
||||
{"GroupNonUniformRotateKHR"}, true, "%u32", "%workgroup", "%u32_1"},
|
||||
Case{{"GroupNonUniformRotateKHR"},
|
||||
false,
|
||||
"%u32",
|
||||
"%workgroup",
|
||||
"%u32_spec_1"},
|
||||
Case{{"GroupNonUniformRotateKHR"},
|
||||
true,
|
||||
"%u32",
|
||||
"%workgroup",
|
||||
"%u32_spec_1"}));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
RequiresCapability, ValidateSpvKHRSubgroupRotate,
|
||||
::testing::Values(Case{{},
|
||||
false,
|
||||
"%u32",
|
||||
"%subgroup",
|
||||
"%u32_1",
|
||||
"",
|
||||
"Opcode GroupNonUniformRotateKHR requires one of "
|
||||
"these capabilities: "
|
||||
"GroupNonUniformRotateKHR"},
|
||||
Case{{},
|
||||
true,
|
||||
"%u32",
|
||||
"%subgroup",
|
||||
"%u32_1",
|
||||
"",
|
||||
"Opcode GroupNonUniformRotateKHR requires one of "
|
||||
"these capabilities: "
|
||||
"GroupNonUniformRotateKHR"}));
|
||||
|
||||
TEST_F(ValidateSpvKHRSubgroupRotate, RequiresExtension) {
|
||||
const std::string str = R"(
|
||||
OpCapability GroupNonUniformRotateKHR
|
||||
)";
|
||||
CompileSuccessfully(str.c_str());
|
||||
EXPECT_NE(SPV_SUCCESS, ValidateInstructions());
|
||||
EXPECT_THAT(
|
||||
getDiagnosticString(),
|
||||
HasSubstr(
|
||||
"1st operand of Capability: operand GroupNonUniformRotateKHR(6026) "
|
||||
"requires one of these extensions: SPV_KHR_subgroup_rotate"));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
InvalidExecutionScope, ValidateSpvKHRSubgroupRotate,
|
||||
::testing::Values(
|
||||
Case{{"GroupNonUniformRotateKHR"},
|
||||
false,
|
||||
"%u32",
|
||||
"%invalid_scope",
|
||||
"%u32_1",
|
||||
"",
|
||||
"Execution scope is limited to Subgroup or Workgroup"},
|
||||
Case{{"GroupNonUniformRotateKHR"},
|
||||
true,
|
||||
"%u32",
|
||||
"%invalid_scope",
|
||||
"%u32_1",
|
||||
"",
|
||||
"Execution scope is limited to Subgroup or Workgroup"}));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
InvalidResultType, ValidateSpvKHRSubgroupRotate,
|
||||
::testing::Values(Case{{"GroupNonUniformRotateKHR"},
|
||||
false,
|
||||
"%ptr",
|
||||
"%subgroup",
|
||||
"%u32_1",
|
||||
"",
|
||||
"Expected Result Type to be a scalar or vector of "
|
||||
"floating-point, integer or boolean type"},
|
||||
Case{{"GroupNonUniformRotateKHR"},
|
||||
true,
|
||||
"%ptr",
|
||||
"%subgroup",
|
||||
"%u32_1",
|
||||
"",
|
||||
"Expected Result Type to be a scalar or vector of "
|
||||
"floating-point, integer or boolean type"}));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
MismatchedResultAndValueTypes, ValidateSpvKHRSubgroupRotate,
|
||||
::testing::Values(
|
||||
Case{{"GroupNonUniformRotateKHR"},
|
||||
false,
|
||||
"%float",
|
||||
"%subgroup",
|
||||
"%u32_1",
|
||||
"",
|
||||
"Result Type must be the same as the type of Value"},
|
||||
Case{{"GroupNonUniformRotateKHR"},
|
||||
true,
|
||||
"%float",
|
||||
"%subgroup",
|
||||
"%u32_1",
|
||||
"",
|
||||
"Result Type must be the same as the type of Value"}));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
InvalidDelta, ValidateSpvKHRSubgroupRotate,
|
||||
::testing::Values(Case{{"GroupNonUniformRotateKHR"},
|
||||
false,
|
||||
"%u32",
|
||||
"%subgroup",
|
||||
"%f32_1",
|
||||
"",
|
||||
"Delta must be a scalar of integer type, whose "
|
||||
"Signedness operand is 0"},
|
||||
Case{{"GroupNonUniformRotateKHR"},
|
||||
true,
|
||||
"%u32",
|
||||
"%subgroup",
|
||||
"%f32_1",
|
||||
"",
|
||||
"Delta must be a scalar of integer type, whose "
|
||||
"Signedness operand is 0"},
|
||||
Case{{"GroupNonUniformRotateKHR"},
|
||||
true,
|
||||
"%u32",
|
||||
"%subgroup",
|
||||
"%i32_1",
|
||||
"",
|
||||
"Delta must be a scalar of integer type, whose "
|
||||
"Signedness operand is 0"}));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
InvalidClusterSize, ValidateSpvKHRSubgroupRotate,
|
||||
::testing::Values(
|
||||
Case{{"GroupNonUniformRotateKHR"},
|
||||
false,
|
||||
"%u32",
|
||||
"%subgroup",
|
||||
"%u32_1",
|
||||
"%f32_1",
|
||||
"ClusterSize must be a scalar of integer type, whose Signedness "
|
||||
"operand is 0"},
|
||||
Case{{"GroupNonUniformRotateKHR"},
|
||||
true,
|
||||
"%u32",
|
||||
"%subgroup",
|
||||
"%u32_1",
|
||||
"%i32_1",
|
||||
"ClusterSize must be a scalar of integer type, whose Signedness "
|
||||
"operand is 0"},
|
||||
Case{{"GroupNonUniformRotateKHR"},
|
||||
true,
|
||||
"%u32",
|
||||
"%subgroup",
|
||||
"%u32_1",
|
||||
"%u32_0",
|
||||
"Behavior is undefined unless ClusterSize is at least 1 and a "
|
||||
"power of 2"},
|
||||
Case{{"GroupNonUniformRotateKHR"},
|
||||
true,
|
||||
"%u32",
|
||||
"%subgroup",
|
||||
"%u32_1",
|
||||
"%u32_15",
|
||||
"Behavior is undefined unless ClusterSize is at least 1 and a "
|
||||
"power of 2"},
|
||||
Case{{"GroupNonUniformRotateKHR"},
|
||||
true,
|
||||
"%u32",
|
||||
"%subgroup",
|
||||
"%u32_1",
|
||||
"%u32_undef",
|
||||
"ClusterSize must come from a constant instruction"}));
|
||||
|
||||
} // namespace
|
||||
} // namespace val
|
||||
} // namespace spvtools
|
Loading…
Reference in New Issue
Block a user