aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Law <law@gcc.gnu.org>1996-10-02 17:31:45 -0600
committerJeff Law <law@gcc.gnu.org>1996-10-02 17:31:45 -0600
commit78c0acfdd3959d2e5542c2ad6734754eb3e6387a (patch)
treed1e534ba80df220419ef3524733d2a1b25cb08af
parent085540da9cdac32931b9d2948dde6857326fd92d (diff)
downloadgcc-78c0acfdd3959d2e5542c2ad6734754eb3e6387a.zip
gcc-78c0acfdd3959d2e5542c2ad6734754eb3e6387a.tar.gz
gcc-78c0acfdd3959d2e5542c2ad6734754eb3e6387a.tar.bz2
pa.h (EXTRA_CONSTRAINT): Loosen conditions for match of 'Q' and 'T' while reload is running.
* pa.h (EXTRA_CONSTRAINT): Loosen conditions for match of 'Q' and 'T' while reload is running. * pa/pa.c (hppa_legitimize_address): Rework to generate more indexed and scaled indexed addressing. * pa/pa.md (scaled indexed store): Add define_splits to undo pessimizations created by hppa_legitimize_address for integer stores. From-SVN: r12892
-rw-r--r--gcc/config/pa/pa.c221
-rw-r--r--gcc/config/pa/pa.h6
-rw-r--r--gcc/config/pa/pa.md46
3 files changed, 213 insertions, 60 deletions
diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c
index 9080f97..046f93a 100644
--- a/gcc/config/pa/pa.c
+++ b/gcc/config/pa/pa.c
@@ -771,11 +771,7 @@ hppa_legitimize_address (x, oldx, mode)
return plus_constant (ptr_reg, offset - newoffset);
}
- /* Try to arrange things so that indexing modes can be used, but
- only do so if indexing is safe.
-
- Indexing is safe when the second operand for the outer PLUS
- is a REG, SUBREG, SYMBOL_REF or the like. */
+ /* Handle (plus (mult (a) (shadd_constant)) (b)). */
if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == MULT
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
@@ -786,66 +782,145 @@ hppa_legitimize_address (x, oldx, mode)
{
int val = INTVAL (XEXP (XEXP (x, 0), 1));
rtx reg1, reg2;
- reg1 = force_reg (Pmode, force_operand (XEXP (x, 1), 0));
- reg2 = force_reg (Pmode,
- force_operand (XEXP (XEXP (x, 0), 0), 0));
- return force_reg (Pmode,
- gen_rtx (PLUS, Pmode,
- gen_rtx (MULT, Pmode, reg2,
- GEN_INT (val)),
- reg1));
+
+ reg1 = XEXP (x, 1);
+ if (GET_CODE (reg1) != REG)
+ reg1 = force_reg (Pmode, force_operand (reg1, 0));
+
+ reg2 = XEXP (XEXP (x, 0), 0);
+ if (GET_CODE (reg2) != REG)
+ reg2 = force_reg (Pmode, force_operand (reg2, 0));
+
+ if (INTVAL (XEXP (XEXP (x, 0), 1)) != GET_MODE_SIZE (mode))
+ {
+ reg2 = force_reg (Pmode, gen_rtx (MULT, Pmode, reg2, GEN_INT (val)));
+ return force_reg (Pmode, gen_rtx (PLUS, Pmode, reg1, reg2));
+ }
+
+ return force_reg (Pmode, gen_rtx (PLUS, Pmode,
+ gen_rtx (MULT, Pmode,
+ reg2, GEN_INT (val)),
+ reg1));
}
/* Similarly for (plus (plus (mult (a) (shadd_constant)) (b)) (c)).
Only do so for floating point modes since this is more speculative
and we lose if it's an integer store. */
- if ((mode == DFmode || mode == SFmode)
- && GET_CODE (x) == PLUS
+ if (GET_CODE (x) == PLUS
&& GET_CODE (XEXP (x, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
&& GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)) == CONST_INT
- && shadd_constant_p (INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1))))
+ && shadd_constant_p (INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1)))
+ && (mode == SFmode || mode == DFmode))
{
- rtx regx1, regx2;
-
- /* Add the two unscaled terms B and C; if either B or C isn't
- a register or small constant int, then fail. */
- regx1 = XEXP (XEXP (x, 0), 1);
- if (! (GET_CODE (regx1) == REG
- || (GET_CODE (regx1) == CONST_INT
- && INT_14_BITS (regx1))))
- return orig;
-
- regx2 = XEXP (x, 1);
- if (! (GET_CODE (regx2) == REG
- || (GET_CODE (regx2) == CONST_INT
- && INT_14_BITS (regx2))))
+
+ /* First, try and figure out what to use as a base register. */
+ rtx reg1, reg2, base, idx, orig_base;
+
+ reg1 = XEXP (XEXP (x, 0), 1);
+ reg2 = XEXP (x, 1);
+ base = NULL_RTX;
+ idx = NULL_RTX;
+
+ /* Make sure they're both regs. If one was a SYMBOL_REF [+ const],
+ then emit_move_sequence will turn on REGNO_POINTER_FLAG so we'll
+ know it's a base register below. */
+ if (GET_CODE (reg1) != REG)
+ reg1 = force_reg (Pmode, force_operand (reg1, 0));
+
+ if (GET_CODE (reg2) != REG)
+ reg2 = force_reg (Pmode, force_operand (reg2, 0));
+
+ /* Figure out what the base and index are. */
+
+ if (GET_CODE (reg1) == REG
+ && REGNO_POINTER_FLAG (REGNO (reg1)))
+ {
+ base = reg1;
+ orig_base = XEXP (XEXP (x, 0), 1);
+ idx = gen_rtx (PLUS, Pmode,
+ gen_rtx (MULT, Pmode,
+ XEXP (XEXP (XEXP (x, 0), 0), 0),
+ XEXP (XEXP (XEXP (x, 0), 0), 1)),
+ XEXP (x, 1));
+ }
+ else if (GET_CODE (reg2) == REG
+ && REGNO_POINTER_FLAG (REGNO (reg2)))
+ {
+ base = reg2;
+ orig_base = XEXP (x, 1);
+ idx = XEXP (x, 0);
+ }
+
+ if (base == 0)
return orig;
+
+ /* If the index adds a large constant, try to scale the
+ constant so that it can be loaded with only one insn. */
+ if (GET_CODE (XEXP (idx, 1)) == CONST_INT
+ && VAL_14_BITS_P (INTVAL (XEXP (idx, 1))
+ / INTVAL (XEXP (XEXP (idx, 0), 1)))
+ && INTVAL (XEXP (idx, 1)) % INTVAL (XEXP (XEXP (idx, 0), 1)) == 0)
+ {
+ /* Divide the CONST_INT by the scale factor, then add it to A. */
+ int val = INTVAL (XEXP (idx, 1));
+
+ val /= INTVAL (XEXP (XEXP (idx, 0), 1));
+ reg1 = XEXP (XEXP (idx, 0), 0);
+ if (GET_CODE (reg1) != REG)
+ reg1 = force_reg (Pmode, force_operand (reg1, 0));
+
+ reg1 = force_reg (Pmode, gen_rtx (PLUS, Pmode, reg1, GEN_INT (val)));
+
+ /* We can now generate a simple scaled indexed address. */
+ return force_reg (Pmode, gen_rtx (PLUS, Pmode,
+ gen_rtx (MULT, Pmode, reg1,
+ XEXP (XEXP (idx, 0), 1)),
+ base));
+ }
+
+ /* If B + C is still a valid base register, then add them. */
+ if (GET_CODE (XEXP (idx, 1)) == CONST_INT
+ && INTVAL (XEXP (idx, 1)) <= 4096
+ && INTVAL (XEXP (idx, 1)) >= -4096)
+ {
+ int val = INTVAL (XEXP (XEXP (idx, 0), 1));
+ rtx reg1, reg2;
+
+ reg1 = force_reg (Pmode, gen_rtx (PLUS, Pmode, base, XEXP (idx, 1)));
+
+ reg2 = XEXP (XEXP (idx, 0), 0);
+ if (GET_CODE (reg2) != CONST_INT)
+ reg2 = force_reg (Pmode, force_operand (reg2, 0));
+
+ return force_reg (Pmode, gen_rtx (PLUS, Pmode,
+ gen_rtx (MULT, Pmode,
+ reg2, GEN_INT (val)),
+ reg1));
+ }
+
+ /* Get the index into a register, then add the base + index and
+ return a register holding the result. */
+
+ /* First get A into a register. */
+ reg1 = XEXP (XEXP (idx, 0), 0);
+ if (GET_CODE (reg1) != REG)
+ reg1 = force_reg (Pmode, force_operand (reg1, 0));
+
+ /* And get B into a register. */
+ reg2 = XEXP (idx, 1);
+ if (GET_CODE (reg2) != REG)
+ reg2 = force_reg (Pmode, force_operand (reg2, 0));
+
+ reg1 = force_reg (Pmode, gen_rtx (PLUS, Pmode,
+ gen_rtx (MULT, Pmode, reg1,
+ XEXP (XEXP (idx, 0), 1)),
+ reg2));
+
+ /* Add the result to our base register and return. */
+ return force_reg (Pmode, gen_rtx (PLUS, Pmode, base, reg1));
- /* Add them, make sure the result is in canonical form. */
- if (GET_CODE (regx1) == REG)
- regx1 = force_reg (Pmode, gen_rtx (PLUS, Pmode, regx1, regx2));
- else if (GET_CODE (regx2) == REG)
- regx1 = force_reg (Pmode, gen_rtx (PLUS, Pmode, regx2, regx1));
- else
- regx1 = force_reg (Pmode, gen_rtx (PLUS, Pmode,
- force_reg (Pmode, regx1),
- regx2));
-
- /* Get the term to scale in a register. */
- regx2 = XEXP (XEXP (XEXP (x, 0), 0), 0);
- if (GET_CODE (regx2) != REG)
- regx2 = force_reg (Pmode, force_operand (regx2, 0));
-
- /* And make an indexed address. */
- regx2 = gen_rtx (PLUS, Pmode,
- gen_rtx (MULT, Pmode, regx2,
- XEXP (XEXP (XEXP (x, 0), 0), 1)),
- regx1);
-
- /* Return it. */
- return force_reg (Pmode, regx2);
}
/* Uh-oh. We might have an address for x[n-100000]. This needs
@@ -879,12 +954,42 @@ hppa_legitimize_address (x, oldx, mode)
(plus (mult (reg) (shadd_const))
(const (plus (symbol_ref) (const_int))))
- Where const_int can be divided evenly by shadd_const and
- added to (reg). This allows more scaled indexed addresses. */
- if ((mode == DFmode || mode == SFmode)
- && GET_CODE (XEXP (y, 0)) == SYMBOL_REF
+ Where const_int is small. In that case the const
+ expression is a valid pointer for indexing.
+
+ If const_int is big, but can be divided evenly by shadd_const
+ and added to (reg). This allows more scaled indexed addresses. */
+ if (GET_CODE (XEXP (y, 0)) == SYMBOL_REF
+ && GET_CODE (XEXP (x, 0)) == MULT
&& GET_CODE (XEXP (y, 1)) == CONST_INT
- && INTVAL (XEXP (y, 1)) % INTVAL (XEXP (XEXP (x, 0), 1)) == 0)
+ && INTVAL (XEXP (y, 1)) >= -4096
+ && INTVAL (XEXP (y, 1)) <= 4095
+ && 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 = XEXP (x, 1);
+ if (GET_CODE (reg1) != REG)
+ reg1 = force_reg (Pmode, force_operand (reg1, 0));
+
+ reg2 = XEXP (XEXP (x, 0), 0);
+ if (GET_CODE (reg2) != REG)
+ reg2 = force_reg (Pmode, force_operand (reg2, 0));
+
+ return force_reg (Pmode, gen_rtx (PLUS, Pmode,
+ gen_rtx (MULT, Pmode,
+ reg2, GEN_INT (val)),
+ reg1));
+ }
+ else if ((mode == DFmode || mode == SFmode)
+ && GET_CODE (XEXP (y, 0)) == SYMBOL_REF
+ && GET_CODE (XEXP (x, 0)) == MULT
+ && GET_CODE (XEXP (y, 1)) == CONST_INT
+ && INTVAL (XEXP (y, 1)) % INTVAL (XEXP (XEXP (x, 0), 1)) == 0
+ && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
+ && shadd_constant_p (INTVAL (XEXP (XEXP (x, 0), 1))))
{
regx1
= force_reg (Pmode, GEN_INT (INTVAL (XEXP (y, 1))
diff --git a/gcc/config/pa/pa.h b/gcc/config/pa/pa.h
index f9a3d93..f691025 100644
--- a/gcc/config/pa/pa.h
+++ b/gcc/config/pa/pa.h
@@ -1405,7 +1405,8 @@ extern struct rtx_def *hppa_builtin_saveregs ();
((C) == 'Q' ? \
(IS_RELOADING_PSEUDO_P (OP) \
|| (GET_CODE (OP) == MEM \
- && memory_address_p (GET_MODE (OP), XEXP (OP, 0))\
+ && (memory_address_p (GET_MODE (OP), XEXP (OP, 0))\
+ || reload_in_progress) \
&& ! symbolic_memory_operand (OP, VOIDmode) \
&& !(GET_CODE (XEXP (OP, 0)) == PLUS \
&& (GET_CODE (XEXP (XEXP (OP, 0), 0)) == MULT\
@@ -1416,7 +1417,8 @@ extern struct rtx_def *hppa_builtin_saveregs ();
&& (GET_CODE (XEXP (XEXP (OP, 0), 0)) == MULT \
|| GET_CODE (XEXP (XEXP (OP, 0), 1)) == MULT) \
&& (move_operand (OP, GET_MODE (OP)) \
- || memory_address_p (GET_MODE (OP), XEXP (OP, 0))))\
+ || memory_address_p (GET_MODE (OP), XEXP (OP, 0))\
+ || reload_in_progress)) \
: ((C) == 'T' ? \
(GET_CODE (OP) == MEM \
/* Using DFmode forces only short displacements \
diff --git a/gcc/config/pa/pa.md b/gcc/config/pa/pa.md
index de3b001..d881956 100644
--- a/gcc/config/pa/pa.md
+++ b/gcc/config/pa/pa.md
@@ -1664,6 +1664,52 @@
(set (match_dup 0) (lo_sum:SI (match_dup 2) (match_dup 1)))]
"")
+;; hppa_legitimize_address goes to a great deal of trouble to
+;; create addresses which use indexing. In some cases, this
+;; is a lose because there isn't any store instructions which
+;; allow indexed addresses (with integer register source).
+;;
+;; These define_splits try to turn a 3 insn store into
+;; a 2 insn store with some creative RTL rewriting.
+(define_split
+ [(set (mem:SI (plus:SI (mult:SI (match_operand:SI 0 "register_operand" "")
+ (match_operand:SI 1 "shadd_operand" ""))
+ (plus:SI (match_operand:SI 2 "register_operand" "")
+ (match_operand:SI 3 "const_int_operand" ""))))
+ (match_operand:SI 4 "register_operand" ""))
+ (clobber (match_operand:SI 5 "register_operand" ""))]
+ ""
+ [(set (match_dup 5) (plus:SI (mult:SI (match_dup 0) (match_dup 1))
+ (match_dup 2)))
+ (set (mem:SI (plus:SI (match_dup 5) (match_dup 3))) (match_dup 4))]
+ "")
+
+(define_split
+ [(set (mem:HI (plus:SI (mult:SI (match_operand:SI 0 "register_operand" "")
+ (match_operand:SI 1 "shadd_operand" ""))
+ (plus:SI (match_operand:SI 2 "register_operand" "")
+ (match_operand:SI 3 "const_int_operand" ""))))
+ (match_operand:HI 4 "register_operand" ""))
+ (clobber (match_operand:SI 5 "register_operand" ""))]
+ ""
+ [(set (match_dup 5) (plus:SI (mult:SI (match_dup 0) (match_dup 1))
+ (match_dup 2)))
+ (set (mem:HI (plus:SI (match_dup 5) (match_dup 3))) (match_dup 4))]
+ "")
+
+(define_split
+ [(set (mem:QI (plus:SI (mult:SI (match_operand:SI 0 "register_operand" "")
+ (match_operand:SI 1 "shadd_operand" ""))
+ (plus:SI (match_operand:SI 2 "register_operand" "")
+ (match_operand:SI 3 "const_int_operand" ""))))
+ (match_operand:QI 4 "register_operand" ""))
+ (clobber (match_operand:SI 5 "register_operand" ""))]
+ ""
+ [(set (match_dup 5) (plus:SI (mult:SI (match_dup 0) (match_dup 1))
+ (match_dup 2)))
+ (set (mem:QI (plus:SI (match_dup 5) (match_dup 3))) (match_dup 4))]
+ "")
+
(define_expand "movhi"
[(set (match_operand:HI 0 "general_operand" "")
(match_operand:HI 1 "general_operand" ""))]