lj_opt_sink.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. /*
  2. ** SINK: Allocation Sinking and Store Sinking.
  3. ** Copyright (C) 2005-2023 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, int *workp)
  33. {
  34. IRIns *ir = IR(ref);
  35. if (!*workp) return 1; /* Give up and pretend it does. */
  36. (*workp)--;
  37. if (irt_isphi(ir->t)) return 1;
  38. if (ir->op1 >= REF_FIRST && sink_phidep(J, ir->op1, workp)) return 1;
  39. if (ir->op2 >= REF_FIRST && sink_phidep(J, ir->op2, workp)) return 1;
  40. return 0;
  41. }
  42. /* Check whether a value is a sinkable PHI or loop-invariant. */
  43. static int sink_checkphi(jit_State *J, IRIns *ira, IRRef ref)
  44. {
  45. if (ref >= REF_FIRST) {
  46. IRIns *ir = IR(ref);
  47. if (irt_isphi(ir->t) || (ir->o == IR_CONV && ir->op2 == IRCONV_NUM_INT &&
  48. irt_isphi(IR(ir->op1)->t))) {
  49. ira->prev++;
  50. return 1; /* Sinkable PHI. */
  51. }
  52. /* Otherwise the value must be loop-invariant. */
  53. if (ref < J->loopref) {
  54. /* Check for PHI dependencies, but give up after reasonable effort. */
  55. int work = 64;
  56. return !sink_phidep(J, ref, &work);
  57. } else {
  58. return 0; /* Loop-variant. */
  59. }
  60. }
  61. return 1; /* Constant (non-PHI). */
  62. }
  63. /* Mark non-sinkable allocations using single-pass backward propagation.
  64. **
  65. ** Roots for the marking process are:
  66. ** - Some PHIs or snapshots (see below).
  67. ** - Non-PHI, non-constant values stored to PHI allocations.
  68. ** - All guards.
  69. ** - Any remaining loads not eliminated by store-to-load forwarding.
  70. ** - Stores with non-constant keys.
  71. ** - All stored values.
  72. */
  73. static void sink_mark_ins(jit_State *J)
  74. {
  75. IRIns *ir, *irlast = IR(J->cur.nins-1);
  76. for (ir = irlast ; ; ir--) {
  77. switch (ir->o) {
  78. case IR_BASE:
  79. return; /* Finished. */
  80. case IR_ALOAD: case IR_HLOAD: case IR_XLOAD: case IR_TBAR: case IR_ALEN:
  81. irt_setmark(IR(ir->op1)->t); /* Mark ref for remaining loads. */
  82. break;
  83. case IR_FLOAD:
  84. if (irt_ismarked(ir->t) || ir->op2 == IRFL_TAB_META)
  85. irt_setmark(IR(ir->op1)->t); /* Mark table for remaining loads. */
  86. break;
  87. case IR_ASTORE: case IR_HSTORE: case IR_FSTORE: case IR_XSTORE: {
  88. IRIns *ira = sink_checkalloc(J, ir);
  89. if (!ira || (irt_isphi(ira->t) && !sink_checkphi(J, ira, ir->op2)))
  90. irt_setmark(IR(ir->op1)->t); /* Mark ineligible ref. */
  91. irt_setmark(IR(ir->op2)->t); /* Mark stored value. */
  92. break;
  93. }
  94. #if LJ_HASFFI
  95. case IR_CNEWI:
  96. if (irt_isphi(ir->t) &&
  97. (!sink_checkphi(J, ir, ir->op2) ||
  98. (LJ_32 && ir+1 < irlast && (ir+1)->o == IR_HIOP &&
  99. !sink_checkphi(J, ir, (ir+1)->op2))))
  100. irt_setmark(ir->t); /* Mark ineligible allocation. */
  101. #endif
  102. /* fallthrough */
  103. case IR_USTORE:
  104. irt_setmark(IR(ir->op2)->t); /* Mark stored value. */
  105. break;
  106. #if LJ_HASFFI
  107. case IR_CALLXS:
  108. #endif
  109. case IR_CALLS:
  110. irt_setmark(IR(ir->op1)->t); /* Mark (potentially) stored values. */
  111. break;
  112. case IR_PHI: {
  113. IRIns *irl = IR(ir->op1), *irr = IR(ir->op2);
  114. irl->prev = irr->prev = 0; /* Clear PHI value counts. */
  115. if (irl->o == irr->o &&
  116. (irl->o == IR_TNEW || irl->o == IR_TDUP ||
  117. (LJ_HASFFI && (irl->o == IR_CNEW || irl->o == IR_CNEWI))))
  118. break;
  119. irt_setmark(irl->t);
  120. irt_setmark(irr->t);
  121. break;
  122. }
  123. default:
  124. if (irt_ismarked(ir->t) || irt_isguard(ir->t)) { /* Propagate mark. */
  125. if (ir->op1 >= REF_FIRST) irt_setmark(IR(ir->op1)->t);
  126. if (ir->op2 >= REF_FIRST) irt_setmark(IR(ir->op2)->t);
  127. }
  128. break;
  129. }
  130. }
  131. }
  132. /* Mark all instructions referenced by a snapshot. */
  133. static void sink_mark_snap(jit_State *J, SnapShot *snap)
  134. {
  135. SnapEntry *map = &J->cur.snapmap[snap->mapofs];
  136. MSize n, nent = snap->nent;
  137. for (n = 0; n < nent; n++) {
  138. IRRef ref = snap_ref(map[n]);
  139. if (!irref_isk(ref))
  140. irt_setmark(IR(ref)->t);
  141. }
  142. }
  143. /* Iteratively remark PHI refs with differing marks or PHI value counts. */
  144. static void sink_remark_phi(jit_State *J)
  145. {
  146. IRIns *ir;
  147. int remark;
  148. do {
  149. remark = 0;
  150. for (ir = IR(J->cur.nins-1); ir->o == IR_PHI; ir--) {
  151. IRIns *irl = IR(ir->op1), *irr = IR(ir->op2);
  152. if (!((irl->t.irt ^ irr->t.irt) & IRT_MARK) && irl->prev == irr->prev)
  153. continue;
  154. remark |= (~(irl->t.irt & irr->t.irt) & IRT_MARK);
  155. irt_setmark(IR(ir->op1)->t);
  156. irt_setmark(IR(ir->op2)->t);
  157. }
  158. } while (remark);
  159. }
  160. /* Sweep instructions and tag sunken allocations and stores. */
  161. static void sink_sweep_ins(jit_State *J)
  162. {
  163. IRIns *ir, *irbase = IR(REF_BASE);
  164. for (ir = IR(J->cur.nins-1) ; ir >= irbase; ir--) {
  165. switch (ir->o) {
  166. case IR_ASTORE: case IR_HSTORE: case IR_FSTORE: case IR_XSTORE: {
  167. IRIns *ira = sink_checkalloc(J, ir);
  168. if (ira && !irt_ismarked(ira->t)) {
  169. int delta = (int)(ir - ira);
  170. ir->prev = REGSP(RID_SINK, delta > 255 ? 255 : delta);
  171. } else {
  172. ir->prev = REGSP_INIT;
  173. }
  174. break;
  175. }
  176. case IR_NEWREF:
  177. if (!irt_ismarked(IR(ir->op1)->t)) {
  178. ir->prev = REGSP(RID_SINK, 0);
  179. } else {
  180. irt_clearmark(ir->t);
  181. ir->prev = REGSP_INIT;
  182. }
  183. break;
  184. #if LJ_HASFFI
  185. case IR_CNEW: case IR_CNEWI:
  186. #endif
  187. case IR_TNEW: case IR_TDUP:
  188. if (!irt_ismarked(ir->t)) {
  189. ir->t.irt &= ~IRT_GUARD;
  190. ir->prev = REGSP(RID_SINK, 0);
  191. J->cur.sinktags = 1; /* Signal present SINK tags to assembler. */
  192. } else {
  193. irt_clearmark(ir->t);
  194. ir->prev = REGSP_INIT;
  195. }
  196. break;
  197. case IR_PHI: {
  198. IRIns *ira = IR(ir->op2);
  199. if (!irt_ismarked(ira->t) &&
  200. (ira->o == IR_TNEW || ira->o == IR_TDUP ||
  201. (LJ_HASFFI && (ira->o == IR_CNEW || ira->o == IR_CNEWI)))) {
  202. ir->prev = REGSP(RID_SINK, 0);
  203. } else {
  204. ir->prev = REGSP_INIT;
  205. }
  206. break;
  207. }
  208. default:
  209. irt_clearmark(ir->t);
  210. ir->prev = REGSP_INIT;
  211. break;
  212. }
  213. }
  214. for (ir = IR(J->cur.nk); ir < irbase; ir++) {
  215. irt_clearmark(ir->t);
  216. ir->prev = REGSP_INIT;
  217. /* The false-positive of irt_is64() for ASMREF_L (REF_NIL) is OK here. */
  218. if (irt_is64(ir->t) && ir->o != IR_KNULL)
  219. ir++;
  220. }
  221. }
  222. /* Allocation sinking and store sinking.
  223. **
  224. ** 1. Mark all non-sinkable allocations.
  225. ** 2. Then sink all remaining allocations and the related stores.
  226. */
  227. void lj_opt_sink(jit_State *J)
  228. {
  229. const uint32_t need = (JIT_F_OPT_SINK|JIT_F_OPT_FWD|
  230. JIT_F_OPT_DCE|JIT_F_OPT_CSE|JIT_F_OPT_FOLD);
  231. if ((J->flags & need) == need &&
  232. (J->chain[IR_TNEW] || J->chain[IR_TDUP] ||
  233. (LJ_HASFFI && (J->chain[IR_CNEW] || J->chain[IR_CNEWI])))) {
  234. if (!J->loopref)
  235. sink_mark_snap(J, &J->cur.snap[J->cur.nsnap-1]);
  236. sink_mark_ins(J);
  237. if (J->loopref)
  238. sink_remark_phi(J);
  239. sink_sweep_ins(J);
  240. }
  241. }
  242. #undef IR
  243. #endif