aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Bonzini <bonzini@gnu.org>2009-06-28 16:53:18 +0000
committerPaolo Bonzini <bonzini@gnu.org>2009-06-28 16:53:18 +0000
commit6b6cc2c7bf20d38ab7da014b2a03f6b2d53d8c7b (patch)
treeabc948e110699df37c14ad5f3cb1c3013f065f80
parent32f41621cd6235708dc942fb368eae84c7e3e9fc (diff)
2009-06-28 Paolo Bonzini <bonzini@gnu.org>
* builtins.c (expand_errno_check): Use do_compare_rtx_and_jump. * dojump.c (do_jump): Change handling of floating-point ops to use just do_compare_and_jump. (split_comparison): New. (do_compare_rtx_and_jump): Add here logic coming previously in do_jump, using split_comparison. git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@149031 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog9
-rw-r--r--gcc/builtins.c4
-rw-r--r--gcc/dojump.c278
-rw-r--r--gcc/expr.h2
4 files changed, 194 insertions, 99 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 5abc31892dc..3a0cae38393 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,12 @@
+2009-06-28 Paolo Bonzini <bonzini@gnu.org>
+
+ * builtins.c (expand_errno_check): Use do_compare_rtx_and_jump.
+ * dojump.c (do_jump): Change handling of floating-point
+ ops to use just do_compare_and_jump.
+ (split_comparison): New.
+ (do_compare_rtx_and_jump): Add here logic coming previously
+ in do_jump, using split_comparison.
+
2009-06-27 H.J. Lu <hongjiu.lu@intel.com>
PR target/40489
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 7fdb4f03428..de1984e5ab5 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -1876,8 +1876,8 @@ expand_errno_check (tree exp, rtx target)
/* Test the result; if it is NaN, set errno=EDOM because
the argument was not in the domain. */
- emit_cmp_and_jump_insns (target, target, EQ, 0, GET_MODE (target),
- 0, lab);
+ do_compare_rtx_and_jump (target, target, EQ, 0, GET_MODE (target),
+ NULL_RTX, NULL_RTX, lab);
#ifdef TARGET_EDOM
/* If this built-in doesn't throw an exception, set errno directly. */
diff --git a/gcc/dojump.c b/gcc/dojump.c
index 76f62c62eba..131aaed977f 100644
--- a/gcc/dojump.c
+++ b/gcc/dojump.c
@@ -346,93 +346,39 @@ do_jump (tree exp, rtx if_false_label, rtx if_true_label)
do_compare_and_jump (exp, GE, GEU, if_false_label, if_true_label);
break;
- case UNORDERED_EXPR:
case ORDERED_EXPR:
- {
- enum rtx_code cmp, rcmp;
- int do_rev;
+ do_compare_and_jump (exp, ORDERED, ORDERED,
+ if_false_label, if_true_label);
+ break;
- if (code == UNORDERED_EXPR)
- cmp = UNORDERED, rcmp = ORDERED;
- else
- cmp = ORDERED, rcmp = UNORDERED;
- mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
-
- do_rev = 0;
- if (! can_compare_p (cmp, mode, ccp_jump)
- && (can_compare_p (rcmp, mode, ccp_jump)
- /* If the target doesn't provide either UNORDERED or ORDERED
- comparisons, canonicalize on UNORDERED for the library. */
- || rcmp == UNORDERED))
- do_rev = 1;
-
- if (! do_rev)
- do_compare_and_jump (exp, cmp, cmp, if_false_label, if_true_label);
- else
- do_compare_and_jump (exp, rcmp, rcmp, if_true_label, if_false_label);
- }
+ case UNORDERED_EXPR:
+ do_compare_and_jump (exp, UNORDERED, UNORDERED,
+ if_false_label, if_true_label);
break;
- {
- enum rtx_code rcode1;
- enum tree_code tcode1, tcode2;
-
- case UNLT_EXPR:
- rcode1 = UNLT;
- tcode1 = UNORDERED_EXPR;
- tcode2 = LT_EXPR;
- goto unordered_bcc;
- case UNLE_EXPR:
- rcode1 = UNLE;
- tcode1 = UNORDERED_EXPR;
- tcode2 = LE_EXPR;
- goto unordered_bcc;
- case UNGT_EXPR:
- rcode1 = UNGT;
- tcode1 = UNORDERED_EXPR;
- tcode2 = GT_EXPR;
- goto unordered_bcc;
- case UNGE_EXPR:
- rcode1 = UNGE;
- tcode1 = UNORDERED_EXPR;
- tcode2 = GE_EXPR;
- goto unordered_bcc;
- case UNEQ_EXPR:
- rcode1 = UNEQ;
- tcode1 = UNORDERED_EXPR;
- tcode2 = EQ_EXPR;
- goto unordered_bcc;
- case LTGT_EXPR:
- /* It is ok for LTGT_EXPR to trap when the result is unordered,
- so expand to (a < b) || (a > b). */
- rcode1 = LTGT;
- tcode1 = LT_EXPR;
- tcode2 = GT_EXPR;
- goto unordered_bcc;
-
- unordered_bcc:
- mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
- if (can_compare_p (rcode1, mode, ccp_jump))
- do_compare_and_jump (exp, rcode1, rcode1, if_false_label,
- if_true_label);
- else
- {
- tree op0 = save_expr (TREE_OPERAND (exp, 0));
- tree op1 = save_expr (TREE_OPERAND (exp, 1));
- tree cmp0, cmp1;
-
- /* If the target doesn't support combined unordered
- compares, decompose into two comparisons. */
- if (if_true_label == 0)
- drop_through_label = if_true_label = gen_label_rtx ();
-
- cmp0 = fold_build2 (tcode1, TREE_TYPE (exp), op0, op1);
- cmp1 = fold_build2 (tcode2, TREE_TYPE (exp), op0, op1);
- do_jump (cmp0, 0, if_true_label);
- do_jump (cmp1, if_false_label, if_true_label);
- }
+ case UNLT_EXPR:
+ do_compare_and_jump (exp, UNLT, UNLT, if_false_label, if_true_label);
+ break;
+
+ case UNLE_EXPR:
+ do_compare_and_jump (exp, UNLE, UNLE, if_false_label, if_true_label);
+ break;
+
+ case UNGT_EXPR:
+ do_compare_and_jump (exp, UNGT, UNGT, if_false_label, if_true_label);
+ break;
+
+ case UNGE_EXPR:
+ do_compare_and_jump (exp, UNGE, UNGE, if_false_label, if_true_label);
+ break;
+
+ case UNEQ_EXPR:
+ do_compare_and_jump (exp, UNEQ, UNEQ, if_false_label, if_true_label);
+ break;
+
+ case LTGT_EXPR:
+ do_compare_and_jump (exp, LTGT, LTGT, if_false_label, if_true_label);
break;
- }
case BIT_AND_EXPR:
/* fold_single_bit_test() converts (X & (1 << C)) into (X >> C) & 1.
@@ -756,6 +702,84 @@ do_jump_by_parts_equality (tree exp, rtx if_false_label, rtx if_true_label)
if_true_label);
}
+/* Split a comparison into two others, the second of which has the other
+ "orderedness". The first is always ORDERED or UNORDERED if MODE
+ does not honor NaNs (which means that it can be skipped in that case;
+ see do_compare_rtx_and_jump).
+
+ The two conditions are written in *CODE1 and *CODE2. Return true if
+ the conditions must be ANDed, false if they must be ORed. */
+
+bool
+split_comparison (enum rtx_code code, enum machine_mode mode,
+ enum rtx_code *code1, enum rtx_code *code2)
+{
+ switch (code)
+ {
+ case LT:
+ *code1 = ORDERED;
+ *code2 = UNLT;
+ return true;
+ case LE:
+ *code1 = ORDERED;
+ *code2 = UNLE;
+ return true;
+ case GT:
+ *code1 = ORDERED;
+ *code2 = UNGT;
+ return true;
+ case GE:
+ *code1 = ORDERED;
+ *code2 = UNGE;
+ return true;
+ case EQ:
+ *code1 = ORDERED;
+ *code2 = UNEQ;
+ return true;
+ case NE:
+ *code1 = UNORDERED;
+ *code2 = LTGT;
+ return false;
+ case UNLT:
+ *code1 = UNORDERED;
+ *code2 = LT;
+ return false;
+ case UNLE:
+ *code1 = UNORDERED;
+ *code2 = LE;
+ return false;
+ case UNGT:
+ *code1 = UNORDERED;
+ *code2 = GT;
+ return false;
+ case UNGE:
+ *code1 = UNORDERED;
+ *code2 = GE;
+ return false;
+ case UNEQ:
+ *code1 = UNORDERED;
+ *code2 = EQ;
+ return false;
+ case LTGT:
+ /* Do not turn a trapping comparison into a non-trapping one. */
+ if (HONOR_SNANS (mode))
+ {
+ *code1 = LT;
+ *code2 = GT;
+ return false;
+ }
+ else
+ {
+ *code1 = ORDERED;
+ *code2 = NE;
+ return true;
+ }
+ default:
+ gcc_unreachable ();
+ }
+}
+
+
/* Like do_compare_and_jump but expects the values to compare as two rtx's.
The decision as to signed or unsigned comparison must be made by the caller.
@@ -768,15 +792,33 @@ do_compare_rtx_and_jump (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
rtx if_true_label)
{
rtx tem;
- int dummy_true_label = 0;
+ rtx dummy_label = NULL_RTX;
/* Reverse the comparison if that is safe and we want to jump if it is
- false. */
- if (! if_true_label && ! FLOAT_MODE_P (mode))
+ false. Also convert to the reverse comparison if the target can
+ implement it. */
+ if ((! if_true_label
+ || ! can_compare_p (code, mode, ccp_jump))
+ && (! FLOAT_MODE_P (mode)
+ || code == ORDERED || code == UNORDERED
+ || (! HONOR_NANS (mode) && (code == LTGT || code == UNEQ))
+ || (! HONOR_SNANS (mode) && (code == EQ || code == NE))))
{
- if_true_label = if_false_label;
- if_false_label = 0;
- code = reverse_condition (code);
+ enum rtx_code rcode;
+ if (FLOAT_MODE_P (mode))
+ rcode = reverse_condition_maybe_unordered (code);
+ else
+ rcode = reverse_condition (code);
+
+ /* Canonicalize to UNORDERED for the libcall. */
+ if (can_compare_p (rcode, mode, ccp_jump)
+ || (code == ORDERED && ! can_compare_p (ORDERED, mode, ccp_jump)))
+ {
+ tem = if_true_label;
+ if_true_label = if_false_label;
+ if_false_label = tem;
+ code = rcode;
+ }
}
/* If one operand is constant, make it the second one. Only do this
@@ -812,12 +854,8 @@ do_compare_rtx_and_jump (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
unsignedp = (code == GTU || code == LTU || code == GEU || code == LEU);
}
-
if (! if_true_label)
- {
- dummy_true_label = 1;
- if_true_label = gen_label_rtx ();
- }
+ dummy_label = if_true_label = gen_label_rtx ();
if (GET_MODE_CLASS (mode) == MODE_INT
&& ! can_compare_p (code, mode, ccp_jump))
@@ -879,13 +917,59 @@ do_compare_rtx_and_jump (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
}
}
else
- emit_cmp_and_jump_insns (op0, op1, code, size, mode, unsignedp,
- if_true_label);
+ {
+ if (GET_MODE_CLASS (mode) == MODE_FLOAT
+ && ! can_compare_p (code, mode, ccp_jump)
+
+ /* Never split ORDERED and UNORDERED. These must be implemented. */
+ && (code != ORDERED && code != UNORDERED)
+
+ /* Split a floating-point comparison if we can jump on other
+ conditions... */
+ && (have_insn_for (COMPARE, mode)
+
+ /* ... or if there is no libcall for it. */
+ || code_to_optab[code] == NULL))
+ {
+ enum rtx_code first_code;
+ bool and_them = split_comparison (code, mode, &first_code, &code);
+
+ /* If there are no NaNs, the first comparison should always fall
+ through. */
+ if (!HONOR_NANS (mode))
+ gcc_assert (first_code == (and_them ? ORDERED : UNORDERED));
+
+ else
+ {
+ if (and_them)
+ {
+ rtx dest_label;
+ /* If we only jump if true, just bypass the second jump. */
+ if (! if_false_label)
+ {
+ if (! dummy_label)
+ dummy_label = gen_label_rtx ();
+ dest_label = dummy_label;
+ }
+ else
+ dest_label = if_false_label;
+ do_compare_rtx_and_jump (op0, op1, first_code, unsignedp, mode,
+ size, dest_label, NULL_RTX);
+ }
+ else
+ do_compare_rtx_and_jump (op0, op1, first_code, unsignedp, mode,
+ size, NULL_RTX, if_true_label);
+ }
+ }
+
+ emit_cmp_and_jump_insns (op0, op1, code, size, mode, unsignedp,
+ if_true_label);
+ }
if (if_false_label)
emit_jump (if_false_label);
- if (dummy_true_label)
- emit_label (if_true_label);
+ if (dummy_label)
+ emit_label (dummy_label);
}
/* Generate code for a comparison expression EXP (including code to compute
diff --git a/gcc/expr.h b/gcc/expr.h
index 64794834771..caf965e9412 100644
--- a/gcc/expr.h
+++ b/gcc/expr.h
@@ -774,6 +774,8 @@ extern rtx expand_mult_highpart_adjust (enum machine_mode, rtx, rtx, rtx, rtx, i
extern rtx assemble_static_space (unsigned HOST_WIDE_INT);
extern int safe_from_p (const_rtx, tree, int);
+extern bool split_comparison (enum rtx_code, enum machine_mode,
+ enum rtx_code *, enum rtx_code *);
/* Call this once to initialize the contents of the optabs
appropriately for the current target machine. */