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:
parent
6e92b232be
commit
39a10a297a
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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. */
|
||||
|
@ -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 */
|
||||
|
@ -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.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user