/* Expand builtin functions.
Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
Free Software Foundation, Inc.
This file is part of GCC.
static tree do_mpfr_remquo (tree, tree, tree);
static tree do_mpfr_lgamma_r (tree, tree, tree);
-/* Return true if NODE should be considered for inline expansion regardless
- of the optimization level. This means whenever a function is invoked with
- its "internal" name, which normally contains the prefix "__builtin". */
-
-static bool called_as_built_in (tree node)
+bool
+is_builtin_name (const char *name)
{
- const char *name = IDENTIFIER_POINTER (DECL_NAME (node));
if (strncmp (name, "__builtin_", 10) == 0)
return true;
if (strncmp (name, "__sync_", 7) == 0)
return false;
}
+/* Return true if NODE should be considered for inline expansion regardless
+ of the optimization level. This means whenever a function is invoked with
+ its "internal" name, which normally contains the prefix "__builtin". */
+
+static bool
+called_as_built_in (tree node)
+{
+ /* Note that we must use DECL_NAME, not DECL_ASSEMBLER_NAME_SET_P since
+ we want the name used to call the function, not the name it
+ will have. */
+ const char *name = IDENTIFIER_POINTER (DECL_NAME (node));
+ return is_builtin_name (name);
+}
+
/* Return the alignment in bits of EXP, an object.
Don't return more than MAX_ALIGN no matter what, ALIGN is the inital
guessed alignment e.g. from type alignment. */
else
offset = tree_low_cst (offset_node, 0);
- /* If the offset is known to be out of bounds, warn, and call strlen at
- runtime. */
+ /* If the offset is known to be out of bounds, the front-end should
+ have warned already. We call strlen at runtime.
+
+ ??? Perhaps we should turn this into an assert and force
+ front-ends to define offsets whtin boundaries. */
if (offset < 0 || offset > max)
{
- /* Suppress multiple warnings for propagated constant strings. */
- if (! TREE_NO_WARNING (src))
- {
- warning (0, "offset outside bounds of constant string");
- TREE_NO_WARNING (src) = 1;
- }
return NULL_TREE;
}
static rtx
get_memory_rtx (tree exp, tree len)
{
- rtx addr = expand_expr (exp, NULL_RTX, ptr_mode, EXPAND_NORMAL);
- rtx mem = gen_rtx_MEM (BLKmode, memory_address (BLKmode, addr));
+ tree orig_exp = exp;
+ rtx addr, mem;
+ HOST_WIDE_INT off;
+
+ /* When EXP is not resolved SAVE_EXPR, MEM_ATTRS can be still derived
+ from its expression, for expr->a.b only <variable>.a.b is recorded. */
+ if (TREE_CODE (exp) == SAVE_EXPR && !SAVE_EXPR_RESOLVED_P (exp))
+ exp = TREE_OPERAND (exp, 0);
+
+ addr = expand_expr (orig_exp, NULL_RTX, ptr_mode, EXPAND_NORMAL);
+ mem = gen_rtx_MEM (BLKmode, memory_address (BLKmode, addr));
/* Get an expression we can use to find the attributes to assign to MEM.
If it is an ADDR_EXPR, use the operand. Otherwise, dereference it if
&& POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (exp, 0))))
exp = TREE_OPERAND (exp, 0);
- if (TREE_CODE (exp) == ADDR_EXPR)
+ off = 0;
+ if (TREE_CODE (exp) == POINTER_PLUS_EXPR
+ && TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
+ && host_integerp (TREE_OPERAND (exp, 1), 0)
+ && (off = tree_low_cst (TREE_OPERAND (exp, 1), 0)) > 0)
+ exp = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+ else if (TREE_CODE (exp) == ADDR_EXPR)
exp = TREE_OPERAND (exp, 0);
else if (POINTER_TYPE_P (TREE_TYPE (exp)))
exp = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (exp)), exp);
{
set_mem_attributes (mem, exp, 0);
+ if (off)
+ mem = adjust_automodify_address_nv (mem, BLKmode, NULL, off);
+
/* Allow the string and memory builtins to overflow from one
field into another, see http://gcc.gnu.org/PR23561.
Thus avoid COMPONENT_REFs in MEM_EXPR unless we know the whole
Call abort to encourage the user to fix the program. */
if (warned)
inform (input_location, "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);
t = build_call_expr (implicit_built_in_decls[BUILT_IN_TRAP], 0);
gimplify_and_add (t, pre_p);
}
while (TREE_CODE (inner) == COMPONENT_REF
|| TREE_CODE (inner) == ARRAY_REF);
- if (DECL_P (inner) && DECL_WEAK (inner))
+ if ((TREE_CODE (inner) == VAR_DECL
+ || TREE_CODE (inner) == FUNCTION_DECL)
+ && DECL_WEAK (inner))
return NULL_TREE;
}
tree tree_root;
/* The inner root was either sqrt or cbrt. */
/* This was a conditional expression but it triggered a bug
- in the Solaris 8 compiler. */
+ in Sun C 5.5. */
REAL_VALUE_TYPE dconstroot;
if (BUILTIN_SQRT_P (fcode))
dconstroot = dconsthalf;
call = build_call_expr (fn, 1, arg0);
call = builtin_save_expr (call);
- return build2 (COMPOUND_EXPR, type,
+ return build2 (COMPOUND_EXPR, void_type_node,
build2 (MODIFY_EXPR, void_type_node,
build_fold_indirect_ref (arg1),
build1 (IMAGPART_EXPR, type, call)),
return NULL_TREE;
}
-/* Return true if EXPR is the real constant contained in VALUE. */
-
-static bool
-real_dconstp (tree expr, const REAL_VALUE_TYPE *value)
-{
- STRIP_NOPS (expr);
-
- return ((TREE_CODE (expr) == REAL_CST
- && !TREE_OVERFLOW (expr)
- && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), *value))
- || (TREE_CODE (expr) == COMPLEX_CST
- && real_dconstp (TREE_REALPART (expr), value)
- && real_zerop (TREE_IMAGPART (expr))));
-}
-
/* A subroutine of fold_builtin to fold the various logarithmic
functions. Return NULL_TREE if no simplification can me made.
FUNC is the corresponding MPFR logarithm function. */
tree res;
const enum built_in_function fcode = builtin_mathfn_code (arg);
- /* Optimize log(e) = 1.0. We're never passed an exact 'e',
- instead we'll look for 'e' truncated to MODE. So only do
- this if flag_unsafe_math_optimizations is set. */
- if (flag_unsafe_math_optimizations && func == mpfr_log)
- {
- const REAL_VALUE_TYPE e_truncated =
- real_value_truncate (TYPE_MODE (type), dconst_e ());
- if (real_dconstp (arg, &e_truncated))
- return build_real (type, dconst1);
- }
-
/* Calculate the result when the argument is a constant. */
if ((res = do_mpfr_arg1 (arg, type, func, &dconst0, NULL, false)))
return res;
really mandatory?
If either SRC is readonly or length is 1, we can use memcpy. */
- if (dest_align && src_align
- && (readonly_data_expr (src)
- || (host_integerp (len, 1)
- && (MIN (src_align, dest_align) / BITS_PER_UNIT >=
- tree_low_cst (len, 1)))))
+ if (!dest_align || !src_align)
+ return NULL_TREE;
+ if (readonly_data_expr (src)
+ || (host_integerp (len, 1)
+ && (MIN (src_align, dest_align) / BITS_PER_UNIT
+ >= tree_low_cst (len, 1))))
{
tree fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
if (!fn)
return NULL_TREE;
return build_call_expr (fn, 3, dest, src, len);
}
+
+ /* If *src and *dest can't overlap, optimize into memcpy as well. */
+ srcvar = build_fold_indirect_ref (src);
+ destvar = build_fold_indirect_ref (dest);
+ if (srcvar
+ && !TREE_THIS_VOLATILE (srcvar)
+ && destvar
+ && !TREE_THIS_VOLATILE (destvar))
+ {
+ tree src_base, dest_base, fn;
+ HOST_WIDE_INT src_offset = 0, dest_offset = 0;
+ HOST_WIDE_INT size = -1;
+ HOST_WIDE_INT maxsize = -1;
+
+ src_base = srcvar;
+ if (handled_component_p (src_base))
+ src_base = get_ref_base_and_extent (src_base, &src_offset,
+ &size, &maxsize);
+ dest_base = destvar;
+ if (handled_component_p (dest_base))
+ dest_base = get_ref_base_and_extent (dest_base, &dest_offset,
+ &size, &maxsize);
+ if (host_integerp (len, 1))
+ {
+ maxsize = tree_low_cst (len, 1);
+ if (maxsize
+ > INTTYPE_MAXIMUM (HOST_WIDE_INT) / BITS_PER_UNIT)
+ maxsize = -1;
+ else
+ maxsize *= BITS_PER_UNIT;
+ }
+ else
+ maxsize = -1;
+ if (SSA_VAR_P (src_base)
+ && SSA_VAR_P (dest_base))
+ {
+ if (operand_equal_p (src_base, dest_base, 0)
+ && ranges_overlap_p (src_offset, maxsize,
+ dest_offset, maxsize))
+ return NULL_TREE;
+ }
+ else if (TREE_CODE (src_base) == INDIRECT_REF
+ && TREE_CODE (dest_base) == INDIRECT_REF)
+ {
+ if (! operand_equal_p (TREE_OPERAND (src_base, 0),
+ TREE_OPERAND (dest_base, 0), 0)
+ || ranges_overlap_p (src_offset, maxsize,
+ dest_offset, maxsize))
+ return NULL_TREE;
+ }
+ else
+ return NULL_TREE;
+
+ fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+ if (!fn)
+ return NULL_TREE;
+ return build_call_expr (fn, 3, dest, src, len);
+ }
return NULL_TREE;
}
|| !TYPE_SIZE_UNIT (srctype)
|| !TYPE_SIZE_UNIT (desttype)
|| TREE_CODE (TYPE_SIZE_UNIT (srctype)) != INTEGER_CST
- || TREE_CODE (TYPE_SIZE_UNIT (desttype)) != INTEGER_CST)
+ || TREE_CODE (TYPE_SIZE_UNIT (desttype)) != INTEGER_CST
+ || TYPE_VOLATILE (srctype)
+ || TYPE_VOLATILE (desttype))
return NULL_TREE;
src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
{
srcvar = build_fold_indirect_ref (src);
if (TREE_THIS_VOLATILE (srcvar))
- srcvar = NULL_TREE;
+ return NULL_TREE;
else if (!tree_int_cst_equal (lang_hooks.expr_size (srcvar), len))
srcvar = NULL_TREE;
/* With memcpy, it is possible to bypass aliasing rules, so without
{
destvar = build_fold_indirect_ref (dest);
if (TREE_THIS_VOLATILE (destvar))
- destvar = NULL_TREE;
+ return NULL_TREE;
else if (!tree_int_cst_equal (lang_hooks.expr_size (destvar), len))
destvar = NULL_TREE;
else if (!var_decl_component_p (destvar))
if (TREE_ADDRESSABLE (TREE_TYPE (destvar)))
return NULL_TREE;
- srctype = desttype;
+ srctype = build_qualified_type (desttype, 0);
if (src_align < (int) TYPE_ALIGN (srctype))
{
if (AGGREGATE_TYPE_P (srctype)
if (TREE_ADDRESSABLE (TREE_TYPE (srcvar)))
return NULL_TREE;
- desttype = srctype;
+ desttype = build_qualified_type (srctype, 0);
if (dest_align < (int) TYPE_ALIGN (desttype))
{
if (AGGREGATE_TYPE_P (desttype)
if (CAN_HAVE_LOCATION_P (realret)
&& !EXPR_HAS_LOCATION (realret))
SET_EXPR_LOCATION (realret, EXPR_LOCATION (exp));
- return realret;
}
return ret;
}
if (! integer_all_onesp (size) && tree_int_cst_lt (size, len))
{
- warning (0, "%Kcall to %D will always overflow destination buffer",
- exp, get_callee_fndecl (exp));
+ warning_at (tree_nonartificial_location (exp),
+ 0, "%Kcall to %D will always overflow destination buffer",
+ exp, get_callee_fndecl (exp));
return NULL_RTX;
}
{
int is_strlen = 0;
tree len, size;
+ location_t loc = tree_nonartificial_location (exp);
switch (fcode)
{
src = c_strlen (src, 1);
if (! src || ! host_integerp (src, 1))
{
- warning (0, "%Kcall to %D might overflow destination buffer",
- exp, get_callee_fndecl (exp));
+ warning_at (loc, 0, "%Kcall to %D might overflow destination buffer",
+ exp, get_callee_fndecl (exp));
return;
}
else if (tree_int_cst_lt (src, size))
else if (! host_integerp (len, 1) || ! tree_int_cst_lt (size, len))
return;
- warning (0, "%Kcall to %D will always overflow destination buffer",
- exp, get_callee_fndecl (exp));
+ warning_at (loc, 0, "%Kcall to %D will always overflow destination buffer",
+ exp, get_callee_fndecl (exp));
}
/* Emit warning if a buffer overflow is detected at compile time
return;
if (! tree_int_cst_lt (len, size))
- {
- warning (0, "%Kcall to %D will always overflow destination buffer",
- exp, get_callee_fndecl (exp));
- }
+ warning_at (tree_nonartificial_location (exp),
+ 0, "%Kcall to %D will always overflow destination buffer",
+ exp, get_callee_fndecl (exp));
}
/* Emit warning if a free is called with address of a variable. */
return;
if (SSA_VAR_P (arg))
- warning (0, "%Kattempt to free a non-heap object %qD", exp, arg);
+ warning_at (tree_nonartificial_location (exp),
+ 0, "%Kattempt to free a non-heap object %qD", exp, arg);
else
- warning (0, "%Kattempt to free a non-heap object", exp);
+ warning_at (tree_nonartificial_location (exp),
+ 0, "%Kattempt to free a non-heap object", exp);
}
/* Fold a call to __builtin_object_size with arguments PTR and OST,