aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>1996-10-24 18:38:30 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>1996-10-24 18:38:30 +0000
commit2a0b0bf589fe2c1f206caaea736915d1ee97c884 (patch)
treef1c9b1e41fb858d59c949260fdfe29934b0e67fc
parent7f423031c0b5c54dd088dd25fb8d64ca3c3bb94a (diff)
downloadgcc-2a0b0bf589fe2c1f206caaea736915d1ee97c884.zip
gcc-2a0b0bf589fe2c1f206caaea736915d1ee97c884.tar.gz
gcc-2a0b0bf589fe2c1f206caaea736915d1ee97c884.tar.bz2
Permit sign_extend operands
From-SVN: r13028
-rw-r--r--gcc/config/mips/mips.c200
1 files changed, 196 insertions, 4 deletions
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index 1026f0d..10545bb 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -719,6 +719,151 @@ move_operand (op, mode)
&& ! (mips_split_addresses && mips_check_split (op, mode)));
}
+/* Return true if OPERAND is valid as a source operand for movdi.
+ This accepts not only general_operand, but also sign extended
+ constants and registers. We need to accept sign extended constants
+ in case a sign extended register which is used in an expression,
+ and is equivalent to a constant, is spilled. */
+
+int
+movdi_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ if (TARGET_64BIT
+ && mode == DImode
+ && GET_CODE (op) == SIGN_EXTEND
+ && GET_MODE (op) == DImode
+ && (GET_MODE (XEXP (op, 0)) == SImode
+ || (GET_CODE (XEXP (op, 0)) == CONST_INT
+ && GET_MODE (XEXP (op, 0)) == VOIDmode))
+ && (register_operand (XEXP (op, 0), SImode)
+ || immediate_operand (XEXP (op, 0), SImode)))
+ return 1;
+
+ return general_operand (op, mode);
+}
+
+/* Like register_operand, but when in 64 bit mode also accept a sign
+ extend of a 32 bit register, since the value is known to be already
+ sign extended. */
+
+int
+se_register_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ if (TARGET_64BIT
+ && mode == DImode
+ && GET_CODE (op) == SIGN_EXTEND
+ && GET_MODE (op) == DImode
+ && GET_MODE (XEXP (op, 0)) == SImode
+ && register_operand (XEXP (op, 0), SImode))
+ return 1;
+
+ return register_operand (op, mode);
+}
+
+/* Like reg_or_0_operand, but when in 64 bit mode also accept a sign
+ extend of a 32 bit register, since the value is known to be already
+ sign extended. */
+
+int
+se_reg_or_0_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ if (TARGET_64BIT
+ && mode == DImode
+ && GET_CODE (op) == SIGN_EXTEND
+ && GET_MODE (op) == DImode
+ && GET_MODE (XEXP (op, 0)) == SImode
+ && register_operand (XEXP (op, 0), SImode))
+ return 1;
+
+ return reg_or_0_operand (op, mode);
+}
+
+/* Like uns_arith_operand, but when in 64 bit mode also accept a sign
+ extend of a 32 bit register, since the value is known to be already
+ sign extended. */
+
+int
+se_uns_arith_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ if (TARGET_64BIT
+ && mode == DImode
+ && GET_CODE (op) == SIGN_EXTEND
+ && GET_MODE (op) == DImode
+ && GET_MODE (XEXP (op, 0)) == SImode
+ && register_operand (XEXP (op, 0), SImode))
+ return 1;
+
+ return uns_arith_operand (op, mode);
+}
+
+/* Like arith_operand, but when in 64 bit mode also accept a sign
+ extend of a 32 bit register, since the value is known to be already
+ sign extended. */
+
+int
+se_arith_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ if (TARGET_64BIT
+ && mode == DImode
+ && GET_CODE (op) == SIGN_EXTEND
+ && GET_MODE (op) == DImode
+ && GET_MODE (XEXP (op, 0)) == SImode
+ && register_operand (XEXP (op, 0), SImode))
+ return 1;
+
+ return arith_operand (op, mode);
+}
+
+/* Like nonmemory_operand, but when in 64 bit mode also accept a sign
+ extend of a 32 bit register, since the value is known to be already
+ sign extended. */
+
+int
+se_nonmemory_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ if (TARGET_64BIT
+ && mode == DImode
+ && GET_CODE (op) == SIGN_EXTEND
+ && GET_MODE (op) == DImode
+ && GET_MODE (XEXP (op, 0)) == SImode
+ && register_operand (XEXP (op, 0), SImode))
+ return 1;
+
+ return nonmemory_operand (op, mode);
+}
+
+/* Like nonimmediate_operand, but when in 64 bit mode also accept a
+ sign extend of a 32 bit register, since the value is known to be
+ already sign extended. */
+
+int
+se_nonimmediate_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ if (TARGET_64BIT
+ && mode == DImode
+ && GET_CODE (op) == SIGN_EXTEND
+ && GET_MODE (op) == DImode
+ && GET_MODE (XEXP (op, 0)) == SImode
+ && register_operand (XEXP (op, 0), SImode))
+ return 1;
+
+ return nonimmediate_operand (op, mode);
+}
+
/* Return true if we split the address into high and low parts. */
/* ??? We should also handle reg+array somewhere. We get four
@@ -1382,6 +1527,12 @@ mips_move_2words (operands, insn)
code0 = GET_CODE (op0);
}
+ if (code1 == SIGN_EXTEND)
+ {
+ op1 = XEXP (op1, 0);
+ code1 = GET_CODE (op1);
+ }
+
while (code1 == SUBREG)
{
subreg_word1 += SUBREG_WORD (op1);
@@ -1389,6 +1540,12 @@ mips_move_2words (operands, insn)
code1 = GET_CODE (op1);
}
+ /* Sanity check. */
+ if (GET_CODE (operands[1]) == SIGN_EXTEND
+ && code1 != REG
+ && code1 != CONST_INT)
+ abort ();
+
if (code0 == REG)
{
int regno0 = REGNO (op0) + subreg_word0;
@@ -1567,7 +1724,9 @@ mips_move_2words (operands, insn)
{
if (TARGET_64BIT)
{
- if (HOST_BITS_PER_WIDE_INT < 64)
+ if (GET_CODE (operands[1]) == SIGN_EXTEND)
+ ret = "li\t%0,%1\t\t# %X1";
+ else if (HOST_BITS_PER_WIDE_INT < 64)
/* We can't use 'X' for negative numbers, because then we won't
get the right value for the upper 32 bits. */
ret = ((INTVAL (op1) < 0) ? "dli\t%0,%1\t\t\t# %X1"
@@ -3862,6 +4021,13 @@ print_operand (file, op, letter)
}
code = GET_CODE (op);
+
+ if (code == SIGN_EXTEND)
+ {
+ op = XEXP (op, 0);
+ code = GET_CODE (op);
+ }
+
if (letter == 'C')
switch (code)
{
@@ -3919,9 +4085,14 @@ print_operand (file, op, letter)
fprintf (file, "%s,", reg_names[regnum]);
}
- else if (code == REG)
+ else if (code == REG || code == SUBREG)
{
- register int regnum = REGNO (op);
+ register int regnum;
+
+ if (code == REG)
+ regnum = REGNO (op);
+ else
+ regnum = true_regnum (op);
if ((letter == 'M' && ! WORDS_BIG_ENDIAN)
|| (letter == 'L' && WORDS_BIG_ENDIAN)
@@ -5832,7 +6003,28 @@ mips_secondary_reload_class (class, mode, x, in_p)
{
int regno = -1;
- if (GET_CODE (x) == REG || GET_CODE (x) == SUBREG)
+ if (GET_CODE (x) == SIGN_EXTEND)
+ {
+ int off = 0;
+
+ x = XEXP (x, 0);
+
+ /* We may be called with reg_renumber NULL from regclass.
+ ??? This is probably a bug. */
+ if (reg_renumber)
+ regno = true_regnum (x);
+ else
+ {
+ while (GET_CODE (x) == SUBREG)
+ {
+ off += SUBREG_WORD (x);
+ x = SUBREG_REG (x);
+ }
+ if (GET_CODE (x) == REG)
+ regno = REGNO (x) + off;
+ }
+ }
+ else if (GET_CODE (x) == REG || GET_CODE (x) == SUBREG)
regno = true_regnum (x);
/* We always require a general register when copying anything to