lj_emit_ppc.h (7074B)
1 /* 2 ** PPC instruction emitter. 3 ** Copyright (C) 2005-2016 Mike Pall. See Copyright Notice in luajit.h 4 */ 5 6 /* -- Emit basic instructions --------------------------------------------- */ 7 8 static void emit_tab(ASMState *as, PPCIns pi, Reg rt, Reg ra, Reg rb) 9 { 10 *--as->mcp = pi | PPCF_T(rt) | PPCF_A(ra) | PPCF_B(rb); 11 } 12 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)) 16 17 static void emit_tai(ASMState *as, PPCIns pi, Reg rt, Reg ra, int32_t i) 18 { 19 *--as->mcp = pi | PPCF_T(rt) | PPCF_A(ra) | (i & 0xffff); 20 } 21 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)) 25 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)) 34 35 static void emit_rot(ASMState *as, PPCIns pi, Reg ra, Reg rs, 36 int32_t n, int32_t b, int32_t e) 37 { 38 *--as->mcp = pi | PPCF_T(rs) | PPCF_A(ra) | PPCF_B(n) | 39 PPCF_MB(b) | PPCF_ME(e); 40 } 41 42 static void emit_slwi(ASMState *as, Reg ra, Reg rs, int32_t n) 43 { 44 lua_assert(n >= 0 && n < 32); 45 emit_rot(as, PPCI_RLWINM, ra, rs, n, 0, 31-n); 46 } 47 48 static void emit_rotlwi(ASMState *as, Reg ra, Reg rs, int32_t n) 49 { 50 lua_assert(n >= 0 && n < 32); 51 emit_rot(as, PPCI_RLWINM, ra, rs, n, 0, 31); 52 } 53 54 /* -- Emit loads/stores --------------------------------------------------- */ 55 56 /* Prefer rematerialization of BASE/L from global_State over spills. */ 57 #define emit_canremat(ref) ((ref) <= REF_BASE) 58 59 /* Try to find a one step delta relative to another constant. */ 60 static int emit_kdelta1(ASMState *as, Reg t, int32_t i) 61 { 62 RegSet work = ~as->freeset & RSET_GPR; 63 while (work) { 64 Reg r = rset_picktop(work); 65 IRRef ref = regcost_ref(as->cost[r]); 66 lua_assert(r != t); 67 if (ref < ASMREF_L) { 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); 71 return 1; 72 } 73 } 74 rset_clear(work, r); 75 } 76 return 0; /* Failed. */ 77 } 78 79 /* Load a 32 bit constant into a GPR. */ 80 static void emit_loadi(ASMState *as, Reg r, int32_t i) 81 { 82 if (checki16(i)) { 83 emit_ti(as, PPCI_LI, r, i); 84 } else { 85 if ((i & 0xffff)) { 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); 89 return; 90 } else if (emit_kdelta1(as, r, i)) { 91 return; 92 } 93 emit_asi(as, PPCI_ORI, r, r, i); 94 } 95 emit_ti(as, PPCI_LIS, r, (i >> 16)); 96 } 97 } 98 99 #define emit_loada(as, r, addr) emit_loadi(as, (r), i32ptr((addr))) 100 101 static Reg ra_allock(ASMState *as, int32_t k, RegSet allow); 102 103 /* Get/set from constant pointer. */ 104 static void emit_lsptr(ASMState *as, PPCIns pi, Reg r, void *p, RegSet allow) 105 { 106 int32_t jgl = i32ptr(J2G(as->J)); 107 int32_t i = i32ptr(p); 108 Reg base; 109 if ((uint32_t)(i-jgl) < 65536) { 110 i = i-jgl-32768; 111 base = RID_JGL; 112 } else { 113 base = ra_allock(as, i-(int16_t)i, allow); 114 } 115 emit_tai(as, pi, r, base, i); 116 } 117 118 #define emit_loadk64(as, r, ir) \ 119 emit_lsptr(as, PPCI_LFD, ((r) & 31), (void *)&ir_knum((ir))->u64, RSET_GPR) 120 121 /* Get/set global_State fields. */ 122 static void emit_lsglptr(ASMState *as, PPCIns pi, Reg r, int32_t ofs) 123 { 124 emit_tai(as, pi, r, RID_JGL, ofs-32768); 125 } 126 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)) 131 132 /* Trace number is determined from per-trace exit stubs. */ 133 #define emit_setvmstate(as, i) UNUSED(i) 134 135 /* -- Emit control-flow instructions -------------------------------------- */ 136 137 /* Label for internal jumps. */ 138 typedef MCode *MCLabel; 139 140 /* Return label pointing to current PC. */ 141 #define emit_label(as) ((as)->mcp) 142 143 static void emit_condbranch(ASMState *as, PPCIns pi, PPCCC cc, MCode *target) 144 { 145 MCode *p = --as->mcp; 146 ptrdiff_t delta = (char *)target - (char *)p; 147 lua_assert(((delta + 0x8000) >> 16) == 0); 148 pi ^= (delta & 0x8000) * (PPCF_Y/0x8000); 149 *p = pi | PPCF_CC(cc) | ((uint32_t)delta & 0xffffu); 150 } 151 152 static void emit_jmp(ASMState *as, MCode *target) 153 { 154 MCode *p = --as->mcp; 155 ptrdiff_t delta = (char *)target - (char *)p; 156 *p = PPCI_B | (delta & 0x03fffffcu); 157 } 158 159 static void emit_call(ASMState *as, void *target) 160 { 161 MCode *p = --as->mcp; 162 ptrdiff_t delta = (char *)target - (char *)p; 163 if ((((delta>>2) + 0x00800000) >> 24) == 0) { 164 *p = PPCI_BL | (delta & 0x03fffffcu); 165 } else { /* Target out of range: need indirect call. Don't use arg reg. */ 166 RegSet allow = RSET_GPR & ~RSET_RANGE(RID_R0, REGARG_LASTGPR+1); 167 Reg r = ra_allock(as, i32ptr(target), allow); 168 *p = PPCI_BCTRL; 169 p[-1] = PPCI_MTCTR | PPCF_T(r); 170 as->mcp = p-1; 171 } 172 } 173 174 /* -- Emit generic operations --------------------------------------------- */ 175 176 #define emit_mr(as, dst, src) \ 177 emit_asb(as, PPCI_MR, (dst), (src), (src)) 178 179 /* Generic move between two regs. */ 180 static void emit_movrr(ASMState *as, IRIns *ir, Reg dst, Reg src) 181 { 182 UNUSED(ir); 183 if (dst < RID_MAX_GPR) 184 emit_mr(as, dst, src); 185 else 186 emit_fb(as, PPCI_FMR, dst, src); 187 } 188 189 /* Generic load of register with base and (small) offset address. */ 190 static void emit_loadofs(ASMState *as, IRIns *ir, Reg r, Reg base, int32_t ofs) 191 { 192 if (r < RID_MAX_GPR) 193 emit_tai(as, PPCI_LWZ, r, base, ofs); 194 else 195 emit_fai(as, irt_isnum(ir->t) ? PPCI_LFD : PPCI_LFS, r, base, ofs); 196 } 197 198 /* Generic store of register with base and (small) offset address. */ 199 static void emit_storeofs(ASMState *as, IRIns *ir, Reg r, Reg base, int32_t ofs) 200 { 201 if (r < RID_MAX_GPR) 202 emit_tai(as, PPCI_STW, r, base, ofs); 203 else 204 emit_fai(as, irt_isnum(ir->t) ? PPCI_STFD : PPCI_STFS, r, base, ofs); 205 } 206 207 /* Emit a compare (for equality) with a constant operand. */ 208 static void emit_cmpi(ASMState *as, Reg r, int32_t k) 209 { 210 if (checki16(k)) { 211 emit_ai(as, PPCI_CMPWI, r, k); 212 } else if (checku16(k)) { 213 emit_ai(as, PPCI_CMPLWI, r, k); 214 } else { 215 emit_ai(as, PPCI_CMPLWI, RID_TMP, k); 216 emit_asi(as, PPCI_XORIS, RID_TMP, r, (k >> 16)); 217 } 218 } 219 220 /* Add offset to pointer. */ 221 static void emit_addptr(ASMState *as, Reg r, int32_t ofs) 222 { 223 if (ofs) { 224 emit_tai(as, PPCI_ADDI, r, r, ofs); 225 if (!checki16(ofs)) 226 emit_tai(as, PPCI_ADDIS, r, r, (ofs + 32768) >> 16); 227 } 228 } 229 230 static void emit_spsub(ASMState *as, int32_t ofs) 231 { 232 if (ofs) { 233 emit_tai(as, PPCI_STWU, RID_TMP, RID_SP, -ofs); 234 emit_tai(as, PPCI_ADDI, RID_TMP, RID_SP, 235 CFRAME_SIZE + (as->parent ? as->parent->spadjust : 0)); 236 } 237 } 238