summaryrefslogtreecommitdiffstats
path: root/js/src/wasm/WasmBCRegMgmt-inl.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/wasm/WasmBCRegMgmt-inl.h')
-rw-r--r--js/src/wasm/WasmBCRegMgmt-inl.h486
1 files changed, 486 insertions, 0 deletions
diff --git a/js/src/wasm/WasmBCRegMgmt-inl.h b/js/src/wasm/WasmBCRegMgmt-inl.h
new file mode 100644
index 0000000000..d448b7405b
--- /dev/null
+++ b/js/src/wasm/WasmBCRegMgmt-inl.h
@@ -0,0 +1,486 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ *
+ * Copyright 2016 Mozilla Foundation
+ *
+ * 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.
+ */
+
+// This is an INTERNAL header for Wasm baseline compiler: inline methods in the
+// compiler for register management.
+
+#ifndef wasm_wasm_baseline_reg_mgmt_inl_h
+#define wasm_wasm_baseline_reg_mgmt_inl_h
+
+namespace js {
+namespace wasm {
+
+bool BaseCompiler::isAvailableI32(RegI32 r) { return ra.isAvailableI32(r); }
+bool BaseCompiler::isAvailableI64(RegI64 r) { return ra.isAvailableI64(r); }
+bool BaseCompiler::isAvailableRef(RegRef r) { return ra.isAvailableRef(r); }
+bool BaseCompiler::isAvailablePtr(RegPtr r) { return ra.isAvailablePtr(r); }
+bool BaseCompiler::isAvailableF32(RegF32 r) { return ra.isAvailableF32(r); }
+bool BaseCompiler::isAvailableF64(RegF64 r) { return ra.isAvailableF64(r); }
+#ifdef ENABLE_WASM_SIMD
+bool BaseCompiler::isAvailableV128(RegV128 r) { return ra.isAvailableV128(r); }
+#endif
+
+[[nodiscard]] RegI32 BaseCompiler::needI32() { return ra.needI32(); }
+[[nodiscard]] RegI64 BaseCompiler::needI64() { return ra.needI64(); }
+[[nodiscard]] RegRef BaseCompiler::needRef() { return ra.needRef(); }
+[[nodiscard]] RegPtr BaseCompiler::needPtr() { return ra.needPtr(); }
+[[nodiscard]] RegF32 BaseCompiler::needF32() { return ra.needF32(); }
+[[nodiscard]] RegF64 BaseCompiler::needF64() { return ra.needF64(); }
+#ifdef ENABLE_WASM_SIMD
+[[nodiscard]] RegV128 BaseCompiler::needV128() { return ra.needV128(); }
+#endif
+
+void BaseCompiler::needI32(RegI32 specific) { ra.needI32(specific); }
+void BaseCompiler::needI64(RegI64 specific) { ra.needI64(specific); }
+void BaseCompiler::needRef(RegRef specific) { ra.needRef(specific); }
+void BaseCompiler::needPtr(RegPtr specific) { ra.needPtr(specific); }
+void BaseCompiler::needF32(RegF32 specific) { ra.needF32(specific); }
+void BaseCompiler::needF64(RegF64 specific) { ra.needF64(specific); }
+#ifdef ENABLE_WASM_SIMD
+void BaseCompiler::needV128(RegV128 specific) { ra.needV128(specific); }
+#endif
+
+#if defined(JS_CODEGEN_ARM)
+[[nodiscard]] RegI64 BaseCompiler::needI64Pair() { return ra.needI64Pair(); }
+#endif
+
+void BaseCompiler::freeI32(RegI32 r) { ra.freeI32(r); }
+void BaseCompiler::freeI64(RegI64 r) { ra.freeI64(r); }
+void BaseCompiler::freeRef(RegRef r) { ra.freeRef(r); }
+void BaseCompiler::freePtr(RegPtr r) { ra.freePtr(r); }
+void BaseCompiler::freeF32(RegF32 r) { ra.freeF32(r); }
+void BaseCompiler::freeF64(RegF64 r) { ra.freeF64(r); }
+#ifdef ENABLE_WASM_SIMD
+void BaseCompiler::freeV128(RegV128 r) { ra.freeV128(r); }
+#endif
+
+void BaseCompiler::freeAny(AnyReg r) {
+ switch (r.tag) {
+ case AnyReg::I32:
+ freeI32(r.i32());
+ break;
+ case AnyReg::I64:
+ freeI64(r.i64());
+ break;
+ case AnyReg::REF:
+ freeRef(r.ref());
+ break;
+ case AnyReg::F32:
+ freeF32(r.f32());
+ break;
+ case AnyReg::F64:
+ freeF64(r.f64());
+ break;
+#ifdef ENABLE_WASM_SIMD
+ case AnyReg::V128:
+ freeV128(r.v128());
+ break;
+#endif
+ default:
+ MOZ_CRASH();
+ }
+}
+
+template <>
+inline void BaseCompiler::free<RegI32>(RegI32 r) {
+ freeI32(r);
+}
+
+template <>
+inline void BaseCompiler::free<RegI64>(RegI64 r) {
+ freeI64(r);
+}
+
+template <>
+inline void BaseCompiler::free<RegRef>(RegRef r) {
+ freeRef(r);
+}
+
+template <>
+inline void BaseCompiler::free<RegPtr>(RegPtr r) {
+ freePtr(r);
+}
+
+template <>
+inline void BaseCompiler::free<RegF32>(RegF32 r) {
+ freeF32(r);
+}
+
+template <>
+inline void BaseCompiler::free<RegF64>(RegF64 r) {
+ freeF64(r);
+}
+
+#ifdef ENABLE_WASM_SIMD
+template <>
+inline void BaseCompiler::free<RegV128>(RegV128 r) {
+ freeV128(r);
+}
+#endif
+
+template <>
+inline void BaseCompiler::free<AnyReg>(AnyReg r) {
+ freeAny(r);
+}
+
+void BaseCompiler::freeI64Except(RegI64 r, RegI32 except) {
+#ifdef JS_PUNBOX64
+ MOZ_ASSERT(r.reg == except);
+#else
+ MOZ_ASSERT(r.high == except || r.low == except);
+ freeI64(r);
+ needI32(except);
+#endif
+}
+
+void BaseCompiler::maybeFree(RegI32 r) {
+ if (r.isValid()) {
+ freeI32(r);
+ }
+}
+
+void BaseCompiler::maybeFree(RegI64 r) {
+ if (r.isValid()) {
+ freeI64(r);
+ }
+}
+
+void BaseCompiler::maybeFree(RegF32 r) {
+ if (r.isValid()) {
+ freeF32(r);
+ }
+}
+
+void BaseCompiler::maybeFree(RegF64 r) {
+ if (r.isValid()) {
+ freeF64(r);
+ }
+}
+
+void BaseCompiler::maybeFree(RegRef r) {
+ if (r.isValid()) {
+ freeRef(r);
+ }
+}
+
+void BaseCompiler::maybeFree(RegPtr r) {
+ if (r.isValid()) {
+ freePtr(r);
+ }
+}
+
+#ifdef ENABLE_WASM_SIMD128
+void BaseCompiler::maybeFree(RegV128 r) {
+ if (r.isValid()) {
+ freeV128(r);
+ }
+}
+#endif
+
+void BaseCompiler::needI32NoSync(RegI32 r) {
+ MOZ_ASSERT(isAvailableI32(r));
+ needI32(r);
+}
+
+// TODO / OPTIMIZE: need2xI32() can be optimized along with needI32()
+// to avoid sync(). (Bug 1316802)
+
+void BaseCompiler::need2xI32(RegI32 r0, RegI32 r1) {
+ needI32(r0);
+ needI32(r1);
+}
+
+void BaseCompiler::need2xI64(RegI64 r0, RegI64 r1) {
+ needI64(r0);
+ needI64(r1);
+}
+
+RegI32 BaseCompiler::fromI64(RegI64 r) { return RegI32(lowPart(r)); }
+
+RegI32 BaseCompiler::maybeFromI64(RegI64 r) {
+ if (!r.isValid()) {
+ return RegI32::Invalid();
+ }
+ return fromI64(r);
+}
+
+#ifdef JS_PUNBOX64
+RegI64 BaseCompiler::fromI32(RegI32 r) { return RegI64(Register64(r)); }
+#endif
+
+RegI64 BaseCompiler::widenI32(RegI32 r) {
+ MOZ_ASSERT(!isAvailableI32(r));
+#ifdef JS_PUNBOX64
+ return fromI32(r);
+#else
+ RegI32 high = needI32();
+ return RegI64(Register64(high, r));
+#endif
+}
+
+RegI32 BaseCompiler::narrowI64(RegI64 r) {
+#ifdef JS_PUNBOX64
+ return RegI32(r.reg);
+#else
+ freeI32(RegI32(r.high));
+ return RegI32(r.low);
+#endif
+}
+
+RegI32 BaseCompiler::narrowRef(RegRef r) { return RegI32(r); }
+
+RegI32 BaseCompiler::lowPart(RegI64 r) {
+#ifdef JS_PUNBOX64
+ return RegI32(r.reg);
+#else
+ return RegI32(r.low);
+#endif
+}
+
+RegI32 BaseCompiler::maybeHighPart(RegI64 r) {
+#ifdef JS_PUNBOX64
+ return RegI32::Invalid();
+#else
+ return RegI32(r.high);
+#endif
+}
+
+void BaseCompiler::maybeClearHighPart(RegI64 r) {
+#if !defined(JS_PUNBOX64)
+ moveImm32(0, RegI32(r.high));
+#endif
+}
+
+// TODO: We want these to be inlined for sure; do we need an `inline` somewhere?
+
+template <>
+inline RegI32 BaseCompiler::need<RegI32>() {
+ return needI32();
+}
+template <>
+inline RegI64 BaseCompiler::need<RegI64>() {
+ return needI64();
+}
+template <>
+inline RegF32 BaseCompiler::need<RegF32>() {
+ return needF32();
+}
+template <>
+inline RegF64 BaseCompiler::need<RegF64>() {
+ return needF64();
+}
+
+template <>
+inline RegI32 BaseCompiler::pop<RegI32>() {
+ return popI32();
+}
+template <>
+inline RegI64 BaseCompiler::pop<RegI64>() {
+ return popI64();
+}
+template <>
+inline RegF32 BaseCompiler::pop<RegF32>() {
+ return popF32();
+}
+template <>
+inline RegF64 BaseCompiler::pop<RegF64>() {
+ return popF64();
+}
+
+#ifdef ENABLE_WASM_SIMD
+template <>
+inline RegV128 BaseCompiler::need<RegV128>() {
+ return needV128();
+}
+template <>
+inline RegV128 BaseCompiler::pop<RegV128>() {
+ return popV128();
+}
+#endif
+
+// RegPtr values can't be pushed, hence can't be popped.
+template <>
+inline RegPtr BaseCompiler::need<RegPtr>() {
+ return needPtr();
+}
+
+void BaseCompiler::needResultRegisters(ResultType type, ResultRegKind which) {
+ if (type.empty()) {
+ return;
+ }
+
+ for (ABIResultIter iter(type); !iter.done(); iter.next()) {
+ ABIResult result = iter.cur();
+ // Register results are visited first; when we see a stack result we're
+ // done.
+ if (!result.inRegister()) {
+ return;
+ }
+ switch (result.type().kind()) {
+ case ValType::I32:
+ needI32(RegI32(result.gpr()));
+ break;
+ case ValType::I64:
+ needI64(RegI64(result.gpr64()));
+ break;
+ case ValType::V128:
+#ifdef ENABLE_WASM_SIMD
+ if (which == ResultRegKind::All) {
+ needV128(RegV128(result.fpr()));
+ }
+ break;
+#else
+ MOZ_CRASH("No SIMD support");
+#endif
+ case ValType::F32:
+ if (which == ResultRegKind::All) {
+ needF32(RegF32(result.fpr()));
+ }
+ break;
+ case ValType::F64:
+ if (which == ResultRegKind::All) {
+ needF64(RegF64(result.fpr()));
+ }
+ break;
+ case ValType::Ref:
+ needRef(RegRef(result.gpr()));
+ break;
+ }
+ }
+}
+
+#ifdef JS_64BIT
+void BaseCompiler::widenInt32ResultRegisters(ResultType type) {
+ if (type.empty()) {
+ return;
+ }
+
+ for (ABIResultIter iter(type); !iter.done(); iter.next()) {
+ ABIResult result = iter.cur();
+ if (result.inRegister() && result.type().kind() == ValType::I32) {
+ masm.widenInt32(result.gpr());
+ }
+ }
+}
+#endif
+
+void BaseCompiler::freeResultRegisters(ResultType type, ResultRegKind which) {
+ if (type.empty()) {
+ return;
+ }
+
+ for (ABIResultIter iter(type); !iter.done(); iter.next()) {
+ ABIResult result = iter.cur();
+ // Register results are visited first; when we see a stack result we're
+ // done.
+ if (!result.inRegister()) {
+ return;
+ }
+ switch (result.type().kind()) {
+ case ValType::I32:
+ freeI32(RegI32(result.gpr()));
+ break;
+ case ValType::I64:
+ freeI64(RegI64(result.gpr64()));
+ break;
+ case ValType::V128:
+#ifdef ENABLE_WASM_SIMD
+ if (which == ResultRegKind::All) {
+ freeV128(RegV128(result.fpr()));
+ }
+ break;
+#else
+ MOZ_CRASH("No SIMD support");
+#endif
+ case ValType::F32:
+ if (which == ResultRegKind::All) {
+ freeF32(RegF32(result.fpr()));
+ }
+ break;
+ case ValType::F64:
+ if (which == ResultRegKind::All) {
+ freeF64(RegF64(result.fpr()));
+ }
+ break;
+ case ValType::Ref:
+ freeRef(RegRef(result.gpr()));
+ break;
+ }
+ }
+}
+
+void BaseCompiler::needIntegerResultRegisters(ResultType type) {
+ needResultRegisters(type, ResultRegKind::OnlyGPRs);
+}
+
+void BaseCompiler::freeIntegerResultRegisters(ResultType type) {
+ freeResultRegisters(type, ResultRegKind::OnlyGPRs);
+}
+
+void BaseCompiler::needResultRegisters(ResultType type) {
+ needResultRegisters(type, ResultRegKind::All);
+}
+
+void BaseCompiler::freeResultRegisters(ResultType type) {
+ freeResultRegisters(type, ResultRegKind::All);
+}
+
+void BaseCompiler::captureResultRegisters(ResultType type) {
+ assertResultRegistersAvailable(type);
+ needResultRegisters(type);
+}
+
+void BaseCompiler::captureCallResultRegisters(ResultType type) {
+ captureResultRegisters(type);
+#ifdef JS_64BIT
+ widenInt32ResultRegisters(type);
+#endif
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Control stack. Some of these are very hot.
+
+void BaseCompiler::initControl(Control& item, ResultType params) {
+ // Make sure the constructor was run properly
+ MOZ_ASSERT(!item.stackHeight.isValid() && item.stackSize == UINT32_MAX);
+
+ uint32_t paramCount = deadCode_ ? 0 : params.length();
+ uint32_t stackParamSize = stackConsumed(paramCount);
+ item.stackHeight = fr.stackResultsBase(stackParamSize);
+ item.stackSize = stk_.length() - paramCount;
+ item.deadOnArrival = deadCode_;
+ item.bceSafeOnEntry = bceSafe_;
+}
+
+Control& BaseCompiler::controlItem() { return iter_.controlItem(); }
+
+Control& BaseCompiler::controlItem(uint32_t relativeDepth) {
+ return iter_.controlItem(relativeDepth);
+}
+
+Control& BaseCompiler::controlOutermost() { return iter_.controlOutermost(); }
+
+LabelKind BaseCompiler::controlKind(uint32_t relativeDepth) {
+ return iter_.controlKind(relativeDepth);
+}
+
+} // namespace wasm
+} // namespace js
+
+#endif // wasm_wasm_baseline_reg_mgmt_inl_h