summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2016-04-18 11:47:04 -0700
committerAlon Zakai <alonzakai@gmail.com>2016-04-18 11:47:04 -0700
commitb08aa103597b00a2b4a54d81cde6454f3082b4d5 (patch)
tree23ffae7e36e0f61729303fa2f5a720e495c2253e /src
parentc611306758e6c811642623500a51b0da52758303 (diff)
downloadbinaryen-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.h55
-rw-r--r--src/asm_v_wasm.h4
-rw-r--r--src/ast_utils.h8
-rw-r--r--src/binaryen-shell.cpp4
-rw-r--r--src/passes/NameManager.cpp10
-rw-r--r--src/passes/Print.cpp24
-rw-r--r--src/passes/ReorderLocals.cpp87
-rw-r--r--src/passes/SimplifyLocals.cpp26
-rw-r--r--src/s2wasm.h23
-rw-r--r--src/wasm-binary.h72
-rw-r--r--src/wasm-builder.h75
-rw-r--r--src/wasm-interpreter.h29
-rw-r--r--src/wasm-s-parser.h74
-rw-r--r--src/wasm.h74
-rw-r--r--src/wasm2asm.h61
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