Commit a8c1d5f8 by Richard Sandiford Committed by Richard Sandiford

mips-protos.h (mips_output_conditional_branch): Change interface.

	* config/mips/mips-protos.h (mips_output_conditional_branch): Change
	interface.
	(mips_output_order_conditional_branch): Declare.
	* config/mips/mips.h (MIPS_BRANCH): New macro.
	* config/mips/mips.c (gen_conditional_branch): Use VOIDmode
	for the comparison.  Use gen_condjump.
	(mips_output_conditional_branch): Rework interface to take the
	asm templates for a direct branch and the inverse of a direct branch.
	(mips_output_order_conditional_branch): New function.
	(mips_builtin_branch_and_move): New function.
	(mips_expand_builtin_compare): Use it.  Use VOIDmode for the
	branch condition.  Use gen_single_cc as the condition for
	__builtin_mips_upper_* or __builtin_mips_lower_*.
	(mips_expand_builtin_bposge): Use mips_builtin_branch_and_move.
	Use VOIDmode for the branch condition.
	* config/mips/predicates.md (order_operator): New predicate.
	* config/mips/mips.md (UNSPEC_SINGLE_CC): New constant.
	(branch_fp): Rename to...
	(*branch_fp): ...this.  Remove mode from comparison operator.
	Use new mips_output_conditional_branch interface.
	(branch_fp_inverted): Rename to...
	(*branch_fp_inverted): ...this and update as for *branch_fp.
	(*branch_zero<mode>): Rename to...
	(*branch_order<mode>): ...this.  Remove mode from comparison operator.
	Use mips_output_order_conditional_branch.  Only accept ordered
	comparisons.  
	(*branch_zero<mode>_inverted): Rename to...
	(*branch_order<mode>_inverted): ...this and update as for
	*branch_order<mode>.
	(*branch_equality<mode>): Accept zero as the second operand to
	the equality operator.  Use the new mips_output_conditional_branch
	interface.
	(*branch_equality<mode>_inverted): Likewise.
	(condjump): New expander.
	* config/mips/mips-dsp.md (mips_bposge): Remove mode from comparison
	operator.
	* config/mips/mips-ps-3d.md (bc1any4t, bc1any4f): Likewise.
	(bc1any2t, bc1any2f): Likewise.
	(single_cc): New expander.
	(*branch_upper_lower, *branch_upper_lower_inverted): New patterns.

