aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Law <law@gcc.gnu.org>1993-03-01 04:15:59 -0700
committerJeff Law <law@gcc.gnu.org>1993-03-01 04:15:59 -0700
commitc1d1b3f05fe1f7fe5027581becc3bd8ad1b25045 (patch)
tree8cf951e32e0fb67a9c5e8e8910005815aa7e0aae
parent901a8cea7b6185e9fa595756c8cc8cff291ae2b9 (diff)
downloadgcc-c1d1b3f05fe1f7fe5027581becc3bd8ad1b25045.zip
gcc-c1d1b3f05fe1f7fe5027581becc3bd8ad1b25045.tar.gz
gcc-c1d1b3f05fe1f7fe5027581becc3bd8ad1b25045.tar.bz2
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
-rw-r--r--gcc/config/pa/pa.c151
1 files changed, 151 insertions, 0 deletions
diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c
index 9d7c5c1..e5cf74f 100644
--- a/gcc/config/pa/pa.c
+++ b/gcc/config/pa/pa.c
@@ -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.