Browse Source

ARM64: Fuse BOR/BXOR and BNOT into ORN/EON.

Contributed by Djordje Kovacevic and Stefan Pejic from RT-RK.com.
Mike Pall 8 years ago
parent
commit
ebec2530be
2 changed files with 36 additions and 17 deletions
  1. 35 17
      src/lj_asm_arm64.h
  2. 1 0
      src/lj_target_arm64.h

+ 35 - 17
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)
 {

+ 1 - 0
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,