1/*
2 * Copyright (C) 2015-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(B3_JIT)
29
30#include "B3Bank.h"
31#include "FPRInfo.h"
32#include "GPRInfo.h"
33#include "Reg.h"
34#include <wtf/HashMap.h>
35
36namespace JSC { namespace B3 { namespace Air {
37
38class Arg;
39class Code;
40
41// A Tmp is a generalization of a register. It can be used to refer to any GPR or FPR. It can also
42// be used to refer to an unallocated register (i.e. a temporary). Like many Air classes, we use
43// deliberately terse naming since we will have to use this name a lot.
44
45class Tmp {
46public:
47 constexpr Tmp()
48 : m_value(0)
49 {
50 }
51
52 explicit Tmp(Reg reg)
53 {
54 if (reg) {
55 if (reg.isGPR())
56 m_value = encodeGPR(reg.gpr());
57 else
58 m_value = encodeFPR(reg.fpr());
59 } else
60 m_value = 0;
61 }
62
63 explicit Tmp(const Arg&);
64
65 static Tmp gpTmpForIndex(unsigned index)
66 {
67 Tmp result;
68 result.m_value = encodeGPTmp(index);
69 return result;
70 }
71
72 static Tmp fpTmpForIndex(unsigned index)
73 {
74 Tmp result;
75 result.m_value = encodeFPTmp(index);
76 return result;
77 }
78
79 static Tmp tmpForIndex(Bank bank, unsigned index)
80 {
81 if (bank == GP)
82 return gpTmpForIndex(index);
83 ASSERT(bank == FP);
84 return fpTmpForIndex(index);
85 }
86
87 explicit operator bool() const { return !!m_value; }
88
89 bool isGP() const
90 {
91 return isEncodedGP(m_value);
92 }
93
94 bool isFP() const
95 {
96 return isEncodedFP(m_value);
97 }
98
99 // For null tmps, returns GP.
100 Bank bank() const
101 {
102 return isFP() ? FP : GP;
103 }
104
105 bool isGPR() const
106 {
107 return isEncodedGPR(m_value);
108 }
109
110 bool isFPR() const
111 {
112 return isEncodedFPR(m_value);
113 }
114
115 bool isReg() const
116 {
117 return isGPR() || isFPR();
118 }
119
120 GPRReg gpr() const
121 {
122 return decodeGPR(m_value);
123 }
124
125 FPRReg fpr() const
126 {
127 return decodeFPR(m_value);
128 }
129
130 Reg reg() const
131 {
132 if (isGP())
133 return gpr();
134 return fpr();
135 }
136
137 bool hasTmpIndex() const
138 {
139 return !isReg();
140 }
141
142 unsigned gpTmpIndex() const
143 {
144 return decodeGPTmp(m_value);
145 }
146
147 unsigned fpTmpIndex() const
148 {
149 return decodeFPTmp(m_value);
150 }
151
152 unsigned tmpIndex(Bank bank) const
153 {
154 if (bank == GP)
155 return gpTmpIndex();
156 ASSERT(bank == FP);
157 return fpTmpIndex();
158 }
159
160 unsigned tmpIndex() const
161 {
162 if (isGP())
163 return gpTmpIndex();
164 return fpTmpIndex();
165 }
166
167 template<Bank bank> class Indexed;
168 template<Bank bank> class AbsolutelyIndexed;
169 class LinearlyIndexed;
170
171 template<Bank bank>
172 Indexed<bank> indexed() const;
173
174 template<Bank bank>
175 AbsolutelyIndexed<bank> absolutelyIndexed() const;
176
177 LinearlyIndexed linearlyIndexed(Code&) const;
178
179 static unsigned indexEnd(Code&, Bank);
180 static unsigned absoluteIndexEnd(Code&, Bank);
181 static unsigned linearIndexEnd(Code&);
182
183 bool isAlive() const
184 {
185 return !!*this;
186 }
187
188 bool operator==(const Tmp& other) const
189 {
190 return m_value == other.m_value;
191 }
192
193 bool operator!=(const Tmp& other) const
194 {
195 return !(*this == other);
196 }
197
198 void dump(PrintStream& out) const;
199
200 Tmp(WTF::HashTableDeletedValueType)
201 : m_value(std::numeric_limits<int>::max())
202 {
203 }
204
205 bool isHashTableDeletedValue() const
206 {
207 return *this == Tmp(WTF::HashTableDeletedValue);
208 }
209
210 unsigned hash() const
211 {
212 return WTF::IntHash<int>::hash(m_value);
213 }
214
215 unsigned internalValue() const { return static_cast<unsigned>(m_value); }
216
217 static Tmp tmpForInternalValue(unsigned index)
218 {
219 Tmp result;
220 result.m_value = static_cast<int>(index);
221 return result;
222 }
223
224 static Tmp tmpForAbsoluteIndex(Bank, unsigned);
225
226 static Tmp tmpForLinearIndex(Code&, unsigned);
227
228private:
229 static int encodeGP(unsigned index)
230 {
231 return 1 + index;
232 }
233
234 static int encodeFP(unsigned index)
235 {
236 return -1 - index;
237 }
238
239 static int encodeGPR(GPRReg gpr)
240 {
241 return encodeGP(gpr - MacroAssembler::firstRegister());
242 }
243
244 static int encodeFPR(FPRReg fpr)
245 {
246 return encodeFP(fpr - MacroAssembler::firstFPRegister());
247 }
248
249 static int encodeGPTmp(unsigned index)
250 {
251 return encodeGPR(MacroAssembler::lastRegister()) + 1 + index;
252 }
253
254 static int encodeFPTmp(unsigned index)
255 {
256 return encodeFPR(MacroAssembler::lastFPRegister()) - 1 - index;
257 }
258
259 static bool isEncodedGP(int value)
260 {
261 return value > 0;
262 }
263
264 static bool isEncodedFP(int value)
265 {
266 return value < 0;
267 }
268
269 static bool isEncodedGPR(int value)
270 {
271 return isEncodedGP(value) && value <= encodeGPR(MacroAssembler::lastRegister());
272 }
273
274 static bool isEncodedFPR(int value)
275 {
276 return isEncodedFP(value) && value >= encodeFPR(MacroAssembler::lastFPRegister());
277 }
278
279 static bool isEncodedGPTmp(int value)
280 {
281 return isEncodedGP(value) && !isEncodedGPR(value);
282 }
283
284 static bool isEncodedFPTmp(int value)
285 {
286 return isEncodedFP(value) && !isEncodedFPR(value);
287 }
288
289 static GPRReg decodeGPR(int value)
290 {
291 ASSERT(isEncodedGPR(value));
292 return static_cast<GPRReg>(
293 (value - encodeGPR(MacroAssembler::firstRegister())) + MacroAssembler::firstRegister());
294 }
295
296 static FPRReg decodeFPR(int value)
297 {
298 ASSERT(isEncodedFPR(value));
299 return static_cast<FPRReg>(
300 (encodeFPR(MacroAssembler::firstFPRegister()) - value) +
301 MacroAssembler::firstFPRegister());
302 }
303
304 static unsigned decodeGPTmp(int value)
305 {
306 ASSERT(isEncodedGPTmp(value));
307 return value - (encodeGPR(MacroAssembler::lastRegister()) + 1);
308 }
309
310 static unsigned decodeFPTmp(int value)
311 {
312 ASSERT(isEncodedFPTmp(value));
313 return (encodeFPR(MacroAssembler::lastFPRegister()) - 1) - value;
314 }
315
316 // 0: empty Tmp
317 // positive: GPRs and then GP temps.
318 // negative: FPRs and then FP temps.
319 int m_value;
320};
321
322struct TmpHash {
323 static unsigned hash(const Tmp& key) { return key.hash(); }
324 static bool equal(const Tmp& a, const Tmp& b) { return a == b; }
325 static constexpr bool safeToCompareToEmptyOrDeleted = true;
326};
327
328} } } // namespace JSC::B3::Air
329
330namespace WTF {
331
332template<typename T> struct DefaultHash;
333template<> struct DefaultHash<JSC::B3::Air::Tmp> {
334 typedef JSC::B3::Air::TmpHash Hash;
335};
336
337template<typename T> struct HashTraits;
338template<> struct HashTraits<JSC::B3::Air::Tmp> : SimpleClassHashTraits<JSC::B3::Air::Tmp> { };
339
340} // namespace WTF
341
342#endif // ENABLE(B3_JIT)
343