diff options
author | Geoff Keating <geoffk@cygnus.com> | 2000-09-06 09:12:51 +0000 |
---|---|---|
committer | Geoffrey Keating <geoffk@gcc.gnu.org> | 2000-09-06 09:12:51 +0000 |
commit | 39a10a297a95e994e1aeb66d43c75fc1b2a15d7f (patch) | |
tree | b7cc73d2c5daab569be640d46abbcb472c5b15ea /gcc/config | |
parent | 6e92b232be51d39eb147f167119a493785a2e98b (diff) | |
download | gcc-39a10a297a95e994e1aeb66d43c75fc1b2a15d7f.zip gcc-39a10a297a95e994e1aeb66d43c75fc1b2a15d7f.tar.gz gcc-39a10a297a95e994e1aeb66d43c75fc1b2a15d7f.tar.bz2 |
rs6000.c (validate_condition_mode): New function.
* config/rs6000/rs6000.c (validate_condition_mode): New function.
(branch_comparison_operator): Call validate_condition_mode to
abort rather than returning 0.
(branch_positive_comparison_operator): New function.
(scc_comparison_operator): Call validate_condition_mode to abort
rather than returning 0.
(ccr_bit): Call validate_condition_mode. Update for
new branch scheme.
(print_operand): Delete %C modifier. Update %E case
to use EQ bit not SO bit.
(rs6000_reverse_condition): New function.
(rs6000_generate_compare): New function.
(rs6000_emit_sCOND): New function.
(rs6000_emit_cbranch): New function.
(output_cbranch): The length of a long branch insn is
now only 8 bytes. Add validate_condition_mode. Use
rs6000_reverse_condition. Remove cror generation.
* config/rs6000/rs6000.h: Update comments.
(PREDICATE_CODES): Add new predicate. Update codes used
by branch_comparison_operator and scc_comparison_operator.
* config/rs6000/rs6000-protos.h: Add prototypes for
new external functions.
* config/rs6000/rs6000.md: Add new scheduling parameters
for cr_logical instructions. Change length of branch
instructions.
(bCOND patterns): Call rs6000_emit_cbranch.
(sCOND patterns): Call rs6000_emit_sCOND.
(branch patterns): Change lengths to 4.
(cr logical patterns): New.
From-SVN: r36191
Diffstat (limited to 'gcc/config')
-rw-r--r-- | gcc/config/rs6000/rs6000-protos.h | 6 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.c | 317 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.h | 110 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.md | 666 |
4 files changed, 482 insertions, 617 deletions
diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h index 7d127ce..38b35de 100644 --- a/gcc/config/rs6000/rs6000-protos.h +++ b/gcc/config/rs6000/rs6000-protos.h @@ -73,6 +73,8 @@ extern int expand_block_move PARAMS ((rtx[])); extern int load_multiple_operation PARAMS ((rtx, enum machine_mode)); extern int store_multiple_operation PARAMS ((rtx, enum machine_mode)); extern int branch_comparison_operator PARAMS ((rtx, enum machine_mode)); +extern int branch_positive_comparison_operator + PARAMS ((rtx, enum machine_mode)); extern int scc_comparison_operator PARAMS ((rtx, enum machine_mode)); extern int trap_comparison_operator PARAMS ((rtx, enum machine_mode)); extern int boolean_operator PARAMS ((rtx, enum machine_mode)); @@ -87,6 +89,10 @@ extern enum reg_class secondary_reload_class PARAMS ((enum reg_class, extern int ccr_bit PARAMS ((rtx, int)); extern void print_operand PARAMS ((FILE *, rtx, int)); extern void print_operand_address PARAMS ((FILE *, rtx)); +extern enum rtx_code rs6000_reverse_condition PARAMS ((enum machine_mode, + enum rtx_code)); +extern void rs6000_emit_sCOND PARAMS ((enum rtx_code, rtx)); +extern void rs6000_emit_cbranch PARAMS ((enum rtx_code, rtx)); extern char * output_cbranch PARAMS ((rtx, const char *, int, rtx)); extern void output_toc PARAMS ((FILE *, rtx, int, enum machine_mode)); extern int rs6000_adjust_cost PARAMS ((rtx, rtx, rtx, int)); diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 18106cb..c1771f5 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -119,6 +119,9 @@ static int rs6000_sr_alias_set; static void rs6000_add_gc_roots PARAMS ((void)); static int num_insns_constant_wide PARAMS ((HOST_WIDE_INT)); static rtx expand_block_move_mem PARAMS ((enum machine_mode, rtx, rtx)); +static void validate_condition_mode + PARAMS ((enum rtx_code, enum machine_mode)); +static rtx rs6000_generate_compare PARAMS ((enum rtx_code)); static void rs6000_maybe_dead PARAMS ((rtx)); static void rs6000_emit_stack_tie PARAMS ((void)); static void rs6000_frame_related PARAMS ((rtx, rtx, HOST_WIDE_INT, rtx, rtx)); @@ -3212,6 +3215,48 @@ stmw_operation (op, mode) return 1; } + +/* A validation routine: say whether CODE, a condition code, + and MODE match. The other alternatives either don't make + sense or should never be generated. */ +static void +validate_condition_mode (code, mode) + enum rtx_code code; + enum machine_mode mode; +{ + if (GET_RTX_CLASS (code) != '<' + || GET_MODE_CLASS (mode) != MODE_CC) + abort (); + + /* These don't make sense. */ + if ((code == GT || code == LT || code == GE || code == LE) + && mode == CCUNSmode) + abort (); + + if ((code == GTU || code == LTU || code == GEU || code == LEU) + && mode != CCUNSmode) + abort (); + + if (mode != CCFPmode + && (code == ORDERED || code == UNORDERED + || code == UNEQ || code == LTGT + || code == UNGT || code == UNLT + || code == UNGE || code == UNLE)) + abort(); + + /* These should never be generated. */ + if (mode == CCFPmode + && (code == LE || code == GE + || code == UNEQ || code == LTGT + || code == UNGT || code == UNLT)) + abort (); + + /* These are invalid; the information is not there. */ + if (mode == CCEQmode + && code != EQ && code != NE) + abort (); +} + /* Return 1 if OP is a comparison operation that is valid for a branch insn. We only check the opcode against the mode of the CC value here. */ @@ -3230,17 +3275,32 @@ branch_comparison_operator (op, mode) if (GET_MODE_CLASS (cc_mode) != MODE_CC) return 0; - if ((code == GT || code == LT || code == GE || code == LE) - && cc_mode == CCUNSmode) - return 0; + validate_condition_mode (code, cc_mode); - if ((code == GTU || code == LTU || code == GEU || code == LEU) - && (cc_mode != CCUNSmode)) + return 1; +} + +/* Return 1 if OP is a comparison operation that is valid for a branch + insn and which is true if the corresponding bit in the CC register + is set. */ + +int +branch_positive_comparison_operator (op, mode) + register rtx op; + enum machine_mode mode; +{ + enum rtx_code code; + + if (! branch_comparison_operator (op, mode)) return 0; - return 1; + code = GET_CODE (op); + return (code == EQ || code == LT || code == GT + || code == LTU || code == GTU + || code == UNORDERED); } + /* Return 1 if OP is a comparison operation that is valid for an scc insn. We check the opcode against the mode of the CC value and disallow EQ or NE comparisons for integers. */ @@ -3263,18 +3323,9 @@ scc_comparison_operator (op, mode) if (GET_MODE_CLASS (cc_mode) != MODE_CC) return 0; - if (code == NE && cc_mode != CCFPmode) - return 0; - - if ((code == GT || code == LT || code == GE || code == LE) - && cc_mode == CCUNSmode) - return 0; + validate_condition_mode (code, cc_mode); - if ((code == GTU || code == LTU || code == GEU || code == LEU) - && (cc_mode != CCUNSmode)) - return 0; - - if (cc_mode == CCEQmode && code != EQ && code != NE) + if (code == NE && cc_mode != CCFPmode) return 0; return 1; @@ -3287,8 +3338,7 @@ trap_comparison_operator (op, mode) { if (mode != VOIDmode && mode != GET_MODE (op)) return 0; - return (GET_RTX_CLASS (GET_CODE (op)) == '<' - || GET_CODE (op) == EQ || GET_CODE (op) == NE); + return GET_RTX_CLASS (GET_CODE (op)) == '<'; } int @@ -3538,11 +3588,7 @@ ccr_bit (op, scc_p) cc_regnum = REGNO (reg); base_bit = 4 * (cc_regnum - CR0_REGNO); - /* In CCEQmode cases we have made sure that the result is always in the - third bit of the CR field. */ - - if (cc_mode == CCEQmode) - return base_bit + 3; + validate_condition_mode (code, cc_mode); switch (code) { @@ -3558,16 +3604,13 @@ ccr_bit (op, scc_p) return base_bit + 3; case GE: case GEU: - /* If floating-point, we will have done a cror to put the bit in the + /* If scc, we will have done a cror to put the bit in the unordered position. So test that bit. For integer, this is ! LT unless this is an scc insn. */ - return cc_mode == CCFPmode || scc_p ? base_bit + 3 : base_bit; + return scc_p ? base_bit + 3 : base_bit; case LE: case LEU: - return cc_mode == CCFPmode || scc_p ? base_bit + 3 : base_bit + 1; - - case UNEQ: case UNGT: case UNLT: case LTGT: - return base_bit + 3; + return scc_p ? base_bit + 3 : base_bit + 1; default: abort (); @@ -3710,40 +3753,11 @@ print_operand (file, x, code) /* %c is output_addr_const if a CONSTANT_ADDRESS_P, otherwise output_operand. */ - case 'C': - { - enum rtx_code code = GET_CODE (x); - - /* This is an optional cror needed for certain floating-point - comparisons. Otherwise write nothing. */ - if ((code == LE || code == GE - || code == UNEQ || code == LTGT - || code == UNGT || code == UNLT) - && GET_MODE (XEXP (x, 0)) == CCFPmode) - { - int base_bit = 4 * (REGNO (XEXP (x, 0)) - CR0_REGNO); - int bit0, bit1; - - if (code == UNEQ) - bit0 = 2; - else if (code == UNGT || code == GE) - bit0 = 1; - else - bit0 = 0; - if (code == LTGT) - bit1 = 1; - else if (code == LE || code == GE) - bit1 = 2; - else - bit1 = 3; - - fprintf (file, "cror %d,%d,%d\n\t", base_bit + 3, - base_bit + bit1, base_bit + bit0); - } - } - return; - case 'D': + /* There used to be a comment for 'C' reading "This is an + optional cror needed for certain floating-point + comparisons. Otherwise write nothing." */ + /* Similar, except that this is for an scc, so we must be able to encode the test in a single bit that is one. We do the above for any LE, GE, GEU, or LEU and invert the bit for NE. */ @@ -3767,11 +3781,11 @@ print_operand (file, x, code) return; case 'E': - /* X is a CR register. Print the number of the third bit of the CR */ + /* X is a CR register. Print the number of the EQ bit of the CR */ if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x))) output_operand_lossage ("invalid %%E value"); else - fprintf (file, "%d", 4 * (REGNO (x) - CR0_REGNO) + 3); + fprintf (file, "%d", 4 * (REGNO (x) - CR0_REGNO) + 2); return; case 'f': @@ -4013,7 +4027,9 @@ print_operand (file, x, code) case 'q': /* This outputs the logical code corresponding to a boolean expression. The expression may have one or both operands - negated (if one, only the first one). */ + negated (if one, only the first one). For condition register + logical operations, it will also treat the negated + CR codes as NOTs, but not handle NOTs of them. */ { const char *const *t = 0; const char *s; @@ -4420,6 +4436,129 @@ print_operand_address (file, x) abort (); } +enum rtx_code +rs6000_reverse_condition (mode, code) + enum machine_mode mode; + enum rtx_code code; +{ + /* Reversal of FP compares takes care -- an ordered compare + becomes an unordered compare and vice versa. */ + if (mode == CCFPmode) + code = reverse_condition_maybe_unordered (code); + else + code = reverse_condition (code); +} + + +/* Generate a compare for CODE. Return a brand-new rtx that + represents the result of the compare. */ +static rtx +rs6000_generate_compare (code) + enum rtx_code code; +{ + enum machine_mode comp_mode; + rtx compare_result; + + if (rs6000_compare_fp_p) + comp_mode = CCFPmode; + else if (code == GTU || code == LTU + || code == GEU || code == LEU) + comp_mode = CCUNSmode; + else + comp_mode = CCmode; + + /* First, the compare. */ + compare_result = gen_reg_rtx (comp_mode); + emit_insn (gen_rtx_SET (VOIDmode, compare_result, + gen_rtx_COMPARE (comp_mode, + rs6000_compare_op0, + rs6000_compare_op1))); + + /* Some kinds of FP comparisons need an OR operation. */ + if (rs6000_compare_fp_p + && (code == LE || code == GE + || code == UNEQ || code == LTGT + || code == UNGT || code == UNLT)) + { + enum rtx_code or1, or2; + rtx or1_rtx, or2_rtx, compare2_rtx; + rtx or_result = gen_reg_rtx (CCEQmode); + + switch (code) + { + case LE: or1 = LT; or2 = EQ; break; + case GE: or1 = GT; or2 = EQ; break; + case UNEQ: or1 = UNORDERED; or2 = EQ; break; + case LTGT: or1 = LT; or2 = GT; break; + case UNGT: or1 = UNORDERED; or2 = GT; break; + case UNLT: or1 = UNORDERED; or2 = LT; break; + default: abort (); + } + validate_condition_mode (or1, comp_mode); + validate_condition_mode (or2, comp_mode); + or1_rtx = gen_rtx (or1, SImode, compare_result, const0_rtx); + or2_rtx = gen_rtx (or2, SImode, compare_result, const0_rtx); + compare2_rtx = gen_rtx_COMPARE (CCEQmode, + gen_rtx_IOR (SImode, or1_rtx, or2_rtx), + const_true_rtx); + emit_insn (gen_rtx_SET (VOIDmode, or_result, compare2_rtx)); + + compare_result = or_result; + code = EQ; + } + + validate_condition_mode (code, GET_MODE (compare_result)); + + return gen_rtx (code, VOIDmode, compare_result, const0_rtx); +} + + +/* Emit the RTL for an sCOND pattern. */ + +void +rs6000_emit_sCOND (code, result) + enum rtx_code code; + rtx result; +{ + rtx condition_rtx; + enum machine_mode op_mode; + + condition_rtx = rs6000_generate_compare (code); + + op_mode = GET_MODE (rs6000_compare_op0); + if (op_mode == VOIDmode) + op_mode = GET_MODE (rs6000_compare_op1); + + if (TARGET_POWERPC64 && (op_mode == DImode || rs6000_compare_fp_p)) + { + PUT_MODE (condition_rtx, DImode); + convert_move (result, condition_rtx, 0); + } + else + { + PUT_MODE (condition_rtx, SImode); + emit_insn (gen_rtx_SET (VOIDmode, result, condition_rtx)); + } +} + + +/* Emit a branch of kind CODE to location LOC. */ + +void +rs6000_emit_cbranch (code, loc) + enum rtx_code code; + rtx loc; +{ + rtx condition_rtx, loc_ref; + + condition_rtx = rs6000_generate_compare (code); + loc_ref = gen_rtx_LABEL_REF (VOIDmode, loc); + emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, + gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx, + loc_ref, pc_rtx))); +} + + /* Return the string to output a conditional branch to LABEL, which is the operand number of the label, or -1 if the branch is really a conditional return. @@ -4444,52 +4583,22 @@ output_cbranch (op, label, reversed, insn) rtx cc_reg = XEXP (op, 0); enum machine_mode mode = GET_MODE (cc_reg); int cc_regno = REGNO (cc_reg) - CR0_REGNO; - int need_longbranch = label != NULL && get_attr_length (insn) == 12; + int need_longbranch = label != NULL && get_attr_length (insn) == 8; int really_reversed = reversed ^ need_longbranch; char *s = string; const char *ccode; const char *pred; rtx note; - /* Work out which way this really branches. */ + validate_condition_mode (code, mode); + + /* Work out which way this really branches. We could use + reverse_condition_maybe_unordered here always but this + makes the resulting assembler clearer. */ if (really_reversed) - { - /* Reversal of FP compares takes care -- an ordered compare - becomes an unordered compare and vice versa. */ - if (mode == CCFPmode) - code = reverse_condition_maybe_unordered (code); - else - code = reverse_condition (code); - } + code = rs6000_reverse_condition (mode, code); - /* If needed, print the CROR required for various floating-point - comparisons; and decide on the condition code to test. */ - if ((code == LE || code == GE - || code == UNEQ || code == LTGT - || code == UNGT || code == UNLT) - && mode == CCFPmode) - { - int base_bit = 4 * cc_regno; - int bit0, bit1; - - if (code == UNEQ) - bit0 = 2; - else if (code == UNGT || code == GE) - bit0 = 1; - else - bit0 = 0; - if (code == LTGT) - bit1 = 1; - else if (code == LE || code == GE) - bit1 = 2; - else - bit1 = 3; - - s += sprintf (s, "cror %d,%d,%d\n\t", base_bit + 3, - base_bit + bit1, base_bit + bit0); - ccode = "so"; - } - else switch (code) + switch (code) { /* Not all of these are actually distinct opcodes, but we distinguish them for clarity of the resulting assembler. */ diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index cb8795f..be10201 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -2275,18 +2275,19 @@ do { \ For the RS/6000, we need separate modes when unsigned (logical) comparisons are being done and we need a separate mode for floating-point. We also use a mode for the case when we are comparing the results of two - comparisons. */ + comparisons, as then only the EQ bit is valid in the register. */ #define EXTRA_CC_MODES \ CC(CCUNSmode, "CCUNS") \ CC(CCFPmode, "CCFP") \ CC(CCEQmode, "CCEQ") -/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE, - return the mode to be used for the comparison. For floating-point, CCFPmode - should be used. CCUNSmode should be used for unsigned comparisons. - CCEQmode should be used when we are doing an inequality comparison on - the result of a comparison. CCmode should be used in all other cases. */ +/* Given a comparison code (EQ, NE, etc.) and the first operand of a + COMPARE, return the mode to be used for the comparison. For + floating-point, CCFPmode should be used. CCUNSmode should be used + for unsigned comparisons. CCEQmode should be used when we are + doing an inequality comparison on the result of a + comparison. CCmode should be used in all other cases. */ #define SELECT_CC_MODE(OP,X,Y) \ (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT ? CCFPmode \ @@ -2720,54 +2721,57 @@ do { \ /* Define the codes that are matched by predicates in rs6000.c. */ -#define PREDICATE_CODES \ - {"short_cint_operand", {CONST_INT}}, \ - {"u_short_cint_operand", {CONST_INT}}, \ - {"non_short_cint_operand", {CONST_INT}}, \ - {"gpc_reg_operand", {SUBREG, REG}}, \ - {"cc_reg_operand", {SUBREG, REG}}, \ - {"cc_reg_not_cr0_operand", {SUBREG, REG}}, \ - {"reg_or_short_operand", {SUBREG, REG, CONST_INT}}, \ - {"reg_or_neg_short_operand", {SUBREG, REG, CONST_INT}}, \ - {"reg_or_u_short_operand", {SUBREG, REG, CONST_INT}}, \ - {"reg_or_cint_operand", {SUBREG, REG, CONST_INT}}, \ - {"reg_or_arith_cint_operand", {SUBREG, REG, CONST_INT}}, \ +#define PREDICATE_CODES \ + {"short_cint_operand", {CONST_INT}}, \ + {"u_short_cint_operand", {CONST_INT}}, \ + {"non_short_cint_operand", {CONST_INT}}, \ + {"gpc_reg_operand", {SUBREG, REG}}, \ + {"cc_reg_operand", {SUBREG, REG}}, \ + {"cc_reg_not_cr0_operand", {SUBREG, REG}}, \ + {"reg_or_short_operand", {SUBREG, REG, CONST_INT}}, \ + {"reg_or_neg_short_operand", {SUBREG, REG, CONST_INT}}, \ + {"reg_or_u_short_operand", {SUBREG, REG, CONST_INT}}, \ + {"reg_or_cint_operand", {SUBREG, REG, CONST_INT}}, \ + {"reg_or_arith_cint_operand", {SUBREG, REG, CONST_INT}}, \ {"reg_or_logical_cint_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}}, \ - {"got_operand", {SYMBOL_REF, CONST, LABEL_REF}}, \ - {"got_no_const_operand", {SYMBOL_REF, LABEL_REF}}, \ - {"easy_fp_constant", {CONST_DOUBLE}}, \ - {"reg_or_mem_operand", {SUBREG, MEM, REG}}, \ - {"lwa_operand", {SUBREG, MEM, REG}}, \ - {"volatile_mem_operand", {MEM}}, \ - {"offsettable_mem_operand", {MEM}}, \ - {"mem_or_easy_const_operand", {SUBREG, MEM, CONST_DOUBLE}}, \ - {"add_operand", {SUBREG, REG, CONST_INT}}, \ - {"non_add_cint_operand", {CONST_INT}}, \ - {"and_operand", {SUBREG, REG, CONST_INT}}, \ - {"and64_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}}, \ - {"logical_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}}, \ - {"non_logical_cint_operand", {CONST_INT, CONST_DOUBLE}}, \ - {"mask_operand", {CONST_INT}}, \ - {"mask64_operand", {CONST_INT, CONST_DOUBLE}}, \ - {"rldic_operand", {CONST_INT, CONST_DOUBLE}}, \ - {"count_register_operand", {REG}}, \ - {"xer_operand", {REG}}, \ - {"call_operand", {SYMBOL_REF, REG}}, \ - {"current_file_function_operand", {SYMBOL_REF}}, \ - {"input_operand", {SUBREG, MEM, REG, CONST_INT, \ - CONST_DOUBLE, SYMBOL_REF}}, \ - {"load_multiple_operation", {PARALLEL}}, \ - {"store_multiple_operation", {PARALLEL}}, \ - {"branch_comparison_operator", {EQ, NE, LE, LT, GE, \ - GT, LEU, LTU, GEU, GTU, \ - UNORDERED, ORDERED, \ - UNEQ, LTGT, \ - UNGE, UNGT, UNLE, UNLT}}, \ - {"scc_comparison_operator", {EQ, NE, LE, LT, GE, \ - GT, LEU, LTU, GEU, GTU}}, \ - {"trap_comparison_operator", {EQ, NE, LE, LT, GE, \ - GT, LEU, LTU, GEU, GTU}}, \ - {"boolean_operator", {AND, IOR, XOR}}, \ + {"got_operand", {SYMBOL_REF, CONST, LABEL_REF}}, \ + {"got_no_const_operand", {SYMBOL_REF, LABEL_REF}}, \ + {"easy_fp_constant", {CONST_DOUBLE}}, \ + {"reg_or_mem_operand", {SUBREG, MEM, REG}}, \ + {"lwa_operand", {SUBREG, MEM, REG}}, \ + {"volatile_mem_operand", {MEM}}, \ + {"offsettable_mem_operand", {MEM}}, \ + {"mem_or_easy_const_operand", {SUBREG, MEM, CONST_DOUBLE}}, \ + {"add_operand", {SUBREG, REG, CONST_INT}}, \ + {"non_add_cint_operand", {CONST_INT}}, \ + {"and_operand", {SUBREG, REG, CONST_INT}}, \ + {"and64_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}}, \ + {"logical_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}}, \ + {"non_logical_cint_operand", {CONST_INT, CONST_DOUBLE}}, \ + {"mask_operand", {CONST_INT}}, \ + {"mask64_operand", {CONST_INT, CONST_DOUBLE}}, \ + {"rldic_operand", {CONST_INT, CONST_DOUBLE}}, \ + {"count_register_operand", {REG}}, \ + {"xer_operand", {REG}}, \ + {"call_operand", {SYMBOL_REF, REG}}, \ + {"current_file_function_operand", {SYMBOL_REF}}, \ + {"input_operand", {SUBREG, MEM, REG, CONST_INT, \ + CONST_DOUBLE, SYMBOL_REF}}, \ + {"load_multiple_operation", {PARALLEL}}, \ + {"store_multiple_operation", {PARALLEL}}, \ + {"branch_comparison_operator", {EQ, NE, LE, LT, GE, \ + GT, LEU, LTU, GEU, GTU, \ + UNORDERED, ORDERED, \ + UNGE, UNLE }}, \ + {"branch_positive_comparison_operator", {EQ, LT, GT, LTU, GTU, \ + UNORDERED }}, \ + {"scc_comparison_operator", {EQ, NE, LE, LT, GE, \ + GT, LEU, LTU, GEU, GTU, \ + UNORDERED, ORDERED, \ + UNGE, UNLE }}, \ + {"trap_comparison_operator", {EQ, NE, LE, LT, GE, \ + GT, LEU, LTU, GEU, GTU}}, \ + {"boolean_operator", {AND, IOR, XOR}}, \ {"boolean_or_operator", {IOR, XOR}}, /* uncomment for disabling the corresponding default options */ diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 5ea5bc8..cabfd96 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -37,7 +37,7 @@ ;; Define an insn type attribute. This is used in function unit delay ;; computations. -(define_attr "type" "integer,load,store,fpload,fpstore,imul,lmul,idiv,ldiv,branch,compare,delayed_compare,fpcompare,mtjmpr,fp,dmul,sdiv,ddiv,ssqrt,dsqrt,jmpreg" +(define_attr "type" "integer,load,store,fpload,fpstore,imul,lmul,idiv,ldiv,branch,compare,cr_logical,delayed_compare,fpcompare,mtjmpr,fp,dmul,sdiv,ddiv,ssqrt,dsqrt,jmpreg" (const_string "integer")) ;; Length (in bytes). @@ -47,8 +47,8 @@ (const_int -32768)) (lt (minus (pc) (match_dup 0)) (const_int 32767))) - (const_int 8) - (const_int 12)) + (const_int 4) + (const_int 8)) (const_int 4))) ;; Processor type -- this attribute must exactly match the processor_type @@ -124,6 +124,11 @@ 1 1) (define_function_unit "iu" 1 0 + (and (eq_attr "type" "cr_logical") + (eq_attr "cpu" "rios1,rs64a,mpccore,ppc403,ppc601")) + 1 1) + +(define_function_unit "iu" 1 0 (and (eq_attr "type" "imul") (eq_attr "cpu" "ppc403")) 4 4) @@ -288,6 +293,15 @@ (eq_attr "cpu" "ppc750")) 19 19) +; CR-logical operations are execute-serialized, that is they don't +; start (and block the function unit) until all preceding operations +; have finished. They don't block dispatch of other insns, though. +; I've imitated this by giving them longer latency. +(define_function_unit "sru" 1 0 + (and (eq_attr "type" "cr_logical") + (eq_attr "cpu" "ppc603,ppc750")) + 3 2) + ; compare is done on integer unit, but feeds insns which ; execute on the branch unit. (define_function_unit "iu" 1 0 @@ -357,6 +371,17 @@ (eq_attr "cpu" "rs64a,mpccore,ppc403,ppc601,ppc603,ppc604,ppc604e,ppc620,ppc750")) 4 1) +(define_function_unit "bpu" 1 0 + (and (eq_attr "type" "cr_logical") + (eq_attr "cpu" "ppc604,ppc620")) + 4 1) + +(define_function_unit "cru" 1 0 + (and (eq_attr "type" "cr_logical") + (eq_attr "cpu" "ppc604e")) + 4 1) + + ; all jumps/branches are executing on the bpu, in 1 cycle, for all machines. (define_function_unit "bpu" 1 0 (eq_attr "type" "jmpreg") @@ -9847,270 +9872,94 @@ operands[2] = GEN_INT (INTVAL (operands[1]) >> 32); }") (define_expand "beq" - [(set (match_dup 2) (match_dup 1)) - (set (pc) - (if_then_else (eq (match_dup 2) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] + [(use (match_operand 0 "" ""))] "" - " -{ enum machine_mode mode = rs6000_compare_fp_p ? CCFPmode : CCmode; - operands[1] = gen_rtx_COMPARE (mode, - rs6000_compare_op0, rs6000_compare_op1); - operands[2] = gen_reg_rtx (mode); -}") + "{ rs6000_emit_cbranch (EQ, operands[0]); DONE; }") (define_expand "bne" - [(set (match_dup 2) (match_dup 1)) - (set (pc) - (if_then_else (ne (match_dup 2) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] + [(use (match_operand 0 "" ""))] "" - " -{ enum machine_mode mode = rs6000_compare_fp_p ? CCFPmode : CCmode; - operands[1] = gen_rtx_COMPARE (mode, - rs6000_compare_op0, rs6000_compare_op1); - operands[2] = gen_reg_rtx (mode); -}") + "{ rs6000_emit_cbranch (NE, operands[0]); DONE; }") -(define_expand "blt" - [(set (match_dup 2) (match_dup 1)) - (set (pc) - (if_then_else (lt (match_dup 2) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] +(define_expand "bge" + [(use (match_operand 0 "" ""))] "" - " -{ enum machine_mode mode = rs6000_compare_fp_p ? CCFPmode : CCmode; - operands[1] = gen_rtx_COMPARE (mode, - rs6000_compare_op0, rs6000_compare_op1); - operands[2] = gen_reg_rtx (mode); -}") + "{ rs6000_emit_cbranch (GE, operands[0]); DONE; }") (define_expand "bgt" - [(set (match_dup 2) (match_dup 1)) - (set (pc) - (if_then_else (gt (match_dup 2) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] + [(use (match_operand 0 "" ""))] "" - " -{ enum machine_mode mode = rs6000_compare_fp_p ? CCFPmode : CCmode; - operands[1] = gen_rtx_COMPARE (mode, - rs6000_compare_op0, rs6000_compare_op1); - operands[2] = gen_reg_rtx (mode); -}") + "{ rs6000_emit_cbranch (GT, operands[0]); DONE; }") (define_expand "ble" - [(set (match_dup 2) (match_dup 1)) - (set (pc) - (if_then_else (le (match_dup 2) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] + [(use (match_operand 0 "" ""))] "" - " -{ enum machine_mode mode = rs6000_compare_fp_p ? CCFPmode : CCmode; - operands[1] = gen_rtx_COMPARE (mode, - rs6000_compare_op0, rs6000_compare_op1); - operands[2] = gen_reg_rtx (mode); -}") + "{ rs6000_emit_cbranch (LE, operands[0]); DONE; }") -(define_expand "bge" - [(set (match_dup 2) (match_dup 1)) - (set (pc) - (if_then_else (ge (match_dup 2) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] +(define_expand "blt" + [(use (match_operand 0 "" ""))] "" - " -{ enum machine_mode mode = rs6000_compare_fp_p ? CCFPmode : CCmode; - operands[1] = gen_rtx_COMPARE (mode, - rs6000_compare_op0, rs6000_compare_op1); - operands[2] = gen_reg_rtx (mode); -}") + "{ rs6000_emit_cbranch (LT, operands[0]); DONE; }") -(define_expand "bgtu" - [(set (match_dup 2) (match_dup 1)) - (set (pc) - (if_then_else (gtu (match_dup 2) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] +(define_expand "bgeu" + [(use (match_operand 0 "" ""))] "" - " -{ operands[1] = gen_rtx_COMPARE (CCUNSmode, - rs6000_compare_op0, rs6000_compare_op1); - operands[2] = gen_reg_rtx (CCUNSmode); -}") + "{ rs6000_emit_cbranch (GEU, operands[0]); DONE; }") -(define_expand "bltu" - [(set (match_dup 2) (match_dup 1)) - (set (pc) - (if_then_else (ltu (match_dup 2) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] +(define_expand "bgtu" + [(use (match_operand 0 "" ""))] "" - " -{ operands[1] = gen_rtx_COMPARE (CCUNSmode, - rs6000_compare_op0, rs6000_compare_op1); - operands[2] = gen_reg_rtx (CCUNSmode); -}") + "{ rs6000_emit_cbranch (GTU, operands[0]); DONE; }") -(define_expand "bgeu" - [(set (match_dup 2) (match_dup 1)) - (set (pc) - (if_then_else (geu (match_dup 2) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] +(define_expand "bleu" + [(use (match_operand 0 "" ""))] "" - " -{ operands[1] = gen_rtx_COMPARE (CCUNSmode, - rs6000_compare_op0, rs6000_compare_op1); - operands[2] = gen_reg_rtx (CCUNSmode); -}") + "{ rs6000_emit_cbranch (LEU, operands[0]); DONE; }") -(define_expand "bleu" - [(set (match_dup 2) (match_dup 1)) - (set (pc) - (if_then_else (leu (match_dup 2) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] +(define_expand "bltu" + [(use (match_operand 0 "" ""))] "" - " -{ operands[1] = gen_rtx_COMPARE (CCUNSmode, - rs6000_compare_op0, rs6000_compare_op1); - operands[2] = gen_reg_rtx (CCUNSmode); -}") + "{ rs6000_emit_cbranch (LTU, operands[0]); DONE; }") (define_expand "bunordered" - [(set (match_dup 2) (match_dup 1)) - (set (pc) - (if_then_else (unordered (match_dup 2) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] + [(use (match_operand 0 "" ""))] "" - " -{ if (!rs6000_compare_fp_p) FAIL; - operands[1] = gen_rtx_COMPARE (CCFPmode, - rs6000_compare_op0, rs6000_compare_op1); - operands[2] = gen_reg_rtx (CCFPmode); -}") + "{ rs6000_emit_cbranch (UNORDERED, operands[0]); DONE; }") (define_expand "bordered" - [(set (match_dup 2) (match_dup 1)) - (set (pc) - (if_then_else (ordered (match_dup 2) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] + [(use (match_operand 0 "" ""))] "" - " -{ if (!rs6000_compare_fp_p) FAIL; - operands[1] = gen_rtx_COMPARE (CCFPmode, - rs6000_compare_op0, rs6000_compare_op1); - operands[2] = gen_reg_rtx (CCFPmode); -}") + "{ rs6000_emit_cbranch (ORDERED, operands[0]); DONE; }") (define_expand "buneq" - [(set (match_dup 2) (match_dup 1)) - (set (pc) - (if_then_else (uneq (match_dup 2) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] + [(use (match_operand 0 "" ""))] "" - " -{ if (!rs6000_compare_fp_p) FAIL; - operands[1] = gen_rtx_COMPARE (CCFPmode, - rs6000_compare_op0, rs6000_compare_op1); - operands[2] = gen_reg_rtx (CCFPmode); -}") + "{ rs6000_emit_cbranch (UNEQ, operands[0]); DONE; }") (define_expand "bunge" - [(set (match_dup 2) (match_dup 1)) - (set (pc) - (if_then_else (unge (match_dup 2) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] + [(use (match_operand 0 "" ""))] "" - " -{ if (!rs6000_compare_fp_p) FAIL; - operands[1] = gen_rtx_COMPARE (CCFPmode, - rs6000_compare_op0, rs6000_compare_op1); - operands[2] = gen_reg_rtx (CCFPmode); -}") + "{ rs6000_emit_cbranch (UNGE, operands[0]); DONE; }") (define_expand "bungt" - [(set (match_dup 2) (match_dup 1)) - (set (pc) - (if_then_else (ungt (match_dup 2) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] + [(use (match_operand 0 "" ""))] "" - " -{ if (!rs6000_compare_fp_p) FAIL; - operands[1] = gen_rtx_COMPARE (CCFPmode, - rs6000_compare_op0, rs6000_compare_op1); - operands[2] = gen_reg_rtx (CCFPmode); -}") + "{ rs6000_emit_cbranch (UNGT, operands[0]); DONE; }") (define_expand "bunle" - [(set (match_dup 2) (match_dup 1)) - (set (pc) - (if_then_else (unle (match_dup 2) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] + [(use (match_operand 0 "" ""))] "" - " -{ if (!rs6000_compare_fp_p) FAIL; - operands[1] = gen_rtx_COMPARE (CCFPmode, - rs6000_compare_op0, rs6000_compare_op1); - operands[2] = gen_reg_rtx (CCFPmode); -}") + "{ rs6000_emit_cbranch (UNLE, operands[0]); DONE; }") (define_expand "bunlt" - [(set (match_dup 2) (match_dup 1)) - (set (pc) - (if_then_else (unlt (match_dup 2) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] + [(use (match_operand 0 "" ""))] "" - " -{ if (!rs6000_compare_fp_p) FAIL; - operands[1] = gen_rtx_COMPARE (CCFPmode, - rs6000_compare_op0, rs6000_compare_op1); - operands[2] = gen_reg_rtx (CCFPmode); -}") + "{ rs6000_emit_cbranch (UNLT, operands[0]); DONE; }") (define_expand "bltgt" - [(set (match_dup 2) (match_dup 1)) - (set (pc) - (if_then_else (ltgt (match_dup 2) - (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] + [(use (match_operand 0 "" ""))] "" - " -{ if (!rs6000_compare_fp_p) FAIL; - operands[1] = gen_rtx_COMPARE (CCFPmode, - rs6000_compare_op0, rs6000_compare_op1); - operands[2] = gen_reg_rtx (CCFPmode); -}") + "{ rs6000_emit_cbranch (LTGT, operands[0]); DONE; }") ;; For SNE, we would prefer that the xor/abs sequence be used for integers. ;; For SEQ, likewise, except that comparisons with zero should be done @@ -10118,261 +9967,85 @@ operands[2] = GEN_INT (INTVAL (operands[1]) >> 32); ;; resulting insns, we must, in fact, allow SEQ for integers. Fail in ;; the cases we don't want to handle. (define_expand "seq" - [(set (match_dup 2) (match_dup 1)) - (set (match_operand:SI 0 "gpc_reg_operand" "") - (eq:SI (match_dup 2) (const_int 0)))] + [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))] "" - " -{ enum machine_mode op_mode, mode = rs6000_compare_fp_p ? CCFPmode : CCmode; - operands[1] = gen_rtx_COMPARE (mode, - rs6000_compare_op0, rs6000_compare_op1); - operands[2] = gen_reg_rtx (mode); - - op_mode = GET_MODE (rs6000_compare_op0); - if (op_mode == VOIDmode) - op_mode = GET_MODE (rs6000_compare_op1); - - if (TARGET_POWERPC64 && (op_mode == DImode || rs6000_compare_fp_p)) - { - emit_insn (gen_rtx_SET (VOIDmode, operands[2], operands[1])); - convert_move (operands[0], - gen_rtx_EQ (DImode, operands[2], const0_rtx), 0); - DONE; - } -}") + "{ rs6000_emit_sCOND (EQ, operands[0]); DONE; }") (define_expand "sne" - [(set (match_dup 2) (match_dup 1)) - (set (match_operand:SI 0 "gpc_reg_operand" "") - (ne:SI (match_dup 2) (const_int 0)))] + [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))] "" " -{ if (! rs6000_compare_fp_p) +{ + if (! rs6000_compare_fp_p) FAIL; - operands[1] = gen_rtx_COMPARE (CCFPmode, - rs6000_compare_op0, rs6000_compare_op1); - operands[2] = gen_reg_rtx (CCFPmode); - - if (TARGET_POWERPC64) - { - emit_insn (gen_rtx_SET (VOIDmode, operands[2], operands[1])); - convert_move (operands[0], - gen_rtx_NE (DImode, operands[2], const0_rtx), 0); - DONE; - } + rs6000_emit_sCOND (NE, operands[0]); + DONE; }") ;; A > 0 is best done using the portable sequence, so fail in that case. (define_expand "sgt" - [(set (match_dup 2) (match_dup 1)) - (set (match_operand:SI 0 "gpc_reg_operand" "") - (gt:SI (match_dup 2) (const_int 0)))] + [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))] "" " -{ enum machine_mode op_mode, mode = rs6000_compare_fp_p ? CCFPmode : CCmode; - +{ if (! rs6000_compare_fp_p && rs6000_compare_op1 == const0_rtx) FAIL; - operands[1] = gen_rtx_COMPARE (mode, - rs6000_compare_op0, rs6000_compare_op1); - operands[2] = gen_reg_rtx (mode); - - op_mode = GET_MODE (rs6000_compare_op0); - if (op_mode == VOIDmode) - op_mode = GET_MODE (rs6000_compare_op1); - - if (TARGET_POWERPC64 && (op_mode == DImode || rs6000_compare_fp_p)) - { - emit_insn (gen_rtx_SET (VOIDmode, operands[2], operands[1])); - convert_move (operands[0], - gen_rtx_GT (DImode, operands[2], const0_rtx), 0); - DONE; - } + rs6000_emit_sCOND (GT, operands[0]); + DONE; }") ;; A < 0 is best done in the portable way for A an integer. (define_expand "slt" - [(set (match_dup 2) (match_dup 1)) - (set (match_operand:SI 0 "gpc_reg_operand" "") - (lt:SI (match_dup 2) (const_int 0)))] + [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))] "" " -{ enum machine_mode op_mode, mode = rs6000_compare_fp_p ? CCFPmode : CCmode; - +{ if (! rs6000_compare_fp_p && rs6000_compare_op1 == const0_rtx) FAIL; - operands[1] = gen_rtx_COMPARE (mode, - rs6000_compare_op0, rs6000_compare_op1); - operands[2] = gen_reg_rtx (mode); - - op_mode = GET_MODE (rs6000_compare_op0); - if (op_mode == VOIDmode) - op_mode = GET_MODE (rs6000_compare_op1); - - if (TARGET_POWERPC64 && (op_mode == DImode || rs6000_compare_fp_p)) - { - emit_insn (gen_rtx_SET (VOIDmode, operands[2], operands[1])); - convert_move (operands[0], - gen_rtx_LT (DImode, operands[2], const0_rtx), 0); - DONE; - } + rs6000_emit_sCOND (LT, operands[0]); + DONE; }") (define_expand "sge" - [(set (match_dup 2) (match_dup 1)) - (set (match_operand:SI 0 "gpc_reg_operand" "") - (ge:SI (match_dup 2) (const_int 0)))] + [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))] "" - " -{ enum machine_mode op_mode, mode = rs6000_compare_fp_p ? CCFPmode : CCmode; - operands[1] = gen_rtx_COMPARE (mode, - rs6000_compare_op0, rs6000_compare_op1); - operands[2] = gen_reg_rtx (mode); - - op_mode = GET_MODE (rs6000_compare_op0); - if (op_mode == VOIDmode) - op_mode = GET_MODE (rs6000_compare_op1); - - if (TARGET_POWERPC64 && (op_mode == DImode || rs6000_compare_fp_p)) - { - emit_insn (gen_rtx_SET (VOIDmode, operands[2], operands[1])); - convert_move (operands[0], - gen_rtx_GE (DImode, operands[2], const0_rtx), 0); - DONE; - } -}") + "{ rs6000_emit_sCOND (GE, operands[0]); DONE; }") ;; A <= 0 is best done the portable way for A an integer. (define_expand "sle" - [(set (match_dup 2) (match_dup 1)) - (set (match_operand:SI 0 "gpc_reg_operand" "") - (le:SI (match_dup 2) (const_int 0)))] + [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))] "" " -{ enum machine_mode op_mode, mode = rs6000_compare_fp_p ? CCFPmode : CCmode; - +{ if (! rs6000_compare_fp_p && rs6000_compare_op1 == const0_rtx) FAIL; - operands[1] = gen_rtx_COMPARE (mode, - rs6000_compare_op0, rs6000_compare_op1); - operands[2] = gen_reg_rtx (mode); - - op_mode = GET_MODE (rs6000_compare_op0); - if (op_mode == VOIDmode) - op_mode = GET_MODE (rs6000_compare_op1); - - if (TARGET_POWERPC64 && (op_mode == DImode || rs6000_compare_fp_p)) - { - emit_insn (gen_rtx_SET (VOIDmode, operands[2], operands[1])); - convert_move (operands[0], - gen_rtx_LE (DImode, operands[2], const0_rtx), 0); - DONE; - } + rs6000_emit_sCOND (LE, operands[0]); + DONE; }") (define_expand "sgtu" - [(set (match_dup 2) (match_dup 1)) - (set (match_operand:SI 0 "gpc_reg_operand" "") - (gtu:SI (match_dup 2) (const_int 0)))] + [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))] "" - " -{ enum machine_mode op_mode; - - operands[1] = gen_rtx_COMPARE (CCUNSmode, - rs6000_compare_op0, rs6000_compare_op1); - operands[2] = gen_reg_rtx (CCUNSmode); - - op_mode = GET_MODE (rs6000_compare_op0); - if (op_mode == VOIDmode) - op_mode = GET_MODE (rs6000_compare_op1); - - if (TARGET_POWERPC64 && op_mode == DImode) - { - emit_insn (gen_rtx_SET (VOIDmode, operands[2], operands[1])); - convert_move (operands[0], - gen_rtx_GTU (DImode, operands[2], const0_rtx), 0); - DONE; - } -}") + "{ rs6000_emit_sCOND (GTU, operands[0]); DONE; }") (define_expand "sltu" - [(set (match_dup 2) (match_dup 1)) - (set (match_operand:SI 0 "gpc_reg_operand" "") - (ltu:SI (match_dup 2) (const_int 0)))] + [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))] "" - " -{ enum machine_mode op_mode; - - operands[1] = gen_rtx_COMPARE (CCUNSmode, - rs6000_compare_op0, rs6000_compare_op1); - operands[2] = gen_reg_rtx (CCUNSmode); - - op_mode = GET_MODE (rs6000_compare_op0); - if (op_mode == VOIDmode) - op_mode = GET_MODE (rs6000_compare_op1); - - if (TARGET_POWERPC64 && op_mode == DImode) - { - emit_insn (gen_rtx_SET (VOIDmode, operands[2], operands[1])); - convert_move (operands[0], - gen_rtx_LTU (DImode, operands[2], const0_rtx), 0); - DONE; - } -}") + "{ rs6000_emit_sCOND (LTU, operands[0]); DONE; }") (define_expand "sgeu" - [(set (match_dup 2) (match_dup 1)) - (set (match_operand:SI 0 "gpc_reg_operand" "") - (geu:SI (match_dup 2) (const_int 0)))] + [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))] "" - " -{ enum machine_mode op_mode; - - operands[1] = gen_rtx_COMPARE (CCUNSmode, - rs6000_compare_op0, rs6000_compare_op1); - operands[2] = gen_reg_rtx (CCUNSmode); - - op_mode = GET_MODE (rs6000_compare_op0); - if (op_mode == VOIDmode) - op_mode = GET_MODE (rs6000_compare_op1); - - if (TARGET_POWERPC64 && op_mode == DImode) - { - emit_insn (gen_rtx_SET (VOIDmode, operands[2], operands[1])); - convert_move (operands[0], - gen_rtx_GEU (DImode, operands[2], const0_rtx), 0); - DONE; - } -}") + "{ rs6000_emit_sCOND (GEU, operands[0]); DONE; }") (define_expand "sleu" - [(set (match_dup 2) (match_dup 1)) - (set (match_operand:SI 0 "gpc_reg_operand" "") - (leu:SI (match_dup 2) (const_int 0)))] + [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))] "" - " -{ enum machine_mode op_mode; - - operands[1] = gen_rtx_COMPARE (CCUNSmode, - rs6000_compare_op0, rs6000_compare_op1); - operands[2] = gen_reg_rtx (CCUNSmode); - - op_mode = GET_MODE (rs6000_compare_op0); - if (op_mode == VOIDmode) - op_mode = GET_MODE (rs6000_compare_op1); - - if (TARGET_POWERPC64 && op_mode == DImode) - { - emit_insn (gen_rtx_SET (VOIDmode, operands[2], operands[1])); - convert_move (operands[0], - gen_rtx_LEU (DImode, operands[2], const0_rtx), 0); - DONE; - } -}") + "{ rs6000_emit_sCOND (LEU, operands[0]); DONE; }") ;; Here are the actual compare insns. (define_insn "*cmpsi_internal1" @@ -10632,38 +10305,6 @@ operands[2] = GEN_INT (INTVAL (operands[1]) >> 32); (const_int 0)))] "") -;; If we are comparing the result of two comparisons, this can be done -;; using creqv or crxor. - -(define_insn "" - [(set (match_operand:CCEQ 0 "cc_reg_operand" "=y") - (compare:CCEQ (match_operator 1 "scc_comparison_operator" - [(match_operand 2 "cc_reg_operand" "y") - (const_int 0)]) - (match_operator 3 "scc_comparison_operator" - [(match_operand 4 "cc_reg_operand" "y") - (const_int 0)])))] - "REGNO (operands[2]) != REGNO (operands[4])" - "* -{ - enum rtx_code code1, code2; - - code1 = GET_CODE (operands[1]); - code2 = GET_CODE (operands[3]); - - if ((code1 == EQ || code1 == LT || code1 == GT - || code1 == LTU || code1 == GTU - || (code1 != NE && GET_MODE (operands[2]) == CCFPmode)) - != - (code2 == EQ || code2 == LT || code2 == GT - || code2 == LTU || code2 == GTU - || (code2 != NE && GET_MODE (operands[4]) == CCFPmode))) - return \"%C1%C3crxor %E0,%j1,%j3\"; - else - return \"%C1%C3creqv %E0,%j1,%j3\"; -}" - [(set_attr "length" "12")]) - ;; There is a 3 cycle delay between consecutive mfcr instructions ;; so it is useful to combine 2 scc instructions to use only one mfcr. @@ -13153,7 +12794,7 @@ operands[2] = GEN_INT (INTVAL (operands[1]) >> 32); return output_cbranch (operands[0], NULL, 0, insn); }" [(set_attr "type" "branch") - (set_attr "length" "8")]) + (set_attr "length" "4")]) (define_insn "" [(set (pc) @@ -13184,7 +12825,112 @@ operands[2] = GEN_INT (INTVAL (operands[1]) >> 32); return output_cbranch (operands[0], NULL, 1, insn); }" [(set_attr "type" "branch") - (set_attr "length" "8")]) + (set_attr "length" "4")]) + +;; Logic on condition register values. + +; This pattern matches things like +; (set (reg:CCEQ 68) (compare:CCEQ (ior:SI (gt:SI (reg:CCFP 68) (const_int 0)) +; (eq:SI (reg:CCFP 68) (const_int 0))) +; (const_int 1))) +; which are generated by the branch logic. + +(define_insn "" + [(set (match_operand:CCEQ 0 "cc_reg_operand" "=y") + (compare:CCEQ (match_operator:SI 1 "boolean_operator" + [(match_operator:SI 2 + "branch_positive_comparison_operator" + [(match_operand 3 + "cc_reg_operand" "y") + (const_int 0)]) + (match_operator:SI 4 + "branch_positive_comparison_operator" + [(match_operand 5 + "cc_reg_operand" "y") + (const_int 0)])]) + (const_int 1)))] + "" + "cr%q1 %E0,%j2,%j4" + [(set_attr "type" "cr_logical")]) + +; Why is the constant -1 here, but 1 in the previous pattern? +; Because ~1 has all but the low bit set. +(define_insn "" + [(set (match_operand:CCEQ 0 "cc_reg_operand" "=y") + (compare:CCEQ (match_operator:SI 1 "boolean_or_operator" + [(not:SI (match_operator:SI 2 + "branch_positive_comparison_operator" + [(match_operand 3 + "cc_reg_operand" "y") + (const_int 0)])) + (match_operator:SI 4 + "branch_positive_comparison_operator" + [(match_operand 5 + "cc_reg_operand" "y") + (const_int 0)])]) + (const_int -1)))] + "" + "cr%q1 %E0,%j2,%j4" + [(set_attr "type" "cr_logical")]) + +(define_insn "" + [(set (match_operand:CCEQ 0 "cc_reg_operand" "=y") + (compare:CCEQ (match_operator:SI 2 + "branch_positive_comparison_operator" + [(match_operand 3 + "cc_reg_operand" "y") + (const_int 0)]) + (const_int 0)))] + "" + "crnot %E0,%j2" + [(set_attr "type" "cr_logical")]) + +;; If we are comparing the result of two comparisons, this can be done +;; using creqv or crxor. + +(define_insn_and_split "" + [(set (match_operand:CCEQ 0 "cc_reg_operand" "=y") + (compare:CCEQ (match_operator 1 "branch_comparison_operator" + [(match_operand 2 "cc_reg_operand" "y") + (const_int 0)]) + (match_operator 3 "branch_comparison_operator" + [(match_operand 4 "cc_reg_operand" "y") + (const_int 0)])))] + "" + "#" + "" + [(set (match_dup 0) (compare:CCEQ (xor:SI (match_dup 1) (match_dup 3)) + (match_dup 5)))] + " +{ + int positive_1, positive_2; + + positive_1 = branch_positive_comparison_operator (operands[1], CCEQmode); + positive_2 = branch_positive_comparison_operator (operands[3], CCEQmode); + + if (! positive_1) + operands[1] = gen_rtx (SImode, + rs6000_reverse_condition (GET_MODE (operands[2]), + GET_CODE (operands[1])), + operands[2]); + else if (GET_MODE (operands[1]) != SImode) + operands[1] = gen_rtx (SImode, + GET_CODE (operands[1]), + operands[2]); + + if (! positive_2) + operands[3] = gen_rtx (SImode, + rs6000_reverse_condition (GET_MODE (operands[4]), + GET_CODE (operands[3])), + operands[4]); + else if (GET_MODE (operands[3]) != SImode) + operands[3] = gen_rtx (SImode, + GET_CODE (operands[3]), + operands[4]); + + if (positive_1 == positive_2) + operands[1] = gen_rtx_NOT (SImode, operands[1]); +}") ;; Unconditional branch and return. |