summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2016-01-04 14:27:46 -0800
committerAlon Zakai <alonzakai@gmail.com>2016-01-04 14:27:56 -0800
commitc6d08d97c196e2ceae5e3b960befcd6c66916cad (patch)
tree89c27cee4f213fd66f6e60ce9b267d53a2c00b00
parent5e82fc26d6bb0cec8863156e052250a4e441595c (diff)
downloadbinaryen-c6d08d97c196e2ceae5e3b960befcd6c66916cad.tar.gz
binaryen-c6d08d97c196e2ceae5e3b960befcd6c66916cad.tar.bz2
binaryen-c6d08d97c196e2ceae5e3b960befcd6c66916cad.zip
parse for loops in asm2wasm #60
-rw-r--r--src/asm2wasm-main.cpp5
-rw-r--r--src/asm2wasm.h43
-rw-r--r--src/emscripten-optimizer/parser.h21
-rw-r--r--src/emscripten-optimizer/simple_ast.h14
-rw-r--r--test/unit.asm.js8
-rw-r--r--test/unit.fromasm30
6 files changed, 119 insertions, 2 deletions
diff --git a/src/asm2wasm-main.cpp b/src/asm2wasm-main.cpp
index 0edd82c2f..6a784bd76 100644
--- a/src/asm2wasm-main.cpp
+++ b/src/asm2wasm-main.cpp
@@ -54,6 +54,11 @@ int main(int argc, char **argv) {
if (debug) std::cerr << "parsing...\n";
cashew::Parser<Ref, DotZeroValueBuilder> builder;
Ref asmjs = builder.parseToplevel(input);
+ if (debug) {
+ std::cerr << "parsed:\n";
+ asmjs->stringify(std::cerr, true);
+ std::cerr << '\n';
+ }
if (debug) std::cerr << "wasming...\n";
AllocatingModule wasm;
diff --git a/src/asm2wasm.h b/src/asm2wasm.h
index d3d76ff83..e37751a66 100644
--- a/src/asm2wasm.h
+++ b/src/asm2wasm.h
@@ -1338,6 +1338,49 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
block->list.push_back(continuer);
ret->body = block;
return ret;
+ } else if (what == FOR) {
+ Ref finit = ast[1],
+ fcond = ast[2],
+ finc = ast[3],
+ fbody = ast[4];
+ auto ret = allocator.alloc<Loop>();
+ IString out, in;
+ if (!parentLabel.isNull()) {
+ out = getBreakLabelName(parentLabel);
+ in = getContinueLabelName(parentLabel);
+ parentLabel = IString();
+ } else {
+ out = getNextId("for-out");
+ in = getNextId("for-in");
+ }
+ ret->out = out;
+ ret->in = in;
+ breakStack.push_back(out);
+ continueStack.push_back(in);
+ Break *breakOut = allocator.alloc<Break>();
+ breakOut->name = out;
+ If *condition = allocator.alloc<If>();
+ condition->condition = process(fcond);
+ condition->ifTrue = allocator.alloc<Nop>();
+ condition->ifFalse = breakOut;
+ auto body = allocator.alloc<Block>();
+ body->list.push_back(condition);
+ body->list.push_back(process(fbody));
+ body->list.push_back(process(finc));
+ ret->body = body;
+ // loops do not automatically loop, add a branch back
+ Block* block = blockify(ret->body);
+ auto continuer = allocator.alloc<Break>();
+ continuer->name = ret->in;
+ block->list.push_back(continuer);
+ ret->body = block;
+ continueStack.pop_back();
+ breakStack.pop_back();
+ Block *outer = allocator.alloc<Block>();
+ // add an outer block for the init as well
+ outer->list.push_back(process(finit));
+ outer->list.push_back(ret);
+ return outer;
} else if (what == LABEL) {
assert(parentLabel.isNull());
parentLabel = ast[1]->getIString();
diff --git a/src/emscripten-optimizer/parser.h b/src/emscripten-optimizer/parser.h
index 6b2fa2faa..c805ca9f6 100644
--- a/src/emscripten-optimizer/parser.h
+++ b/src/emscripten-optimizer/parser.h
@@ -386,6 +386,7 @@ class Parser {
else if (frag.str == CONTINUE) return parseContinue(src, seps);
else if (frag.str == SWITCH) return parseSwitch(src, seps);
else if (frag.str == NEW) return parseNew(src, seps);
+ else if (frag.str == FOR) return parseFor(src, seps);
dump(frag.str.str, src);
abort();
return nullptr;
@@ -492,6 +493,26 @@ class Parser {
return Builder::makeWhile(condition, body);
}
+ NodeRef parseFor(char*& src, const char* seps) {
+ skipSpace(src);
+ assert(*src == '(');
+ src++;
+ NodeRef init = parseElement(src, ";");
+ skipSpace(src);
+ assert(*src == ';');
+ src++;
+ NodeRef condition = parseElement(src, ";");
+ skipSpace(src);
+ assert(*src == ';');
+ src++;
+ NodeRef inc = parseElement(src, ")");
+ skipSpace(src);
+ assert(*src == ')');
+ src++;
+ NodeRef body = parseMaybeBracketed(src, seps);
+ return Builder::makeFor(init, condition, inc, body);
+ }
+
NodeRef parseBreak(char*& src, const char* seps) {
skipSpace(src);
Frag next(src);
diff --git a/src/emscripten-optimizer/simple_ast.h b/src/emscripten-optimizer/simple_ast.h
index 862e1f0bc..712845dea 100644
--- a/src/emscripten-optimizer/simple_ast.h
+++ b/src/emscripten-optimizer/simple_ast.h
@@ -380,7 +380,11 @@ struct Value {
#define indentify() { for (int i = 0; i < indent; i++) os << " "; }
switch (type) {
case String:
- os << '"' << str.str << '"';
+ if (str.str) {
+ os << '"' << str.str << '"';
+ } else {
+ os << "\"(null)\"";
+ }
break;
case Number:
os << std::setprecision(17) << num; // doubles can have 17 digits of precision
@@ -1561,6 +1565,14 @@ public:
.push_back(body);
}
+ static Ref makeFor(Ref init, Ref condition, Ref inc, Ref body) {
+ return &makeRawArray(5)->push_back(makeRawString(FOR))
+ .push_back(init)
+ .push_back(condition)
+ .push_back(inc)
+ .push_back(body);
+ }
+
static Ref makeBreak(IString label) {
return &makeRawArray(2)->push_back(makeRawString(BREAK))
.push_back(!!label ? makeRawString(label) : makeNull());
diff --git a/test/unit.asm.js b/test/unit.asm.js
index a2235dd62..e539c6139 100644
--- a/test/unit.asm.js
+++ b/test/unit.asm.js
@@ -1,4 +1,4 @@
-function () {
+function asm() {
"use asm";
var t = global.NaN, u = global.Infinity;
@@ -129,6 +129,12 @@ function () {
function cneg_nosemicolon() {
FUNCTION_TABLE_c[1 & 7](1) // no semicolon
}
+ function forLoop() {
+ var i = 0;
+ for (i = 1; (i | 0) < 200; i = i + 1 | 0) {
+ h(i | 0);
+ }
+ }
function z() {
}
diff --git a/test/unit.fromasm b/test/unit.fromasm
index 5a6b78de5..4b95dfea1 100644
--- a/test/unit.fromasm
+++ b/test/unit.fromasm
@@ -409,6 +409,36 @@
(i32.const 1)
)
)
+ (func $forLoop
+ (local $i i32)
+ (block
+ (set_local $i
+ (i32.const 1)
+ )
+ (loop $for-out$0 $for-in$1
+ (block
+ (if_else
+ (i32.lt_s
+ (get_local $i)
+ (i32.const 200)
+ )
+ (nop)
+ (br $for-out$0)
+ )
+ (call $h
+ (get_local $i)
+ )
+ (set_local $i
+ (i32.add
+ (get_local $i)
+ (i32.const 1)
+ )
+ )
+ (br $for-in$1)
+ )
+ )
+ )
+ )
(func $z
(nop)
)