diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 5c8604f..47875ac 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -4710,6 +4710,51 @@ aarch64_legitimize_address (rtx x, rtx /* orig_x */, machine_mode mode) { HOST_WIDE_INT offset = INTVAL (XEXP (x, 1)); HOST_WIDE_INT base_offset; + rtx op0 = XEXP (x,0); + + if (GET_CODE (op0) == PLUS) + { + rtx op0_ = XEXP (op0, 0); + rtx op1_ = XEXP (op0, 1); + + /* RTX pattern in the form of (PLUS (PLUS REG, REG), CONST) will + reach here, the 'CONST' may be valid in which case we should + not split. */ + if (REG_P (op0_) && REG_P (op1_)) + { + machine_mode addr_mode = GET_MODE (op0); + rtx addr = gen_reg_rtx (addr_mode); + + rtx ret = plus_constant (addr_mode, addr, offset); + if (aarch64_legitimate_address_hook_p (mode, ret, false)) + { + emit_insn (gen_adddi3 (addr, op0_, op1_)); + return ret; + } + } + /* RTX pattern in the form of (PLUS (PLUS REG, NON_REG), CONST) + will reach here. If (PLUS REG, NON_REG) is valid addr expr, + we split it into Y=REG+CONST, Y+NON_REG. */ + else if (REG_P (op0_) || REG_P (op1_)) + { + machine_mode addr_mode = GET_MODE (op0); + rtx addr = gen_reg_rtx (addr_mode); + + /* Switch to make sure that register is in op0_. */ + if (REG_P (op1_)) + std::swap (op0_, op1_); + + rtx ret = gen_rtx_fmt_ee (PLUS, addr_mode, addr, op1_); + if (aarch64_legitimate_address_hook_p (mode, ret, false)) + { + addr = force_operand (plus_constant (addr_mode, + op0_, offset), + NULL_RTX); + ret = gen_rtx_fmt_ee (PLUS, addr_mode, addr, op1_); + return ret; + } + } + } /* Does it look like we'll need a load/store-pair operation? */ if (GET_MODE_SIZE (mode) > 16