From 2a0b0bf589fe2c1f206caaea736915d1ee97c884 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 24 Oct 1996 18:38:30 +0000 Subject: [PATCH] Permit sign_extend operands From-SVN: r13028 --- gcc/config/mips/mips.c | 200 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file 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 -- 2.7.4