summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/emscripten-optimizer/simple_ast.h2
-rw-r--r--src/wasm2asm.h100
2 files changed, 49 insertions, 53 deletions
diff --git a/src/emscripten-optimizer/simple_ast.h b/src/emscripten-optimizer/simple_ast.h
index 4d34713a6..b524a4b2b 100644
--- a/src/emscripten-optimizer/simple_ast.h
+++ b/src/emscripten-optimizer/simple_ast.h
@@ -1527,7 +1527,7 @@ public:
.push_back(value));
}
- static Ref makeAssign(Ref obj, Ref target, Ref value) {
+ static Ref makeAssign(Ref target, Ref value) {
return &makeRawArray(3)->push_back(makeRawString(ASSIGN))
.push_back(&arena.alloc()->setBool(true))
.push_back(target)
diff --git a/src/wasm2asm.h b/src/wasm2asm.h
index 7bf84020e..d23dffca6 100644
--- a/src/wasm2asm.h
+++ b/src/wasm2asm.h
@@ -89,20 +89,6 @@ public:
// Free a temp var.
void freeTemp(IString temp);
- // break and continue stacks
- void pushBreak(Name name) {
- breakStack.push_back(name);
- }
- void popBreak() {
- breakStack.pop_back();
- }
- void pushContinue(Name name) {
- continueStack.push_back(name);
- }
- void popContinue() {
- continueStack.pop_back();
- }
-
IString fromName(Name name) {
return name; // TODO: add a "$" or other prefixing? sanitization of bad chars?
}
@@ -132,9 +118,6 @@ private:
// Label names to which we break with a value aka spooky-return-at-a-distance
std::set<Name> breakedWithValue;
-
- std::vector<Name> breakStack;
- std::vector<Name> continueStack;
};
Ref Wasm2AsmBuilder::processWasm(Module* wasm) {
@@ -164,7 +147,6 @@ Ref Wasm2AsmBuilder::processFunction(Function* func) {
if (result != NO_RESULT) freeTemp(result);
// locals, including new temp locals XXX
// checks
- assert(breakStack.empty() && continueStack.empty());
assert(i32sFree.size() == i32s); // all temp vars should be free at the end
assert(f32sFree.size() == f32s);
assert(f64sFree.size() == f64s);
@@ -293,9 +275,12 @@ Ref Wasm2AsmBuilder::processFunctionBody(Expression* curr, IString result) {
}
};
- Ast visit(Expression* curr, IString nextResult) {
+ Ref visit(Expression* curr, IString nextResult) {
+ IString old = result;
result = nextResult;
- return visit(curr);
+ Ref ret = visit(curr);
+ result = old; // keep it consistent for the rest of this frame, which may call visit on multiple children
+ return ret;
}
Ast visit(Expression* curr, ScopedTemp& temp) {
@@ -312,6 +297,16 @@ Ref Wasm2AsmBuilder::processFunctionBody(Expression* curr, IString result) {
}
}
+ Ref visitAndAssign(Expression* curr, IString result) {
+ Ref ret = visit(curr, result);
+ // if it's not already a statement, then it's an expression, and we need to assign it
+ // (if it is a statement, it already assigns to the result var)
+ if (!isStatement(curr)) {
+ ret = ValueBuilder::makeStatement(ValueBuilder::makeAssign(makeName(result), ret)));
+ }
+ return ret;
+ }
+
bool isStatement(Expression* curr) {
return parent->isStatement(curr);
}
@@ -368,6 +363,15 @@ Ref Wasm2AsmBuilder::processFunctionBody(Expression* curr, IString result) {
// what the result var is for a specific label.
std::map<Name, IString> breakResults;
+ // Breaks to the top of a loop should be emitted as continues, to that loop's main label
+ std::map<Name, Name> actualBreakLabel;
+
+ Name getActualBreakLabel(Name name) {
+ auto iter = actualBreakLabel.find(name);
+ if (iter == actualBreakLabel.end()) return name;
+ return iter->second;
+ }
+
// Visitors
void visitBlock(Block *curr) override {
@@ -378,6 +382,9 @@ Ref Wasm2AsmBuilder::processFunctionBody(Expression* curr, IString result) {
// TODO: flatten out, if we receive a block, just insert the elements
ret[1]->push_back(visit(curr->list[i], i < size-1 ? none : result);
}
+ if (curr->name.is()) {
+ ret = ValueBuilder::makeLabel(fromName(curr->name), ret);
+ }
return ret;
}
void visitIf(If *curr) override {
@@ -396,46 +403,35 @@ Ref Wasm2AsmBuilder::processFunctionBody(Expression* curr, IString result) {
condition[1]->push_back(ValueBuilder::makeIf(ValueBuilder::makeName(temp), ifTrue, ifFalse));
return condition;
}
-XXX
void visitLoop(Loop *curr) override {
- if (curr->out.is()) parent->pushBreak(curr->out);
- if (curr->in.is()) parent->pushContinue(curr->in);
- Ref body = processExpression(curr->body, none);
- if (curr->in.is()) parent->popContinue();
- if (curr->out.is()) parent->popBreak();
+ Name asmLabel = curr->out.is() ? curr->out : curr->in; // label using the outside, normal for breaks. if no outside, then inside
+ if (curr->in.is()) continues[curr->in] = asmLabel;
+ Ref body = visit(curr->body, result);
+ if (asmLabel.is()) {
+ body = ValueBuilder::makeLabel(fromName(asmLabel), body);
+ }
return ValueBuilder::makeDo(body, ValueBuilder::makeInt(0));
}
void visitLabel(Label *curr) override {
- assert(result == none);
- parent->pushBreak(curr->name);
- Ref ret = ValueBuilder::makeLabel(fromName(curr->name), blockify(processExpression(curr->body, none)));
- parent->popBreak();
- return ret;
+ return ValueBuilder::makeLabel(fromName(curr->name), visit(curr->body, result)));
}
void visitBreak(Break *curr) override {
- Ref theBreak = ValueBuilder::makeBreak(fromName(curr->name));
- if (!curr->condition && !curr->value) {
- return theBreak;
- }
- Ref ret = ValueBuilder::makeBlock();
- Ref condition;
if (curr->condition) {
- condition = visitTyped(curr->condition);
+ // we need an equivalent to an if here, so use that code
+ Break fakeBreak = *curr;
+ fakeBreak->condition = nullptr;
+ If fakeIf;
+ fakeIf.condition = curr->condition;
+ fakeIf.ifTrue = fakeBreak;
+ return visit(fake, result);
}
- Ref value;
- if (curr->value) {
- value = visitTyped(curr->value);
- value = blockifyWithResult(value);
- value[1]->push_back(theBreak);
- theBreak = value; // theBreak now sets the return value, then breaks
- }
- if (!condition) return theBreak;
- if (!isStatement(condition)) {
- return ValueBuilder::makeIf(condition, theBreak, Ref());
- }
- condition = blockify(condition);
- condition[1]->push_back(ValueBuilder::makeIf(getBlockValue(condition), theBreak, Ref()));
- return condition;
+ Ref theBreak = ValueBuilder::makeBreak(fromName(getActualBreakLabel(curr->name)));
+ if (!curr->value) return theBreak;
+ // generate the value, including assigning to the result, and then do the break
+ Ref ret = visitAndAssign(curr->value, result);
+ ret = blockify(ret);
+ ret[1]->push_back(theBreak);
+ return ret;
}
void visitSwitch(Switch *curr) override {
abort();