aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog17
-rw-r--r--gcc/config/rs6000/predicates.md10
-rw-r--r--gcc/config/rs6000/rs6000-protos.h1
-rw-r--r--gcc/config/rs6000/rs6000.c98
-rw-r--r--gcc/config/rs6000/rs6000.md78
5 files changed, 147 insertions, 57 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index a4b4580..2525bcd 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,20 @@
+2019-11-21 Segher Boessenkool <segher@kernel.crashing.org>
+
+ * config/rs6000/predicates.md (extra_insn_branch_comparison_operator):
+ New predicate.
+ * config/rs6000/rs6000-protos.h (rs6000_emit_fp_cror): New declaration.
+ * config/rs6000/rs6000.c (rs6000_generate_compare): Don't do anything
+ special for FP comparisons that need a cror instruction eventually.
+ (rs6000_emit_fp_cror): New function.
+ (rs6000_emit_sCOND): Expand all floating point comparisons to one
+ instruction, for normal FP modes, with HONOR_NANS.
+ (rs6000_emit_cbranch): Reformat.
+ * config/rs6000/rs6000.md (fp_rev): New iterator.
+ (fp_two): New iterator.
+ *<code><mode>_cc for fp_rev and GPR: New define_insn_and_split.
+ *<code><mode>_cc for fp_two and GPR: New define_insn_and_split.
+ *cbranch_2insn: New define_insn_and_split.
+
2019-11-21 Richard Sandiford <richard.sandiford@arm.com>
PR tree-optimization/92526
diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md
index f4ecc41..42c41b3 100644
--- a/gcc/config/rs6000/predicates.md
+++ b/gcc/config/rs6000/predicates.md
@@ -1143,6 +1143,16 @@
GET_MODE (XEXP (op, 0))),
1")))
+;; Return 1 if OP is a comparison that needs an extra instruction to do (a
+;; crlogical or an extra branch).
+(define_predicate "extra_insn_branch_comparison_operator"
+ (and (match_operand 0 "comparison_operator")
+ (match_test "GET_MODE (XEXP (op, 0)) == CCFPmode")
+ (match_code "ltgt,le,ge,unlt,ungt,uneq")
+ (match_test "validate_condition_mode (GET_CODE (op),
+ GET_MODE (XEXP (op, 0))),
+ 1")))
+
;; Return 1 if OP is an unsigned comparison operator.
(define_predicate "unsigned_comparison_operator"
(match_code "ltu,gtu,leu,geu"))
diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
index 0dddb40..69e67ac 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -112,6 +112,7 @@ extern const char *rs6000_pltseq_template (rtx *, int);
extern enum rtx_code rs6000_reverse_condition (machine_mode,
enum rtx_code);
extern rtx rs6000_emit_eqne (machine_mode, rtx, rtx, rtx);
+extern rtx rs6000_emit_fp_cror (rtx_code, machine_mode, rtx);
extern void rs6000_emit_sCOND (machine_mode, rtx[]);
extern void rs6000_emit_cbranch (machine_mode, rtx[]);
extern char * output_cbranch (rtx, const char *, int, rtx_insn *);
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 0282ebd..2995348 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -13954,42 +13954,6 @@ rs6000_generate_compare (rtx cmp, machine_mode mode)
gen_rtx_COMPARE (comp_mode, op0, op1)));
}
- /* Some kinds of FP comparisons need an OR operation;
- under flag_finite_math_only we don't bother. */
- if (FLOAT_MODE_P (mode)
- && (!FLOAT128_IEEE_P (mode) || TARGET_FLOAT128_HW)
- && !flag_finite_math_only
- && (code == LE || code == GE
- || code == UNEQ || code == LTGT
- || code == UNGT || code == UNLT))
- {
- enum rtx_code or1, or2;
- rtx or1_rtx, or2_rtx, compare2_rtx;
- rtx or_result = gen_reg_rtx (CCEQmode);
-
- switch (code)
- {
- case LE: or1 = LT; or2 = EQ; break;
- case GE: or1 = GT; or2 = EQ; break;
- case UNEQ: or1 = UNORDERED; or2 = EQ; break;
- case LTGT: or1 = LT; or2 = GT; break;
- case UNGT: or1 = UNORDERED; or2 = GT; break;
- case UNLT: or1 = UNORDERED; or2 = LT; break;
- default: gcc_unreachable ();
- }
- validate_condition_mode (or1, comp_mode);
- validate_condition_mode (or2, comp_mode);
- or1_rtx = gen_rtx_fmt_ee (or1, SImode, compare_result, const0_rtx);
- or2_rtx = gen_rtx_fmt_ee (or2, SImode, compare_result, const0_rtx);
- compare2_rtx = gen_rtx_COMPARE (CCEQmode,
- gen_rtx_IOR (SImode, or1_rtx, or2_rtx),
- const_true_rtx);
- emit_insn (gen_rtx_SET (or_result, compare2_rtx));
-
- compare_result = or_result;
- code = EQ;
- }
-
validate_condition_mode (code, GET_MODE (compare_result));
return gen_rtx_fmt_ee (code, VOIDmode, compare_result, const0_rtx);
@@ -14301,21 +14265,44 @@ rs6000_emit_eqne (machine_mode mode, rtx op1, rtx op2, rtx scratch)
return scratch;
}
+/* Emit code doing a cror of two CR bits, for FP comparisons with a CODE that
+ requires this. The result is mode MODE. */
+rtx
+rs6000_emit_fp_cror (rtx_code code, machine_mode mode, rtx x)
+{
+ rtx cond[2];
+ int n = 0;
+ if (code == LTGT || code == LE || code == UNLT)
+ cond[n++] = gen_rtx_fmt_ee (LT, mode, x, const0_rtx);
+ if (code == LTGT || code == GE || code == UNGT)
+ cond[n++] = gen_rtx_fmt_ee (GT, mode, x, const0_rtx);
+ if (code == LE || code == GE || code == UNEQ)
+ cond[n++] = gen_rtx_fmt_ee (EQ, mode, x, const0_rtx);
+ if (code == UNLT || code == UNGT || code == UNEQ)
+ cond[n++] = gen_rtx_fmt_ee (UNORDERED, mode, x, const0_rtx);
+
+ gcc_assert (n == 2);
+
+ rtx cc = gen_reg_rtx (CCEQmode);
+ rtx logical = gen_rtx_IOR (mode, cond[0], cond[1]);
+ emit_insn (gen_cceq_ior_compare (mode, cc, logical, cond[0], x, cond[1], x));
+
+ return cc;
+}
+
void
rs6000_emit_sCOND (machine_mode mode, rtx operands[])
{
- rtx condition_rtx;
- machine_mode op_mode;
- enum rtx_code cond_code;
- rtx result = operands[0];
+ rtx condition_rtx = rs6000_generate_compare (operands[1], mode);
+ rtx_code cond_code = GET_CODE (condition_rtx);
- condition_rtx = rs6000_generate_compare (operands[1], mode);
- cond_code = GET_CODE (condition_rtx);
-
- if (cond_code == NE
- || cond_code == GE || cond_code == LE
- || cond_code == GEU || cond_code == LEU
- || cond_code == ORDERED || cond_code == UNGE || cond_code == UNLE)
+ if (FLOAT_MODE_P (mode) && HONOR_NANS (mode)
+ && !(FLOAT128_VECTOR_P (mode) && !TARGET_FLOAT128_HW))
+ ;
+ else if (cond_code == NE
+ || cond_code == GE || cond_code == LE
+ || cond_code == GEU || cond_code == LEU
+ || cond_code == ORDERED || cond_code == UNGE || cond_code == UNLE)
{
rtx not_result = gen_reg_rtx (CCEQmode);
rtx not_op, rev_cond_rtx;
@@ -14330,19 +14317,19 @@ rs6000_emit_sCOND (machine_mode mode, rtx operands[])
condition_rtx = gen_rtx_EQ (VOIDmode, not_result, const0_rtx);
}
- op_mode = GET_MODE (XEXP (operands[1], 0));
+ machine_mode op_mode = GET_MODE (XEXP (operands[1], 0));
if (op_mode == VOIDmode)
op_mode = GET_MODE (XEXP (operands[1], 1));
if (TARGET_POWERPC64 && (op_mode == DImode || FLOAT_MODE_P (mode)))
{
PUT_MODE (condition_rtx, DImode);
- convert_move (result, condition_rtx, 0);
+ convert_move (operands[0], condition_rtx, 0);
}
else
{
PUT_MODE (condition_rtx, SImode);
- emit_insn (gen_rtx_SET (result, condition_rtx));
+ emit_insn (gen_rtx_SET (operands[0], condition_rtx));
}
}
@@ -14351,13 +14338,10 @@ rs6000_emit_sCOND (machine_mode mode, rtx operands[])
void
rs6000_emit_cbranch (machine_mode mode, rtx operands[])
{
- rtx condition_rtx, loc_ref;
-
- condition_rtx = rs6000_generate_compare (operands[0], mode);
- loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands[3]);
- emit_jump_insn (gen_rtx_SET (pc_rtx,
- gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx,
- loc_ref, pc_rtx)));
+ rtx condition_rtx = rs6000_generate_compare (operands[0], mode);
+ rtx loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands[3]);
+ rtx ite = gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx, loc_ref, pc_rtx);
+ emit_jump_insn (gen_rtx_SET (pc_rtx, ite));
}
/* Return the string to output a conditional branch to LABEL, which is
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 8dc0a29..dff5680 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -12373,6 +12373,44 @@
(if_then_else (match_test "operands[2] == const0_rtx")
(const_string "12")
(const_string "16")))])
+
+
+(define_code_iterator fp_rev [ordered ne unle unge])
+(define_code_iterator fp_two [ltgt le ge unlt ungt uneq])
+
+(define_insn_and_split "*<code><mode>_cc"
+ [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
+ (fp_rev:GPR (match_operand:CCFP 1 "cc_reg_operand" "y")
+ (const_int 0)))]
+ "!flag_finite_math_only"
+ "#"
+ "&& 1"
+ [(pc)]
+{
+ rtx_code revcode = reverse_condition_maybe_unordered (<CODE>);
+ rtx eq = gen_rtx_fmt_ee (revcode, <MODE>mode, operands[1], const0_rtx);
+ rtx tmp = gen_reg_rtx (<MODE>mode);
+ emit_move_insn (tmp, eq);
+ emit_insn (gen_xor<mode>3 (operands[0], tmp, const1_rtx));
+ DONE;
+}
+ [(set_attr "length" "12")])
+
+(define_insn_and_split "*<code><mode>_cc"
+ [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
+ (fp_two:GPR (match_operand:CCFP 1 "cc_reg_operand" "y")
+ (const_int 0)))]
+ "!flag_finite_math_only"
+ "#"
+ "&& 1"
+ [(pc)]
+{
+ rtx cc = rs6000_emit_fp_cror (<CODE>, <MODE>mode, operands[1]);
+
+ emit_move_insn (operands[0], gen_rtx_EQ (<MODE>mode, cc, const0_rtx));
+ DONE;
+}
+ [(set_attr "length" "12")])
;; Conditional branches.
;; These either are a single bc insn, or a bc around a b.
@@ -12397,6 +12435,46 @@
(const_int 4)
(const_int 8)))])
+(define_insn_and_split "*cbranch_2insn"
+ [(set (pc)
+ (if_then_else (match_operator 1 "extra_insn_branch_comparison_operator"
+ [(match_operand 2 "cc_reg_operand" "y")
+ (const_int 0)])
+ (label_ref (match_operand 0))
+ (pc)))]
+ "!flag_finite_math_only"
+ "#"
+ "&& 1"
+ [(pc)]
+{
+ rtx cc = rs6000_emit_fp_cror (GET_CODE (operands[1]), SImode, operands[2]);
+
+ rtx note = find_reg_note (curr_insn, REG_BR_PROB, 0);
+
+ rtx loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands[0]);
+ rtx cond = gen_rtx_EQ (CCEQmode, cc, const0_rtx);
+ rtx ite = gen_rtx_IF_THEN_ELSE (VOIDmode, cond, loc_ref, pc_rtx);
+ emit_jump_insn (gen_rtx_SET (pc_rtx, ite));
+
+ if (note)
+ {
+ profile_probability prob
+ = profile_probability::from_reg_br_prob_note (XINT (note, 0));
+
+ add_reg_br_prob_note (get_last_insn (), prob);
+ }
+
+ DONE;
+}
+ [(set_attr "type" "branch")
+ (set (attr "length")
+ (if_then_else (and (ge (minus (match_dup 0) (pc))
+ (const_int -32764))
+ (lt (minus (match_dup 0) (pc))
+ (const_int 32760)))
+ (const_int 8)
+ (const_int 16)))])
+
;; Conditional return.
(define_insn "*creturn"
[(set (pc)