arm_rtx_costs prices (lshiftrt:DI (mult:DI (extend) (extend)) 32) as a
DImode shift on top of the multiply, 24 against 12, although SMULL,
UMULL and SMMUL compute it in one instruction.  The TRUNCATE case meant
to catch this is never reached: it tests ASHIFTRT, and rtx_cost does not
ask the port about a TRUNCATE between tieable modes.  Price the shift as
the multiply, remove the TRUNCATE case, and give SMUL_HIGHPART the same
price.  Both signs have to change together: pricing only the signed form
moved 63 unsigned divisions to SMMUL and grew the kernel by 32 bytes.

At -Os 621 of 1023 signed constant divisors now use SMMUL instead of
SMULL, at the same size.  bcmrpi_defconfig -O2 .text is 96 bytes
smaller; no gcc.c-torture/compile file changes size at -O2 or -Os on
arm1176jzf-s or cortex-a9.

Bootstrapped on x86_64-pc-linux-gnu, regression tested on arm-none-eabi.

Assisted-by: Claude Opus 5 (Anthropic)

gcc/ChangeLog:

        * config/arm/arm.cc (arm_rtx_costs_internal): Price a DImode
        logical shift by 32 of a widening multiply as that multiply.
        Add SMUL_HIGHPART.  Remove the TRUNCATE case.

Signed-off-by: Dominic P <[email protected]>
---
 gcc/config/arm/arm.cc | 39 ++++++++++++++++++---------------------
 1 file changed, 18 insertions(+), 21 deletions(-)

diff --git a/gcc/config/arm/arm.cc b/gcc/config/arm/arm.cc
index 33b64995442..c1d13f9d719 100644
--- a/gcc/config/arm/arm.cc
+++ b/gcc/config/arm/arm.cc
@@ -10758,6 +10758,18 @@ arm_rtx_costs_internal (rtx x, enum rtx_code code, 
enum rtx_code outer_code,
     case ASHIFTRT:
       if (mode == DImode && CONST_INT_P (XEXP (x, 1)))
        {
+         if (code == LSHIFTRT
+             && INTVAL (XEXP (x, 1)) == 32
+             && GET_CODE (XEXP (x, 0)) == MULT
+             && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SIGN_EXTEND
+                 || GET_CODE (XEXP (XEXP (x, 0), 0)) == ZERO_EXTEND)
+             && (GET_CODE (XEXP (XEXP (x, 0), 1))
+                 == GET_CODE (XEXP (XEXP (x, 0), 0))))
+           {
+             *cost = rtx_cost (XEXP (x, 0), mode, code, 0, speed_p);
+             return true;
+           }
+
          *cost += (COSTS_N_INSNS (2)
                   + rtx_cost (XEXP (x, 0), mode, code, 0, speed_p));
          if (speed_p)
@@ -12173,27 +12185,12 @@ arm_rtx_costs_internal (rtx x, enum rtx_code code, 
enum rtx_code outer_code,
       *cost += COSTS_N_INSNS (1);
       return false;
 
-    case TRUNCATE:
-      if (GET_CODE (XEXP (x, 0)) == ASHIFTRT
-         && CONST_INT_P (XEXP (XEXP (x, 0), 1))
-         && INTVAL (XEXP (XEXP (x, 0), 1)) == 32
-         && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
-         && ((GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == SIGN_EXTEND
-              && GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)) == SIGN_EXTEND)
-             || (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == ZERO_EXTEND
-                 && (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1))
-                     == ZERO_EXTEND))))
-       {
-         if (speed_p)
-           *cost += extra_cost->mult[1].extend;
-         *cost += (rtx_cost (XEXP (XEXP (XEXP (x, 0), 0), 0), VOIDmode,
-                             ZERO_EXTEND, 0, speed_p)
-                   + rtx_cost (XEXP (XEXP (XEXP (x, 0), 0), 1), VOIDmode,
-                               ZERO_EXTEND, 0, speed_p));
-         return true;
-       }
-      *cost = LIBCALL_COST (1);
-      return false;
+    case SMUL_HIGHPART:
+      if (speed_p)
+       *cost += extra_cost->mult[1].extend;
+      *cost += (rtx_cost (XEXP (x, 0), mode, code, 0, speed_p)
+               + rtx_cost (XEXP (x, 1), mode, code, 1, speed_p));
+      return true;
 
     case UNSPEC_VOLATILE:
     case UNSPEC:
-- 
2.55.0

Reply via email to