summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/generate-names.cc2
-rw-r--r--src/tools/wasm2wast.cc10
-rw-r--r--src/tools/wast-desugar.cc10
-rw-r--r--src/wat-writer.cc322
-rw-r--r--src/wat-writer.h6
-rw-r--r--test/help/wasm-wast.txt1
-rw-r--r--test/roundtrip/fold-basic.txt70
-rw-r--r--test/roundtrip/fold-block.txt105
-rw-r--r--test/roundtrip/fold-call.txt69
-rw-r--r--test/roundtrip/fold-fac.txt60
-rw-r--r--test/roundtrip/fold-getset-global.txt41
-rw-r--r--test/roundtrip/fold-getset-local.txt66
-rw-r--r--test/roundtrip/fold-load-store.txt59
-rw-r--r--test/roundtrip/fold-nop.txt17
-rw-r--r--test/roundtrip/fold-unreachable.txt54
-rw-r--r--test/roundtrip/generate-if-label-names.txt10
-rwxr-xr-xtest/run-roundtrip.py2
-rwxr-xr-xtest/run-tests.py13
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)