diff options
Diffstat (limited to 'src/lj_opt_fold.c')
-rw-r--r-- | src/lj_opt_fold.c | 67 |
1 files changed, 36 insertions, 31 deletions
diff --git a/src/lj_opt_fold.c b/src/lj_opt_fold.c index 9c751d98..e9f873b7 100644 --- a/src/lj_opt_fold.c +++ b/src/lj_opt_fold.c | |||
@@ -520,9 +520,23 @@ LJFOLDF(kfold_strcmp) | |||
520 | 520 | ||
521 | /* -- Constant folding and forwarding for buffers ------------------------- */ | 521 | /* -- Constant folding and forwarding for buffers ------------------------- */ |
522 | 522 | ||
523 | /* Note: buffer ops are not CSEd until the BUFSTR. It's ok to modify them. */ | 523 | /* |
524 | ** Buffer ops perform stores, but their effect is limited to the buffer | ||
525 | ** itself. Also, buffer ops are chained: a use of an op implies a use of | ||
526 | ** all other ops up the chain. Conversely, if an op is unused, all ops | ||
527 | ** up the chain can go unsed. This largely eliminates the need to treat | ||
528 | ** them as stores. | ||
529 | ** | ||
530 | ** Alas, treating them as normal (IRM_N) ops doesn't work, because they | ||
531 | ** cannot be CSEd in isolation. CSE for IRM_N is implicitly done in LOOP | ||
532 | ** or if FOLD is disabled. | ||
533 | ** | ||
534 | ** The compromise is to declare them as loads, emit them like stores and | ||
535 | ** CSE whole chains manually when the BUFSTR is to be emitted. Any chain | ||
536 | ** fragments left over from CSE are eliminated by DCE. | ||
537 | */ | ||
524 | 538 | ||
525 | /* BUFHDR is treated like a store, see below. */ | 539 | /* BUFHDR is emitted like a store, see below. */ |
526 | 540 | ||
527 | LJFOLD(BUFPUT BUFHDR BUFSTR) | 541 | LJFOLD(BUFPUT BUFHDR BUFSTR) |
528 | LJFOLDF(bufput_append) | 542 | LJFOLDF(bufput_append) |
@@ -530,14 +544,14 @@ LJFOLDF(bufput_append) | |||
530 | /* New buffer, no other buffer op inbetween and same buffer? */ | 544 | /* New buffer, no other buffer op inbetween and same buffer? */ |
531 | if ((J->flags & JIT_F_OPT_FWD) && | 545 | if ((J->flags & JIT_F_OPT_FWD) && |
532 | !(fleft->op2 & IRBUFHDR_APPEND) && | 546 | !(fleft->op2 & IRBUFHDR_APPEND) && |
533 | fleft->prev == fright->op1 && | 547 | fleft->prev == fright->op2 && |
534 | fleft->op1 == IR(fright->op1)->op1) { | 548 | fleft->op1 == IR(fright->op2)->op1) { |
535 | IRRef ref = fins->op1; | 549 | IRRef ref = fins->op1; |
536 | IR(ref)->op2 = (fleft->op2 | IRBUFHDR_APPEND); /* Modify BUFHDR. */ | 550 | IR(ref)->op2 = (fleft->op2 | IRBUFHDR_APPEND); /* Modify BUFHDR. */ |
537 | IR(ref)->op1 = fright->op2; | 551 | IR(ref)->op1 = fright->op1; |
538 | return ref; | 552 | return ref; |
539 | } | 553 | } |
540 | return EMITFOLD; /* This is a store and always emitted. */ | 554 | return EMITFOLD; /* Always emit, CSE later. */ |
541 | } | 555 | } |
542 | 556 | ||
543 | LJFOLD(BUFPUT any any) | 557 | LJFOLD(BUFPUT any any) |
@@ -565,45 +579,36 @@ LJFOLDF(bufput_kgc) | |||
565 | } | 579 | } |
566 | } | 580 | } |
567 | } | 581 | } |
568 | return EMITFOLD; /* This is a store and always emitted. */ | 582 | return EMITFOLD; /* Always emit, CSE later. */ |
569 | } | 583 | } |
570 | 584 | ||
571 | LJFOLD(BUFSTR any any) | 585 | LJFOLD(BUFSTR any any) |
572 | LJFOLDF(bufstr_kfold_cse) | 586 | LJFOLDF(bufstr_kfold_cse) |
573 | { | 587 | { |
574 | lua_assert(fright->o == IR_BUFHDR || fright->o == IR_BUFPUT || | 588 | lua_assert(fleft->o == IR_BUFHDR || fleft->o == IR_BUFPUT || |
575 | fright->o == IR_CALLS); | 589 | fleft->o == IR_CALLL); |
576 | if (LJ_LIKELY(J->flags & JIT_F_OPT_FOLD)) { | 590 | if (LJ_LIKELY(J->flags & JIT_F_OPT_FOLD)) { |
577 | if (fright->o == IR_BUFHDR) { /* No put operations? */ | 591 | if (fleft->o == IR_BUFHDR) { /* No put operations? */ |
578 | if (!(fright->op2 & IRBUFHDR_APPEND)) { /* Empty buffer? */ | 592 | if (!(fleft->op2 & IRBUFHDR_APPEND)) /* Empty buffer? */ |
579 | lj_ir_rollback(J, fins->op1); /* Eliminate the current chain. */ | ||
580 | return lj_ir_kstr(J, &J2G(J)->strempty); | 593 | return lj_ir_kstr(J, &J2G(J)->strempty); |
581 | } | 594 | fins->op1 = fleft->prev; /* Relies on checks in bufput_append. */ |
582 | fins->op2 = fright->prev; /* Relies on checks in bufput_append. */ | ||
583 | return CSEFOLD; | 595 | return CSEFOLD; |
584 | } else if (fright->o == IR_BUFPUT) { | 596 | } else if (fleft->o == IR_BUFPUT) { |
585 | IRIns *irb = IR(fright->op1); | 597 | IRIns *irb = IR(fleft->op1); |
586 | if (irb->o == IR_BUFHDR && !(irb->op2 & IRBUFHDR_APPEND)) { | 598 | if (irb->o == IR_BUFHDR && !(irb->op2 & IRBUFHDR_APPEND)) |
587 | lj_ir_rollback(J, fins->op1); /* Eliminate the current chain. */ | 599 | return fleft->op2; /* Shortcut for a single put operation. */ |
588 | return fright->op2; /* Shortcut for a single put operation. */ | ||
589 | } | ||
590 | } | 600 | } |
591 | } | 601 | } |
592 | /* Try to CSE the whole chain. */ | 602 | /* Try to CSE the whole chain. */ |
593 | if (LJ_LIKELY(J->flags & JIT_F_OPT_CSE)) { | 603 | if (LJ_LIKELY(J->flags & JIT_F_OPT_CSE)) { |
594 | IRRef ref = J->chain[IR_BUFSTR]; | 604 | IRRef ref = J->chain[IR_BUFSTR]; |
595 | while (ref) { | 605 | while (ref) { |
596 | IRRef last = fins->op2; | 606 | IRRef last = fins->op1; |
597 | IRIns *irs = IR(ref), *ira = fright, *irb = IR(irs->op2); | 607 | IRIns *irs = IR(ref), *ira = fleft, *irb = IR(irs->op1); |
598 | while (ira->o == irb->o && ira->op2 == irb->op2) { | 608 | while (ira->o == irb->o && ira->op2 == irb->op2) { |
599 | if (ira->o == IR_BUFHDR && !(ira->op2 & IRBUFHDR_APPEND)) { | 609 | if (ira->o == IR_BUFHDR && !(ira->op2 & IRBUFHDR_APPEND)) { |
600 | IRIns *irh; | ||
601 | for (irh = IR(ira->prev); irh != irb; irh = IR(irh->prev)) | ||
602 | if (irh->op1 == irs->op2) | ||
603 | return ref; /* Do CSE, but avoid rollback if append follows. */ | ||
604 | lj_ir_rollback(J, last); /* Eliminate the current chain. */ | ||
605 | return ref; /* CSE succeeded. */ | 610 | return ref; /* CSE succeeded. */ |
606 | } else if (ira->o == IR_CALLS) { | 611 | } else if (ira->o == IR_CALLL) { |
607 | ira = IR(ira->op1); irb = IR(irb->op1); | 612 | ira = IR(ira->op1); irb = IR(irb->op1); |
608 | lua_assert(ira->o == IR_CARG && irb->o == IR_CARG); | 613 | lua_assert(ira->o == IR_CARG && irb->o == IR_CARG); |
609 | if (ira->op2 != irb->op2) break; | 614 | if (ira->op2 != irb->op2) break; |
@@ -618,9 +623,9 @@ LJFOLDF(bufstr_kfold_cse) | |||
618 | return EMITFOLD; /* No CSE possible. */ | 623 | return EMITFOLD; /* No CSE possible. */ |
619 | } | 624 | } |
620 | 625 | ||
621 | LJFOLD(CALLS CARG IRCALL_lj_buf_putstr_reverse) | 626 | LJFOLD(CALLL CARG IRCALL_lj_buf_putstr_reverse) |
622 | LJFOLD(CALLS CARG IRCALL_lj_buf_putstr_upper) | 627 | LJFOLD(CALLL CARG IRCALL_lj_buf_putstr_upper) |
623 | LJFOLD(CALLS CARG IRCALL_lj_buf_putstr_lower) | 628 | LJFOLD(CALLL CARG IRCALL_lj_buf_putstr_lower) |
624 | LJFOLDF(bufput_kfold_op) | 629 | LJFOLDF(bufput_kfold_op) |
625 | { | 630 | { |
626 | if (irref_isk(fleft->op2)) { | 631 | if (irref_isk(fleft->op2)) { |