Hi all,This patch improves the rtx costs computation for the add/sub + shift operations for modes narrower than SImode. There's a bit of refactoring going on, but essentially they are computed in the same way that SImode costs for these operations are computed, except that only left-shifts are considered for the narrow ones.
Regtested arm-non-eabi on qemu and bootstrapped on a Chromebook before trunk for arm became unstable recently.
Ok for trunk? Thanks, Kyrill 2013-11-19 Kyrylo Tkachov <kyrylo.tkac...@arm.com> * config/arm/arm.c (arm_new_rtx_costs): Handle narrow mode add-shifts properly. * config/arm/arm-common.c (arm_rtx_shift_left_p): Remove static. * config/arm/arm-common-protos.h (arm_rtx_shift_left_p): Declare extern.
diff --git a/gcc/config/arm/aarch-common-protos.h b/gcc/config/arm/aarch-common-protos.h index 841f544..c3652a7 100644 --- a/gcc/config/arm/aarch-common-protos.h +++ b/gcc/config/arm/aarch-common-protos.h @@ -31,6 +31,7 @@ extern int arm_no_early_alu_shift_dep (rtx, rtx); extern int arm_no_early_alu_shift_value_dep (rtx, rtx); extern int arm_no_early_mul_dep (rtx, rtx); extern int arm_no_early_store_addr_dep (rtx, rtx); +extern bool arm_rtx_shift_left_p (rtx); /* RTX cost table definitions. These are used when tuning for speed rather than for size and should reflect the _additional_ cost over the cost diff --git a/gcc/config/arm/aarch-common.c b/gcc/config/arm/aarch-common.c index 201e581..a46e675 100644 --- a/gcc/config/arm/aarch-common.c +++ b/gcc/config/arm/aarch-common.c @@ -40,7 +40,7 @@ typedef struct /* Return TRUE if X is either an arithmetic shift left, or is a multiplication by a power of two. */ -static bool +bool arm_rtx_shift_left_p (rtx x) { enum rtx_code code = GET_CODE (x); diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index f0f6c89..a7abdfe 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -9203,6 +9203,29 @@ arm_new_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer_code, *cost = LIBCALL_COST (2); return false; +#define HANDLE_NARROW_SHIFT_ARITH(OP, IDX) \ + do \ + { \ + shift_op = shifter_op_p (XEXP (x, IDX), &shift_reg); \ + if (shift_op != NULL \ + && arm_rtx_shift_left_p (XEXP (x, IDX))) \ + { \ + if (shift_reg) \ + { \ + if (speed_p) \ + *cost += extra_cost->alu.arith_shift_reg; \ + *cost += rtx_cost (shift_reg, ASHIFT, 1, speed_p); \ + } \ + else if (speed_p) \ + *cost += extra_cost->alu.arith_shift; \ + \ + *cost += (rtx_cost (shift_op, ASHIFT, 0, speed_p) \ + + rtx_cost (XEXP (x, 1 - IDX), \ + OP, 1, speed_p)); \ + return true; \ + } \ + } \ + while (0); case MINUS: if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT && (mode == SFmode || !TARGET_VFP_SINGLE)) @@ -9309,6 +9332,15 @@ arm_new_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer_code, if (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE_SIZE (mode) < 4) { + rtx shift_op, shift_reg; + shift_reg = NULL; + + /* We check both sides of the MINUS for shifter operands since, + unlike PLUS, it's not commutative. */ + + HANDLE_NARROW_SHIFT_ARITH (MINUS, 0) + HANDLE_NARROW_SHIFT_ARITH (MINUS, 1) + /* Slightly disparage, as we might need to widen the result. */ *cost = 1 + COSTS_N_INSNS (1); if (speed_p) @@ -9408,11 +9440,20 @@ arm_new_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer_code, return false; } + /* Narrow modes can be synthesized in SImode, but the range + of useful sub-operations is limited. Check for shift operations + on one of the operands. Only left shifts can be used in the + narrow modes. */ if (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE_SIZE (mode) < 4) { - /* Narrow modes can be synthesized in SImode, but the range - of useful sub-operations is limited. */ + rtx shift_op, shift_reg; + shift_reg = NULL; + + HANDLE_NARROW_SHIFT_ARITH (PLUS, 0) + +#undef HANDLE_NARROW_SHIFT_ARITH + if (CONST_INT_P (XEXP (x, 1))) { int insns = arm_gen_constant (PLUS, SImode, NULL_RTX,