diff options
Diffstat (limited to 'src/asm2wasm.h')
-rw-r--r-- | src/asm2wasm.h | 61 |
1 files changed, 38 insertions, 23 deletions
diff --git a/src/asm2wasm.h b/src/asm2wasm.h index be11344b2..355a521f1 100644 --- a/src/asm2wasm.h +++ b/src/asm2wasm.h @@ -1404,7 +1404,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) { ret->finalize(); return ret; } else if (what == SWITCH) { - IString name; + IString name; // for breaking out of the entire switch if (!parentLabel.isNull()) { name = getBreakLabelName(parentLabel); parentLabel = IString(); @@ -1412,10 +1412,11 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) { name = getNextId("switch"); } breakStack.push_back(name); - auto ret = allocator.alloc<Switch>(); - ret->name = name; - ret->value = process(ast[1]); - assert(ret->value->type == i32); + + auto br = allocator.alloc<Switch>(); + br->condition = process(ast[1]); + assert(br->condition->type == i32); + Ref cases = ast[2]; bool seen = false; int min = 0; // the lowest index we see; we will offset to it @@ -1435,18 +1436,23 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) { } Binary* offsetor = allocator.alloc<Binary>(); offsetor->op = BinaryOp::Sub; - offsetor->left = ret->value; + offsetor->left = br->condition; offsetor->right = allocator.alloc<Const>()->set(Literal(min)); offsetor->type = i32; - ret->value = offsetor; + br->condition = offsetor; + + auto top = allocator.alloc<Block>(); + top->list.push_back(br); + top->finalize(); + for (unsigned i = 0; i < cases->size(); i++) { Ref curr = cases[i]; Ref condition = curr[0]; Ref body = curr[1]; - Switch::Case case_; - case_.body = processStatements(body, 0); + auto case_ = processStatements(body, 0); + Name name; if (condition->isNull()) { - case_.name = ret->default_ = getNextId("switch-default"); + name = br->default_ = getNextId("switch-default"); } else { assert(condition[0] == NUM || condition[0] == UNARY_PREFIX); int32_t index = getLiteral(condition).geti32(); @@ -1454,26 +1460,35 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) { index -= min; assert(index >= 0); size_t index_s = index; - case_.name = getNextId("switch-case"); - if (ret->targets.size() <= index_s) { - ret->targets.resize(index_s+1); + name = getNextId("switch-case"); + if (br->targets.size() <= index_s) { + br->targets.resize(index_s+1); } - ret->targets[index_s] = case_.name; + br->targets[index_s] = name; } - ret->cases.push_back(case_); + auto next = allocator.alloc<Block>(); + top->name = name; + next->list.push_back(top); + next->list.push_back(case_); + next->finalize(); + top = next; } + // ensure a default - if (ret->default_.isNull()) { - Switch::Case defaultCase; - defaultCase.name = ret->default_ = getNextId("switch-default"); - defaultCase.body = allocator.alloc<Nop>(); // ok if others fall through to this - ret->cases.push_back(defaultCase); + if (br->default_.isNull()) { + br->default_ = getNextId("switch-default"); } - for (size_t i = 0; i < ret->targets.size(); i++) { - if (ret->targets[i].isNull()) ret->targets[i] = ret->default_; + for (size_t i = 0; i < br->targets.size(); i++) { + if (br->targets[i].isNull()) br->targets[i] = br->default_; } - // finalize + top->name = br->default_; + breakStack.pop_back(); + + // Create a topmost block for breaking out of the entire switch + auto ret = allocator.alloc<Block>(); + ret->name = name; + ret->list.push_back(top); return ret; } abort_on("confusing expression", ast); |