Add -O, -Os and -Oconfig flags.
These flags are expanded to a series of spirv-opt flags with the following semantics: -O: expands to passes that attempt to improve the performance of the generated code. -Os: expands to passes that attempt to reduce the size of the generated code. -Oconfig=<file> expands to the sequence of passes determined by the flags specified in the user-provided file.
This commit is contained in:
Родитель
c26778fa99
Коммит
c90d7305e7
|
@ -77,17 +77,32 @@ class Optimizer {
|
|||
// method.
|
||||
Optimizer& RegisterPass(PassToken&& pass);
|
||||
|
||||
// Registers passes that attempt to improve performance of generated code.
|
||||
// This sequence of passes is subject to constant review and will change
|
||||
// from time to time.
|
||||
Optimizer& RegisterPerformancePasses();
|
||||
|
||||
// Registers passes that attempt to improve the size of generated code.
|
||||
// This sequence of passes is subject to constant review and will change
|
||||
// from time to time.
|
||||
Optimizer& RegisterSizePasses();
|
||||
|
||||
// Optimizes the given SPIR-V module |original_binary| and writes the
|
||||
// optimized binary into |optimized_binary|.
|
||||
// Returns true on successful optimization, whether or not the module is
|
||||
// modified. Returns false if errors occur when processing |original_binary|
|
||||
// using any of the registered passes. In that case, no further passes are
|
||||
// excuted and the contents in |optimized_binary| may be invalid.
|
||||
// executed and the contents in |optimized_binary| may be invalid.
|
||||
//
|
||||
// It's allowed to alias |original_binary| to the start of |optimized_binary|.
|
||||
bool Run(const uint32_t* original_binary, size_t original_binary_size,
|
||||
std::vector<uint32_t>* optimized_binary) const;
|
||||
|
||||
// Returns a vector of strings with all the pass names added to this
|
||||
// optimizer's pass manager. These strings are valid until the associated
|
||||
// pass manager is destroyed.
|
||||
std::vector<const char *> GetPassNames() const;
|
||||
|
||||
private:
|
||||
struct Impl; // Opaque struct for holding internal data.
|
||||
std::unique_ptr<Impl> impl_; // Unique pointer to internal data.
|
||||
|
|
|
@ -42,7 +42,7 @@ class AggressiveDCEPass : public MemPass {
|
|||
std::function<std::vector<ir::BasicBlock*>*(const ir::BasicBlock*)>;
|
||||
|
||||
AggressiveDCEPass();
|
||||
const char* name() const override { return "aggressive-dce"; }
|
||||
const char* name() const override { return "eliminate-dead-code-aggressive"; }
|
||||
Status Process(ir::Module*) override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace opt {
|
|||
class BlockMergePass : public Pass {
|
||||
public:
|
||||
BlockMergePass();
|
||||
const char* name() const override { return "sroa"; }
|
||||
const char* name() const override { return "merge-blocks"; }
|
||||
Status Process(ir::Module*) override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -41,7 +41,7 @@ class CommonUniformElimPass : public Pass {
|
|||
std::function<std::vector<ir::BasicBlock*>*(const ir::BasicBlock*)>;
|
||||
|
||||
CommonUniformElimPass();
|
||||
const char* name() const override { return "common-uniform-elim"; }
|
||||
const char* name() const override { return "eliminate-common-uniform"; }
|
||||
Status Process(ir::Module*) override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -43,7 +43,7 @@ class DeadBranchElimPass : public MemPass {
|
|||
std::function<std::vector<ir::BasicBlock*>*(const ir::BasicBlock*)>;
|
||||
|
||||
DeadBranchElimPass();
|
||||
const char* name() const override { return "dead-branch-elim"; }
|
||||
const char* name() const override { return "eliminate-dead-branches"; }
|
||||
Status Process(ir::Module*) override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -37,7 +37,7 @@ class InlineExhaustivePass : public InlinePass {
|
|||
InlineExhaustivePass();
|
||||
Status Process(ir::Module*) override;
|
||||
|
||||
const char* name() const override { return "inline-exhaustive"; }
|
||||
const char* name() const override { return "inline-entry-points-exhaustive"; }
|
||||
|
||||
private:
|
||||
// Exhaustively inline all function calls in func as well as in
|
||||
|
|
|
@ -37,7 +37,7 @@ class InlineOpaquePass : public InlinePass {
|
|||
InlineOpaquePass();
|
||||
Status Process(ir::Module*) override;
|
||||
|
||||
const char* name() const override { return "inline-opaque"; }
|
||||
const char* name() const override { return "inline-entry-points-opaque"; }
|
||||
|
||||
private:
|
||||
// Return true if |typeId| is or contains opaque type
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace opt {
|
|||
class InsertExtractElimPass : public Pass {
|
||||
public:
|
||||
InsertExtractElimPass();
|
||||
const char* name() const override { return "insert_extract_elim"; }
|
||||
const char* name() const override { return "eliminate-insert-extract"; }
|
||||
Status Process(ir::Module*) override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -66,6 +66,34 @@ Optimizer& Optimizer::RegisterPass(PassToken&& p) {
|
|||
return *this;
|
||||
}
|
||||
|
||||
Optimizer& Optimizer::RegisterPerformancePasses() {
|
||||
return RegisterPass(CreateInlineExhaustivePass())
|
||||
.RegisterPass(CreateLocalAccessChainConvertPass())
|
||||
.RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
|
||||
.RegisterPass(CreateLocalSingleStoreElimPass())
|
||||
.RegisterPass(CreateInsertExtractElimPass())
|
||||
.RegisterPass(CreateAggressiveDCEPass())
|
||||
.RegisterPass(CreateDeadBranchElimPass())
|
||||
.RegisterPass(CreateBlockMergePass())
|
||||
.RegisterPass(CreateLocalMultiStoreElimPass())
|
||||
.RegisterPass(CreateInsertExtractElimPass())
|
||||
.RegisterPass(CreateCommonUniformElimPass());
|
||||
}
|
||||
|
||||
Optimizer& Optimizer::RegisterSizePasses() {
|
||||
return RegisterPass(CreateInlineExhaustivePass())
|
||||
.RegisterPass(CreateLocalAccessChainConvertPass())
|
||||
.RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
|
||||
.RegisterPass(CreateLocalSingleStoreElimPass())
|
||||
.RegisterPass(CreateInsertExtractElimPass())
|
||||
.RegisterPass(CreateAggressiveDCEPass())
|
||||
.RegisterPass(CreateDeadBranchElimPass())
|
||||
.RegisterPass(CreateBlockMergePass())
|
||||
.RegisterPass(CreateLocalMultiStoreElimPass())
|
||||
.RegisterPass(CreateInsertExtractElimPass())
|
||||
.RegisterPass(CreateCommonUniformElimPass());
|
||||
}
|
||||
|
||||
bool Optimizer::Run(const uint32_t* original_binary,
|
||||
const size_t original_binary_size,
|
||||
std::vector<uint32_t>* optimized_binary) const {
|
||||
|
@ -95,13 +123,11 @@ Optimizer::PassToken CreateStripDebugInfoPass() {
|
|||
MakeUnique<opt::StripDebugInfoPass>());
|
||||
}
|
||||
|
||||
|
||||
Optimizer::PassToken CreateEliminateDeadFunctionsPass() {
|
||||
return MakeUnique<Optimizer::PassToken::Impl>(
|
||||
MakeUnique<opt::EliminateDeadFunctionsPass>());
|
||||
}
|
||||
|
||||
|
||||
Optimizer::PassToken CreateSetSpecConstantDefaultValuePass(
|
||||
const std::unordered_map<uint32_t, std::string>& id_value_map) {
|
||||
return MakeUnique<Optimizer::PassToken::Impl>(
|
||||
|
@ -153,17 +179,17 @@ Optimizer::PassToken CreateInlineExhaustivePass() {
|
|||
return MakeUnique<Optimizer::PassToken::Impl>(
|
||||
MakeUnique<opt::InlineExhaustivePass>());
|
||||
}
|
||||
|
||||
|
||||
Optimizer::PassToken CreateInlineOpaquePass() {
|
||||
return MakeUnique<Optimizer::PassToken::Impl>(
|
||||
MakeUnique<opt::InlineOpaquePass>());
|
||||
}
|
||||
|
||||
|
||||
Optimizer::PassToken CreateLocalAccessChainConvertPass() {
|
||||
return MakeUnique<Optimizer::PassToken::Impl>(
|
||||
MakeUnique<opt::LocalAccessChainConvertPass>());
|
||||
}
|
||||
|
||||
|
||||
Optimizer::PassToken CreateLocalSingleBlockLoadStoreElimPass() {
|
||||
return MakeUnique<Optimizer::PassToken::Impl>(
|
||||
MakeUnique<opt::LocalSingleBlockLoadStoreElimPass>());
|
||||
|
@ -204,4 +230,12 @@ Optimizer::PassToken CreateCompactIdsPass() {
|
|||
MakeUnique<opt::CompactIdsPass>());
|
||||
}
|
||||
|
||||
std::vector<const char*> Optimizer::GetPassNames() const {
|
||||
std::vector<const char*> v;
|
||||
for (uint32_t i = 0; i < impl_->pass_manager.NumPasses(); i++) {
|
||||
v.push_back(impl_->pass_manager.GetPass(i)->name());
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
} // namespace spvtools
|
||||
|
|
|
@ -56,6 +56,11 @@ class Pass {
|
|||
virtual ~Pass() = default;
|
||||
|
||||
// Returns a descriptive name for this pass.
|
||||
//
|
||||
// NOTE: When deriving a new pass class, make sure you make the name
|
||||
// compatible with the corresponding spirv-opt command-line flag. For example,
|
||||
// if you add the flag --my-pass to spirv-opt, make this function return
|
||||
// "my-pass" (no leading hyphens).
|
||||
virtual const char* name() const = 0;
|
||||
|
||||
// Sets the message consumer to the given |consumer|. |consumer| which will be
|
||||
|
|
|
@ -12,8 +12,10 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
@ -27,6 +29,36 @@
|
|||
|
||||
using namespace spvtools;
|
||||
|
||||
namespace {
|
||||
|
||||
// Status and actions to perform after parsing command-line arguments.
|
||||
enum OptActions { OPT_CONTINUE, OPT_STOP };
|
||||
|
||||
struct OptStatus {
|
||||
OptActions action;
|
||||
int code;
|
||||
};
|
||||
|
||||
std::string GetListOfPassesAsString(const spvtools::Optimizer& optimizer) {
|
||||
std::stringstream ss;
|
||||
for (const auto& name : optimizer.GetPassNames()) {
|
||||
ss << "\n\t\t" << name;
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string GetOptimizationPasses() {
|
||||
spvtools::Optimizer optimizer(SPV_ENV_UNIVERSAL_1_2);
|
||||
optimizer.RegisterPerformancePasses();
|
||||
return GetListOfPassesAsString(optimizer);
|
||||
}
|
||||
|
||||
std::string GetSizePasses() {
|
||||
spvtools::Optimizer optimizer(SPV_ENV_UNIVERSAL_1_2);
|
||||
optimizer.RegisterSizePasses();
|
||||
return GetListOfPassesAsString(optimizer);
|
||||
}
|
||||
|
||||
void PrintUsage(const char* program) {
|
||||
printf(
|
||||
R"(%s - Optimize a SPIR-V binary file.
|
||||
|
@ -117,15 +149,257 @@ Options:
|
|||
call tree functions.
|
||||
--strength-reduction
|
||||
Replaces instructions with equivalent and less expensive ones.
|
||||
-h, --help
|
||||
-O
|
||||
Optimize for performance. Apply a sequence of transformations
|
||||
in an attempt to improve the performance of the generated
|
||||
code. For this version of the optimizer, this flag is equivalent
|
||||
to specifying the following optimization code names:
|
||||
%s
|
||||
-Os
|
||||
Optimize for size. Apply a sequence of transformations in an
|
||||
attempt to minimize the size of the generated code. For this
|
||||
version of the optimizer, this flag is equivalent to specifying
|
||||
the following optimization code names:
|
||||
%s
|
||||
|
||||
NOTE: The specific transformations done by -O and -Os change
|
||||
from release to release.
|
||||
-Oconfig=<file>
|
||||
Apply the sequence of transformations indicated in <file>.
|
||||
This file contains a sequence of strings separated by whitespace
|
||||
(tabs, newlines or blanks). Each string is one of the flags
|
||||
accepted by spirv-opt. Optimizations will be applied in the
|
||||
sequence they appear in the file. This is equivalent to
|
||||
specifying all the flags on the command line. For example,
|
||||
given the file opts.cfg with the content:
|
||||
|
||||
--inline-entry-points-exhaustive
|
||||
--eliminate-dead-code-aggressive
|
||||
|
||||
The following two invocations to spirv-opt are equivalent:
|
||||
|
||||
$ spirv-opt -Oconfig=opts.cfg program.spv
|
||||
|
||||
$ spirv-opt --inline-entry-points-exhaustive \
|
||||
--eliminate-dead-code-aggressive program.spv
|
||||
|
||||
Lines starting with the character '#' in the configuration
|
||||
file indicate a comment and will be ignored.
|
||||
|
||||
The -O, -Os, and -Oconfig flags act as macros. Using one of them
|
||||
is equivalent to explicitly inserting the underlying flags at
|
||||
that position in the command line. For example, the invocation
|
||||
'spirv-opt --merge-blocks -O ...' applies the transformation
|
||||
--merge-blocks followed by all the transformations implied by
|
||||
-O.
|
||||
-h, --help
|
||||
Print this help.
|
||||
--version
|
||||
--version
|
||||
Display optimizer version information.
|
||||
)",
|
||||
program, program);
|
||||
program, program, GetOptimizationPasses().c_str(),
|
||||
GetSizePasses().c_str());
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
// Reads command-line flags the file specified in |oconfig_flag|. This string
|
||||
// is assumed to have the form "-Oconfig=FILENAME". This function parses the
|
||||
// string and extracts the file name after the '=' sign.
|
||||
//
|
||||
// Flags found in |FILENAME| are pushed at the end of the vector |file_flags|.
|
||||
//
|
||||
// This function returns true on success, false on failure.
|
||||
bool ReadFlagsFromFile(const char* oconfig_flag,
|
||||
std::vector<std::string>* file_flags) {
|
||||
const char* fname = strchr(oconfig_flag, '=');
|
||||
if (fname == nullptr || fname[0] != '=') {
|
||||
fprintf(stderr, "error: Invalid -Oconfig flag %s\n", oconfig_flag);
|
||||
return false;
|
||||
}
|
||||
fname++;
|
||||
|
||||
std::ifstream input_file;
|
||||
input_file.open(fname);
|
||||
if (input_file.fail()) {
|
||||
fprintf(stderr, "error: Could not open file '%s'\n", fname);
|
||||
return false;
|
||||
}
|
||||
|
||||
while (!input_file.eof()) {
|
||||
std::string flag;
|
||||
input_file >> flag;
|
||||
if (flag.length() > 0 && flag[0] != '#') {
|
||||
file_flags->push_back(flag);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
OptStatus ParseFlags(int argc, const char** argv, Optimizer* optimizer,
|
||||
const char** in_file, const char** out_file);
|
||||
|
||||
// Parses and handles the -Oconfig flag. |prog_name| contains the name of
|
||||
// the spirv-opt binary (used to build a new argv vector for the recursive
|
||||
// invocation to ParseFlags). |opt_flag| contains the -Oconfig=FILENAME flag.
|
||||
// |optimizer|, |in_file| and |out_file| are as in ParseFlags.
|
||||
//
|
||||
// This returns the same OptStatus instance returned by ParseFlags.
|
||||
OptStatus ParseOconfigFlag(const char* prog_name, const char* opt_flag,
|
||||
Optimizer* optimizer, const char** in_file,
|
||||
const char** out_file) {
|
||||
std::vector<std::string> flags;
|
||||
flags.push_back(prog_name);
|
||||
|
||||
std::vector<std::string> file_flags;
|
||||
if (!ReadFlagsFromFile(opt_flag, &file_flags)) {
|
||||
fprintf(stderr,
|
||||
"error: Could not read optimizer flags from configuration file\n");
|
||||
return {OPT_STOP, 1};
|
||||
}
|
||||
flags.insert(flags.end(), file_flags.begin(), file_flags.end());
|
||||
|
||||
const char** new_argv = new const char*[flags.size()];
|
||||
for (size_t i = 0; i < flags.size(); i++) {
|
||||
if (flags[i].find("-Oconfig=") != std::string::npos) {
|
||||
fprintf(stderr,
|
||||
"error: Flag -Oconfig= may not be used inside the configuration "
|
||||
"file\n");
|
||||
return {OPT_STOP, 1};
|
||||
}
|
||||
new_argv[i] = flags[i].c_str();
|
||||
}
|
||||
|
||||
return ParseFlags(static_cast<int>(flags.size()), new_argv, optimizer,
|
||||
in_file, out_file);
|
||||
}
|
||||
|
||||
// Parses command-line flags. |argc| contains the number of command-line flags.
|
||||
// |argv| points to an array of strings holding the flags. |optimizer| is the
|
||||
// Optimizer instance used to optimize the program.
|
||||
//
|
||||
// On return, this function stores the name of the input program in |in_file|.
|
||||
// The name of the output file in |out_file|. The return value indicates whether
|
||||
// optimization should continue and a status code indicating an error or
|
||||
// success.
|
||||
OptStatus ParseFlags(int argc, const char** argv, Optimizer* optimizer,
|
||||
const char** in_file, const char** out_file) {
|
||||
for (int argi = 1; argi < argc; ++argi) {
|
||||
const char* cur_arg = argv[argi];
|
||||
if ('-' == cur_arg[0]) {
|
||||
if (0 == strcmp(cur_arg, "--version")) {
|
||||
printf("%s\n", spvSoftwareVersionDetailsString());
|
||||
return {OPT_STOP, 0};
|
||||
} else if (0 == strcmp(cur_arg, "--help") || 0 == strcmp(cur_arg, "-h")) {
|
||||
PrintUsage(argv[0]);
|
||||
return {OPT_STOP, 0};
|
||||
} else if (0 == strcmp(cur_arg, "-o")) {
|
||||
if (!*out_file && argi + 1 < argc) {
|
||||
*out_file = argv[++argi];
|
||||
} else {
|
||||
PrintUsage(argv[0]);
|
||||
return {OPT_STOP, 1};
|
||||
}
|
||||
} else if (0 == strcmp(cur_arg, "--strip-debug")) {
|
||||
optimizer->RegisterPass(CreateStripDebugInfoPass());
|
||||
} else if (0 == strcmp(cur_arg, "--set-spec-const-default-value")) {
|
||||
if (++argi < argc) {
|
||||
auto spec_ids_vals =
|
||||
opt::SetSpecConstantDefaultValuePass::ParseDefaultValuesString(
|
||||
argv[argi]);
|
||||
if (!spec_ids_vals) {
|
||||
fprintf(stderr,
|
||||
"error: Invalid argument for "
|
||||
"--set-spec-const-default-value: %s\n",
|
||||
argv[argi]);
|
||||
return {OPT_STOP, 1};
|
||||
}
|
||||
optimizer->RegisterPass(
|
||||
CreateSetSpecConstantDefaultValuePass(std::move(*spec_ids_vals)));
|
||||
} else {
|
||||
fprintf(
|
||||
stderr,
|
||||
"error: Expected a string of <spec id>:<default value> pairs.");
|
||||
return {OPT_STOP, 1};
|
||||
}
|
||||
} else if (0 == strcmp(cur_arg, "--freeze-spec-const")) {
|
||||
optimizer->RegisterPass(CreateFreezeSpecConstantValuePass());
|
||||
} else if (0 == strcmp(cur_arg, "--inline-entry-points-exhaustive")) {
|
||||
optimizer->RegisterPass(CreateInlineExhaustivePass());
|
||||
} else if (0 == strcmp(cur_arg, "--inline-entry-points-opaque")) {
|
||||
optimizer->RegisterPass(CreateInlineOpaquePass());
|
||||
} else if (0 == strcmp(cur_arg, "--convert-local-access-chains")) {
|
||||
optimizer->RegisterPass(CreateLocalAccessChainConvertPass());
|
||||
} else if (0 == strcmp(cur_arg, "--eliminate-dead-code-aggressive")) {
|
||||
optimizer->RegisterPass(CreateAggressiveDCEPass());
|
||||
} else if (0 == strcmp(cur_arg, "--eliminate-insert-extract")) {
|
||||
optimizer->RegisterPass(CreateInsertExtractElimPass());
|
||||
} else if (0 == strcmp(cur_arg, "--eliminate-local-single-block")) {
|
||||
optimizer->RegisterPass(CreateLocalSingleBlockLoadStoreElimPass());
|
||||
} else if (0 == strcmp(cur_arg, "--eliminate-local-single-store")) {
|
||||
optimizer->RegisterPass(CreateLocalSingleStoreElimPass());
|
||||
} else if (0 == strcmp(cur_arg, "--merge-blocks")) {
|
||||
optimizer->RegisterPass(CreateBlockMergePass());
|
||||
} else if (0 == strcmp(cur_arg, "--eliminate-dead-branches")) {
|
||||
optimizer->RegisterPass(CreateDeadBranchElimPass());
|
||||
} else if (0 == strcmp(cur_arg, "--eliminate-dead-functions")) {
|
||||
optimizer->RegisterPass(CreateEliminateDeadFunctionsPass());
|
||||
} else if (0 == strcmp(cur_arg, "--eliminate-local-multi-store")) {
|
||||
optimizer->RegisterPass(CreateLocalMultiStoreElimPass());
|
||||
} else if (0 == strcmp(cur_arg, "--eliminate-common-uniform")) {
|
||||
optimizer->RegisterPass(CreateCommonUniformElimPass());
|
||||
} else if (0 == strcmp(cur_arg, "--eliminate-dead-const")) {
|
||||
optimizer->RegisterPass(CreateEliminateDeadConstantPass());
|
||||
} else if (0 == strcmp(cur_arg, "--fold-spec-const-op-composite")) {
|
||||
optimizer->RegisterPass(CreateFoldSpecConstantOpAndCompositePass());
|
||||
} else if (0 == strcmp(cur_arg, "--strength-reduction")) {
|
||||
optimizer->RegisterPass(CreateStrengthReductionPass());
|
||||
} else if (0 == strcmp(cur_arg, "--unify-const")) {
|
||||
optimizer->RegisterPass(CreateUnifyConstantPass());
|
||||
} else if (0 == strcmp(cur_arg, "--flatten-decorations")) {
|
||||
optimizer->RegisterPass(CreateFlattenDecorationPass());
|
||||
} else if (0 == strcmp(cur_arg, "--compact-ids")) {
|
||||
optimizer->RegisterPass(CreateCompactIdsPass());
|
||||
} else if (0 == strcmp(cur_arg, "-O")) {
|
||||
optimizer->RegisterPerformancePasses();
|
||||
} else if (0 == strcmp(cur_arg, "-Os")) {
|
||||
optimizer->RegisterSizePasses();
|
||||
} else if (0 == strncmp(cur_arg, "-Oconfig=", sizeof("-Oconfig=") - 1)) {
|
||||
OptStatus status =
|
||||
ParseOconfigFlag(argv[0], cur_arg, optimizer, in_file, out_file);
|
||||
if (status.action != OPT_CONTINUE) {
|
||||
return status;
|
||||
}
|
||||
} else if ('\0' == cur_arg[1]) {
|
||||
// Setting a filename of "-" to indicate stdin.
|
||||
if (!*in_file) {
|
||||
*in_file = cur_arg;
|
||||
} else {
|
||||
fprintf(stderr, "error: More than one input file specified\n");
|
||||
return {OPT_STOP, 1};
|
||||
}
|
||||
} else {
|
||||
fprintf(
|
||||
stderr,
|
||||
"error: Unknown flag '%s'. Use --help for a list of valid flags\n",
|
||||
cur_arg);
|
||||
return {OPT_STOP, 1};
|
||||
}
|
||||
} else {
|
||||
if (!*in_file) {
|
||||
*in_file = cur_arg;
|
||||
} else {
|
||||
fprintf(stderr, "error: More than one input file specified\n");
|
||||
return {OPT_STOP, 1};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {OPT_CONTINUE, 0};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, const char** argv) {
|
||||
const char* in_file = nullptr;
|
||||
const char* out_file = nullptr;
|
||||
|
||||
|
@ -139,102 +413,9 @@ int main(int argc, char** argv) {
|
|||
<< std::endl;
|
||||
});
|
||||
|
||||
for (int argi = 1; argi < argc; ++argi) {
|
||||
const char* cur_arg = argv[argi];
|
||||
if ('-' == cur_arg[0]) {
|
||||
if (0 == strcmp(cur_arg, "--version")) {
|
||||
printf("%s\n", spvSoftwareVersionDetailsString());
|
||||
return 0;
|
||||
} else if (0 == strcmp(cur_arg, "--help") || 0 == strcmp(cur_arg, "-h")) {
|
||||
PrintUsage(argv[0]);
|
||||
return 0;
|
||||
} else if (0 == strcmp(cur_arg, "-o")) {
|
||||
if (!out_file && argi + 1 < argc) {
|
||||
out_file = argv[++argi];
|
||||
} else {
|
||||
PrintUsage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
} else if (0 == strcmp(cur_arg, "--strip-debug")) {
|
||||
optimizer.RegisterPass(CreateStripDebugInfoPass());
|
||||
} else if (0 == strcmp(cur_arg, "--set-spec-const-default-value")) {
|
||||
if (++argi < argc) {
|
||||
auto spec_ids_vals =
|
||||
opt::SetSpecConstantDefaultValuePass::ParseDefaultValuesString(
|
||||
argv[argi]);
|
||||
if (!spec_ids_vals) {
|
||||
fprintf(stderr,
|
||||
"error: Invalid argument for "
|
||||
"--set-spec-const-default-value: %s\n",
|
||||
argv[argi]);
|
||||
return 1;
|
||||
}
|
||||
optimizer.RegisterPass(
|
||||
CreateSetSpecConstantDefaultValuePass(std::move(*spec_ids_vals)));
|
||||
} else {
|
||||
fprintf(
|
||||
stderr,
|
||||
"error: Expected a string of <spec id>:<default value> pairs.");
|
||||
return 1;
|
||||
}
|
||||
} else if (0 == strcmp(cur_arg, "--freeze-spec-const")) {
|
||||
optimizer.RegisterPass(CreateFreezeSpecConstantValuePass());
|
||||
} else if (0 == strcmp(cur_arg, "--inline-entry-points-exhaustive")) {
|
||||
optimizer.RegisterPass(CreateInlineExhaustivePass());
|
||||
} else if (0 == strcmp(cur_arg, "--inline-entry-points-opaque")) {
|
||||
optimizer.RegisterPass(CreateInlineOpaquePass());
|
||||
} else if (0 == strcmp(cur_arg, "--convert-local-access-chains")) {
|
||||
optimizer.RegisterPass(CreateLocalAccessChainConvertPass());
|
||||
} else if (0 == strcmp(cur_arg, "--eliminate-dead-code-aggressive")) {
|
||||
optimizer.RegisterPass(CreateAggressiveDCEPass());
|
||||
} else if (0 == strcmp(cur_arg, "--eliminate-insert-extract")) {
|
||||
optimizer.RegisterPass(CreateInsertExtractElimPass());
|
||||
} else if (0 == strcmp(cur_arg, "--eliminate-local-single-block")) {
|
||||
optimizer.RegisterPass(CreateLocalSingleBlockLoadStoreElimPass());
|
||||
} else if (0 == strcmp(cur_arg, "--eliminate-local-single-store")) {
|
||||
optimizer.RegisterPass(CreateLocalSingleStoreElimPass());
|
||||
} else if (0 == strcmp(cur_arg, "--merge-blocks")) {
|
||||
optimizer.RegisterPass(CreateBlockMergePass());
|
||||
} else if (0 == strcmp(cur_arg, "--eliminate-dead-branches")) {
|
||||
optimizer.RegisterPass(CreateDeadBranchElimPass());
|
||||
} else if (0 == strcmp(cur_arg, "--eliminate-dead-functions")) {
|
||||
optimizer.RegisterPass(CreateEliminateDeadFunctionsPass());
|
||||
} else if (0 == strcmp(cur_arg, "--eliminate-local-multi-store")) {
|
||||
optimizer.RegisterPass(CreateLocalMultiStoreElimPass());
|
||||
} else if (0 == strcmp(cur_arg, "--eliminate-common-uniform")) {
|
||||
optimizer.RegisterPass(CreateCommonUniformElimPass());
|
||||
} else if (0 == strcmp(cur_arg, "--eliminate-dead-const")) {
|
||||
optimizer.RegisterPass(CreateEliminateDeadConstantPass());
|
||||
} else if (0 == strcmp(cur_arg, "--fold-spec-const-op-composite")) {
|
||||
optimizer.RegisterPass(CreateFoldSpecConstantOpAndCompositePass());
|
||||
} else if (0 == strcmp(cur_arg, "--strength-reduction")) {
|
||||
optimizer.RegisterPass(CreateStrengthReductionPass());
|
||||
} else if (0 == strcmp(cur_arg, "--unify-const")) {
|
||||
optimizer.RegisterPass(CreateUnifyConstantPass());
|
||||
} else if (0 == strcmp(cur_arg, "--flatten-decorations")) {
|
||||
optimizer.RegisterPass(CreateFlattenDecorationPass());
|
||||
} else if (0 == strcmp(cur_arg, "--compact-ids")) {
|
||||
optimizer.RegisterPass(CreateCompactIdsPass());
|
||||
} else if ('\0' == cur_arg[1]) {
|
||||
// Setting a filename of "-" to indicate stdin.
|
||||
if (!in_file) {
|
||||
in_file = cur_arg;
|
||||
} else {
|
||||
fprintf(stderr, "error: More than one input file specified\n");
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
PrintUsage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (!in_file) {
|
||||
in_file = cur_arg;
|
||||
} else {
|
||||
fprintf(stderr, "error: More than one input file specified\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
OptStatus status = ParseFlags(argc, argv, &optimizer, &in_file, &out_file);
|
||||
if (status.action == OPT_STOP) {
|
||||
return status.code;
|
||||
}
|
||||
|
||||
if (out_file == nullptr) {
|
||||
|
@ -243,7 +424,9 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
|
||||
std::vector<uint32_t> binary;
|
||||
if (!ReadFile<uint32_t>(in_file, "rb", &binary)) return 1;
|
||||
if (!ReadFile<uint32_t>(in_file, "rb", &binary)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Let's do validation first.
|
||||
spv_context context = spvContextCreate(target_env);
|
||||
|
|
Загрузка…
Ссылка в новой задаче