Commit eb548534 by Segher Boessenkool Committed by Segher Boessenkool

rs6000: Don't split FP comparisons at expand time

We currently expand various floating point comparisons early, to some
sequences with cror insns and the like.  This doesn't optimize well.

Change that to allow any of the 14 floating point comparisons in the
instruction stream, and split them after combine (at split1).


	* 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.

From-SVN: r278593
parent 557532d1
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> 2019-11-21 Richard Sandiford <richard.sandiford@arm.com>
PR tree-optimization/92526 PR tree-optimization/92526
...@@ -1143,6 +1143,16 @@ ...@@ -1143,6 +1143,16 @@
GET_MODE (XEXP (op, 0))), GET_MODE (XEXP (op, 0))),
1"))) 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. ;; Return 1 if OP is an unsigned comparison operator.
(define_predicate "unsigned_comparison_operator" (define_predicate "unsigned_comparison_operator"
(match_code "ltu,gtu,leu,geu")) (match_code "ltu,gtu,leu,geu"))
......
...@@ -112,6 +112,7 @@ extern const char *rs6000_pltseq_template (rtx *, int); ...@@ -112,6 +112,7 @@ extern const char *rs6000_pltseq_template (rtx *, int);
extern enum rtx_code rs6000_reverse_condition (machine_mode, extern enum rtx_code rs6000_reverse_condition (machine_mode,
enum rtx_code); enum rtx_code);
extern rtx rs6000_emit_eqne (machine_mode, rtx, rtx, rtx); 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_sCOND (machine_mode, rtx[]);
extern void rs6000_emit_cbranch (machine_mode, rtx[]); extern void rs6000_emit_cbranch (machine_mode, rtx[]);
extern char * output_cbranch (rtx, const char *, int, rtx_insn *); extern char * output_cbranch (rtx, const char *, int, rtx_insn *);
......
...@@ -13954,42 +13954,6 @@ rs6000_generate_compare (rtx cmp, machine_mode mode) ...@@ -13954,42 +13954,6 @@ rs6000_generate_compare (rtx cmp, machine_mode mode)
gen_rtx_COMPARE (comp_mode, op0, op1))); 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)); validate_condition_mode (code, GET_MODE (compare_result));
return gen_rtx_fmt_ee (code, VOIDmode, compare_result, const0_rtx); 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) ...@@ -14301,21 +14265,44 @@ rs6000_emit_eqne (machine_mode mode, rtx op1, rtx op2, rtx scratch)
return 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 void
rs6000_emit_sCOND (machine_mode mode, rtx operands[]) rs6000_emit_sCOND (machine_mode mode, rtx operands[])
{ {
rtx condition_rtx; rtx condition_rtx = rs6000_generate_compare (operands[1], mode);
machine_mode op_mode; rtx_code cond_code = GET_CODE (condition_rtx);
enum rtx_code cond_code;
rtx result = operands[0];
condition_rtx = rs6000_generate_compare (operands[1], mode); if (FLOAT_MODE_P (mode) && HONOR_NANS (mode)
cond_code = GET_CODE (condition_rtx); && !(FLOAT128_VECTOR_P (mode) && !TARGET_FLOAT128_HW))
;
if (cond_code == NE else if (cond_code == NE
|| cond_code == GE || cond_code == LE || cond_code == GE || cond_code == LE
|| cond_code == GEU || cond_code == LEU || cond_code == GEU || cond_code == LEU
|| cond_code == ORDERED || cond_code == UNGE || cond_code == UNLE) || cond_code == ORDERED || cond_code == UNGE || cond_code == UNLE)
{ {
rtx not_result = gen_reg_rtx (CCEQmode); rtx not_result = gen_reg_rtx (CCEQmode);
rtx not_op, rev_cond_rtx; rtx not_op, rev_cond_rtx;
...@@ -14330,19 +14317,19 @@ rs6000_emit_sCOND (machine_mode mode, rtx operands[]) ...@@ -14330,19 +14317,19 @@ rs6000_emit_sCOND (machine_mode mode, rtx operands[])
condition_rtx = gen_rtx_EQ (VOIDmode, not_result, const0_rtx); 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) if (op_mode == VOIDmode)
op_mode = GET_MODE (XEXP (operands[1], 1)); op_mode = GET_MODE (XEXP (operands[1], 1));
if (TARGET_POWERPC64 && (op_mode == DImode || FLOAT_MODE_P (mode))) if (TARGET_POWERPC64 && (op_mode == DImode || FLOAT_MODE_P (mode)))
{ {
PUT_MODE (condition_rtx, DImode); PUT_MODE (condition_rtx, DImode);
convert_move (result, condition_rtx, 0); convert_move (operands[0], condition_rtx, 0);
} }
else else
{ {
PUT_MODE (condition_rtx, SImode); 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[]) ...@@ -14351,13 +14338,10 @@ rs6000_emit_sCOND (machine_mode mode, rtx operands[])
void void
rs6000_emit_cbranch (machine_mode mode, rtx operands[]) rs6000_emit_cbranch (machine_mode mode, rtx operands[])
{ {
rtx condition_rtx, loc_ref; rtx condition_rtx = rs6000_generate_compare (operands[0], mode);
rtx loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands[3]);
condition_rtx = rs6000_generate_compare (operands[0], mode); rtx ite = gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx, loc_ref, pc_rtx);
loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands[3]); emit_jump_insn (gen_rtx_SET (pc_rtx, ite));
emit_jump_insn (gen_rtx_SET (pc_rtx,
gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx,
loc_ref, pc_rtx)));
} }
/* Return the string to output a conditional branch to LABEL, which is /* Return the string to output a conditional branch to LABEL, which is
......
...@@ -12373,6 +12373,44 @@ ...@@ -12373,6 +12373,44 @@
(if_then_else (match_test "operands[2] == const0_rtx") (if_then_else (match_test "operands[2] == const0_rtx")
(const_string "12") (const_string "12")
(const_string "16")))]) (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. ;; Conditional branches.
;; These either are a single bc insn, or a bc around a b. ;; These either are a single bc insn, or a bc around a b.
...@@ -12397,6 +12435,46 @@ ...@@ -12397,6 +12435,46 @@
(const_int 4) (const_int 4)
(const_int 8)))]) (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. ;; Conditional return.
(define_insn "*creturn" (define_insn "*creturn"
[(set (pc) [(set (pc)
......
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