Clean up code-gen control flow helpers
[hiphop-php.git] / hphp / runtime / vm / jit / mc-generator-internal.h
blobea29e07cf4828a281a1f65513f24e103275a5a85
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2014 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 +----------------------------------------------------------------------+
16 #ifndef incl_HPHP_MC_GENERATOR_INTERNAL_H_
17 #define incl_HPHP_MC_GENERATOR_INTERNAL_H_
19 #include <boost/filesystem.hpp>
20 #include <boost/utility/typed_in_place_factory.hpp>
22 #include "hphp/runtime/vm/jit/abi-x64.h"
23 #include "hphp/runtime/vm/jit/translator-inline.h"
24 #include "hphp/runtime/vm/jit/vasm-emit.h"
25 #include "hphp/runtime/vm/jit/vasm-instr.h"
26 #include "hphp/runtime/vm/jit/vasm-reg.h"
28 namespace HPHP { namespace jit {
29 ///////////////////////////////////////////////////////////////////////////////
31 // Helper structs for jcc vs. jcc8.
32 struct Jcc8 {
33 static void branch(X64Assembler& a, ConditionCode cc, TCA dest) {
34 a. jcc8(cc, dest);
36 static void patch(X64Assembler& a, TCA site, TCA newDest) {
37 a.patchJcc8(site, newDest);
41 struct Jcc32 {
42 static void branch(X64Assembler& a, ConditionCode cc, TCA dest) {
43 a. jcc(cc, dest);
45 static void patch(X64Assembler& a, TCA site, TCA newDest) {
46 a.patchJcc(site, newDest);
50 // A CondBlock is an RAII structure for emitting conditional code. It
51 // compares the source register at fieldOffset with fieldValue, and
52 // conditionally branches over the enclosing block of assembly on the
53 // passed-in condition-code.
55 // E.g.:
56 // {
57 // RefCountedOnly ifRefCounted(a, rdi, 0);
58 // emitIncRef(rdi);
59 // }
61 // will only execute emitIncRef if we find at runtime that rdi points at
62 // a ref-counted cell.
64 // It's ok to do reconcilable register operations in the body.
65 template<unsigned FieldOffset, int32_t FieldValue, ConditionCode Jcc,
66 typename FieldType>
67 struct CondBlock {
68 X64Assembler& m_a;
69 int m_off;
70 TCA m_jcc8;
72 CondBlock(X64Assembler& a, PhysReg reg, int offset = 0)
73 : m_a(a)
74 , m_off(offset) {
75 int typeDisp = m_off + FieldOffset;
76 static_assert(sizeof(FieldType) == 1 || sizeof(FieldType) == 4,
77 "CondBlock of unimplemented field size");
78 if (sizeof(FieldType) == 4) {
79 a. cmpl(FieldValue, reg[typeDisp]);
80 } else if (sizeof(FieldType) == 1) {
81 a. cmpb(FieldValue, reg[typeDisp]);
83 m_jcc8 = a.frontier();
84 a. jcc8(Jcc, m_jcc8);
85 // ...
88 ~CondBlock() {
89 m_a.patchJcc8(m_jcc8, m_a.frontier());
93 // IfRefCounted --
94 // Emits if (IS_REFCOUNTED_TYPE()) { ... }
95 typedef CondBlock <TVOFF(m_type),
96 KindOfRefCountThreshold,
97 CC_LE,
98 DataType> IfRefCounted;
100 typedef CondBlock <TVOFF(m_type),
101 KindOfRef,
102 CC_NZ,
103 DataType> IfVariant;
105 typedef CondBlock <TVOFF(m_type),
106 KindOfUninit,
107 CC_Z,
108 DataType> UnlessUninit;
111 * locToRegDisp --
113 * Helper code for stack frames. The struct is a "template" in the
114 * non-C++ sense: we don't build source-level stack frames in C++
115 * for the most part, but its offsets tell us where to find fields
116 * in assembly.
118 * If we were physically pushing stack frames, we would push them
119 * in reverse order to what you see here.
121 static inline void
122 locToRegDisp(int32_t localIndex, PhysReg *outbase, int *outdisp) {
123 *outdisp = cellsToBytes(locPhysicalOffset(localIndex));
124 *outbase = x64::rVmFp;
127 // Common code emission patterns.
129 static_assert(sizeof(DataType) == 1,
130 "Your DataType has an unsupported size.");
131 static inline Reg8 toByte(const Reg32& x) { return rbyte(x); }
132 static inline Reg8 toByte(const Reg64& x) { return rbyte(x); }
133 static inline Reg8 toByte(PhysReg x) { return rbyte(Reg64(x)); }
135 static inline Reg32 toReg32(const Reg64& x) { return r32(x); }
136 static inline Reg32 toReg32(const Reg8& x) { return r32(x); }
137 static inline Reg32 toReg32(PhysReg x) { return r32(Reg64(x)); }
139 // For other operand types, let whatever conversions (or compile
140 // errors) exist handle it.
141 template<typename OpndType>
142 static OpndType toByte(const OpndType& x) { return x; }
143 template<typename OpndType>
144 static OpndType toReg32(const OpndType& x) { return x; }
146 template<typename OpndType>
147 static inline void verifyTVOff(const OpndType& op) { /* nop */ }
148 static inline void verifyTVOff(MemoryRef mr) {
149 DEBUG_ONLY auto disp = mr.r.disp;
150 // Make sure that we're operating on the m_type field of a
151 // TypedValue*.
152 assertx((disp & (sizeof(TypedValue) - 1)) == TVOFF(m_type));
155 template<typename SrcType, typename OpndType>
156 void emitTestTVType(X64Assembler& a, SrcType src, OpndType tvOp) {
157 a. testb(src, toByte(tvOp));
160 inline void emitTestTVType(Vout& v, Vreg sf, Immed s0, Vreg s1) {
161 v << testbi{s0, s1, sf};
164 inline void emitTestTVType(Vout& v, Vreg sf, Immed s0, Vptr s1) {
165 v << testbim{s0, s1, sf};
168 template<typename SrcType, typename OpndType>
169 static inline void
170 emitLoadTVType(X64Assembler& a, SrcType src, OpndType tvOp) {
171 // Zero extend the type, just in case.
172 a. loadzbl(src, toReg32(tvOp));
175 inline void emitLoadTVType(Vout& v, Vptr mem, Vreg d) {
176 v << loadzbq{mem, d};
179 template<typename SrcType, typename OpndType>
180 void emitCmpTVType(X64Assembler& a, SrcType src, OpndType tvOp) {
181 a. cmpb(src, toByte(tvOp));
184 inline void emitCmpTVType(Vout& v, Vreg sf, Immed s0, Vptr s1) {
185 v << cmpbim{s0, s1, sf};
188 inline void emitCmpTVType(Vout& v, Vreg sf, Immed s0, Vreg s1) {
189 v << cmpbi{s0, s1, sf};
192 template<typename DestType, typename OpndType>
193 void emitStoreTVType(X64Assembler& a, OpndType tvOp, DestType dest) {
194 a. storeb(toByte(tvOp), dest);
197 inline void emitStoreTVType(Vout& v, Vreg src, Vptr dest) {
198 v << storeb{src, dest};
201 inline void
202 emitStoreTVType(Vout& v, DataType src, Vptr dest) {
203 v << storebi{src, dest};
206 // emitDeref --
207 // emitStoreTypedValue --
208 // emitStoreUninitNull --
210 // Helpers for common cell operations.
212 // Dereference the var in the cell whose address lives in src into
213 // dest.
214 static inline void
215 emitDeref(X64Assembler &a, PhysReg src, PhysReg dest) {
216 // src is a RefData, dest will be m_data field of inner gizmoom.
217 a. loadq (src[TVOFF(m_data)], dest);
220 // NB: leaves count field unmodified. Does not store to m_data if type
221 // is a null type.
222 static inline void
223 emitStoreTypedValue(X64Assembler& a, DataType type, PhysReg val,
224 int disp, PhysReg dest, bool writeType = true) {
225 if (writeType) {
226 emitStoreTVType(a, type, dest[disp + TVOFF(m_type)]);
228 if (!IS_NULL_TYPE(type)) {
229 assertx(val != InvalidReg);
230 a. storeq(val, dest[disp + TVOFF(m_data)]);
234 static inline void
235 emitStoreUninitNull(X64Assembler& a,
236 int disp,
237 PhysReg dest) {
238 // OK to leave garbage in m_data, m_aux.
239 emitStoreTVType(a, KindOfUninit, dest[disp + TVOFF(m_type)]);
242 static inline void
243 emitCopyTo(X64Assembler& a,
244 Reg64 src,
245 int srcOff,
246 Reg64 dest,
247 int destOff,
248 PhysReg scratch) {
249 assertx(src != scratch);
250 // This is roughly how gcc compiles this. Blow off m_aux.
251 a. loadq (src[srcOff + TVOFF(m_data)], scratch);
252 a. storeq (scratch, dest[destOff + TVOFF(m_data)]);
253 emitLoadTVType(a, src[srcOff + TVOFF(m_type)], r32(scratch));
254 emitStoreTVType(a, r32(scratch), dest[destOff + TVOFF(m_type)]);
257 ///////////////////////////////////////////////////////////////////////////////
260 #endif