diff --git a/src/lj_asm_arm64.h b/src/lj_asm_arm64.h index 372429db..28050bf8 100644 --- a/src/lj_asm_arm64.h +++ b/src/lj_asm_arm64.h @@ -1464,40 +1464,58 @@ static void asm_neg(ASMState *as, IRIns *ir) asm_intneg(as, ir); } -static void asm_bitop(ASMState *as, IRIns *ir, A64Ins ai) +static void asm_band(ASMState *as, IRIns *ir) { - if (as->flagmcp == as->mcp && ai == A64I_ANDw) { + A64Ins ai = A64I_ANDw; + if (asm_fuseandshift(as, ir)) + return; + if (as->flagmcp == as->mcp) { /* Try to drop cmp r, #0. */ as->flagmcp = NULL; as->mcp++; - ai += A64I_ANDSw - A64I_ANDw; + ai = A64I_ANDSw; } - if (ir->op2 == 0) { - Reg dest = ra_dest(as, ir, RSET_GPR); - uint32_t m = asm_fuseopm(as, ai, ir->op1, RSET_GPR); + asm_intop(as, ir, ai); +} + +static void asm_borbxor(ASMState *as, IRIns *ir, A64Ins ai) +{ + IRRef lref = ir->op1, rref = ir->op2; + IRIns *irl = IR(lref), *irr = IR(rref); + if ((canfuse(as, irl) && irl->o == IR_BNOT && !irref_isk(rref)) || + (canfuse(as, irr) && irr->o == IR_BNOT && !irref_isk(lref))) { + Reg left, dest = ra_dest(as, ir, RSET_GPR); + uint32_t m; + if (irl->o == IR_BNOT) { + IRRef tmp = lref; lref = rref; rref = tmp; + } + left = ra_alloc1(as, lref, RSET_GPR); + ai |= A64I_ON; if (irt_is64(ir->t)) ai |= A64I_X; - emit_d(as, ai^m, dest); + m = asm_fuseopm(as, ai, IR(rref)->op1, rset_exclude(RSET_GPR, left)); + emit_dn(as, ai^m, dest, left); } else { asm_intop(as, ir, ai); } } -static void asm_band(ASMState *as, IRIns *ir) -{ - if (asm_fuseandshift(as, ir)) - return; - asm_bitop(as, ir, A64I_ANDw); -} - static void asm_bor(ASMState *as, IRIns *ir) { if (asm_fuseorshift(as, ir)) return; - asm_bitop(as, ir, A64I_ORRw); + asm_borbxor(as, ir, A64I_ORRw); } -#define asm_bnot(as, ir) asm_bitop(as, ir, A64I_MVNw) -#define asm_bxor(as, ir) asm_bitop(as, ir, A64I_EORw) +#define asm_bxor(as, ir) asm_borbxor(as, ir, A64I_EORw) + +static void asm_bnot(ASMState *as, IRIns *ir) +{ + A64Ins ai = A64I_MVNw; + Reg dest = ra_dest(as, ir, RSET_GPR); + uint32_t m = asm_fuseopm(as, ai, ir->op1, RSET_GPR); + if (irt_is64(ir->t)) ai |= A64I_X; + emit_d(as, ai^m, dest); +} static void asm_bswap(ASMState *as, IRIns *ir) { diff --git a/src/lj_target_arm64.h b/src/lj_target_arm64.h index f77a58a0..9e9fbd01 100644 --- a/src/lj_target_arm64.h +++ b/src/lj_target_arm64.h @@ -142,6 +142,7 @@ typedef enum A64Ins { A64I_S = 0x20000000, A64I_X = 0x80000000, A64I_EX = 0x00200000, + A64I_ON = 0x00200000, A64I_K12 = 0x1a000000, A64I_K13 = 0x18000000, A64I_LS_U = 0x01000000,