2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #ifndef incl_HPHP_VM_LINEAR_SCAN_H_
18 #define incl_HPHP_VM_LINEAR_SCAN_H_
20 #include "hphp/runtime/vm/translator/hopt/state_vector.h"
21 #include "hphp/runtime/vm/translator/physreg.h"
22 #include "hphp/runtime/vm/translator/abi-x64.h"
24 namespace HPHP
{ namespace JIT
{
29 // This value must be consistent with the number of pre-allocated
30 // bytes for spill locations in __enterTCHelper in translator-x64.cpp.
31 // Be careful when changing this value.
32 const int NumPreAllocatedSpillLocs
= 64;
35 UseInfo() : lastUse(0), count(0) {}
36 uint32_t lastUse
; // linear id of last use
37 uint32_t count
; // number of uses
40 typedef StateVector
<IRInstruction
, uint32_t> LinearIdVector
;
41 typedef StateVector
<SSATmp
, UseInfo
> UsesVector
;
44 explicit LifetimeInfo(const IRFactory
* factory
)
45 : linear(factory
, 0), uses(factory
, UseInfo()) {
47 explicit LifetimeInfo(const LinearIdVector
& linear
,
48 const UsesVector
& uses
)
49 : linear(linear
), uses(uses
) {
51 explicit LifetimeInfo(LinearIdVector
&& linear
,
53 : linear(linear
), uses(uses
) {
56 LinearIdVector linear
; // linear id of each instruction
57 UsesVector uses
; // last use id and use count of each tmp
60 // Information about one spilled value.
62 explicit SpillInfo(uint32_t v
) : m_val(v
) {
66 // Return logical slot number
67 uint32_t slot() const {
72 bool isValid() const {
73 return int(m_val
) != int(Transl::InvalidReg
);
76 // return the offset from RSP for this slot; takes into account
77 // the native stack layout.
84 // Register allocation info about one SSATmp
86 enum { kMaxNumRegs
= 2 };
92 m_regs
[0] = m_regs
[1] = Transl::InvalidReg
;
96 * Returns whether or not a given register index is allocated to a
97 * register, or returns false if it is spilled.
99 * Right now, we only spill both at the same time and only Spill and
100 * Reload instructions need to deal with SSATmps that are spilled.
102 bool hasReg(uint32_t i
= 0) const {
103 return !m_isSpilled
&& m_regs
[i
] != Transl::InvalidReg
;
107 * The number of regs actually allocated to this SSATmp. This might
108 * end up fewer than numNeededRegs if the SSATmp isn't really
111 int numAllocatedRegs() const;
114 * Access to allocated registers.
116 * Returns InvalidReg for slots that aren't allocated.
118 PhysReg
getReg() const {
119 assert(!m_isSpilled
);
123 PhysReg
getReg(uint32_t i
) const {
124 assert(!m_isSpilled
);
128 void setReg(PhysReg reg
, uint32_t i
) {
129 assert(!m_isSpilled
);
134 * Used when the SSATmp needs two 64-bit registers and got assigned
135 * one 128-bit XMM register.
137 void setRegFullXMM(PhysReg reg
) {
139 assert(!m_isSpilled
);
144 bool spilled() const {
149 * Returns whether the SSATmp needed 2 regs and was allocated to a
150 * whole 128-bit XMM register.
152 bool isFullXMM() const {
156 /* Returns the set of registers in this RegisterInfo */
157 RegSet
getRegs() const;
160 * Returns information about how to spill/fill a SSATmp.
162 * These functions are only valid if this SSATmp is being spilled or
163 * filled. In all normal instructions (i.e. other than Spill and
164 * Reload), SSATmps are assigned registers instead of spill
167 void setSpillInfo(int i
, SpillInfo si
) {
168 assert(si
.isValid());
173 SpillInfo
getSpillInfo(int idx
) const {
175 return m_spillInfo
[idx
];
182 PhysReg m_regs
[kMaxNumRegs
];
183 SpillInfo m_spillInfo
[kMaxNumRegs
];
187 struct RegAllocInfo
{
188 explicit RegAllocInfo(const IRFactory
* factory
)
189 : m_regs(factory
, RegisterInfo()) {}
190 RegAllocInfo(const RegAllocInfo
& other
) : m_regs(other
.m_regs
) {}
191 RegAllocInfo(RegAllocInfo
&& other
) : m_regs(other
.m_regs
) {}
192 RegisterInfo
& operator[](const SSATmp
* k
) { return m_regs
[k
]; }
193 RegisterInfo
& operator[](const SSATmp
& k
) { return m_regs
[k
]; }
194 const RegisterInfo
& operator[](const SSATmp
* k
) const { return m_regs
[k
]; }
195 const RegisterInfo
& operator[](const SSATmp
& k
) const { return m_regs
[k
]; }
197 StateVector
<SSATmp
, RegisterInfo
> m_regs
;
200 inline std::ostream
& operator<<(std::ostream
& os
, SpillInfo si
) {
201 os
<< "spill[" << si
.slot() << "]";
206 * The main entry point for register allocation. Called prior to code
209 RegAllocInfo
allocRegsForTrace(Trace
*, IRFactory
*, LifetimeInfo
* = nullptr);
211 // Native stack layout:
214 // | | <-- spill[5..]
215 // | pre allocated | <-- spill[4]
216 // | (16 slots) | <-- spill[3]
221 // We need to increase spill indexes by 1 to avoid overwriting the
225 * compute the offset from RSP for a logical spill slot. Given a logical
226 * slot number, return a byte offset from RSP, taking into account the layout
227 * above. LinearScan punts if any extra spill locations would be required,
228 * so all we really need to do is adjust for the return address and scale
229 * by the machine word size.
231 inline int SpillInfo::offset() const {
232 return (m_val
+ 1) * sizeof(uint64_t);