summaryrefslogtreecommitdiffstats
path: root/js/src/jit/mips32/Architecture-mips32.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit/mips32/Architecture-mips32.h')
-rw-r--r--js/src/jit/mips32/Architecture-mips32.h287
1 files changed, 287 insertions, 0 deletions
diff --git a/js/src/jit/mips32/Architecture-mips32.h b/js/src/jit/mips32/Architecture-mips32.h
new file mode 100644
index 000000000..9e5f3ca28
--- /dev/null
+++ b/js/src/jit/mips32/Architecture-mips32.h
@@ -0,0 +1,287 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef jit_mips32_Architecture_mips32_h
+#define jit_mips32_Architecture_mips32_h
+
+#include "mozilla/MathAlgorithms.h"
+
+#include <limits.h>
+#include <stdint.h>
+
+#include "jit/mips-shared/Architecture-mips-shared.h"
+
+#include "js/Utility.h"
+
+namespace js {
+namespace jit {
+
+// Shadow stack space is not required on MIPS.
+static const uint32_t ShadowStackSpace = 4 * sizeof(uintptr_t);
+
+// These offsets are specific to nunboxing, and capture offsets into the
+// components of a js::Value.
+// Size of MIPS32 general purpose registers is 32 bits.
+static const int32_t NUNBOX32_TYPE_OFFSET = 4;
+static const int32_t NUNBOX32_PAYLOAD_OFFSET = 0;
+
+// Size of each bailout table entry.
+// For MIPS this is 2 instructions relative call.
+static const uint32_t BAILOUT_TABLE_ENTRY_SIZE = 2 * sizeof(void*);
+
+// MIPS32 can have two types of floating-point coprocessors:
+// - 32 bit floating-point coprocessor - In this case, there are 32 single
+// precision registers and pairs of even and odd float registers are used as
+// double precision registers. Example: f0 (double) is composed of
+// f0 and f1 (single).
+// - 64 bit floating-point coprocessor - In this case, there are 32 double
+// precision register which can also be used as single precision registers.
+
+// When using O32 ABI, floating-point coprocessor is 32 bit.
+// When using N32 ABI, floating-point coprocessor is 64 bit.
+class FloatRegisters : public FloatRegistersMIPSShared
+{
+ public:
+ static const char* GetName(uint32_t i) {
+ MOZ_ASSERT(i < Total);
+ return FloatRegistersMIPSShared::GetName(Code(i % 32));
+ }
+
+ static Code FromName(const char* name);
+
+ static const uint32_t Total = 64;
+ static const uint32_t TotalDouble = 16;
+ static const uint32_t RegisterIdLimit = 32;
+ // Workarounds: On Loongson CPU-s the odd FP registers behave differently
+ // in fp-32 mode than standard MIPS.
+#if defined(_MIPS_ARCH_LOONGSON3A)
+ static const uint32_t TotalSingle = 16;
+ static const uint32_t Allocatable = 28;
+ static const SetType AllSingleMask = 0x55555555ULL;
+#else
+ static const uint32_t TotalSingle = 32;
+ static const uint32_t Allocatable = 42;
+ static const SetType AllSingleMask = (1ULL << 32) - 1;
+#endif
+ // When saving all registers we only need to do is save double registers.
+ static const uint32_t TotalPhys = 16;
+
+ static_assert(sizeof(SetType) * 8 >= Total,
+ "SetType should be large enough to enumerate all registers.");
+
+ static const SetType AllDoubleMask = 0x55555555ULL << 32;
+ static const SetType AllMask = AllDoubleMask | AllSingleMask;
+
+ static const SetType NonVolatileDoubleMask =
+ ((1ULL << FloatRegisters::f20) |
+ (1ULL << FloatRegisters::f22) |
+ (1ULL << FloatRegisters::f24) |
+ (1ULL << FloatRegisters::f26) |
+ (1ULL << FloatRegisters::f28) |
+ (1ULL << FloatRegisters::f30)) << 32;
+
+ // f20-single and f21-single alias f20-double ...
+ static const SetType NonVolatileMask =
+ NonVolatileDoubleMask |
+ (1ULL << FloatRegisters::f20) |
+ (1ULL << FloatRegisters::f21) |
+ (1ULL << FloatRegisters::f22) |
+ (1ULL << FloatRegisters::f23) |
+ (1ULL << FloatRegisters::f24) |
+ (1ULL << FloatRegisters::f25) |
+ (1ULL << FloatRegisters::f26) |
+ (1ULL << FloatRegisters::f27) |
+ (1ULL << FloatRegisters::f28) |
+ (1ULL << FloatRegisters::f29) |
+ (1ULL << FloatRegisters::f30) |
+ (1ULL << FloatRegisters::f31);
+
+ static const SetType VolatileMask = AllMask & ~NonVolatileMask;
+ static const SetType VolatileDoubleMask = AllDoubleMask & ~NonVolatileDoubleMask;
+
+ static const SetType WrapperMask = VolatileMask;
+
+ static const SetType NonAllocatableDoubleMask =
+ ((1ULL << FloatRegisters::f16) |
+ (1ULL << FloatRegisters::f18)) << 32;
+ // f16-single and f17-single alias f16-double ...
+ static const SetType NonAllocatableMask =
+ NonAllocatableDoubleMask |
+ (1ULL << FloatRegisters::f16) |
+ (1ULL << FloatRegisters::f17) |
+ (1ULL << FloatRegisters::f18) |
+ (1ULL << FloatRegisters::f19);
+
+ // Registers that can be allocated without being saved, generally.
+ static const SetType TempMask = VolatileMask & ~NonAllocatableMask;
+
+ static const SetType AllocatableMask = AllMask & ~NonAllocatableMask;
+};
+
+class FloatRegister : public FloatRegisterMIPSShared
+{
+ public:
+ enum RegType {
+ Single = 0x0,
+ Double = 0x1,
+ };
+
+ typedef FloatRegisters Codes;
+ typedef Codes::Code Code;
+ typedef Codes::Encoding Encoding;
+
+ uint32_t code_ : 6;
+ protected:
+ RegType kind_ : 1;
+
+ public:
+ constexpr FloatRegister(uint32_t code, RegType kind = Double)
+ : code_ (Code(code)), kind_(kind)
+ { }
+ constexpr FloatRegister()
+ : code_(Code(FloatRegisters::invalid_freg)), kind_(Double)
+ { }
+
+ bool operator==(const FloatRegister& other) const {
+ MOZ_ASSERT(!isInvalid());
+ MOZ_ASSERT(!other.isInvalid());
+ return kind_ == other.kind_ && code_ == other.code_;
+ }
+ bool equiv(const FloatRegister& other) const { return other.kind_ == kind_; }
+ size_t size() const { return (kind_ == Double) ? 8 : 4; }
+ bool isInvalid() const {
+ return code_ == FloatRegisters::invalid_freg;
+ }
+
+ bool isSingle() const { return kind_ == Single; }
+ bool isDouble() const { return kind_ == Double; }
+
+ FloatRegister doubleOverlay(unsigned int which = 0) const;
+ FloatRegister singleOverlay(unsigned int which = 0) const;
+ FloatRegister sintOverlay(unsigned int which = 0) const;
+ FloatRegister uintOverlay(unsigned int which = 0) const;
+
+ FloatRegister asSingle() const { return singleOverlay(); }
+ FloatRegister asDouble() const { return doubleOverlay(); }
+ FloatRegister asSimd128() const { MOZ_CRASH("NYI"); }
+
+ Code code() const {
+ MOZ_ASSERT(!isInvalid());
+ return Code(code_ | (kind_ << 5));
+ }
+ Encoding encoding() const {
+ MOZ_ASSERT(!isInvalid());
+ return Encoding(code_);
+ }
+ uint32_t id() const {
+ return code_;
+ }
+ static FloatRegister FromCode(uint32_t i) {
+ uint32_t code = i & 31;
+ uint32_t kind = i >> 5;
+ return FloatRegister(code, RegType(kind));
+ }
+ // This is similar to FromCode except for double registers on O32.
+ static FloatRegister FromIndex(uint32_t index, RegType kind) {
+#if defined(USES_O32_ABI)
+ // Only even FP registers are avaiable for Loongson on O32.
+# if defined(_MIPS_ARCH_LOONGSON3A)
+ return FloatRegister(index * 2, kind);
+# else
+ if (kind == Double)
+ return FloatRegister(index * 2, kind);
+# endif
+#endif
+ return FloatRegister(index, kind);
+ }
+
+ bool volatile_() const {
+ if (isDouble())
+ return !!((1ULL << code_) & FloatRegisters::VolatileMask);
+ return !!((1ULL << (code_ & ~1)) & FloatRegisters::VolatileMask);
+ }
+ const char* name() const {
+ return FloatRegisters::GetName(code_);
+ }
+ bool operator != (const FloatRegister& other) const {
+ return other.kind_ != kind_ || code_ != other.code_;
+ }
+ bool aliases(const FloatRegister& other) {
+ if (kind_ == other.kind_)
+ return code_ == other.code_;
+ return doubleOverlay() == other.doubleOverlay();
+ }
+ uint32_t numAliased() const {
+ if (isDouble()) {
+ MOZ_ASSERT((code_ & 1) == 0);
+ return 3;
+ }
+ return 2;
+ }
+ void aliased(uint32_t aliasIdx, FloatRegister* ret) {
+ if (aliasIdx == 0) {
+ *ret = *this;
+ return;
+ }
+ if (isDouble()) {
+ MOZ_ASSERT((code_ & 1) == 0);
+ MOZ_ASSERT(aliasIdx <= 2);
+ *ret = singleOverlay(aliasIdx - 1);
+ return;
+ }
+ MOZ_ASSERT(aliasIdx == 1);
+ *ret = doubleOverlay(aliasIdx - 1);
+ }
+ uint32_t numAlignedAliased() const {
+ if (isDouble()) {
+ MOZ_ASSERT((code_ & 1) == 0);
+ return 2;
+ }
+ // f1-float32 has 0 other aligned aliases, 1 total.
+ // f0-float32 has 1 other aligned alias, 2 total.
+ return 2 - (code_ & 1);
+ }
+ // | f0-double |
+ // | f0-float32 | f1-float32 |
+ // We only push double registers on MIPS. So, if we've stored f0-double
+ // we also want to f0-float32 is stored there.
+ void alignedAliased(uint32_t aliasIdx, FloatRegister* ret) {
+ MOZ_ASSERT(isDouble());
+ MOZ_ASSERT((code_ & 1) == 0);
+ if (aliasIdx == 0) {
+ *ret = *this;
+ return;
+ }
+ MOZ_ASSERT(aliasIdx == 1);
+ *ret = singleOverlay(aliasIdx - 1);
+ }
+
+ SetType alignedOrDominatedAliasedSet() const {
+ if (isSingle())
+ return SetType(1) << code_;
+
+ MOZ_ASSERT(isDouble());
+ return SetType(0b11) << code_;
+ }
+
+ static Code FromName(const char* name) {
+ return FloatRegisters::FromName(name);
+ }
+ static TypedRegisterSet<FloatRegister> ReduceSetForPush(const TypedRegisterSet<FloatRegister>& s);
+ static uint32_t GetPushSizeInBytes(const TypedRegisterSet<FloatRegister>& s);
+ uint32_t getRegisterDumpOffsetInBytes();
+};
+
+// In order to handle functions such as int(*)(int, double) where the first
+// argument is a general purpose register, and the second argument is a floating
+// point register, we have to store the double content into 2 general purpose
+// registers, namely a2 and a3.
+#define JS_CODEGEN_REGISTER_PAIR 1
+
+} // namespace jit
+} // namespace js
+
+#endif /* jit_mips32_Architecture_mips32_h */