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_opt_sink.c (7252B)


      1 /*
      2 ** SINK: Allocation Sinking and Store Sinking.
      3 ** Copyright (C) 2005-2016 Mike Pall. See Copyright Notice in luajit.h
      4 */
      5 
      6 #define lj_opt_sink_c
      7 #define LUA_CORE
      8 
      9 #include "lj_obj.h"
     10 
     11 #if LJ_HASJIT
     12 
     13 #include "lj_ir.h"
     14 #include "lj_jit.h"
     15 #include "lj_iropt.h"
     16 #include "lj_target.h"
     17 
     18 /* Some local macros to save typing. Undef'd at the end. */
     19 #define IR(ref)		(&J->cur.ir[(ref)])
     20 
     21 /* Check whether the store ref points to an eligible allocation. */
     22 static IRIns *sink_checkalloc(jit_State *J, IRIns *irs)
     23 {
     24   IRIns *ir = IR(irs->op1);
     25   if (!irref_isk(ir->op2))
     26     return NULL;  /* Non-constant key. */
     27   if (ir->o == IR_HREFK || ir->o == IR_AREF)
     28     ir = IR(ir->op1);
     29   else if (!(ir->o == IR_HREF || ir->o == IR_NEWREF ||
     30 	     ir->o == IR_FREF || ir->o == IR_ADD))
     31     return NULL;  /* Unhandled reference type (for XSTORE). */
     32   ir = IR(ir->op1);
     33   if (!(ir->o == IR_TNEW || ir->o == IR_TDUP || ir->o == IR_CNEW))
     34     return NULL;  /* Not an allocation. */
     35   return ir;  /* Return allocation. */
     36 }
     37 
     38 /* Recursively check whether a value depends on a PHI. */
     39 static int sink_phidep(jit_State *J, IRRef ref)
     40 {
     41   IRIns *ir = IR(ref);
     42   if (irt_isphi(ir->t)) return 1;
     43   if (ir->op1 >= REF_FIRST && sink_phidep(J, ir->op1)) return 1;
     44   if (ir->op2 >= REF_FIRST && sink_phidep(J, ir->op2)) return 1;
     45   return 0;
     46 }
     47 
     48 /* Check whether a value is a sinkable PHI or loop-invariant. */
     49 static int sink_checkphi(jit_State *J, IRIns *ira, IRRef ref)
     50 {
     51   if (ref >= REF_FIRST) {
     52     IRIns *ir = IR(ref);
     53     if (irt_isphi(ir->t) || (ir->o == IR_CONV && ir->op2 == IRCONV_NUM_INT &&
     54 			     irt_isphi(IR(ir->op1)->t))) {
     55       ira->prev++;
     56       return 1;  /* Sinkable PHI. */
     57     }
     58     /* Otherwise the value must be loop-invariant. */
     59     return ref < J->loopref && !sink_phidep(J, ref);
     60   }
     61   return 1;  /* Constant (non-PHI). */
     62 }
     63 
     64 /* Mark non-sinkable allocations using single-pass backward propagation.
     65 **
     66 ** Roots for the marking process are:
     67 ** - Some PHIs or snapshots (see below).
     68 ** - Non-PHI, non-constant values stored to PHI allocations.
     69 ** - All guards.
     70 ** - Any remaining loads not eliminated by store-to-load forwarding.
     71 ** - Stores with non-constant keys.
     72 ** - All stored values.
     73 */
     74 static void sink_mark_ins(jit_State *J)
     75 {
     76   IRIns *ir, *irlast = IR(J->cur.nins-1);
     77   for (ir = irlast ; ; ir--) {
     78     switch (ir->o) {
     79     case IR_BASE:
     80       return;  /* Finished. */
     81     case IR_CALLL:  /* IRCALL_lj_tab_len */
     82     case IR_ALOAD: case IR_HLOAD: case IR_XLOAD: case IR_TBAR:
     83       irt_setmark(IR(ir->op1)->t);  /* Mark ref for remaining loads. */
     84       break;
     85     case IR_FLOAD:
     86       if (irt_ismarked(ir->t) || ir->op2 == IRFL_TAB_META)
     87 	irt_setmark(IR(ir->op1)->t);  /* Mark table for remaining loads. */
     88       break;
     89     case IR_ASTORE: case IR_HSTORE: case IR_FSTORE: case IR_XSTORE: {
     90       IRIns *ira = sink_checkalloc(J, ir);
     91       if (!ira || (irt_isphi(ira->t) && !sink_checkphi(J, ira, ir->op2)))
     92 	irt_setmark(IR(ir->op1)->t);  /* Mark ineligible ref. */
     93       irt_setmark(IR(ir->op2)->t);  /* Mark stored value. */
     94       break;
     95       }
     96 #if LJ_HASFFI
     97     case IR_CNEWI:
     98       if (irt_isphi(ir->t) &&
     99 	  (!sink_checkphi(J, ir, ir->op2) ||
    100 	   (LJ_32 && ir+1 < irlast && (ir+1)->o == IR_HIOP &&
    101 	    !sink_checkphi(J, ir, (ir+1)->op2))))
    102 	irt_setmark(ir->t);  /* Mark ineligible allocation. */
    103       /* fallthrough */
    104 #endif
    105     case IR_USTORE:
    106       irt_setmark(IR(ir->op2)->t);  /* Mark stored value. */
    107       break;
    108 #if LJ_HASFFI
    109     case IR_CALLXS:
    110 #endif
    111     case IR_CALLS:
    112       irt_setmark(IR(ir->op1)->t);  /* Mark (potentially) stored values. */
    113       break;
    114     case IR_PHI: {
    115       IRIns *irl = IR(ir->op1), *irr = IR(ir->op2);
    116       irl->prev = irr->prev = 0;  /* Clear PHI value counts. */
    117       if (irl->o == irr->o &&
    118 	  (irl->o == IR_TNEW || irl->o == IR_TDUP ||
    119 	   (LJ_HASFFI && (irl->o == IR_CNEW || irl->o == IR_CNEWI))))
    120 	break;
    121       irt_setmark(irl->t);
    122       irt_setmark(irr->t);
    123       break;
    124       }
    125     default:
    126       if (irt_ismarked(ir->t) || irt_isguard(ir->t)) {  /* Propagate mark. */
    127 	if (ir->op1 >= REF_FIRST) irt_setmark(IR(ir->op1)->t);
    128 	if (ir->op2 >= REF_FIRST) irt_setmark(IR(ir->op2)->t);
    129       }
    130       break;
    131     }
    132   }
    133 }
    134 
    135 /* Mark all instructions referenced by a snapshot. */
    136 static void sink_mark_snap(jit_State *J, SnapShot *snap)
    137 {
    138   SnapEntry *map = &J->cur.snapmap[snap->mapofs];
    139   MSize n, nent = snap->nent;
    140   for (n = 0; n < nent; n++) {
    141     IRRef ref = snap_ref(map[n]);
    142     if (!irref_isk(ref))
    143       irt_setmark(IR(ref)->t);
    144   }
    145 }
    146 
    147 /* Iteratively remark PHI refs with differing marks or PHI value counts. */
    148 static void sink_remark_phi(jit_State *J)
    149 {
    150   IRIns *ir;
    151   int remark;
    152   do {
    153     remark = 0;
    154     for (ir = IR(J->cur.nins-1); ir->o == IR_PHI; ir--) {
    155       IRIns *irl = IR(ir->op1), *irr = IR(ir->op2);
    156       if (!((irl->t.irt ^ irr->t.irt) & IRT_MARK) && irl->prev == irr->prev)
    157 	continue;
    158       remark |= (~(irl->t.irt & irr->t.irt) & IRT_MARK);
    159       irt_setmark(IR(ir->op1)->t);
    160       irt_setmark(IR(ir->op2)->t);
    161     }
    162   } while (remark);
    163 }
    164 
    165 /* Sweep instructions and tag sunken allocations and stores. */
    166 static void sink_sweep_ins(jit_State *J)
    167 {
    168   IRIns *ir, *irbase = IR(REF_BASE);
    169   for (ir = IR(J->cur.nins-1) ; ir >= irbase; ir--) {
    170     switch (ir->o) {
    171     case IR_ASTORE: case IR_HSTORE: case IR_FSTORE: case IR_XSTORE: {
    172       IRIns *ira = sink_checkalloc(J, ir);
    173       if (ira && !irt_ismarked(ira->t)) {
    174 	int delta = (int)(ir - ira);
    175 	ir->prev = REGSP(RID_SINK, delta > 255 ? 255 : delta);
    176       } else {
    177 	ir->prev = REGSP_INIT;
    178       }
    179       break;
    180       }
    181     case IR_NEWREF:
    182       if (!irt_ismarked(IR(ir->op1)->t)) {
    183 	ir->prev = REGSP(RID_SINK, 0);
    184       } else {
    185 	irt_clearmark(ir->t);
    186 	ir->prev = REGSP_INIT;
    187       }
    188       break;
    189 #if LJ_HASFFI
    190     case IR_CNEW: case IR_CNEWI:
    191 #endif
    192     case IR_TNEW: case IR_TDUP:
    193       if (!irt_ismarked(ir->t)) {
    194 	ir->t.irt &= ~IRT_GUARD;
    195 	ir->prev = REGSP(RID_SINK, 0);
    196 	J->cur.sinktags = 1;  /* Signal present SINK tags to assembler. */
    197       } else {
    198 	irt_clearmark(ir->t);
    199 	ir->prev = REGSP_INIT;
    200       }
    201       break;
    202     case IR_PHI: {
    203       IRIns *ira = IR(ir->op2);
    204       if (!irt_ismarked(ira->t) &&
    205 	  (ira->o == IR_TNEW || ira->o == IR_TDUP ||
    206 	   (LJ_HASFFI && (ira->o == IR_CNEW || ira->o == IR_CNEWI)))) {
    207 	ir->prev = REGSP(RID_SINK, 0);
    208       } else {
    209 	ir->prev = REGSP_INIT;
    210       }
    211       break;
    212       }
    213     default:
    214       irt_clearmark(ir->t);
    215       ir->prev = REGSP_INIT;
    216       break;
    217     }
    218   }
    219   for (ir = IR(J->cur.nk); ir < irbase; ir++) {
    220     irt_clearmark(ir->t);
    221     ir->prev = REGSP_INIT;
    222     if (irt_is64(ir->t) && ir->o != IR_KNULL)
    223       ir++;
    224   }
    225 }
    226 
    227 /* Allocation sinking and store sinking.
    228 **
    229 ** 1. Mark all non-sinkable allocations.
    230 ** 2. Then sink all remaining allocations and the related stores.
    231 */
    232 void lj_opt_sink(jit_State *J)
    233 {
    234   const uint32_t need = (JIT_F_OPT_SINK|JIT_F_OPT_FWD|
    235 			 JIT_F_OPT_DCE|JIT_F_OPT_CSE|JIT_F_OPT_FOLD);
    236   if ((J->flags & need) == need &&
    237       (J->chain[IR_TNEW] || J->chain[IR_TDUP] ||
    238        (LJ_HASFFI && (J->chain[IR_CNEW] || J->chain[IR_CNEWI])))) {
    239     if (!J->loopref)
    240       sink_mark_snap(J, &J->cur.snap[J->cur.nsnap-1]);
    241     sink_mark_ins(J);
    242     if (J->loopref)
    243       sink_remark_phi(J);
    244     sink_sweep_ins(J);
    245   }
    246 }
    247 
    248 #undef IR
    249 
    250 #endif