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
This commit is contained in:
Geoff Keating 2000-09-06 09:12:51 +00:00 committed by Geoffrey Keating
parent 6e92b232be
commit 39a10a297a
5 changed files with 521 additions and 624 deletions

View File

@ -1,3 +1,35 @@
2000-09-06 Geoff Keating <geoffk@cygnus.com>
* 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.
2000-09-06 Richard Henderson <rth@cygnus.com>
* config/i386/i386.md (call_pop): Fix test for setting

View File

@ -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));

View File

@ -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;
if ((code == GTU || code == LTU || code == GEU || code == LEU)
&& (cc_mode != CCUNSmode))
return 0;
validate_condition_mode (code, cc_mode);
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;
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,20 +3323,11 @@ scc_comparison_operator (op, mode)
if (GET_MODE_CLASS (cc_mode) != MODE_CC)
return 0;
validate_condition_mode (code, cc_mode);
if (code == NE && cc_mode != CCFPmode)
return 0;
if ((code == GT || code == LT || code == GE || code == LE)
&& cc_mode == CCUNSmode)
return 0;
if ((code == GTU || code == LTU || code == GEU || code == LEU)
&& (cc_mode != CCUNSmode))
return 0;
if (cc_mode == CCEQmode && code != EQ && code != NE)
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. */
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);
}
validate_condition_mode (code, mode);
/* 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)
/* 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)
code = rs6000_reverse_condition (mode, code);
switch (code)
{
/* Not all of these are actually distinct opcodes, but
we distinguish them for clarity of the resulting assembler. */

View File

@ -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 */

View File

@ -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
@ -123,6 +123,11 @@
(eq_attr "cpu" "rios1,rs64a,mpccore,ppc403,ppc601,ppc603"))
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"))
@ -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);
}")
(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)))]
""
"
{ 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);
}")
(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)))]
""
"
{ 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);
}")
(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)))]
""
"
{ 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 "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)))]
[(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 "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 "bgt"
[(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 (GT, 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 "ble"
[(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 (LE, operands[0]); DONE; }")
(define_expand "blt"
[(use (match_operand 0 "" ""))]
""
"{ rs6000_emit_cbranch (LT, 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)))]
[(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 "bgtu"
[(use (match_operand 0 "" ""))]
""
"{ rs6000_emit_cbranch (GTU, 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)))]
[(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 "bltu"
[(use (match_operand 0 "" ""))]
""
"{ 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.