aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/mips
diff options
context:
space:
mode:
authorRichard Sandiford <richard@codesourcery.com>2006-03-09 21:03:17 +0000
committerRichard Sandiford <rsandifo@gcc.gnu.org>2006-03-09 21:03:17 +0000
commita8c1d5f80e0b710089f7e5f6265bdc345c7b514f (patch)
tree158c3ae50f6fe3219c35b26ac707baac94ae4ad9 /gcc/config/mips
parent1fea4e6c4301b2b69d6e2fa72c3c62ffdc8cfb78 (diff)
downloadgcc-a8c1d5f80e0b710089f7e5f6265bdc345c7b514f.zip
gcc-a8c1d5f80e0b710089f7e5f6265bdc345c7b514f.tar.gz
gcc-a8c1d5f80e0b710089f7e5f6265bdc345c7b514f.tar.bz2
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
Diffstat (limited to 'gcc/config/mips')
-rw-r--r--gcc/config/mips/mips-dsp.md9
-rw-r--r--gcc/config/mips/mips-protos.h5
-rw-r--r--gcc/config/mips/mips-ps-3d.md69
-rw-r--r--gcc/config/mips/mips.c443
-rw-r--r--gcc/config/mips/mips.h6
-rw-r--r--gcc/config/mips/mips.md100
-rw-r--r--gcc/config/mips/predicates.md3
7 files changed, 277 insertions, 358 deletions
diff --git a/gcc/config/mips/mips-dsp.md b/gcc/config/mips/mips-dsp.md
index a61b23f..3fdcc59 100644
--- a/gcc/config/mips/mips-dsp.md
+++ b/gcc/config/mips/mips-dsp.md
@@ -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")
diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h
index 9481b08..1dc31f5 100644
--- a/gcc/config/mips/mips-protos.h
+++ b/gcc/config/mips/mips-protos.h
@@ -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);
diff --git a/gcc/config/mips/mips-ps-3d.md b/gcc/config/mips/mips-ps-3d.md
index 17dd038..6a4c2b9 100644
--- a/gcc/config/mips/mips-ps-3d.md
+++ b/gcc/config/mips/mips-ps-3d.md
@@ -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.
;----------------------------------------------------------------------------
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index aed07e5..daa7488 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -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.
diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
index 8a993e0..b0ae120 100644
--- a/gcc/config/mips/mips.h
+++ b/gcc/config/mips/mips.h
@@ -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. */
diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
index 23677f0..01653d6 100644
--- a/gcc/config/mips/mips.md
+++ b/gcc/config/mips/mips.md
@@ -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)))])
;;
;; ....................
diff --git a/gcc/config/mips/predicates.md b/gcc/config/mips/predicates.md
index a96e017..d93621d 100644
--- a/gcc/config/mips/predicates.md
+++ b/gcc/config/mips/predicates.md
@@ -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")