--- /dev/null
+/* { dg-do run } */
+/* { dg-require-effective-target fenv_exceptions } */
+
+#include <fenv.h>
+#include <math.h>
+#include <errno.h>
+
+extern void abort (void) __attribute__ ((noreturn));
+
+#define LARGE_NEG_MAYBE_ERANGE 0x01
+#define LARGE_NEG_ERANGE 0x02
+#define LARGE_POS_ERANGE 0x04
+#define LARGE_NEG_EDOM 0x08
+#define LARGE_POS_EDOM 0x10
+
+#define LARGE_ERANGE (LARGE_NEG_ERANGE | LARGE_POS_ERANGE)
+#define LARGE_EDOM (LARGE_NEG_EDOM | LARGE_POS_EDOM)
+#define POWER_ERANGE (LARGE_NEG_MAYBE_ERANGE | LARGE_POS_ERANGE)
+
+#define TEST(CALL, FLAGS) (CALL, tester (FLAGS))
+
+volatile double d;
+volatile int i;
+
+static void (*tester) (int);
+
+void
+check_quiet_nan (int flags __attribute__ ((unused)))
+{
+ if (fetestexcept (FE_ALL_EXCEPT))
+ abort ();
+ if (errno)
+ abort ();
+}
+
+void
+check_large_neg (int flags)
+{
+ if (flags & LARGE_NEG_MAYBE_ERANGE)
+ return;
+ int expected_errno = (flags & LARGE_NEG_ERANGE ? ERANGE
+ : flags & LARGE_NEG_EDOM ? EDOM
+ : 0);
+ if (expected_errno != errno)
+ abort ();
+ errno = 0;
+}
+
+void
+check_large_pos (int flags)
+{
+ int expected_errno = (flags & LARGE_POS_ERANGE ? ERANGE
+ : flags & LARGE_POS_EDOM ? EDOM
+ : 0);
+ if (expected_errno != errno)
+ abort ();
+ errno = 0;
+}
+
+void
+test (void)
+{
+ TEST (acos (d), LARGE_EDOM);
+ TEST (asin (d), LARGE_EDOM);
+ TEST (acosh (d), LARGE_NEG_EDOM);
+ TEST (atanh (d), LARGE_EDOM);
+ TEST (cosh (d), LARGE_ERANGE);
+ TEST (sinh (d), LARGE_ERANGE);
+ TEST (log (d), LARGE_NEG_EDOM);
+ TEST (log2 (d), LARGE_NEG_EDOM);
+ TEST (log10 (d), LARGE_NEG_EDOM);
+ /* Disabled due to glibc PR 6792, fixed in Apr 2015. */
+ if (0)
+ TEST (log1p (d), LARGE_NEG_EDOM);
+ TEST (exp (d), POWER_ERANGE);
+ TEST (exp2 (d), POWER_ERANGE);
+ TEST (expm1 (d), POWER_ERANGE);
+ TEST (sqrt (d), LARGE_NEG_EDOM);
+ TEST (pow (100.0, d), POWER_ERANGE);
+ TEST (pow (i, d), POWER_ERANGE);
+}
+
+int
+main (void)
+{
+ errno = 0;
+ i = 100;
+ d = __builtin_nan ("");
+ tester = check_quiet_nan;
+ feclearexcept (FE_ALL_EXCEPT);
+ test ();
+
+ d = -1.0e80;
+ tester = check_large_neg;
+ errno = 0;
+ test ();
+
+ d = 1.0e80;
+ tester = check_large_pos;
+ errno = 0;
+ test ();
+
+ return 0;
+}
built_in_call (args)
An actual simple example is :
- log (x); // Mostly dead call
+ log (x); // Mostly dead call
==>
- if (x <= 0)
- log (x);
+ if (__builtin_islessequal (x, 0))
+ log (x);
+
With this change, call to log (x) is effectively eliminated, as
in majority of the cases, log won't be called with x out of
range. The branch is totally predictable, so the branch cost
}
\f
-/* A helper function to generate gimple statements for
- one bound comparison. ARG is the call argument to
- be compared with the bound, LBUB is the bound value
- in integer, TCODE is the tree_code of the comparison,
- TEMP_NAME1/TEMP_NAME2 are names of the temporaries,
- CONDS is a vector holding the produced GIMPLE statements,
- and NCONDS points to the variable holding the number
- of logical comparisons. CONDS is either empty or
- a list ended with a null tree. */
+/* A helper function to generate gimple statements for one bound
+ comparison, so that the built-in function is called whenever
+ TCODE <ARG, LBUB> is *false*. TEMP_NAME1/TEMP_NAME2 are names
+ of the temporaries, CONDS is a vector holding the produced GIMPLE
+ statements, and NCONDS points to the variable holding the number of
+ logical comparisons. CONDS is either empty or a list ended with a
+ null tree. */
static void
gen_one_condition (tree arg, int lbub,
if (domain.has_lb)
gen_one_condition (arg, domain.lb,
(domain.is_lb_inclusive
- ? LT_EXPR : LE_EXPR),
+ ? UNGE_EXPR : UNGT_EXPR),
"DCE_COND_LB", "DCE_COND_LB_TEST",
conds, nconds);
gen_one_condition (arg, domain.ub,
(domain.is_ub_inclusive
- ? GT_EXPR : GE_EXPR),
+ ? UNLE_EXPR : UNLT_EXPR),
"DCE_COND_UB", "DCE_COND_UB_TEST",
conds, nconds);
}
See candidate selection in check_pow. Since the
candidates' base values have a limited range,
the guarded code generated for y are simple:
- if (y > max_y)
+ if (__builtin_isgreater (y, max_y))
pow (const, y);
Note max_y can be computed separately for each
const base, but in this implementation, we
/* For pow ((double)x, y), generate the following conditions:
cond 1:
temp1 = x;
- if (temp1 <= 0)
+ if (__builtin_islessequal (temp1, 0))
cond 2:
temp2 = y;
- if (temp2 > max_exp_real_cst) */
+ if (__builtin_isgreater (temp2, max_exp_real_cst)) */
/* Generate condition in reverse order -- first
the condition for the exp argument. */
stmt1 = gimple_build_assign (temp, base_val0);
tempn = make_ssa_name (temp, stmt1);
gimple_assign_set_lhs (stmt1, tempn);
- stmt2 = gimple_build_cond (LE_EXPR, tempn, cst0, NULL_TREE, NULL_TREE);
+ stmt2 = gimple_build_cond (GT_EXPR, tempn, cst0, NULL_TREE, NULL_TREE);
conds.quick_push (stmt1);
conds.quick_push (stmt2);
bi_call_in_edge0 = split_block (bi_call_bb, cond_expr);
bi_call_in_edge0->flags &= ~EDGE_FALLTHRU;
- bi_call_in_edge0->flags |= EDGE_TRUE_VALUE;
+ bi_call_in_edge0->flags |= EDGE_FALSE_VALUE;
guard_bb = bi_call_bb;
bi_call_bb = bi_call_in_edge0->dest;
join_tgt_in_edge_fall_thru = make_edge (guard_bb, join_tgt_bb,
- EDGE_FALSE_VALUE);
+ EDGE_TRUE_VALUE);
bi_call_in_edge0->probability = REG_BR_PROB_BASE * ERR_PROB;
bi_call_in_edge0->count =
gcc_assert (cond_expr && gimple_code (cond_expr) == GIMPLE_COND);
guard_bb_in_edge = split_block (guard_bb, cond_expr);
guard_bb_in_edge->flags &= ~EDGE_FALLTHRU;
- guard_bb_in_edge->flags |= EDGE_FALSE_VALUE;
+ guard_bb_in_edge->flags |= EDGE_TRUE_VALUE;
- bi_call_in_edge = make_edge (guard_bb, bi_call_bb, EDGE_TRUE_VALUE);
+ bi_call_in_edge = make_edge (guard_bb, bi_call_bb, EDGE_FALSE_VALUE);
bi_call_in_edge->probability = REG_BR_PROB_BASE * ERR_PROB;
bi_call_in_edge->count =