diff mbox series

[10/29,arm] Correct cost calculations involving borrow for subtracts.

Message ID 20191018194900.34795-11-Richard.Earnshaw@arm.com
State New
Headers show
Series Rewrite DImode arithmetic support | expand

Commit Message

Richard Earnshaw (lists) Oct. 18, 2019, 7:48 p.m. UTC
The rtx_cost calculations when a borrow operation was being performed were
not being calculated correctly.  The borrow is free as part of the
subtract-with-carry instructions.  This patch recognizes the various
idioms that can describe this and returns the correct costs.

	* config/arm/arm.c (arm_rtx_costs_internal, case MINUS): Handle
	borrow operations.
---
 gcc/config/arm/arm.c | 49 +++++++++++++++++++++++++++++++++++++-------
 1 file changed, 42 insertions(+), 7 deletions(-)
diff mbox series

Patch

diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index dfbd5cde5eb..b91b52f6d51 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -10049,15 +10049,46 @@  arm_rtx_costs_internal (rtx x, enum rtx_code code, enum rtx_code outer_code,
 	  rtx shift_by_reg = NULL;
 	  rtx shift_op;
 	  rtx non_shift_op;
+	  rtx op0 = XEXP (x, 0);
+	  rtx op1 = XEXP (x, 1);
 
-	  shift_op = shifter_op_p (XEXP (x, 0), &shift_by_reg);
+	  /* Factor out any borrow operation.  There's more than one way
+	     of expressing this; try to recognize them all.  */
+	  if (GET_CODE (op0) == MINUS)
+	    {
+	      if (arm_borrow_operation (op1, SImode))
+		{
+		  op1 = XEXP (op0, 1);
+		  op0 = XEXP (op0, 0);
+		}
+	      else if (arm_borrow_operation (XEXP (op0, 1), SImode))
+		op0 = XEXP (op0, 0);
+	    }
+	  else if (GET_CODE (op1) == PLUS
+		   && arm_borrow_operation (XEXP (op1, 0), SImode))
+	    op1 = XEXP (op1, 0);
+	  else if (GET_CODE (op0) == NEG
+		   && arm_borrow_operation (op1, SImode))
+	    {
+	      /* Negate with carry-in.  For Thumb2 this is done with
+		 SBC R, X, X lsl #1 (ie X - 2X - C) as Thumb lacks the
+		 RSC instruction that exists in Arm mode.  */
+	      if (speed_p)
+		*cost += (TARGET_THUMB2
+			  ? extra_cost->alu.arith_shift
+			  : extra_cost->alu.arith);
+	      *cost += rtx_cost (XEXP (op0, 0), mode, MINUS, 0, speed_p);
+	      return true;
+	    }
+
+	  shift_op = shifter_op_p (op0, &shift_by_reg);
 	  if (shift_op == NULL)
 	    {
-	      shift_op = shifter_op_p (XEXP (x, 1), &shift_by_reg);
-	      non_shift_op = XEXP (x, 0);
+	      shift_op = shifter_op_p (op1, &shift_by_reg);
+	      non_shift_op = op0;
 	    }
 	  else
-	    non_shift_op = XEXP (x, 1);
+	    non_shift_op = op1;
 
 	  if (shift_op != NULL)
 	    {
@@ -10087,10 +10118,10 @@  arm_rtx_costs_internal (rtx x, enum rtx_code code, enum rtx_code outer_code,
 	      return true;
 	    }
 
-	  if (CONST_INT_P (XEXP (x, 0)))
+	  if (CONST_INT_P (op0))
 	    {
 	      int insns = arm_gen_constant (MINUS, SImode, NULL_RTX,
-					    INTVAL (XEXP (x, 0)), NULL_RTX,
+					    INTVAL (op0), NULL_RTX,
 					    NULL_RTX, 1, 0);
 	      *cost = COSTS_N_INSNS (insns);
 	      if (speed_p)
@@ -10101,7 +10132,11 @@  arm_rtx_costs_internal (rtx x, enum rtx_code code, enum rtx_code outer_code,
 	  else if (speed_p)
 	    *cost += extra_cost->alu.arith;
 
-	  return false;
+	  /* Don't recurse as we don't want to cost any borrow that
+	     we've stripped.  */
+	  *cost += rtx_cost (op0, mode, MINUS, 0, speed_p);
+	  *cost += rtx_cost (op1, mode, MINUS, 1, speed_p);
+	  return true;
 	}
 
       if (GET_MODE_CLASS (mode) == MODE_INT