lj_opt_sink.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. /*
  2. ** SINK: Allocation Sinking and Store Sinking.
  3. ** Copyright (C) 2005-2014 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