Commit 8214bf98 by Richard Sandiford Committed by Richard Sandiford

mips-protos.h (mips_sign_extend): Declare.

	* config/mips/mips-protos.h (mips_sign_extend): Declare.
	* config/mips/mips.h (MASK_DEBUG_H, TARGET_DEBUG_H_MODE): Remove.
	(TARGET_SWITCHES): Remove debugh.
	(ISA_HAS_TRUNC_W): New macro.
	(CLASS_CANNOT_CHANGE_MODE): Include FP_REGS if TARGET_FLOAT64.
	(PREDICATE_CODES): Remove se_nonimmediate_operand.
	* config/mips/mips.c (movdi_operand): Allow sign-extensions of
	any SImode move_operand.
	(se_nonimmediate_operand): Remove.
	(mips_sign_extend): New.
	(mips_move_2words): Use it for sign-extended source operands.
	(override_options): Allow integers to be put into single FPRs.
	(mips_secondary_reload_class): Handle integers in float registers.
	* config/mips/mips.md (extendsidi2): Turn into a define_expand.
	(fix_truncsfsi2, fix_truncdfsi2): Likewise.
	(fix_truncdfsi2_insn, fix_truncdfsi2_macro): New.
	(fix_truncsfsi2_insn, fix_truncsfsi2_macro): New.
	(fix_truncdfdi2): Provide only a single alternative, in which the
	integer is in a float register.  Depend on TARGET_FLOAT64 rather
	than TARGET_64BIT.
	(fix_truncsfdi2, floatdidf2, floatdisf2): Likewise.
	(floatsidf2, floatsisf2): Likewise, but no TARGET_FLOAT64 dependency.
	(movdi_internal2): Don't allow the source operand to be sign-extended.
	Add alternatives for float registers.
	(*movdi_internal2_extend): New.  Version of movdi_internal2 that
	allows sign-extension.
	(*movdi_internal2_mips16): Name the existing mips16 movdi pattern.
	(movsi_internal2): Rename to movsi_internal.  Add alternatives for
	float registers.  Remove TARGET_DEBUG_H_MODE test.
	(movhi_internal1): Rename to movhi_internal.  Don't check
	TARGET_DEBUG_H_MODE.  Fix transposed *d and *f source constraints.
	(movqi_internal1): Rename to movqi_internal and remove
	TARGET_DEBUG_H_MODE dependency.
	(movsi_internal1, movhi_internal2, movqi_internal2): Remove.

