diff options
-rw-r--r-- | src/generate-names.cc | 2 | ||||
-rw-r--r-- | src/tools/wasm2wast.cc | 10 | ||||
-rw-r--r-- | src/tools/wast-desugar.cc | 10 | ||||
-rw-r--r-- | src/wat-writer.cc | 322 | ||||
-rw-r--r-- | src/wat-writer.h | 6 | ||||
-rw-r--r-- | test/help/wasm-wast.txt | 1 | ||||
-rw-r--r-- | test/roundtrip/fold-basic.txt | 70 | ||||
-rw-r--r-- | test/roundtrip/fold-block.txt | 105 | ||||
-rw-r--r-- | test/roundtrip/fold-call.txt | 69 | ||||
-rw-r--r-- | test/roundtrip/fold-fac.txt | 60 | ||||
-rw-r--r-- | test/roundtrip/fold-getset-global.txt | 41 | ||||
-rw-r--r-- | test/roundtrip/fold-getset-local.txt | 66 | ||||
-rw-r--r-- | test/roundtrip/fold-load-store.txt | 59 | ||||
-rw-r--r-- | test/roundtrip/fold-nop.txt | 17 | ||||
-rw-r--r-- | test/roundtrip/fold-unreachable.txt | 54 | ||||
-rw-r--r-- | test/roundtrip/generate-if-label-names.txt | 10 | ||||
-rwxr-xr-x | test/run-roundtrip.py | 2 | ||||
-rwxr-xr-x | test/run-tests.py | 13 |
18 files changed, 875 insertions, 42 deletions
diff --git a/src/generate-names.cc b/src/generate-names.cc index 769c4fe3..7358893e 100644 --- a/src/generate-names.cc +++ b/src/generate-names.cc @@ -112,7 +112,7 @@ static Result begin_loop_expr(Expr* expr, void* user_data) { static Result begin_if_expr(Expr* expr, void* user_data) { Context* ctx = static_cast<Context*>(user_data); - maybe_generate_name("$L", ctx->label_count++, &expr->if_.true_->label); + maybe_generate_name("$I", ctx->label_count++, &expr->if_.true_->label); return Result::Ok; } diff --git a/src/tools/wasm2wast.cc b/src/tools/wasm2wast.cc index 94dd3fa8..9cf46072 100644 --- a/src/tools/wasm2wast.cc +++ b/src/tools/wasm2wast.cc @@ -38,6 +38,7 @@ static int s_verbose; static const char* s_infile; static const char* s_outfile; static ReadBinaryOptions s_read_binary_options = {nullptr, true}; +static WriteWatOptions s_write_wat_options; static bool s_generate_names; static std::unique_ptr<FileStream> s_log_stream; @@ -50,6 +51,7 @@ enum { FLAG_OUTPUT, FLAG_NO_DEBUG_NAMES, FLAG_GENERATE_NAMES, + FLAG_FOLD_EXPRS, NUM_FLAGS }; @@ -70,6 +72,8 @@ static Option s_options[] = { {FLAG_HELP, 'h', "help", nullptr, NOPE, "print this help message"}, {FLAG_OUTPUT, 'o', "output", "FILENAME", YEP, "output file for the generated wast file, by default use stdout"}, + {FLAG_FOLD_EXPRS, 'f', "fold-exprs", nullptr, NOPE, + "Write folded expressions where possible"}, {FLAG_NO_DEBUG_NAMES, 0, "no-debug-names", nullptr, NOPE, "Ignore debug names in the binary file"}, {FLAG_GENERATE_NAMES, 0, "generate-names", nullptr, NOPE, @@ -96,6 +100,10 @@ static void on_option(struct OptionParser* parser, s_outfile = argument; break; + case FLAG_FOLD_EXPRS: + s_write_wat_options.fold_exprs = true; + break; + case FLAG_NO_DEBUG_NAMES: s_read_binary_options.read_debug_names = false; break; @@ -159,7 +167,7 @@ int ProgramMain(int argc, char** argv) { if (WABT_SUCCEEDED(result)) { FileWriter writer(s_outfile ? FileWriter(s_outfile) : FileWriter(stdout)); - result = write_wat(&writer, &module); + result = write_wat(&writer, &module, &s_write_wat_options); } } delete[] data; diff --git a/src/tools/wast-desugar.cc b/src/tools/wast-desugar.cc index b1418e6c..a22bdc05 100644 --- a/src/tools/wast-desugar.cc +++ b/src/tools/wast-desugar.cc @@ -38,11 +38,13 @@ using namespace wabt; static const char* s_infile; static const char* s_outfile; +static WriteWatOptions s_write_wat_options; static bool s_generate_names; enum { FLAG_HELP, FLAG_OUTPUT, + FLAG_FOLD_EXPRS, FLAG_GENERATE_NAMES, NUM_FLAGS }; @@ -65,6 +67,8 @@ static Option s_options[] = { "print this help message"}, {FLAG_OUTPUT, 'o', "output", "FILE", HasArgument::Yes, "output file for the formatted file"}, + {FLAG_FOLD_EXPRS, 'f', "fold-exprs", nullptr, HasArgument::No, + "Write folded expressions where possible"}, {FLAG_GENERATE_NAMES, 0, "generate-names", nullptr, HasArgument::No, "Give auto-generated names to non-named functions, types, etc."}, }; @@ -83,6 +87,10 @@ static void on_option(struct OptionParser* parser, s_outfile = argument; break; + case FLAG_FOLD_EXPRS: + s_write_wat_options.fold_exprs = true; + break; + case FLAG_GENERATE_NAMES: s_generate_names = true; break; @@ -149,7 +157,7 @@ int ProgramMain(int argc, char** argv) { if (WABT_SUCCEEDED(result)) { FileWriter writer(s_outfile ? FileWriter(s_outfile) : FileWriter(stdout)); - result = write_wat(&writer, module); + result = write_wat(&writer, module, &s_write_wat_options); } } diff --git a/src/wat-writer.cc b/src/wat-writer.cc index 9e2e40bb..d8a16934 100644 --- a/src/wat-writer.cc +++ b/src/wat-writer.cc @@ -16,10 +16,12 @@ #include "wat-writer.h" +#include <algorithm> #include <cassert> #include <cinttypes> #include <cstdarg> #include <cstdio> +#include <iterator> #include <string> #include <vector> @@ -57,9 +59,26 @@ enum class NextChar { ForceNewline, }; +struct ExprTree { + explicit ExprTree(const Expr* expr) : expr(expr) {} + + const Expr* expr; + std::vector<ExprTree> children; +}; + +struct Label { + Label(LabelType label_type, StringSlice name, const BlockSignature& sig) + : name(name), label_type(label_type), sig(sig) {} + + StringSlice name; + LabelType label_type; + const BlockSignature& sig; // Share with Expr. +}; + class WatWriter { public: - WatWriter(Writer* writer) : stream_(writer) {} + WatWriter(Writer* writer, const WriteWatOptions* options) + : options_(options), stream_(writer) {} Result WriteModule(const Module* module); @@ -95,9 +114,13 @@ class WatWriter { void WriteType(Type type, NextChar next_char); void WriteTypes(const TypeVector& types, const char* name); void WriteFuncSigSpace(const FuncSignature* func_sig); - void WriteBeginBlock(const Block* block, const char* text); + void WriteBeginBlock(LabelType label_type, + const Block* block, + const char* text); void WriteEndBlock(); - void WriteBlock(const Block* block, const char* start_text); + void WriteBlock(LabelType label_type, + const Block* block, + const char* start_text); void WriteConst(const Const* const_); void WriteExpr(const Expr* expr); void WriteExprList(const Expr* first); @@ -119,12 +142,30 @@ class WatWriter { void WriteFuncType(const FuncType* func_type); void WriteStartFunction(const Var* start); + Index GetLabelStackSize() { return label_stack_.size(); } + Label* GetLabel(const Var* var); + Index GetLabelArity(const Var* var); + Index GetFuncParamCount(const Var* var); + Index GetFuncResultCount(const Var* var); + Index GetFuncSigParamCount(const Var* var); + Index GetFuncSigResultCount(const Var* var); + void PushExpr(const Expr* expr, Index operand_count, Index result_count); + void FlushExprTree(const ExprTree& expr_tree); + void FlushExprTreeVector(const std::vector<ExprTree>&); + void FlushExprTreeStack(); + void WriteFoldedExpr(const Expr* first); + void WriteFoldedExprList(const Expr* first); + + const WriteWatOptions* options_ = nullptr; + const Module* module_ = nullptr; + const Func* current_func_ = nullptr; Stream stream_; Result result_ = Result::Ok; int indent_ = 0; NextChar next_char_ = NextChar::None; - Index depth_ = 0; std::vector<std::string> index_to_name_; + std::vector<Label> label_stack_; + std::vector<ExprTree> expr_tree_stack_; Index func_index_ = 0; Index global_index_ = 0; @@ -133,8 +174,6 @@ class WatWriter { Index func_type_index_ = 0; }; -} // namespace - void WatWriter::Indent() { indent_ += INDENT_SIZE; } @@ -309,9 +348,9 @@ void WatWriter::WriteVar(const Var* var, NextChar next_char) { void WatWriter::WriteBrVar(const Var* var, NextChar next_char) { if (var->type == VarType::Index) { - assert(var->index < depth_); + assert(var->index < GetLabelStackSize()); Writef("%" PRIindex " (;@%" PRIindex ";)", var->index, - depth_ - var->index - 1); + GetLabelStackSize() - var->index - 1); next_char_ = next_char; } else { WriteStringSlice(&var->name, next_char); @@ -328,7 +367,7 @@ void WatWriter::WriteTypes(const TypeVector& types, const char* name) { if (types.size()) { if (name) WriteOpenSpace(name); - for (Type type: types) + for (Type type : types) WriteType(type, NextChar::Space); if (name) WriteCloseSpace(); @@ -340,25 +379,29 @@ void WatWriter::WriteFuncSigSpace(const FuncSignature* func_sig) { WriteTypes(func_sig->result_types, "result"); } -void WatWriter::WriteBeginBlock(const Block* block, const char* text) { +void WatWriter::WriteBeginBlock(LabelType label_type, + const Block* block, + const char* text) { WritePutsSpace(text); bool has_label = WriteStringSliceOpt(&block->label, NextChar::Space); WriteTypes(block->sig, nullptr); if (!has_label) - Writef(" ;; label = @%" PRIindex, depth_); + Writef(" ;; label = @%" PRIindex, GetLabelStackSize()); WriteNewline(FORCE_NEWLINE); - depth_++; + label_stack_.emplace_back(label_type, block->label, block->sig); Indent(); } void WatWriter::WriteEndBlock() { Dedent(); - depth_--; + label_stack_.pop_back(); WritePutsNewline(get_opcode_name(Opcode::End)); } -void WatWriter::WriteBlock(const Block* block, const char* start_text) { - WriteBeginBlock(block, start_text); +void WatWriter::WriteBlock(LabelType label_type, + const Block* block, + const char* start_text) { + WriteBeginBlock(label_type, block, start_text); WriteExprList(block->first); WriteEndBlock(); } @@ -414,7 +457,7 @@ void WatWriter::WriteExpr(const Expr* expr) { break; case ExprType::Block: - WriteBlock(expr->block, get_opcode_name(Opcode::Block)); + WriteBlock(LabelType::Block, expr->block, get_opcode_name(Opcode::Block)); break; case ExprType::Br: @@ -476,7 +519,8 @@ void WatWriter::WriteExpr(const Expr* expr) { break; case ExprType::If: - WriteBeginBlock(expr->if_.true_, get_opcode_name(Opcode::If)); + WriteBeginBlock(LabelType::If, expr->if_.true_, + get_opcode_name(Opcode::If)); WriteExprList(expr->if_.true_->first); if (expr->if_.false_) { Dedent(); @@ -498,7 +542,7 @@ void WatWriter::WriteExpr(const Expr* expr) { break; case ExprType::Loop: - WriteBlock(expr->loop, get_opcode_name(Opcode::Loop)); + WriteBlock(LabelType::Loop, expr->loop, get_opcode_name(Opcode::Loop)); break; case ExprType::CurrentMemory: @@ -561,6 +605,214 @@ void WatWriter::WriteExprList(const Expr* first) { WriteExpr(expr); } +Label* WatWriter::GetLabel(const Var* var) { + if (var->type == VarType::Name) { + for (Index i = GetLabelStackSize(); i > 0; --i) { + Label* label = &label_stack_[i - 1]; + if (string_slices_are_equal(&label->name, &var->name)) + return label; + } + } else if (var->index < GetLabelStackSize()) { + Label* label = &label_stack_[GetLabelStackSize() - var->index - 1]; + return label; + } + return nullptr; +} + + +Index WatWriter::GetLabelArity(const Var* var) { + Label* label = GetLabel(var); + return label && label->label_type != LabelType::Loop ? label->sig.size() : 0; +} + +Index WatWriter::GetFuncParamCount(const Var* var) { + Func* func = get_func_by_var(module_, var); + return func ? get_num_params(func) : 0; +} + +Index WatWriter::GetFuncResultCount(const Var* var) { + Func* func = get_func_by_var(module_, var); + return func ? get_num_results(func) : 0; +} + +Index WatWriter::GetFuncSigParamCount(const Var* var) { + FuncType* func_type = get_func_type_by_var(module_, var); + return func_type ? get_func_type_num_params(func_type) : 0; +} + +Index WatWriter::GetFuncSigResultCount(const Var* var) { + FuncType* func_type = get_func_type_by_var(module_, var); + return func_type ? get_func_type_num_results(func_type) : 0; +} + +void WatWriter::WriteFoldedExpr(const Expr* expr) { + switch (expr->type) { + case ExprType::Binary: + case ExprType::Compare: + case ExprType::Store: + PushExpr(expr, 2, 1); + break; + + case ExprType::Block: + PushExpr(expr, 0, expr->block->sig.size()); + break; + + case ExprType::Br: + PushExpr(expr, GetLabelArity(&expr->br.var), 1); + break; + + case ExprType::BrIf: { + Index arity = GetLabelArity(&expr->br_if.var); + PushExpr(expr, arity + 1, arity); + break; + } + + case ExprType::BrTable: + PushExpr(expr, GetLabelArity(&expr->br_table.default_target) + 1, 1); + break; + + case ExprType::Call: + PushExpr(expr, GetFuncParamCount(&expr->call.var), + GetFuncResultCount(&expr->call.var)); + break; + + case ExprType::CallIndirect: + PushExpr(expr, GetFuncSigParamCount(&expr->call_indirect.var) + 1, + GetFuncSigResultCount(&expr->call_indirect.var)); + break; + + case ExprType::Const: + case ExprType::CurrentMemory: + case ExprType::GetGlobal: + case ExprType::GetLocal: + case ExprType::Unreachable: + PushExpr(expr, 0, 1); + break; + + case ExprType::Convert: + case ExprType::GrowMemory: + case ExprType::Load: + case ExprType::TeeLocal: + case ExprType::Unary: + PushExpr(expr, 1, 1); + break; + + case ExprType::Drop: + case ExprType::SetGlobal: + case ExprType::SetLocal: + PushExpr(expr, 1, 0); + break; + + case ExprType::If: + PushExpr(expr, 1, expr->if_.true_->sig.size()); + break; + + case ExprType::Loop: + PushExpr(expr, 0, expr->loop->sig.size()); + break; + + case ExprType::Nop: + PushExpr(expr, 0, 0); + break; + + case ExprType::Return: + PushExpr(expr, current_func_->decl.sig.result_types.size(), 1); + break; + + case ExprType::Select: + PushExpr(expr, 3, 1); + break; + + default: + fprintf(stderr, "bad expr type: %d\n", static_cast<int>(expr->type)); + assert(0); + break; + } +} + +void WatWriter::WriteFoldedExprList(const Expr* first) { + for (const Expr* expr = first; expr; expr = expr->next) + WriteFoldedExpr(expr); +} + +void WatWriter::PushExpr(const Expr* expr, + Index operand_count, + Index result_count) { + if (operand_count <= expr_tree_stack_.size()) { + auto last_operand = expr_tree_stack_.end(); + auto first_operand = last_operand - operand_count; + ExprTree tree(expr); + std::move(first_operand, last_operand, std::back_inserter(tree.children)); + expr_tree_stack_.erase(first_operand, last_operand); + expr_tree_stack_.push_back(std::move(tree)); + if (result_count == 0) + FlushExprTreeStack(); + } else { + expr_tree_stack_.emplace_back(expr); + FlushExprTreeStack(); + } +} + +void WatWriter::FlushExprTree(const ExprTree& expr_tree) { + switch (expr_tree.expr->type) { + case ExprType::Block: + WritePuts("(", NextChar::None); + WriteBeginBlock(LabelType::Block, expr_tree.expr->block, + get_opcode_name(Opcode::Block)); + WriteFoldedExprList(expr_tree.expr->block->first); + FlushExprTreeStack(); + WriteCloseNewline(); + break; + + case ExprType::Loop: + WritePuts("(", NextChar::None); + WriteBeginBlock(LabelType::Loop, expr_tree.expr->loop, + get_opcode_name(Opcode::Loop)); + WriteFoldedExprList(expr_tree.expr->loop->first); + FlushExprTreeStack(); + WriteCloseNewline(); + break; + + case ExprType::If: + WritePuts("(", NextChar::None); + WriteBeginBlock(LabelType::If, expr_tree.expr->if_.true_, + get_opcode_name(Opcode::If)); + FlushExprTreeVector(expr_tree.children); + WriteOpenNewline("then"); + WriteFoldedExprList(expr_tree.expr->if_.true_->first); + FlushExprTreeStack(); + WriteCloseNewline(); + if (expr_tree.expr->if_.false_) { + WriteOpenNewline("else"); + WriteFoldedExprList(expr_tree.expr->if_.false_); + FlushExprTreeStack(); + WriteCloseNewline(); + } + WriteCloseNewline(); + break; + + default: { + WritePuts("(", NextChar::None); + WriteExpr(expr_tree.expr); + Indent(); + FlushExprTreeVector(expr_tree.children); + WriteCloseNewline(); + break; + } + } +} + +void WatWriter::FlushExprTreeVector(const std::vector<ExprTree>& expr_trees) { + for (auto expr_tree : expr_trees) + FlushExprTree(expr_tree); +} + +void WatWriter::FlushExprTreeStack() { + std::vector<ExprTree> stack_copy(std::move(expr_tree_stack_)); + expr_tree_stack_.clear(); + FlushExprTreeVector(stack_copy); +} + void WatWriter::WriteInitExpr(const Expr* expr) { if (expr) { WritePuts("(", NextChar::None); @@ -618,15 +870,23 @@ void WatWriter::WriteFunc(const Module* module, const Func* func) { WriteTypeBindings("local", func, func->local_types, func->local_bindings); } WriteNewline(NO_FORCE_NEWLINE); - depth_ = 1; /* for the implicit "return" label */ - WriteExprList(func->first_expr); + label_stack_.clear(); + label_stack_.emplace_back(LabelType::Func, empty_string_slice(), + func->decl.sig.result_types); + current_func_ = func; + if (options_->fold_exprs) { + WriteFoldedExprList(func->first_expr); + FlushExprTreeStack(); + } else { + WriteExprList(func->first_expr); + } + current_func_ = nullptr; WriteCloseNewline(); } void WatWriter::WriteBeginGlobal(const Global* global) { WriteOpenSpace("global"); - WriteNameOrIndex(&global->name, global_index_++, - NextChar::Space); + WriteNameOrIndex(&global->name, global_index_++, NextChar::Space); if (global->mutable_) { WriteOpenSpace("mut"); WriteType(global->type, NextChar::Space); @@ -650,8 +910,7 @@ void WatWriter::WriteLimits(const Limits* limits) { void WatWriter::WriteTable(const Table* table) { WriteOpenSpace("table"); - WriteNameOrIndex(&table->name, table_index_++, - NextChar::Space); + WriteNameOrIndex(&table->name, table_index_++, NextChar::Space); WriteLimits(&table->elem_limits); WritePutsSpace("anyfunc"); WriteCloseNewline(); @@ -667,8 +926,7 @@ void WatWriter::WriteElemSegment(const ElemSegment* segment) { void WatWriter::WriteMemory(const Memory* memory) { WriteOpenSpace("memory"); - WriteNameOrIndex(&memory->name, memory_index_++, - NextChar::Space); + WriteNameOrIndex(&memory->name, memory_index_++, NextChar::Space); WriteLimits(&memory->page_limits); WriteCloseNewline(); } @@ -687,8 +945,7 @@ void WatWriter::WriteImport(const Import* import) { switch (import->kind) { case ExternalKind::Func: WriteOpenSpace("func"); - WriteNameOrIndex(&import->func->name, func_index_++, - NextChar::Space); + WriteNameOrIndex(&import->func->name, func_index_++, NextChar::Space); if (decl_has_func_type(&import->func->decl)) { WriteOpenSpace("type"); WriteVar(&import->func->decl.type_var, NextChar::None); @@ -743,6 +1000,7 @@ void WatWriter::WriteStartFunction(const Var* start) { } Result WatWriter::WriteModule(const Module* module) { + module_ = module; WriteOpenNewline("module"); for (const ModuleField* field = module->first_field; field; field = field->next) { @@ -785,8 +1043,12 @@ Result WatWriter::WriteModule(const Module* module) { return result_; } -Result write_wat(Writer* writer, const Module* module) { - WatWriter wat_writer(writer); +} // namespace + +Result write_wat(Writer* writer, + const Module* module, + const WriteWatOptions* options) { + WatWriter wat_writer(writer, options); return wat_writer.WriteModule(module); } diff --git a/src/wat-writer.h b/src/wat-writer.h index 840b77e7..85f85458 100644 --- a/src/wat-writer.h +++ b/src/wat-writer.h @@ -24,7 +24,11 @@ namespace wabt { struct Module; class Writer; -Result write_wat(Writer*, const Module*); +struct WriteWatOptions { + bool fold_exprs = false; // Write folded expressions. +}; + +Result write_wat(Writer*, const Module*, const WriteWatOptions*); } // namespace wabt diff --git a/test/help/wasm-wast.txt b/test/help/wasm-wast.txt index 1da862da..21a8c994 100644 --- a/test/help/wasm-wast.txt +++ b/test/help/wasm-wast.txt @@ -17,6 +17,7 @@ options: -v, --verbose use multiple times for more info -h, --help print this help message -o, --output=FILENAME output file for the generated wast file, by default use stdout + -f, --fold-exprs Write folded expressions where possible --no-debug-names Ignore debug names in the binary file --generate-names Give auto-generated names to non-named functions, types, etc. ;;; STDOUT ;;) diff --git a/test/roundtrip/fold-basic.txt b/test/roundtrip/fold-basic.txt new file mode 100644 index 00000000..f0f0bff3 --- /dev/null +++ b/test/roundtrip/fold-basic.txt @@ -0,0 +1,70 @@ +;;; TOOL: run-roundtrip +;;; FLAGS: --stdout --fold-exprs +(module + (func $fold-binary (result i32) + i32.const 1 + i32.const 2 + i32.add) + + (func $fold-binary-chain (result i32) + i32.const 1 + i32.const 1 + i32.const 1 + i32.add + i32.sub) + + (func $fold-compare (result i32) + f32.const 1 + f32.const 2 + f32.le) + + (func $fold-unary (result f32) + f32.const 1 + f32.neg + f32.neg) + + (func $fold-convert (result i64) + f64.const 0 + f32.demote/f64 + i32.trunc_s/f32 + i64.extend_s/i32) + + (func $fold-select (result f32) + f32.const 1 + f32.const 2 + i32.const 3 + select)) +(;; STDOUT ;;; +(module + (type (;0;) (func (result i32))) + (type (;1;) (func (result f32))) + (type (;2;) (func (result i64))) + (func (;0;) (type 0) (result i32) + (i32.add + (i32.const 1) + (i32.const 2))) + (func (;1;) (type 0) (result i32) + (i32.sub + (i32.const 1) + (i32.add + (i32.const 1) + (i32.const 1)))) + (func (;2;) (type 0) (result i32) + (f32.le + (f32.const 0x1p+0 (;=1;)) + (f32.const 0x1p+1 (;=2;)))) + (func (;3;) (type 1) (result f32) + (f32.neg + (f32.neg + (f32.const 0x1p+0 (;=1;))))) + (func (;4;) (type 2) (result i64) + (i64.extend_s/i32 + (i32.trunc_s/f32 + (f32.demote/f64 + (f64.const 0x0p+0 (;=0;)))))) + (func (;5;) (type 1) (result f32) + (select + (f32.const 0x1p+0 (;=1;)) + (f32.const 0x1p+1 (;=2;)) + (i32.const 3)))) +;;; STDOUT ;;) diff --git a/test/roundtrip/fold-block.txt b/test/roundtrip/fold-block.txt new file mode 100644 index 00000000..a2f84d08 --- /dev/null +++ b/test/roundtrip/fold-block.txt @@ -0,0 +1,105 @@ +;;; TOOL: run-roundtrip +;;; FLAGS: --stdout --fold-exprs --debug-names +(module + (func $fold-block (result f32) + f32.const 2 + block + f32.const 3 + br 0 + end + f32.const 1 + f32.add) + + (func $fold-block-br-value (result i32) + block i32 + i32.const 1 + br 0 + end) + + (func $fold-loop + loop i64 + br 0 + i64.const 1 + end + drop) + + (func $fold-loop-br (result i32) + loop i32 + i32.const 1 + br 0 + end) + + (func $fold-if + i32.const 1 + if + nop + nop + end) + + (func $fold-if-else + i32.const 1 + if i32 + i32.const 2 + else + i32.const 3 + end + drop) + + (func $fold-if-else-br + i32.const 1 + if i32 + i32.const 2 + br 0 + else + i32.const 3 + end + drop)) +(;; STDOUT ;;; +(module + (type (;0;) (func (result f32))) + (type (;1;) (func (result i32))) + (type (;2;) (func)) + (func $fold-block (type 0) (result f32) + (f32.const 0x1p+1 (;=2;)) + (block ;; label = @1 + (f32.const 0x1.8p+1 (;=3;)) + (br 0 (;@1;))) + (f32.const 0x1p+0 (;=1;)) + (f32.add)) + (func $fold-block-br-value (type 1) (result i32) + (block i32 ;; label = @1 + (br 0 (;@1;) + (i32.const 1)))) + (func $fold-loop (type 2) + (drop + (loop i64 ;; label = @1 + (br 0 (;@1;)) + (i64.const 1)))) + (func $fold-loop-br (type 1) (result i32) + (loop i32 ;; label = @1 + (i32.const 1) + (br 0 (;@1;)))) + (func $fold-if (type 2) + (if ;; label = @1 + (i32.const 1) + (then + (nop) + (nop)))) + (func $fold-if-else (type 2) + (drop + (if i32 ;; label = @1 + (i32.const 1) + (then + (i32.const 2)) + (else + (i32.const 3))))) + (func $fold-if-else-br (type 2) + (drop + (if i32 ;; label = @1 + (i32.const 1) + (then + (br 0 (;@1;) + (i32.const 2))) + (else + (i32.const 3)))))) +;;; STDOUT ;;) diff --git a/test/roundtrip/fold-call.txt b/test/roundtrip/fold-call.txt new file mode 100644 index 00000000..73c72cc0 --- /dev/null +++ b/test/roundtrip/fold-call.txt @@ -0,0 +1,69 @@ +;;; TOOL: run-roundtrip +;;; FLAGS: --stdout --fold-exprs +(module + (type $i_i (func (param i32) (result i32))) + + (func $i_i (type $i_i) + i32.const 1) + + (func $if_f (param i32 f32) (result f32) + f32.const 0) + + (func $ffff_v (param f32 f32 f32 f32)) + + (func $fold-call (result i32) + i32.const 1 + call $i_i + drop + i32.const 2 + call $i_i) + + (func $fold-call-2 + f32.const 0 + f32.const 1 + f32.const 2 + i32.const 3 + f32.const 4 + call $if_f + call $ffff_v) + + (table anyfunc (elem $i_i $if_f)) + (func $fold-call-indirect (result i32) + i32.const 1 + i32.const 2 + call_indirect $i_i) +) + +(;; STDOUT ;;; +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (param i32 f32) (result f32))) + (type (;2;) (func (param f32 f32 f32 f32))) + (type (;3;) (func (result i32))) + (type (;4;) (func)) + (func (;0;) (type 0) (param i32) (result i32) + (i32.const 1)) + (func (;1;) (type 1) (param i32 f32) (result f32) + (f32.const 0x0p+0 (;=0;))) + (func (;2;) (type 2) (param f32 f32 f32 f32)) + (func (;3;) (type 3) (result i32) + (drop + (call 0 + (i32.const 1))) + (call 0 + (i32.const 2))) + (func (;4;) (type 4) + (call 2 + (f32.const 0x0p+0 (;=0;)) + (f32.const 0x1p+0 (;=1;)) + (f32.const 0x1p+1 (;=2;)) + (call 1 + (i32.const 3) + (f32.const 0x1p+2 (;=4;))))) + (func (;5;) (type 3) (result i32) + (call_indirect 0 + (i32.const 1) + (i32.const 2))) + (table (;0;) 2 2 anyfunc) + (elem (i32.const 0) 0 1)) +;;; STDOUT ;;) diff --git a/test/roundtrip/fold-fac.txt b/test/roundtrip/fold-fac.txt new file mode 100644 index 00000000..a41f822b --- /dev/null +++ b/test/roundtrip/fold-fac.txt @@ -0,0 +1,60 @@ +;;; TOOL: run-roundtrip +;;; FLAGS: --stdout --fold-exprs --debug-names --generate-names +(module + (func $fac-stack-raw (param $n i64) (result i64) + (local $i i64) + (local $res i64) + get_local $n + set_local $i + i64.const 1 + set_local $res + block $done + loop $loop + get_local $i + i64.const 0 + i64.eq + if $body + br $done + else $body + get_local $i + get_local $res + i64.mul + set_local $res + get_local $i + i64.const 1 + i64.sub + set_local $i + end $body + br $loop + end $loop + end $done + get_local $res)) +(;; STDOUT ;;; +(module + (type $t0 (func (param i64) (result i64))) + (func $fac-stack-raw (type $t0) (param $n i64) (result i64) + (local $i i64) (local $res i64) + (set_local $i + (get_local $n)) + (set_local $res + (i64.const 1)) + (block $B0 + (loop $L1 + (if $I2 + (i64.eq + (get_local $i) + (i64.const 0)) + (then + (br $B0)) + (else + (set_local $res + (i64.mul + (get_local $i) + (get_local $res))) + (set_local $i + (i64.sub + (get_local $i) + (i64.const 1))))) + (br $L1))) + (get_local $res))) +;;; STDOUT ;;) diff --git a/test/roundtrip/fold-getset-global.txt b/test/roundtrip/fold-getset-global.txt new file mode 100644 index 00000000..c5005019 --- /dev/null +++ b/test/roundtrip/fold-getset-global.txt @@ -0,0 +1,41 @@ +;;; TOOL: run-roundtrip +;;; FLAGS: --stdout --fold-exprs +(module + (global i32 (i32.const 1)) + (global f32 (f32.const 1.5)) + + (func $fold-get-global (result i32) + get_global 1 + drop + get_global 0 + get_global 0 + i32.mul) + + (func $fold-set-global + get_global 0 + i32.const 1 + i32.add + set_global 0 + f32.const 2 + set_global 1) +) +(;; STDOUT ;;; +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + (drop + (get_global 1)) + (i32.mul + (get_global 0) + (get_global 0))) + (func (;1;) (type 1) + (set_global 0 + (i32.add + (get_global 0) + (i32.const 1))) + (set_global 1 + (f32.const 0x1p+1 (;=2;)))) + (global (;0;) i32 (i32.const 1)) + (global (;1;) f32 (f32.const 0x1.8p+0 (;=1.5;)))) +;;; STDOUT ;;) diff --git a/test/roundtrip/fold-getset-local.txt b/test/roundtrip/fold-getset-local.txt new file mode 100644 index 00000000..31230efd --- /dev/null +++ b/test/roundtrip/fold-getset-local.txt @@ -0,0 +1,66 @@ +;;; TOOL: run-roundtrip +;;; FLAGS: --stdout --fold-exprs +(module + (func $fold-get-local (result f32) + (local f32 f32 f64 f64) + get_local 0 + get_local 1 + f32.add + get_local 2 + get_local 3 + f64.add + f32.demote/f64 + f32.add) + + (func $fold-set-local + (local i64 i32) + i64.const 1 + i64.const 2 + i64.const 3 + i64.xor + i64.xor + set_local 0 + i32.const 4 + set_local 1) + + (func $fold-tee-local (result i32) + (local i32 i32) + i32.const 1 + tee_local 0 + i32.const 2 + tee_local 1 + i32.add) + ) +(;; STDOUT ;;; +(module + (type (;0;) (func (result f32))) + (type (;1;) (func)) + (type (;2;) (func (result i32))) + (func (;0;) (type 0) (result f32) + (local f32 f32 f64 f64) + (f32.add + (f32.add + (get_local 0) + (get_local 1)) + (f32.demote/f64 + (f64.add + (get_local 2) + (get_local 3))))) + (func (;1;) (type 1) + (local i64 i32) + (set_local 0 + (i64.xor + (i64.const 1) + (i64.xor + (i64.const 2) + (i64.const 3)))) + (set_local 1 + (i32.const 4))) + (func (;2;) (type 2) (result i32) + (local i32 i32) + (i32.add + (tee_local 0 + (i32.const 1)) + (tee_local 1 + (i32.const 2))))) +;;; STDOUT ;;) diff --git a/test/roundtrip/fold-load-store.txt b/test/roundtrip/fold-load-store.txt new file mode 100644 index 00000000..108dd27f --- /dev/null +++ b/test/roundtrip/fold-load-store.txt @@ -0,0 +1,59 @@ +;;; TOOL: run-roundtrip +;;; FLAGS: --stdout --fold-exprs +(module + (memory 1) + (func $fold-load + i32.const 1 + i32.load + drop + i32.const 2 + i32.load + drop) + + (func $fold-store + i32.const 1 + i32.load + f32.const 2 + f32.store) + + (func $fold-current-memory (result i32) + current_memory + i32.const 1 + i32.add + drop + i32.const 2) + + (func $fold-grow-memory (result i32) + i32.const 1 + i32.const 2 + grow_memory + i32.lt_s)) +(;; STDOUT ;;; +(module + (type (;0;) (func)) + (type (;1;) (func (result i32))) + (func (;0;) (type 0) + (drop + (i32.load + (i32.const 1))) + (drop + (i32.load + (i32.const 2)))) + (func (;1;) (type 0) + (f32.store + (i32.load + (i32.const 1)) + (f32.const 0x1p+1 (;=2;)))) + (func (;2;) (type 1) (result i32) + (drop + (i32.add + (current_memory) + (i32.const 1))) + (i32.const 2)) + (func (;3;) (type 1) (result i32) + (i32.lt_s + (i32.const 1) + (grow_memory + (i32.const 2)))) + (memory (;0;) 1)) +;;; STDOUT ;;) diff --git a/test/roundtrip/fold-nop.txt b/test/roundtrip/fold-nop.txt new file mode 100644 index 00000000..197312e2 --- /dev/null +++ b/test/roundtrip/fold-nop.txt @@ -0,0 +1,17 @@ +;;; TOOL: run-roundtrip +;;; FLAGS: --stdout --fold-exprs +(module + (func (result i32) + i32.const 1 + i32.const 2 + nop + i32.add)) +(;; STDOUT ;;; +(module + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + (i32.const 1) + (i32.const 2) + (nop) + (i32.add))) +;;; STDOUT ;;) diff --git a/test/roundtrip/fold-unreachable.txt b/test/roundtrip/fold-unreachable.txt new file mode 100644 index 00000000..51867ae4 --- /dev/null +++ b/test/roundtrip/fold-unreachable.txt @@ -0,0 +1,54 @@ +;;; TOOL: run-roundtrip +;;; FLAGS: --stdout --fold-exprs +(module + (func (result i32) + i32.const 1 + unreachable + i32.add) + + (func + br 0 + drop) + + (func + block + block + block + i32.const 1 + br_table 0 1 2 0 + i32.const 2 + i32.div_s + return + end + end + end) + + (func (result i32) + i32.const 0 + return + i32.eqz)) +(;; STDOUT ;;; +(module + (type (;0;) (func (result i32))) + (type (;1;) (func)) + (func (;0;) (type 0) (result i32) + (i32.add + (i32.const 1) + (unreachable))) + (func (;1;) (type 1) + (drop + (br 0 (;@0;)))) + (func (;2;) (type 1) + (block ;; label = @1 + (block ;; label = @2 + (block ;; label = @3 + (i32.div_s + (br_table 0 (;@3;) 1 (;@2;) 2 (;@1;) 0 (;@3;) + (i32.const 1)) + (i32.const 2)) + (return))))) + (func (;3;) (type 0) (result i32) + (i32.eqz + (return + (i32.const 0))))) +;;; STDOUT ;;) diff --git a/test/roundtrip/generate-if-label-names.txt b/test/roundtrip/generate-if-label-names.txt index 4604aa28..bfe8962c 100644 --- a/test/roundtrip/generate-if-label-names.txt +++ b/test/roundtrip/generate-if-label-names.txt @@ -18,13 +18,13 @@ (type $t0 (func)) (func $f0 (type $t0) i32.const 1 - if $L0 - br $L0 + if $I0 + br $I0 end i32.const 2 - if $L1 - br $L1 + if $I1 + br $I1 else - br $L1 + br $I1 end)) ;;; STDOUT ;;) diff --git a/test/run-roundtrip.py b/test/run-roundtrip.py index 49afecf3..66c3d4f2 100755 --- a/test/run-roundtrip.py +++ b/test/run-roundtrip.py @@ -115,6 +115,7 @@ def main(args): parser.add_argument('--no-check', action='store_true') parser.add_argument('--debug-names', action='store_true') parser.add_argument('--generate-names', action='store_true') + parser.add_argument('--fold-exprs', action='store_true') parser.add_argument('file', help='test file.') options = parser.parse_args(args) @@ -130,6 +131,7 @@ def main(args): find_exe.GetWasm2WastExecutable(options.bindir), error_cmdline=options.error_cmdline) wasm2wast.AppendOptionalArgs({ + '--fold-exprs': options.fold_exprs, '--no-debug-names': not options.debug_names, '--generate-names': options.generate_names, }) diff --git a/test/run-tests.py b/test/run-tests.py index 6359bf74..47de4fe9 100755 --- a/test/run-tests.py +++ b/test/run-tests.py @@ -228,7 +228,7 @@ class TestInfo(object): self.skip = False self.is_roundtrip = False - def CreateRoundtripInfo(self): + def CreateRoundtripInfo(self, fold_exprs): result = TestInfo() result.filename = self.filename result.header = self.header @@ -239,16 +239,22 @@ class TestInfo(object): result.tool = 'run-roundtrip' result.exe = ROUNDTRIP_PY result.flags = ['--bindir', '%(bindir)s', '-v'] + if fold_exprs: + result.flags.append('--fold-exprs') result.expected_error = 0 result.slow = self.slow result.skip = self.skip result.is_roundtrip = True + result.fold_exprs = fold_exprs return result def GetName(self): name = self.filename if self.is_roundtrip: - name += ' (roundtrip)' + if self.fold_exprs: + name += ' (roundtrip fold-exprs)' + else: + name += ' (roundtrip)' return name def GetGeneratedInputFilename(self): @@ -735,7 +741,8 @@ def main(args): infos_to_run.append(info) if options.roundtrip and info.ShouldCreateRoundtrip(): - infos_to_run.append(info.CreateRoundtripInfo()) + infos_to_run.append(info.CreateRoundtripInfo(fold_exprs=False)) + infos_to_run.append(info.CreateRoundtripInfo(fold_exprs=True)) if not os.path.exists(OUT_DIR): os.makedirs(OUT_DIR) |