ljx

FORK: LuaJIT with native 5.2 and 5.3 support
git clone https://git.neptards.moe/neptards/ljx.git
Log | Files | Refs | README

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