diff options
author | Paolo Bonzini <bonzini@gnu.org> | 2009-06-28 16:53:18 +0000 |
---|---|---|
committer | Paolo Bonzini <bonzini@gnu.org> | 2009-06-28 16:53:18 +0000 |
commit | 6b6cc2c7bf20d38ab7da014b2a03f6b2d53d8c7b (patch) | |
tree | abc948e110699df37c14ad5f3cb1c3013f065f80 | |
parent | 32f41621cd6235708dc942fb368eae84c7e3e9fc (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/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/builtins.c | 4 | ||||
-rw-r--r-- | gcc/dojump.c | 278 | ||||
-rw-r--r-- | gcc/expr.h | 2 |
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. */ |