]> git.saurik.com Git - apple/javascriptcore.git/blame - dfg/DFGRegisterBank.h
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / dfg / DFGRegisterBank.h
CommitLineData
14957cd0
A
1/*
2 * Copyright (C) 2011 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#ifndef DFGRegisterBank_h
27#define DFGRegisterBank_h
28
29#if ENABLE(DFG_JIT)
30
93a37866 31#include "DFGCommon.h"
81345200
A
32#include "FPRInfo.h"
33#include "GPRInfo.h"
14957cd0
A
34
35namespace JSC { namespace DFG {
36
37// === RegisterBank ===
38//
39// This class is used to implement the GPR and FPR register banks.
40// All registers have two pieces of state associated with them:
41// a lock count (used to indicate this register is already in use
42// in code generation of the current node, and cannot be spilled or
43// allocated as a temporary), and VirtualRegister 'name', recording
44// which value (if any) a machine register currently holds.
45// Either or both of these pieces of information may be valid for a
46// given register. A register may be:
47//
48// - unlocked, and unnamed: Available for allocation.
49// - locked, but unnamed: Already allocated as a temporary or
50// result for the current node.
51// - unlocked, but named: Contains the result of a prior operation,
52// not yet in use for this node,
53// - locked, but named: Contains the result of a prior operation,
54// already allocated as a operand to the
55// current operation.
56//
57// For every named register we also record a hint value indicating
58// the order in which registers should be selected to be spilled;
59// registers that can be more cheaply spilled and/or filled should
60// be selected first.
61//
62// Locking register is a strong retention mechanism; a locked register
63// will never be reallocated (this is used to ensure the operands to
64// the current node are in registers). Naming, conversely, in a weak
65// retention mechanism - allocating a register may force a named value
66// to be spilled.
67//
68// All named values must be given a hint that is greater than Min and
69// less than Max.
70template<class BankInfo>
71class RegisterBank {
72 typedef typename BankInfo::RegisterType RegID;
73 static const size_t NUM_REGS = BankInfo::numberOfRegisters;
74
75 typedef uint32_t SpillHint;
76 static const SpillHint SpillHintInvalid = 0xffffffff;
77
78public:
79 RegisterBank()
14957cd0
A
80 {
81 }
82
6fe7ccc8
A
83 // Attempt to allocate a register - this function finds an unlocked
84 // register, locks it, and returns it. If none can be found, this
85 // returns -1 (InvalidGPRReg or InvalidFPRReg).
86 RegID tryAllocate()
87 {
81345200 88 VirtualRegister ignored = VirtualRegister();
6fe7ccc8 89
93a37866 90 for (uint32_t i = 0; i < NUM_REGS; ++i) {
81345200 91 if (!m_data[i].lockCount && !m_data[i].name.isValid())
6fe7ccc8
A
92 return allocateInternal(i, ignored);
93 }
94
95 return (RegID)-1;
96 }
97
14957cd0
A
98 // Allocate a register - this function finds an unlocked register,
99 // locks it, and returns it. If any named registers exist, one
100 // of these should be selected to be allocated. If all unlocked
101 // registers are named, then one of the named registers will need
102 // to be spilled. In this case the register selected to be spilled
103 // will be one of the registers that has the lowest 'spillOrder'
104 // cost associated with it.
105 //
106 // This method select the register to be allocated, and calls the
107 // private 'allocateInternal' method to update internal data
108 // structures accordingly.
109 RegID allocate(VirtualRegister &spillMe)
110 {
111 uint32_t currentLowest = NUM_REGS;
112 SpillHint currentSpillOrder = SpillHintInvalid;
113
14957cd0
A
114 // This loop is broken into two halves, looping from the last allocated
115 // register (the register returned last time this method was called) to
116 // the maximum register value, then from 0 to the last allocated.
117 // This implements a simple round-robin like approach to try to reduce
118 // thrash, and minimize time spent scanning locked registers in allocation.
119 // If a unlocked and unnamed register is found return it immediately.
120 // Otherwise, find the first unlocked register with the lowest spillOrder.
93a37866 121 for (uint32_t i = 0 ; i < NUM_REGS; ++i) {
14957cd0
A
122 // (1) If the current register is locked, it is not a candidate.
123 if (m_data[i].lockCount)
124 continue;
125 // (2) If the current register's spill order is 0, pick this! – unassigned registers have spill order 0.
126 SpillHint spillOrder = m_data[i].spillOrder;
127 if (spillOrder == SpillHintInvalid)
128 return allocateInternal(i, spillMe);
129 // If this register is better (has a lower spill order value) than any prior
130 // candidate, then record it.
131 if (spillOrder < currentSpillOrder) {
132 currentSpillOrder = spillOrder;
133 currentLowest = i;
134 }
135 }
14957cd0
A
136
137 // Deadlock check - this could only occur is all registers are locked!
138 ASSERT(currentLowest != NUM_REGS && currentSpillOrder != SpillHintInvalid);
139 // There were no available registers; currentLowest will need to be spilled.
140 return allocateInternal(currentLowest, spillMe);
141 }
142
6fe7ccc8
A
143 // Allocates the given register, even if this will force a spill.
144 VirtualRegister allocateSpecific(RegID reg)
145 {
146 unsigned index = BankInfo::toIndex(reg);
147
148 ++m_data[index].lockCount;
149 VirtualRegister name = nameAtIndex(index);
81345200 150 if (name.isValid())
6fe7ccc8
A
151 releaseAtIndex(index);
152
153 return name;
154 }
155
14957cd0
A
156 // retain/release - these methods are used to associate/disassociate names
157 // with values in registers. retain should only be called on locked registers.
158 void retain(RegID reg, VirtualRegister name, SpillHint spillOrder)
159 {
160 unsigned index = BankInfo::toIndex(reg);
161
162 // SpillHint must be valid.
163 ASSERT(spillOrder != SpillHintInvalid);
164 // 'index' must be a valid, locked register.
165 ASSERT(index < NUM_REGS);
166 ASSERT(m_data[index].lockCount);
167 // 'index' should not currently be named, the new name must be valid.
81345200
A
168 ASSERT(!m_data[index].name.isValid());
169 ASSERT(name.isValid());
14957cd0
A
170 // 'index' should not currently have a spillOrder.
171 ASSERT(m_data[index].spillOrder == SpillHintInvalid);
172
173 m_data[index].name = name;
174 m_data[index].spillOrder = spillOrder;
175 }
176 void release(RegID reg)
177 {
178 releaseAtIndex(BankInfo::toIndex(reg));
179 }
180
181 // lock/unlock register, ensures that they are not spilled.
182 void lock(RegID reg)
183 {
184 unsigned index = BankInfo::toIndex(reg);
185
186 ASSERT(index < NUM_REGS);
187 ++m_data[index].lockCount;
188 ASSERT(m_data[index].lockCount);
189 }
190 void unlock(RegID reg)
191 {
192 unsigned index = BankInfo::toIndex(reg);
193
194 ASSERT(index < NUM_REGS);
195 ASSERT(m_data[index].lockCount);
196 --m_data[index].lockCount;
197 }
198 bool isLocked(RegID reg) const
199 {
200 return isLockedAtIndex(BankInfo::toIndex(reg));
201 }
202
203 // Get the name (VirtualRegister) associated with the
81345200 204 // given register (or default VirtualRegister() for none).
14957cd0
A
205 VirtualRegister name(RegID reg) const
206 {
207 return nameAtIndex(BankInfo::toIndex(reg));
208 }
209
93a37866
A
210 bool isInUse(RegID reg) const
211 {
81345200 212 return isLocked(reg) || name(reg).isValid();
93a37866
A
213 }
214
14957cd0
A
215 void dump()
216 {
217 // For each register, print the VirtualRegister 'name'.
218 for (uint32_t i =0; i < NUM_REGS; ++i) {
81345200
A
219 if (m_data[i].name.isValid())
220 dataLogF("[%02d]", m_data[i].name.offset());
14957cd0 221 else
93a37866 222 dataLogF("[--]");
14957cd0 223 }
93a37866 224 dataLogF("\n");
14957cd0 225 }
14957cd0
A
226
227 class iterator {
228 friend class RegisterBank<BankInfo>;
229 public:
230 VirtualRegister name() const
231 {
232 return m_bank->nameAtIndex(m_index);
233 }
234
235 bool isLocked() const
236 {
237 return m_bank->isLockedAtIndex(m_index);
238 }
239
240 void release() const
241 {
242 m_bank->releaseAtIndex(m_index);
243 }
244
245 RegID regID() const
246 {
247 return BankInfo::toRegister(m_index);
248 }
249
250#ifndef NDEBUG
251 const char* debugName() const
252 {
253 return BankInfo::debugName(regID());
254 }
255#endif
256
257 iterator& operator++()
258 {
259 ++m_index;
260 return *this;
261 }
262
263 bool operator!=(const iterator& other) const
264 {
265 ASSERT(m_bank == other.m_bank);
266 return m_index != other.m_index;
267 }
268
269 unsigned index() const
270 {
271 return m_index;
272 }
273
274 private:
275 iterator(RegisterBank<BankInfo>* bank, unsigned index)
276 : m_bank(bank)
277 , m_index(index)
278 {
279 }
280
281 RegisterBank<BankInfo>* m_bank;
282 unsigned m_index;
283 };
284
285 iterator begin()
286 {
287 return iterator(this, 0);
288 }
289
290 iterator end()
291 {
292 return iterator(this, NUM_REGS);
293 }
294
295private:
296 bool isLockedAtIndex(unsigned index) const
297 {
298 ASSERT(index < NUM_REGS);
299 return m_data[index].lockCount;
300 }
301
302 VirtualRegister nameAtIndex(unsigned index) const
303 {
304 ASSERT(index < NUM_REGS);
305 return m_data[index].name;
306 }
307
308 void releaseAtIndex(unsigned index)
309 {
310 // 'index' must be a valid register.
311 ASSERT(index < NUM_REGS);
312 // 'index' should currently be named.
81345200 313 ASSERT(m_data[index].name.isValid());
14957cd0
A
314 // 'index' should currently have a valid spill order.
315 ASSERT(m_data[index].spillOrder != SpillHintInvalid);
316
81345200 317 m_data[index].name = VirtualRegister();
14957cd0
A
318 m_data[index].spillOrder = SpillHintInvalid;
319 }
320
321 // Used by 'allocate', above, to update inforamtion in the map.
322 RegID allocateInternal(uint32_t i, VirtualRegister &spillMe)
323 {
324 // 'i' must be a valid, unlocked register.
325 ASSERT(i < NUM_REGS && !m_data[i].lockCount);
326
327 // Return the VirtualRegister of the named value currently stored in
81345200 328 // the register being returned - or default VirtualRegister() if none.
14957cd0
A
329 spillMe = m_data[i].name;
330
331 // Clear any name/spillOrder currently associated with the register,
332 m_data[i] = MapEntry();
333 // Mark the register as locked (with a lock count of 1).
334 m_data[i].lockCount = 1;
335
14957cd0
A
336 return BankInfo::toRegister(i);
337 }
338
339 // === MapEntry ===
340 //
341 // This structure provides information for an individual machine register
342 // being managed by the RegisterBank. For each register we track a lock
343 // count, name and spillOrder hint.
344 struct MapEntry {
345 MapEntry()
81345200 346 : name(VirtualRegister())
14957cd0
A
347 , spillOrder(SpillHintInvalid)
348 , lockCount(0)
349 {
350 }
351
352 VirtualRegister name;
353 SpillHint spillOrder;
354 uint32_t lockCount;
355 };
356
357 // Holds the current status of all registers.
358 MapEntry m_data[NUM_REGS];
14957cd0
A
359};
360
81345200
A
361typedef RegisterBank<GPRInfo>::iterator gpr_iterator;
362typedef RegisterBank<FPRInfo>::iterator fpr_iterator;
363
14957cd0
A
364} } // namespace JSC::DFG
365
366#endif
367#endif