summaryrefslogtreecommitdiffstats
path: root/js/src/jit/mips64/Architecture-mips64.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit/mips64/Architecture-mips64.h')
-rw-r--r--js/src/jit/mips64/Architecture-mips64.h233
1 files changed, 233 insertions, 0 deletions
diff --git a/js/src/jit/mips64/Architecture-mips64.h b/js/src/jit/mips64/Architecture-mips64.h
new file mode 100644
index 0000000000..d3db37ea2c
--- /dev/null
+++ b/js/src/jit/mips64/Architecture-mips64.h
@@ -0,0 +1,233 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * 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_mips64_Architecture_mips64_h
+#define jit_mips64_Architecture_mips64_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 MIPS64.
+static const uint32_t ShadowStackSpace = 0;
+
+// MIPS64 have 64 bit floating-point coprocessor. There are 32 double
+// precision register which can also be used as single precision registers.
+class FloatRegisters : public FloatRegistersMIPSShared {
+ public:
+ enum ContentType { Single, Double, NumTypes };
+
+ static const char* GetName(uint32_t i) {
+ MOZ_ASSERT(i < TotalPhys);
+ return FloatRegistersMIPSShared::GetName(Encoding(i));
+ }
+
+ static Encoding FromName(const char* name);
+
+ static const uint32_t Total = 32 * NumTypes;
+#ifdef MIPSR6
+ static const uint32_t Allocatable = 60;
+#else
+ static const uint32_t Allocatable = 62;
+#endif
+ // When saving all registers we only need to do is save double registers.
+ static const uint32_t TotalPhys = 32;
+
+ static_assert(sizeof(SetType) * 8 >= Total,
+ "SetType should be large enough to enumerate all registers.");
+
+ // Magic values which are used to duplicate a mask of physical register for
+ // a specific type of register. A multiplication is used to copy and shift
+ // the bits of the physical register mask.
+ static const SetType SpreadSingle = SetType(1)
+ << (uint32_t(Single) * TotalPhys);
+ static const SetType SpreadDouble = SetType(1)
+ << (uint32_t(Double) * TotalPhys);
+ static const SetType SpreadScalar = SpreadSingle | SpreadDouble;
+ static const SetType SpreadVector = 0;
+ static const SetType Spread = SpreadScalar | SpreadVector;
+
+ static const SetType AllPhysMask = ((SetType(1) << TotalPhys) - 1);
+ static const SetType AllMask = AllPhysMask * Spread;
+ static const SetType AllSingleMask = AllPhysMask * SpreadSingle;
+ static const SetType AllDoubleMask = AllPhysMask * SpreadDouble;
+
+ static const SetType NonVolatileMask =
+ ((1U << FloatRegisters::f24) | (1U << FloatRegisters::f25) |
+ (1U << FloatRegisters::f26) | (1U << FloatRegisters::f27) |
+ (1U << FloatRegisters::f28) | (1U << FloatRegisters::f29) |
+ (1U << FloatRegisters::f30) | (1U << FloatRegisters::f31)) *
+ SpreadScalar |
+ AllPhysMask * SpreadVector;
+
+ static const SetType VolatileMask = AllMask & ~NonVolatileMask;
+
+ static const SetType WrapperMask = VolatileMask;
+
+#ifdef MIPSR6
+ static const SetType NonAllocatableMask =
+ ((1U << FloatRegisters::f23) | (1U << FloatRegisters::f24)) * Spread;
+#else
+ static const SetType NonAllocatableMask =
+ (1U << FloatRegisters::f23) * Spread;
+#endif
+
+ static const SetType AllocatableMask = AllMask & ~NonAllocatableMask;
+};
+
+template <typename T>
+class TypedRegisterSet;
+
+class FloatRegister : public FloatRegisterMIPSShared {
+ public:
+ typedef FloatRegisters Codes;
+ typedef size_t Code;
+ typedef Codes::Encoding Encoding;
+ typedef Codes::ContentType ContentType;
+
+ Encoding reg_ : 6;
+
+ private:
+ ContentType kind_ : 3;
+
+ public:
+ constexpr FloatRegister(uint32_t r, ContentType kind = Codes::Double)
+ : reg_(Encoding(r)), kind_(kind) {}
+ constexpr FloatRegister()
+ : reg_(Encoding(FloatRegisters::invalid_freg)), kind_(Codes::Double) {}
+
+ static uint32_t SetSize(SetType x) {
+ // Count the number of non-aliased registers.
+ x |= x >> Codes::TotalPhys;
+ x &= Codes::AllPhysMask;
+ static_assert(Codes::AllPhysMask <= 0xffffffff,
+ "We can safely use CountPopulation32");
+ return mozilla::CountPopulation32(x);
+ }
+
+ bool operator==(const FloatRegister& other) const {
+ MOZ_ASSERT(!isInvalid());
+ MOZ_ASSERT(!other.isInvalid());
+ return kind_ == other.kind_ && reg_ == other.reg_;
+ }
+ bool equiv(const FloatRegister& other) const { return other.kind_ == kind_; }
+ size_t size() const {
+ return (kind_ == Codes::Double) ? sizeof(double) : sizeof(float);
+ }
+ // Always push doubles to maintain 8-byte stack alignment.
+ size_t pushSize() const { return sizeof(double); }
+ bool isInvalid() const { return reg_ == FloatRegisters::invalid_freg; }
+
+ bool isSingle() const { return kind_ == Codes::Single; }
+ bool isDouble() const { return kind_ == Codes::Double; }
+ bool isSimd128() const { return false; }
+
+ FloatRegister singleOverlay() const;
+ FloatRegister doubleOverlay() 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(reg_ | (kind_ << 5));
+ }
+ Encoding encoding() const {
+ MOZ_ASSERT(!isInvalid());
+ MOZ_ASSERT(uint32_t(reg_) < Codes::TotalPhys);
+ return reg_;
+ }
+ uint32_t id() const { return reg_; }
+ static FloatRegister FromCode(uint32_t i) {
+ uint32_t code = i & 0x1f;
+ uint32_t kind = i >> 5;
+ return FloatRegister(Code(code), ContentType(kind));
+ }
+
+ bool volatile_() const {
+ return !!((1 << reg_) & FloatRegisters::VolatileMask);
+ }
+ const char* name() const { return FloatRegisters::GetName(reg_); }
+ bool operator!=(const FloatRegister& other) const {
+ return kind_ != other.kind_ || reg_ != other.reg_;
+ }
+ bool aliases(const FloatRegister& other) { return reg_ == other.reg_; }
+ uint32_t numAliased() const { return 2; }
+ FloatRegister aliased(uint32_t aliasIdx) {
+ if (aliasIdx == 0) {
+ return *this;
+ }
+ MOZ_ASSERT(aliasIdx == 1);
+ if (isDouble()) {
+ return singleOverlay();
+ }
+ return doubleOverlay();
+ }
+ uint32_t numAlignedAliased() const { return 2; }
+ FloatRegister alignedAliased(uint32_t aliasIdx) {
+ MOZ_ASSERT(isDouble());
+ if (aliasIdx == 0) {
+ return *this;
+ }
+ MOZ_ASSERT(aliasIdx == 1);
+ return singleOverlay();
+ }
+
+ SetType alignedOrDominatedAliasedSet() const { return Codes::Spread << reg_; }
+
+ static constexpr RegTypeName DefaultType = RegTypeName::Float64;
+
+ template <RegTypeName = DefaultType>
+ static SetType LiveAsIndexableSet(SetType s) {
+ return SetType(0);
+ }
+
+ template <RegTypeName Name = DefaultType>
+ static SetType AllocatableAsIndexableSet(SetType s) {
+ static_assert(Name != RegTypeName::Any, "Allocatable set are not iterable");
+ return LiveAsIndexableSet<Name>(s);
+ }
+
+ 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();
+};
+
+template <>
+inline FloatRegister::SetType
+FloatRegister::LiveAsIndexableSet<RegTypeName::Float32>(SetType set) {
+ return set & FloatRegisters::AllSingleMask;
+}
+
+template <>
+inline FloatRegister::SetType
+FloatRegister::LiveAsIndexableSet<RegTypeName::Float64>(SetType set) {
+ return set & FloatRegisters::AllDoubleMask;
+}
+
+template <>
+inline FloatRegister::SetType
+FloatRegister::LiveAsIndexableSet<RegTypeName::Any>(SetType set) {
+ return set;
+}
+
+} // namespace jit
+} // namespace js
+
+#endif /* jit_mips64_Architecture_mips64_h */