1/*
2 * Copyright (C) 2014-2019 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#if ENABLE(ASSEMBLER)
29
30#include "MacroAssembler.h"
31
32namespace JSC {
33
34// Reg is a polymorphic register class. It can refer to either integer or float registers.
35// Here are some use cases:
36//
37// GPRReg gpr;
38// Reg reg = gpr;
39// reg.isSet() == true
40// reg.isGPR() == true
41// reg.isFPR() == false
42//
43// for (Reg reg = Reg::first(); reg <= Reg::last(); reg = reg.next()) {
44// if (reg.isGPR()) {
45// } else /* reg.isFPR() */ {
46// }
47// }
48//
49// The above loop could have also used !!reg or reg.isSet() as a condition.
50
51class Reg {
52public:
53 Reg()
54 : m_index(invalid())
55 {
56 }
57
58 Reg(WTF::HashTableDeletedValueType)
59 : m_index(deleted())
60 {
61 }
62
63 Reg(MacroAssembler::RegisterID reg)
64 : m_index(MacroAssembler::registerIndex(reg))
65 {
66 }
67
68 Reg(MacroAssembler::FPRegisterID reg)
69 : m_index(MacroAssembler::registerIndex(reg))
70 {
71 }
72
73 static Reg fromIndex(unsigned index)
74 {
75 Reg result;
76 result.m_index = index;
77 return result;
78 }
79
80 static Reg first()
81 {
82 Reg result;
83 result.m_index = 0;
84 return result;
85 }
86
87 static Reg last()
88 {
89 Reg result;
90 result.m_index = MacroAssembler::numberOfRegisters() + MacroAssembler::numberOfFPRegisters() - 1;
91 return result;
92 }
93
94 Reg next() const
95 {
96 ASSERT(!!*this);
97 if (*this == last())
98 return Reg();
99 Reg result;
100 result.m_index = m_index + 1;
101 return result;
102 }
103
104 unsigned index() const { return m_index; }
105
106 static unsigned maxIndex()
107 {
108 return last().index();
109 }
110
111 bool isSet() const { return m_index != invalid(); }
112 explicit operator bool() const { return isSet(); }
113
114 bool isHashTableDeletedValue() const { return m_index == deleted(); }
115
116 bool isGPR() const
117 {
118 return m_index < MacroAssembler::numberOfRegisters();
119 }
120
121 bool isFPR() const
122 {
123 return (m_index - MacroAssembler::numberOfRegisters()) < MacroAssembler::numberOfFPRegisters();
124 }
125
126 MacroAssembler::RegisterID gpr() const
127 {
128 ASSERT(isGPR());
129 return static_cast<MacroAssembler::RegisterID>(MacroAssembler::firstRegister() + m_index);
130 }
131
132 MacroAssembler::FPRegisterID fpr() const
133 {
134 ASSERT(isFPR());
135 return static_cast<MacroAssembler::FPRegisterID>(
136 MacroAssembler::firstFPRegister() + (m_index - MacroAssembler::numberOfRegisters()));
137 }
138
139 bool operator==(const Reg& other) const
140 {
141 return m_index == other.m_index;
142 }
143
144 bool operator!=(const Reg& other) const
145 {
146 return m_index != other.m_index;
147 }
148
149 bool operator<(const Reg& other) const
150 {
151 return m_index < other.m_index;
152 }
153
154 bool operator>(const Reg& other) const
155 {
156 return m_index > other.m_index;
157 }
158
159 bool operator<=(const Reg& other) const
160 {
161 return m_index <= other.m_index;
162 }
163
164 bool operator>=(const Reg& other) const
165 {
166 return m_index >= other.m_index;
167 }
168
169 unsigned hash() const
170 {
171 return m_index;
172 }
173
174 const char* debugName() const;
175
176 void dump(PrintStream&) const;
177
178 class AllRegsIterable {
179 public:
180
181 class iterator {
182 public:
183 iterator() { }
184
185 explicit iterator(Reg reg)
186 : m_regIndex(reg.index())
187 {
188 }
189
190 Reg operator*() const { return Reg::fromIndex(m_regIndex); }
191
192 iterator& operator++()
193 {
194 m_regIndex = Reg::fromIndex(m_regIndex).next().index();
195 return *this;
196 }
197
198 bool operator==(const iterator& other) const
199 {
200 return m_regIndex == other.m_regIndex;
201 }
202
203 bool operator!=(const iterator& other) const
204 {
205 return !(*this == other);
206 }
207
208 private:
209 unsigned m_regIndex;
210 };
211
212 iterator begin() const { return iterator(Reg::first()); }
213 iterator end() const { return iterator(Reg()); }
214 };
215
216 static AllRegsIterable all() { return AllRegsIterable(); }
217
218private:
219 static uint8_t invalid() { return 0xff; }
220
221 static uint8_t deleted() { return 0xfe; }
222
223 uint8_t m_index;
224};
225
226struct RegHash {
227 static unsigned hash(const Reg& key) { return key.hash(); }
228 static bool equal(const Reg& a, const Reg& b) { return a == b; }
229 static constexpr bool safeToCompareToEmptyOrDeleted = true;
230};
231
232} // namespace JSC
233
234namespace WTF {
235
236template<typename T> struct DefaultHash;
237template<> struct DefaultHash<JSC::Reg> {
238 typedef JSC::RegHash Hash;
239};
240
241template<typename T> struct HashTraits;
242template<> struct HashTraits<JSC::Reg> : SimpleClassHashTraits<JSC::Reg> {
243 static constexpr bool emptyValueIsZero = false;
244 };
245
246} // namespace WTF
247
248#endif // ENABLE(ASSEMBLER)
249