summaryrefslogtreecommitdiff
path: root/src/abi/stack.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/abi/stack.h')
-rw-r--r--src/abi/stack.h115
1 files changed, 115 insertions, 0 deletions
diff --git a/src/abi/stack.h b/src/abi/stack.h
new file mode 100644
index 000000000..cc678b6e8
--- /dev/null
+++ b/src/abi/stack.h
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+
+#ifndef wasm_abi_stack_h
+#define wasm_abi_stack_h
+
+#include "asmjs/shared-constants.h"
+#include "ir/find_all.h"
+#include "ir/global-utils.h"
+#include "shared-constants.h"
+#include "wasm-builder.h"
+#include "wasm-emscripten.h"
+#include "wasm.h"
+
+namespace wasm {
+
+namespace ABI {
+
+enum { StackAlign = 16 };
+
+inline Index stackAlign(Index size) {
+ return (size + StackAlign - 1) & -StackAlign;
+}
+
+// Allocate some space on the stack, and assign it to a local.
+// The local will have the same constant value in all the function, so you can
+// just local.get it anywhere there.
+//
+// FIXME: This function assumes that the stack grows upward, per the convention
+// used by fastcomp. The stack grows downward when using the WASM backend.
+
+inline void
+getStackSpace(Index local, Function* func, Index size, Module& wasm) {
+ auto* stackPointer = getStackPointerGlobal(wasm);
+ if (!stackPointer) {
+ Fatal() << "getStackSpace: failed to find the stack pointer";
+ }
+ // align the size
+ size = stackAlign(size);
+ auto pointerType = wasm.memory.indexType;
+ // TODO: find existing stack usage, and add on top of that - carefully
+ Builder builder(wasm);
+ auto* block = builder.makeBlock();
+ block->list.push_back(builder.makeLocalSet(
+ local, builder.makeGlobalGet(stackPointer->name, pointerType)));
+ // TODO: add stack max check
+ Expression* added;
+ if (pointerType == Type::i32) {
+ // The stack goes downward in the LLVM wasm backend.
+ added = builder.makeBinary(SubInt32,
+ builder.makeLocalGet(local, pointerType),
+ builder.makeConst(int32_t(size)));
+ } else {
+ WASM_UNREACHABLE("unhandled pointerType");
+ }
+ block->list.push_back(builder.makeGlobalSet(stackPointer->name, added));
+ auto makeStackRestore = [&]() {
+ return builder.makeGlobalSet(stackPointer->name,
+ builder.makeLocalGet(local, pointerType));
+ };
+ // add stack restores to the returns
+ FindAllPointers<Return> finder(func->body);
+ for (auto** ptr : finder.list) {
+ auto* ret = (*ptr)->cast<Return>();
+ if (ret->value && ret->value->type != Type::unreachable) {
+ // handle the returned value
+ auto* block = builder.makeBlock();
+ auto temp = builder.addVar(func, ret->value->type);
+ block->list.push_back(builder.makeLocalSet(temp, ret->value));
+ block->list.push_back(makeStackRestore());
+ block->list.push_back(
+ builder.makeReturn(builder.makeLocalGet(temp, ret->value->type)));
+ block->finalize();
+ *ptr = block;
+ } else {
+ // restore, then return
+ *ptr = builder.makeSequence(makeStackRestore(), ret);
+ }
+ }
+ // add stack restores to the body
+ if (func->body->type == Type::none) {
+ block->list.push_back(func->body);
+ block->list.push_back(makeStackRestore());
+ } else if (func->body->type == Type::unreachable) {
+ block->list.push_back(func->body);
+ // no need to restore the old stack value, we're gone anyhow
+ } else {
+ // save the return value
+ auto temp = builder.addVar(func, func->getResults());
+ block->list.push_back(builder.makeLocalSet(temp, func->body));
+ block->list.push_back(makeStackRestore());
+ block->list.push_back(builder.makeLocalGet(temp, func->getResults()));
+ }
+ block->finalize();
+ func->body = block;
+}
+
+} // namespace ABI
+
+} // namespace wasm
+
+#endif // wasm_abi_stack_h