[arm] Correct cost calculations involving borrow for subtracts.
authorRichard Earnshaw <rearnsha@arm.com>
Fri, 18 Oct 2019 19:02:50 +0000 (19:02 +0000)
committerRichard Earnshaw <rearnsha@gcc.gnu.org>
Fri, 18 Oct 2019 19:02:50 +0000 (19:02 +0000)
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.

From-SVN: r277173

gcc/ChangeLog
gcc/config/arm/arm.c

index aa6b2cb4254ebb08d94848c396ec7fe661dcb49a..e40511bf148d0f4a70fb2ea6c86b015952d7b3c1 100644 (file)
@@ -1,3 +1,8 @@
+2019-10-18  Richard Earnshaw  <rearnsha@arm.com>
+
+       * config/arm/arm.c (arm_rtx_costs_internal, case MINUS): Handle
+       borrow operations.
+
 2019-10-18  Richard Earnshaw  <rearnsha@arm.com>
 
        * config/arm/arm.c (strip_carry_operation): New function.
index 820a41f8a242722446f836e22e48437e81a48c4f..fd742226f16ed65b40137865ab1640c24b0700e3 100644 (file)
@@ -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