From-SVN: r55514
parent 5fc5be15
2002-07-17 Richard Sandiford <rsandifo@redhat.com>
* config/mips/mips-protos.h (mips_sign_extend): Declare.
* config/mips/mips.h (MASK_DEBUG_H, TARGET_DEBUG_H_MODE): Remove.
(TARGET_SWITCHES): Remove debugh.
(ISA_HAS_TRUNC_W): New macro.
(CLASS_CANNOT_CHANGE_MODE): Include FP_REGS if TARGET_FLOAT64.
(PREDICATE_CODES): Remove se_nonimmediate_operand.
* config/mips/mips.c (movdi_operand): Allow sign-extensions of
any SImode move_operand.
(se_nonimmediate_operand): Remove.
(mips_sign_extend): New.
(mips_move_2words): Use it for sign-extended source operands.
(override_options): Allow integers to be put into single FPRs.
(mips_secondary_reload_class): Handle integers in float registers.
* config/mips/mips.md (extendsidi2): Turn into a define_expand.
(fix_truncsfsi2, fix_truncdfsi2): Likewise.
(fix_truncdfsi2_insn, fix_truncdfsi2_macro): New.
(fix_truncsfsi2_insn, fix_truncsfsi2_macro): New.
(fix_truncdfdi2): Provide only a single alternative, in which the
integer is in a float register. Depend on TARGET_FLOAT64 rather
than TARGET_64BIT.
(fix_truncsfdi2, floatdidf2, floatdisf2): Likewise.
(floatsidf2, floatsisf2): Likewise, but no TARGET_FLOAT64 dependency.
(movdi_internal2): Don't allow the source operand to be sign-extended.
Add alternatives for float registers.
(*movdi_internal2_extend): New. Version of movdi_internal2 that
allows sign-extension.
(*movdi_internal2_mips16): Name the existing mips16 movdi pattern.
(movsi_internal2): Rename to movsi_internal. Add alternatives for
float registers. Remove TARGET_DEBUG_H_MODE test.
(movhi_internal1): Rename to movhi_internal. Don't check
TARGET_DEBUG_H_MODE. Fix transposed *d and *f source constraints.
(movqi_internal1): Rename to movqi_internal and remove
TARGET_DEBUG_H_MODE dependency.
(movsi_internal1, movhi_internal2, movqi_internal2): Remove.
2002-07-16 Jim Wilson <wilson@redhat.com> 2002-07-16 Jim Wilson <wilson@redhat.com>
* toplev.c (lang_dependent_init): Create function context for * toplev.c (lang_dependent_init): Create function context for
......
...@@ -98,6 +98,7 @@ extern const char *mips_fill_delay_slot PARAMS ((const char *, ...@@ -98,6 +98,7 @@ extern const char *mips_fill_delay_slot PARAMS ((const char *,
rtx)); rtx));
extern const char *mips_move_1word PARAMS ((rtx *, rtx, int)); extern const char *mips_move_1word PARAMS ((rtx *, rtx, int));
extern const char *mips_move_2words PARAMS ((rtx *, rtx)); extern const char *mips_move_2words PARAMS ((rtx *, rtx));
extern const char *mips_sign_extend PARAMS ((rtx, rtx, rtx));
extern const char *mips_emit_prefetch PARAMS ((rtx *)); extern const char *mips_emit_prefetch PARAMS ((rtx *));
extern const char *mips_restore_gp PARAMS ((rtx *, rtx)); extern const char *mips_restore_gp PARAMS ((rtx *, rtx));
extern const char *output_block_move PARAMS ((rtx, rtx *, int, extern const char *output_block_move PARAMS ((rtx, rtx *, int,
......
...@@ -1200,9 +1200,11 @@ move_operand (op, mode) ...@@ -1200,9 +1200,11 @@ move_operand (op, mode)
/* Return nonzero if OPERAND is valid as a source operand for movdi. /* Return nonzero if OPERAND is valid as a source operand for movdi.
This accepts not only general_operand, but also sign extended This accepts not only general_operand, but also sign extended
constants and registers. We need to accept sign extended constants move_operands. Note that we need to accept sign extended constants
in case a sign extended register which is used in an expression, in case a sign extended register which is used in an expression,
and is equivalent to a constant, is spilled. */ and is equivalent to a constant, is spilled. We need to accept
sign-extended memory in order to reload registers from stack slots,
and so that we generate efficient code for extendsidi2. */
int int
movdi_operand (op, mode) movdi_operand (op, mode)
...@@ -1213,11 +1215,7 @@ movdi_operand (op, mode) ...@@ -1213,11 +1215,7 @@ movdi_operand (op, mode)
&& mode == DImode && mode == DImode
&& GET_CODE (op) == SIGN_EXTEND && GET_CODE (op) == SIGN_EXTEND
&& GET_MODE (op) == DImode && GET_MODE (op) == DImode
&& (GET_MODE (XEXP (op, 0)) == SImode && move_operand (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 1;
return (general_operand (op, mode) return (general_operand (op, mode)
...@@ -1326,26 +1324,6 @@ se_nonmemory_operand (op, mode) ...@@ -1326,26 +1324,6 @@ se_nonmemory_operand (op, mode)
return nonmemory_operand (op, mode); 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);
}
/* Accept any operand that can appear in a mips16 constant table /* Accept any operand that can appear in a mips16 constant table
instruction. We can't use any of the standard operand functions instruction. We can't use any of the standard operand functions
because for these instructions we accept values that are not because for these instructions we accept values that are not
...@@ -2464,6 +2442,33 @@ mips_restore_gp (operands, insn) ...@@ -2464,6 +2442,33 @@ mips_restore_gp (operands, insn)
return mips_move_1word (operands, insn, 0); return mips_move_1word (operands, insn, 0);
} }
/* Return an instruction to sign-extend SImode value SRC and store it
in DImode value DEST. INSN is the original extendsidi2-type insn. */
const char *
mips_sign_extend (insn, dest, src)
rtx insn, dest, src;
{
rtx operands[MAX_RECOG_OPERANDS];
if ((register_operand (src, SImode) && FP_REG_P (true_regnum (src)))
|| memory_operand (src, SImode))
{
/* If the source is a floating-point register, we need to use a
32-bit move, since the float register is not kept sign-extended.
If the source is in memory, we need a 32-bit load. */
operands[0] = gen_lowpart_SUBREG (SImode, dest);
operands[1] = src;
return mips_move_1word (operands, insn, false);
}
else
{
operands[0] = dest;
operands[1] = src;
return mips_move_2words (operands, insn);
}
}
/* Return the appropriate instructions to move 2 words */ /* Return the appropriate instructions to move 2 words */
const char * const char *
...@@ -2480,6 +2485,9 @@ mips_move_2words (operands, insn) ...@@ -2480,6 +2485,9 @@ mips_move_2words (operands, insn)
int subreg_offset1 = 0; int subreg_offset1 = 0;
enum delay_type delay = DELAY_NONE; enum delay_type delay = DELAY_NONE;
if (code1 == SIGN_EXTEND)
return mips_sign_extend (insn, op0, XEXP (op1, 0));
while (code0 == SUBREG) while (code0 == SUBREG)
{ {
subreg_offset0 += subreg_regno_offset (REGNO (SUBREG_REG (op0)), subreg_offset0 += subreg_regno_offset (REGNO (SUBREG_REG (op0)),
...@@ -2490,12 +2498,6 @@ mips_move_2words (operands, insn) ...@@ -2490,12 +2498,6 @@ mips_move_2words (operands, insn)
code0 = GET_CODE (op0); code0 = GET_CODE (op0);
} }
if (code1 == SIGN_EXTEND)
{
op1 = XEXP (op1, 0);
code1 = GET_CODE (op1);
}
while (code1 == SUBREG) while (code1 == SUBREG)
{ {
subreg_offset1 += subreg_regno_offset (REGNO (SUBREG_REG (op1)), subreg_offset1 += subreg_regno_offset (REGNO (SUBREG_REG (op1)),
...@@ -2506,17 +2508,6 @@ mips_move_2words (operands, insn) ...@@ -2506,17 +2508,6 @@ mips_move_2words (operands, insn)
code1 = GET_CODE (op1); code1 = GET_CODE (op1);
} }
/* Sanity check. */
if (GET_CODE (operands[1]) == SIGN_EXTEND
&& code1 != REG
&& code1 != CONST_INT
/* The following three can happen as the result of a questionable
cast. */
&& code1 != LABEL_REF
&& code1 != SYMBOL_REF
&& code1 != CONST)
abort ();
if (code0 == REG) if (code0 == REG)
{ {
int regno0 = REGNO (op0) + subreg_offset0; int regno0 = REGNO (op0) + subreg_offset0;
...@@ -5406,10 +5397,12 @@ override_options () ...@@ -5406,10 +5397,12 @@ override_options ()
the value, not about whether math works on the the value, not about whether math works on the
register. */ register. */
|| (mips_abi == ABI_MEABI && size <= 4)) || (mips_abi == ABI_MEABI && size <= 4))
&& (class == MODE_FLOAT && (((class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
|| class == MODE_COMPLEX_FLOAT && size <= UNITS_PER_FPVALUE)
|| (TARGET_DEBUG_H_MODE && class == MODE_INT)) /* Allow integer modes that fit into a single
&& size <= UNITS_PER_FPVALUE); register. We need to put integers into FPRs
when using instructions like cvt and trunc. */
|| (class == MODE_INT && size <= UNITS_PER_FPREG)));
else if (MD_REG_P (regno)) else if (MD_REG_P (regno))
temp = (class == MODE_INT temp = (class == MODE_INT
...@@ -8319,6 +8312,18 @@ mips_secondary_reload_class (class, mode, x, in_p) ...@@ -8319,6 +8312,18 @@ mips_secondary_reload_class (class, mode, x, in_p)
if (GET_CODE (x) == REG) if (GET_CODE (x) == REG)
regno = REGNO (x) + off; regno = REGNO (x) + off;
} }
/* 64-bit floating-point registers don't store 32-bit values
in sign-extended form. The only way we can reload
(sign_extend:DI (reg:SI $f0)) is by moving $f0 into
an integer register using a 32-bit move. */
if (FP_REG_P (regno))
return (class == GR_REGS ? NO_REGS : GR_REGS);
/* For the same reason, we can only reload (sign_extend:DI FOO) into
a floating-point register when FOO is an integer register. */
if (class == FP_REGS)
return (GP_REG_P (regno) ? NO_REGS : GR_REGS);
} }
else if (GET_CODE (x) == REG || GET_CODE (x) == SUBREG) else if (GET_CODE (x) == REG || GET_CODE (x) == SUBREG)
...@@ -8378,6 +8383,37 @@ mips_secondary_reload_class (class, mode, x, in_p) ...@@ -8378,6 +8383,37 @@ mips_secondary_reload_class (class, mode, x, in_p)
return class == GR_REGS ? NO_REGS : GR_REGS; return class == GR_REGS ? NO_REGS : GR_REGS;
} }
if (class == FP_REGS)
{
if (GET_CODE (x) == MEM)
{
/* In this case we can use lwc1, swc1, ldc1 or sdc1. */
return NO_REGS;
}
else if (CONSTANT_P (x) && GET_MODE_CLASS (mode) == MODE_FLOAT)
{
/* We can use the l.s and l.d macros to load floating-point
constants. ??? For l.s, we could probably get better
code by returning GR_REGS here. */
return NO_REGS;
}
else if (GP_REG_P (regno) || x == CONST0_RTX (mode))
{
/* In this case we can use mtc1, mfc1, dmtc1 or dmfc1. */
return NO_REGS;
}
else if (FP_REG_P (regno))
{
/* In this case we can use mov.s or mov.d. */
return NO_REGS;
}
else
{
/* Otherwise, we need to reload through an integer register. */
return GR_REGS;
}
}
/* In mips16 mode, going between memory and anything but M16_REGS /* In mips16 mode, going between memory and anything but M16_REGS
requires an M16_REG. */ requires an M16_REG. */
if (TARGET_MIPS16) if (TARGET_MIPS16)
......
...@@ -225,7 +225,6 @@ extern void sbss_section PARAMS ((void)); ...@@ -225,7 +225,6 @@ extern void sbss_section PARAMS ((void));
#define MASK_DEBUG_E 0 /* function_arg debug */ #define MASK_DEBUG_E 0 /* function_arg debug */
#define MASK_DEBUG_F 0 /* ??? */ #define MASK_DEBUG_F 0 /* ??? */
#define MASK_DEBUG_G 0 /* don't support 64 bit arithmetic */ #define MASK_DEBUG_G 0 /* don't support 64 bit arithmetic */
#define MASK_DEBUG_H 0 /* allow ints in FP registers */
#define MASK_DEBUG_I 0 /* unused */ #define MASK_DEBUG_I 0 /* unused */
/* Dummy switches used only in specs */ /* Dummy switches used only in specs */
...@@ -253,7 +252,6 @@ extern void sbss_section PARAMS ((void)); ...@@ -253,7 +252,6 @@ extern void sbss_section PARAMS ((void));
#define TARGET_DEBUG_E_MODE (target_flags & MASK_DEBUG_E) #define TARGET_DEBUG_E_MODE (target_flags & MASK_DEBUG_E)
#define TARGET_DEBUG_F_MODE (target_flags & MASK_DEBUG_F) #define TARGET_DEBUG_F_MODE (target_flags & MASK_DEBUG_F)
#define TARGET_DEBUG_G_MODE (target_flags & MASK_DEBUG_G) #define TARGET_DEBUG_G_MODE (target_flags & MASK_DEBUG_G)
#define TARGET_DEBUG_H_MODE (target_flags & MASK_DEBUG_H)
#define TARGET_DEBUG_I_MODE (target_flags & MASK_DEBUG_I) #define TARGET_DEBUG_I_MODE (target_flags & MASK_DEBUG_I)
/* Reg. Naming in .s ($21 vs. $a0) */ /* Reg. Naming in .s ($21 vs. $a0) */
...@@ -585,8 +583,6 @@ extern void sbss_section PARAMS ((void)); ...@@ -585,8 +583,6 @@ extern void sbss_section PARAMS ((void));
NULL}, \ NULL}, \
{"debugg", MASK_DEBUG_G, \ {"debugg", MASK_DEBUG_G, \
NULL}, \ NULL}, \
{"debugh", MASK_DEBUG_H, \
NULL}, \
{"debugi", MASK_DEBUG_I, \ {"debugi", MASK_DEBUG_I, \
NULL}, \ NULL}, \
{"", (TARGET_DEFAULT \ {"", (TARGET_DEFAULT \
...@@ -783,6 +779,11 @@ extern void sbss_section PARAMS ((void)); ...@@ -783,6 +779,11 @@ extern void sbss_section PARAMS ((void));
|| ISA_MIPS64) \ || ISA_MIPS64) \
&& !TARGET_MIPS16) && !TARGET_MIPS16)
/* True if trunc.w.s and trunc.w.d are real (not synthetic)
instructions. Both require TARGET_HARD_FLOAT, and trunc.w.d
also requires TARGET_DOUBLE_FLOAT. */
#define ISA_HAS_TRUNC_W (!ISA_MIPS1)
/* CC1_SPEC causes -mips3 and -mips4 to set -mfp64 and -mgp64; -mips1 or /* CC1_SPEC causes -mips3 and -mips4 to set -mfp64 and -mgp64; -mips1 or
-mips2 sets -mfp32 and -mgp32. This can be overridden by an explicit -mips2 sets -mfp32 and -mgp32. This can be overridden by an explicit
-mfp32, -mfp64, -mgp32 or -mgp64. -mfp64 sets MASK_FLOAT64 in -mfp32, -mfp64, -mgp32 or -mgp64. -mfp64 sets MASK_FLOAT64 in
...@@ -2243,17 +2244,20 @@ extern enum reg_class mips_char_to_class[256]; ...@@ -2243,17 +2244,20 @@ extern enum reg_class mips_char_to_class[256];
/* If defined, gives a class of registers that cannot be used as the /* If defined, gives a class of registers that cannot be used as the
operand of a SUBREG that changes the mode of the object illegally. operand of a SUBREG that changes the mode of the object illegally.
When FP regs are larger than integer regs... Er, anyone remember what
goes wrong?
In little-endian mode, the hi-lo registers are numbered backwards, In little-endian mode, the hi-lo registers are numbered backwards,
so (subreg:SI (reg:DI hi) 0) gets the high word instead of the low so (subreg:SI (reg:DI hi) 0) gets the high word instead of the low
word as intended. */ word as intended.
Also, loading a 32-bit value into a 64-bit floating-point register
will not sign-extend the value, despite what LOAD_EXTEND_OP says.
We can't allow 64-bit float registers to change from a 32-bit
mode to a 64-bit mode. */
#define CLASS_CANNOT_CHANGE_MODE \ #define CLASS_CANNOT_CHANGE_MODE \
(TARGET_BIG_ENDIAN \ (TARGET_BIG_ENDIAN \
? (TARGET_FLOAT64 && ! TARGET_64BIT ? FP_REGS : NO_REGS) \ ? (TARGET_FLOAT64 ? FP_REGS : NO_REGS) \
: (TARGET_FLOAT64 && ! TARGET_64BIT ? HI_AND_FP_REGS : HI_REG)) : (TARGET_FLOAT64 ? HI_AND_FP_REGS : HI_REG))
/* Defines illegal mode changes for CLASS_CANNOT_CHANGE_MODE. */ /* Defines illegal mode changes for CLASS_CANNOT_CHANGE_MODE. */
...@@ -3677,7 +3681,6 @@ typedef struct mips_args { ...@@ -3677,7 +3681,6 @@ typedef struct mips_args {
{"se_nonmemory_operand", { CONST_INT, CONST_DOUBLE, CONST, \ {"se_nonmemory_operand", { CONST_INT, CONST_DOUBLE, CONST, \
SYMBOL_REF, LABEL_REF, SUBREG, \ SYMBOL_REF, LABEL_REF, SUBREG, \
REG, SIGN_EXTEND }}, \ REG, SIGN_EXTEND }}, \
{"se_nonimmediate_operand", { SUBREG, REG, MEM, SIGN_EXTEND }}, \
{"consttable_operand", { LABEL_REF, SYMBOL_REF, CONST_INT, \ {"consttable_operand", { LABEL_REF, SYMBOL_REF, CONST_INT, \
CONST_DOUBLE, CONST }}, \ CONST_DOUBLE, CONST }}, \
{"extend_operator", { SIGN_EXTEND, ZERO_EXTEND }}, \ {"extend_operator", { SIGN_EXTEND, ZERO_EXTEND }}, \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment