aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/sparc/sparc.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/sparc/sparc.c')
-rw-r--r--gcc/config/sparc/sparc.c163
1 files changed, 114 insertions, 49 deletions
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
index 8bf67aa..dc6bcbf 100644
--- a/gcc/config/sparc/sparc.c
+++ b/gcc/config/sparc/sparc.c
@@ -99,7 +99,7 @@ char leaf_reg_remap[] =
72, 73, 74, 75, 76, 77, 78, 79,
80, 81, 82, 83, 84, 85, 86, 87,
88, 89, 90, 91, 92, 93, 94, 95,
- 96, 97, 98, 99};
+ 96, 97, 98, 99, 100};
#endif
@@ -268,13 +268,19 @@ v9_regcmp_p (code)
/* Operand constraints. */
/* Return non-zero only if OP is a register of mode MODE,
- or const0_rtx. */
+ or const0_rtx. Don't allow const0_rtx if TARGET_LIVE_G0 because
+ %g0 may contain anything. */
+
int
reg_or_0_operand (op, mode)
rtx op;
enum machine_mode mode;
{
- if (op == const0_rtx || register_operand (op, mode))
+ if (register_operand (op, mode))
+ return 1;
+ if (TARGET_LIVE_G0)
+ return 0;
+ if (op == const0_rtx)
return 1;
if (GET_MODE (op) == VOIDmode && GET_CODE (op) == CONST_DOUBLE
&& CONST_DOUBLE_HIGH (op) == 0
@@ -288,6 +294,7 @@ reg_or_0_operand (op, mode)
}
/* Nonzero if OP is a floating point value with value 0.0. */
+
int
fp_zero_operand (op)
rtx op;
@@ -312,26 +319,38 @@ intreg_operand (op, mode)
/* Nonzero if OP is a floating point condition code register. */
int
-ccfp_reg_operand (op, mode)
+fcc_reg_operand (op, mode)
rtx op;
enum machine_mode mode;
{
/* This can happen when recog is called from combine. Op may be a MEM.
Fail instead of calling abort in this case. */
- if (GET_CODE (op) != REG || REGNO (op) == 0)
+ if (GET_CODE (op) != REG)
return 0;
- if (GET_MODE (op) != mode)
+ if (mode != VOIDmode && mode != GET_MODE (op))
return 0;
-#if 0 /* ??? ==> 1 when %fcc1-3 are pseudos first. See gen_compare_reg(). */
+#if 0 /* ??? ==> 1 when %fcc0-3 are pseudos first. See gen_compare_reg(). */
if (reg_renumber == 0)
return REGNO (op) >= FIRST_PSEUDO_REGISTER;
return REGNO_OK_FOR_CCFP_P (REGNO (op));
#else
- return (unsigned) REGNO (op) - 96 < 4;
+ return (unsigned) REGNO (op) - SPARC_FIRST_V9_FCC_REG < 4;
#endif
}
+/* Nonzero if OP is an integer or floating point condition code register. */
+
+int
+icc_or_fcc_reg_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ if (GET_CODE (op) == REG && REGNO (op) == SPARC_ICC_REG)
+ return 1;
+ return fcc_reg_operand (op, mode);
+}
+
/* Nonzero if OP can appear as the dest of a RESTORE insn. */
int
restore_operand (op, mode)
@@ -855,7 +874,7 @@ gen_compare_reg (code, x, y)
rtx cc_reg;
/* ??? We don't have movcc patterns so we cannot generate pseudo regs for the
- fpcc regs (cse can't tell they're really call clobbered regs and will
+ fcc regs (cse can't tell they're really call clobbered regs and will
remove a duplicate comparison even if there is an intervening function
call - it will then try to reload the cc reg via an int reg which is why
we need the movcc patterns). It is possible to provide the movcc
@@ -875,8 +894,8 @@ gen_compare_reg (code, x, y)
{
int reg;
/* We cycle through the registers to ensure they're all exercised. */
- static int next_fpcc_reg = 0;
- /* Previous x,y for each fpcc reg. */
+ static int next_fcc_reg = 0;
+ /* Previous x,y for each fcc reg. */
static rtx prev_args[4][2];
/* Scan prev_args for x,y. */
@@ -885,18 +904,20 @@ gen_compare_reg (code, x, y)
break;
if (reg == 4)
{
- reg = next_fpcc_reg;
+ reg = next_fcc_reg;
prev_args[reg][0] = x;
prev_args[reg][1] = y;
- next_fpcc_reg = (next_fpcc_reg + 1) & 3;
+ next_fcc_reg = (next_fcc_reg + 1) & 3;
}
- cc_reg = gen_rtx (REG, mode, reg + 96);
+ cc_reg = gen_rtx (REG, mode, reg + SPARC_FIRST_V9_FCC_REG);
}
#else
cc_reg = gen_reg_rtx (mode);
#endif /* ! experiment */
+ else if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
+ cc_reg = gen_rtx (REG, mode, SPARC_FCC_REG);
else
- cc_reg = gen_rtx (REG, mode, 0);
+ cc_reg = gen_rtx (REG, mode, SPARC_ICC_REG);
emit_insn (gen_rtx (SET, VOIDmode, cc_reg,
gen_rtx (COMPARE, mode, x, y)));
@@ -1062,6 +1083,14 @@ eligible_for_epilogue_delay (trial, slot)
if (get_attr_length (trial) != 1)
return 0;
+ pat = PATTERN (trial);
+
+ /* If %g0 is live, there are lots of things we can't handle.
+ Rather than trying to find them all now, let's punt and only
+ optimize things as necessary. */
+ if (TARGET_LIVE_G0)
+ return 0;
+
/* In the case of a true leaf function, anything can go into the delay slot.
A delay slot only exists however if the frame size is zero, otherwise
we will put an insn to adjust the stack after the return. */
@@ -1074,9 +1103,7 @@ eligible_for_epilogue_delay (trial, slot)
/* Otherwise, only operations which can be done in tandem with
a `restore' insn can go into the delay slot. */
- pat = PATTERN (trial);
if (GET_CODE (SET_DEST (pat)) != REG
- || REGNO (SET_DEST (pat)) == 0
|| REGNO (SET_DEST (pat)) >= 32
|| REGNO (SET_DEST (pat)) < 24)
return 0;
@@ -1442,7 +1469,8 @@ emit_move_sequence (operands, mode)
}
else if (GET_CODE (operand0) == MEM)
{
- if (register_operand (operand1, mode) || operand1 == const0_rtx)
+ if (register_operand (operand1, mode)
+ || (operand1 == const0_rtx && ! TARGET_LIVE_G0))
{
/* Run this case quickly. */
emit_insn (gen_rtx (SET, VOIDmode, operand0, operand1));
@@ -2575,7 +2603,8 @@ output_scc_insn (operands, insn)
LABEL_NUSES (label) += 1;
- operands[2] = label;
+ /* operands[3] is an unused slot. */
+ operands[3] = label;
/* If we are in a delay slot, assume it is the delay slot of an fpcc
insn since our type isn't allowed anywhere else. */
@@ -2598,17 +2627,17 @@ output_scc_insn (operands, insn)
if (final_sequence)
{
strcpy (string, "mov 0,%0\n\t");
- strcat (string, output_cbranch (operands[1], 0, 2, 0, 1, 0));
+ strcat (string, output_cbranch (operands[2], 3, 0, 1, 0));
strcat (string, "\n\tmov 1,%0");
}
else
{
- strcpy (string, output_cbranch (operands[1], 0, 2, 0, 1, 0));
+ strcpy (string, output_cbranch (operands[2], 3, 0, 1, 0));
strcat (string, "\n\tmov 1,%0\n\tmov 0,%0");
}
if (need_label)
- strcat (string, "\n%l2:");
+ strcat (string, "\n%l3:");
return string;
}
@@ -2623,15 +2652,11 @@ output_scc_insn (operands, insn)
mapped into one sparc_mode_class mode. */
enum sparc_mode_class {
- C_MODE, CCFP_MODE,
S_MODE, D_MODE, T_MODE, O_MODE,
- SF_MODE, DF_MODE, TF_MODE, OF_MODE
+ SF_MODE, DF_MODE, TF_MODE, OF_MODE,
+ CC_MODE, CCFP_MODE
};
-/* Modes for condition codes. */
-#define C_MODES ((1 << (int) C_MODE) | (1 << (int) CCFP_MODE))
-#define CCFP_MODES (1 << (int) CCFP_MODE)
-
/* Modes for single-word and smaller quantities. */
#define S_MODES ((1 << (int) S_MODE) | (1 << (int) SF_MODE))
@@ -2653,7 +2678,8 @@ enum sparc_mode_class {
#define DF_MODES64 (SF_MODES | DF_MODE /* | D_MODE*/)
/* Modes for double-float only quantities. */
-/* ??? Sparc64 fp regs cannot hold DImode values. */
+/* ??? Sparc64 fp regs cannot hold DImode values.
+ See fix_truncsfdi2. */
#define DF_ONLY_MODES ((1 << (int) DF_MODE) /*| (1 << (int) D_MODE)*/)
/* Modes for double-float and larger quantities. */
@@ -2665,20 +2691,25 @@ enum sparc_mode_class {
/* Modes for quad-float and smaller quantities. */
#define TF_MODES (DF_MODES | TF_ONLY_MODES)
-/* ??? Sparc64 fp regs cannot hold DImode values. */
+/* ??? Sparc64 fp regs cannot hold DImode values.
+ See fix_truncsfdi2. */
#define TF_MODES64 (DF_MODES64 | TF_ONLY_MODES)
+/* Modes for condition codes. */
+#define CC_MODES (1 << (int) CC_MODE)
+#define CCFP_MODES (1 << (int) CCFP_MODE)
+
/* Value is 1 if register/mode pair is acceptable on sparc.
The funny mixture of D and T modes is because integer operations
do not specially operate on tetra quantities, so non-quad-aligned
registers can hold quadword quantities (except %o4 and %i4 because
- they cross fixed registers. */
+ they cross fixed registers). */
/* This points to either the 32 bit or the 64 bit version. */
int *hard_regno_mode_classes;
static int hard_32bit_mode_classes[] = {
- C_MODES, S_MODES, T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES,
+ S_MODES, S_MODES, T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES,
T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, D_MODES, S_MODES,
T_MODES, S_MODES, T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES,
T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, D_MODES, S_MODES,
@@ -2696,11 +2727,14 @@ static int hard_32bit_mode_classes[] = {
DF_UP_MODES, 0, DF_ONLY_MODES, 0, DF_UP_MODES, 0, DF_ONLY_MODES, 0,
/* %fcc[0123] */
- CCFP_MODE, CCFP_MODE, CCFP_MODE, CCFP_MODE
+ CCFP_MODES, CCFP_MODES, CCFP_MODES, CCFP_MODES,
+
+ /* %icc */
+ CC_MODES
};
static int hard_64bit_mode_classes[] = {
- C_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES,
+ D_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES,
T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES,
T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES,
T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES,
@@ -2718,11 +2752,16 @@ static int hard_64bit_mode_classes[] = {
DF_UP_MODES, 0, DF_ONLY_MODES, 0, DF_UP_MODES, 0, DF_ONLY_MODES, 0,
/* %fcc[0123] */
- CCFP_MODE, CCFP_MODE, CCFP_MODE, CCFP_MODE
+ CCFP_MODES, CCFP_MODES, CCFP_MODES, CCFP_MODES,
+
+ /* %icc */
+ CC_MODES
};
int sparc_mode_class [NUM_MACHINE_MODES];
+enum reg_class sparc_regno_reg_class[FIRST_PSEUDO_REGISTER];
+
static void
sparc_init_modes ()
{
@@ -2767,7 +2806,7 @@ sparc_init_modes ()
sparc_mode_class[i] = 1 << (int) CCFP_MODE;
else if (i == (int) CCmode || i == (int) CC_NOOVmode
|| i == (int) CCXmode || i == (int) CCX_NOOVmode)
- sparc_mode_class[i] = 1 << (int) C_MODE;
+ sparc_mode_class[i] = 1 << (int) CC_MODE;
else
sparc_mode_class[i] = 0;
break;
@@ -2778,6 +2817,21 @@ sparc_init_modes ()
hard_regno_mode_classes = hard_64bit_mode_classes;
else
hard_regno_mode_classes = hard_32bit_mode_classes;
+
+ /* Initialize the array used by REGNO_REG_CLASS. */
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ {
+ if (i < 32)
+ sparc_regno_reg_class[i] = GENERAL_REGS;
+ else if (i < 64)
+ sparc_regno_reg_class[i] = FP_REGS;
+ else if (i < 96)
+ sparc_regno_reg_class[i] = EXTRA_FP_REGS;
+ else if (i < 100)
+ sparc_regno_reg_class[i] = FPCC_REGS;
+ else
+ sparc_regno_reg_class[i] = NO_REGS;
+ }
}
/* Save non call used registers from LOW to HIGH at BASE+OFFSET.
@@ -3320,11 +3374,9 @@ sparc_builtin_saveregs (arglist)
#endif /* ! SPARC_ARCH64 */
/* Return the string to output a conditional branch to LABEL, which is
- the operand number of the label. OP is the conditional expression. The
- mode of register 0 says what kind of comparison we made.
-
- FP_COND_REG indicates which fp condition code register to use if this is
- a floating point branch.
+ the operand number of the label. OP is the conditional expression.
+ XEXP (OP, 0) is assumed to be a condition code register (integer or
+ floating point) and its mode specifies what kind of comparison we made.
REVERSED is non-zero if we should reverse the sense of the comparison.
@@ -3333,14 +3385,15 @@ sparc_builtin_saveregs (arglist)
NOOP is non-zero if we have to follow this branch by a noop. */
char *
-output_cbranch (op, fp_cond_reg, label, reversed, annul, noop)
- rtx op, fp_cond_reg;
+output_cbranch (op, label, reversed, annul, noop)
+ rtx op;
int label;
int reversed, annul, noop;
{
static char string[20];
enum rtx_code code = GET_CODE (op);
- enum machine_mode mode = GET_MODE (XEXP (op, 0));
+ rtx cc_reg = XEXP (op, 0);
+ enum machine_mode mode = GET_MODE (cc_reg);
static char v8_labelno[] = " %lX";
static char v9_icc_labelno[] = " %%icc,%lX";
static char v9_xcc_labelno[] = " %%xcc,%lX";
@@ -3467,7 +3520,7 @@ output_cbranch (op, fp_cond_reg, label, reversed, annul, noop)
labeloff = 10;
labelno = v9_fcc_labelno;
/* Set the char indicating the number of the fcc reg to use. */
- labelno[6] = REGNO (fp_cond_reg) - 96 + '0';
+ labelno[6] = REGNO (cc_reg) - SPARC_FIRST_V9_FCC_REG + '0';
}
else if (mode == CCXmode || mode == CCX_NOOVmode)
labelno = v9_xcc_labelno;
@@ -3930,8 +3983,9 @@ print_operand (file, x, code)
else if (GET_CODE (x) == MEM)
{
fputc ('[', file);
- if (CONSTANT_P (XEXP (x, 0)))
/* Poor Sun assembler doesn't understand absolute addressing. */
+ if (CONSTANT_P (XEXP (x, 0))
+ && ! TARGET_LIVE_G0)
fputs ("%g0+", file);
output_address (XEXP (x, 0));
fputc (']', file);
@@ -4847,10 +4901,21 @@ sparc_flat_eligible_for_epilogue_delay (trial, slot)
rtx trial;
int slot;
{
- if (get_attr_length (trial) == 1
- && ! reg_mentioned_p (stack_pointer_rtx, PATTERN (trial))
- && ! reg_mentioned_p (frame_pointer_rtx, PATTERN (trial)))
+ rtx pat = PATTERN (trial);
+
+ if (get_attr_length (trial) != 1)
+ return 0;
+
+ /* If %g0 is live, there are lots of things we can't handle.
+ Rather than trying to find them all now, let's punt and only
+ optimize things as necessary. */
+ if (TARGET_LIVE_G0)
+ return 0;
+
+ if (! reg_mentioned_p (stack_pointer_rtx, pat)
+ && ! reg_mentioned_p (frame_pointer_rtx, pat))
return 1;
+
return 0;
}