mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-27 05:40:06 +00:00
Add changes for SPV_EXT_shader_atomic_float (#3562)
This commit is contained in:
parent
5dc96d5d27
commit
e4aebf99fa
@ -413,6 +413,7 @@ bool spvOpcodeIsAtomicWithLoad(const SpvOp opcode) {
|
|||||||
case SpvOpAtomicIIncrement:
|
case SpvOpAtomicIIncrement:
|
||||||
case SpvOpAtomicIDecrement:
|
case SpvOpAtomicIDecrement:
|
||||||
case SpvOpAtomicIAdd:
|
case SpvOpAtomicIAdd:
|
||||||
|
case SpvOpAtomicFAddEXT:
|
||||||
case SpvOpAtomicISub:
|
case SpvOpAtomicISub:
|
||||||
case SpvOpAtomicSMin:
|
case SpvOpAtomicSMin:
|
||||||
case SpvOpAtomicUMin:
|
case SpvOpAtomicUMin:
|
||||||
@ -700,6 +701,7 @@ std::vector<uint32_t> spvOpcodeMemorySemanticsOperandIndices(SpvOp opcode) {
|
|||||||
case SpvOpAtomicIIncrement:
|
case SpvOpAtomicIIncrement:
|
||||||
case SpvOpAtomicIDecrement:
|
case SpvOpAtomicIDecrement:
|
||||||
case SpvOpAtomicIAdd:
|
case SpvOpAtomicIAdd:
|
||||||
|
case SpvOpAtomicFAddEXT:
|
||||||
case SpvOpAtomicISub:
|
case SpvOpAtomicISub:
|
||||||
case SpvOpAtomicSMin:
|
case SpvOpAtomicSMin:
|
||||||
case SpvOpAtomicUMin:
|
case SpvOpAtomicUMin:
|
||||||
|
@ -214,6 +214,7 @@ bool CodeSinkingPass::HasUniformMemorySync() {
|
|||||||
case SpvOpAtomicIIncrement:
|
case SpvOpAtomicIIncrement:
|
||||||
case SpvOpAtomicIDecrement:
|
case SpvOpAtomicIDecrement:
|
||||||
case SpvOpAtomicIAdd:
|
case SpvOpAtomicIAdd:
|
||||||
|
case SpvOpAtomicFAddEXT:
|
||||||
case SpvOpAtomicISub:
|
case SpvOpAtomicISub:
|
||||||
case SpvOpAtomicSMin:
|
case SpvOpAtomicSMin:
|
||||||
case SpvOpAtomicUMin:
|
case SpvOpAtomicUMin:
|
||||||
|
@ -54,11 +54,16 @@ namespace val {
|
|||||||
spv_result_t AtomicsPass(ValidationState_t& _, const Instruction* inst) {
|
spv_result_t AtomicsPass(ValidationState_t& _, const Instruction* inst) {
|
||||||
const SpvOp opcode = inst->opcode();
|
const SpvOp opcode = inst->opcode();
|
||||||
const uint32_t result_type = inst->type_id();
|
const uint32_t result_type = inst->type_id();
|
||||||
|
bool is_atomic_float_opcode = false;
|
||||||
|
if (opcode == SpvOpAtomicLoad || opcode == SpvOpAtomicStore ||
|
||||||
|
opcode == SpvOpAtomicFAddEXT || opcode == SpvOpAtomicExchange) {
|
||||||
|
is_atomic_float_opcode = true;
|
||||||
|
}
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case SpvOpAtomicLoad:
|
case SpvOpAtomicLoad:
|
||||||
case SpvOpAtomicStore:
|
case SpvOpAtomicStore:
|
||||||
case SpvOpAtomicExchange:
|
case SpvOpAtomicExchange:
|
||||||
|
case SpvOpAtomicFAddEXT:
|
||||||
case SpvOpAtomicCompareExchange:
|
case SpvOpAtomicCompareExchange:
|
||||||
case SpvOpAtomicCompareExchangeWeak:
|
case SpvOpAtomicCompareExchangeWeak:
|
||||||
case SpvOpAtomicIIncrement:
|
case SpvOpAtomicIIncrement:
|
||||||
@ -92,11 +97,59 @@ spv_result_t AtomicsPass(ValidationState_t& _, const Instruction* inst) {
|
|||||||
} else if (opcode == SpvOpAtomicFlagClear || opcode == SpvOpAtomicStore) {
|
} else if (opcode == SpvOpAtomicFlagClear || opcode == SpvOpAtomicStore) {
|
||||||
assert(result_type == 0);
|
assert(result_type == 0);
|
||||||
} else {
|
} else {
|
||||||
if (!_.IsIntScalarType(result_type)) {
|
if (_.IsFloatScalarType(result_type)) {
|
||||||
|
if (is_atomic_float_opcode) {
|
||||||
|
if (opcode == SpvOpAtomicFAddEXT) {
|
||||||
|
if ((_.GetBitWidth(result_type) == 32) &&
|
||||||
|
(!_.HasCapability(SpvCapabilityAtomicFloat32AddEXT))) {
|
||||||
|
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||||
|
<< spvOpcodeString(opcode)
|
||||||
|
<< ": float add atomics require the AtomicFloat32AddEXT "
|
||||||
|
"capability";
|
||||||
|
}
|
||||||
|
if ((_.GetBitWidth(result_type) == 64) &&
|
||||||
|
(!_.HasCapability(SpvCapabilityAtomicFloat64AddEXT))) {
|
||||||
|
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||||
|
<< spvOpcodeString(opcode)
|
||||||
|
<< ": float add atomics require the AtomicFloat64AddEXT "
|
||||||
|
"capability";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||||
<< spvOpcodeString(opcode)
|
<< spvOpcodeString(opcode)
|
||||||
<< ": expected Result Type to be int scalar type";
|
<< ": expected Result Type to be int scalar type";
|
||||||
}
|
}
|
||||||
|
} else if (_.IsIntScalarType(result_type) &&
|
||||||
|
opcode == SpvOpAtomicFAddEXT) {
|
||||||
|
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||||
|
<< spvOpcodeString(opcode)
|
||||||
|
<< ": expected Result Type to be float scalar type";
|
||||||
|
} else if (!_.IsFloatScalarType(result_type) &&
|
||||||
|
!_.IsIntScalarType(result_type)) {
|
||||||
|
switch (opcode) {
|
||||||
|
case SpvOpAtomicFAddEXT:
|
||||||
|
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||||
|
<< spvOpcodeString(opcode)
|
||||||
|
<< ": expected Result Type to be float scalar type";
|
||||||
|
case SpvOpAtomicIIncrement:
|
||||||
|
case SpvOpAtomicIDecrement:
|
||||||
|
case SpvOpAtomicIAdd:
|
||||||
|
case SpvOpAtomicISub:
|
||||||
|
case SpvOpAtomicSMin:
|
||||||
|
case SpvOpAtomicSMax:
|
||||||
|
case SpvOpAtomicUMin:
|
||||||
|
case SpvOpAtomicUMax:
|
||||||
|
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||||
|
<< spvOpcodeString(opcode)
|
||||||
|
<< ": expected Result Type to be integer scalar type";
|
||||||
|
default:
|
||||||
|
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||||
|
<< spvOpcodeString(opcode)
|
||||||
|
<< ": expected Result Type to be int or float scalar type";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (spvIsVulkanEnv(_.context()->target_env) &&
|
if (spvIsVulkanEnv(_.context()->target_env) &&
|
||||||
_.GetBitWidth(result_type) != 32) {
|
_.GetBitWidth(result_type) != 32) {
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
@ -108,11 +161,17 @@ spv_result_t AtomicsPass(ValidationState_t& _, const Instruction* inst) {
|
|||||||
case SpvOpAtomicOr:
|
case SpvOpAtomicOr:
|
||||||
case SpvOpAtomicXor:
|
case SpvOpAtomicXor:
|
||||||
case SpvOpAtomicIAdd:
|
case SpvOpAtomicIAdd:
|
||||||
|
case SpvOpAtomicISub:
|
||||||
|
case SpvOpAtomicFAddEXT:
|
||||||
case SpvOpAtomicLoad:
|
case SpvOpAtomicLoad:
|
||||||
case SpvOpAtomicStore:
|
case SpvOpAtomicStore:
|
||||||
case SpvOpAtomicExchange:
|
case SpvOpAtomicExchange:
|
||||||
|
case SpvOpAtomicIIncrement:
|
||||||
|
case SpvOpAtomicIDecrement:
|
||||||
|
case SpvOpAtomicCompareExchangeWeak:
|
||||||
case SpvOpAtomicCompareExchange: {
|
case SpvOpAtomicCompareExchange: {
|
||||||
if (_.GetBitWidth(result_type) == 64 &&
|
if (_.GetBitWidth(result_type) == 64 &&
|
||||||
|
_.IsIntScalarType(result_type) &&
|
||||||
!_.HasCapability(SpvCapabilityInt64Atomics))
|
!_.HasCapability(SpvCapabilityInt64Atomics))
|
||||||
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
return _.diag(SPV_ERROR_INVALID_DATA, inst)
|
||||||
<< spvOpcodeString(opcode)
|
<< spvOpcodeString(opcode)
|
||||||
|
@ -177,6 +177,8 @@ INSTANTIATE_TEST_SUITE_P(
|
|||||||
{SpvCapabilityStoragePushConstant16, "StoragePushConstant16"},
|
{SpvCapabilityStoragePushConstant16, "StoragePushConstant16"},
|
||||||
{SpvCapabilityStorageInputOutput16, "StorageInputOutput16"},
|
{SpvCapabilityStorageInputOutput16, "StorageInputOutput16"},
|
||||||
{SpvCapabilityDeviceGroup, "DeviceGroup"},
|
{SpvCapabilityDeviceGroup, "DeviceGroup"},
|
||||||
|
{SpvCapabilityAtomicFloat32AddEXT, "AtomicFloat32AddEXT"},
|
||||||
|
{SpvCapabilityAtomicFloat64AddEXT, "AtomicFloat64AddEXT"},
|
||||||
{SpvCapabilityMultiView, "MultiView"},
|
{SpvCapabilityMultiView, "MultiView"},
|
||||||
{SpvCapabilitySampleMaskOverrideCoverageNV,
|
{SpvCapabilitySampleMaskOverrideCoverageNV,
|
||||||
"SampleMaskOverrideCoverageNV"},
|
"SampleMaskOverrideCoverageNV"},
|
||||||
|
@ -238,6 +238,120 @@ TEST_F(ValidateAtomics, AtomicLoadInt32VulkanSuccess) {
|
|||||||
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateAtomics, AtomicAddIntVulkanWrongType1) {
|
||||||
|
const std::string body = R"(
|
||||||
|
%val1 = OpAtomicIAdd %f32 %f32_var %device %relaxed %f32_1
|
||||||
|
)";
|
||||||
|
|
||||||
|
CompileSuccessfully(GenerateShaderCode(body));
|
||||||
|
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||||
|
EXPECT_THAT(getDiagnosticString(),
|
||||||
|
HasSubstr("AtomicIAdd: "
|
||||||
|
"expected Result Type to be int scalar type"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateAtomics, AtomicAddIntVulkanWrongType2) {
|
||||||
|
const std::string body = R"(
|
||||||
|
%val1 = OpAtomicIAdd %f32vec4 %f32vec4_var %device %relaxed %f32_1
|
||||||
|
)";
|
||||||
|
|
||||||
|
CompileSuccessfully(GenerateShaderCode(body));
|
||||||
|
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
||||||
|
EXPECT_THAT(getDiagnosticString(),
|
||||||
|
HasSubstr("AtomicIAdd: "
|
||||||
|
"expected Result Type to be integer scalar type"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateAtomics, AtomicAddFloatVulkan) {
|
||||||
|
const std::string body = R"(
|
||||||
|
%val1 = OpAtomicFAddEXT %f32 %f32_var %device %relaxed %f32_1
|
||||||
|
)";
|
||||||
|
|
||||||
|
CompileSuccessfully(GenerateShaderCode(body));
|
||||||
|
ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions());
|
||||||
|
EXPECT_THAT(
|
||||||
|
getDiagnosticString(),
|
||||||
|
HasSubstr("Opcode AtomicFAddEXT requires one of these capabilities: "
|
||||||
|
"AtomicFloat32AddEXT AtomicFloat64AddEXT"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateAtomics, AtomicAddFloatVulkanWrongType1) {
|
||||||
|
const std::string body = R"(
|
||||||
|
%val1 = OpAtomicFAddEXT %f32vec4 %f32vec4_var %device %relaxed %f32_1
|
||||||
|
)";
|
||||||
|
const std::string extra = R"(
|
||||||
|
OpCapability AtomicFloat32AddEXT
|
||||||
|
OpExtension "SPV_EXT_shader_atomic_float_add"
|
||||||
|
)";
|
||||||
|
|
||||||
|
CompileSuccessfully(GenerateShaderCode(body, extra), SPV_ENV_VULKAN_1_0);
|
||||||
|
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
||||||
|
EXPECT_THAT(getDiagnosticString(),
|
||||||
|
HasSubstr("AtomicFAddEXT: "
|
||||||
|
"expected Result Type to be float scalar type"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateAtomics, AtomicAddFloatVulkanWrongType2) {
|
||||||
|
const std::string body = R"(
|
||||||
|
%val1 = OpAtomicFAddEXT %u32 %u32_var %device %relaxed %u32_1
|
||||||
|
)";
|
||||||
|
const std::string extra = R"(
|
||||||
|
OpCapability AtomicFloat32AddEXT
|
||||||
|
OpExtension "SPV_EXT_shader_atomic_float_add"
|
||||||
|
)";
|
||||||
|
|
||||||
|
CompileSuccessfully(GenerateShaderCode(body, extra), SPV_ENV_VULKAN_1_0);
|
||||||
|
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
||||||
|
EXPECT_THAT(getDiagnosticString(),
|
||||||
|
HasSubstr("AtomicFAddEXT: "
|
||||||
|
"expected Result Type to be float scalar type"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateAtomics, AtomicAddFloatVulkanWrongType3) {
|
||||||
|
const std::string body = R"(
|
||||||
|
%val1 = OpAtomicFAddEXT %u64 %u64_var %device %relaxed %u64_1
|
||||||
|
)";
|
||||||
|
const std::string extra = R"(
|
||||||
|
OpCapability AtomicFloat32AddEXT
|
||||||
|
OpExtension "SPV_EXT_shader_atomic_float_add"
|
||||||
|
)";
|
||||||
|
|
||||||
|
CompileSuccessfully(GenerateShaderCode(body, extra), SPV_ENV_VULKAN_1_0);
|
||||||
|
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
||||||
|
EXPECT_THAT(getDiagnosticString(),
|
||||||
|
HasSubstr("AtomicFAddEXT: "
|
||||||
|
"expected Result Type to be float scalar type"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateAtomics, AtomicAddFloatVulkanWrongCapability) {
|
||||||
|
const std::string body = R"(
|
||||||
|
%val1 = OpAtomicFAddEXT %f32 %f32_var %device %relaxed %f32_1
|
||||||
|
)";
|
||||||
|
const std::string extra = R"(
|
||||||
|
OpCapability AtomicFloat64AddEXT
|
||||||
|
OpExtension "SPV_EXT_shader_atomic_float_add"
|
||||||
|
)";
|
||||||
|
|
||||||
|
CompileSuccessfully(GenerateShaderCode(body, extra), SPV_ENV_VULKAN_1_0);
|
||||||
|
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
||||||
|
EXPECT_THAT(getDiagnosticString(),
|
||||||
|
HasSubstr("AtomicFAddEXT: float add atomics "
|
||||||
|
"require the AtomicFloat32AddEXT capability"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateAtomics, AtomicAddFloatVulkanSuccess) {
|
||||||
|
const std::string body = R"(
|
||||||
|
%val1 = OpAtomicFAddEXT %f32 %f32_var %device %relaxed %f32_1
|
||||||
|
)";
|
||||||
|
const std::string extra = R"(
|
||||||
|
OpCapability AtomicFloat32AddEXT
|
||||||
|
OpExtension "SPV_EXT_shader_atomic_float_add"
|
||||||
|
)";
|
||||||
|
|
||||||
|
CompileSuccessfully(GenerateShaderCode(body, extra), SPV_ENV_VULKAN_1_0);
|
||||||
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(ValidateAtomics, AtomicLoadFloatVulkan) {
|
TEST_F(ValidateAtomics, AtomicLoadFloatVulkan) {
|
||||||
const std::string body = R"(
|
const std::string body = R"(
|
||||||
%val1 = OpAtomicLoad %f32 %f32_var %device %relaxed
|
%val1 = OpAtomicLoad %f32 %f32_var %device %relaxed
|
||||||
@ -245,9 +359,25 @@ TEST_F(ValidateAtomics, AtomicLoadFloatVulkan) {
|
|||||||
)";
|
)";
|
||||||
|
|
||||||
CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
|
CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
|
||||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
||||||
EXPECT_THAT(getDiagnosticString(),
|
}
|
||||||
HasSubstr("expected Result Type to be int scalar type"));
|
|
||||||
|
TEST_F(ValidateAtomics, AtomicStoreFloatVulkan) {
|
||||||
|
const std::string body = R"(
|
||||||
|
OpAtomicStore %f32_var %device %relaxed %f32_1
|
||||||
|
)";
|
||||||
|
|
||||||
|
CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
|
||||||
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateAtomics, AtomicExchangeFloatVulkan) {
|
||||||
|
const std::string body = R"(
|
||||||
|
%val2 = OpAtomicExchange %f32 %f32_var %device %relaxed %f32_0
|
||||||
|
)";
|
||||||
|
|
||||||
|
CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0);
|
||||||
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ValidateAtomics, AtomicLoadInt64WithCapabilityVulkanSuccess) {
|
TEST_F(ValidateAtomics, AtomicLoadInt64WithCapabilityVulkanSuccess) {
|
||||||
@ -355,10 +485,7 @@ TEST_F(ValidateAtomics, AtomicLoadShaderFloat) {
|
|||||||
)";
|
)";
|
||||||
|
|
||||||
CompileSuccessfully(GenerateShaderCode(body));
|
CompileSuccessfully(GenerateShaderCode(body));
|
||||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||||
EXPECT_THAT(getDiagnosticString(),
|
|
||||||
HasSubstr("AtomicLoad: "
|
|
||||||
"expected Result Type to be int scalar type"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ValidateAtomics, AtomicLoadVulkanInt64) {
|
TEST_F(ValidateAtomics, AtomicLoadVulkanInt64) {
|
||||||
@ -733,10 +860,7 @@ OpAtomicStore %f32_var %device %relaxed %f32_1
|
|||||||
)";
|
)";
|
||||||
|
|
||||||
CompileSuccessfully(GenerateShaderCode(body));
|
CompileSuccessfully(GenerateShaderCode(body));
|
||||||
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
|
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
|
||||||
EXPECT_THAT(getDiagnosticString(),
|
|
||||||
HasSubstr("AtomicExchange: "
|
|
||||||
"expected Result Type to be int scalar type"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ValidateAtomics, AtomicExchangeWrongResultType) {
|
TEST_F(ValidateAtomics, AtomicExchangeWrongResultType) {
|
||||||
|
Loading…
Reference in New Issue
Block a user