aboutsummaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
authorGeoff Keating <geoffk@cygnus.com>2000-09-06 09:12:51 +0000
committerGeoffrey Keating <geoffk@gcc.gnu.org>2000-09-06 09:12:51 +0000
commit39a10a297a95e994e1aeb66d43c75fc1b2a15d7f (patch)
treeb7cc73d2c5daab569be640d46abbcb472c5b15ea /gcc/config
parent6e92b232be51d39eb147f167119a493785a2e98b (diff)
downloadgcc-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.h6
-rw-r--r--gcc/config/rs6000/rs6000.c317
-rw-r--r--gcc/config/rs6000/rs6000.h110
-rw-r--r--gcc/config/rs6000/rs6000.md666
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.