pa.c (symbolic_expression_p): New function.
* pa.c (symbolic_expression_p): New function. (hppa_legitimize_address): Old LEGITIMIZE_ADDRESS moved here. Handle symbol_ref + displacement addresses. Use rounding instead of masking off lower bits. Avoid creating useless pseudos and strip off CONST in (const (...)) expressions to make processing easier. From-SVN: r3571
This commit is contained in:
parent
901a8cea7b
commit
c1d1b3f05f
@ -67,6 +67,21 @@ call_operand_address (op, mode)
|
||||
|| (CONSTANT_P (op) && ! TARGET_LONG_CALLS));
|
||||
}
|
||||
|
||||
/* Return 1 if X contains a symbolic expression. We know these
|
||||
expressions will have one of a few well defined forms, so
|
||||
we need only check those forms. */
|
||||
int
|
||||
symbolic_expression_p (x)
|
||||
register rtx x;
|
||||
{
|
||||
|
||||
/* Strip off any HIGH. */
|
||||
if (GET_CODE (x) == HIGH)
|
||||
x = XEXP (x, 0);
|
||||
|
||||
return (symbolic_operand (x, VOIDmode));
|
||||
}
|
||||
|
||||
int
|
||||
symbolic_operand (op, mode)
|
||||
register rtx op;
|
||||
@ -470,6 +485,142 @@ finalize_pic ()
|
||||
|
||||
}
|
||||
|
||||
/* Try machine-dependent ways of modifying an illegitimate address
|
||||
to be legitimate. If we find one, return the new, valid address.
|
||||
This macro is used in only one place: `memory_address' in explow.c.
|
||||
|
||||
OLDX is the address as it was before break_out_memory_refs was called.
|
||||
In some cases it is useful to look at this to decide what needs to be done.
|
||||
|
||||
MODE and WIN are passed so that this macro can use
|
||||
GO_IF_LEGITIMATE_ADDRESS.
|
||||
|
||||
It is always safe for this macro to do nothing. It exists to recognize
|
||||
opportunities to optimize the output.
|
||||
|
||||
For the PA, transform:
|
||||
|
||||
memory(X + <large int>)
|
||||
|
||||
into:
|
||||
|
||||
if (<large int> & mask) >= 16
|
||||
Y = (<large int> & ~mask) + mask + 1 Round up.
|
||||
else
|
||||
Y = (<large int> & ~mask) Round down.
|
||||
Z = X + Y
|
||||
memory (Z + (<large int> - Y));
|
||||
|
||||
This is for CSE to find several similar references, and only use one Z.
|
||||
|
||||
X can either be a SYMBOL_REF or REG, but because combine can not
|
||||
perform a 4->2 combination we do nothing for SYMBOL_REF + D where
|
||||
D will not fit in 14 bits.
|
||||
|
||||
MODE_FLOAT references allow displacements which fit in 5 bits, so use
|
||||
0x1f as the mask.
|
||||
|
||||
MODE_INT references allow displacements which fit in 14 bits, so use
|
||||
0x3fff as the mask.
|
||||
|
||||
This relies on the fact that most mode MODE_FLOAT references will use FP
|
||||
registers and most mode MODE_INT references will use integer registers.
|
||||
(In the rare case of an FP register used in an integer MODE, we depend
|
||||
on secondary reloads to clean things up.)
|
||||
|
||||
|
||||
It is also beneficial to handle (plus (mult (X) (Y)) (Z)) in a special
|
||||
manner if Y is 2, 4, or 8. (allows more shadd insns and shifted indexed
|
||||
adressing modes to be used).
|
||||
|
||||
Put X and Z into registers. Then put the entire expression into
|
||||
a register. */
|
||||
|
||||
rtx
|
||||
hppa_legitimize_address (x, oldx, mode)
|
||||
rtx x, oldx;
|
||||
enum machine_mode mode;
|
||||
{
|
||||
|
||||
rtx orig = x;
|
||||
|
||||
/* Strip off CONST. */
|
||||
if (GET_CODE (x) == CONST)
|
||||
x = XEXP (x, 0);
|
||||
|
||||
if (GET_CODE (x) == PLUS
|
||||
&& GET_CODE (XEXP (x, 1)) == CONST_INT
|
||||
&& (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
|
||||
|| GET_CODE (XEXP (x, 0)) == REG))
|
||||
{
|
||||
rtx int_part, ptr_reg;
|
||||
int newoffset;
|
||||
int offset = INTVAL (XEXP (x, 1));
|
||||
int mask = GET_MODE_CLASS (mode) == MODE_FLOAT ? 0x1f : 0x3fff;
|
||||
|
||||
/* Choose which way to round the offset. Round up if we
|
||||
are >= halfway to the next boundary. */
|
||||
if ((offset & mask) >= ((mask + 1) / 2))
|
||||
newoffset = (offset & ~ mask) + mask + 1;
|
||||
else
|
||||
newoffset = (offset & ~ mask);
|
||||
|
||||
/* If the newoffset will not fit in 14 bits (ldo), then
|
||||
handling this would take 4 or 5 instructions (2 to load
|
||||
the SYMBOL_REF + 1 or 2 to load the newoffset + 1 to
|
||||
add the new offset and the SYMBOL_REF.) Combine can
|
||||
not handle 4->2 or 5->2 combinations, so do not create
|
||||
them. */
|
||||
if (! VAL_14_BITS_P (newoffset)
|
||||
&& GET_CODE (XEXP (x, 0)) == SYMBOL_REF)
|
||||
{
|
||||
rtx const_part = gen_rtx (CONST, VOIDmode,
|
||||
gen_rtx (PLUS, SImode,
|
||||
XEXP (x, 0),
|
||||
GEN_INT (newoffset)));
|
||||
rtx tmp_reg
|
||||
= force_reg (SImode,
|
||||
gen_rtx (HIGH, SImode, const_part));
|
||||
ptr_reg
|
||||
= force_reg (SImode,
|
||||
gen_rtx (LO_SUM, SImode,
|
||||
tmp_reg, const_part));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (! VAL_14_BITS_P (newoffset))
|
||||
int_part = force_reg (SImode, GEN_INT (newoffset));
|
||||
else
|
||||
int_part = GEN_INT (newoffset);
|
||||
|
||||
ptr_reg = force_reg (SImode,
|
||||
gen_rtx (PLUS, SImode,
|
||||
force_reg (SImode, XEXP (x, 0)),
|
||||
int_part));
|
||||
}
|
||||
return plus_constant (ptr_reg, offset - newoffset);
|
||||
}
|
||||
if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == MULT
|
||||
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
|
||||
&& shadd_constant_p (INTVAL (XEXP (XEXP (x, 0), 1))))
|
||||
{
|
||||
int val = INTVAL (XEXP (XEXP (x, 0), 1));
|
||||
rtx reg1, reg2;
|
||||
reg1 = force_reg (SImode, force_operand (XEXP (x, 1), 0));
|
||||
reg2 = force_reg (SImode,
|
||||
force_operand (XEXP (XEXP (x, 0), 0), 0));
|
||||
return force_reg (SImode,
|
||||
gen_rtx (PLUS, SImode,
|
||||
gen_rtx (MULT, SImode, reg2,
|
||||
GEN_INT (val)),
|
||||
reg1));
|
||||
}
|
||||
if (flag_pic)
|
||||
return legitimize_pic_address (x, mode, gen_reg_rtx (Pmode));
|
||||
|
||||
return orig;
|
||||
}
|
||||
|
||||
/* For the HPPA, REG and REG+CONST is cost 0
|
||||
and addresses involving symbolic constants are cost 2.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user