diff options
Diffstat (limited to 'gcc/reload1.c')
-rw-r--r-- | gcc/reload1.c | 66 |
1 files changed, 42 insertions, 24 deletions
diff --git a/gcc/reload1.c b/gcc/reload1.c index ea7df99580d..e65503b9fa5 100644 --- a/gcc/reload1.c +++ b/gcc/reload1.c @@ -4471,6 +4471,43 @@ scan_paradoxical_subregs (rtx x) } } } + +/* *OP_PTR and *OTHER_PTR are two operands to a conceptual reload. + If *OP_PTR is a paradoxical subreg, try to remove that subreg + and apply the corresponding narrowing subreg to *OTHER_PTR. + Return true if the operands were changed, false otherwise. */ + +static bool +strip_paradoxical_subreg (rtx *op_ptr, rtx *other_ptr) +{ + rtx op, inner, other, tem; + + op = *op_ptr; + if (GET_CODE (op) != SUBREG) + return false; + + inner = SUBREG_REG (op); + if (GET_MODE_SIZE (GET_MODE (op)) <= GET_MODE_SIZE (GET_MODE (inner))) + return false; + + other = *other_ptr; + tem = gen_lowpart_common (GET_MODE (inner), other); + if (!tem) + return false; + + /* If the lowpart operation turned a hard register into a subreg, + rather than simplifying it to another hard register, then the + mode change cannot be properly represented. For example, OTHER + might be valid in its current mode, but not in the new one. */ + if (GET_CODE (tem) == SUBREG + && REG_P (other) + && HARD_REGISTER_P (other)) + return false; + + *op_ptr = inner; + *other_ptr = tem; + return true; +} /* A subroutine of reload_as_needed. If INSN has a REG_EH_REGION note, examine all of the reload insns between PREV and NEXT exclusive, and @@ -5538,7 +5575,7 @@ gen_reload_chain_without_interm_reg_p (int r1, int r2) chain reloads or do need an intermediate hard registers. */ bool result = true; int regno, n, code; - rtx out, in, tem, insn; + rtx out, in, insn; rtx last = get_last_insn (); /* Make r2 a component of r1. */ @@ -5557,11 +5594,7 @@ gen_reload_chain_without_interm_reg_p (int r1, int r2) /* If IN is a paradoxical SUBREG, remove it and try to put the opposite SUBREG on OUT. Likewise for a paradoxical SUBREG on OUT. */ - if (GET_CODE (in) == SUBREG - && (GET_MODE_SIZE (GET_MODE (in)) - > GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))) - && (tem = gen_lowpart_common (GET_MODE (SUBREG_REG (in)), out)) != 0) - in = SUBREG_REG (in), out = tem; + strip_paradoxical_subreg (&in, &out); if (GET_CODE (in) == PLUS && (REG_P (XEXP (in, 0)) @@ -7557,7 +7590,6 @@ emit_output_reload_insns (struct insn_chain *chain, struct reload *rl, if (tertiary_icode != CODE_FOR_nothing) { rtx third_reloadreg = rld[tertiary_reload].reg_rtx; - rtx tem; /* Copy primary reload reg to secondary reload reg. (Note that these have been swapped above, then @@ -7566,13 +7598,7 @@ emit_output_reload_insns (struct insn_chain *chain, struct reload *rl, /* If REAL_OLD is a paradoxical SUBREG, remove it and try to put the opposite SUBREG on RELOADREG. */ - if (GET_CODE (real_old) == SUBREG - && (GET_MODE_SIZE (GET_MODE (real_old)) - > GET_MODE_SIZE (GET_MODE (SUBREG_REG (real_old)))) - && 0 != (tem = gen_lowpart_common - (GET_MODE (SUBREG_REG (real_old)), - reloadreg))) - real_old = SUBREG_REG (real_old), reloadreg = tem; + strip_paradoxical_subreg (&real_old, &reloadreg); gen_reload (reloadreg, second_reloadreg, rl->opnum, rl->when_needed); @@ -8388,16 +8414,8 @@ gen_reload (rtx out, rtx in, int opnum, enum reload_type type) /* If IN is a paradoxical SUBREG, remove it and try to put the opposite SUBREG on OUT. Likewise for a paradoxical SUBREG on OUT. */ - if (GET_CODE (in) == SUBREG - && (GET_MODE_SIZE (GET_MODE (in)) - > GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))) - && (tem = gen_lowpart_common (GET_MODE (SUBREG_REG (in)), out)) != 0) - in = SUBREG_REG (in), out = tem; - else if (GET_CODE (out) == SUBREG - && (GET_MODE_SIZE (GET_MODE (out)) - > GET_MODE_SIZE (GET_MODE (SUBREG_REG (out)))) - && (tem = gen_lowpart_common (GET_MODE (SUBREG_REG (out)), in)) != 0) - out = SUBREG_REG (out), in = tem; + if (!strip_paradoxical_subreg (&in, &out)) + strip_paradoxical_subreg (&out, &in); /* How to do this reload can get quite tricky. Normally, we are being asked to reload a simple operand, such as a MEM, a constant, or a pseudo |