Add —preserve-bindings and —preserve-spec-constants (#2693)

Add optimizer options to for preservation of spec constants and variable with
binding decorations.  They are to be preserved even if they are unused.
This commit is contained in:
Thomas Roughton 2019-07-11 06:12:19 +12:00 коммит произвёл Steven Perron
Родитель 86e45efe15
Коммит cd153db8ed
10 изменённых файлов: 170 добавлений и 4 удалений

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

@ -574,6 +574,15 @@ SPIRV_TOOLS_EXPORT void spvOptimizerOptionsSetValidatorOptions(
SPIRV_TOOLS_EXPORT void spvOptimizerOptionsSetMaxIdBound(
spv_optimizer_options options, uint32_t val);
// Records whether all bindings within the module should be preserved.
SPIRV_TOOLS_EXPORT void spvOptimizerOptionsSetPreserveBindings(
spv_optimizer_options options, bool val);
// Records whether all specialization constants within the module
// should be preserved.
SPIRV_TOOLS_EXPORT void spvOptimizerOptionsSetPreserveSpecConstants(
spv_optimizer_options options, bool val);
// Creates a reducer options object with default options. Returns a valid
// options object. The object remains valid until it is passed into
// |spvReducerOptionsDestroy|.

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

@ -161,6 +161,18 @@ class OptimizerOptions {
spvOptimizerOptionsSetMaxIdBound(options_, new_bound);
}
// Records whether all bindings within the module should be preserved.
void set_preserve_bindings(bool preserve_bindings) {
spvOptimizerOptionsSetPreserveBindings(options_, preserve_bindings);
}
// Records whether all specialization constants within the module
// should be preserved.
void set_preserve_spec_constants(bool preserve_spec_constants) {
spvOptimizerOptionsSetPreserveSpecConstants(options_,
preserve_spec_constants);
}
private:
spv_optimizer_options options_;
};

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

@ -570,13 +570,28 @@ void AggressiveDCEPass::InitializeModuleScopeLiveInstructions() {
AddToWorklist(&entry);
}
}
// Keep workgroup size.
for (auto& anno : get_module()->annotations()) {
if (anno.opcode() == SpvOpDecorate) {
// Keep workgroup size.
if (anno.GetSingleWordInOperand(1u) == SpvDecorationBuiltIn &&
anno.GetSingleWordInOperand(2u) == SpvBuiltInWorkgroupSize) {
AddToWorklist(&anno);
}
if (context()->preserve_bindings()) {
// Keep all bindings.
if ((anno.GetSingleWordInOperand(1u) == SpvDecorationDescriptorSet) ||
(anno.GetSingleWordInOperand(1u) == SpvDecorationBinding)) {
AddToWorklist(&anno);
}
}
if (context()->preserve_spec_constants()) {
// Keep all specialization constant instructions
if (anno.GetSingleWordInOperand(1u) == SpvDecorationSpecId) {
AddToWorklist(&anno);
}
}
}
}
}

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

