2 ** PPC instruction emitter.
3 ** Copyright (C) 2005-2012 Mike Pall. See Copyright Notice in luajit.h
6 /* -- Emit basic instructions --------------------------------------------- */
8 static void emit_tab(ASMState
*as
, PPCIns pi
, Reg rt
, Reg ra
, Reg rb
)
10 *--as
->mcp
= pi
| PPCF_T(rt
) | PPCF_A(ra
) | PPCF_B(rb
);
13 #define emit_asb(as, pi, ra, rs, rb) emit_tab(as, (pi), (rs), (ra), (rb))
14 #define emit_as(as, pi, ra, rs) emit_tab(as, (pi), (rs), (ra), 0)
15 #define emit_ab(as, pi, ra, rb) emit_tab(as, (pi), 0, (ra), (rb))
17 static void emit_tai(ASMState
*as
, PPCIns pi
, Reg rt
, Reg ra
, int32_t i
)
19 *--as
->mcp
= pi
| PPCF_T(rt
) | PPCF_A(ra
) | (i
& 0xffff);
22 #define emit_ti(as, pi, rt, i) emit_tai(as, (pi), (rt), 0, (i))
23 #define emit_ai(as, pi, ra, i) emit_tai(as, (pi), 0, (ra), (i))
24 #define emit_asi(as, pi, ra, rs, i) emit_tai(as, (pi), (rs), (ra), (i))
26 #define emit_fab(as, pi, rf, ra, rb) \
27 emit_tab(as, (pi), (rf)&31, (ra)&31, (rb)&31)
28 #define emit_fb(as, pi, rf, rb) emit_tab(as, (pi), (rf)&31, 0, (rb)&31)
29 #define emit_fac(as, pi, rf, ra, rc) \
30 emit_tab(as, (pi) | PPCF_C((rc) & 31), (rf)&31, (ra)&31, 0)
31 #define emit_facb(as, pi, rf, ra, rc, rb) \
32 emit_tab(as, (pi) | PPCF_C((rc) & 31), (rf)&31, (ra)&31, (rb)&31)
33 #define emit_fai(as, pi, rf, ra, i) emit_tai(as, (pi), (rf)&31, (ra), (i))
35 static void emit_rot(ASMState
*as
, PPCIns pi
, Reg ra
, Reg rs
,
36 int32_t n
, int32_t b
, int32_t e
)
38 *--as
->mcp
= pi
| PPCF_T(rs
) | PPCF_A(ra
) | PPCF_B(n
) |
39 PPCF_MB(b
) | PPCF_ME(e
);
42 static void emit_slwi(ASMState
*as
, Reg ra
, Reg rs
, int32_t n
)
44 lua_assert(n
>= 0 && n
< 32);
45 emit_rot(as
, PPCI_RLWINM
, ra
, rs
, n
, 0, 31-n
);
48 static void emit_rotlwi(ASMState
*as
, Reg ra
, Reg rs
, int32_t n
)
50 lua_assert(n
>= 0 && n
< 32);
51 emit_rot(as
, PPCI_RLWINM
, ra
, rs
, n
, 0, 31);
54 /* -- Emit loads/stores --------------------------------------------------- */
56 /* Prefer rematerialization of BASE/L from global_State over spills. */
57 #define emit_canremat(ref) ((ref) <= REF_BASE)
59 /* Try to find a one step delta relative to another constant. */
60 static int emit_kdelta1(ASMState
*as
, Reg t
, int32_t i
)
62 RegSet work
= ~as
->freeset
& RSET_GPR
;
64 Reg r
= rset_picktop(work
);
65 IRRef ref
= regcost_ref(as
->cost
[r
]);
68 int32_t delta
= i
- (ra_iskref(ref
) ? ra_krefk(as
, ref
) : IR(ref
)->i
);
69 if (checki16(delta
)) {
70 emit_tai(as
, PPCI_ADDI
, t
, r
, delta
);
76 return 0; /* Failed. */
79 /* Load a 32 bit constant into a GPR. */
80 static void emit_loadi(ASMState
*as
, Reg r
, int32_t i
)
83 emit_ti(as
, PPCI_LI
, r
, i
);
86 int32_t jgl
= i32ptr(J2G(as
->J
));
87 if ((uint32_t)(i
-jgl
) < 65536) {
88 emit_tai(as
, PPCI_ADDI
, r
, RID_JGL
, i
-jgl
-32768);
90 } else if (emit_kdelta1(as
, r
, i
)) {
93 emit_asi(as
, PPCI_ORI
, r
, r
, i
);
95 emit_ti(as
, PPCI_LIS
, r
, (i
>> 16));
99 #define emit_loada(as, r, addr) emit_loadi(as, (r), i32ptr((addr)))
101 static Reg
ra_allock(ASMState
*as
, int32_t k
, RegSet allow
);
103 /* Get/set from constant pointer. */
104 static void emit_lsptr(ASMState
*as
, PPCIns pi
, Reg r
, void *p
, RegSet allow
)
106 int32_t jgl
= i32ptr(J2G(as
->J
));
107 int32_t i
= i32ptr(p
);
109 if ((uint32_t)(i
-jgl
) < 65536) {
113 base
= ra_allock(as
, i
-(int16_t)i
, allow
);
115 emit_tai(as
, pi
, r
, base
, i
);
118 #define emit_loadn(as, r, tv) \
119 emit_lsptr(as, PPCI_LFD, ((r) & 31), (void *)(tv), RSET_GPR)
121 /* Get/set global_State fields. */
122 static void emit_lsglptr(ASMState
*as
, PPCIns pi
, Reg r
, int32_t ofs
)
124 emit_tai(as
, pi
, r
, RID_JGL
, ofs
-32768);
127 #define emit_getgl(as, r, field) \
128 emit_lsglptr(as, PPCI_LWZ, (r), (int32_t)offsetof(global_State, field))
129 #define emit_setgl(as, r, field) \
130 emit_lsglptr(as, PPCI_STW, (r), (int32_t)offsetof(global_State, field))
132 /* Trace number is determined from per-trace exit stubs. */
133 #define emit_setvmstate(as, i) UNUSED(i)
135 /* -- Emit control-flow instructions -------------------------------------- */
137 /* Label for internal jumps. */
138 typedef MCode
*MCLabel
;
140 /* Return label pointing to current PC. */
141 #define emit_label(as) ((as)->mcp)
143 static void emit_condbranch(ASMState
*as
, PPCIns pi
, PPCCC cc
, MCode
*target
)
146 ptrdiff_t delta
= ((char *)target
- (char *)p
) + 4;
147 lua_assert(((delta
+ 0x8000) >> 16) == 0);
148 pi
^= (delta
& 0x8000) * (PPCF_Y
/0x8000);
149 *--p
= pi
| PPCF_CC(cc
) | ((uint32_t)delta
& 0xffffu
);
153 static void emit_call(ASMState
*as
, void *target
)
155 MCode
*p
= --as
->mcp
;
156 ptrdiff_t delta
= (char *)target
- (char *)p
;
157 if ((((delta
>>2) + 0x00800000) >> 24) == 0) {
158 *p
= PPCI_BL
| (delta
& 0x03fffffcu
);
159 } else { /* Target out of range: need indirect call. Don't use arg reg. */
160 RegSet allow
= RSET_GPR
& ~RSET_RANGE(RID_R0
, REGARG_LASTGPR
+1);
161 Reg r
= ra_allock(as
, i32ptr(target
), allow
);
163 p
[-1] = PPCI_MTCTR
| PPCF_T(r
);
168 /* -- Emit generic operations --------------------------------------------- */
170 #define emit_mr(as, dst, src) \
171 emit_asb(as, PPCI_MR, (dst), (src), (src))
173 /* Generic move between two regs. */
174 static void emit_movrr(ASMState
*as
, IRIns
*ir
, Reg dst
, Reg src
)
177 if (dst
< RID_MAX_GPR
)
178 emit_mr(as
, dst
, src
);
180 emit_fb(as
, PPCI_FMR
, dst
, src
);
183 /* Generic load of register from stack slot. */
184 static void emit_spload(ASMState
*as
, IRIns
*ir
, Reg r
, int32_t ofs
)
187 emit_tai(as
, PPCI_LWZ
, r
, RID_SP
, ofs
);
189 emit_fai(as
, irt_isnum(ir
->t
) ? PPCI_LFD
: PPCI_LFS
, r
, RID_SP
, ofs
);
192 /* Generic store of register to stack slot. */
193 static void emit_spstore(ASMState
*as
, IRIns
*ir
, Reg r
, int32_t ofs
)
196 emit_tai(as
, PPCI_STW
, r
, RID_SP
, ofs
);
198 emit_fai(as
, irt_isnum(ir
->t
) ? PPCI_STFD
: PPCI_STFS
, r
, RID_SP
, ofs
);
201 /* Emit a compare (for equality) with a constant operand. */
202 static void emit_cmpi(ASMState
*as
, Reg r
, int32_t k
)
205 emit_ai(as
, PPCI_CMPWI
, r
, k
);
206 } else if (checku16(k
)) {
207 emit_ai(as
, PPCI_CMPLWI
, r
, k
);
209 emit_ai(as
, PPCI_CMPLWI
, RID_TMP
, k
);
210 emit_asi(as
, PPCI_XORIS
, RID_TMP
, r
, (k
>> 16));
214 /* Add offset to pointer. */
215 static void emit_addptr(ASMState
*as
, Reg r
, int32_t ofs
)
218 emit_tai(as
, PPCI_ADDI
, r
, r
, ofs
);
220 emit_tai(as
, PPCI_ADDIS
, r
, r
, (ofs
+ 32768) >> 16);
224 static void emit_spsub(ASMState
*as
, int32_t ofs
)
227 emit_tai(as
, PPCI_STWU
, RID_TMP
, RID_SP
, -ofs
);
228 emit_tai(as
, PPCI_ADDI
, RID_TMP
, RID_SP
,
229 CFRAME_SIZE
+ (as
->parent
? as
->parent
->spadjust
: 0));