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:
Greg Fischer 2022-11-23 10:48:58 -07:00 коммит произвёл GitHub
Родитель 46ca66e699
Коммит 81ec2aaa0e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
5 изменённых файлов: 102 добавлений и 13 удалений

Просмотреть файл

@ -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