From-SVN: r111909
parent 1fea4e6c
2006-03-09 Richard Sandiford <richard@codesourcery.com>
* config/mips/mips-protos.h (mips_output_conditional_branch): Change
interface.
(mips_output_order_conditional_branch): Declare.
* config/mips/mips.h (MIPS_BRANCH): New macro.
* config/mips/mips.c (gen_conditional_branch): Use VOIDmode
for the comparison. Use gen_condjump.
(mips_output_conditional_branch): Rework interface to take the
asm templates for a direct branch and the inverse of a direct branch.
(mips_output_order_conditional_branch): New function.
(mips_builtin_branch_and_move): New function.
(mips_expand_builtin_compare): Use it. Use VOIDmode for the
branch condition. Use gen_single_cc as the condition for
__builtin_mips_upper_* or __builtin_mips_lower_*.
(mips_expand_builtin_bposge): Use mips_builtin_branch_and_move.
Use VOIDmode for the branch condition.
* config/mips/predicates.md (order_operator): New predicate.
* config/mips/mips.md (UNSPEC_SINGLE_CC): New constant.
(branch_fp): Rename to...
(*branch_fp): ...this. Remove mode from comparison operator.
Use new mips_output_conditional_branch interface.
(branch_fp_inverted): Rename to...
(*branch_fp_inverted): ...this and update as for *branch_fp.
(*branch_zero<mode>): Rename to...
(*branch_order<mode>): ...this. Remove mode from comparison operator.
Use mips_output_order_conditional_branch. Only accept ordered
comparisons.
(*branch_zero<mode>_inverted): Rename to...
(*branch_order<mode>_inverted): ...this and update as for
*branch_order<mode>.
(*branch_equality<mode>): Accept zero as the second operand to
the equality operator. Use the new mips_output_conditional_branch
interface.
(*branch_equality<mode>_inverted): Likewise.
(condjump): New expander.
* config/mips/mips-dsp.md (mips_bposge): Remove mode from comparison
operator.
* config/mips/mips-ps-3d.md (bc1any4t, bc1any4f): Likewise.
(bc1any2t, bc1any2f): Likewise.
(single_cc): New expander.
(*branch_upper_lower, *branch_upper_lower_inverted): New patterns.
2006-03-09 Richard Sandiford <richard@codesourcery.com>
* doc/md.texi: Update documentation of MIPS constraints.
* config/mips/constraints.md: New file.
* config/mips/mips.md: Include it.
......
......@@ -1046,11 +1046,10 @@
;; BPOSGE32
(define_insn "mips_bposge"
[(set (pc)
(if_then_else
(ge:CCDSP (reg:CCDSP CCDSP_PO_REGNUM)
(match_operand:SI 0 "immediate_operand" "I"))
(label_ref (match_operand 1 "" ""))
(pc)))]
(if_then_else (ge (reg:CCDSP CCDSP_PO_REGNUM)
(match_operand:SI 0 "immediate_operand" "I"))
(label_ref (match_operand 1 "" ""))
(pc)))]
"TARGET_DSP"
"%*bposge%0\t%1%/"
[(set_attr "type" "branch")
......
......@@ -212,8 +212,9 @@ extern int mips_register_move_cost (enum machine_mode, enum reg_class,
extern int mips_adjust_insn_length (rtx, int);
extern const char *mips_output_load_label (void);
extern const char *mips_output_conditional_branch (rtx, rtx *, int, int,
int, int);
extern const char *mips_output_conditional_branch (rtx, rtx *, const char *,
const char *);
extern const char *mips_output_order_conditional_branch (rtx, rtx *, bool);
extern const char *mips_output_division (const char *, rtx *);
extern unsigned int mips_hard_regno_nregs (int, enum machine_mode);
extern bool mips_linked_madd_p (rtx, rtx);
......
......@@ -389,8 +389,8 @@
; Branch on Any of Four Floating Point Condition Codes True
(define_insn "bc1any4t"
[(set (pc)
(if_then_else (ne:CCV4 (match_operand:CCV4 0 "register_operand" "z")
(const_int 0))
(if_then_else (ne (match_operand:CCV4 0 "register_operand" "z")
(const_int 0))
(label_ref (match_operand 1 "" ""))
(pc)))]
"TARGET_MIPS3D"
......@@ -401,8 +401,8 @@
; Branch on Any of Four Floating Point Condition Codes False
(define_insn "bc1any4f"
[(set (pc)
(if_then_else (ne:CCV4 (match_operand:CCV4 0 "register_operand" "z")
(const_int -1))
(if_then_else (ne (match_operand:CCV4 0 "register_operand" "z")
(const_int -1))
(label_ref (match_operand 1 "" ""))
(pc)))]
"TARGET_MIPS3D"
......@@ -413,8 +413,8 @@
; Branch on Any of Two Floating Point Condition Codes True
(define_insn "bc1any2t"
[(set (pc)
(if_then_else (ne:CCV2 (match_operand:CCV2 0 "register_operand" "z")
(const_int 0))
(if_then_else (ne (match_operand:CCV2 0 "register_operand" "z")
(const_int 0))
(label_ref (match_operand 1 "" ""))
(pc)))]
"TARGET_MIPS3D"
......@@ -425,8 +425,8 @@
; Branch on Any of Two Floating Point Condition Codes False
(define_insn "bc1any2f"
[(set (pc)
(if_then_else (ne:CCV2 (match_operand:CCV2 0 "register_operand" "z")
(const_int -1))
(if_then_else (ne (match_operand:CCV2 0 "register_operand" "z")
(const_int -1))
(label_ref (match_operand 1 "" ""))
(pc)))]
"TARGET_MIPS3D"
......@@ -434,6 +434,59 @@
[(set_attr "type" "branch")
(set_attr "mode" "none")])
; Used to access one register in a CCV2 pair. Operand 0 is the register
; pair and operand 1 is the index of the register we want (a CONST_INT).
(define_expand "single_cc"
[(ne (unspec:CC [(match_operand 0) (match_operand 1)] UNSPEC_SINGLE_CC)
(const_int 0))])
; This is a normal floating-point branch pattern, but rather than check
; a single CCmode register, it checks one register in a CCV2 pair.
; Operand 2 is the register pair and operand 3 is the index of the
; register we want.
(define_insn "*branch_upper_lower"
[(set (pc)
(if_then_else
(match_operator 0 "equality_operator"
[(unspec:CC [(match_operand:CCV2 2 "register_operand" "z")
(match_operand 3 "const_int_operand")]
UNSPEC_SINGLE_CC)
(const_int 0)])
(label_ref (match_operand 1 "" ""))
(pc)))]
"TARGET_HARD_FLOAT"
{
operands[2]
= gen_rtx_REG (CCmode, REGNO (operands[2]) + INTVAL (operands[3]));
return mips_output_conditional_branch (insn, operands,
MIPS_BRANCH ("b%F0", "%2,%1"),
MIPS_BRANCH ("b%W0", "%2,%1"));
}
[(set_attr "type" "branch")
(set_attr "mode" "none")])
; As above, but with the sense of the condition reversed.
(define_insn "*branch_upper_lower_inverted"
[(set (pc)
(if_then_else
(match_operator 0 "equality_operator"
[(unspec:CC [(match_operand:CCV2 2 "register_operand" "z")
(match_operand 3 "const_int_operand")]
UNSPEC_SINGLE_CC)
(const_int 0)])
(pc)
(label_ref (match_operand 1 "" ""))))]
"TARGET_HARD_FLOAT"
{
operands[2]
= gen_rtx_REG (CCmode, REGNO (operands[2]) + INTVAL (operands[3]));
return mips_output_conditional_branch (insn, operands,
MIPS_BRANCH ("b%W0", "%2,%1"),
MIPS_BRANCH ("b%F0", "%2,%1"));
}
[(set_attr "type" "branch")
(set_attr "mode" "none")])
;----------------------------------------------------------------------------
; Floating Point Reduced Precision Reciprocal Square Root Instructions.
;----------------------------------------------------------------------------
......
......@@ -3186,15 +3186,11 @@ mips_emit_scc (enum rtx_code code, rtx target)
void
gen_conditional_branch (rtx *operands, enum rtx_code code)
{
rtx op0, op1, target;
rtx op0, op1, condition;
mips_emit_compare (&code, &op0, &op1, TARGET_MIPS16);
target = gen_rtx_IF_THEN_ELSE (VOIDmode,
gen_rtx_fmt_ee (code, GET_MODE (op0),
op0, op1),
gen_rtx_LABEL_REF (VOIDmode, operands[0]),
pc_rtx);
emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, target));
condition = gen_rtx_fmt_ee (code, VOIDmode, op0, op1);
emit_jump_insn (gen_condjump (condition, operands[0]));
}
/* Emit the common code for conditional moves. OPERANDS is the array
......@@ -9127,217 +9123,126 @@ mips_output_load_label (void)
}
}
/* Return the assembly code for INSN, which has the operands given by
OPERANDS, and which branches to OPERANDS[1] if some condition is true.
BRANCH_IF_TRUE is the asm template that should be used if OPERANDS[1]
is in range of a direct branch. BRANCH_IF_FALSE is an inverted
version of BRANCH_IF_TRUE. */
/* Output assembly instructions to peform a conditional branch.
INSN is the branch instruction. OPERANDS[0] is the condition.
OPERANDS[1] is the target of the branch. OPERANDS[2] is the target
of the first operand to the condition. If TWO_OPERANDS_P is
nonzero the comparison takes two operands; OPERANDS[3] will be the
second operand.
If INVERTED_P is nonzero we are to branch if the condition does
not hold. If FLOAT_P is nonzero this is a floating-point comparison.
LENGTH is the length (in bytes) of the sequence we are to generate.
That tells us whether to generate a simple conditional branch, or a
reversed conditional branch around a `jr' instruction. */
const char *
mips_output_conditional_branch (rtx insn, rtx *operands, int two_operands_p,
int float_p, int inverted_p, int length)
{
static char buffer[200];
/* The kind of comparison we are doing. */
enum rtx_code code = GET_CODE (operands[0]);
/* Nonzero if the opcode for the comparison needs a `z' indicating
that it is a comparison against zero. */
int need_z_p;
/* A string to use in the assembly output to represent the first
operand. */
const char *op1 = "%z2";
/* A string to use in the assembly output to represent the second
operand. Use the hard-wired zero register if there's no second
operand. */
const char *op2 = (two_operands_p ? ",%z3" : ",%.");
/* The operand-printing string for the comparison. */
const char *const comp = (float_p ? "%F0" : "%C0");
/* The operand-printing string for the inverted comparison. */
const char *const inverted_comp = (float_p ? "%W0" : "%N0");
/* The MIPS processors (for levels of the ISA at least two), have
"likely" variants of each branch instruction. These instructions
annul the instruction in the delay slot if the branch is not
taken. */
mips_branch_likely = (final_sequence && INSN_ANNULLED_BRANCH_P (insn));
if (!two_operands_p)
{
/* To compute whether than A > B, for example, we normally
subtract B from A and then look at the sign bit. But, if we
are doing an unsigned comparison, and B is zero, we don't
have to do the subtraction. Instead, we can just check to
see if A is nonzero. Thus, we change the CODE here to
reflect the simpler comparison operation. */
switch (code)
{
case GTU:
code = NE;
break;
mips_output_conditional_branch (rtx insn, rtx *operands,
const char *branch_if_true,
const char *branch_if_false)
{
unsigned int length;
rtx taken, not_taken;
case LEU:
code = EQ;
break;
length = get_attr_length (insn);
if (length <= 8)
{
/* Just a simple conditional branch. */
mips_branch_likely = (final_sequence && INSN_ANNULLED_BRANCH_P (insn));
return branch_if_true;
}
case GEU:
/* A condition which will always be true. */
code = EQ;
op1 = "%.";
break;
/* Generate a reversed branch around a direct jump. This fallback does
not use branch-likely instructions. */
mips_branch_likely = false;
not_taken = gen_label_rtx ();
taken = operands[1];
case LTU:
/* A condition which will always be false. */
code = NE;
op1 = "%.";
break;
/* Generate the reversed branch to NOT_TAKEN. */
operands[1] = not_taken;
output_asm_insn (branch_if_false, operands);
default:
/* Not a special case. */
break;
/* If INSN has a delay slot, we must provide delay slots for both the
branch to NOT_TAKEN and the conditional jump. We must also ensure
that INSN's delay slot is executed in the appropriate cases. */
if (final_sequence)
{
/* This first delay slot will always be executed, so use INSN's
delay slot if is not annulled. */
if (!INSN_ANNULLED_BRANCH_P (insn))
{
final_scan_insn (XVECEXP (final_sequence, 0, 1),
asm_out_file, optimize, 1, NULL);
INSN_DELETED_P (XVECEXP (final_sequence, 0, 1)) = 1;
}
else
output_asm_insn ("nop", 0);
fprintf (asm_out_file, "\n");
}
/* Relative comparisons are always done against zero. But
equality comparisons are done between two operands, and therefore
do not require a `z' in the assembly language output. */
need_z_p = (!float_p && code != EQ && code != NE);
/* For comparisons against zero, the zero is not provided
explicitly. */
if (need_z_p)
op2 = "";
/* Begin by terminating the buffer. That way we can always use
strcat to add to it. */
buffer[0] = '\0';
/* Output the unconditional branch to TAKEN. */
if (length <= 16)
output_asm_insn ("j\t%0%/", &taken);
else
{
output_asm_insn (mips_output_load_label (), &taken);
output_asm_insn ("jr\t%@%]%/", 0);
}
switch (length)
/* Now deal with its delay slot; see above. */
if (final_sequence)
{
case 4:
case 8:
/* Just a simple conditional branch. */
if (float_p)
sprintf (buffer, "%%*b%s%%?\t%%Z2%%1%%/",
inverted_p ? inverted_comp : comp);
/* This delay slot will only be executed if the branch is taken.
Use INSN's delay slot if is annulled. */
if (INSN_ANNULLED_BRANCH_P (insn))
{
final_scan_insn (XVECEXP (final_sequence, 0, 1),
asm_out_file, optimize, 1, NULL);
INSN_DELETED_P (XVECEXP (final_sequence, 0, 1)) = 1;
}
else
sprintf (buffer, "%%*b%s%s%%?\t%s%s,%%1%%/",
inverted_p ? inverted_comp : comp,
need_z_p ? "z" : "",
op1,
op2);
return buffer;
case 12:
case 16:
case 24:
case 28:
{
/* Generate a reversed conditional branch around ` j'
instruction:
.set noreorder
.set nomacro
bc l
delay_slot or #nop
j target
#nop
l:
.set macro
.set reorder
If the original branch was a likely branch, the delay slot
must be executed only if the branch is taken, so generate:
.set noreorder
.set nomacro
bc l
#nop
j target
delay slot or #nop
l:
.set macro
.set reorder
When generating PIC, instead of:
j target
we emit:
.set noat
la $at, target
jr $at
.set at
*/
rtx orig_target;
rtx target = gen_label_rtx ();
orig_target = operands[1];
operands[1] = target;
/* Generate the reversed comparison. This takes four
bytes. */
if (float_p)
sprintf (buffer, "%%*b%s\t%%Z2%%1",
inverted_p ? comp : inverted_comp);
else
sprintf (buffer, "%%*b%s%s\t%s%s,%%1",
inverted_p ? comp : inverted_comp,
need_z_p ? "z" : "",
op1,
op2);
output_asm_insn (buffer, operands);
if (length != 16 && length != 28 && ! mips_branch_likely)
{
/* Output delay slot instruction. */
rtx insn = final_sequence;
final_scan_insn (XVECEXP (insn, 0, 1), asm_out_file,
optimize, 1, NULL);
INSN_DELETED_P (XVECEXP (insn, 0, 1)) = 1;
}
else
output_asm_insn ("%#", 0);
output_asm_insn ("nop", 0);
fprintf (asm_out_file, "\n");
}
if (length <= 16)
output_asm_insn ("j\t%0", &orig_target);
else
{
output_asm_insn (mips_output_load_label (), &orig_target);
output_asm_insn ("jr\t%@%]", 0);
}
/* Output NOT_TAKEN. */
(*targetm.asm_out.internal_label) (asm_out_file, "L",
CODE_LABEL_NUMBER (not_taken));
return "";
}
if (length != 16 && length != 28 && mips_branch_likely)
{
/* Output delay slot instruction. */
rtx insn = final_sequence;
final_scan_insn (XVECEXP (insn, 0, 1), asm_out_file,
optimize, 1, NULL);
INSN_DELETED_P (XVECEXP (insn, 0, 1)) = 1;
}
else
output_asm_insn ("%#", 0);
/* Return the assembly code for INSN, which branches to OPERANDS[1]
if some ordered condition is true. The condition is given by
OPERANDS[0] if !INVERTED_P, otherwise it is the inverse of
OPERANDS[0]. OPERANDS[2] is the comparison's first operand;
its second is always zero. */
(*targetm.asm_out.internal_label) (asm_out_file, "L",
CODE_LABEL_NUMBER (target));
const char *
mips_output_order_conditional_branch (rtx insn, rtx *operands, bool inverted_p)
{
const char *branch[2];
return "";
}
/* Make BRANCH[1] branch to OPERANDS[1] when the condition is true.
Make BRANCH[0] branch on the inverse condition. */
switch (GET_CODE (operands[0]))
{
/* These cases are equivalent to comparisons against zero. */
case LEU:
inverted_p = !inverted_p;
/* Fall through. */
case GTU:
branch[!inverted_p] = MIPS_BRANCH ("bne", "%2,%.,%1");
branch[inverted_p] = MIPS_BRANCH ("beq", "%2,%.,%1");
break;
/* These cases are always true or always false. */
case LTU:
inverted_p = !inverted_p;
/* Fall through. */
case GEU:
branch[!inverted_p] = MIPS_BRANCH ("beq", "%.,%.,%1");
branch[inverted_p] = MIPS_BRANCH ("bne", "%.,%.,%1");
break;
default:
gcc_unreachable ();
branch[!inverted_p] = MIPS_BRANCH ("b%C0z", "%2,%1");
branch[inverted_p] = MIPS_BRANCH ("b%N0z", "%2,%1");
break;
}
/* NOTREACHED */
return 0;
return mips_output_conditional_branch (insn, operands, branch[1], branch[0]);
}
/* Used to output div or ddiv instruction DIVISION, which has the operands
......@@ -10591,6 +10496,34 @@ mips_expand_builtin_movtf (enum mips_builtin_type type,
return target;
}
/* Move VALUE_IF_TRUE into TARGET if CONDITION is true; move VALUE_IF_FALSE
into TARGET otherwise. Return TARGET. */
static rtx
mips_builtin_branch_and_move (rtx condition, rtx target,
rtx value_if_true, rtx value_if_false)
{
rtx true_label, done_label;
true_label = gen_label_rtx ();
done_label = gen_label_rtx ();
/* First assume that CONDITION is false. */
emit_move_insn (target, value_if_false);
/* Branch to TRUE_LABEL if CONDITION is true and DONE_LABEL otherwise. */
emit_jump_insn (gen_condjump (condition, true_label));
emit_jump_insn (gen_jump (done_label));
emit_barrier ();
/* Fix TARGET if CONDITION is true. */
emit_label (true_label);
emit_move_insn (target, value_if_true);
emit_label (done_label);
return target;
}
/* Expand a comparison builtin of type BUILTIN_TYPE. ICODE is the code
of the comparison instruction and COND is the condition it should test.
ARGLIST is the list of function arguments and TARGET, if nonnull,
......@@ -10601,10 +10534,8 @@ mips_expand_builtin_compare (enum mips_builtin_type builtin_type,
enum insn_code icode, enum mips_fp_condition cond,
rtx target, tree arglist)
{
rtx label1, label2, if_then_else;
rtx pat, cmp_result, ops[MAX_RECOG_OPERANDS];
rtx target_if_equal, target_if_unequal;
int cmp_value, i;
rtx offset, condition, cmp_result, ops[MAX_RECOG_OPERANDS];
int i;
if (target == 0 || GET_MODE (target) != SImode)
target = gen_reg_rtx (SImode);
......@@ -10617,12 +10548,12 @@ mips_expand_builtin_compare (enum mips_builtin_type builtin_type,
switch (insn_data[icode].n_operands)
{
case 4:
pat = GEN_FCN (icode) (cmp_result, ops[1], ops[2], GEN_INT (cond));
emit_insn (GEN_FCN (icode) (cmp_result, ops[1], ops[2], GEN_INT (cond)));
break;
case 6:
pat = GEN_FCN (icode) (cmp_result, ops[1], ops[2],
ops[3], ops[4], GEN_INT (cond));
emit_insn (GEN_FCN (icode) (cmp_result, ops[1], ops[2],
ops[3], ops[4], GEN_INT (cond)));
break;
default:
......@@ -10631,71 +10562,35 @@ mips_expand_builtin_compare (enum mips_builtin_type builtin_type,
/* If the comparison sets more than one register, we define the result
to be 0 if all registers are false and -1 if all registers are true.
The value of the complete result is indeterminate otherwise. It is
possible to test individual registers using SUBREGs.
Set up CMP_RESULT, CMP_VALUE, TARGET_IF_EQUAL and TARGET_IF_UNEQUAL so
that the result should be TARGET_IF_EQUAL if (EQ CMP_RESULT CMP_VALUE)
and TARGET_IF_UNEQUAL otherwise. */
if (builtin_type == MIPS_BUILTIN_CMP_ALL)
{
cmp_value = -1;
target_if_equal = const1_rtx;
target_if_unequal = const0_rtx;
}
else
The value of the complete result is indeterminate otherwise. */
switch (builtin_type)
{
cmp_value = 0;
target_if_equal = const0_rtx;
target_if_unequal = const1_rtx;
if (builtin_type == MIPS_BUILTIN_CMP_UPPER)
cmp_result = simplify_gen_subreg (CCmode, cmp_result, CCV2mode, 4);
else if (builtin_type == MIPS_BUILTIN_CMP_LOWER)
cmp_result = simplify_gen_subreg (CCmode, cmp_result, CCV2mode, 0);
}
/* First assume that CMP_RESULT == CMP_VALUE. */
emit_move_insn (target, target_if_equal);
/* Branch to LABEL1 if CMP_RESULT != CMP_VALUE. */
emit_insn (pat);
label1 = gen_label_rtx ();
label2 = gen_label_rtx ();
if_then_else
= gen_rtx_IF_THEN_ELSE (VOIDmode,
gen_rtx_fmt_ee (NE, GET_MODE (cmp_result),
cmp_result, GEN_INT (cmp_value)),
gen_rtx_LABEL_REF (VOIDmode, label1), pc_rtx);
emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, if_then_else));
emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
gen_rtx_LABEL_REF (VOIDmode, label2)));
emit_barrier ();
emit_label (label1);
case MIPS_BUILTIN_CMP_ALL:
condition = gen_rtx_NE (VOIDmode, cmp_result, constm1_rtx);
return mips_builtin_branch_and_move (condition, target,
const0_rtx, const1_rtx);
/* Fix TARGET for CMP_RESULT != CMP_VALUE. */
emit_move_insn (target, target_if_unequal);
emit_label (label2);
case MIPS_BUILTIN_CMP_UPPER:
case MIPS_BUILTIN_CMP_LOWER:
offset = GEN_INT (builtin_type == MIPS_BUILTIN_CMP_UPPER);
condition = gen_single_cc (cmp_result, offset);
return mips_builtin_branch_and_move (condition, target,
const1_rtx, const0_rtx);
return target;
default:
condition = gen_rtx_NE (VOIDmode, cmp_result, const0_rtx);
return mips_builtin_branch_and_move (condition, target,
const1_rtx, const0_rtx);
}
}
/* Expand a bposge builtin of type BUILTIN_TYPE. TARGET, if nonnull,
suggests a good place to put the boolean result.
The sequence we want is
li target, 0
bposge* label1
j label2
label1:
li target, 1
label2: */
suggests a good place to put the boolean result. */
static rtx
mips_expand_builtin_bposge (enum mips_builtin_type builtin_type, rtx target)
{
rtx label1, label2, if_then_else;
rtx cmp_result;
rtx condition, cmp_result;
int cmp_value;
if (target == 0 || GET_MODE (target) != SImode)
......@@ -10708,29 +10603,9 @@ mips_expand_builtin_bposge (enum mips_builtin_type builtin_type, rtx target)
else
gcc_assert (0);
/* Move 0 to target */
emit_move_insn (target, const0_rtx);
/* Generate two labels */
label1 = gen_label_rtx ();
label2 = gen_label_rtx ();
/* Generate if_then_else */
if_then_else
= gen_rtx_IF_THEN_ELSE (VOIDmode,
gen_rtx_fmt_ee (GE, CCDSPmode,
cmp_result, GEN_INT (cmp_value)),
gen_rtx_LABEL_REF (VOIDmode, label1), pc_rtx);
emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, if_then_else));
emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
gen_rtx_LABEL_REF (VOIDmode, label2)));
emit_barrier ();
emit_label (label1);
emit_move_insn (target, const1_rtx);
emit_label (label2);
return target;
condition = gen_rtx_GE (VOIDmode, cmp_result, GEN_INT (cmp_value));
return mips_builtin_branch_and_move (condition, target,
const1_rtx, const0_rtx);
}
/* Set SYMBOL_REF_FLAGS for the SYMBOL_REF inside RTL, which belongs to DECL.
......
......@@ -2272,6 +2272,12 @@ typedef struct mips_args {
be updated with the correct length of the insn. */
#define ADJUST_INSN_LENGTH(INSN, LENGTH) \
((LENGTH) = mips_adjust_insn_length ((INSN), (LENGTH)))
/* Return the asm template for a non-MIPS16 conditional branch instruction.
OPCODE is the opcode's mnemonic and OPERANDS is the asm template for
its operands. */
#define MIPS_BRANCH(OPCODE, OPERANDS) \
"%*" OPCODE "%?\t" OPERANDS "%/"
/* Control the assembler format that we output. */
......
......@@ -72,6 +72,7 @@
(UNSPEC_RSQRT2 209)
(UNSPEC_RECIP1 210)
(UNSPEC_RECIP2 211)
(UNSPEC_SINGLE_CC 212)
;; MIPS DSP ASE Revision 0.98 3/24/2005
(UNSPEC_ADDQ 300)
......@@ -4272,85 +4273,65 @@
;; Conditional branches on floating-point equality tests.
(define_insn "branch_fp"
(define_insn "*branch_fp"
[(set (pc)
(if_then_else
(match_operator:CC 0 "comparison_operator"
[(match_operand:CC 2 "register_operand" "z")
(const_int 0)])
(match_operator 0 "equality_operator"
[(match_operand:CC 2 "register_operand" "z")
(const_int 0)])
(label_ref (match_operand 1 "" ""))
(pc)))]
"TARGET_HARD_FLOAT"
{
return mips_output_conditional_branch (insn,
operands,
/*two_operands_p=*/0,
/*float_p=*/1,
/*inverted_p=*/0,
get_attr_length (insn));
return mips_output_conditional_branch (insn, operands,
MIPS_BRANCH ("b%F0", "%2,%1"),
MIPS_BRANCH ("b%W0", "%2,%1"));
}
[(set_attr "type" "branch")
(set_attr "mode" "none")])
[(set_attr "type" "branch")
(set_attr "mode" "none")])
(define_insn "branch_fp_inverted"
(define_insn "*branch_fp_inverted"
[(set (pc)
(if_then_else
(match_operator:CC 0 "comparison_operator"
[(match_operand:CC 2 "register_operand" "z")
(const_int 0)])
(match_operator 0 "equality_operator"
[(match_operand:CC 2 "register_operand" "z")
(const_int 0)])
(pc)
(label_ref (match_operand 1 "" ""))))]
"TARGET_HARD_FLOAT"
{
return mips_output_conditional_branch (insn,
operands,
/*two_operands_p=*/0,
/*float_p=*/1,
/*inverted_p=*/1,
get_attr_length (insn));
return mips_output_conditional_branch (insn, operands,
MIPS_BRANCH ("b%W0", "%2,%1"),
MIPS_BRANCH ("b%F0", "%2,%1"));
}
[(set_attr "type" "branch")
(set_attr "mode" "none")])
[(set_attr "type" "branch")
(set_attr "mode" "none")])
;; Conditional branches on comparisons with zero.
;; Conditional branches on ordered comparisons with zero.
(define_insn "*branch_zero<mode>"
(define_insn "*branch_order<mode>"
[(set (pc)
(if_then_else
(match_operator 0 "comparison_operator"
(match_operator 0 "order_operator"
[(match_operand:GPR 2 "register_operand" "d")
(const_int 0)])
(label_ref (match_operand 1 "" ""))
(pc)))]
"!TARGET_MIPS16"
{
return mips_output_conditional_branch (insn,
operands,
/*two_operands_p=*/0,
/*float_p=*/0,
/*inverted_p=*/0,
get_attr_length (insn));
}
{ return mips_output_order_conditional_branch (insn, operands, false); }
[(set_attr "type" "branch")
(set_attr "mode" "none")])
(define_insn "*branch_zero<mode>_inverted"
(define_insn "*branch_order<mode>_inverted"
[(set (pc)
(if_then_else
(match_operator 0 "comparison_operator"
(match_operator 0 "order_operator"
[(match_operand:GPR 2 "register_operand" "d")
(const_int 0)])
(pc)
(label_ref (match_operand 1 "" ""))))]
"!TARGET_MIPS16"
{
return mips_output_conditional_branch (insn,
operands,
/*two_operands_p=*/0,
/*float_p=*/0,
/*inverted_p=*/1,
get_attr_length (insn));
}
{ return mips_output_order_conditional_branch (insn, operands, true); }
[(set_attr "type" "branch")
(set_attr "mode" "none")])
......@@ -4361,17 +4342,14 @@
(if_then_else
(match_operator 0 "equality_operator"
[(match_operand:GPR 2 "register_operand" "d")
(match_operand:GPR 3 "register_operand" "d")])
(match_operand:GPR 3 "reg_or_0_operand" "dJ")])
(label_ref (match_operand 1 "" ""))
(pc)))]
"!TARGET_MIPS16"
{
return mips_output_conditional_branch (insn,
operands,
/*two_operands_p=*/1,
/*float_p=*/0,
/*inverted_p=*/0,
get_attr_length (insn));
return mips_output_conditional_branch (insn, operands,
MIPS_BRANCH ("b%C0", "%2,%z3,%1"),
MIPS_BRANCH ("b%N0", "%2,%z3,%1"));
}
[(set_attr "type" "branch")
(set_attr "mode" "none")])
......@@ -4381,17 +4359,14 @@
(if_then_else
(match_operator 0 "equality_operator"
[(match_operand:GPR 2 "register_operand" "d")
(match_operand:GPR 3 "register_operand" "d")])
(match_operand:GPR 3 "reg_or_0_operand" "dJ")])
(pc)
(label_ref (match_operand 1 "" ""))))]
"!TARGET_MIPS16"
{
return mips_output_conditional_branch (insn,
operands,
/*two_operands_p=*/1,
/*float_p=*/0,
/*inverted_p=*/1,
get_attr_length (insn));
return mips_output_conditional_branch (insn, operands,
MIPS_BRANCH ("b%N0", "%2,%z3,%1"),
MIPS_BRANCH ("b%C0", "%2,%z3,%1"));
}
[(set_attr "type" "branch")
(set_attr "mode" "none")])
......@@ -4438,6 +4413,13 @@
gen_conditional_branch (operands, <CODE>);
DONE;
})
;; Used to implement built-in functions.
(define_expand "condjump"
[(set (pc)
(if_then_else (match_operand 0)
(label_ref (match_operand 1))
(pc)))])
;;
;; ....................
......
......@@ -212,6 +212,9 @@
(define_predicate "trap_comparison_operator"
(match_code "eq,ne,lt,ltu,ge,geu"))
(define_predicate "order_operator"
(match_code "lt,ltu,le,leu,ge,geu,gt,gtu"))
(define_predicate "small_data_pattern"
(and (match_code "set,parallel,unspec,unspec_volatile,prefetch")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment