aboutsummaryrefslogtreecommitdiff
path: root/src/lj_opt_mem.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lj_opt_mem.c')
-rw-r--r--src/lj_opt_mem.c195
1 files changed, 136 insertions, 59 deletions
diff --git a/src/lj_opt_mem.c b/src/lj_opt_mem.c
index feec6bb7..cafa0523 100644
--- a/src/lj_opt_mem.c
+++ b/src/lj_opt_mem.c
@@ -17,12 +17,14 @@
17#include "lj_ir.h" 17#include "lj_ir.h"
18#include "lj_jit.h" 18#include "lj_jit.h"
19#include "lj_iropt.h" 19#include "lj_iropt.h"
20#include "lj_ircall.h"
21#include "lj_dispatch.h"
20 22
21/* Some local macros to save typing. Undef'd at the end. */ 23/* Some local macros to save typing. Undef'd at the end. */
22#define IR(ref) (&J->cur.ir[(ref)]) 24#define IR(ref) (&J->cur.ir[(ref)])
23#define fins (&J->fold.ins) 25#define fins (&J->fold.ins)
24#define fleft (&J->fold.left) 26#define fleft (J->fold.left)
25#define fright (&J->fold.right) 27#define fright (J->fold.right)
26 28
27/* 29/*
28** Caveat #1: return value is not always a TRef -- only use with tref_ref(). 30** Caveat #1: return value is not always a TRef -- only use with tref_ref().
@@ -55,8 +57,8 @@ static AliasRet aa_table(jit_State *J, IRRef ta, IRRef tb)
55{ 57{
56 IRIns *taba = IR(ta), *tabb = IR(tb); 58 IRIns *taba = IR(ta), *tabb = IR(tb);
57 int newa, newb; 59 int newa, newb;
58 lua_assert(ta != tb); 60 lj_assertJ(ta != tb, "bad usage");
59 lua_assert(irt_istab(taba->t) && irt_istab(tabb->t)); 61 lj_assertJ(irt_istab(taba->t) && irt_istab(tabb->t), "bad usage");
60 /* Disambiguate new allocations. */ 62 /* Disambiguate new allocations. */
61 newa = (taba->o == IR_TNEW || taba->o == IR_TDUP); 63 newa = (taba->o == IR_TNEW || taba->o == IR_TDUP);
62 newb = (tabb->o == IR_TNEW || tabb->o == IR_TDUP); 64 newb = (tabb->o == IR_TNEW || tabb->o == IR_TDUP);
@@ -70,6 +72,34 @@ static AliasRet aa_table(jit_State *J, IRRef ta, IRRef tb)
70 return aa_escape(J, taba, tabb); 72 return aa_escape(J, taba, tabb);
71} 73}
72 74
75/* Check whether there's no aliasing table.clear. */
76static int fwd_aa_tab_clear(jit_State *J, IRRef lim, IRRef ta)
77{
78 IRRef ref = J->chain[IR_CALLS];
79 while (ref > lim) {
80 IRIns *calls = IR(ref);
81 if (calls->op2 == IRCALL_lj_tab_clear &&
82 (ta == calls->op1 || aa_table(J, ta, calls->op1) != ALIAS_NO))
83 return 0; /* Conflict. */
84 ref = calls->prev;
85 }
86 return 1; /* No conflict. Can safely FOLD/CSE. */
87}
88
89/* Check whether there's no aliasing NEWREF/table.clear for the left operand. */
90int LJ_FASTCALL lj_opt_fwd_tptr(jit_State *J, IRRef lim)
91{
92 IRRef ta = fins->op1;
93 IRRef ref = J->chain[IR_NEWREF];
94 while (ref > lim) {
95 IRIns *newref = IR(ref);
96 if (ta == newref->op1 || aa_table(J, ta, newref->op1) != ALIAS_NO)
97 return 0; /* Conflict. */
98 ref = newref->prev;
99 }
100 return fwd_aa_tab_clear(J, lim, ta);
101}
102
73/* Alias analysis for array and hash access using key-based disambiguation. */ 103/* Alias analysis for array and hash access using key-based disambiguation. */
74static AliasRet aa_ahref(jit_State *J, IRIns *refa, IRIns *refb) 104static AliasRet aa_ahref(jit_State *J, IRIns *refa, IRIns *refb)
75{ 105{
@@ -98,7 +128,7 @@ static AliasRet aa_ahref(jit_State *J, IRIns *refa, IRIns *refb)
98 /* Disambiguate array references based on index arithmetic. */ 128 /* Disambiguate array references based on index arithmetic. */
99 int32_t ofsa = 0, ofsb = 0; 129 int32_t ofsa = 0, ofsb = 0;
100 IRRef basea = ka, baseb = kb; 130 IRRef basea = ka, baseb = kb;
101 lua_assert(refb->o == IR_AREF); 131 lj_assertJ(refb->o == IR_AREF, "expected AREF");
102 /* Gather base and offset from t[base] or t[base+-ofs]. */ 132 /* Gather base and offset from t[base] or t[base+-ofs]. */
103 if (keya->o == IR_ADD && irref_isk(keya->op2)) { 133 if (keya->o == IR_ADD && irref_isk(keya->op2)) {
104 basea = keya->op1; 134 basea = keya->op1;
@@ -116,8 +146,9 @@ static AliasRet aa_ahref(jit_State *J, IRIns *refa, IRIns *refb)
116 return ALIAS_NO; /* t[base+-o1] vs. t[base+-o2] and o1 != o2. */ 146 return ALIAS_NO; /* t[base+-o1] vs. t[base+-o2] and o1 != o2. */
117 } else { 147 } else {
118 /* Disambiguate hash references based on the type of their keys. */ 148 /* Disambiguate hash references based on the type of their keys. */
119 lua_assert((refa->o==IR_HREF || refa->o==IR_HREFK || refa->o==IR_NEWREF) && 149 lj_assertJ((refa->o==IR_HREF || refa->o==IR_HREFK || refa->o==IR_NEWREF) &&
120 (refb->o==IR_HREF || refb->o==IR_HREFK || refb->o==IR_NEWREF)); 150 (refb->o==IR_HREF || refb->o==IR_HREFK || refb->o==IR_NEWREF),
151 "bad xREF IR op %d or %d", refa->o, refb->o);
121 if (!irt_sametype(keya->t, keyb->t)) 152 if (!irt_sametype(keya->t, keyb->t))
122 return ALIAS_NO; /* Different key types. */ 153 return ALIAS_NO; /* Different key types. */
123 } 154 }
@@ -151,7 +182,8 @@ static TRef fwd_ahload(jit_State *J, IRRef xref)
151 IRIns *ir = (xr->o == IR_HREFK || xr->o == IR_AREF) ? IR(xr->op1) : xr; 182 IRIns *ir = (xr->o == IR_HREFK || xr->o == IR_AREF) ? IR(xr->op1) : xr;
152 IRRef tab = ir->op1; 183 IRRef tab = ir->op1;
153 ir = IR(tab); 184 ir = IR(tab);
154 if (ir->o == IR_TNEW || (ir->o == IR_TDUP && irref_isk(xr->op2))) { 185 if ((ir->o == IR_TNEW || (ir->o == IR_TDUP && irref_isk(xr->op2))) &&
186 fwd_aa_tab_clear(J, tab, tab)) {
155 /* A NEWREF with a number key may end up pointing to the array part. 187 /* A NEWREF with a number key may end up pointing to the array part.
156 ** But it's referenced from HSTORE and not found in the ASTORE chain. 188 ** But it's referenced from HSTORE and not found in the ASTORE chain.
157 ** For now simply consider this a conflict without forwarding anything. 189 ** For now simply consider this a conflict without forwarding anything.
@@ -191,7 +223,8 @@ static TRef fwd_ahload(jit_State *J, IRRef xref)
191 if (key->o == IR_KSLOT) key = IR(key->op1); 223 if (key->o == IR_KSLOT) key = IR(key->op1);
192 lj_ir_kvalue(J->L, &keyv, key); 224 lj_ir_kvalue(J->L, &keyv, key);
193 tv = lj_tab_get(J->L, ir_ktab(IR(ir->op1)), &keyv); 225 tv = lj_tab_get(J->L, ir_ktab(IR(ir->op1)), &keyv);
194 lua_assert(itype2irt(tv) == irt_type(fins->t)); 226 lj_assertJ(itype2irt(tv) == irt_type(fins->t),
227 "mismatched type in constant table");
195 if (irt_isnum(fins->t)) 228 if (irt_isnum(fins->t))
196 return lj_ir_knum_u64(J, tv->u64); 229 return lj_ir_knum_u64(J, tv->u64);
197 else if (LJ_DUALNUM && irt_isint(fins->t)) 230 else if (LJ_DUALNUM && irt_isint(fins->t))
@@ -265,7 +298,7 @@ TRef LJ_FASTCALL lj_opt_fwd_hrefk(jit_State *J)
265 while (ref > tab) { 298 while (ref > tab) {
266 IRIns *newref = IR(ref); 299 IRIns *newref = IR(ref);
267 if (tab == newref->op1) { 300 if (tab == newref->op1) {
268 if (fright->op1 == newref->op2) 301 if (fright->op1 == newref->op2 && fwd_aa_tab_clear(J, ref, tab))
269 return ref; /* Forward from NEWREF. */ 302 return ref; /* Forward from NEWREF. */
270 else 303 else
271 goto docse; 304 goto docse;
@@ -275,7 +308,7 @@ TRef LJ_FASTCALL lj_opt_fwd_hrefk(jit_State *J)
275 ref = newref->prev; 308 ref = newref->prev;
276 } 309 }
277 /* No conflicting NEWREF: key location unchanged for HREFK of TDUP. */ 310 /* No conflicting NEWREF: key location unchanged for HREFK of TDUP. */
278 if (IR(tab)->o == IR_TDUP) 311 if (IR(tab)->o == IR_TDUP && fwd_aa_tab_clear(J, tab, tab))
279 fins->t.irt &= ~IRT_GUARD; /* Drop HREFK guard. */ 312 fins->t.irt &= ~IRT_GUARD; /* Drop HREFK guard. */
280docse: 313docse:
281 return CSEFOLD; 314 return CSEFOLD;
@@ -309,20 +342,6 @@ int LJ_FASTCALL lj_opt_fwd_href_nokey(jit_State *J)
309 return 1; /* No conflict. Can fold to niltv. */ 342 return 1; /* No conflict. Can fold to niltv. */
310} 343}
311 344
312/* Check whether there's no aliasing NEWREF for the left operand. */
313int LJ_FASTCALL lj_opt_fwd_tptr(jit_State *J, IRRef lim)
314{
315 IRRef ta = fins->op1;
316 IRRef ref = J->chain[IR_NEWREF];
317 while (ref > lim) {
318 IRIns *newref = IR(ref);
319 if (ta == newref->op1 || aa_table(J, ta, newref->op1) != ALIAS_NO)
320 return 0; /* Conflict. */
321 ref = newref->prev;
322 }
323 return 1; /* No conflict. Can safely FOLD/CSE. */
324}
325
326/* ASTORE/HSTORE elimination. */ 345/* ASTORE/HSTORE elimination. */
327TRef LJ_FASTCALL lj_opt_dse_ahstore(jit_State *J) 346TRef LJ_FASTCALL lj_opt_dse_ahstore(jit_State *J)
328{ 347{
@@ -346,9 +365,12 @@ TRef LJ_FASTCALL lj_opt_dse_ahstore(jit_State *J)
346 /* Different value: try to eliminate the redundant store. */ 365 /* Different value: try to eliminate the redundant store. */
347 if (ref > J->chain[IR_LOOP]) { /* Quick check to avoid crossing LOOP. */ 366 if (ref > J->chain[IR_LOOP]) { /* Quick check to avoid crossing LOOP. */
348 IRIns *ir; 367 IRIns *ir;
349 /* Check for any intervening guards (includes conflicting loads). */ 368 /* Check for any intervening guards (includes conflicting loads).
369 ** Note that lj_tab_keyindex and lj_vm_next don't need guards,
370 ** since they are followed by at least one guarded VLOAD.
371 */
350 for (ir = IR(J->cur.nins-1); ir > store; ir--) 372 for (ir = IR(J->cur.nins-1); ir > store; ir--)
351 if (irt_isguard(ir->t) || ir->o == IR_CALLL) 373 if (irt_isguard(ir->t) || ir->o == IR_ALEN)
352 goto doemit; /* No elimination possible. */ 374 goto doemit; /* No elimination possible. */
353 /* Remove redundant store from chain and replace with NOP. */ 375 /* Remove redundant store from chain and replace with NOP. */
354 *refp = store->prev; 376 *refp = store->prev;
@@ -363,6 +385,67 @@ doemit:
363 return EMITFOLD; /* Otherwise we have a conflict or simply no match. */ 385 return EMITFOLD; /* Otherwise we have a conflict or simply no match. */
364} 386}
365 387
388/* ALEN forwarding. */
389TRef LJ_FASTCALL lj_opt_fwd_alen(jit_State *J)
390{
391 IRRef tab = fins->op1; /* Table reference. */
392 IRRef lim = tab; /* Search limit. */
393 IRRef ref;
394
395 /* Search for conflicting HSTORE with numeric key. */
396 ref = J->chain[IR_HSTORE];
397 while (ref > lim) {
398 IRIns *store = IR(ref);
399 IRIns *href = IR(store->op1);
400 IRIns *key = IR(href->op2);
401 if (irt_isnum(key->o == IR_KSLOT ? IR(key->op1)->t : key->t)) {
402 lim = ref; /* Conflicting store found, limits search for ALEN. */
403 break;
404 }
405 ref = store->prev;
406 }
407
408 /* Try to find a matching ALEN. */
409 ref = J->chain[IR_ALEN];
410 while (ref > lim) {
411 /* CSE for ALEN only depends on the table, not the hint. */
412 if (IR(ref)->op1 == tab) {
413 IRRef sref;
414
415 /* Search for aliasing table.clear. */
416 if (!fwd_aa_tab_clear(J, ref, tab))
417 break;
418
419 /* Search for hint-forwarding or conflicting store. */
420 sref = J->chain[IR_ASTORE];
421 while (sref > ref) {
422 IRIns *store = IR(sref);
423 IRIns *aref = IR(store->op1);
424 IRIns *fref = IR(aref->op1);
425 if (tab == fref->op1) { /* ASTORE to the same table. */
426 /* Detect t[#t+1] = x idiom for push. */
427 IRIns *idx = IR(aref->op2);
428 if (!irt_isnil(store->t) &&
429 idx->o == IR_ADD && idx->op1 == ref &&
430 IR(idx->op2)->o == IR_KINT && IR(idx->op2)->i == 1) {
431 /* Note: this requires an extra PHI check in loop unroll. */
432 fins->op2 = aref->op2; /* Set ALEN hint. */
433 }
434 goto doemit; /* Conflicting store, possibly giving a hint. */
435 } else if (aa_table(J, tab, fref->op1) == ALIAS_NO) {
436 goto doemit; /* Conflicting store. */
437 }
438 sref = store->prev;
439 }
440
441 return ref; /* Plain ALEN forwarding. */
442 }
443 ref = IR(ref)->prev;
444 }
445doemit:
446 return EMITFOLD;
447}
448
366/* -- ULOAD forwarding ---------------------------------------------------- */ 449/* -- ULOAD forwarding ---------------------------------------------------- */
367 450
368/* The current alias analysis for upvalues is very simplistic. It only 451/* The current alias analysis for upvalues is very simplistic. It only
@@ -412,7 +495,6 @@ TRef LJ_FASTCALL lj_opt_fwd_uload(jit_State *J)
412 495
413cselim: 496cselim:
414 /* Try to find a matching load. Below the conflicting store, if any. */ 497 /* Try to find a matching load. Below the conflicting store, if any. */
415
416 ref = J->chain[IR_ULOAD]; 498 ref = J->chain[IR_ULOAD];
417 while (ref > lim) { 499 while (ref > lim) {
418 IRIns *ir = IR(ref); 500 IRIns *ir = IR(ref);
@@ -542,8 +624,9 @@ TRef LJ_FASTCALL lj_opt_dse_fstore(jit_State *J)
542 goto doemit; 624 goto doemit;
543 break; /* Otherwise continue searching. */ 625 break; /* Otherwise continue searching. */
544 case ALIAS_MUST: 626 case ALIAS_MUST:
545 if (store->op2 == val) /* Same value: drop the new store. */ 627 if (store->op2 == val &&
546 return DROPFOLD; 628 !(xr->op2 >= IRFL_SBUF_W && xr->op2 <= IRFL_SBUF_R))
629 return DROPFOLD; /* Same value: drop the new store. */
547 /* Different value: try to eliminate the redundant store. */ 630 /* Different value: try to eliminate the redundant store. */
548 if (ref > J->chain[IR_LOOP]) { /* Quick check to avoid crossing LOOP. */ 631 if (ref > J->chain[IR_LOOP]) { /* Quick check to avoid crossing LOOP. */
549 IRIns *ir; 632 IRIns *ir;
@@ -564,6 +647,29 @@ doemit:
564 return EMITFOLD; /* Otherwise we have a conflict or simply no match. */ 647 return EMITFOLD; /* Otherwise we have a conflict or simply no match. */
565} 648}
566 649
650/* Check whether there's no aliasing buffer op between IRFL_SBUF_*. */
651int LJ_FASTCALL lj_opt_fwd_sbuf(jit_State *J, IRRef lim)
652{
653 IRRef ref;
654 if (J->chain[IR_BUFPUT] > lim)
655 return 0; /* Conflict. */
656 ref = J->chain[IR_CALLS];
657 while (ref > lim) {
658 IRIns *ir = IR(ref);
659 if (ir->op2 >= IRCALL_lj_strfmt_putint && ir->op2 < IRCALL_lj_buf_tostr)
660 return 0; /* Conflict. */
661 ref = ir->prev;
662 }
663 ref = J->chain[IR_CALLL];
664 while (ref > lim) {
665 IRIns *ir = IR(ref);
666 if (ir->op2 >= IRCALL_lj_strfmt_putint && ir->op2 < IRCALL_lj_buf_tostr)
667 return 0; /* Conflict. */
668 ref = ir->prev;
669 }
670 return 1; /* No conflict. Can safely FOLD/CSE. */
671}
672
567/* -- XLOAD forwarding and XSTORE elimination ----------------------------- */ 673/* -- XLOAD forwarding and XSTORE elimination ----------------------------- */
568 674
569/* Find cdata allocation for a reference (if any). */ 675/* Find cdata allocation for a reference (if any). */
@@ -815,35 +921,6 @@ doemit:
815 return EMITFOLD; /* Otherwise we have a conflict or simply no match. */ 921 return EMITFOLD; /* Otherwise we have a conflict or simply no match. */
816} 922}
817 923
818/* -- Forwarding of lj_tab_len -------------------------------------------- */
819
820/* This is rather simplistic right now, but better than nothing. */
821TRef LJ_FASTCALL lj_opt_fwd_tab_len(jit_State *J)
822{
823 IRRef tab = fins->op1; /* Table reference. */
824 IRRef lim = tab; /* Search limit. */
825 IRRef ref;
826
827 /* Any ASTORE is a conflict and limits the search. */
828 if (J->chain[IR_ASTORE] > lim) lim = J->chain[IR_ASTORE];
829
830 /* Search for conflicting HSTORE with numeric key. */
831 ref = J->chain[IR_HSTORE];
832 while (ref > lim) {
833 IRIns *store = IR(ref);
834 IRIns *href = IR(store->op1);
835 IRIns *key = IR(href->op2);
836 if (irt_isnum(key->o == IR_KSLOT ? IR(key->op1)->t : key->t)) {
837 lim = ref; /* Conflicting store found, limits search for TLEN. */
838 break;
839 }
840 ref = store->prev;
841 }
842
843 /* Try to find a matching load. Below the conflicting store, if any. */
844 return lj_opt_cselim(J, lim);
845}
846
847/* -- ASTORE/HSTORE previous type analysis -------------------------------- */ 924/* -- ASTORE/HSTORE previous type analysis -------------------------------- */
848 925
849/* Check whether the previous value for a table store is non-nil. 926/* Check whether the previous value for a table store is non-nil.