mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-10-18 11:10:05 +00:00
Add option to ADCE to remove output variables from interface. (#4994)
This can cause interface incompatibility and should only be done if ADCE has been applied to the following shader in the pipeline. For this reason this capability is not available through the CLI but rather only non-default through the API. This functionality is intended as part of a larger cross-shader dead code elimination sequence.
This commit is contained in:
parent
46ca66e699
commit
81ec2aaa0e
@ -521,8 +521,12 @@ Optimizer::PassToken CreateDeadInsertElimPass();
|
||||
// interface are considered live and are not eliminated. This mode is needed
|
||||
// by GPU-Assisted validation instrumentation, where a change in the interface
|
||||
// is not allowed.
|
||||
Optimizer::PassToken CreateAggressiveDCEPass();
|
||||
Optimizer::PassToken CreateAggressiveDCEPass(bool preserve_interface);
|
||||
//
|
||||
// If |remove_outputs| is true, allow outputs to be removed from the interface.
|
||||
// This is only safe if the caller knows that there is no corresponding input
|
||||
// variable in the following shader. It is false by default.
|
||||
Optimizer::PassToken CreateAggressiveDCEPass(bool preserve_interface = false,
|
||||
bool remove_outputs = false);
|
||||
|
||||
// Creates a remove-unused-interface-variables pass.
|
||||
// Removes variables referenced on the |OpEntryPoint| instruction that are not
|
||||
|
@ -579,8 +579,10 @@ void AggressiveDCEPass::InitializeModuleScopeLiveInstructions() {
|
||||
auto* var = get_def_use_mgr()->GetDef(entry.GetSingleWordInOperand(i));
|
||||
auto storage_class = var->GetSingleWordInOperand(0u);
|
||||
// Vulkan support outputs without an associated input, but not inputs
|
||||
// without an associated output.
|
||||
if (spv::StorageClass(storage_class) == spv::StorageClass::Output) {
|
||||
// without an associated output. Don't remove outputs unless explicitly
|
||||
// allowed.
|
||||
if (!remove_outputs_ &&
|
||||
spv::StorageClass(storage_class) == spv::StorageClass::Output) {
|
||||
AddToWorklist(var);
|
||||
}
|
||||
}
|
||||
|
@ -44,8 +44,10 @@ class AggressiveDCEPass : public MemPass {
|
||||
using GetBlocksFunction =
|
||||
std::function<std::vector<BasicBlock*>*(const BasicBlock*)>;
|
||||
|
||||
AggressiveDCEPass(bool preserve_interface = false)
|
||||
: preserve_interface_(preserve_interface) {}
|
||||
AggressiveDCEPass(bool preserve_interface = false,
|
||||
bool remove_outputs = false)
|
||||
: preserve_interface_(preserve_interface),
|
||||
remove_outputs_(remove_outputs) {}
|
||||
|
||||
const char* name() const override { return "eliminate-dead-code-aggressive"; }
|
||||
Status Process() override;
|
||||
@ -63,6 +65,11 @@ class AggressiveDCEPass : public MemPass {
|
||||
// is not allowed.
|
||||
bool preserve_interface_;
|
||||
|
||||
// Output variables can be removed from the interface if this is true.
|
||||
// This is safe if the caller knows that the corresponding input variable
|
||||
// in the following shader has been removed. It is false by default.
|
||||
bool remove_outputs_;
|
||||
|
||||
// Return true if |varId| is a variable of |storageClass|. |varId| must either
|
||||
// be 0 or the result of an instruction.
|
||||
bool IsVarOfStorage(uint32_t varId, spv::StorageClass storageClass);
|
||||
|
@ -785,14 +785,10 @@ Optimizer::PassToken CreateLocalMultiStoreElimPass() {
|
||||
MakeUnique<opt::SSARewritePass>());
|
||||
}
|
||||
|
||||
Optimizer::PassToken CreateAggressiveDCEPass() {
|
||||
Optimizer::PassToken CreateAggressiveDCEPass(bool preserve_interface,
|
||||
bool remove_outputs) {
|
||||
return MakeUnique<Optimizer::PassToken::Impl>(
|
||||
MakeUnique<opt::AggressiveDCEPass>(false));
|
||||
}
|
||||
|
||||
Optimizer::PassToken CreateAggressiveDCEPass(bool preserve_interface) {
|
||||
return MakeUnique<Optimizer::PassToken::Impl>(
|
||||
MakeUnique<opt::AggressiveDCEPass>(preserve_interface));
|
||||
MakeUnique<opt::AggressiveDCEPass>(preserve_interface, remove_outputs));
|
||||
}
|
||||
|
||||
Optimizer::PassToken CreateRemoveUnusedInterfaceVariablesPass() {
|
||||
|
@ -7777,6 +7777,86 @@ PS_OUTPUT MainPs ( )
|
||||
SinglePassRunAndMatch<AggressiveDCEPass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(AggressiveDCETest, RemoveOutputTrue) {
|
||||
// Remove dead n_out output variable from module
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Vertex %main "main" %c_out %c_in %n_out
|
||||
;CHECK: OpEntryPoint Vertex %main "main" %c_out %c_in
|
||||
OpSource GLSL 450
|
||||
OpName %main "main"
|
||||
OpName %c_out "c_out"
|
||||
OpName %c_in "c_in"
|
||||
OpName %n_out "n_out"
|
||||
OpDecorate %c_out Location 0
|
||||
OpDecorate %c_in Location 0
|
||||
OpDecorate %n_out Location 1
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%c_out = OpVariable %_ptr_Output_v4float Output
|
||||
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
||||
%c_in = OpVariable %_ptr_Input_v4float Input
|
||||
%v3float = OpTypeVector %float 3
|
||||
%_ptr_Output_v3float = OpTypePointer Output %v3float
|
||||
%n_out = OpVariable %_ptr_Output_v3float Output
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
%12 = OpLoad %v4float %c_in
|
||||
OpStore %c_out %12
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SetTargetEnv(SPV_ENV_VULKAN_1_3);
|
||||
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
||||
SinglePassRunAndMatch<AggressiveDCEPass>(text, true, false, true);
|
||||
}
|
||||
|
||||
TEST_F(AggressiveDCETest, RemoveOutputFalse) {
|
||||
// Remove dead n_out output variable from module
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Vertex %main "main" %c_out %c_in %n_out
|
||||
;CHECK: OpEntryPoint Vertex %main "main" %c_out %c_in %n_out
|
||||
OpSource GLSL 450
|
||||
OpName %main "main"
|
||||
OpName %c_out "c_out"
|
||||
OpName %c_in "c_in"
|
||||
OpName %n_out "n_out"
|
||||
OpDecorate %c_out Location 0
|
||||
OpDecorate %c_in Location 0
|
||||
OpDecorate %n_out Location 1
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%c_out = OpVariable %_ptr_Output_v4float Output
|
||||
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
||||
%c_in = OpVariable %_ptr_Input_v4float Input
|
||||
%v3float = OpTypeVector %float 3
|
||||
%_ptr_Output_v3float = OpTypePointer Output %v3float
|
||||
%n_out = OpVariable %_ptr_Output_v3float Output
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
%12 = OpLoad %v4float %c_in
|
||||
OpStore %c_out %12
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SetTargetEnv(SPV_ENV_VULKAN_1_3);
|
||||
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
||||
SinglePassRunAndMatch<AggressiveDCEPass>(text, true, false, false);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
|
Loading…
Reference in New Issue
Block a user