1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim: set ts=8 sts=4 et sw=4 tw=99:
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef jit_mips64_Architecture_mips64_h
8 #define jit_mips64_Architecture_mips64_h
9 
10 #include "mozilla/MathAlgorithms.h"
11 
12 #include <limits.h>
13 #include <stdint.h>
14 
15 #include "jit/mips-shared/Architecture-mips-shared.h"
16 
17 #include "js/Utility.h"
18 
19 namespace js {
20 namespace jit {
21 
22 // Shadow stack space is not required on MIPS64.
23 static const uint32_t ShadowStackSpace = 0;
24 
25 // MIPS64 have 64 bit floating-point coprocessor. There are 32 double
26 // precision register which can also be used as single precision registers.
27 class FloatRegisters : public FloatRegistersMIPSShared
28 {
29   public:
30     enum ContentType {
31         Single,
32         Double,
33         NumTypes
34     };
35 
36     static const char* GetName(uint32_t i) {
37         MOZ_ASSERT(i < TotalPhys);
38         return FloatRegistersMIPSShared::GetName(Encoding(i));
39     }
40 
41     static Encoding FromName(const char* name);
42 
43     static const uint32_t Total = 32 * NumTypes;
44     static const uint32_t Allocatable = 60;
45     // When saving all registers we only need to do is save double registers.
46     static const uint32_t TotalPhys = 32;
47 
48     static_assert(sizeof(SetType) * 8 >= Total,
49                   "SetType should be large enough to enumerate all registers.");
50 
51     // Magic values which are used to duplicate a mask of physical register for
52     // a specific type of register. A multiplication is used to copy and shift
53     // the bits of the physical register mask.
54     static const SetType SpreadSingle = SetType(1) << (uint32_t(Single) * TotalPhys);
55     static const SetType SpreadDouble = SetType(1) << (uint32_t(Double) * TotalPhys);
56     static const SetType SpreadScalar = SpreadSingle | SpreadDouble;
57     static const SetType SpreadVector = 0;
58     static const SetType Spread = SpreadScalar | SpreadVector;
59 
60     static const SetType AllPhysMask = ((SetType(1) << TotalPhys) - 1);
61     static const SetType AllMask = AllPhysMask * Spread;
62     static const SetType AllSingleMask = AllPhysMask * SpreadSingle;
63     static const SetType AllDoubleMask = AllPhysMask * SpreadDouble;
64 
65     static const SetType NonVolatileMask =
66         ( (1U << FloatRegisters::f24) |
67           (1U << FloatRegisters::f25) |
68           (1U << FloatRegisters::f26) |
69           (1U << FloatRegisters::f27) |
70           (1U << FloatRegisters::f28) |
71           (1U << FloatRegisters::f29) |
72           (1U << FloatRegisters::f30) |
73           (1U << FloatRegisters::f31)
74         ) * SpreadScalar
75         | AllPhysMask * SpreadVector;
76 
77     static const SetType VolatileMask = AllMask & ~NonVolatileMask;
78 
79     static const SetType WrapperMask = VolatileMask;
80 
81     static const SetType NonAllocatableMask =
82         ( // f21 and f23 are MIPS scratch float registers.
83           (1U << FloatRegisters::f21) |
84           (1U << FloatRegisters::f23)
85         ) * Spread;
86 
87     // Registers that can be allocated without being saved, generally.
88     static const SetType TempMask = VolatileMask & ~NonAllocatableMask;
89 
90     static const SetType AllocatableMask = AllMask & ~NonAllocatableMask;
91 };
92 
93 template <typename T>
94 class TypedRegisterSet;
95 
96 class FloatRegister : public FloatRegisterMIPSShared
97 {
98   public:
99     typedef FloatRegisters Codes;
100     typedef size_t Code;
101     typedef Codes::Encoding Encoding;
102     typedef Codes::ContentType ContentType;
103 
104     Encoding reg_: 6;
105   private:
106     ContentType kind_ : 3;
107 
108   public:
109     constexpr FloatRegister(uint32_t r, ContentType kind = Codes::Double)
110       : reg_(Encoding(r)), kind_(kind)
111     { }
112     constexpr FloatRegister()
113       : reg_(Encoding(FloatRegisters::invalid_freg)), kind_(Codes::Double)
114     { }
115 
116     bool operator==(const FloatRegister& other) const {
117         MOZ_ASSERT(!isInvalid());
118         MOZ_ASSERT(!other.isInvalid());
119         return kind_ == other.kind_ && reg_ == other.reg_;
120     }
121     bool equiv(const FloatRegister& other) const { return other.kind_ == kind_; }
122     size_t size() const { return (kind_ == Codes::Double) ? sizeof(double) : sizeof (float); }
123     bool isInvalid() const {
124         return reg_ == FloatRegisters::invalid_freg;
125     }
126 
127     bool isSingle() const { return kind_ == Codes::Single; }
128     bool isDouble() const { return kind_ == Codes::Double; }
129 
130     FloatRegister singleOverlay() const;
131     FloatRegister doubleOverlay() const;
132 
133     FloatRegister asSingle() const { return singleOverlay(); }
134     FloatRegister asDouble() const { return doubleOverlay(); }
135     FloatRegister asSimd128() const { MOZ_CRASH("NYI"); }
136 
137     Code code() const {
138         MOZ_ASSERT(!isInvalid());
139         return Code(reg_ | (kind_ << 5));
140     }
141     Encoding encoding() const {
142         MOZ_ASSERT(!isInvalid());
143         MOZ_ASSERT(uint32_t(reg_) < Codes::TotalPhys);
144         return reg_;
145     }
146     uint32_t id() const {
147         return reg_;
148     }
149     static FloatRegister FromCode(uint32_t i) {
150         uint32_t code = i & 0x1f;
151         uint32_t kind = i >> 5;
152         return FloatRegister(Code(code), ContentType(kind));
153     }
154 
155     bool volatile_() const {
156         return !!((1 << reg_) & FloatRegisters::VolatileMask);
157     }
158     const char* name() const {
159         return FloatRegisters::GetName(reg_);
160     }
161     bool operator != (const FloatRegister& other) const {
162         return kind_ != other.kind_ || reg_ != other.reg_;
163     }
164     bool aliases(const FloatRegister& other) {
165         return reg_ == other.reg_;
166     }
167     uint32_t numAliased() const {
168         return 2;
169     }
170     void aliased(uint32_t aliasIdx, FloatRegister* ret) {
171         if (aliasIdx == 0) {
172             *ret = *this;
173             return;
174         }
175         MOZ_ASSERT(aliasIdx == 1);
176         if (isDouble())
177           *ret = singleOverlay();
178         else
179           *ret = doubleOverlay();
180     }
181     uint32_t numAlignedAliased() const {
182         return 2;
183     }
184     void alignedAliased(uint32_t aliasIdx, FloatRegister* ret) {
185         MOZ_ASSERT(isDouble());
186         if (aliasIdx == 0) {
187             *ret = *this;
188             return;
189         }
190         MOZ_ASSERT(aliasIdx == 1);
191         *ret = singleOverlay();
192     }
193 
194     SetType alignedOrDominatedAliasedSet() const {
195         return Codes::Spread << reg_;
196     }
197 
198     static Code FromName(const char* name) {
199         return FloatRegisters::FromName(name);
200     }
201     static TypedRegisterSet<FloatRegister> ReduceSetForPush(const TypedRegisterSet<FloatRegister>& s);
202     static uint32_t GetPushSizeInBytes(const TypedRegisterSet<FloatRegister>& s);
203     uint32_t getRegisterDumpOffsetInBytes();
204 };
205 
206 } // namespace jit
207 } // namespace js
208 
209 #endif /* jit_mips64_Architecture_mips64_h */
210