Skip to content

Commit 155728b

Browse files
authored
Add preserver-interface option to spirv-opt (KhronosGroup#5524)
The optimizer is able to preserve the interface variables of the shaders, but that feature has not been exposed to the command line tool. This commit adds an option `--preserve-interface` to spirv-opt that will cause all calls to ADCE to leave the input and output variables, even if the variable is unused. It will apply regardless of where the option appears on the command line. Fixes KhronosGroup#5522
1 parent 01ee1bf commit 155728b

File tree

4 files changed

+61
-18
lines changed

4 files changed

+61
-18
lines changed

include/spirv-tools/libspirv.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -966,9 +966,16 @@ SPIRV_TOOLS_EXPORT bool spvOptimizerRegisterPassFromFlag(
966966
spv_optimizer_t* optimizer, const char* flag);
967967

968968
// Registers passes specified by length number of flags in an optimizer object.
969+
// Passes may remove interface variables that are unused.
969970
SPIRV_TOOLS_EXPORT bool spvOptimizerRegisterPassesFromFlags(
970971
spv_optimizer_t* optimizer, const char** flags, const size_t flag_count);
971972

973+
// Registers passes specified by length number of flags in an optimizer object.
974+
// Passes will not remove interface variables.
975+
SPIRV_TOOLS_EXPORT bool
976+
spvOptimizerRegisterPassesFromFlagsWhilePreservingTheInterface(
977+
spv_optimizer_t* optimizer, const char** flags, const size_t flag_count);
978+
972979
// Optimizes the SPIR-V code of size |word_count| pointed to by |binary| and
973980
// returns an optimized spv_binary in |optimized_binary|.
974981
//

include/spirv-tools/optimizer.hpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,6 @@ class Optimizer {
100100
//
101101
// If |preserve_interface| is true, all non-io variables in the entry point
102102
// interface are considered live and are not eliminated.
103-
// |preserve_interface| should be true if HLSL is generated
104-
// from the SPIR-V bytecode.
105103
Optimizer& RegisterPerformancePasses();
106104
Optimizer& RegisterPerformancePasses(bool preserve_interface);
107105

@@ -111,8 +109,6 @@ class Optimizer {
111109
//
112110
// If |preserve_interface| is true, all non-io variables in the entry point
113111
// interface are considered live and are not eliminated.
114-
// |preserve_interface| should be true if HLSL is generated
115-
// from the SPIR-V bytecode.
116112
Optimizer& RegisterSizePasses();
117113
Optimizer& RegisterSizePasses(bool preserve_interface);
118114

@@ -127,8 +123,6 @@ class Optimizer {
127123
//
128124
// If |preserve_interface| is true, all non-io variables in the entry point
129125
// interface are considered live and are not eliminated.
130-
// |preserve_interface| should be true if HLSL is generated
131-
// from the SPIR-V bytecode.
132126
Optimizer& RegisterLegalizationPasses();
133127
Optimizer& RegisterLegalizationPasses(bool preserve_interface);
134128

@@ -139,8 +133,13 @@ class Optimizer {
139133
// error message is emitted to the MessageConsumer object (use
140134
// Optimizer::SetMessageConsumer to define a message consumer, if needed).
141135
//
136+
// If |preserve_interface| is true, all non-io variables in the entry point
137+
// interface are considered live and are not eliminated.
138+
//
142139
// If all the passes are registered successfully, it returns true.
143140
bool RegisterPassesFromFlags(const std::vector<std::string>& flags);
141+
bool RegisterPassesFromFlags(const std::vector<std::string>& flags,
142+
bool preserve_interface);
144143

145144
// Registers the optimization pass associated with |flag|. This only accepts
146145
// |flag| values of the form "--pass_name[=pass_args]". If no such pass
@@ -157,7 +156,11 @@ class Optimizer {
157156
//
158157
// --legalize-hlsl: Registers all passes that legalize SPIR-V generated by an
159158
// HLSL front-end.
159+
//
160+
// If |preserve_interface| is true, all non-io variables in the entry point
161+
// interface are considered live and are not eliminated.
160162
bool RegisterPassFromFlag(const std::string& flag);
163+
bool RegisterPassFromFlag(const std::string& flag, bool preserve_interface);
161164

162165
// Validates that |flag| has a valid format. Strings accepted:
163166
//

source/opt/optimizer.cpp

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,15 @@
3333

3434
namespace spvtools {
3535

36+
std::vector<std::string> GetVectorOfStrings(const char** strings,
37+
const size_t string_count) {
38+
std::vector<std::string> result;
39+
for (uint32_t i = 0; i < string_count; i++) {
40+
result.emplace_back(strings[i]);
41+
}
42+
return result;
43+
}
44+
3645
struct Optimizer::PassToken::Impl {
3746
Impl(std::unique_ptr<opt::Pass> p) : pass(std::move(p)) {}
3847

@@ -256,8 +265,13 @@ Optimizer& Optimizer::RegisterSizePasses(bool preserve_interface) {
256265
Optimizer& Optimizer::RegisterSizePasses() { return RegisterSizePasses(false); }
257266

258267
bool Optimizer::RegisterPassesFromFlags(const std::vector<std::string>& flags) {
268+
return RegisterPassesFromFlags(flags, false);
269+
}
270+
271+
bool Optimizer::RegisterPassesFromFlags(const std::vector<std::string>& flags,
272+
bool preserve_interface) {
259273
for (const auto& flag : flags) {
260-
if (!RegisterPassFromFlag(flag)) {
274+
if (!RegisterPassFromFlag(flag, preserve_interface)) {
261275
return false;
262276
}
263277
}
@@ -281,6 +295,11 @@ bool Optimizer::FlagHasValidForm(const std::string& flag) const {
281295
}
282296

283297
bool Optimizer::RegisterPassFromFlag(const std::string& flag) {
298+
return RegisterPassFromFlag(flag, false);
299+
}
300+
301+
bool Optimizer::RegisterPassFromFlag(const std::string& flag,
302+
bool preserve_interface) {
284303
if (!FlagHasValidForm(flag)) {
285304
return false;
286305
}
@@ -342,7 +361,7 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) {
342361
} else if (pass_name == "descriptor-scalar-replacement") {
343362
RegisterPass(CreateDescriptorScalarReplacementPass());
344363
} else if (pass_name == "eliminate-dead-code-aggressive") {
345-
RegisterPass(CreateAggressiveDCEPass());
364+
RegisterPass(CreateAggressiveDCEPass(preserve_interface));
346365
} else if (pass_name == "eliminate-insert-extract") {
347366
RegisterPass(CreateInsertExtractElimPass());
348367
} else if (pass_name == "eliminate-local-single-block") {
@@ -513,11 +532,11 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) {
513532
} else if (pass_name == "fix-storage-class") {
514533
RegisterPass(CreateFixStorageClassPass());
515534
} else if (pass_name == "O") {
516-
RegisterPerformancePasses();
535+
RegisterPerformancePasses(preserve_interface);
517536
} else if (pass_name == "Os") {
518-
RegisterSizePasses();
537+
RegisterSizePasses(preserve_interface);
519538
} else if (pass_name == "legalize-hlsl") {
520-
RegisterLegalizationPasses();
539+
RegisterLegalizationPasses(preserve_interface);
521540
} else if (pass_name == "remove-unused-interface-variables") {
522541
RegisterPass(CreateRemoveUnusedInterfaceVariablesPass());
523542
} else if (pass_name == "graphics-robust-access") {
@@ -1170,13 +1189,19 @@ SPIRV_TOOLS_EXPORT bool spvOptimizerRegisterPassFromFlag(
11701189

11711190
SPIRV_TOOLS_EXPORT bool spvOptimizerRegisterPassesFromFlags(
11721191
spv_optimizer_t* optimizer, const char** flags, const size_t flag_count) {
1173-
std::vector<std::string> opt_flags;
1174-
for (uint32_t i = 0; i < flag_count; i++) {
1175-
opt_flags.emplace_back(flags[i]);
1176-
}
1192+
std::vector<std::string> opt_flags =
1193+
spvtools::GetVectorOfStrings(flags, flag_count);
1194+
return reinterpret_cast<spvtools::Optimizer*>(optimizer)
1195+
->RegisterPassesFromFlags(opt_flags, false);
1196+
}
11771197

1178-
return reinterpret_cast<spvtools::Optimizer*>(optimizer)->
1179-
RegisterPassesFromFlags(opt_flags);
1198+
SPIRV_TOOLS_EXPORT bool
1199+
spvOptimizerRegisterPassesFromFlagsWhilePreservingTheInterface(
1200+
spv_optimizer_t* optimizer, const char** flags, const size_t flag_count) {
1201+
std::vector<std::string> opt_flags =
1202+
spvtools::GetVectorOfStrings(flags, flag_count);
1203+
return reinterpret_cast<spvtools::Optimizer*>(optimizer)
1204+
->RegisterPassesFromFlags(opt_flags, true);
11801205
}
11811206

11821207
SPIRV_TOOLS_EXPORT

tools/opt/opt.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,11 @@ Options (in lexicographical order):)",
392392
Ensure that the optimizer preserves all bindings declared within
393393
the module, even when those bindings are unused.)");
394394
printf(R"(
395+
--preserve-interface
396+
Ensure that input and output variables are not removed from the
397+
shader, even if they are unused. Note that this option applies to
398+
all passes that will be run regardless of the order of the flags.)");
399+
printf(R"(
395400
--preserve-spec-constants
396401
Ensure that the optimizer preserves all specialization constants declared
397402
within the module, even when those constants are unused.)");
@@ -701,6 +706,7 @@ OptStatus ParseFlags(int argc, const char** argv,
701706
spvtools::ValidatorOptions* validator_options,
702707
spvtools::OptimizerOptions* optimizer_options) {
703708
std::vector<std::string> pass_flags;
709+
bool preserve_interface = true;
704710
for (int argi = 1; argi < argc; ++argi) {
705711
const char* cur_arg = argv[argi];
706712
if ('-' == cur_arg[0]) {
@@ -790,6 +796,8 @@ OptStatus ParseFlags(int argc, const char** argv,
790796
validator_options->SetSkipBlockLayout(true);
791797
} else if (0 == strcmp(cur_arg, "--relax-struct-store")) {
792798
validator_options->SetRelaxStructStore(true);
799+
} else if (0 == strcmp(cur_arg, "--preserve-interface")) {
800+
preserve_interface = true;
793801
} else {
794802
// Some passes used to accept the form '--pass arg', canonicalize them
795803
// to '--pass=arg'.
@@ -812,7 +820,7 @@ OptStatus ParseFlags(int argc, const char** argv,
812820
}
813821
}
814822

815-
if (!optimizer->RegisterPassesFromFlags(pass_flags)) {
823+
if (!optimizer->RegisterPassesFromFlags(pass_flags, preserve_interface)) {
816824
return {OPT_STOP, 1};
817825
}
818826

0 commit comments

Comments
 (0)