aboutsummaryrefslogtreecommitdiff
path: root/gcc/reload.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/reload.c')
-rw-r--r--gcc/reload.c165
1 files changed, 119 insertions, 46 deletions
diff --git a/gcc/reload.c b/gcc/reload.c
index 9849aed..ea5bea6 100644
--- a/gcc/reload.c
+++ b/gcc/reload.c
@@ -791,7 +791,7 @@ reload_inner_reg_of_subreg (x, mode)
return 0;
/* If INNER is not ok for MODE, then INNER will need reloading. */
- if (! HARD_REGNO_MODE_OK (REGNO (inner) + SUBREG_WORD (x), mode))
+ if (! HARD_REGNO_MODE_OK (subreg_regno (x), mode))
return 1;
/* If the outer part is a word or smaller, INNER larger than a
@@ -938,13 +938,12 @@ push_reload (in, out, inloc, outloc, class,
Finally, reload the inner expression if it is a register that is in
the class whose registers cannot be referenced in a different size
- and M1 is not the same size as M2. If SUBREG_WORD is nonzero, we
+ and M1 is not the same size as M2. If SUBREG_BYTE is nonzero, we
cannot reload just the inside since we might end up with the wrong
register class. But if it is inside a STRICT_LOW_PART, we have
no choice, so we hope we do get the right register class there. */
if (in != 0 && GET_CODE (in) == SUBREG
- && (SUBREG_WORD (in) == 0 || strict_low)
#ifdef CLASS_CANNOT_CHANGE_MODE
&& (class != CLASS_CANNOT_CHANGE_MODE
|| ! CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (in)), inmode))
@@ -978,7 +977,7 @@ push_reload (in, out, inloc, outloc, class,
&& REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
/* The case where out is nonzero
is handled differently in the following statement. */
- && (out == 0 || SUBREG_WORD (in) == 0)
+ && (out == 0 || SUBREG_BYTE (in) == 0)
&& ((GET_MODE_SIZE (inmode) <= UNITS_PER_WORD
&& (GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
> UNITS_PER_WORD)
@@ -986,9 +985,7 @@ push_reload (in, out, inloc, outloc, class,
/ UNITS_PER_WORD)
!= HARD_REGNO_NREGS (REGNO (SUBREG_REG (in)),
GET_MODE (SUBREG_REG (in)))))
- || ! HARD_REGNO_MODE_OK ((REGNO (SUBREG_REG (in))
- + SUBREG_WORD (in)),
- inmode)))
+ || ! HARD_REGNO_MODE_OK (subreg_regno (in), inmode)))
#ifdef SECONDARY_INPUT_RELOAD_CLASS
|| (SECONDARY_INPUT_RELOAD_CLASS (class, inmode, in) != NO_REGS
&& (SECONDARY_INPUT_RELOAD_CLASS (class,
@@ -1028,7 +1025,7 @@ push_reload (in, out, inloc, outloc, class,
that case. */
/* Similar issue for (SUBREG constant ...) if it was not handled by the
- code above. This can happen if SUBREG_WORD != 0. */
+ code above. This can happen if SUBREG_BYTE != 0. */
if (in != 0 && reload_inner_reg_of_subreg (in, inmode))
{
@@ -1038,7 +1035,11 @@ push_reload (in, out, inloc, outloc, class,
RELOAD_OTHER, we are guaranteed that this inner reload will be
output before the outer reload. */
push_reload (SUBREG_REG (in), NULL_RTX, &SUBREG_REG (in), NULL_PTR,
- find_valid_class (inmode, SUBREG_WORD (in)),
+ find_valid_class (inmode,
+ subreg_regno_offset (REGNO (SUBREG_REG (in)),
+ GET_MODE (SUBREG_REG (in)),
+ SUBREG_BYTE (in),
+ GET_MODE (in))),
VOIDmode, VOIDmode, 0, 0, opnum, type);
dont_remove_subreg = 1;
}
@@ -1050,7 +1051,7 @@ push_reload (in, out, inloc, outloc, class,
(except in the case of STRICT_LOW_PART,
and in that case the constraint should label it input-output.) */
if (out != 0 && GET_CODE (out) == SUBREG
- && (SUBREG_WORD (out) == 0 || strict_low)
+ && (SUBREG_BYTE (out) == 0 || strict_low)
#ifdef CLASS_CANNOT_CHANGE_MODE
&& (class != CLASS_CANNOT_CHANGE_MODE
|| ! CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (out)),
@@ -1080,9 +1081,7 @@ push_reload (in, out, inloc, outloc, class,
/ UNITS_PER_WORD)
!= HARD_REGNO_NREGS (REGNO (SUBREG_REG (out)),
GET_MODE (SUBREG_REG (out)))))
- || ! HARD_REGNO_MODE_OK ((REGNO (SUBREG_REG (out))
- + SUBREG_WORD (out)),
- outmode)))
+ || ! HARD_REGNO_MODE_OK (subreg_regno (out), outmode)))
#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
|| (SECONDARY_OUTPUT_RELOAD_CLASS (class, outmode, out) != NO_REGS
&& (SECONDARY_OUTPUT_RELOAD_CLASS (class,
@@ -1129,7 +1128,11 @@ push_reload (in, out, inloc, outloc, class,
dont_remove_subreg = 1;
push_reload (SUBREG_REG (out), SUBREG_REG (out), &SUBREG_REG (out),
&SUBREG_REG (out),
- find_valid_class (outmode, SUBREG_WORD (out)),
+ find_valid_class (outmode,
+ subreg_regno_offset (REGNO (SUBREG_REG (out)),
+ GET_MODE (SUBREG_REG (out)),
+ SUBREG_BYTE (out),
+ GET_MODE (out))),
VOIDmode, VOIDmode, 0, 0,
opnum, RELOAD_OTHER);
}
@@ -1146,16 +1149,14 @@ push_reload (in, out, inloc, outloc, class,
if (in != 0 && GET_CODE (in) == SUBREG && GET_CODE (SUBREG_REG (in)) == REG
&& REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
&& ! dont_remove_subreg)
- in = gen_rtx_REG (GET_MODE (in),
- REGNO (SUBREG_REG (in)) + SUBREG_WORD (in));
+ in = gen_rtx_REG (GET_MODE (in), subreg_regno (in));
/* Similarly for OUT. */
if (out != 0 && GET_CODE (out) == SUBREG
&& GET_CODE (SUBREG_REG (out)) == REG
&& REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER
&& ! dont_remove_subreg)
- out = gen_rtx_REG (GET_MODE (out),
- REGNO (SUBREG_REG (out)) + SUBREG_WORD (out));
+ out = gen_rtx_REG (GET_MODE (out), subreg_regno (out));
/* Narrow down the class of register wanted if that is
desirable on this machine for efficiency. */
@@ -1810,15 +1811,28 @@ find_dummy_reload (real_in, real_out, inloc, outloc,
|| GET_MODE_SIZE (inmode) > UNITS_PER_WORD))
return 0;
+ /* Note that {in,out}_offset are needed only when 'in' or 'out'
+ respectively refers to a hard register. */
+
/* Find the inside of any subregs. */
while (GET_CODE (out) == SUBREG)
{
- out_offset = SUBREG_WORD (out);
+ if (GET_CODE (SUBREG_REG (out)) == REG
+ && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER)
+ out_offset += subreg_regno_offset (REGNO (SUBREG_REG (out)),
+ GET_MODE (SUBREG_REG (out)),
+ SUBREG_BYTE (out),
+ GET_MODE (out));
out = SUBREG_REG (out);
}
while (GET_CODE (in) == SUBREG)
{
- in_offset = SUBREG_WORD (in);
+ if (GET_CODE (SUBREG_REG (in)) == REG
+ && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER)
+ in_offset += subreg_regno_offset (REGNO (SUBREG_REG (in)),
+ GET_MODE (SUBREG_REG (in)),
+ SUBREG_BYTE (in),
+ GET_MODE (in));
in = SUBREG_REG (in);
}
@@ -2035,7 +2049,10 @@ operands_match_p (x, y)
i = REGNO (SUBREG_REG (x));
if (i >= FIRST_PSEUDO_REGISTER)
goto slow;
- i += SUBREG_WORD (x);
+ i += subreg_regno_offset (REGNO (SUBREG_REG (x)),
+ GET_MODE (SUBREG_REG (x)),
+ SUBREG_BYTE (x),
+ GET_MODE (x));
}
else
i = REGNO (x);
@@ -2045,7 +2062,10 @@ operands_match_p (x, y)
j = REGNO (SUBREG_REG (y));
if (j >= FIRST_PSEUDO_REGISTER)
goto slow;
- j += SUBREG_WORD (y);
+ j += subreg_regno_offset (REGNO (SUBREG_REG (y)),
+ GET_MODE (SUBREG_REG (y)),
+ SUBREG_BYTE (y),
+ GET_MODE (y));
}
else
j = REGNO (y);
@@ -2777,7 +2797,18 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
while (GET_CODE (operand) == SUBREG)
{
- offset += SUBREG_WORD (operand);
+ /* Offset only matters when operand is a REG and
+ it is a hard reg. This is because it is passed
+ to reg_fits_class_p if it is a REG and all pseudos
+ return 0 from that function. */
+ if (GET_CODE (SUBREG_REG (operand)) == REG
+ && REGNO (SUBREG_REG (operand)) < FIRST_PSEUDO_REGISTER)
+ {
+ offset += subreg_regno_offset (REGNO (SUBREG_REG (operand)),
+ GET_MODE (SUBREG_REG (operand)),
+ SUBREG_BYTE (operand),
+ GET_MODE (operand));
+ }
operand = SUBREG_REG (operand);
/* Force reload if this is a constant or PLUS or if there may
be a problem accessing OPERAND in the outer mode. */
@@ -2828,6 +2859,11 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
)
#endif
)
+ /* This following hunk of code should no longer be
+ needed at all with SUBREG_BYTE. If you need this
+ code back, please explain to me why so I can
+ fix the real problem. -DaveM */
+#if 0
/* Subreg of a hard reg which can't handle the subreg's mode
or which would handle that mode in the wrong number of
registers for subregging to work. */
@@ -2841,7 +2877,9 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
!= HARD_REGNO_NREGS (REGNO (operand),
GET_MODE (operand))))
|| ! HARD_REGNO_MODE_OK (REGNO (operand) + offset,
- operand_mode[i]))))
+ operand_mode[i])))
+#endif
+ )
force_reload = 1;
}
@@ -3716,7 +3754,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
rtx operand = recog_data.operand[i];
while (GET_CODE (operand) == SUBREG)
- operand = XEXP (operand, 0);
+ operand = SUBREG_REG (operand);
if ((GET_CODE (operand) == MEM
|| (GET_CODE (operand) == REG
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER))
@@ -3766,7 +3804,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
operand = *recog_data.operand_loc[i];
while (GET_CODE (operand) == SUBREG)
- operand = XEXP (operand, 0);
+ operand = SUBREG_REG (operand);
if (GET_CODE (operand) == REG)
{
if (modified[i] != RELOAD_WRITE)
@@ -3789,7 +3827,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
rtx operand = recog_data.operand[i];
while (GET_CODE (operand) == SUBREG)
- operand = XEXP (operand, 0);
+ operand = SUBREG_REG (operand);
if ((GET_CODE (operand) == MEM
|| (GET_CODE (operand) == REG
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER))
@@ -4303,7 +4341,7 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest, insn,
&& regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
&& reg_equiv_constant[regno] != 0
&& (tem = operand_subword (reg_equiv_constant[regno],
- SUBREG_WORD (x), 0,
+ SUBREG_BYTE (x) / UNITS_PER_WORD, 0,
GET_MODE (SUBREG_REG (x)))) != 0)
{
/* TEM is now a word sized constant for the bits from X that
@@ -4329,7 +4367,7 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest, insn,
&& (GET_MODE_SIZE (GET_MODE (x))
< GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
{
- int shift = SUBREG_WORD (x) * BITS_PER_WORD;
+ int shift = SUBREG_BYTE (x) * BITS_PER_UNIT;
if (WORDS_BIG_ENDIAN)
shift = (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x)))
- GET_MODE_BITSIZE (GET_MODE (x))
@@ -4383,13 +4421,18 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest, insn,
the meaning of the memory access. */
enum machine_mode subreg_mode = GET_MODE (SUBREG_REG (x));
+ /* SUBREG_REG (x) is a MEM, so we cant take the offset, instead we
+ calculate the register number as :
+ SUBREG_BYTE (x) / GET_MODE_SIZE (subreg_mode) */
if (is_set_dest)
push_reload (NULL_RTX, SUBREG_REG (x), NULL_PTR, &SUBREG_REG (x),
- find_valid_class (subreg_mode, SUBREG_WORD (x)),
+ find_valid_class (subreg_mode,
+ SUBREG_BYTE (x) / GET_MODE_SIZE (subreg_mode)),
VOIDmode, subreg_mode, 0, 0, opnum, type);
else
push_reload (SUBREG_REG (x), NULL_RTX, &SUBREG_REG (x), NULL_PTR,
- find_valid_class (subreg_mode, SUBREG_WORD (x)),
+ find_valid_class (subreg_mode,
+ SUBREG_BYTE (x) / GET_MODE_SIZE (subreg_mode)),
subreg_mode, VOIDmode, 0, 0, opnum, type);
}
@@ -5075,7 +5118,11 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
code0 = GET_CODE (op0);
if (code0 == REG && REGNO (op0) < FIRST_PSEUDO_REGISTER)
op0 = gen_rtx_REG (word_mode,
- REGNO (op0) + SUBREG_WORD (orig_op0));
+ (REGNO (op0) +
+ subreg_regno_offset (REGNO (SUBREG_REG (orig_op0)),
+ GET_MODE (SUBREG_REG (orig_op0)),
+ SUBREG_BYTE (orig_op0),
+ GET_MODE (orig_op0))));
}
if (GET_CODE (op1) == SUBREG)
@@ -5083,8 +5130,14 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
op1 = SUBREG_REG (op1);
code1 = GET_CODE (op1);
if (code1 == REG && REGNO (op1) < FIRST_PSEUDO_REGISTER)
+ /* ??? Why is this given op1's mode and above for
+ ??? op0 SUBREGs we use word_mode? */
op1 = gen_rtx_REG (GET_MODE (op1),
- REGNO (op1) + SUBREG_WORD (orig_op1));
+ (REGNO (op1) +
+ subreg_regno_offset (REGNO (SUBREG_REG (orig_op1)),
+ GET_MODE (SUBREG_REG (orig_op1)),
+ SUBREG_BYTE (orig_op1),
+ GET_MODE (orig_op1))));
}
if (code0 == MULT || code0 == SIGN_EXTEND || code0 == TRUNCATE
@@ -5492,7 +5545,7 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
needless copies if SUBREG_REG is multi-word. */
if (REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER)
{
- int regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x);
+ int regno = subreg_regno (x);
if (! (context ? REGNO_OK_FOR_INDEX_P (regno)
: REGNO_MODE_OK_FOR_BASE_P (regno, mode)))
@@ -5646,15 +5699,10 @@ find_reloads_subreg_address (x, force_replace, opnum, type,
if (force_replace
|| ! rtx_equal_p (tem, reg_equiv_mem[regno]))
{
- int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
+ int offset = SUBREG_BYTE (x);
unsigned outer_size = GET_MODE_SIZE (GET_MODE (x));
unsigned inner_size = GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)));
- if (BYTES_BIG_ENDIAN)
- {
- offset += MIN (inner_size, UNITS_PER_WORD);
- offset -= MIN (outer_size, UNITS_PER_WORD);
- }
XEXP (tem, 0) = plus_constant (XEXP (tem, 0), offset);
PUT_MODE (tem, GET_MODE (x));
@@ -5741,8 +5789,18 @@ subst_reloads (insn)
*r->subreg_loc = SUBREG_REG (reloadreg);
else
{
+ int final_offset =
+ SUBREG_BYTE (*r->subreg_loc) + SUBREG_BYTE (reloadreg);
+
+ /* When working with SUBREGs the rule is that the byte
+ offset must be a multiple of the SUBREG's mode. */
+ final_offset = (final_offset /
+ GET_MODE_SIZE (GET_MODE (*r->subreg_loc)));
+ final_offset = (final_offset *
+ GET_MODE_SIZE (GET_MODE (*r->subreg_loc)));
+
*r->where = SUBREG_REG (reloadreg);
- SUBREG_WORD (*r->subreg_loc) += SUBREG_WORD (reloadreg);
+ SUBREG_BYTE (*r->subreg_loc) = final_offset;
}
}
else
@@ -5843,12 +5901,24 @@ find_replacement (loc)
if (GET_CODE (reloadreg) == REG)
return gen_rtx_REG (GET_MODE (*loc),
- REGNO (reloadreg) + SUBREG_WORD (*loc));
+ (REGNO (reloadreg) +
+ subreg_regno_offset (REGNO (SUBREG_REG (*loc)),
+ GET_MODE (SUBREG_REG (*loc)),
+ SUBREG_BYTE (*loc),
+ GET_MODE (*loc))));
else if (GET_MODE (reloadreg) == GET_MODE (*loc))
return reloadreg;
else
- return gen_rtx_SUBREG (GET_MODE (*loc), SUBREG_REG (reloadreg),
- SUBREG_WORD (reloadreg) + SUBREG_WORD (*loc));
+ {
+ int final_offset = SUBREG_BYTE (reloadreg) + SUBREG_BYTE (*loc);
+
+ /* When working with SUBREGs the rule is that the byte
+ offset must be a multiple of the SUBREG's mode. */
+ final_offset = (final_offset / GET_MODE_SIZE (GET_MODE (*loc)));
+ final_offset = (final_offset * GET_MODE_SIZE (GET_MODE (*loc)));
+ return gen_rtx_SUBREG (GET_MODE (*loc), SUBREG_REG (reloadreg),
+ final_offset);
+ }
}
}
@@ -5925,7 +5995,7 @@ refers_to_regno_for_reload_p (regno, endregno, x, loc)
if (GET_CODE (SUBREG_REG (x)) == REG
&& REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER)
{
- unsigned int inner_regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x);
+ unsigned int inner_regno = subreg_regno (x);
unsigned int inner_endregno
= inner_regno + (inner_regno < FIRST_PSEUDO_REGISTER
? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
@@ -6020,7 +6090,10 @@ reg_overlap_mentioned_for_reload_p (x, in)
{
regno = REGNO (SUBREG_REG (x));
if (regno < FIRST_PSEUDO_REGISTER)
- regno += SUBREG_WORD (x);
+ regno += subreg_regno_offset (REGNO (SUBREG_REG (x)),
+ GET_MODE (SUBREG_REG (x)),
+ SUBREG_BYTE (x),
+ GET_MODE (x));
}
else if (GET_CODE (x) == REG)
{