aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/frv/frv.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/frv/frv.c')
-rw-r--r--gcc/config/frv/frv.c308
1 files changed, 83 insertions, 225 deletions
diff --git a/gcc/config/frv/frv.c b/gcc/config/frv/frv.c
index 5d49e17..bef28f5 100644
--- a/gcc/config/frv/frv.c
+++ b/gcc/config/frv/frv.c
@@ -276,6 +276,7 @@ static void frv_print_operand_memory_reference_reg
(FILE *, rtx);
static void frv_print_operand_memory_reference (FILE *, rtx, int);
static int frv_print_operand_jump_hint (rtx);
+static const char *comparison_string (enum rtx_code, rtx);
static FRV_INLINE int frv_regno_ok_for_base_p (int, int);
static rtx single_set_pattern (rtx);
static int frv_function_contains_far_jump (void);
@@ -2683,6 +2684,29 @@ frv_print_operand_jump_hint (rtx insn)
}
+/* Return the comparison operator to use for CODE given that the ICC
+ register is OP0. */
+
+static const char *
+comparison_string (enum rtx_code code, rtx op0)
+{
+ bool is_nz_p = GET_MODE (op0) == CC_NZmode;
+ switch (code)
+ {
+ default: output_operand_lossage ("bad condition code");
+ case EQ: return "eq";
+ case NE: return "ne";
+ case LT: return is_nz_p ? "n" : "lt";
+ case LE: return "le";
+ case GT: return "gt";
+ case GE: return is_nz_p ? "p" : "ge";
+ case LTU: return is_nz_p ? "no" : "c";
+ case LEU: return is_nz_p ? "eq" : "ls";
+ case GTU: return is_nz_p ? "ne" : "hi";
+ case GEU: return is_nz_p ? "ra" : "nc";
+ }
+}
+
/* Print an operand to an assembler instruction.
`%' followed by a letter and a digit says to output an operand in an
@@ -2786,45 +2810,13 @@ frv_print_operand (FILE * file, rtx x, int code)
case 'C':
/* Print appropriate test for integer branch false operation. */
- switch (GET_CODE (x))
- {
- default:
- fatal_insn ("Bad insn to frv_print_operand, 'C' modifier:", x);
-
- case EQ: fputs ("ne", file); break;
- case NE: fputs ("eq", file); break;
- case LT: fputs ("ge", file); break;
- case LE: fputs ("gt", file); break;
- case GT: fputs ("le", file); break;
- case GE: fputs ("lt", file); break;
- case LTU: fputs ("nc", file); break;
- case LEU: fputs ("hi", file); break;
- case GTU: fputs ("ls", file); break;
- case GEU: fputs ("c", file); break;
- }
+ fputs (comparison_string (reverse_condition (GET_CODE (x)),
+ XEXP (x, 0)), file);
break;
- /* case 'c': print a constant without the constant prefix. If
- CONSTANT_ADDRESS_P(x) is not true, PRINT_OPERAND is called. */
-
case 'c':
/* Print appropriate test for integer branch true operation. */
- switch (GET_CODE (x))
- {
- default:
- fatal_insn ("Bad insn to frv_print_operand, 'c' modifier:", x);
-
- case EQ: fputs ("eq", file); break;
- case NE: fputs ("ne", file); break;
- case LT: fputs ("lt", file); break;
- case LE: fputs ("le", file); break;
- case GT: fputs ("gt", file); break;
- case GE: fputs ("ge", file); break;
- case LTU: fputs ("c", file); break;
- case LEU: fputs ("ls", file); break;
- case GTU: fputs ("hi", file); break;
- case GEU: fputs ("nc", file); break;
- }
+ fputs (comparison_string (GET_CODE (x), XEXP (x, 0)), file);
break;
case 'e':
@@ -4801,71 +4793,20 @@ sibcall_operand (rtx op, enum machine_mode mode)
int
relational_operator (rtx op, enum machine_mode mode)
{
- rtx op0;
- rtx op1;
- int regno;
-
- if (mode != VOIDmode && mode != GET_MODE (op))
- return FALSE;
-
- switch (GET_CODE (op))
- {
- default:
- return FALSE;
-
- case EQ:
- case NE:
- case LE:
- case LT:
- case GE:
- case GT:
- case LEU:
- case LTU:
- case GEU:
- case GTU:
- break;
- }
-
- op1 = XEXP (op, 1);
- if (op1 != const0_rtx)
- return FALSE;
-
- op0 = XEXP (op, 0);
- if (GET_CODE (op0) != REG)
- return FALSE;
-
- regno = REGNO (op0);
- switch (GET_MODE (op0))
- {
- default:
- break;
-
- case CCmode:
- case CC_UNSmode:
- return ICC_OR_PSEUDO_P (regno);
-
- case CC_FPmode:
- return FCC_OR_PSEUDO_P (regno);
-
- case CC_CCRmode:
- return CR_OR_PSEUDO_P (regno);
- }
-
- return FALSE;
+ return (integer_relational_operator (op, mode)
+ || float_relational_operator (op, mode));
}
-/* Return true if operator is a signed integer relational operator. */
+/* Return true if OP is a relational operator suitable for CCmode,
+ CC_UNSmode or CC_NZmode. */
int
-signed_relational_operator (rtx op, enum machine_mode mode)
+integer_relational_operator (rtx op, enum machine_mode mode)
{
- rtx op0;
- rtx op1;
- int regno;
-
if (mode != VOIDmode && mode != GET_MODE (op))
return FALSE;
+ /* The allowable relations depend on the mode of the ICC register. */
switch (GET_CODE (op))
{
default:
@@ -4873,71 +4814,22 @@ signed_relational_operator (rtx op, enum machine_mode mode)
case EQ:
case NE:
- case LE:
case LT:
case GE:
- case GT:
- break;
- }
+ return (GET_MODE (XEXP (op, 0)) == CC_NZmode
+ || GET_MODE (XEXP (op, 0)) == CCmode);
- op1 = XEXP (op, 1);
- if (op1 != const0_rtx)
- return FALSE;
-
- op0 = XEXP (op, 0);
- if (GET_CODE (op0) != REG)
- return FALSE;
-
- regno = REGNO (op0);
- if (GET_MODE (op0) == CCmode && ICC_OR_PSEUDO_P (regno))
- return TRUE;
-
- if (GET_MODE (op0) == CC_CCRmode && CR_OR_PSEUDO_P (regno))
- return TRUE;
-
- return FALSE;
-}
-
-/* Return true if operator is a signed integer relational operator. */
-
-int
-unsigned_relational_operator (rtx op, enum machine_mode mode)
-{
- rtx op0;
- rtx op1;
- int regno;
-
- if (mode != VOIDmode && mode != GET_MODE (op))
- return FALSE;
-
- switch (GET_CODE (op))
- {
- default:
- return FALSE;
+ case LE:
+ case GT:
+ return GET_MODE (XEXP (op, 0)) == CCmode;
- case LEU:
- case LTU:
- case GEU:
case GTU:
- break;
+ case GEU:
+ case LTU:
+ case LEU:
+ return (GET_MODE (XEXP (op, 0)) == CC_NZmode
+ || GET_MODE (XEXP (op, 0)) == CC_UNSmode);
}
-
- op1 = XEXP (op, 1);
- if (op1 != const0_rtx)
- return FALSE;
-
- op0 = XEXP (op, 0);
- if (GET_CODE (op0) != REG)
- return FALSE;
-
- regno = REGNO (op0);
- if (GET_MODE (op0) == CC_UNSmode && ICC_OR_PSEUDO_P (regno))
- return TRUE;
-
- if (GET_MODE (op0) == CC_CCRmode && CR_OR_PSEUDO_P (regno))
- return TRUE;
-
- return FALSE;
}
/* Return true if operator is a floating point relational operator. */
@@ -4945,10 +4837,6 @@ unsigned_relational_operator (rtx op, enum machine_mode mode)
int
float_relational_operator (rtx op, enum machine_mode mode)
{
- rtx op0;
- rtx op1;
- int regno;
-
if (mode != VOIDmode && mode != GET_MODE (op))
return FALSE;
@@ -4967,25 +4855,8 @@ float_relational_operator (rtx op, enum machine_mode mode)
case ORDERED:
case UNORDERED:
#endif
- break;
+ return GET_MODE (XEXP (op, 0)) == CC_FPmode;
}
-
- op1 = XEXP (op, 1);
- if (op1 != const0_rtx)
- return FALSE;
-
- op0 = XEXP (op, 0);
- if (GET_CODE (op0) != REG)
- return FALSE;
-
- regno = REGNO (op0);
- if (GET_MODE (op0) == CC_FPmode && FCC_OR_PSEUDO_P (regno))
- return TRUE;
-
- if (GET_MODE (op0) == CC_CCRmode && CR_OR_PSEUDO_P (regno))
- return TRUE;
-
- return FALSE;
}
/* Return true if operator is EQ/NE of a conditional execution register. */
@@ -5227,51 +5098,13 @@ condexec_memory_operand (rtx op, enum machine_mode mode)
return frv_legitimate_address_p (mode, addr, reload_completed, TRUE, FALSE);
}
-/* Return true if operator is an integer binary operator that can be combined
- with a setcc operation. Do not allow the arithmetic operations that could
- potentially overflow since the FR-V sets the condition code based on the
- "true" value of the result, not the result after truncating to a 32-bit
- register. */
+/* Return true if OP is an integer binary operator that can be combined
+ with a (set ... (compare:CC_NZ ...)) pattern. */
int
intop_compare_operator (rtx op, enum machine_mode mode)
{
- enum machine_mode op_mode = GET_MODE (op);
-
- if (mode != VOIDmode && op_mode != mode)
- return FALSE;
-
- switch (GET_CODE (op))
- {
- default:
- return FALSE;
-
- case AND:
- case IOR:
- case XOR:
- case ASHIFTRT:
- case LSHIFTRT:
- break;
- }
-
- if (! integer_register_operand (XEXP (op, 0), SImode))
- return FALSE;
-
- if (! gpr_or_int10_operand (XEXP (op, 1), SImode))
- return FALSE;
-
- return TRUE;
-}
-
-/* Return true if operator is an integer binary operator that can be combined
- with a setcc operation inside of a conditional execution. */
-
-int
-condexec_intop_cmp_operator (rtx op, enum machine_mode mode)
-{
- enum machine_mode op_mode = GET_MODE (op);
-
- if (mode != VOIDmode && op_mode != mode)
+ if (mode != VOIDmode && GET_MODE (op) != mode)
return FALSE;
switch (GET_CODE (op))
@@ -5279,21 +5112,15 @@ condexec_intop_cmp_operator (rtx op, enum machine_mode mode)
default:
return FALSE;
+ case PLUS:
+ case MINUS:
case AND:
case IOR:
case XOR:
case ASHIFTRT:
case LSHIFTRT:
- break;
+ return GET_MODE (op) == SImode;
}
-
- if (! integer_register_operand (XEXP (op, 0), SImode))
- return FALSE;
-
- if (! integer_register_operand (XEXP (op, 1), SImode))
- return FALSE;
-
- return TRUE;
}
/* Return 1 if operand is a valid ACC register number. */
@@ -6895,7 +6722,7 @@ frv_ifcvt_modify_tests (ce_if_block_t *ce_info, rtx *p_true, rtx *p_false)
/* Allocate the appropriate temporary condition code register. Try to
allocate the ICR/FCR register that corresponds to the ICC/FCC register so
that conditional cmp's can be done. */
- if (mode == CCmode || mode == CC_UNSmode)
+ if (mode == CCmode || mode == CC_UNSmode || mode == CC_NZmode)
{
cr_class = ICR_REGS;
cc_class = ICC_REGS;
@@ -7050,7 +6877,7 @@ frv_ifcvt_modify_multiple_tests (ce_if_block_t *ce_info,
if (GET_CODE (cr) != REG)
goto fail;
- if (mode == CCmode || mode == CC_UNSmode)
+ if (mode == CCmode || mode == CC_UNSmode || mode == CC_NZmode)
{
cr_class = ICR_REGS;
p_new_cr = &frv_ifcvt.extra_int_cr;
@@ -8010,6 +7837,7 @@ frv_hard_regno_mode_ok (int regno, enum machine_mode mode)
{
case CCmode:
case CC_UNSmode:
+ case CC_NZmode:
return ICC_P (regno) || GPR_P (regno);
case CC_CCRmode:
@@ -8164,6 +7992,36 @@ frv_legitimate_constant_p (rtx x)
/* Otherwise store the constant away and do a load. */
return FALSE;
}
+
+/* Implement SELECT_CC_MODE. Choose CC_FP for floating-point comparisons,
+ CC_NZ for comparisons against zero in which a single Z or N flag test
+ is enough, CC_UNS for other unsigned comparisons, and CC for other
+ signed comparisons. */
+
+enum machine_mode
+frv_select_cc_mode (enum rtx_code code, rtx x, rtx y)
+{
+ if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
+ return CC_FPmode;
+
+ switch (code)
+ {
+ case EQ:
+ case NE:
+ case LT:
+ case GE:
+ return y == const0_rtx ? CC_NZmode : CCmode;
+
+ case GTU:
+ case GEU:
+ case LTU:
+ case LEU:
+ return y == const0_rtx ? CC_NZmode : CC_UNSmode;
+
+ default:
+ return CCmode;
+ }
+}
/* A C expression for the cost of moving data from a register in class FROM to
one in class TO. The classes are expressed using the enumeration values