diff options
| author | Mike Pall <mike> | 2013-04-22 20:47:39 +0200 |
|---|---|---|
| committer | Mike Pall <mike> | 2013-04-22 20:47:39 +0200 |
| commit | 2cd4ce614167804896c54e04d3d8a69ec16321c7 (patch) | |
| tree | 24fdcebc4fac059abc3015114dffb01e75822028 | |
| parent | 988e1839658523e772de53f89df389b568883fde (diff) | |
| download | luajit-2cd4ce614167804896c54e04d3d8a69ec16321c7.tar.gz luajit-2cd4ce614167804896c54e04d3d8a69ec16321c7.tar.bz2 luajit-2cd4ce614167804896c54e04d3d8a69ec16321c7.zip | |
Use same HREF+EQ/NE optimization in all assembler backends.
| -rw-r--r-- | src/lj_asm_mips.h | 48 | ||||
| -rw-r--r-- | src/lj_asm_x86.h | 46 |
2 files changed, 47 insertions, 47 deletions
diff --git a/src/lj_asm_mips.h b/src/lj_asm_mips.h index 44cb85e5..cbbd2966 100644 --- a/src/lj_asm_mips.h +++ b/src/lj_asm_mips.h | |||
| @@ -570,7 +570,7 @@ static void asm_aref(ASMState *as, IRIns *ir) | |||
| 570 | ** } while ((n = nextnode(n))); | 570 | ** } while ((n = nextnode(n))); |
| 571 | ** return niltv(L); | 571 | ** return niltv(L); |
| 572 | */ | 572 | */ |
| 573 | static void asm_href(ASMState *as, IRIns *ir) | 573 | static void asm_href(ASMState *as, IRIns *ir, IROp merge) |
| 574 | { | 574 | { |
| 575 | RegSet allow = RSET_GPR; | 575 | RegSet allow = RSET_GPR; |
| 576 | int destused = ra_used(ir); | 576 | int destused = ra_used(ir); |
| @@ -596,37 +596,42 @@ static void asm_href(ASMState *as, IRIns *ir) | |||
| 596 | tmp2 = ra_scratch(as, allow); | 596 | tmp2 = ra_scratch(as, allow); |
| 597 | rset_clear(allow, tmp2); | 597 | rset_clear(allow, tmp2); |
| 598 | 598 | ||
| 599 | /* Key not found in chain: load niltv. */ | 599 | /* Key not found in chain: jump to exit (if merged) or load niltv. */ |
| 600 | l_end = emit_label(as); | 600 | l_end = emit_label(as); |
| 601 | if (destused) | 601 | as->invmcp = NULL; |
| 602 | if (merge == IR_NE) | ||
| 603 | asm_guard(as, MIPSI_B, RID_ZERO, RID_ZERO); | ||
| 604 | else if (destused) | ||
| 602 | emit_loada(as, dest, niltvg(J2G(as->J))); | 605 | emit_loada(as, dest, niltvg(J2G(as->J))); |
| 603 | else | ||
| 604 | *--as->mcp = MIPSI_NOP; | ||
| 605 | /* Follow hash chain until the end. */ | 606 | /* Follow hash chain until the end. */ |
| 606 | emit_move(as, dest, tmp1); | 607 | emit_move(as, dest, tmp2); |
| 607 | l_loop = --as->mcp; | 608 | l_loop = --as->mcp; |
| 608 | emit_tsi(as, MIPSI_LW, tmp1, dest, (int32_t)offsetof(Node, next)); | 609 | emit_tsi(as, MIPSI_LW, tmp2, dest, (int32_t)offsetof(Node, next)); |
| 609 | l_next = emit_label(as); | 610 | l_next = emit_label(as); |
| 610 | 611 | ||
| 611 | /* Type and value comparison. */ | 612 | /* Type and value comparison. */ |
| 613 | if (merge == IR_EQ) { /* Must match asm_guard(). */ | ||
| 614 | emit_ti(as, MIPSI_LI, RID_TMP, as->snapno); | ||
| 615 | l_end = asm_exitstub_addr(as); | ||
| 616 | } | ||
| 612 | if (irt_isnum(kt)) { | 617 | if (irt_isnum(kt)) { |
| 613 | emit_branch(as, MIPSI_BC1T, 0, 0, l_end); | 618 | emit_branch(as, MIPSI_BC1T, 0, 0, l_end); |
| 614 | emit_fgh(as, MIPSI_C_EQ_D, 0, tmpnum, key); | 619 | emit_fgh(as, MIPSI_C_EQ_D, 0, tmpnum, key); |
| 615 | emit_tg(as, MIPSI_MFC1, tmp1, key+1); | 620 | *--as->mcp = MIPSI_NOP; /* Avoid NaN comparison overhead. */ |
| 616 | emit_branch(as, MIPSI_BEQ, tmp1, RID_ZERO, l_next); | 621 | emit_branch(as, MIPSI_BEQ, tmp2, RID_ZERO, l_next); |
| 617 | emit_tsi(as, MIPSI_SLTIU, tmp1, tmp1, (int32_t)LJ_TISNUM); | 622 | emit_tsi(as, MIPSI_SLTIU, tmp2, tmp2, (int32_t)LJ_TISNUM); |
| 618 | emit_hsi(as, MIPSI_LDC1, tmpnum, dest, (int32_t)offsetof(Node, key.n)); | 623 | emit_hsi(as, MIPSI_LDC1, tmpnum, dest, (int32_t)offsetof(Node, key.n)); |
| 619 | } else { | 624 | } else { |
| 620 | if (irt_ispri(kt)) { | 625 | if (irt_ispri(kt)) { |
| 621 | emit_branch(as, MIPSI_BEQ, tmp1, type, l_end); | 626 | emit_branch(as, MIPSI_BEQ, tmp2, type, l_end); |
| 622 | } else { | 627 | } else { |
| 623 | emit_branch(as, MIPSI_BEQ, tmp2, key, l_end); | 628 | emit_branch(as, MIPSI_BEQ, tmp1, key, l_end); |
| 624 | emit_tsi(as, MIPSI_LW, tmp2, dest, (int32_t)offsetof(Node, key.gcr)); | 629 | emit_tsi(as, MIPSI_LW, tmp1, dest, (int32_t)offsetof(Node, key.gcr)); |
| 625 | emit_branch(as, MIPSI_BNE, tmp1, type, l_next); | 630 | emit_branch(as, MIPSI_BNE, tmp2, type, l_next); |
| 626 | } | 631 | } |
| 627 | } | 632 | } |
| 628 | emit_tsi(as, MIPSI_LW, tmp1, dest, (int32_t)offsetof(Node, key.it)); | 633 | emit_tsi(as, MIPSI_LW, tmp2, dest, (int32_t)offsetof(Node, key.it)); |
| 629 | *l_loop = MIPSI_BNE | MIPSF_S(tmp1) | ((as->mcp-l_loop-1) & 0xffffu); | 634 | *l_loop = MIPSI_BNE | MIPSF_S(tmp2) | ((as->mcp-l_loop-1) & 0xffffu); |
| 630 | 635 | ||
| 631 | /* Load main position relative to tab->node into dest. */ | 636 | /* Load main position relative to tab->node into dest. */ |
| 632 | khash = irref_isk(refkey) ? ir_khash(irkey) : 1; | 637 | khash = irref_isk(refkey) ? ir_khash(irkey) : 1; |
| @@ -1694,7 +1699,14 @@ static void asm_ir(ASMState *as, IRIns *ir) | |||
| 1694 | case IR_GCSTEP: asm_gcstep(as, ir); break; | 1699 | case IR_GCSTEP: asm_gcstep(as, ir); break; |
| 1695 | 1700 | ||
| 1696 | /* Guarded assertions. */ | 1701 | /* Guarded assertions. */ |
| 1697 | case IR_EQ: case IR_NE: asm_compeq(as, ir); break; | 1702 | case IR_EQ: case IR_NE: |
| 1703 | if ((ir-1)->o == IR_HREF && ir->op1 == as->curins-1) { | ||
| 1704 | as->curins--; | ||
| 1705 | asm_href(as, ir-1, (IROp)ir->o); | ||
| 1706 | break; | ||
| 1707 | } | ||
| 1708 | asm_compeq(as, ir); | ||
| 1709 | break; | ||
| 1698 | case IR_LT: case IR_GE: case IR_LE: case IR_GT: | 1710 | case IR_LT: case IR_GE: case IR_LE: case IR_GT: |
| 1699 | case IR_ULT: case IR_UGE: case IR_ULE: case IR_UGT: | 1711 | case IR_ULT: case IR_UGE: case IR_ULE: case IR_UGT: |
| 1700 | case IR_ABC: | 1712 | case IR_ABC: |
| @@ -1749,7 +1761,7 @@ static void asm_ir(ASMState *as, IRIns *ir) | |||
| 1749 | 1761 | ||
| 1750 | /* Memory references. */ | 1762 | /* Memory references. */ |
| 1751 | case IR_AREF: asm_aref(as, ir); break; | 1763 | case IR_AREF: asm_aref(as, ir); break; |
| 1752 | case IR_HREF: asm_href(as, ir); break; | 1764 | case IR_HREF: asm_href(as, ir, 0); break; |
| 1753 | case IR_HREFK: asm_hrefk(as, ir); break; | 1765 | case IR_HREFK: asm_hrefk(as, ir); break; |
| 1754 | case IR_NEWREF: asm_newref(as, ir); break; | 1766 | case IR_NEWREF: asm_newref(as, ir); break; |
| 1755 | case IR_UREFO: case IR_UREFC: asm_uref(as, ir); break; | 1767 | case IR_UREFO: case IR_UREFC: asm_uref(as, ir); break; |
diff --git a/src/lj_asm_x86.h b/src/lj_asm_x86.h index e79dca93..45fc7e85 100644 --- a/src/lj_asm_x86.h +++ b/src/lj_asm_x86.h | |||
| @@ -947,23 +947,6 @@ static void asm_aref(ASMState *as, IRIns *ir) | |||
| 947 | emit_rr(as, XO_MOV, dest, as->mrm.base); | 947 | emit_rr(as, XO_MOV, dest, as->mrm.base); |
| 948 | } | 948 | } |
| 949 | 949 | ||
| 950 | /* Merge NE(HREF, niltv) check. */ | ||
| 951 | static MCode *merge_href_niltv(ASMState *as, IRIns *ir) | ||
| 952 | { | ||
| 953 | /* Assumes nothing else generates NE of HREF. */ | ||
| 954 | if ((ir[1].o == IR_NE || ir[1].o == IR_EQ) && ir[1].op1 == as->curins && | ||
| 955 | ra_hasreg(ir->r)) { | ||
| 956 | MCode *p = as->mcp; | ||
| 957 | p += (LJ_64 && *p != XI_ARITHi) ? 7+6 : 6+6; | ||
| 958 | /* Ensure no loop branch inversion happened. */ | ||
| 959 | if (p[-6] == 0x0f && p[-5] == XI_JCCn+(CC_NE^(ir[1].o & 1))) { | ||
| 960 | as->mcp = p; /* Kill cmp reg, imm32 + jz exit. */ | ||
| 961 | return p + *(int32_t *)(p-4); /* Return exit address. */ | ||
| 962 | } | ||
| 963 | } | ||
| 964 | return NULL; | ||
| 965 | } | ||
| 966 | |||
| 967 | /* Inlined hash lookup. Specialized for key type and for const keys. | 950 | /* Inlined hash lookup. Specialized for key type and for const keys. |
| 968 | ** The equivalent C code is: | 951 | ** The equivalent C code is: |
| 969 | ** Node *n = hashkey(t, key); | 952 | ** Node *n = hashkey(t, key); |
| @@ -972,10 +955,10 @@ static MCode *merge_href_niltv(ASMState *as, IRIns *ir) | |||
| 972 | ** } while ((n = nextnode(n))); | 955 | ** } while ((n = nextnode(n))); |
| 973 | ** return niltv(L); | 956 | ** return niltv(L); |
| 974 | */ | 957 | */ |
| 975 | static void asm_href(ASMState *as, IRIns *ir) | 958 | static void asm_href(ASMState *as, IRIns *ir, IROp merge) |
| 976 | { | 959 | { |
| 977 | MCode *nilexit = merge_href_niltv(as, ir); /* Do this before any restores. */ | ||
| 978 | RegSet allow = RSET_GPR; | 960 | RegSet allow = RSET_GPR; |
| 961 | int destused = ra_used(ir); | ||
| 979 | Reg dest = ra_dest(as, ir, allow); | 962 | Reg dest = ra_dest(as, ir, allow); |
| 980 | Reg tab = ra_alloc1(as, ir->op1, rset_clear(allow, dest)); | 963 | Reg tab = ra_alloc1(as, ir->op1, rset_clear(allow, dest)); |
| 981 | Reg key = RID_NONE, tmp = RID_NONE; | 964 | Reg key = RID_NONE, tmp = RID_NONE; |
| @@ -992,14 +975,12 @@ static void asm_href(ASMState *as, IRIns *ir) | |||
| 992 | tmp = ra_scratch(as, rset_exclude(allow, key)); | 975 | tmp = ra_scratch(as, rset_exclude(allow, key)); |
| 993 | } | 976 | } |
| 994 | 977 | ||
| 995 | /* Key not found in chain: jump to exit (if merged with NE) or load niltv. */ | 978 | /* Key not found in chain: jump to exit (if merged) or load niltv. */ |
| 996 | l_end = emit_label(as); | 979 | l_end = emit_label(as); |
| 997 | if (nilexit && ir[1].o == IR_NE) { | 980 | if (merge == IR_NE) |
| 998 | emit_jcc(as, CC_E, nilexit); /* XI_JMP is not found by lj_asm_patchexit. */ | 981 | asm_guardcc(as, CC_E); /* XI_JMP is not found by lj_asm_patchexit. */ |
| 999 | nilexit = NULL; | 982 | else if (destused) |
| 1000 | } else { | ||
| 1001 | emit_loada(as, dest, niltvg(J2G(as->J))); | 983 | emit_loada(as, dest, niltvg(J2G(as->J))); |
| 1002 | } | ||
| 1003 | 984 | ||
| 1004 | /* Follow hash chain until the end. */ | 985 | /* Follow hash chain until the end. */ |
| 1005 | l_loop = emit_sjcc_label(as, CC_NZ); | 986 | l_loop = emit_sjcc_label(as, CC_NZ); |
| @@ -1008,8 +989,8 @@ static void asm_href(ASMState *as, IRIns *ir) | |||
| 1008 | l_next = emit_label(as); | 989 | l_next = emit_label(as); |
| 1009 | 990 | ||
| 1010 | /* Type and value comparison. */ | 991 | /* Type and value comparison. */ |
| 1011 | if (nilexit) | 992 | if (merge == IR_EQ) |
| 1012 | emit_jcc(as, CC_E, nilexit); | 993 | asm_guardcc(as, CC_E); |
| 1013 | else | 994 | else |
| 1014 | emit_sjcc(as, CC_E, l_end); | 995 | emit_sjcc(as, CC_E, l_end); |
| 1015 | if (irt_isnum(kt)) { | 996 | if (irt_isnum(kt)) { |
| @@ -2519,9 +2500,16 @@ static void asm_ir(ASMState *as, IRIns *ir) | |||
| 2519 | case IR_GCSTEP: asm_gcstep(as, ir); break; | 2500 | case IR_GCSTEP: asm_gcstep(as, ir); break; |
| 2520 | 2501 | ||
| 2521 | /* Guarded assertions. */ | 2502 | /* Guarded assertions. */ |
| 2503 | case IR_EQ: case IR_NE: | ||
| 2504 | if ((ir-1)->o == IR_HREF && ir->op1 == as->curins-1) { | ||
| 2505 | as->curins--; | ||
| 2506 | asm_href(as, ir-1, (IROp)ir->o); | ||
| 2507 | break; | ||
| 2508 | } | ||
| 2509 | /* fallthrough */ | ||
| 2522 | case IR_LT: case IR_GE: case IR_LE: case IR_GT: | 2510 | case IR_LT: case IR_GE: case IR_LE: case IR_GT: |
| 2523 | case IR_ULT: case IR_UGE: case IR_ULE: case IR_UGT: | 2511 | case IR_ULT: case IR_UGE: case IR_ULE: case IR_UGT: |
| 2524 | case IR_EQ: case IR_NE: case IR_ABC: | 2512 | case IR_ABC: |
| 2525 | asm_comp(as, ir, asm_compmap[ir->o]); | 2513 | asm_comp(as, ir, asm_compmap[ir->o]); |
| 2526 | break; | 2514 | break; |
| 2527 | 2515 | ||
| @@ -2615,7 +2603,7 @@ static void asm_ir(ASMState *as, IRIns *ir) | |||
| 2615 | 2603 | ||
| 2616 | /* Memory references. */ | 2604 | /* Memory references. */ |
| 2617 | case IR_AREF: asm_aref(as, ir); break; | 2605 | case IR_AREF: asm_aref(as, ir); break; |
| 2618 | case IR_HREF: asm_href(as, ir); break; | 2606 | case IR_HREF: asm_href(as, ir, 0); break; |
| 2619 | case IR_HREFK: asm_hrefk(as, ir); break; | 2607 | case IR_HREFK: asm_hrefk(as, ir); break; |
| 2620 | case IR_NEWREF: asm_newref(as, ir); break; | 2608 | case IR_NEWREF: asm_newref(as, ir); break; |
| 2621 | case IR_UREFO: case IR_UREFC: asm_uref(as, ir); break; | 2609 | case IR_UREFO: case IR_UREFC: asm_uref(as, ir); break; |
