aboutsummaryrefslogtreecommitdiff
path: root/gcc/lra-constraints.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/lra-constraints.cc')
-rw-r--r--gcc/lra-constraints.cc60
1 files changed, 36 insertions, 24 deletions
diff --git a/gcc/lra-constraints.cc b/gcc/lra-constraints.cc
index 68aaf86..c941d2f 100644
--- a/gcc/lra-constraints.cc
+++ b/gcc/lra-constraints.cc
@@ -2416,14 +2416,15 @@ process_alt_operands (int only_alternative)
if (curr_static_id->operand[nop].type == OP_INOUT
|| curr_static_id->operand[m].type == OP_INOUT)
break;
- /* Operands don't match. If the operands are
- different user defined explicit hard
+ /* Operands don't match. For asm if the operands
+ are different user defined explicit hard
registers, then we cannot make them match
when one is early clobber operand. */
if ((REG_P (*curr_id->operand_loc[nop])
|| SUBREG_P (*curr_id->operand_loc[nop]))
&& (REG_P (*curr_id->operand_loc[m])
- || SUBREG_P (*curr_id->operand_loc[m])))
+ || SUBREG_P (*curr_id->operand_loc[m]))
+ && INSN_CODE (curr_insn) < 0)
{
rtx nop_reg = *curr_id->operand_loc[nop];
if (SUBREG_P (nop_reg))
@@ -3328,19 +3329,15 @@ process_alt_operands (int only_alternative)
first_conflict_j = j;
last_conflict_j = j;
/* Both the earlyclobber operand and conflicting operand
- cannot both be user defined hard registers. */
+ cannot both be user defined hard registers for asm.
+ Let curr_insn_transform diagnose it. */
if (HARD_REGISTER_P (operand_reg[i])
&& REG_USERVAR_P (operand_reg[i])
&& operand_reg[j] != NULL_RTX
&& HARD_REGISTER_P (operand_reg[j])
- && REG_USERVAR_P (operand_reg[j]))
- {
- /* For asm, let curr_insn_transform diagnose it. */
- if (INSN_CODE (curr_insn) < 0)
+ && REG_USERVAR_P (operand_reg[j])
+ && INSN_CODE (curr_insn) < 0)
return false;
- fatal_insn ("unable to generate reloads for "
- "impossible constraints:", curr_insn);
- }
}
if (last_conflict_j < 0)
continue;
@@ -3930,6 +3927,16 @@ process_address_1 (int nop, bool check_only_p,
enum reg_class cl;
rtx set;
rtx_insn *insns, *last_insn;
+
+ cl = base_reg_class (ad.mode, ad.as, ad.base_outer_code,
+ get_index_code (&ad), curr_insn);
+
+ if (REG_P (*ad.base_term)
+ && ira_class_subset_p[get_reg_class (REGNO (*ad.base_term))][cl])
+ /* It seems base reg is already in the base reg class and changing it
+ does not make a progress. So reload the whole inner address. */
+ goto reload_inner_addr;
+
/* Try to reload base into register only if the base is invalid
for the address but with valid offset, case (4) above. */
start_sequence ();
@@ -3975,8 +3982,6 @@ process_address_1 (int nop, bool check_only_p,
{
*ad.base_term = XEXP (SET_SRC (set), 0);
*ad.disp_term = XEXP (SET_SRC (set), 1);
- cl = base_reg_class (ad.mode, ad.as, ad.base_outer_code,
- get_index_code (&ad), curr_insn);
regno = REGNO (*ad.base_term);
if (regno >= FIRST_PSEUDO_REGISTER
&& cl != lra_get_allocno_class (regno))
@@ -4019,11 +4024,11 @@ process_address_1 (int nop, bool check_only_p,
}
else
{
- enum reg_class cl = base_reg_class (ad.mode, ad.as,
- SCRATCH, SCRATCH,
- curr_insn);
- rtx addr = *ad.inner;
-
+ enum reg_class cl;
+ rtx addr;
+ reload_inner_addr:
+ cl = base_reg_class (ad.mode, ad.as, SCRATCH, SCRATCH, curr_insn);
+ addr = *ad.inner;
new_reg = lra_create_new_reg (Pmode, NULL_RTX, cl, NULL, "addr");
/* addr => new_base. */
lra_emit_move (new_reg, addr);
@@ -4044,14 +4049,21 @@ process_address (int nop, bool check_only_p,
rtx_insn **before, rtx_insn **after)
{
bool res = false;
-
- while (process_address_1 (nop, check_only_p, before, after))
+ /* Use enough iterations to process all address parts: */
+ for (int i = 0; i < 10; i++)
{
- if (check_only_p)
- return true;
- res = true;
+ if (!process_address_1 (nop, check_only_p, before, after))
+ {
+ return res;
+ }
+ else
+ {
+ if (check_only_p)
+ return true;
+ res = true;
+ }
}
- return res;
+ fatal_insn ("unable to reload address in ", curr_insn);
}
/* Override the generic address_reload_context in order to