| /* | |
| * Copyright 2018 WebAssembly Community Group participants | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #ifndef wasm_tools_tool_options_h | |
| #define wasm_tools_tool_options_h | |
| #include "ir/module-utils.h" | |
| #include "pass.h" | |
| #include "support/command-line.h" | |
| #include "wasm-io.h" | |
| // | |
| // Shared options for commandline tools | |
| // | |
| namespace wasm { | |
| struct ToolOptions : public Options { | |
| PassOptions passOptions; | |
| bool quiet = false; | |
| bool preserveTypeOrder = false; | |
| bool emitModuleNames = false; | |
| IRProfile profile = IRProfile::Normal; | |
| constexpr static const char* ToolOptionsCategory = "Tool options"; | |
| ToolOptions(const std::string& command, const std::string& description) | |
| : Options(command, description) { | |
| (*this) | |
| .add("--mvp-features", | |
| "-mvp", | |
| "Disable all non-MVP features", | |
| ToolOptionsCategory, | |
| Arguments::Zero, | |
| [this](Options*, const std::string&) { | |
| enabledFeatures.setMVP(); | |
| disabledFeatures.setAll(); | |
| }) | |
| .add("--all-features", | |
| "-all", | |
| "Enable all features", | |
| ToolOptionsCategory, | |
| Arguments::Zero, | |
| [this](Options*, const std::string&) { | |
| enabledFeatures.setAll(); | |
| disabledFeatures.setMVP(); | |
| }) | |
| .add("--detect-features", | |
| "", | |
| "(deprecated - this flag does nothing)", | |
| ToolOptionsCategory, | |
| Arguments::Zero, | |
| [](Options*, const std::string&) {}) | |
| .add("--quiet", | |
| "-q", | |
| "Emit less verbose output and hide trivial warnings.", | |
| ToolOptionsCategory, | |
| Arguments::Zero, | |
| [this](Options*, const std::string&) { quiet = true; }) | |
| .add("--experimental-poppy", | |
| "", | |
| "Parse wast files as Poppy IR for testing purposes.", | |
| ToolOptionsCategory, | |
| Arguments::Zero, | |
| [this](Options*, const std::string&) { profile = IRProfile::Poppy; }) | |
| .add("--emit-module-names", | |
| "", | |
| "Emit module names, even if not emitting the rest of the names " | |
| "section.", | |
| ToolOptionsCategory, | |
| Arguments::Zero, | |
| [this](Options*, const std::string&) { emitModuleNames = true; }); | |
| (*this) | |
| .addFeature(FeatureSet::SignExt, "sign extension operations") | |
| .addFeature(FeatureSet::Atomics, "atomic operations") | |
| .addFeature(FeatureSet::MutableGlobals, "mutable globals") | |
| .addFeature(FeatureSet::TruncSat, "nontrapping float-to-int operations") | |
| .addFeature(FeatureSet::SIMD, "SIMD operations and types") | |
| .addFeature(FeatureSet::BulkMemory, | |
| "bulk memory operations", | |
| FeatureSet(FeatureSet::BulkMemoryOpt)) | |
| .addFeature(FeatureSet::BulkMemoryOpt, | |
| "memory.copy and memory.fill", | |
| FeatureSet::None, | |
| FeatureSet(FeatureSet::BulkMemory)) | |
| .addFeature(FeatureSet::CallIndirectOverlong, | |
| "LEB encoding of call-indirect (Ignored for compatibility as " | |
| "it has no effect on Binaryen)") | |
| .addFeature(FeatureSet::ExceptionHandling, | |
| "exception handling operations") | |
| .addFeature(FeatureSet::TailCall, "tail call operations") | |
| .addFeature(FeatureSet::ReferenceTypes, "reference types") | |
| .addFeature(FeatureSet::Multivalue, "multivalue functions") | |
| .addFeature(FeatureSet::GC, "garbage collection") | |
| .addFeature(FeatureSet::Memory64, "memory64") | |
| .addFeature(FeatureSet::RelaxedSIMD, "relaxed SIMD") | |
| .addFeature(FeatureSet::ExtendedConst, "extended const expressions") | |
| .addFeature(FeatureSet::Strings, "strings") | |
| .addFeature(FeatureSet::MultiMemory, "multimemory") | |
| .addFeature(FeatureSet::StackSwitching, "stack switching") | |
| .addFeature(FeatureSet::SharedEverything, "shared-everything threads") | |
| .addFeature(FeatureSet::FP16, "float 16 operations") | |
| .addFeature(FeatureSet::CustomDescriptors, | |
| "custom descriptors (RTTs) and exact references") | |
| .addFeature(FeatureSet::Multibyte, "multibyte array loads and stores") | |
| .addFeature(FeatureSet::RelaxedAtomics, | |
| "acquire/release atomic memory operations") | |
| .addFeature(FeatureSet::CustomPageSizes, "custom page sizes") | |
| .addFeature(FeatureSet::WideArithmetic, "wide arithmetic") | |
| .addFeature(FeatureSet::CompactImports, "compact import section") | |
| .add("--enable-typed-function-references", | |
| "", | |
| "Deprecated compatibility flag", | |
| ToolOptionsCategory, | |
| Options::Arguments::Zero, | |
| [](Options* o, const std::string& argument) { | |
| std::cerr | |
| << "Warning: Typed function references have been made part of " | |
| "GC and --enable-typed-function-references is deprecated\n"; | |
| }) | |
| .add("--disable-typed-function-references", | |
| "", | |
| "Deprecated compatibility flag", | |
| ToolOptionsCategory, | |
| Options::Arguments::Zero, | |
| [](Options* o, const std::string& argument) { | |
| std::cerr | |
| << "Warning: Typed function references have been made part of " | |
| "GC and --disable-typed-function-references is deprecated\n"; | |
| }) | |
| .add("--no-validation", | |
| "-n", | |
| "Disables validation, assumes inputs are correct", | |
| ToolOptionsCategory, | |
| Options::Arguments::Zero, | |
| [this](Options* o, const std::string& argument) { | |
| passOptions.validate = false; | |
| }) | |
| .add("--pass-arg", | |
| "-pa", | |
| "An argument passed along to optimization passes being run. Must be " | |
| "in the form KEY@VALUE. If KEY is the name of a pass then it " | |
| "applies to the closest instance of that pass before us. If KEY is " | |
| "not the name of a pass then it is a global option that applies to " | |
| "all pass instances that read it.", | |
| ToolOptionsCategory, | |
| Options::Arguments::N, | |
| [this](Options*, const std::string& argument) { | |
| std::string key, value; | |
| auto colon = argument.find('@'); | |
| if (colon == std::string::npos) { | |
| key = argument; | |
| value = "1"; | |
| } else { | |
| key = argument.substr(0, colon); | |
| value = argument.substr(colon + 1); | |
| } | |
| addPassArg(key, value); | |
| }) | |
| .add( | |
| "--closed-world", | |
| "-cw", | |
| "Assume code outside of the module does not inspect or interact with " | |
| "GC and function references, even if they are passed out. The outside " | |
| "may hold on to them and pass them back in, but not inspect their " | |
| "contents or call them.", | |
| ToolOptionsCategory, | |
| Options::Arguments::Zero, | |
| [this](Options*, const std::string&) { | |
| passOptions.worldMode = WorldMode::Closed; | |
| }) | |
| .add( | |
| "--preserve-type-order", | |
| "", | |
| "Preserve the order of types from the input (useful for debugging and " | |
| "testing)", | |
| ToolOptionsCategory, | |
| Options::Arguments::Zero, | |
| [&](Options* o, const std::string& arguments) { | |
| preserveTypeOrder = true; | |
| }) | |
| .add("--generate-stack-ir", | |
| "", | |
| "generate StackIR during writing", | |
| ToolOptionsCategory, | |
| Options::Arguments::Zero, | |
| [&](Options* o, const std::string& arguments) { | |
| passOptions.generateStackIR = true; | |
| }) | |
| .add("--optimize-stack-ir", | |
| "", | |
| "optimize StackIR during writing", | |
| ToolOptionsCategory, | |
| Options::Arguments::Zero, | |
| [&](Options* o, const std::string& arguments) { | |
| // Also generate StackIR, to have something to optimize. | |
| passOptions.generateStackIR = true; | |
| passOptions.optimizeStackIR = true; | |
| }) | |
| .add("--print-stack-ir", | |
| "", | |
| "print StackIR during writing", | |
| ToolOptionsCategory, | |
| Options::Arguments::Zero, | |
| [&](Options* o, const std::string& arguments) { | |
| // Also generate StackIR, to have something to print. | |
| passOptions.generateStackIR = true; | |
| passOptions.printStackIR = &std::cout; | |
| }); | |
| } | |
| ToolOptions& addFeature(FeatureSet::Feature feature, | |
| const std::string& description, | |
| FeatureSet impliedEnable = FeatureSet::None, | |
| FeatureSet impliedDisable = FeatureSet::None) { | |
| (*this) | |
| .add(std::string("--enable-") + FeatureSet::toString(feature), | |
| "", | |
| std::string("Enable ") + description, | |
| ToolOptionsCategory, | |
| Arguments::Zero, | |
| [this, feature, impliedEnable](Options*, const std::string&) { | |
| enabledFeatures.set(feature | impliedEnable, true); | |
| disabledFeatures.set(feature | impliedEnable, false); | |
| }) | |
| .add(std::string("--disable-") + FeatureSet::toString(feature), | |
| "", | |
| std::string("Disable ") + description, | |
| ToolOptionsCategory, | |
| Arguments::Zero, | |
| [this, feature, impliedDisable](Options*, const std::string&) { | |
| enabledFeatures.set(feature | impliedDisable, false); | |
| disabledFeatures.set(feature | impliedDisable, true); | |
| }); | |
| return *this; | |
| } | |
| void applyOptionsBeforeParse(Module& module) const { | |
| module.features.enable(enabledFeatures); | |
| module.features.disable(disabledFeatures); | |
| } | |
| void applyOptionsAfterParse(Module& module) const { | |
| if (!preserveTypeOrder) { | |
| module.typeIndices.clear(); | |
| } | |
| } | |
| void write(ModuleWriter& writer, Module& wasm, Output& output) const { | |
| writer.setEmitModuleName(emitModuleNames); | |
| writer.write(wasm, output); | |
| } | |
| void | |
| write(ModuleWriter& writer, Module& wasm, const std::string& filename) const { | |
| writer.setEmitModuleName(emitModuleNames); | |
| writer.write(wasm, filename); | |
| } | |
| virtual void addPassArg(const std::string& key, const std::string& value) { | |
| passOptions.arguments[key] = value; | |
| } | |
| virtual ~ToolOptions() = default; | |
| private: | |
| FeatureSet enabledFeatures = FeatureSet::Default; | |
| FeatureSet disabledFeatures = FeatureSet::None; | |
| }; | |
| } // namespace wasm | |
| #endif |