src/lj_opt_sink.c - luajit-2.0-src

Functions defined

Macros defined

Source code

  1. /*
  2. ** SINK: Allocation Sinking and Store Sinking.
  3. ** Copyright (C) 2005-2015 Mike Pall. See Copyright Notice in luajit.h
  4. */

  5. #define lj_opt_sink_c
  6. #define LUA_CORE

  7. #include "lj_obj.h"

  8. #if LJ_HASJIT

  9. #include "lj_ir.h"
  10. #include "lj_jit.h"
  11. #include "lj_iropt.h"
  12. #include "lj_target.h"

  13. /* Some local macros to save typing. Undef'd at the end. */
  14. #define IR(ref)                (&J->cur.ir[(ref)])

  15. /* Check whether the store ref points to an eligible allocation. */
  16. static IRIns *sink_checkalloc(jit_State *J, IRIns *irs)
  17. {
  18.   IRIns *ir = IR(irs->op1);
  19.   if (!irref_isk(ir->op2))
  20.     return NULL/* Non-constant key. */
  21.   if (ir->o == IR_HREFK || ir->o == IR_AREF)
  22.     ir = IR(ir->op1);
  23.   else if (!(ir->o == IR_HREF || ir->o == IR_NEWREF ||
  24.              ir->o == IR_FREF || ir->o == IR_ADD))
  25.     return NULL/* Unhandled reference type (for XSTORE). */
  26.   ir = IR(ir->op1);
  27.   if (!(ir->o == IR_TNEW || ir->o == IR_TDUP || ir->o == IR_CNEW))
  28.     return NULL/* Not an allocation. */
  29.   return ir;  /* Return allocation. */
  30. }

  31. /* Recursively check whether a value depends on a PHI. */
  32. static int sink_phidep(jit_State *J, IRRef ref)
  33. {
  34.   IRIns *ir = IR(ref);
  35.   if (irt_isphi(ir->t)) return 1;
  36.   if (ir->op1 >= REF_FIRST && sink_phidep(J, ir->op1)) return 1;
  37.   if (ir->op2 >= REF_FIRST && sink_phidep(J, ir->op2)) return 1;
  38.   return 0;
  39. }

  40. /* Check whether a value is a sinkable PHI or loop-invariant. */
  41. static int sink_checkphi(jit_State *J, IRIns *ira, IRRef ref)
  42. {
  43.   if (ref >= REF_FIRST) {
  44.     IRIns *ir = IR(ref);
  45.     if (irt_isphi(ir->t) || (ir->o == IR_CONV && ir->op2 == IRCONV_NUM_INT &&
  46.                              irt_isphi(IR(ir->op1)->t))) {
  47.       ira->prev++;
  48.       return 1/* Sinkable PHI. */
  49.     }
  50.     /* Otherwise the value must be loop-invariant. */
  51.     return ref < J->loopref && !sink_phidep(J, ref);
  52.   }
  53.   return 1/* Constant (non-PHI). */
  54. }

  55. /* Mark non-sinkable allocations using single-pass backward propagation.
  56. **
  57. ** Roots for the marking process are:
  58. ** - Some PHIs or snapshots (see below).
  59. ** - Non-PHI, non-constant values stored to PHI allocations.
  60. ** - All guards.
  61. ** - Any remaining loads not eliminated by store-to-load forwarding.
  62. ** - Stores with non-constant keys.
  63. ** - All stored values.
  64. */
  65. static void sink_mark_ins(jit_State *J)
  66. {
  67.   IRIns *ir, *irlast = IR(J->cur.nins-1);
  68.   for (ir = irlast ; ; ir--) {
  69.     switch (ir->o) {
  70.     case IR_BASE:
  71.       return/* Finished. */
  72.     case IR_CALLL:  /* IRCALL_lj_tab_len */
  73.     case IR_ALOAD: case IR_HLOAD: case IR_XLOAD: case IR_TBAR:
  74.       irt_setmark(IR(ir->op1)->t);  /* Mark ref for remaining loads. */
  75.       break;
  76.     case IR_FLOAD:
  77.       if (irt_ismarked(ir->t) || ir->op2 == IRFL_TAB_META)
  78.         irt_setmark(IR(ir->op1)->t);  /* Mark table for remaining loads. */
  79.       break;
  80.     case IR_ASTORE: case IR_HSTORE: case IR_FSTORE: case IR_XSTORE: {
  81.       IRIns *ira = sink_checkalloc(J, ir);
  82.       if (!ira || (irt_isphi(ira->t) && !sink_checkphi(J, ira, ir->op2)))
  83.         irt_setmark(IR(ir->op1)->t);  /* Mark ineligible ref. */
  84.       irt_setmark(IR(ir->op2)->t);  /* Mark stored value. */
  85.       break;
  86.       }
  87. #if LJ_HASFFI
  88.     case IR_CNEWI:
  89.       if (irt_isphi(ir->t) &&
  90.           (!sink_checkphi(J, ir, ir->op2) ||
  91.            (LJ_32 && ir+1 < irlast && (ir+1)->o == IR_HIOP &&
  92.             !sink_checkphi(J, ir, (ir+1)->op2))))
  93.         irt_setmark(ir->t);  /* Mark ineligible allocation. */
  94.       /* fallthrough */
  95. #endif
  96.     case IR_USTORE:
  97.       irt_setmark(IR(ir->op2)->t);  /* Mark stored value. */
  98.       break;
  99. #if LJ_HASFFI
  100.     case IR_CALLXS:
  101. #endif
  102.     case IR_CALLS:
  103.       irt_setmark(IR(ir->op1)->t);  /* Mark (potentially) stored values. */
  104.       break;
  105.     case IR_PHI: {
  106.       IRIns *irl = IR(ir->op1), *irr = IR(ir->op2);
  107.       irl->prev = irr->prev = 0/* Clear PHI value counts. */
  108.       if (irl->o == irr->o &&
  109.           (irl->o == IR_TNEW || irl->o == IR_TDUP ||
  110.            (LJ_HASFFI && (irl->o == IR_CNEW || irl->o == IR_CNEWI))))
  111.         break;
  112.       irt_setmark(irl->t);
  113.       irt_setmark(irr->t);
  114.       break;
  115.       }
  116.     default:
  117.       if (irt_ismarked(ir->t) || irt_isguard(ir->t)) {  /* Propagate mark. */
  118.         if (ir->op1 >= REF_FIRST) irt_setmark(IR(ir->op1)->t);
  119.         if (ir->op2 >= REF_FIRST) irt_setmark(IR(ir->op2)->t);
  120.       }
  121.       break;
  122.     }
  123.   }
  124. }

  125. /* Mark all instructions referenced by a snapshot. */
  126. static void sink_mark_snap(jit_State *J, SnapShot *snap)
  127. {
  128.   SnapEntry *map = &J->cur.snapmap[snap->mapofs];
  129.   MSize n, nent = snap->nent;
  130.   for (n = 0; n < nent; n++) {
  131.     IRRef ref = snap_ref(map[n]);
  132.     if (!irref_isk(ref))
  133.       irt_setmark(IR(ref)->t);
  134.   }
  135. }

  136. /* Iteratively remark PHI refs with differing marks or PHI value counts. */
  137. static void sink_remark_phi(jit_State *J)
  138. {
  139.   IRIns *ir;
  140.   int remark;
  141.   do {
  142.     remark = 0;
  143.     for (ir = IR(J->cur.nins-1); ir->o == IR_PHI; ir--) {
  144.       IRIns *irl = IR(ir->op1), *irr = IR(ir->op2);
  145.       if (((irl->t.irt ^ irr->t.irt) & IRT_MARK))
  146.         remark = 1;
  147.       else if (irl->prev == irr->prev)
  148.         continue;
  149.       irt_setmark(IR(ir->op1)->t);
  150.       irt_setmark(IR(ir->op2)->t);
  151.     }
  152.   } while (remark);
  153. }

  154. /* Sweep instructions and tag sunken allocations and stores. */
  155. static void sink_sweep_ins(jit_State *J)
  156. {
  157.   IRIns *ir, *irfirst = IR(J->cur.nk);
  158.   for (ir = IR(J->cur.nins-1) ; ir >= irfirst; ir--) {
  159.     switch (ir->o) {
  160.     case IR_ASTORE: case IR_HSTORE: case IR_FSTORE: case IR_XSTORE: {
  161.       IRIns *ira = sink_checkalloc(J, ir);
  162.       if (ira && !irt_ismarked(ira->t)) {
  163.         int delta = (int)(ir - ira);
  164.         ir->prev = REGSP(RID_SINK, delta > 255 ? 255 : delta);
  165.       } else {
  166.         ir->prev = REGSP_INIT;
  167.       }
  168.       break;
  169.       }
  170.     case IR_NEWREF:
  171.       if (!irt_ismarked(IR(ir->op1)->t)) {
  172.         ir->prev = REGSP(RID_SINK, 0);
  173.       } else {
  174.         irt_clearmark(ir->t);
  175.         ir->prev = REGSP_INIT;
  176.       }
  177.       break;
  178. #if LJ_HASFFI
  179.     case IR_CNEW: case IR_CNEWI:
  180. #endif
  181.     case IR_TNEW: case IR_TDUP:
  182.       if (!irt_ismarked(ir->t)) {
  183.         ir->t.irt &= ~IRT_GUARD;
  184.         ir->prev = REGSP(RID_SINK, 0);
  185.         J->cur.sinktags = 1/* Signal present SINK tags to assembler. */
  186.       } else {
  187.         irt_clearmark(ir->t);
  188.         ir->prev = REGSP_INIT;
  189.       }
  190.       break;
  191.     case IR_PHI: {
  192.       IRIns *ira = IR(ir->op2);
  193.       if (!irt_ismarked(ira->t) &&
  194.           (ira->o == IR_TNEW || ira->o == IR_TDUP ||
  195.            (LJ_HASFFI && (ira->o == IR_CNEW || ira->o == IR_CNEWI)))) {
  196.         ir->prev = REGSP(RID_SINK, 0);
  197.       } else {
  198.         ir->prev = REGSP_INIT;
  199.       }
  200.       break;
  201.       }
  202.     default:
  203.       irt_clearmark(ir->t);
  204.       ir->prev = REGSP_INIT;
  205.       break;
  206.     }
  207.   }
  208. }

  209. /* Allocation sinking and store sinking.
  210. **
  211. ** 1. Mark all non-sinkable allocations.
  212. ** 2. Then sink all remaining allocations and the related stores.
  213. */
  214. void lj_opt_sink(jit_State *J)
  215. {
  216.   const uint32_t need = (JIT_F_OPT_SINK|JIT_F_OPT_FWD|
  217.                          JIT_F_OPT_DCE|JIT_F_OPT_CSE|JIT_F_OPT_FOLD);
  218.   if ((J->flags & need) == need &&
  219.       (J->chain[IR_TNEW] || J->chain[IR_TDUP] ||
  220.        (LJ_HASFFI && (J->chain[IR_CNEW] || J->chain[IR_CNEWI])))) {
  221.     if (!J->loopref)
  222.       sink_mark_snap(J, &J->cur.snap[J->cur.nsnap-1]);
  223.     sink_mark_ins(J);
  224.     if (J->loopref)
  225.       sink_remark_phi(J);
  226.     sink_sweep_ins(J);
  227.   }
  228. }

  229. #undef IR

  230. #endif