summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Earnshaw <rearnsha@arm.com>1998-10-02 00:22:05 +0000
committerJeff Law <law@gcc.gnu.org>1998-10-01 18:22:05 -0600
commit0b8b4eac1334ffff718fa022669da8522591d789 (patch)
treed90ec519171349e2f00dfb0e332f90a6fa3ce786
parent77ad537cca8cdcd2ca9c59cba1f0b1b207f2efcb (diff)
downloadgcc-0b8b4eac1334ffff718fa022669da8522591d789.tar.gz
arm.c (add_constant): New parameter address_only, change caller.
* arm.c (add_constant): New parameter address_only, change caller. Set it non-zero if taking the address of an item in the pool. (arm_reorg): Handle cases where we need the address of an item in the pool. * arm.c (bad_signed_byte_operand): Check both arms of a sum in a memory address. * arm.md (splits for *extendqihi_insn and *extendqisi_insn): Handle memory addresses that are not in standard canonical form. From-SVN: r22729
-rw-r--r--gcc/ChangeLog12
-rw-r--r--gcc/config/arm/arm.c78
-rw-r--r--gcc/config/arm/arm.md12
3 files changed, 76 insertions, 26 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 0a0ae1156e0..1800f6f209b 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,15 @@
+Fri Oct 2 01:20:04 1998 Richard Earnshaw (rearnsha@arm.com)
+
+ * arm.c (add_constant): New parameter address_only, change caller.
+ Set it non-zero if taking the address of an item in the pool.
+ (arm_reorg): Handle cases where we need the address of an item in
+ the pool.
+
+ * arm.c (bad_signed_byte_operand): Check both arms of a sum in
+ a memory address.
+ * arm.md (splits for *extendqihi_insn and *extendqisi_insn): Handle
+ memory addresses that are not in standard canonical form.
+
Fri Oct 2 01:16:02 1998 Jeffrey A Law (law@cygnus.com)
* reg-stack.c (straighten_stack): Do nothing if the virtual stack is
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 8c8e4286912..9a808a80f8d 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -55,7 +55,7 @@ static int arm_naked_function_p PROTO ((tree));
static void init_fpa_table PROTO ((void));
static enum machine_mode select_dominance_cc_mode PROTO ((enum rtx_code, rtx,
rtx, HOST_WIDE_INT));
-static HOST_WIDE_INT add_constant PROTO ((rtx, enum machine_mode));
+static HOST_WIDE_INT add_constant PROTO ((rtx, enum machine_mode, int *));
static void dump_table PROTO ((rtx));
static int fixit PROTO ((rtx, enum machine_mode, int));
static rtx find_barrier PROTO ((rtx, int));
@@ -1769,7 +1769,9 @@ bad_signed_byte_operand (op, mode)
/* A sum of anything more complex than reg + reg or reg + const is bad */
if ((GET_CODE (op) == PLUS || GET_CODE (op) == MINUS)
- && ! s_register_operand (XEXP (op, 0), VOIDmode))
+ && (! s_register_operand (XEXP (op, 0), VOIDmode)
+ || (! s_register_operand (XEXP (op, 1), VOIDmode)
+ && GET_CODE (XEXP (op, 1)) != CONST_INT)))
return 1;
/* Big constants are also bad */
@@ -3446,18 +3448,30 @@ static pool_node pool_vector[MAX_POOL_SIZE];
static int pool_size;
static rtx pool_vector_label;
-/* Add a constant to the pool and return its label. */
+/* Add a constant to the pool and return its offset within the current
+ pool.
+
+ X is the rtx we want to replace. MODE is its mode. On return,
+ ADDRESS_ONLY will be non-zero if we really want the address of such
+ a constant, not the constant itself. */
static HOST_WIDE_INT
-add_constant (x, mode)
+add_constant (x, mode, address_only)
rtx x;
enum machine_mode mode;
+ int *address_only;
{
int i;
HOST_WIDE_INT offset;
+ *address_only = 0;
if (mode == SImode && GET_CODE (x) == MEM && CONSTANT_P (XEXP (x, 0))
&& CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)))
x = get_pool_constant (XEXP (x, 0));
+ else if (GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P(x))
+ {
+ *address_only = 1;
+ x = get_pool_constant (x);
+ }
#ifndef AOF_ASSEMBLER
else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == 3)
x = XVECEXP (x, 0, 0);
@@ -3709,6 +3723,7 @@ arm_reorg (first)
rtx newsrc;
rtx addr;
int scratch;
+ int address_only;
/* If this is an HImode constant load, convert it into
an SImode constant load. Since the register is always
@@ -3722,39 +3737,50 @@ arm_reorg (first)
PUT_MODE (dst, SImode);
}
- offset = add_constant (src, mode);
+ offset = add_constant (src, mode, &address_only);
addr = plus_constant (gen_rtx (LABEL_REF, VOIDmode,
pool_vector_label),
offset);
- /* For wide moves to integer regs we need to split the
- address calculation off into a separate insn, so that
- the load can then be done with a load-multiple. This is
- safe, since we have already noted the length of such
- insns to be 8, and we are immediately over-writing the
- scratch we have grabbed with the final result. */
- if (GET_MODE_SIZE (mode) > 4
+ /* If we only want the address of the pool entry, or
+ for wide moves to integer regs we need to split
+ the address calculation off into a separate insn.
+ If necessary, the load can then be done with a
+ load-multiple. This is safe, since we have
+ already noted the length of such insns to be 8,
+ and we are immediately over-writing the scratch
+ we have grabbed with the final result. */
+ if ((address_only || GET_MODE_SIZE (mode) > 4)
&& (scratch = REGNO (dst)) < 16)
{
- rtx reg = gen_rtx (REG, SImode, scratch);
+ rtx reg;
+
+ if (mode == SImode)
+ reg = dst;
+ else
+ reg = gen_rtx (REG, SImode, scratch);
+
newinsn = emit_insn_after (gen_movaddr (reg, addr),
newinsn);
addr = reg;
}
- newsrc = gen_rtx (MEM, mode, addr);
-
- /* Build a jump insn wrapper around the move instead
- of an ordinary insn, because we want to have room for
- the target label rtx in fld[7], which an ordinary
- insn doesn't have. */
- newinsn = emit_jump_insn_after (gen_rtx (SET, VOIDmode,
- dst, newsrc),
- newinsn);
- JUMP_LABEL (newinsn) = pool_vector_label;
-
- /* But it's still an ordinary insn */
- PUT_CODE (newinsn, INSN);
+ if (! address_only)
+ {
+ newsrc = gen_rtx (MEM, mode, addr);
+
+ /* XXX Fixme -- I think the following is bogus. */
+ /* Build a jump insn wrapper around the move instead
+ of an ordinary insn, because we want to have room for
+ the target label rtx in fld[7], which an ordinary
+ insn doesn't have. */
+ newinsn = emit_jump_insn_after
+ (gen_rtx (SET, VOIDmode, dst, newsrc), newinsn);
+ JUMP_LABEL (newinsn) = pool_vector_label;
+
+ /* But it's still an ordinary insn */
+ PUT_CODE (newinsn, INSN);
+ }
/* Kill old insn */
delete_insn (scan);
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 5a313e4d8e4..18093c784e7 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -2399,6 +2399,12 @@
XEXP (operands[2], 0) = plus_constant (operands[3], low);
operands[1] = plus_constant (XEXP (operands[1], 0), offset - low);
}
+ /* Ensure the sum is in correct canonical form */
+ else if (GET_CODE (operands[1]) == PLUS
+ && GET_CODE (XEXP (operands[1], 1)) != CONST_INT
+ && ! s_register_operand (XEXP (operands[1], 1), VOIDmode))
+ operands[1] = gen_rtx (PLUS, GET_MODE (operands[1]),
+ XEXP (operands[1], 1), XEXP (operands[1], 0));
}
")
@@ -2464,6 +2470,12 @@
XEXP (operands[2], 0) = plus_constant (operands[0], low);
operands[1] = plus_constant (XEXP (operands[1], 0), offset - low);
}
+ /* Ensure the sum is in correct canonical form */
+ else if (GET_CODE (operands[1]) == PLUS
+ && GET_CODE (XEXP (operands[1], 1)) != CONST_INT
+ && ! s_register_operand (XEXP (operands[1], 1), VOIDmode))
+ operands[1] = gen_rtx (PLUS, GET_MODE (operands[1]),
+ XEXP (operands[1], 1), XEXP (operands[1], 0));
}
")