@ -100,7 +100,9 @@ class IRContext {
constant_mgr_(nullptr),
type_mgr_(nullptr),
id_to_name_(nullptr),
max_id_bound_(kDefaultMaxIdBound) {
max_id_bound_(kDefaultMaxIdBound),
preserve_bindings_(false),
preserve_spec_constants_(false) {
SetContextMessageConsumer(syntax_context_, consumer_);
module_->SetContext(this);
}
@ -115,7 +117,9 @@ class IRContext {
valid_analyses_(kAnalysisNone),
type_mgr_(nullptr),
id_to_name_(nullptr),
max_id_bound_(kDefaultMaxIdBound) {
max_id_bound_(kDefaultMaxIdBound),
preserve_bindings_(false),
preserve_spec_constants_(false) {
SetContextMessageConsumer(syntax_context_, consumer_);
module_->SetContext(this);
InitializeCombinators();
@ -491,6 +495,16 @@ class IRContext {
uint32_t max_id_bound() const { return max_id_bound_; }
void set_max_id_bound(uint32_t new_bound) { max_id_bound_ = new_bound; }
bool preserve_bindings() const { return preserve_bindings_; }
void set_preserve_bindings(bool should_preserve_bindings) {
preserve_bindings_ = should_preserve_bindings;
}
bool preserve_spec_constants() const { return preserve_spec_constants_; }
void set_preserve_spec_constants(bool should_preserve_spec_constants) {
preserve_spec_constants_ = should_preserve_spec_constants;
}
// Return id of input variable only decorated with |builtin|, if in module.
// Create variable and return its id otherwise. If builtin not currently
// supported, return 0.
@ -750,6 +764,13 @@ class IRContext {
// The maximum legal value for the id bound.
uint32_t max_id_bound_;
// Whether all bindings within |module_| should be preserved.
bool preserve_bindings_;
// Whether all specialization constants within |module_|
// should be preserved.
bool preserve_spec_constants_;
};
inline IRContext::Analysis operator|(IRContext::Analysis lhs,

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

@ -528,6 +528,8 @@ bool Optimizer::Run(const uint32_t* original_binary,
if (context == nullptr) return false;
context->set_max_id_bound(opt_options->max_id_bound_);
context->set_preserve_bindings(opt_options->preserve_bindings_);
context->set_preserve_spec_constants(opt_options->preserve_spec_constants_);
impl_->pass_manager.SetValidatorOptions(&opt_options->val_options_);
impl_->pass_manager.SetTargetEnv(impl_->target_env);

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

@ -39,3 +39,13 @@ SPIRV_TOOLS_EXPORT void spvOptimizerOptionsSetMaxIdBound(
spv_optimizer_options options, uint32_t val) {
options->max_id_bound_ = val;
}
SPIRV_TOOLS_EXPORT void spvOptimizerOptionsSetPreserveBindings(
spv_optimizer_options options, bool val) {
options->preserve_bindings_ = val;
}
SPIRV_TOOLS_EXPORT void spvOptimizerOptionsSetPreserveSpecConstants(
spv_optimizer_options options, bool val) {
options->preserve_spec_constants_ = val;
}

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

@ -24,7 +24,9 @@ struct spv_optimizer_options_t {
spv_optimizer_options_t()
: run_validator_(true),
val_options_(),
max_id_bound_(kDefaultMaxIdBound) {}
max_id_bound_(kDefaultMaxIdBound),
preserve_bindings_(false),
preserve_spec_constants_(false) {}
// When true the validator will be run before optimizations are run.
bool run_validator_;
@ -36,5 +38,12 @@ struct spv_optimizer_options_t {
// this value must be at least 0x3FFFFF, but implementations can allow for a
// higher value.
uint32_t max_id_bound_;
// When true, all binding declarations within the module should be preserved.
bool preserve_bindings_;
// When true, all specialization constants within the module should be
// preserved.
bool preserve_spec_constants_;
};
#endif // SOURCE_SPIRV_OPTIMIZER_OPTIONS_H_

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

@ -6496,6 +6496,70 @@ OpFunctionEnd
SinglePassRunAndMatch<AggressiveDCEPass>(spirv, true);
}
TEST_F(AggressiveDCETest, PreserveBindings) {
const std::string spirv = R"(
; CHECK: OpDecorate %unusedSampler DescriptorSet 0
; CHECK: OpDecorate %unusedSampler Binding 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 430
OpName %main "main"
OpName %unusedSampler "unusedSampler"
OpDecorate %unusedSampler DescriptorSet 0
OpDecorate %unusedSampler Binding 0
%void = OpTypeVoid
%5 = OpTypeFunction %void
%float = OpTypeFloat 32
%7 = OpTypeImage %float 2D 0 0 0 1 Unknown
%8 = OpTypeSampledImage %7
%_ptr_UniformConstant_8 = OpTypePointer UniformConstant %8
%unusedSampler = OpVariable %_ptr_UniformConstant_8 UniformConstant
%main = OpFunction %void None %5
%10 = OpLabel
OpReturn
OpFunctionEnd
)";
SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
OptimizerOptions()->preserve_bindings_ = true;
SinglePassRunAndMatch<AggressiveDCEPass>(spirv, true);
}
TEST_F(AggressiveDCETest, PreserveSpecConstants) {
const std::string spirv = R"(
; CHECK: OpName %specConstant "specConstant"
; CHECK: %specConstant = OpSpecConstant %int 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 430
OpName %main "main"
OpName %specConstant "specConstant"
OpDecorate %specConstant SpecId 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%int = OpTypeInt 32 1
%specConstant = OpSpecConstant %int 0
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
OptimizerOptions()->preserve_spec_constants_ = true;
SinglePassRunAndMatch<AggressiveDCEPass>(spirv, true);
}
// TODO(greg-lunarg): Add tests to verify handling of these cases:
//
// Check that logical addressing required

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

@ -27,6 +27,7 @@
#include "source/opt/build_module.h"
#include "source/opt/pass_manager.h"
#include "source/opt/passes.h"
#include "source/spirv_optimizer_options.h"
#include "source/spirv_validator_options.h"
#include "source/util/make_unique.h"
#include "spirv-tools/libspirv.hpp"
@ -67,6 +68,10 @@ class PassTest : public TestT {
return std::make_tuple(std::vector<uint32_t>(), Pass::Status::Failure);
}
context()->set_preserve_bindings(OptimizerOptions()->preserve_bindings_);
context()->set_preserve_spec_constants(
OptimizerOptions()->preserve_spec_constants_);
const auto status = pass->Run(context());
std::vector<uint32_t> binary;
@ -206,6 +211,10 @@ class PassTest : public TestT {
std::move(BuildModule(env_, nullptr, original, assemble_options_));
ASSERT_NE(nullptr, context());
context()->set_preserve_bindings(OptimizerOptions()->preserve_bindings_);
context()->set_preserve_spec_constants(
OptimizerOptions()->preserve_spec_constants_);
manager_->Run(context());
std::vector<uint32_t> binary;
@ -232,6 +241,8 @@ class PassTest : public TestT {
consumer_ = msg_consumer;
}
spv_optimizer_options OptimizerOptions() { return &optimizer_options_; }
spv_validator_options ValidatorOptions() { return &validator_options_; }
void SetTargetEnv(spv_target_env env) { env_ = env; }
@ -242,6 +253,7 @@ class PassTest : public TestT {
std::unique_ptr<PassManager> manager_; // The pass manager.
uint32_t assemble_options_;
uint32_t disassemble_options_;
spv_optimizer_options_t optimizer_options_;
spv_validator_options_t validator_options_;
spv_target_env env_;
};

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

@ -357,6 +357,14 @@ Options (in lexicographical order):)",
--merge-blocks followed by all the transformations implied by
-O.)");
printf(R"(
--preserve-bindings
Ensure that the optimizer preserves all bindings declared within
the module, even when those bindings are unused.)");
printf(R"(
--preserve-spec-constants
Ensure that the optimizer preserves all specialization constants declared
within the module, even when those constants are unused.)");
printf(R"(
--print-all
Print SPIR-V assembly to standard error output before each pass
and after the last pass.)");
@ -693,6 +701,10 @@ OptStatus ParseFlags(int argc, const char** argv,
optimizer_options->set_run_validator(false);
} else if (0 == strcmp(cur_arg, "--print-all")) {
optimizer->SetPrintAll(&std::cerr);
} else if (0 == strcmp(cur_arg, "--preserve-bindings")) {
optimizer_options->set_preserve_bindings(true);
} else if (0 == strcmp(cur_arg, "--preserve-spec-constants")) {
optimizer_options->set_preserve_spec_constants(true);
} else if (0 == strcmp(cur_arg, "--time-report")) {
optimizer->SetTimeReport(&std::cerr);
} else if (0 == strcmp(cur_arg, "--relax-struct-store")) {