Hi, This patch refines scaled address expression on ARM. It supports "base+index*scale" in arm_legitimate_address_outer_p. It also tries to legitimize "base + index * scale + offset" with "reg <- base + offset; reg + index * scale" by introducing thumb2_legitimize_address. For now function thumb2_legitimize_address is a kind of placeholder and just does the mentioned transformation by calling to try_multiplier_address. Hoping we can improve it in the future.
With this patch: 1) "base+index*scale" is recognized. 2) PR57540 is fixed. Bootstrapped and Tested on A15. Is it OK? Thanks. Bin 2013-08-28 Bin Cheng <bin.ch...@arm.com> * config/arm/arm.c (arm_legitimate_address_outer_p): Support addressing mode like "base + index * scale". (try_multiplier_address): New function. (arm_legitimize_address): Call try_multiplier_address.
Index: gcc/config/arm/arm.c =================================================================== --- gcc/config/arm/arm.c (revision 200774) +++ gcc/config/arm/arm.c (working copy) @@ -5931,7 +5931,9 @@ arm_legitimate_address_outer_p (enum machine_mode && arm_legitimate_index_p (mode, xop1, outer, strict_p)) || (!strict_p && will_be_in_index_register (xop1)))) || (arm_address_register_rtx_p (xop1, strict_p) - && arm_legitimate_index_p (mode, xop0, outer, strict_p))); + && arm_legitimate_index_p (mode, xop0, outer, strict_p)) + || (arm_address_register_rtx_p (xop0, strict_p) + && arm_legitimate_index_p (mode, xop1, outer, strict_p))); } #if 0 @@ -6652,6 +6654,106 @@ legitimize_tls_address (rtx x, rtx reg) } } +/* Try to find address expression like base + index * scale + offset + in X. If we find one, force base + offset into register and + construct new expression reg + index * scale; return the new + address expression if it's valid. Otherwise return X. */ +static rtx +try_multiplier_address (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + rtx tmp, base_reg, new_rtx; + rtx base = NULL_RTX, index = NULL_RTX, scale = NULL_RTX, offset = NULL_RTX; + + gcc_assert (GET_CODE (x) == PLUS); + + /* Try to find and record base/index/scale/offset in X. */ + if (GET_CODE (XEXP (x, 1)) == MULT) + { + tmp = XEXP (x, 0); + index = XEXP (XEXP (x, 1), 0); + scale = XEXP (XEXP (x, 1), 1); + if (GET_CODE (tmp) != PLUS) + return x; + + base = XEXP (tmp, 0); + offset = XEXP (tmp, 1); + } + else + { + tmp = XEXP (x, 0); + offset = XEXP (x, 1); + if (GET_CODE (tmp) != PLUS) + return x; + + base = XEXP (tmp, 0); + scale = XEXP (tmp, 1); + if (GET_CODE (base) == MULT) + { + tmp = base; + base = scale; + scale = tmp; + } + if (GET_CODE (scale) != MULT) + return x; + + index = XEXP (scale, 0); + scale = XEXP (scale, 1); + } + + if (CONST_INT_P (base)) + { + tmp = base; + base = offset; + offset = tmp; + } + + if (CONST_INT_P (index)) + { + tmp = index; + index = scale; + scale = tmp; + } + + /* ARM only supports constant scale in address. */ + if (!CONST_INT_P (scale)) + return x; + + if (GET_MODE (base) != SImode || GET_MODE (index) != SImode) + return x; + + /* Only register/constant are allowed in each part. */ + if (!symbol_mentioned_p (base) + && !symbol_mentioned_p (offset) + && !symbol_mentioned_p (index) + && !symbol_mentioned_p (scale)) + { + /* Force "base+offset" into register and construct + "register+index*scale". Return the new expression + only if it's valid. */ + tmp = gen_rtx_PLUS (SImode, base, offset); + base_reg = force_reg (SImode, tmp); + tmp = gen_rtx_fmt_ee (MULT, SImode, index, scale); + new_rtx = gen_rtx_PLUS (SImode, base_reg, tmp); + return new_rtx; + } + + return x; +} + +/* Try machine-dependent ways of modifying an illegitimate Thumb2 address + to be legitimate. If we find one, return the new address. + + TODO: legitimize_address for Thumb2. */ +static rtx +thumb2_legitimize_address (rtx x, rtx orig_x ATTRIBUTE_UNUSED, + enum machine_mode mode) +{ + if (GET_CODE (x) == PLUS) + return try_multiplier_address (x, mode); + + return x; +} + /* Try machine-dependent ways of modifying an illegitimate address to be legitimate. If we find one, return the new, valid address. */ rtx @@ -6659,9 +6761,9 @@ arm_legitimize_address (rtx x, rtx orig_x, enum ma { if (!TARGET_ARM) { - /* TODO: legitimize_address for Thumb2. */ if (TARGET_THUMB2) - return x; + return thumb2_legitimize_address (x, orig_x, mode); + return thumb_legitimize_address (x, orig_x, mode); } @@ -6673,6 +6775,10 @@ arm_legitimize_address (rtx x, rtx orig_x, enum ma rtx xop0 = XEXP (x, 0); rtx xop1 = XEXP (x, 1); + rtx new_rtx = try_multiplier_address (x, mode); + if (new_rtx != x) + return new_rtx; + if (CONSTANT_P (xop0) && !symbol_mentioned_p (xop0)) xop0 = force_reg (SImode, xop0);