#ifndef PAD_VARARGS_DOWN
#define PAD_VARARGS_DOWN BYTES_BIG_ENDIAN
#endif
+#ifdef HAVE_mpc
+static tree do_mpc_arg1 (tree, tree, int (*)(mpc_ptr, mpc_srcptr, mpc_rnd_t));
+#endif
/* Define the names of the builtin function types and codes. */
const char *const built_in_class_names[4]
gcc_assert (TREE_CODE (inner) == COMPONENT_REF);
if (MEM_OFFSET (mem)
- && GET_CODE (MEM_OFFSET (mem)) == CONST_INT)
+ && CONST_INT_P (MEM_OFFSET (mem)))
offset = INTVAL (MEM_OFFSET (mem));
if (offset >= 0 && len && host_integerp (len, 0))
dest = virtual_outgoing_args_rtx;
#ifndef STACK_GROWS_DOWNWARD
- if (GET_CODE (argsize) == CONST_INT)
+ if (CONST_INT_P (argsize))
dest = plus_constant (dest, -INTVAL (argsize));
else
dest = gen_rtx_PLUS (Pmode, dest, negate_rtx (Pmode, argsize));
/* 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. */
/* Else fallthrough and expand as rint. */
CASE_FLT_FN (BUILT_IN_RINT):
builtin_optab = rint_optab; break;
+ CASE_FLT_FN (BUILT_IN_SIGNIFICAND):
+ builtin_optab = significand_optab; break;
default:
gcc_unreachable ();
}
by pieces, we can avoid loading the string from memory
and only stored the computed constants. */
if (src_str
- && GET_CODE (len_rtx) == CONST_INT
+ && CONST_INT_P (len_rtx)
&& (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
&& can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
CONST_CAST (char *, src_str),
by pieces, we can avoid loading the string from memory
and only stored the computed constants. */
if (src_str
- && GET_CODE (len_rtx) == CONST_INT
+ && CONST_INT_P (len_rtx)
&& (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
&& can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
CONST_CAST (char *, src_str),
return dest_mem;
}
- if (GET_CODE (len_rtx) == CONST_INT
+ if (CONST_INT_P (len_rtx)
&& can_move_by_pieces (INTVAL (len_rtx),
MIN (dest_align, src_align)))
{
{
rtx len_rtx = expand_normal (len);
- if (GET_CODE (len_rtx) == CONST_INT)
+ if (CONST_INT_P (len_rtx))
{
ret = expand_builtin_strcpy_args (get_callee_fndecl (exp),
dst, src, target, mode);
arg1_rtx = get_memory_rtx (arg1, len);
arg2_rtx = get_memory_rtx (arg2, len);
- arg3_rtx = expand_normal (len);
+ arg3_rtx = expand_normal (fold_convert (sizetype, len));
/* Set MEM_SIZE as appropriate. */
- if (GET_CODE (arg3_rtx) == CONST_INT)
+ if (CONST_INT_P (arg3_rtx))
{
set_mem_size (arg1_rtx, arg3_rtx);
set_mem_size (arg2_rtx, arg3_rtx);
tree valist = TREE_OPERAND (*expr_p, 0);
tree type = TREE_TYPE (*expr_p);
tree t;
+ location_t loc = EXPR_HAS_LOCATION (*expr_p) ? EXPR_LOCATION (*expr_p) :
+ UNKNOWN_LOCATION;
/* Verify that valist is of the proper type. */
have_va_type = TREE_TYPE (valist);
if (have_va_type == NULL_TREE)
{
- error ("first argument to %<va_arg%> not of type %<va_list%>");
+ error_at (loc, "first argument to %<va_arg%> not of type %<va_list%>");
return GS_ERROR;
}
/* Unfortunately, this is merely undefined, rather than a constraint
violation, so we cannot make this an error. If this call is never
executed, the program is still strictly conforming. */
- warned = warning (0, "%qT is promoted to %qT when passed through %<...%>",
- type, promoted_type);
+ warned = warning_at (loc, 0,
+ "%qT is promoted to %qT when passed through %<...%>",
+ type, promoted_type);
if (!gave_help && warned)
{
gave_help = true;
- inform (input_location, "(so you should pass %qT not %qT to %<va_arg%>)",
- promoted_type, type);
+ inform (loc, "(so you should pass %qT not %qT to %<va_arg%>)",
+ promoted_type, type);
}
/* We can, however, treat "undefined" any way we please.
Call abort to encourage the user to fix the program. */
if (warned)
- inform (input_location, "if this code is reached, the program will abort");
+ inform (loc, "if this code is reached, the program will abort");
/* Before the abort, allow the evaluation of the va_list
expression to exit or longjmp. */
gimplify_and_add (valist, pre_p);
if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE)
{
tree p1 = build_pointer_type (TREE_TYPE (have_va_type));
- valist = build_fold_addr_expr_with_type (valist, p1);
+ valist = fold_convert (p1, build_fold_addr_expr (valist));
}
gimplify_expr (&valist, pre_p, post_p, is_gimple_val, fb_rvalue);
rtx op0;
rtx result;
- /* In -fmudflap-instrumented code, alloca() and __builtin_alloca()
- should always expand to function calls. These can be intercepted
- in libmudflap. */
- if (flag_mudflap)
+ /* Emit normal call if marked not-inlineable. */
+ if (CALL_CANNOT_INLINE_P (exp))
return NULL_RTX;
if (!validate_arglist (exp, INTEGER_TYPE, VOID_TYPE))
emit_barrier ();
}
+/* Expand a call to __builtin_unreachable. We do nothing except emit
+ a barrier saying that control flow will not pass here.
+
+ It is the responsibility of the program being compiled to ensure
+ that control flow does never reach __builtin_unreachable. */
+static void
+expand_builtin_unreachable (void)
+{
+ emit_barrier ();
+}
+
/* Expand EXP, a call to fabs, fabsf or fabsl.
Return NULL_RTX if a normal call should be emitted rather than expanding
the function inline. If convenient, the result should be placed
gcc_unreachable ();
}
- decl = build_decl (FUNCTION_DECL, id, TREE_TYPE (fn));
+ decl = build_decl (DECL_SOURCE_LOCATION (fn),
+ FUNCTION_DECL, id, TREE_TYPE (fn));
DECL_EXTERNAL (decl) = 1;
TREE_PUBLIC (decl) = 1;
DECL_ARTIFICIAL (decl) = 1;
{
rtx val, mem;
enum machine_mode old_mode;
+ location_t loc = EXPR_LOCATION (exp);
if (code == NOT && warn_sync_nand)
{
break;
fndecl = implicit_built_in_decls[BUILT_IN_FETCH_AND_NAND_N];
- inform (input_location,
- "%qD changed semantics in GCC 4.4", fndecl);
+ inform (loc, "%qD changed semantics in GCC 4.4", fndecl);
warned_f_a_n = true;
break;
break;
fndecl = implicit_built_in_decls[BUILT_IN_NAND_AND_FETCH_N];
- inform (input_location,
- "%qD changed semantics in GCC 4.4", fndecl);
+ inform (loc, "%qD changed semantics in GCC 4.4", fndecl);
warned_n_a_f = true;
break;
CASE_FLT_FN (BUILT_IN_ASIN):
CASE_FLT_FN (BUILT_IN_ACOS):
CASE_FLT_FN (BUILT_IN_ATAN):
+ CASE_FLT_FN (BUILT_IN_SIGNIFICAND):
/* Treat these like sqrt only if unsafe math optimizations are allowed,
because of possible accuracy problems. */
if (! flag_unsafe_math_optimizations)
expand_builtin_trap ();
return const0_rtx;
+ case BUILT_IN_UNREACHABLE:
+ expand_builtin_unreachable ();
+ return const0_rtx;
+
case BUILT_IN_PRINTF:
target = expand_builtin_printf (exp, target, mode, false);
if (target)
return NULL_TREE;
}
+/* Fold function call to builtin ccos (or ccosh if HYPER is TRUE) with
+ argument ARG. TYPE is the type of the return value. Return
+ NULL_TREE if no simplification can be made. */
+
+static tree
+fold_builtin_ccos (tree arg, tree type ATTRIBUTE_UNUSED, tree fndecl,
+ bool hyper ATTRIBUTE_UNUSED)
+{
+ if (validate_arg (arg, COMPLEX_TYPE)
+ && TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) == REAL_TYPE)
+ {
+ tree tmp;
+
+#ifdef HAVE_mpc
+ /* Calculate the result when the argument is a constant. */
+ if ((tmp = do_mpc_arg1 (arg, type, (hyper ? mpc_cosh : mpc_cos))))
+ return tmp;
+#endif
+
+ /* Optimize fn(-x) into fn(x). */
+ if ((tmp = fold_strip_sign_ops (arg)))
+ return build_call_expr (fndecl, 1, tmp);
+ }
+
+ return NULL_TREE;
+}
+
/* Fold function call to builtin tan, tanf, or tanl with argument ARG.
Return NULL_TREE if no simplification can be made. */
{
tree rtype;
tree realp, imagp, ifn;
+#ifdef HAVE_mpc
+ tree res;
+#endif
- if (!validate_arg (arg0, COMPLEX_TYPE))
+ if (!validate_arg (arg0, COMPLEX_TYPE)
+ && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
return NULL_TREE;
+#ifdef HAVE_mpc
+ /* Calculate the result when the argument is a constant. */
+ if ((res = do_mpc_arg1 (arg0, type, mpc_exp)))
+ return res;
+#endif
+
rtype = TREE_TYPE (TREE_TYPE (arg0));
/* In case we can figure out the real part of arg0 and it is constant zero
}
srctype = TREE_TYPE (TREE_TYPE (src));
if (srctype
- && TREE_CODE (srctype) == ARRAY_TYPE)
+ && TREE_CODE (srctype) == ARRAY_TYPE
+ && !tree_int_cst_equal (TYPE_SIZE_UNIT (srctype), len))
{
srctype = TREE_TYPE (srctype);
STRIP_NOPS (src);
}
desttype = TREE_TYPE (TREE_TYPE (dest));
if (desttype
- && TREE_CODE (desttype) == ARRAY_TYPE)
+ && TREE_CODE (desttype) == ARRAY_TYPE
+ && !tree_int_cst_equal (TYPE_SIZE_UNIT (desttype), len))
{
desttype = TREE_TYPE (desttype);
STRIP_NOPS (dest);
static tree
fold_builtin_carg (tree arg, tree type)
{
- if (validate_arg (arg, COMPLEX_TYPE))
+ if (validate_arg (arg, COMPLEX_TYPE)
+ && TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) == REAL_TYPE)
{
tree atan2_fn = mathfn_built_in (type, BUILT_IN_ATAN2);
return fold_builtin_abs (arg0, type);
CASE_FLT_FN (BUILT_IN_CONJ):
- if (validate_arg (arg0, COMPLEX_TYPE))
+ if (validate_arg (arg0, COMPLEX_TYPE)
+ && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
return fold_build1 (CONJ_EXPR, type, arg0);
break;
CASE_FLT_FN (BUILT_IN_CREAL):
- if (validate_arg (arg0, COMPLEX_TYPE))
+ if (validate_arg (arg0, COMPLEX_TYPE)
+ && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
return non_lvalue (fold_build1 (REALPART_EXPR, type, arg0));;
break;
break;
CASE_FLT_FN (BUILT_IN_CCOS):
+ return fold_builtin_ccos(arg0, type, fndecl, /*hyper=*/ false);
+
CASE_FLT_FN (BUILT_IN_CCOSH):
- /* These functions are "even", i.e. f(x) == f(-x). */
- if (validate_arg (arg0, COMPLEX_TYPE))
- {
- tree narg = fold_strip_sign_ops (arg0);
- if (narg)
- return build_call_expr (fndecl, 1, narg);
- }
+ return fold_builtin_ccos(arg0, type, fndecl, /*hyper=*/ true);
+
+#ifdef HAVE_mpc
+ CASE_FLT_FN (BUILT_IN_CSIN):
+ if (validate_arg (arg0, COMPLEX_TYPE)
+ && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
+ return do_mpc_arg1 (arg0, type, mpc_sin);
break;
-
+
+ CASE_FLT_FN (BUILT_IN_CSINH):
+ if (validate_arg (arg0, COMPLEX_TYPE)
+ && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
+ return do_mpc_arg1 (arg0, type, mpc_sinh);
+ break;
+
+ CASE_FLT_FN (BUILT_IN_CTAN):
+ if (validate_arg (arg0, COMPLEX_TYPE)
+ && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
+ return do_mpc_arg1 (arg0, type, mpc_tan);
+ break;
+
+ CASE_FLT_FN (BUILT_IN_CTANH):
+ if (validate_arg (arg0, COMPLEX_TYPE)
+ && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
+ return do_mpc_arg1 (arg0, type, mpc_tanh);
+ break;
+
+ CASE_FLT_FN (BUILT_IN_CLOG):
+ if (validate_arg (arg0, COMPLEX_TYPE)
+ && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
+ return do_mpc_arg1 (arg0, type, mpc_log);
+ break;
+
+ CASE_FLT_FN (BUILT_IN_CSQRT):
+ if (validate_arg (arg0, COMPLEX_TYPE)
+ && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
+ return do_mpc_arg1 (arg0, type, mpc_sqrt);
+ break;
+#endif
+
CASE_FLT_FN (BUILT_IN_CABS):
return fold_builtin_cabs (arg0, type, fndecl);
CASE_FLT_FN (BUILT_IN_COS):
return fold_builtin_cos (arg0, type, fndecl);
- break;
CASE_FLT_FN (BUILT_IN_TAN):
return fold_builtin_tan (arg0, type);
do
{
- code = va_arg (ap, enum tree_code);
+ code = (enum tree_code) va_arg (ap, int);
switch (code)
{
case 0:
do
{
- code = va_arg (ap, enum tree_code);
+ code = (enum tree_code) va_arg (ap, int);
switch (code)
{
case 0:
return NULL_TREE;
}
+#ifdef HAVE_mpc
+/* Helper function for do_mpc_arg*(). Ensure M is a normal complex
+ number and no overflow/underflow occurred. INEXACT is true if M
+ was not exactly calculated. TYPE is the tree type for the result.
+ This function assumes that you cleared the MPFR flags and then
+ calculated M to see if anything subsequently set a flag prior to
+ entering this function. Return NULL_TREE if any checks fail. */
+
+static tree
+do_mpc_ckconv (mpc_srcptr m, tree type, int inexact)
+{
+ /* Proceed iff we get a normal number, i.e. not NaN or Inf and no
+ overflow/underflow occurred. If -frounding-math, proceed iff the
+ result of calling FUNC was exact. */
+ if (mpfr_number_p (mpc_realref (m)) && mpfr_number_p (mpc_imagref (m))
+ && !mpfr_overflow_p () && !mpfr_underflow_p ()
+ && (!flag_rounding_math || !inexact))
+ {
+ REAL_VALUE_TYPE re, im;
+
+ real_from_mpfr (&re, mpc_realref (m), type, GMP_RNDN);
+ real_from_mpfr (&im, mpc_imagref (m), type, GMP_RNDN);
+ /* Proceed iff GCC's REAL_VALUE_TYPE can hold the MPFR values,
+ check for overflow/underflow. If the REAL_VALUE_TYPE is zero
+ but the mpft_t is not, then we underflowed in the
+ conversion. */
+ if (real_isfinite (&re) && real_isfinite (&im)
+ && (re.cl == rvc_zero) == (mpfr_zero_p (mpc_realref (m)) != 0)
+ && (im.cl == rvc_zero) == (mpfr_zero_p (mpc_imagref (m)) != 0))
+ {
+ REAL_VALUE_TYPE re_mode, im_mode;
+
+ real_convert (&re_mode, TYPE_MODE (TREE_TYPE (type)), &re);
+ real_convert (&im_mode, TYPE_MODE (TREE_TYPE (type)), &im);
+ /* Proceed iff the specified mode can hold the value. */
+ if (real_identical (&re_mode, &re) && real_identical (&im_mode, &im))
+ return build_complex (type, build_real (TREE_TYPE (type), re_mode),
+ build_real (TREE_TYPE (type), im_mode));
+ }
+ }
+ return NULL_TREE;
+}
+#endif /* HAVE_mpc */
+
/* If argument ARG is a REAL_CST, call the one-argument mpfr function
FUNC on it and return the resulting value as a tree with type TYPE.
If MIN and/or MAX are not NULL, then the supplied ARG must be
return result;
}
+#ifdef HAVE_mpc
+/* If argument ARG is a COMPLEX_CST, call the one-argument mpc
+ function FUNC on it and return the resulting value as a tree with
+ type TYPE. The mpfr precision is set to the precision of TYPE. We
+ assume that function FUNC returns zero if the result could be
+ calculated exactly within the requested precision. */
+
+static tree
+do_mpc_arg1 (tree arg, tree type, int (*func)(mpc_ptr, mpc_srcptr, mpc_rnd_t))
+{
+ tree result = NULL_TREE;
+
+ STRIP_NOPS (arg);
+
+ /* To proceed, MPFR must exactly represent the target floating point
+ format, which only happens when the target base equals two. */
+ if (TREE_CODE (arg) == COMPLEX_CST && !TREE_OVERFLOW (arg)
+ && TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) == REAL_TYPE
+ && REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (TREE_TYPE (arg))))->b == 2)
+ {
+ const REAL_VALUE_TYPE *const re = TREE_REAL_CST_PTR (TREE_REALPART (arg));
+ const REAL_VALUE_TYPE *const im = TREE_REAL_CST_PTR (TREE_IMAGPART (arg));
+
+ if (real_isfinite (re) && real_isfinite (im))
+ {
+ const struct real_format *const fmt =
+ REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (type)));
+ const int prec = fmt->p;
+ const mp_rnd_t rnd = fmt->round_towards_zero ? GMP_RNDZ : GMP_RNDN;
+ const mpc_rnd_t crnd = fmt->round_towards_zero ? MPC_RNDZZ : MPC_RNDNN;
+ int inexact;
+ mpc_t m;
+
+ mpc_init2 (m, prec);
+ mpfr_from_real (mpc_realref(m), re, rnd);
+ mpfr_from_real (mpc_imagref(m), im, rnd);
+ mpfr_clear_flags ();
+ inexact = func (m, m, crnd);
+ result = do_mpc_ckconv (m, type, inexact);
+ mpc_clear (m);
+ }
+ }
+
+ return result;
+}
+#endif /* HAVE_mpc */
+
/* FIXME tuples.
The functions below provide an alternate interface for folding
builtin function calls presented as GIMPLE_CALL statements rather