diff options
author | Alon Zakai <alonzakai@gmail.com> | 2016-04-18 11:47:04 -0700 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2016-04-18 11:47:04 -0700 |
commit | b08aa103597b00a2b4a54d81cde6454f3082b4d5 (patch) | |
tree | 23ffae7e36e0f61729303fa2f5a720e495c2253e /src | |
parent | c611306758e6c811642623500a51b0da52758303 (diff) | |
download | binaryen-b08aa103597b00a2b4a54d81cde6454f3082b4d5.tar.gz binaryen-b08aa103597b00a2b4a54d81cde6454f3082b4d5.tar.bz2 binaryen-b08aa103597b00a2b4a54d81cde6454f3082b4d5.zip |
index locals, so that get_local and set_local have just an index, and local names are kept on the Function object (#354)
Diffstat (limited to 'src')
-rw-r--r-- | src/asm2wasm.h | 55 | ||||
-rw-r--r-- | src/asm_v_wasm.h | 4 | ||||
-rw-r--r-- | src/ast_utils.h | 8 | ||||
-rw-r--r-- | src/binaryen-shell.cpp | 4 | ||||
-rw-r--r-- | src/passes/NameManager.cpp | 10 | ||||
-rw-r--r-- | src/passes/Print.cpp | 24 | ||||
-rw-r--r-- | src/passes/ReorderLocals.cpp | 87 | ||||
-rw-r--r-- | src/passes/SimplifyLocals.cpp | 26 | ||||
-rw-r--r-- | src/s2wasm.h | 23 | ||||
-rw-r--r-- | src/wasm-binary.h | 72 | ||||
-rw-r--r-- | src/wasm-builder.h | 75 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 29 | ||||
-rw-r--r-- | src/wasm-s-parser.h | 74 | ||||
-rw-r--r-- | src/wasm.h | 74 | ||||
-rw-r--r-- | src/wasm2asm.h | 61 |
15 files changed, 413 insertions, 213 deletions
diff --git a/src/asm2wasm.h b/src/asm2wasm.h index 8fcb1fb64..da97d7580 100644 --- a/src/asm2wasm.h +++ b/src/asm2wasm.h @@ -742,16 +742,18 @@ void Asm2WasmBuilder::processAsm(Ref ast) { // apply memory growth, if relevant if (memoryGrowth) { // create and export a function that just calls memory growth - auto growWasmMemory = allocator.alloc<Function>(); - growWasmMemory->name = GROW_WASM_MEMORY; - growWasmMemory->params.emplace_back(NEW_SIZE, i32); // the new size - auto get = allocator.alloc<GetLocal>(); - get->name = NEW_SIZE; - auto grow = allocator.alloc<Host>(); - grow->op = GrowMemory; - grow->operands.push_back(get); - growWasmMemory->body = grow; - wasm.addFunction(growWasmMemory); + Builder builder(wasm); + wasm.addFunction(builder.makeFunction( + GROW_WASM_MEMORY, + { { NEW_SIZE, i32 } }, + none, + {}, + builder.makeHost( + GrowMemory, + Name(), + { builder.makeGetLocal(0, i32) } + ) + )); auto export_ = allocator.alloc<Export>(); export_->name = export_->value = GROW_WASM_MEMORY; wasm.addExport(export_); @@ -777,17 +779,16 @@ void Asm2WasmBuilder::processAsm(Ref ast) { // returns x / y auto* func = wasm.getFunction(udivmoddi4); assert(!func->type.is()); - Name xl = func->params[0].name, - xh = func->params[1].name, - yl = func->params[2].name, - yh = func->params[3].name, - r = func->params[4].name; - func->vars.clear(); - Name x64("x64"), y64("y64"); - func->vars.emplace_back(x64, i64); - func->vars.emplace_back(y64, i64); + Builder::clearLocals(func); + Index xl = Builder::addParam(func, "xl", i32), + xh = Builder::addParam(func, "xh", i32), + yl = Builder::addParam(func, "yl", i32), + yh = Builder::addParam(func, "yh", i32), + r = Builder::addParam(func, "r", i32), + x64 = Builder::addVar(func, "x64", i64), + y64 = Builder::addVar(func, "y64", i64); auto* body = allocator.alloc<Block>(); - auto recreateI64 = [&](Name target, Name low, Name high) { + auto recreateI64 = [&](Index target, Index low, Index high) { return builder.makeSetLocal( target, builder.makeBinary( @@ -899,7 +900,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) { assert(curr[0] == ASSIGN && curr[2][0] == NAME); IString name = curr[2][1]->getIString(); AsmType asmType = detectType(curr[3], nullptr, false, Math_fround); - function->params.emplace_back(name, asmToWasmType(asmType)); + Builder::addParam(function, name, asmToWasmType(asmType)); functionVariables.insert(name); asmData.addParam(name, asmType); } @@ -910,7 +911,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) { Ref pair = curr[1][j]; IString name = pair[0]->getIString(); AsmType asmType = detectType(pair[1], nullptr, true, Math_fround); - function->vars.emplace_back(name, asmToWasmType(asmType)); + Builder::addVar(function, name, asmToWasmType(asmType)); functionVariables.insert(name); asmData.addVar(name, asmType); } @@ -921,7 +922,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) { auto ensureI32Temp = [&]() { if (addedI32Temp) return; addedI32Temp = true; - function->vars.emplace_back(I32_TEMP, i32); + Builder::addVar(function, I32_TEMP, i32); functionVariables.insert(I32_TEMP); asmData.addVar(I32_TEMP, ASM_INT); }; @@ -946,7 +947,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) { IString name = ast[2][1]->getIString(); if (functionVariables.has(name)) { auto ret = allocator.alloc<SetLocal>(); - ret->name = ast[2][1]->getIString(); + ret->index = function->getLocalIndex(ast[2][1]->getIString()); ret->value = process(ast[3]); ret->type = ret->value->type; return ret; @@ -1041,7 +1042,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) { if (functionVariables.has(name)) { // var in scope auto ret = allocator.alloc<GetLocal>(); - ret->name = name; + ret->index = function->getLocalIndex(name); ret->type = asmToWasmType(asmData.getType(name)); return ret; } @@ -1248,12 +1249,12 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) { // No wasm support, so use a temp local ensureI32Temp(); auto set = allocator.alloc<SetLocal>(); - set->name = I32_TEMP; + set->index = function->getLocalIndex(I32_TEMP); set->value = value; set->type = i32; auto get = [&]() { auto ret = allocator.alloc<GetLocal>(); - ret->name = I32_TEMP; + ret->index = function->getLocalIndex(I32_TEMP); ret->type = i32; return ret; }; diff --git a/src/asm_v_wasm.h b/src/asm_v_wasm.h index 6a279a2a7..440c9ec89 100644 --- a/src/asm_v_wasm.h +++ b/src/asm_v_wasm.h @@ -67,8 +67,8 @@ std::string getSig(FunctionType *type) { std::string getSig(Function *func) { std::string ret; ret += getSig(func->result); - for (auto param : func->params) { - ret += getSig(param.type); + for (auto type : func->params) { + ret += getSig(type); } return ret; } diff --git a/src/ast_utils.h b/src/ast_utils.h index f97697265..3fe4ee17a 100644 --- a/src/ast_utils.h +++ b/src/ast_utils.h @@ -45,8 +45,8 @@ struct BreakSeeker : public PostWalker<BreakSeeker> { struct EffectAnalyzer : public PostWalker<EffectAnalyzer> { bool branches = false; bool calls = false; - std::set<Name> localsRead; - std::set<Name> localsWritten; + std::set<Index> localsRead; + std::set<Index> localsWritten; bool readsMemory = false; bool writesMemory = false; @@ -98,10 +98,10 @@ struct EffectAnalyzer : public PostWalker<EffectAnalyzer> { void visitCallImport(CallImport *curr) { calls = true; } void visitCallIndirect(CallIndirect *curr) { calls = true; } void visitGetLocal(GetLocal *curr) { - localsRead.insert(curr->name); + localsRead.insert(curr->index); } void visitSetLocal(SetLocal *curr) { - localsWritten.insert(curr->name); + localsWritten.insert(curr->index); } void visitLoad(Load *curr) { readsMemory = true; } void visitStore(Store *curr) { writesMemory = true; } diff --git a/src/binaryen-shell.cpp b/src/binaryen-shell.cpp index 6e3cc8af2..82094a697 100644 --- a/src/binaryen-shell.cpp +++ b/src/binaryen-shell.cpp @@ -89,8 +89,8 @@ static void run_asserts(size_t* i, bool* checked, AllocatingModule* wasm, std::cerr << "Unknown entry " << entry << std::endl; } else { ModuleInstance::LiteralList arguments; - for (NameType param : function->params) { - arguments.push_back(Literal(param.type)); + for (WasmType param : function->params) { + arguments.push_back(Literal(param)); } try { instance->callExport(entry, arguments); diff --git a/src/passes/NameManager.cpp b/src/passes/NameManager.cpp index 6a07de4c7..2f20979b8 100644 --- a/src/passes/NameManager.cpp +++ b/src/passes/NameManager.cpp @@ -60,11 +60,11 @@ void NameManager::visitFunctionType(FunctionType* curr) { } void NameManager::visitFunction(Function* curr) { names.insert(curr->name); - for (auto& param : curr->params) { - names.insert(param.name); - } - for (auto& var : curr->vars) { - names.insert(var.name); + for (Index i = 0; i < curr->getNumLocals(); i++) { + Name name = curr->tryLocalName(i); + if (name.is()) { + names.insert(name); + } } } void NameManager::visitImport(Import* curr) { diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index d791e5377..aa533849f 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -35,6 +35,8 @@ struct PrintSExpression : public Visitor<PrintSExpression> { bool fullAST = false; // whether to not elide nodes in output when possible // (like implicit blocks) + Function* currFunction = nullptr; + PrintSExpression(std::ostream& o) : o(o) { setMinify(false); } @@ -64,6 +66,15 @@ struct PrintSExpression : public Visitor<PrintSExpression> { visit(expression); o << maybeNewLine; } + + Name printableLocal(Index index) { + Name name = currFunction->tryLocalName(index); + if (!name.is()) { + name = Name::fromInt(index); + } + return name; + } + void visitBlock(Block *curr) { // special-case Block, because Block nesting (in their first element) can be incredibly deep std::vector<Block*> stack; @@ -205,10 +216,10 @@ struct PrintSExpression : public Visitor<PrintSExpression> { decIndent(); } void visitGetLocal(GetLocal *curr) { - printOpening(o, "get_local ") << curr->name << ')'; + printOpening(o, "get_local ") << printableLocal(curr->index) << ')'; } void visitSetLocal(SetLocal *curr) { - printOpening(o, "set_local ") << curr->name; + printOpening(o, "set_local ") << printableLocal(curr->index); incIndent(); printFullLine(curr->value); decIndent(); @@ -423,14 +434,15 @@ struct PrintSExpression : public Visitor<PrintSExpression> { printText(o, curr->name.str) << ' ' << curr->value << ')'; } void visitFunction(Function *curr) { + currFunction = curr; printOpening(o, "func ", true) << curr->name; if (curr->type.is()) { o << maybeSpace << "(type " << curr->type << ')'; } if (curr->params.size() > 0) { - for (auto& param : curr->params) { + for (size_t i = 0; i < curr->params.size(); i++) { o << maybeSpace; - printMinorOpening(o, "param ") << param.name << ' ' << printWasmType(param.type) << ")"; + printMinorOpening(o, "param ") << printableLocal(i) << ' ' << printWasmType(curr->getLocalType(i)) << ")"; } } if (curr->result != none) { @@ -438,9 +450,9 @@ struct PrintSExpression : public Visitor<PrintSExpression> { printMinorOpening(o, "result ") << printWasmType(curr->result) << ")"; } incIndent(); - for (auto& local : curr->vars) { + for (size_t i = curr->getVarIndexBase(); i < curr->getNumLocals(); i++) { doIndent(o, indent); - printMinorOpening(o, "local ") << local.name << ' ' << printWasmType(local.type) << ")"; + printMinorOpening(o, "local ") << printableLocal(i) << ' ' << printWasmType(curr->getLocalType(i)) << ")"; o << maybeNewLine; } // It is ok to emit a block here, as a function can directly contain a list, even if our diff --git a/src/passes/ReorderLocals.cpp b/src/passes/ReorderLocals.cpp index 66ea131de..22295dc1a 100644 --- a/src/passes/ReorderLocals.cpp +++ b/src/passes/ReorderLocals.cpp @@ -29,29 +29,94 @@ namespace wasm { struct ReorderLocals : public WalkerPass<PostWalker<ReorderLocals>> { bool isFunctionParallel() { return true; } - std::map<Name, uint32_t> counts; + std::map<Index, uint32_t> counts; void visitFunction(Function *curr) { - auto& vars = curr->vars; - sort(vars.begin(), vars.end(), [this](NameType a, NameType b) -> bool { - if (this->counts[a.name] == this->counts[b.name]) { - return strcmp(a.name.str, b.name.str) > 0; + Index num = curr->getNumLocals(); + std::vector<Index> newToOld; + for (size_t i = 0; i < num; i++) { + newToOld.push_back(i); + } + // sort, keeping params in front (where they will not be moved) + sort(newToOld.begin(), newToOld.end(), [this, curr, &newToOld](Index a, Index b) -> bool { + if (curr->isParam(a) && !curr->isParam(b)) return true; + if (curr->isParam(b) && !curr->isParam(a)) return false; + if (curr->isParam(b) && curr->isParam(a)) { + return a < b; + } + if (this->counts[a] == this->counts[b]) { + return a < b; } - return this->counts[a.name] > this->counts[b.name]; + return this->counts[a] > this->counts[b]; }); - // drop completely unused vars - while (vars.size() > 0 && counts[vars.back().name] == 0) { - vars.pop_back(); + // sorting left params in front, perhaps slightly reordered. verify and fix. + for (size_t i = 0; i < curr->params.size(); i++) { + assert(newToOld[i] < curr->params.size()); + } + for (size_t i = 0; i < curr->params.size(); i++) { + newToOld[i] = i; + } + // sort vars, and drop unused ones + auto oldVars = curr->vars; + curr->vars.clear(); + for (size_t i = curr->getVarIndexBase(); i < newToOld.size(); i++) { + Index index = newToOld[i]; + if (counts[index] > 0) { + curr->vars.push_back(oldVars[index - curr->getVarIndexBase()]); + } else { + newToOld.resize(i); + break; + } } counts.clear(); + std::vector<Index> oldToNew; + oldToNew.resize(num); + for (size_t i = 0; i < newToOld.size(); i++) { + if (curr->isParam(i)) { + oldToNew[i] = i; + } else { + oldToNew[newToOld[i]] = i; + } + } + // apply the renaming to AST nodes + struct ReIndexer : public PostWalker<ReIndexer> { + Function* func; + std::vector<Index>& oldToNew; + + ReIndexer(Function* func, std::vector<Index>& oldToNew) : func(func), oldToNew(oldToNew) {} + + void visitGetLocal(GetLocal *curr) { + if (func->isVar(curr->index)) { + curr->index = oldToNew[curr->index]; + } + } + + void visitSetLocal(SetLocal *curr) { + if (func->isVar(curr->index)) { + curr->index = oldToNew[curr->index]; + } + } + }; + ReIndexer reIndexer(curr, oldToNew); + reIndexer.walk(curr->body); + // apply to the names + auto oldLocalNames = curr->localNames; + auto oldLocalIndices = curr->localIndices; + curr->localNames.clear(); + curr->localNames.resize(newToOld.size()); + curr->localIndices.clear(); + for (size_t i = 0; i < newToOld.size(); i++) { + curr->localNames[i] = oldLocalNames[newToOld[i]]; + curr->localIndices[oldLocalNames[newToOld[i]]] = i; + } } void visitGetLocal(GetLocal *curr) { - counts[curr->name]++; + counts[curr->index]++; } void visitSetLocal(SetLocal *curr) { - counts[curr->name]++; + counts[curr->index]++; } }; diff --git a/src/passes/SimplifyLocals.cpp b/src/passes/SimplifyLocals.cpp index 6220d0780..ddb3bccae 100644 --- a/src/passes/SimplifyLocals.cpp +++ b/src/passes/SimplifyLocals.cpp @@ -45,12 +45,12 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals>> }; // locals in current linear execution trace, which we try to sink - std::map<Name, SinkableInfo> sinkables; + std::map<Index, SinkableInfo> sinkables; bool sunk; - // name => # of get_locals for it - std::map<Name, int> numGetLocals; + // local => # of get_locals for it + std::map<Index, int> numGetLocals; // for each set_local, its origin pointer std::map<SetLocal*, Expression**> setLocalOrigins; @@ -60,7 +60,7 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals>> } void visitGetLocal(GetLocal *curr) { - auto found = sinkables.find(curr->name); + auto found = sinkables.find(curr->index); if (found != sinkables.end()) { // sink it, and nop the origin TODO: clean up nops replaceCurrent(*found->second.item); @@ -70,7 +70,7 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals>> sinkables.erase(found); sunk = true; } else { - numGetLocals[curr->name]++; + numGetLocals[curr->index]++; } } @@ -78,7 +78,7 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals>> // if we are a potentially-sinkable thing, forget it - this // write overrides the last TODO: optimizable // TODO: if no get_locals left, can remove the set as well (== expressionizer in emscripten optimizer) - auto found = sinkables.find(curr->name); + auto found = sinkables.find(curr->index); if (found != sinkables.end()) { sinkables.erase(found); } @@ -86,14 +86,14 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals>> void checkInvalidations(EffectAnalyzer& effects) { // TODO: this is O(bad) - std::vector<Name> invalidated; + std::vector<Index> invalidated; for (auto& sinkable : sinkables) { if (effects.invalidates(sinkable.second.effects)) { invalidated.push_back(sinkable.first); } } - for (auto name : invalidated) { - sinkables.erase(name); + for (auto index : invalidated) { + sinkables.erase(index); } } @@ -125,9 +125,9 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals>> static void tryMarkSinkable(SimplifyLocals* self, Expression** currp) { auto* curr = (*currp)->dynCast<SetLocal>(); if (curr) { - Name name = curr->name; - assert(self->sinkables.count(name) == 0); - self->sinkables.emplace(std::make_pair(name, SinkableInfo(currp))); + Index index = curr->index; + assert(self->sinkables.count(index) == 0); + self->sinkables.emplace(std::make_pair(index, SinkableInfo(currp))); } } @@ -175,7 +175,7 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals>> std::vector<SetLocal*> optimizables; for (auto pair : setLocalOrigins) { SetLocal* curr = pair.first; - if (numGetLocals[curr->name] == 0) { + if (numGetLocals[curr->index] == 0) { // no gets, can remove the set and leave just the value optimizables.push_back(curr); } diff --git a/src/s2wasm.h b/src/s2wasm.h index 1edbb7b6b..4cfb4a20d 100644 --- a/src/s2wasm.h +++ b/src/s2wasm.h @@ -638,8 +638,8 @@ class S2WasmBuilder { inputs[i] = nullptr; } else { auto curr = allocator.alloc<GetLocal>(); - curr->name = getStrToSep(); - curr->type = localTypes[curr->name]; + curr->index = func->getLocalIndex(getStrToSep()); + curr->type = func->getLocalType(curr->index); inputs[i] = curr; } if (*s == ')') s++; // tolerate 0(argument) syntax, where we started at the 'a' @@ -664,7 +664,7 @@ class S2WasmBuilder { push(curr); } else { // set to a local auto set = allocator.alloc<SetLocal>(); - set->name = assign; + set->index = func->getLocalIndex(assign); set->value = curr; set->type = curr->type; addToBlock(set); @@ -1056,7 +1056,7 @@ class S2WasmBuilder { Name assign = getAssign(); skipComma(); auto curr = allocator.alloc<SetLocal>(); - curr->name = getAssign(); + curr->index = func->getLocalIndex(getAssign()); skipComma(); curr->value = getInput(); curr->type = curr->value->type; @@ -1261,10 +1261,10 @@ class S2WasmBuilder { int p = 0; for (const auto& ty : funcType->params) params.emplace_back("$" + std::to_string(p++), ty); Function* f = wasmBuilder.makeFunction(std::string("dynCall_") + sig, std::move(params), funcType->result, {}); - Expression* fptr = wasmBuilder.makeGetLocal("fptr", i32); + Expression* fptr = wasmBuilder.makeGetLocal(0, i32); std::vector<Expression*> args; for (unsigned i = 0; i < funcType->params.size(); ++i) { - args.push_back(wasmBuilder.makeGetLocal("$" + std::to_string(i), funcType->params[i])); + args.push_back(wasmBuilder.makeGetLocal(i + 1, funcType->params[i])); } Expression* call = wasmBuilder.makeCallIndirect(funcType, fptr, std::move(args)); f->body = funcType->result == none ? call : wasmBuilder.makeReturn(call); @@ -1344,17 +1344,18 @@ class S2WasmBuilder { wasm.addStart(start); auto* block = allocator.alloc<Block>(); func->body = block; - { // Create the call, matching its parameters. + { + // Create the call, matching its parameters. // TODO allow calling with non-default values. auto* call = allocator.alloc<Call>(); call->target = startFunction; size_t paramNum = 0; - for (const NameType& nt : target->params) { + for (WasmType type : target->params) { Name name = Name::fromInt(paramNum++); - func->vars.emplace_back(name, nt.type); + Builder::addVar(func, name, type); auto* param = allocator.alloc<GetLocal>(); - param->name = name; - param->type = nt.type; + param->index = func->getLocalIndex(name); + param->type = type; call->operands.push_back(param); } block->list.push_back(call); diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 6b77500bf..0af60600d 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -28,6 +28,7 @@ #include "wasm-traversal.h" #include "shared-constants.h" #include "asm_v_wasm.h" +#include "wasm-builder.h" namespace wasm { @@ -550,40 +551,39 @@ public: finishSection(start); } - std::map<Name, size_t> mappedLocals; // local name => index in compact form of [all int32s][all int64s]etc + std::map<Index, size_t> mappedLocals; // local index => index in compact form of [all int32s][all int64s]etc std::map<WasmType, size_t> numLocalsByType; // type => number of locals of that type in the compact form void mapLocals(Function* function) { - for (auto& param : function->params) { + for (Index i = 0; i < function->getNumParams(); i++) { size_t curr = mappedLocals.size(); - mappedLocals[param.name] = curr; + mappedLocals[i] = curr; } - for (auto& var : function->vars) { - numLocalsByType[var.type]++; + for (auto type : function->vars) { + numLocalsByType[type]++; } std::map<WasmType, size_t> currLocalsByType; - for (auto& var : function->vars) { - size_t index = function->params.size(); - Name name = var.name; - WasmType type = var.type; + for (Index i = function->getVarIndexBase(); i < function->getNumLocals(); i++) { + size_t index = function->getVarIndexBase(); + WasmType type = function->getLocalType(i); currLocalsByType[type]++; // increment now for simplicity, must decrement it in returns if (type == i32) { - mappedLocals[name] = index + currLocalsByType[i32] - 1; + mappedLocals[i] = index + currLocalsByType[i32] - 1; continue; } index += numLocalsByType[i32]; if (type == i64) { - mappedLocals[name] = index + currLocalsByType[i64] - 1; + mappedLocals[i] = index + currLocalsByType[i64] - 1; continue; } index += numLocalsByType[i64]; if (type == f32) { - mappedLocals[name] = index + currLocalsByType[f32] - 1; + mappedLocals[i] = index + currLocalsByType[f32] - 1; continue; } index += numLocalsByType[f32]; if (type == f64) { - mappedLocals[name] = index + currLocalsByType[f64] - 1; + mappedLocals[i] = index + currLocalsByType[f64] - 1; continue; } abort(); @@ -879,12 +879,12 @@ public: } void visitGetLocal(GetLocal *curr) { if (debug) std::cerr << "zz node: GetLocal " << (o.size() + 1) << std::endl; - o << int8_t(BinaryConsts::GetLocal) << U32LEB(mappedLocals[curr->name]); + o << int8_t(BinaryConsts::GetLocal) << U32LEB(mappedLocals[curr->index]); } void visitSetLocal(SetLocal *curr) { if (debug) std::cerr << "zz node: SetLocal" << std::endl; recurse(curr->value); - o << int8_t(BinaryConsts::SetLocal) << U32LEB(mappedLocals[curr->name]); + o << int8_t(BinaryConsts::SetLocal) << U32LEB(mappedLocals[curr->index]); } void emitMemoryAccess(size_t alignment, size_t bytes, uint32_t offset) { @@ -1390,6 +1390,7 @@ public: std::vector<Function*> functions; // we store functions here before wasm.addFunction after we know their names std::map<size_t, std::vector<Call*>> functionCalls; // at index i we have all calls to i + Function* currFunction = nullptr; void readFunctions() { if (debug) std::cerr << "== readFunctions" << std::endl; @@ -1400,41 +1401,36 @@ public: assert(size > 0); // we could also check it matches the seen size auto type = functionTypes[i]; if (debug) std::cerr << "reading" << i << std::endl; - auto func = allocator.alloc<Function>(); - func->type = type->name; - func->result = type->result; size_t nextVar = 0; auto addVar = [&]() { Name name = cashew::IString(("var$" + std::to_string(nextVar++)).c_str(), false); return name; }; + std::vector<NameType> params, vars; for (size_t j = 0; j < type->params.size(); j++) { - func->params.emplace_back(addVar(), type->params[j]); + params.emplace_back(addVar(), type->params[j]); } size_t numLocalTypes = getU32LEB(); for (size_t t = 0; t < numLocalTypes; t++) { auto num = getU32LEB(); auto type = getWasmType(); while (num > 0) { - func->vars.emplace_back(addVar(), type); + vars.emplace_back(addVar(), type); num--; } } + auto func = Builder(wasm).makeFunction( + Name("TODO"), + std::move(params), + type->result, + std::move(vars) + ); + func->type = type->name; + currFunction = func; { // process the function body if (debug) std::cerr << "processing function: " << i << std::endl; nextLabel = 0; - // prepare locals - mappedLocals.clear(); - localTypes.clear(); - for (size_t i = 0; i < func->params.size(); i++) { - mappedLocals.push_back(func->params[i].name); - localTypes[func->params[i].name] = func->params[i].type; - } - for (size_t i = 0; i < func->vars.size(); i++) { - mappedLocals.push_back(func->vars[i].name); - localTypes[func->vars[i].name] = func->vars[i].type; - } // process body assert(breakStack.empty()); assert(expressionStack.empty()); @@ -1446,6 +1442,7 @@ public: assert(breakStack.empty()); assert(expressionStack.empty()); } + currFunction = nullptr; functions.push_back(func); } } @@ -1466,9 +1463,6 @@ public: } } - std::vector<Name> mappedLocals; // index => local name - std::map<Name, WasmType> localTypes; // TODO: optimize - std::vector<Name> breakStack; std::vector<Expression*> expressionStack; @@ -1745,14 +1739,14 @@ public: } void visitGetLocal(GetLocal *curr) { if (debug) std::cerr << "zz node: GetLocal " << pos << std::endl; - curr->name = mappedLocals[getU32LEB()]; - assert(curr->name.is()); - curr->type = localTypes[curr->name]; + curr->index = getU32LEB(); + assert(curr->index < currFunction->getNumLocals()); + curr->type = currFunction->getLocalType(curr->index); } void visitSetLocal(SetLocal *curr) { if (debug) std::cerr << "zz node: SetLocal" << std::endl; - curr->name = mappedLocals[getU32LEB()]; - assert(curr->name.is()); + curr->index = getU32LEB(); + assert(curr->index < currFunction->getNumLocals()); curr->value = popExpression(); curr->type = curr->value->type; } diff --git a/src/wasm-builder.h b/src/wasm-builder.h index 362f1a871..0d6ba30cd 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -21,21 +21,46 @@ namespace wasm { +// Useful data structures + +struct NameType { + Name name; + WasmType type; + NameType() : name(nullptr), type(none) {} + NameType(Name name, WasmType type) : name(name), type(type) {} +}; + +// General AST node builder + class Builder { MixedArena &allocator; public: Builder(AllocatingModule& wasm) : allocator(wasm.allocator) {} + // make* functions, create nodes + Function* makeFunction(Name name, std::vector<NameType>&& params, WasmType resultType, - std::vector<NameType>&& vars) { + std::vector<NameType>&& vars, + Expression* body = nullptr) { auto* func = allocator.alloc<Function>(); func->name = name; - func->params = params; func->result = resultType; - func->vars = vars; + func->body = body; + + for (auto& param : params) { + func->params.push_back(param.type); + func->localIndices[param.name] = func->localNames.size(); + func->localNames.push_back(param.name); + } + for (auto& var : vars) { + func->vars.push_back(var.type); + func->localIndices[var.name] = func->localNames.size(); + func->localNames.push_back(var.name); + } + return func; } @@ -63,15 +88,15 @@ public: return call; } // FunctionType - GetLocal* makeGetLocal(Name name, WasmType type) { + GetLocal* makeGetLocal(Index index, WasmType type) { auto* ret = allocator.alloc<GetLocal>(); - ret->name = name; + ret->index = index; ret->type = type; return ret; } - SetLocal* makeSetLocal(Name name, Expression* value) { + SetLocal* makeSetLocal(Index index, Expression* value) { auto* ret = allocator.alloc<SetLocal>(); - ret->name = name; + ret->index = index; ret->value = value; ret->type = value->type; return ret; @@ -130,9 +155,43 @@ public: ret->value = value; return ret; } - // Host + Host* makeHost(HostOp op, Name nameOperand, ExpressionList&& operands) { + auto* ret = allocator.alloc<Host>(); + ret->op = op; + ret->nameOperand = nameOperand; + ret->operands = operands; + return ret; + } // Unreachable + // Additional utility functions for building on top of nodes + + static Index addParam(Function* func, Name name, WasmType type) { + // only ok to add a param if no vars, otherwise indices are invalidated + assert(func->localIndices.size() == func->params.size()); + func->params.push_back(type); + Index index = func->localNames.size(); + func->localIndices[name] = index; + func->localNames.push_back(name); + return index; + } + + static Index addVar(Function* func, Name name, WasmType type) { + // always ok to add a var, it does not affect other indices + assert(func->localIndices.size() == func->params.size() + func->vars.size()); + func->vars.emplace_back(type); + Index index = func->localNames.size(); + func->localIndices[name] = index; + func->localNames.push_back(name); + return index; + } + + static void clearLocals(Function* func) { + func->params.clear(); + func->vars.clear(); + func->localNames.clear(); + func->localIndices.clear(); + } }; } // namespace wasm diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 528f812d0..8f3f09ed1 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -156,18 +156,21 @@ private: << arguments.size() << " arguments." << std::endl; abort(); } - for (size_t i = 0; i < arguments.size(); i++) { - if (function->params[i].type != arguments[i].type) { - std::cerr << "Function `" << function->name << "` expects type " - << printWasmType(function->params[i].type) - << " for parameter " << i << ", got " - << printWasmType(arguments[i].type) << "." << std::endl; - abort(); + for (size_t i = 0; i < function->getNumLocals(); i++) { + if (i < arguments.size()) { + assert(function->isParam(i)); + if (function->params[i] != arguments[i].type) { + std::cerr << "Function `" << function->name << "` expects type " + << printWasmType(function->params[i]) + << " for parameter " << i << ", got " + << printWasmType(arguments[i].type) << "." << std::endl; + abort(); + } + locals[function->getLocalName(i)] = arguments[i]; + } else { + assert(function->isVar(i)); + locals[function->getLocalName(i)].type = function->getLocalType(i); } - locals[function->params[i].name] = arguments[i]; - } - for (auto& local : function->vars) { - locals[local.name].type = local.type; } } }; @@ -356,14 +359,14 @@ private: Flow visitGetLocal(GetLocal *curr) { NOTE_ENTER("GetLocal"); - IString name = curr->name; + IString name = scope.function->getLocalName(curr->index); NOTE_NAME(name); NOTE_EVAL1(scope.locals[name]); return scope.locals[name]; } Flow visitSetLocal(SetLocal *curr) { NOTE_ENTER("SetLocal"); - IString name = curr->name; + IString name = scope.function->getLocalName(curr->index); Flow flow = visit(curr->value); if (flow.breaking()) return flow; NOTE_NAME(name); diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h index a85899c6a..994aac4da 100644 --- a/src/wasm-s-parser.h +++ b/src/wasm-s-parser.h @@ -32,6 +32,7 @@ #include "parsing.h" #include "asm_v_wasm.h" #include "ast_utils.h" +#include "wasm-builder.h" namespace wasm { @@ -341,21 +342,33 @@ private: } void parseFunction(Element& s) { - auto func = currFunction = allocator.alloc<Function>(); size_t i = 1; + Name name; if (s[i]->isStr()) { - func->name = s[i]->str(); + name = s[i]->str(); i++; } else { // unnamed, use an index - func->name = Name::fromInt(functionCounter); + name = Name::fromInt(functionCounter); } functionCounter++; - func->body = nullptr; + Expression* body = nullptr; localIndex = 0; otherIndex = 0; std::vector<NameType> typeParams; // we may have both params and a type. store the type info here + std::vector<NameType> params; + std::vector<NameType> vars; + WasmType result = none; + Name type; Block* autoBlock = nullptr; // we may need to add a block for the very top level + auto makeFunction = [&]() { + currFunction = Builder(wasm).makeFunction( + name, + std::move(params), + result, + std::move(vars) + ); + }; for (;i < s.size(); i++) { Element& curr = *s[i]; IString id = curr[0]->str(); @@ -377,21 +390,21 @@ private: } j++; if (id == PARAM) { - func->params.emplace_back(name, type); + params.emplace_back(name, type); } else { - func->vars.emplace_back(name, type); + vars.emplace_back(name, type); } localIndex++; currLocalTypes[name] = type; } } else if (id == RESULT) { - func->result = stringToWasmType(curr[1]->str()); + result = stringToWasmType(curr[1]->str()); } else if (id == TYPE) { Name name = curr[1]->str(); - func->type = name; + type = name; if (!wasm.checkFunctionType(name)) onError(); FunctionType* type = wasm.getFunctionType(name); - func->result = type->result; + result = type->result; for (size_t j = 0; j < type->params.size(); j++) { IString name = Name::fromInt(j); WasmType currType = type->params[j]; @@ -400,25 +413,32 @@ private: } } else { // body - if (typeParams.size() > 0 && func->params.size() == 0) { - func->params = typeParams; + if (typeParams.size() > 0 && params.size() == 0) { + params = typeParams; } + if (!currFunction) makeFunction(); Expression* ex = parseExpression(curr); - if (!func->body) { - func->body = ex; + if (!body) { + body = ex; } else { if (!autoBlock) { autoBlock = allocator.alloc<Block>(); - autoBlock->list.push_back(func->body); + autoBlock->list.push_back(body); autoBlock->finalize(); - func->body = autoBlock; + body = autoBlock; } autoBlock->list.push_back(ex); } } } - if (!func->body) func->body = allocator.alloc<Nop>(); - wasm.addFunction(func); + if (!currFunction) { + makeFunction(); + body = allocator.alloc<Nop>(); + } + assert(currFunction->result == result); + currFunction->body = body; + currFunction->type = type; + wasm.addFunction(currFunction); currLocalTypes.clear(); labelStack.clear(); currFunction = nullptr; @@ -701,30 +721,24 @@ private: return ret; } - Name getLocalName(Element& s) { - if (s.dollared()) return s.str(); + Index getLocalIndex(Element& s) { + if (s.dollared()) return currFunction->getLocalIndex(s.str()); // this is a numeric index - size_t i = atoi(s.c_str()); - size_t numParams = currFunction->params.size(); - if (i < numParams) { - return currFunction->params[i].name; - } else { - return currFunction->vars[i - currFunction->params.size()].name; - } + return atoi(s.c_str()); } Expression* makeGetLocal(Element& s) { auto ret = allocator.alloc<GetLocal>(); - ret->name = getLocalName(*s[1]); - ret->type = currLocalTypes[ret->name]; + ret->index = getLocalIndex(*s[1]); + ret->type = currFunction->getLocalType(ret->index); return ret; } Expression* makeSetLocal(Element& s) { auto ret = allocator.alloc<SetLocal>(); - ret->name = getLocalName(*s[1]); + ret->index = getLocalIndex(*s[1]); ret->value = parseExpression(s[2]); - ret->type = currLocalTypes[ret->name]; + ret->type = currFunction->getLocalType(ret->index); return ret; } diff --git a/src/wasm.h b/src/wasm.h index d9c36d878..d62d4fcab 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -64,7 +64,11 @@ namespace wasm { // We use a Name for all of the identifiers. These are IStrings, so they are // all interned - comparisons etc are just pointer comparisons, so there is no -// perf loss. Having names everywhere makes using the AST much nicer. +// perf loss. Having names everywhere makes using the AST much nicer (for +// example, block names are strings and not offsets, which makes composition +// - adding blocks, removing blocks - easy). One exception is local variables, +// where we do use indices, as they are a large proportion of the AST, +// perf matters a lot there, and compositionality is not a problem. // TODO: as an optimization, IString values < some threshold could be considered // numerical indices directly. @@ -84,6 +88,10 @@ struct Name : public cashew::IString { } }; +// An index in a wasm module + +typedef uint32_t Index; + // Types enum WasmType { @@ -924,14 +932,14 @@ class GetLocal : public Expression { public: GetLocal() : Expression(GetLocalId) {} - Name name; + Index index; }; class SetLocal : public Expression { public: SetLocal() : Expression(SetLocalId) {} - Name name; + Index index; Expression *value; }; @@ -1055,23 +1063,65 @@ public: // Globals -struct NameType { - Name name; - WasmType type; - NameType() : name(nullptr), type(none) {} - NameType(Name name, WasmType type) : name(name), type(type) {} -}; - class Function { public: Name name; WasmType result; - std::vector<NameType> params; // function locals are params - std::vector<NameType> vars; // plus vars + std::vector<WasmType> params; // function locals are + std::vector<WasmType> vars; // params plus vars Name type; // if null, it is implicit in params and result Expression *body; + // local names. these are optional. + std::vector<Name> localNames; + std::map<Name, Index> localIndices; + Function() : result(none) {} + + size_t getNumParams() { + return params.size(); + } + size_t getNumVars() { + return vars.size(); + } + size_t getNumLocals() { + return params.size() + vars.size(); + } + + bool isParam(Index index) { + return index < params.size(); + } + bool isVar(Index index) { + return index >= params.size(); + } + + Name getLocalName(Index index) { + assert(index < localNames.size() && localNames[index].is()); + return localNames[index]; + } + Name tryLocalName(Index index) { + if (index < localNames.size() && localNames[index].is()) { + return localNames[index]; + } + // this is an unnamed local + return Name(); + } + Index getLocalIndex(Name name) { + assert(localIndices.count(name) > 0); + return localIndices[name]; + } + Index getVarIndexBase() { + return params.size(); + } + WasmType getLocalType(Index index) { + if (isParam(index)) { + return params[index]; + } else if (isVar(index)) { + return vars[index - getVarIndexBase()]; + } else { + WASM_UNREACHABLE(); + } + } }; class Import { diff --git a/src/wasm2asm.h b/src/wasm2asm.h index 0e244a932..9ccbb4f19 100644 --- a/src/wasm2asm.h +++ b/src/wasm2asm.h @@ -119,7 +119,7 @@ public: // @param result Whether the context we are in receives a value, // and its type, or if not, then we can drop our return, // if we have one. - Ref processFunctionBody(Expression* curr, IString result); + Ref processFunctionBody(Function* func, IString result); // Get a temp var. IString getTemp(WasmType type) { @@ -333,14 +333,14 @@ Ref Wasm2AsmBuilder::processFunction(Function* func) { temps.resize(std::max(i32, std::max(f32, f64)) + 1); temps[i32] = temps[f32] = temps[f64] = 0; // arguments - for (auto& param : func->params) { - IString name = fromName(param.name); + for (Index i = 0; i < func->getNumParams(); i++) { + IString name = fromName(func->getLocalName(i)); ValueBuilder::appendArgumentToFunction(ret, name); ret[3]->push_back( ValueBuilder::makeStatement( ValueBuilder::makeAssign( ValueBuilder::makeName(name), - makeAsmCoercion(ValueBuilder::makeName(name), wasmToAsmType(param.type)) + makeAsmCoercion(ValueBuilder::makeName(name), wasmToAsmType(func->getLocalType(i))) ) ) ); @@ -352,7 +352,7 @@ Ref Wasm2AsmBuilder::processFunction(Function* func) { scanFunctionBody(func->body); if (isStatement(func->body)) { IString result = func->result != none ? getTemp(func->result) : NO_RESULT; - flattenAppend(ret, ValueBuilder::makeStatement(processFunctionBody(func->body, result))); + flattenAppend(ret, ValueBuilder::makeStatement(processFunctionBody(func, result))); if (func->result != none) { // do the actual return ret[3]->push_back(ValueBuilder::makeStatement(ValueBuilder::makeReturn(makeAsmCoercion(ValueBuilder::makeName(result), wasmToAsmType(func->result))))); @@ -361,14 +361,14 @@ Ref Wasm2AsmBuilder::processFunction(Function* func) { } else { // whole thing is an expression, just do a return if (func->result != none) { - ret[3]->push_back(ValueBuilder::makeStatement(ValueBuilder::makeReturn(makeAsmCoercion(processFunctionBody(func->body, EXPRESSION_RESULT), wasmToAsmType(func->result))))); + ret[3]->push_back(ValueBuilder::makeStatement(ValueBuilder::makeReturn(makeAsmCoercion(processFunctionBody(func, EXPRESSION_RESULT), wasmToAsmType(func->result))))); } else { - flattenAppend(ret, processFunctionBody(func->body, NO_RESULT)); + flattenAppend(ret, processFunctionBody(func, NO_RESULT)); } } // vars, including new temp vars - for (auto& var : func->vars) { - ValueBuilder::appendToVar(theVar, fromName(var.name), makeAsmCoercedZero(wasmToAsmType(var.type))); + for (Index i = func->getVarIndexBase(); i < func->getNumLocals(); i++) { + ValueBuilder::appendToVar(theVar, fromName(func->getLocalName(i)), makeAsmCoercedZero(wasmToAsmType(func->getLocalType(i)))); } for (auto f : frees[i32]) { ValueBuilder::appendToVar(theVar, f, makeAsmCoercedZero(ASM_INT)); @@ -482,11 +482,12 @@ void Wasm2AsmBuilder::scanFunctionBody(Expression* curr) { ExpressionScanner(this).walk(curr); } -Ref Wasm2AsmBuilder::processFunctionBody(Expression* curr, IString result) { +Ref Wasm2AsmBuilder::processFunctionBody(Function* func, IString result) { struct ExpressionProcessor : public Visitor<ExpressionProcessor, Ref> { Wasm2AsmBuilder* parent; IString result; - ExpressionProcessor(Wasm2AsmBuilder* parent) : parent(parent) {} + Function* func; + ExpressionProcessor(Wasm2AsmBuilder* parent, Function* func) : parent(parent), func(func) {} // A scoped temporary variable. struct ScopedTemp { @@ -735,23 +736,23 @@ Ref Wasm2AsmBuilder::processFunctionBody(Expression* curr, IString result) { return makeStatementizedCall(curr->operands, ret, theCall, result, curr->type); } Ref visitGetLocal(GetLocal *curr) { - return ValueBuilder::makeName(fromName(curr->name)); + return ValueBuilder::makeName(fromName(func->getLocalName(curr->index))); } Ref visitSetLocal(SetLocal *curr) { if (!isStatement(curr)) { - return ValueBuilder::makeAssign(ValueBuilder::makeName(fromName(curr->name)), visit(curr->value, EXPRESSION_RESULT)); + return ValueBuilder::makeAssign(ValueBuilder::makeName(fromName(func->getLocalName(curr->index))), visit(curr->value, EXPRESSION_RESULT)); } ScopedTemp temp(curr->type, parent, result); // if result was provided, our child can just assign there. otherwise, allocate a temp for it to assign to. Ref ret = blockify(visit(curr->value, temp)); // the output was assigned to result, so we can just assign it to our target - ret[1]->push_back(ValueBuilder::makeStatement(ValueBuilder::makeAssign(ValueBuilder::makeName(fromName(curr->name)), temp.getAstName()))); + ret[1]->push_back(ValueBuilder::makeStatement(ValueBuilder::makeAssign(ValueBuilder::makeName(fromName(func->getLocalName(curr->index))), temp.getAstName()))); return ret; } Ref visitLoad(Load *curr) { if (isStatement(curr)) { ScopedTemp temp(i32, parent); GetLocal fakeLocal; - fakeLocal.name = temp.getName(); + fakeLocal.index = func->getLocalIndex(temp.getName()); Load fakeLoad = *curr; fakeLoad.ptr = &fakeLocal; Ref ret = blockify(visitAndAssign(curr->ptr, temp)); @@ -762,11 +763,11 @@ Ref Wasm2AsmBuilder::processFunctionBody(Expression* curr, IString result) { // set the pointer to a local ScopedTemp temp(i32, parent); SetLocal set; - set.name = temp.getName(); + set.index = func->getLocalIndex(temp.getName()); set.value = curr->ptr; Ref ptrSet = visit(&set, NO_RESULT); GetLocal get; - get.name = temp.getName(); + get.index = func->getLocalIndex(temp.getName()); // fake loads Load load = *curr; load.ptr = &get; @@ -814,9 +815,9 @@ Ref Wasm2AsmBuilder::processFunctionBody(Expression* curr, IString result) { ScopedTemp tempPtr(i32, parent); ScopedTemp tempValue(curr->type, parent); GetLocal fakeLocalPtr; - fakeLocalPtr.name = tempPtr.getName(); + fakeLocalPtr.index = func->getLocalIndex(tempPtr.getName()); GetLocal fakeLocalValue; - fakeLocalValue.name = tempValue.getName(); + fakeLocalValue.index = func->getLocalIndex(tempValue.getName()); Store fakeStore = *curr; fakeStore.ptr = &fakeLocalPtr; fakeStore.value = &fakeLocalValue; @@ -829,19 +830,19 @@ Ref Wasm2AsmBuilder::processFunctionBody(Expression* curr, IString result) { // set the pointer to a local ScopedTemp temp(i32, parent); SetLocal set; - set.name = temp.getName(); + set.index = func->getLocalIndex(temp.getName()); set.value = curr->ptr; Ref ptrSet = visit(&set, NO_RESULT); GetLocal get; - get.name = temp.getName(); + get.index = func->getLocalIndex(temp.getName()); // set the value to a local ScopedTemp tempValue(curr->value->type, parent); SetLocal setValue; - setValue.name = tempValue.getName(); + setValue.index = func->getLocalIndex(tempValue.getName()); setValue.value = curr->value; Ref valueSet = visit(&setValue, NO_RESULT); GetLocal getValue; - getValue.name = tempValue.getName(); + getValue.index = func->getLocalIndex(tempValue.getName()); // fake stores Store store = *curr; store.ptr = &get; @@ -929,7 +930,7 @@ Ref Wasm2AsmBuilder::processFunctionBody(Expression* curr, IString result) { if (isStatement(curr)) { ScopedTemp temp(curr->value->type, parent); GetLocal fakeLocal; - fakeLocal.name = temp.getName(); + fakeLocal.index = func->getLocalIndex(temp.getName()); Unary fakeUnary = *curr; fakeUnary.value = &fakeLocal; Ref ret = blockify(visitAndAssign(curr->value, temp)); @@ -977,10 +978,10 @@ Ref Wasm2AsmBuilder::processFunctionBody(Expression* curr, IString result) { if (isStatement(curr)) { ScopedTemp tempLeft(curr->left->type, parent); GetLocal fakeLocalLeft; - fakeLocalLeft.name = tempLeft.getName(); + fakeLocalLeft.index = func->getLocalIndex(tempLeft.getName()); ScopedTemp tempRight(curr->right->type, parent); GetLocal fakeLocalRight; - fakeLocalRight.name = tempRight.getName(); + fakeLocalRight.index = func->getLocalIndex(tempRight.getName()); Binary fakeBinary = *curr; fakeBinary.left = &fakeLocalLeft; fakeBinary.right = &fakeLocalRight; @@ -1050,13 +1051,13 @@ Ref Wasm2AsmBuilder::processFunctionBody(Expression* curr, IString result) { if (isStatement(curr)) { ScopedTemp tempIfTrue(curr->ifTrue->type, parent); GetLocal fakeLocalIfTrue; - fakeLocalIfTrue.name = tempIfTrue.getName(); + fakeLocalIfTrue.index = func->getLocalIndex(tempIfTrue.getName()); ScopedTemp tempIfFalse(curr->ifFalse->type, parent); GetLocal fakeLocalIfFalse; - fakeLocalIfFalse.name = tempIfFalse.getName(); + fakeLocalIfFalse.index = func->getLocalIndex(tempIfFalse.getName()); ScopedTemp tempCondition(i32, parent); GetLocal fakeCondition; - fakeCondition.name = tempCondition.getName(); + fakeCondition.index = func->getLocalIndex(tempCondition.getName()); Select fakeSelect = *curr; fakeSelect.ifTrue = &fakeLocalIfTrue; fakeSelect.ifFalse = &fakeLocalIfFalse; @@ -1099,7 +1100,7 @@ Ref Wasm2AsmBuilder::processFunctionBody(Expression* curr, IString result) { return ValueBuilder::makeCall(ABORT_FUNC); } }; - return ExpressionProcessor(this).visit(curr, result); + return ExpressionProcessor(this, func).visit(func->body, result); } } // namespace wasm |