diff options
Diffstat (limited to 'gcc/config/frv/frv.c')
-rw-r--r-- | gcc/config/frv/frv.c | 308 |
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 |