summaryrefslogtreecommitdiff
path: root/src/passes/SpillPointers.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/passes/SpillPointers.cpp')
-rw-r--r--src/passes/SpillPointers.cpp206
1 files changed, 0 insertions, 206 deletions
diff --git a/src/passes/SpillPointers.cpp b/src/passes/SpillPointers.cpp
deleted file mode 100644
index 453510592..000000000
--- a/src/passes/SpillPointers.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright 2017 WebAssembly Community Group participants
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//
-// Spills values that might be pointers to the C stack. This allows
-// Boehm-style GC to see them properly.
-//
-// To reduce the overhead of the extra operations added here, you
-// should probably run optimizations after doing it.
-// TODO: add a dead store elimination pass, which would help here
-//
-// * There is currently no check that there is enough stack space.
-//
-
-#include "abi/abi.h"
-#include "abi/stack.h"
-#include "cfg/liveness-traversal.h"
-#include "pass.h"
-#include "wasm-builder.h"
-#include "wasm.h"
-
-namespace wasm {
-
-struct SpillPointers
- : public WalkerPass<LivenessWalker<SpillPointers, Visitor<SpillPointers>>> {
- bool isFunctionParallel() override { return true; }
-
- Pass* create() override { return new SpillPointers; }
-
- // a mapping of the pointers to all the spillable things. We need to know
- // how to replace them, and as we spill we may modify them. This map
- // gives us, for an Expression** seen during the walk (and placed in the
- // basic block, which is what we iterate on for efficiency) => the
- // current actual pointer, which may have moded
- std::unordered_map<Expression**, Expression**> actualPointers;
-
- // note calls in basic blocks
- template<typename T> void visitSpillable(T* curr) {
- // if in unreachable code, ignore
- if (!currBasicBlock) {
- return;
- }
- auto* pointer = getCurrentPointer();
- currBasicBlock->contents.actions.emplace_back(pointer);
- // starts out as correct, may change later
- actualPointers[pointer] = pointer;
- }
-
- void visitCall(Call* curr) { visitSpillable(curr); }
- void visitCallIndirect(CallIndirect* curr) { visitSpillable(curr); }
-
- // main entry point
-
- void doWalkFunction(Function* func) {
- if (!canRun(func)) {
- return;
- }
- super::doWalkFunction(func);
- spillPointers();
- }
-
- // map pointers to their offset in the spill area
- typedef std::unordered_map<Index, Index> PointerMap;
-
- void spillPointers() {
- // we only care about possible pointers
- auto* func = getFunction();
- PointerMap pointerMap;
- for (Index i = 0; i < func->getNumLocals(); i++) {
- if (func->getLocalType(i) == ABI::PointerType) {
- auto offset = pointerMap.size() * ABI::PointerType.getByteSize();
- pointerMap[i] = offset;
- }
- }
- // find calls and spill around them
- bool spilled = false;
- Index spillLocal = -1;
- for (auto& curr : basicBlocks) {
- if (liveBlocks.count(curr.get()) == 0) {
- continue; // ignore dead blocks
- }
- auto& liveness = curr->contents;
- auto& actions = liveness.actions;
- Index lastCall = -1;
- for (Index i = 0; i < actions.size(); i++) {
- auto& action = liveness.actions[i];
- if (action.isOther()) {
- lastCall = i;
- }
- }
- if (lastCall == Index(-1)) {
- continue; // nothing to see here
- }
- // scan through the block, spilling around the calls
- // TODO: we can filter on pointerMap everywhere
- SetOfLocals live = liveness.end;
- for (int i = int(actions.size()) - 1; i >= 0; i--) {
- auto& action = actions[i];
- if (action.isGet()) {
- live.insert(action.index);
- } else if (action.isSet()) {
- live.erase(action.index);
- } else if (action.isOther()) {
- std::vector<Index> toSpill;
- for (auto index : live) {
- if (pointerMap.count(index) > 0) {
- toSpill.push_back(index);
- }
- }
- if (!toSpill.empty()) {
- // we now have a call + the information about which locals
- // should be spilled
- if (!spilled) {
- // prepare stack support: get a pointer to stack space big enough
- // for all our data
- spillLocal = Builder::addVar(func, ABI::PointerType);
- spilled = true;
- }
- // the origin was seen at walk, but the thing may have moved
- auto* pointer = actualPointers[action.origin];
- spillPointersAroundCall(
- pointer, toSpill, spillLocal, pointerMap, func, getModule());
- }
- } else {
- WASM_UNREACHABLE("unexpected action");
- }
- }
- }
- if (spilled) {
- // get the stack space, and set the local to it
- ABI::getStackSpace(spillLocal,
- func,
- ABI::PointerType.getByteSize() * pointerMap.size(),
- *getModule());
- }
- }
-
- void spillPointersAroundCall(Expression** origin,
- std::vector<Index>& toSpill,
- Index spillLocal,
- PointerMap& pointerMap,
- Function* func,
- Module* module) {
- auto* call = *origin;
- if (call->type == Type::unreachable) {
- return; // the call is never reached anyhow, ignore
- }
- Builder builder(*module);
- auto* block = builder.makeBlock();
- // move the operands into locals, as we must spill after they are executed
- auto handleOperand = [&](Expression*& operand) {
- auto temp = builder.addVar(func, operand->type);
- auto* set = builder.makeLocalSet(temp, operand);
- block->list.push_back(set);
- block->finalize();
- if (actualPointers.count(&operand) > 0) {
- // this is something we track, and it's moving - update
- actualPointers[&operand] = &set->value;
- }
- operand = builder.makeLocalGet(temp, operand->type);
- };
- if (call->is<Call>()) {
- for (auto*& operand : call->cast<Call>()->operands) {
- handleOperand(operand);
- }
- } else if (call->is<CallIndirect>()) {
- for (auto*& operand : call->cast<CallIndirect>()->operands) {
- handleOperand(operand);
- }
- handleOperand(call->cast<CallIndirect>()->target);
- } else {
- WASM_UNREACHABLE("unexpected expr");
- }
- // add the spills
- for (auto index : toSpill) {
- block->list.push_back(
- builder.makeStore(ABI::PointerType.getByteSize(),
- pointerMap[index],
- ABI::PointerType.getByteSize(),
- builder.makeLocalGet(spillLocal, ABI::PointerType),
- builder.makeLocalGet(index, ABI::PointerType),
- ABI::PointerType));
- }
- // add the (modified) call
- block->list.push_back(call);
- block->finalize();
- *origin = block;
- }
-};
-
-Pass* createSpillPointersPass() { return new SpillPointers(); }
-
-} // namespace wasm