Blob Blame History Raw
From 24429cc95657332e3953a21581d3220884da3d75 Mon Sep 17 00:00:00 2001
From: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Wed, 8 May 2019 22:14:00 +0530
Subject: [PATCH] arm: Fix up condition codes for conditional arithmetic insn

When an arithmetic instruction such as add or sub are combined with a
subsequent compare with zero, its following conditional branch code
needs fixing up.  This is necessary because one could generate an add
with a subtract of the negative but such a substitution, while correct
on its own, will change the effect on condition flags since while
addition of two positive numbers may signal an overflow, addition of a
positive and a negative number may not.  So if earlier the condition
code was GE, it needs to be fixed up to PL to remain correct.

We did that for bit operations but not for arithmetic, so do that now.
---
 src/lj_asm_arm.h | 38 ++++++++++++++++++++------------------
 1 file changed, 20 insertions(+), 18 deletions(-)

diff --git a/src/lj_asm_arm.h b/src/lj_asm_arm.h
index 37bfa40f..e585b4c2 100644
--- a/src/lj_asm_arm.h
+++ b/src/lj_asm_arm.h
@@ -1412,13 +1412,28 @@ static void asm_intop(ASMState *as, IRIns *ir, ARMIns ai)
   emit_dn(as, ai^m, dest, left);
 }
 
-static void asm_intop_s(ASMState *as, IRIns *ir, ARMIns ai)
+static ARMIns maybe_drop_zero_cmp(ASMState *as, ARMIns ai)
 {
-  if (as->flagmcp == as->mcp) {  /* Drop cmp r, #0. */
+  if (as->flagmcp == as->mcp) {  /* Try to drop cmp r, #0. */
+    uint32_t cc = (as->mcp[1] >> 28);
     as->flagmcp = NULL;
-    as->mcp++;
-    ai |= ARMI_S;
+    if (cc <= CC_NE) {
+      as->mcp++;
+      ai |= ARMI_S;
+    } else if (cc == CC_GE) {
+      *++as->mcp ^= ((CC_GE^CC_PL) << 28);
+      ai |= ARMI_S;
+    } else if (cc == CC_LT) {
+      *++as->mcp ^= ((CC_LT^CC_MI) << 28);
+      ai |= ARMI_S;
+    }  /* else: other conds don't work with bit ops. */
   }
+  return ai;
+}
+
+static void asm_intop_s(ASMState *as, IRIns *ir, ARMIns ai)
+{
+  ai = maybe_drop_zero_cmp(as, ai);
   asm_intop(as, ir, ai);
 }
 
@@ -1514,20 +1529,7 @@ static void asm_neg(ASMState *as, IRIns *ir)
 
 static void asm_bitop(ASMState *as, IRIns *ir, ARMIns ai)
 {
-  if (as->flagmcp == as->mcp) {  /* Try to drop cmp r, #0. */
-    uint32_t cc = (as->mcp[1] >> 28);
-    as->flagmcp = NULL;
-    if (cc <= CC_NE) {
-      as->mcp++;
-      ai |= ARMI_S;
-    } else if (cc == CC_GE) {
-      *++as->mcp ^= ((CC_GE^CC_PL) << 28);
-      ai |= ARMI_S;
-    } else if (cc == CC_LT) {
-      *++as->mcp ^= ((CC_LT^CC_MI) << 28);
-      ai |= ARMI_S;
-    }  /* else: other conds don't work with bit ops. */
-  }
+  ai = maybe_drop_zero_cmp(as, ai);
   if (ir->op2 == 0) {
     Reg dest = ra_dest(as, ir, RSET_GPR);
     uint32_t m = asm_fuseopm(as, ai, ir->op1, RSET_GPR);
-- 
2.21.0