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> 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. * doc/md.texi: Update documentation of MIPS constraints.
* config/mips/constraints.md: New file. * config/mips/constraints.md: New file.
* config/mips/mips.md: Include it. * config/mips/mips.md: Include it.
......
...@@ -1046,11 +1046,10 @@ ...@@ -1046,11 +1046,10 @@
;; BPOSGE32 ;; BPOSGE32
(define_insn "mips_bposge" (define_insn "mips_bposge"
[(set (pc) [(set (pc)
(if_then_else (if_then_else (ge (reg:CCDSP CCDSP_PO_REGNUM)
(ge:CCDSP (reg:CCDSP CCDSP_PO_REGNUM) (match_operand:SI 0 "immediate_operand" "I"))
(match_operand:SI 0 "immediate_operand" "I")) (label_ref (match_operand 1 "" ""))
(label_ref (match_operand 1 "" "")) (pc)))]
(pc)))]
"TARGET_DSP" "TARGET_DSP"
"%*bposge%0\t%1%/" "%*bposge%0\t%1%/"
[(set_attr "type" "branch") [(set_attr "type" "branch")
......
...@@ -212,8 +212,9 @@ extern int mips_register_move_cost (enum machine_mode, enum reg_class, ...@@ -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 int mips_adjust_insn_length (rtx, int);
extern const char *mips_output_load_label (void); extern const char *mips_output_load_label (void);
extern const char *mips_output_conditional_branch (rtx, rtx *, int, int, extern const char *mips_output_conditional_branch (rtx, rtx *, const char *,
int, int); const char *);
extern const char *mips_output_order_conditional_branch (rtx, rtx *, bool);
extern const char *mips_output_division (const char *, rtx *); extern const char *mips_output_division (const char *, rtx *);
extern unsigned int mips_hard_regno_nregs (int, enum machine_mode); extern unsigned int mips_hard_regno_nregs (int, enum machine_mode);
extern bool mips_linked_madd_p (rtx, rtx); extern bool mips_linked_madd_p (rtx, rtx);
......
...@@ -389,8 +389,8 @@ ...@@ -389,8 +389,8 @@
; Branch on Any of Four Floating Point Condition Codes True ; Branch on Any of Four Floating Point Condition Codes True
(define_insn "bc1any4t" (define_insn "bc1any4t"
[(set (pc) [(set (pc)
(if_then_else (ne:CCV4 (match_operand:CCV4 0 "register_operand" "z") (if_then_else (ne (match_operand:CCV4 0 "register_operand" "z")
(const_int 0)) (const_int 0))
(label_ref (match_operand 1 "" "")) (label_ref (match_operand 1 "" ""))
(pc)))] (pc)))]
"TARGET_MIPS3D" "TARGET_MIPS3D"
...@@ -401,8 +401,8 @@ ...@@ -401,8 +401,8 @@
; Branch on Any of Four Floating Point Condition Codes False ; Branch on Any of Four Floating Point Condition Codes False
(define_insn "bc1any4f" (define_insn "bc1any4f"
[(set (pc) [(set (pc)
(if_then_else (ne:CCV4 (match_operand:CCV4 0 "register_operand" "z") (if_then_else (ne (match_operand:CCV4 0 "register_operand" "z")
(const_int -1)) (const_int -1))
(label_ref (match_operand 1 "" "")) (label_ref (match_operand 1 "" ""))
(pc)))] (pc)))]
"TARGET_MIPS3D" "TARGET_MIPS3D"
...@@ -413,8 +413,8 @@ ...@@ -413,8 +413,8 @@
; Branch on Any of Two Floating Point Condition Codes True ; Branch on Any of Two Floating Point Condition Codes True
(define_insn "bc1any2t" (define_insn "bc1any2t"
[(set (pc) [(set (pc)
(if_then_else (ne:CCV2 (match_operand:CCV2 0 "register_operand" "z") (if_then_else (ne (match_operand:CCV2 0 "register_operand" "z")
(const_int 0)) (const_int 0))
(label_ref (match_operand 1 "" "")) (label_ref (match_operand 1 "" ""))
(pc)))] (pc)))]
"TARGET_MIPS3D" "TARGET_MIPS3D"
...@@ -425,8 +425,8 @@ ...@@ -425,8 +425,8 @@
; Branch on Any of Two Floating Point Condition Codes False ; Branch on Any of Two Floating Point Condition Codes False
(define_insn "bc1any2f" (define_insn "bc1any2f"
[(set (pc) [(set (pc)
(if_then_else (ne:CCV2 (match_operand:CCV2 0 "register_operand" "z") (if_then_else (ne (match_operand:CCV2 0 "register_operand" "z")
(const_int -1)) (const_int -1))
(label_ref (match_operand 1 "" "")) (label_ref (match_operand 1 "" ""))
(pc)))] (pc)))]
"TARGET_MIPS3D" "TARGET_MIPS3D"
...@@ -434,6 +434,59 @@ ...@@ -434,6 +434,59 @@
[(set_attr "type" "branch") [(set_attr "type" "branch")
(set_attr "mode" "none")]) (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. ; Floating Point Reduced Precision Reciprocal Square Root Instructions.
;---------------------------------------------------------------------------- ;----------------------------------------------------------------------------
......
...@@ -3186,15 +3186,11 @@ mips_emit_scc (enum rtx_code code, rtx target) ...@@ -3186,15 +3186,11 @@ mips_emit_scc (enum rtx_code code, rtx target)
void void
gen_conditional_branch (rtx *operands, enum rtx_code code) 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); mips_emit_compare (&code, &op0, &op1, TARGET_MIPS16);
target = gen_rtx_IF_THEN_ELSE (VOIDmode, condition = gen_rtx_fmt_ee (code, VOIDmode, op0, op1);
gen_rtx_fmt_ee (code, GET_MODE (op0), emit_jump_insn (gen_condjump (condition, operands[0]));
op0, op1),
gen_rtx_LABEL_REF (VOIDmode, operands[0]),
pc_rtx);
emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, target));
} }
/* Emit the common code for conditional moves. OPERANDS is the array /* Emit the common code for conditional moves. OPERANDS is the array
...@@ -9127,217 +9123,126 @@ mips_output_load_label (void) ...@@ -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 * const char *
mips_output_conditional_branch (rtx insn, rtx *operands, int two_operands_p, mips_output_conditional_branch (rtx insn, rtx *operands,
int float_p, int inverted_p, int length) const char *branch_if_true,
{ const char *branch_if_false)
static char buffer[200]; {
/* The kind of comparison we are doing. */ unsigned int length;
enum rtx_code code = GET_CODE (operands[0]); rtx taken, not_taken;
/* 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;
case LEU: length = get_attr_length (insn);
code = EQ; if (length <= 8)
break; {
/* Just a simple conditional branch. */
mips_branch_likely = (final_sequence && INSN_ANNULLED_BRANCH_P (insn));
return branch_if_true;
}
case GEU: /* Generate a reversed branch around a direct jump. This fallback does
/* A condition which will always be true. */ not use branch-likely instructions. */
code = EQ; mips_branch_likely = false;
op1 = "%."; not_taken = gen_label_rtx ();
break; taken = operands[1];
case LTU: /* Generate the reversed branch to NOT_TAKEN. */
/* A condition which will always be false. */ operands[1] = not_taken;
code = NE; output_asm_insn (branch_if_false, operands);
op1 = "%.";
break;
default: /* If INSN has a delay slot, we must provide delay slots for both the
/* Not a special case. */ branch to NOT_TAKEN and the conditional jump. We must also ensure
break; 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 /* Output the unconditional branch to TAKEN. */
equality comparisons are done between two operands, and therefore if (length <= 16)
do not require a `z' in the assembly language output. */ output_asm_insn ("j\t%0%/", &taken);
need_z_p = (!float_p && code != EQ && code != NE); else
/* For comparisons against zero, the zero is not provided {
explicitly. */ output_asm_insn (mips_output_load_label (), &taken);
if (need_z_p) output_asm_insn ("jr\t%@%]%/", 0);
op2 = ""; }
/* Begin by terminating the buffer. That way we can always use
strcat to add to it. */
buffer[0] = '\0';
switch (length) /* Now deal with its delay slot; see above. */
if (final_sequence)
{ {
case 4: /* This delay slot will only be executed if the branch is taken.
case 8: Use INSN's delay slot if is annulled. */
/* Just a simple conditional branch. */ if (INSN_ANNULLED_BRANCH_P (insn))
if (float_p) {
sprintf (buffer, "%%*b%s%%?\t%%Z2%%1%%/", final_scan_insn (XVECEXP (final_sequence, 0, 1),
inverted_p ? inverted_comp : comp); asm_out_file, optimize, 1, NULL);
INSN_DELETED_P (XVECEXP (final_sequence, 0, 1)) = 1;
}
else else
sprintf (buffer, "%%*b%s%s%%?\t%s%s,%%1%%/", output_asm_insn ("nop", 0);
inverted_p ? inverted_comp : comp, fprintf (asm_out_file, "\n");
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);
if (length <= 16) /* Output NOT_TAKEN. */
output_asm_insn ("j\t%0", &orig_target); (*targetm.asm_out.internal_label) (asm_out_file, "L",
else CODE_LABEL_NUMBER (not_taken));
{ return "";
output_asm_insn (mips_output_load_label (), &orig_target); }
output_asm_insn ("jr\t%@%]", 0);
}
if (length != 16 && length != 28 && mips_branch_likely) /* Return the assembly code for INSN, which branches to OPERANDS[1]
{ if some ordered condition is true. The condition is given by
/* Output delay slot instruction. */ OPERANDS[0] if !INVERTED_P, otherwise it is the inverse of
rtx insn = final_sequence; OPERANDS[0]. OPERANDS[2] is the comparison's first operand;
final_scan_insn (XVECEXP (insn, 0, 1), asm_out_file, its second is always zero. */
optimize, 1, NULL);
INSN_DELETED_P (XVECEXP (insn, 0, 1)) = 1;
}
else
output_asm_insn ("%#", 0);
(*targetm.asm_out.internal_label) (asm_out_file, "L", const char *
CODE_LABEL_NUMBER (target)); 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: default:
gcc_unreachable (); branch[!inverted_p] = MIPS_BRANCH ("b%C0z", "%2,%1");
branch[inverted_p] = MIPS_BRANCH ("b%N0z", "%2,%1");
break;
} }
return mips_output_conditional_branch (insn, operands, branch[1], branch[0]);
/* NOTREACHED */
return 0;
} }
/* Used to output div or ddiv instruction DIVISION, which has the operands /* 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, ...@@ -10591,6 +10496,34 @@ mips_expand_builtin_movtf (enum mips_builtin_type type,
return target; 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 /* Expand a comparison builtin of type BUILTIN_TYPE. ICODE is the code
of the comparison instruction and COND is the condition it should test. of the comparison instruction and COND is the condition it should test.
ARGLIST is the list of function arguments and TARGET, if nonnull, 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, ...@@ -10601,10 +10534,8 @@ mips_expand_builtin_compare (enum mips_builtin_type builtin_type,
enum insn_code icode, enum mips_fp_condition cond, enum insn_code icode, enum mips_fp_condition cond,
rtx target, tree arglist) rtx target, tree arglist)
{ {
rtx label1, label2, if_then_else; rtx offset, condition, cmp_result, ops[MAX_RECOG_OPERANDS];
rtx pat, cmp_result, ops[MAX_RECOG_OPERANDS]; int i;
rtx target_if_equal, target_if_unequal;
int cmp_value, i;
if (target == 0 || GET_MODE (target) != SImode) if (target == 0 || GET_MODE (target) != SImode)
target = gen_reg_rtx (SImode); target = gen_reg_rtx (SImode);
...@@ -10617,12 +10548,12 @@ mips_expand_builtin_compare (enum mips_builtin_type builtin_type, ...@@ -10617,12 +10548,12 @@ mips_expand_builtin_compare (enum mips_builtin_type builtin_type,
switch (insn_data[icode].n_operands) switch (insn_data[icode].n_operands)
{ {
case 4: 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; break;
case 6: case 6:
pat = GEN_FCN (icode) (cmp_result, ops[1], ops[2], emit_insn (GEN_FCN (icode) (cmp_result, ops[1], ops[2],
ops[3], ops[4], GEN_INT (cond)); ops[3], ops[4], GEN_INT (cond)));
break; break;
default: default:
...@@ -10631,71 +10562,35 @@ mips_expand_builtin_compare (enum mips_builtin_type builtin_type, ...@@ -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 /* 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. 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 The value of the complete result is indeterminate otherwise. */
possible to test individual registers using SUBREGs. switch (builtin_type)
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
{ {
cmp_value = 0; case MIPS_BUILTIN_CMP_ALL:
target_if_equal = const0_rtx; condition = gen_rtx_NE (VOIDmode, cmp_result, constm1_rtx);
target_if_unequal = const1_rtx; return mips_builtin_branch_and_move (condition, target,
if (builtin_type == MIPS_BUILTIN_CMP_UPPER) const0_rtx, const1_rtx);
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);
/* Fix TARGET for CMP_RESULT != CMP_VALUE. */ case MIPS_BUILTIN_CMP_UPPER:
emit_move_insn (target, target_if_unequal); case MIPS_BUILTIN_CMP_LOWER:
emit_label (label2); 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, /* Expand a bposge builtin of type BUILTIN_TYPE. TARGET, if nonnull,
suggests a good place to put the boolean result. 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: */
static rtx static rtx
mips_expand_builtin_bposge (enum mips_builtin_type builtin_type, rtx target) mips_expand_builtin_bposge (enum mips_builtin_type builtin_type, rtx target)
{ {
rtx label1, label2, if_then_else; rtx condition, cmp_result;
rtx cmp_result;
int cmp_value; int cmp_value;
if (target == 0 || GET_MODE (target) != SImode) if (target == 0 || GET_MODE (target) != SImode)
...@@ -10708,29 +10603,9 @@ mips_expand_builtin_bposge (enum mips_builtin_type builtin_type, rtx target) ...@@ -10708,29 +10603,9 @@ mips_expand_builtin_bposge (enum mips_builtin_type builtin_type, rtx target)
else else
gcc_assert (0); gcc_assert (0);
/* Move 0 to target */ condition = gen_rtx_GE (VOIDmode, cmp_result, GEN_INT (cmp_value));
emit_move_insn (target, const0_rtx); return mips_builtin_branch_and_move (condition, target,
const1_rtx, 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;
} }
/* Set SYMBOL_REF_FLAGS for the SYMBOL_REF inside RTL, which belongs to DECL. /* Set SYMBOL_REF_FLAGS for the SYMBOL_REF inside RTL, which belongs to DECL.
......
...@@ -2272,6 +2272,12 @@ typedef struct mips_args { ...@@ -2272,6 +2272,12 @@ typedef struct mips_args {
be updated with the correct length of the insn. */ be updated with the correct length of the insn. */
#define ADJUST_INSN_LENGTH(INSN, LENGTH) \ #define ADJUST_INSN_LENGTH(INSN, LENGTH) \
((LENGTH) = mips_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. */ /* Control the assembler format that we output. */
......
...@@ -72,6 +72,7 @@ ...@@ -72,6 +72,7 @@
(UNSPEC_RSQRT2 209) (UNSPEC_RSQRT2 209)
(UNSPEC_RECIP1 210) (UNSPEC_RECIP1 210)
(UNSPEC_RECIP2 211) (UNSPEC_RECIP2 211)
(UNSPEC_SINGLE_CC 212)
;; MIPS DSP ASE Revision 0.98 3/24/2005 ;; MIPS DSP ASE Revision 0.98 3/24/2005
(UNSPEC_ADDQ 300) (UNSPEC_ADDQ 300)
...@@ -4272,85 +4273,65 @@ ...@@ -4272,85 +4273,65 @@
;; Conditional branches on floating-point equality tests. ;; Conditional branches on floating-point equality tests.
(define_insn "branch_fp" (define_insn "*branch_fp"
[(set (pc) [(set (pc)
(if_then_else (if_then_else
(match_operator:CC 0 "comparison_operator" (match_operator 0 "equality_operator"
[(match_operand:CC 2 "register_operand" "z") [(match_operand:CC 2 "register_operand" "z")
(const_int 0)]) (const_int 0)])
(label_ref (match_operand 1 "" "")) (label_ref (match_operand 1 "" ""))
(pc)))] (pc)))]
"TARGET_HARD_FLOAT" "TARGET_HARD_FLOAT"
{ {
return mips_output_conditional_branch (insn, return mips_output_conditional_branch (insn, operands,
operands, MIPS_BRANCH ("b%F0", "%2,%1"),
/*two_operands_p=*/0, MIPS_BRANCH ("b%W0", "%2,%1"));
/*float_p=*/1,
/*inverted_p=*/0,
get_attr_length (insn));
} }
[(set_attr "type" "branch") [(set_attr "type" "branch")
(set_attr "mode" "none")]) (set_attr "mode" "none")])
(define_insn "branch_fp_inverted" (define_insn "*branch_fp_inverted"
[(set (pc) [(set (pc)
(if_then_else (if_then_else
(match_operator:CC 0 "comparison_operator" (match_operator 0 "equality_operator"
[(match_operand:CC 2 "register_operand" "z") [(match_operand:CC 2 "register_operand" "z")
(const_int 0)]) (const_int 0)])
(pc) (pc)
(label_ref (match_operand 1 "" ""))))] (label_ref (match_operand 1 "" ""))))]
"TARGET_HARD_FLOAT" "TARGET_HARD_FLOAT"
{ {
return mips_output_conditional_branch (insn, return mips_output_conditional_branch (insn, operands,
operands, MIPS_BRANCH ("b%W0", "%2,%1"),
/*two_operands_p=*/0, MIPS_BRANCH ("b%F0", "%2,%1"));
/*float_p=*/1,
/*inverted_p=*/1,
get_attr_length (insn));
} }
[(set_attr "type" "branch") [(set_attr "type" "branch")
(set_attr "mode" "none")]) (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) [(set (pc)
(if_then_else (if_then_else
(match_operator 0 "comparison_operator" (match_operator 0 "order_operator"
[(match_operand:GPR 2 "register_operand" "d") [(match_operand:GPR 2 "register_operand" "d")
(const_int 0)]) (const_int 0)])
(label_ref (match_operand 1 "" "")) (label_ref (match_operand 1 "" ""))
(pc)))] (pc)))]
"!TARGET_MIPS16" "!TARGET_MIPS16"
{ { return mips_output_order_conditional_branch (insn, operands, false); }
return mips_output_conditional_branch (insn,
operands,
/*two_operands_p=*/0,
/*float_p=*/0,
/*inverted_p=*/0,
get_attr_length (insn));
}
[(set_attr "type" "branch") [(set_attr "type" "branch")
(set_attr "mode" "none")]) (set_attr "mode" "none")])
(define_insn "*branch_zero<mode>_inverted" (define_insn "*branch_order<mode>_inverted"
[(set (pc) [(set (pc)
(if_then_else (if_then_else
(match_operator 0 "comparison_operator" (match_operator 0 "order_operator"
[(match_operand:GPR 2 "register_operand" "d") [(match_operand:GPR 2 "register_operand" "d")
(const_int 0)]) (const_int 0)])
(pc) (pc)
(label_ref (match_operand 1 "" ""))))] (label_ref (match_operand 1 "" ""))))]
"!TARGET_MIPS16" "!TARGET_MIPS16"
{ { return mips_output_order_conditional_branch (insn, operands, true); }
return mips_output_conditional_branch (insn,
operands,
/*two_operands_p=*/0,
/*float_p=*/0,
/*inverted_p=*/1,
get_attr_length (insn));
}
[(set_attr "type" "branch") [(set_attr "type" "branch")
(set_attr "mode" "none")]) (set_attr "mode" "none")])
...@@ -4361,17 +4342,14 @@ ...@@ -4361,17 +4342,14 @@
(if_then_else (if_then_else
(match_operator 0 "equality_operator" (match_operator 0 "equality_operator"
[(match_operand:GPR 2 "register_operand" "d") [(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 "" "")) (label_ref (match_operand 1 "" ""))
(pc)))] (pc)))]
"!TARGET_MIPS16" "!TARGET_MIPS16"
{ {
return mips_output_conditional_branch (insn, return mips_output_conditional_branch (insn, operands,
operands, MIPS_BRANCH ("b%C0", "%2,%z3,%1"),
/*two_operands_p=*/1, MIPS_BRANCH ("b%N0", "%2,%z3,%1"));
/*float_p=*/0,
/*inverted_p=*/0,
get_attr_length (insn));
} }
[(set_attr "type" "branch") [(set_attr "type" "branch")
(set_attr "mode" "none")]) (set_attr "mode" "none")])
...@@ -4381,17 +4359,14 @@ ...@@ -4381,17 +4359,14 @@
(if_then_else (if_then_else
(match_operator 0 "equality_operator" (match_operator 0 "equality_operator"
[(match_operand:GPR 2 "register_operand" "d") [(match_operand:GPR 2 "register_operand" "d")
(match_operand:GPR 3 "register_operand" "d")]) (match_operand:GPR 3 "reg_or_0_operand" "dJ")])
(pc) (pc)
(label_ref (match_operand 1 "" ""))))] (label_ref (match_operand 1 "" ""))))]
"!TARGET_MIPS16" "!TARGET_MIPS16"
{ {
return mips_output_conditional_branch (insn, return mips_output_conditional_branch (insn, operands,
operands, MIPS_BRANCH ("b%N0", "%2,%z3,%1"),
/*two_operands_p=*/1, MIPS_BRANCH ("b%C0", "%2,%z3,%1"));
/*float_p=*/0,
/*inverted_p=*/1,
get_attr_length (insn));
} }
[(set_attr "type" "branch") [(set_attr "type" "branch")
(set_attr "mode" "none")]) (set_attr "mode" "none")])
...@@ -4438,6 +4413,13 @@ ...@@ -4438,6 +4413,13 @@
gen_conditional_branch (operands, <CODE>); gen_conditional_branch (operands, <CODE>);
DONE; 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 @@ ...@@ -212,6 +212,9 @@
(define_predicate "trap_comparison_operator" (define_predicate "trap_comparison_operator"
(match_code "eq,ne,lt,ltu,ge,geu")) (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" (define_predicate "small_data_pattern"
(and (match_code "set,parallel,unspec,unspec_volatile,prefetch") (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