opt: Add VulkanMemoryModelDeviceScope to trim (#5544)

Add the VulkanMemoryModelDeviceScope capability to the capability
trimming pass. According the the spec, "If the Vulkan memory model is
declared and any instruction uses Device scope, the
VulkanMemoryModelDeviceScope capability must be declared." Since this
case, based on the type of an operand, is not covered by the JSON
grammar, it is added explicitly.
This commit is contained in:
Natalie Chouinard 2024-01-25 14:05:04 -05:00 committed by GitHub
parent ef2f432364
commit 0045b01ff9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 95 additions and 1 deletions

View File

@ -229,6 +229,8 @@ class IRContext {
inline void AddExtInstImport(std::unique_ptr<Instruction>&& e);
// Set the memory model for this module.
inline void SetMemoryModel(std::unique_ptr<Instruction>&& m);
// Get the memory model for this module.
inline const Instruction* GetMemoryModel() const;
// Appends an entry point instruction to this module.
inline void AddEntryPoint(std::unique_ptr<Instruction>&& e);
// Appends an execution mode instruction to this module.
@ -1156,6 +1158,10 @@ void IRContext::SetMemoryModel(std::unique_ptr<Instruction>&& m) {
module()->SetMemoryModel(std::move(m));
}
const Instruction* IRContext::GetMemoryModel() const {
return module()->GetMemoryModel();
}
void IRContext::AddEntryPoint(std::unique_ptr<Instruction>&& e) {
module()->AddEntryPoint(std::move(e));
}

View File

@ -448,6 +448,17 @@ void TrimCapabilitiesPass::addInstructionRequirementsForOperand(
return;
}
// If the Vulkan memory model is declared and any instruction uses Device
// scope, the VulkanMemoryModelDeviceScope capability must be declared. This
// rule cannot be covered by the grammar, so must be checked explicitly.
if (operand.type == SPV_OPERAND_TYPE_SCOPE_ID) {
const Instruction* memory_model = context()->GetMemoryModel();
if (memory_model && memory_model->GetSingleWordInOperand(1u) ==
uint32_t(spv::MemoryModel::Vulkan)) {
capabilities->insert(spv::Capability::VulkanMemoryModelDeviceScope);
}
}
// case 1: Operand is a single value, can directly lookup.
if (!spvOperandIsConcreteMask(operand.type)) {
const spv_operand_desc_t* desc = {};

View File

@ -97,7 +97,8 @@ class TrimCapabilitiesPass : public Pass {
spv::Capability::StorageInputOutput16,
spv::Capability::StoragePushConstant16,
spv::Capability::StorageUniform16,
spv::Capability::StorageUniformBufferBlock16
spv::Capability::StorageUniformBufferBlock16,
spv::Capability::VulkanMemoryModelDeviceScope
// clang-format on
};

View File

@ -2584,6 +2584,82 @@ TEST_F(TrimCapabilitiesPassTest, UInt16_RemainsWhenUsed) {
EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
}
TEST_F(TrimCapabilitiesPassTest,
VulkanMemoryModelDeviceScope_RemovedWhenUnused) {
const std::string kTest = R"(
OpCapability VulkanMemoryModelDeviceScope
; CHECK-NOT: OpCapability VulkanMemoryModelDeviceScope
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %1 "main"
%void = OpTypeVoid
%3 = OpTypeFunction %void
%1 = OpFunction %void None %3
%6 = OpLabel
OpReturn
OpFunctionEnd;
)";
const auto result =
SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
}
TEST_F(TrimCapabilitiesPassTest,
VulkanMemoryModelDeviceScope_RemovedWhenUsedWithGLSL450) {
const std::string kTest = R"(
OpCapability VulkanMemoryModelDeviceScope
; CHECK-NOT: OpCapability VulkanMemoryModelDeviceScope
OpCapability Shader
OpCapability ShaderClockKHR
OpCapability Int64
OpExtension "SPV_KHR_shader_clock"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 2 4
%void = OpTypeVoid
%uint = OpTypeInt 32 0
%ulong = OpTypeInt 64 0
%uint_1 = OpConstant %uint 1
%3 = OpTypeFunction %void
%main = OpFunction %void None %3
%6 = OpLabel
%22 = OpReadClockKHR %ulong %uint_1 ; Device Scope
OpReturn
OpFunctionEnd
)";
const auto result =
SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange);
}
TEST_F(TrimCapabilitiesPassTest,
VulkanMemoryModelDeviceScope_RemainsWhenUsedWithVulkan) {
const std::string kTest = R"(
OpCapability VulkanMemoryModelDeviceScope
; CHECK: OpCapability VulkanMemoryModelDeviceScope
OpCapability Shader
OpCapability ShaderClockKHR
OpCapability Int64
OpExtension "SPV_KHR_shader_clock"
OpMemoryModel Logical Vulkan
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 2 4
%void = OpTypeVoid
%uint = OpTypeInt 32 0
%ulong = OpTypeInt 64 0
%uint_1 = OpConstant %uint 1
%3 = OpTypeFunction %void
%main = OpFunction %void None %3
%6 = OpLabel
%22 = OpReadClockKHR %ulong %uint_1 ; Device Scope
OpReturn
OpFunctionEnd
)";
const auto result =
SinglePassRunAndMatch<TrimCapabilitiesPass>(kTest, /* skip_nop= */ false);
EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange);
}
} // namespace
} // namespace opt
} // namespace spvtools