RFC: Disentangle builtin folding from expanding
Michael Matz
matz@suse.de
Wed Sep 23 18:18:00 GMT 2009
Hi,
so this is my current WIP stuff for separating builtin folding from
builtin expansion. I've started by adding a gcc_assert at most expanders
that called folding routines directly, asserting that nothing was folded,
and from there started to fix the resulting ICEs. In addition to that I
changed some build_call_expr calls (that implicitely call folders) in
expanders to a new routine build_call_expr_nofold, that really just builds
a call statement.
Fixing the resulting ICEs needed moving some folding from expand time to,
well, folding time, e.g. the strcat expander sometimes folded into
strlen+strcpy, but no, not at folding time :-/ The stpcpy folder (that
didn't really exist then) needed similar surgery.
Further I made fold_stmt_1 (when inplace is false) possibly emit multiple
statements, effectively doing what pass_fold_builtin always did. By
doing this we can often fold much earlier that waiting until that pass
(which I moved up to the end of the pipeline). This in turn required
changes in some places that uses fold_stmt, in particular the inliner
needs to go over all emitted insns to see if any of them are calls, and
substitute_and_fold needs some changes as it walks backwards over the
instructions and otherwise would hit decls not in SSA form.
(I tried to use an into_ssa gimplify context in
gimplify_and_update_call_from_tree, but that's theoretically a bit
dangerous as the folders not necessarily write into temp decls they create
only once)
Unfortunately I still need the full pass_fold_builtins, as quite some
passes that propagate stuff around (possibly making a builtin call
foldable) use fold_stmt_inplace and aren't trivial to change to use
fold_stmt. Eventually that should be done, but not in this patch set, it
requires some surgery on the fold_stmt interface first.
I didn't want to introduce a second pass_fold_builtins, so I moved it very
late. That works except for calls to __builtin_constant_p. Those are a
bit special: we can't fold them to false too early (we want to wait until
some cprop was run), so it's nothing we can do right in fold_gimple_stmt.
But we can't fold them too late either, as otherwise dead code isn't
removed and leads to warnings/errors. So we can't wait for the (now very
late) pass_fold_builtins. I've decided to add this into the first dom
pass, that's late enough so that usual propagations already occured, but
early enough that dead code will be eliminated.
This patch as is regstraps on x86_64-linux with all langs+Ada. As it
contains all the "gcc_assert (!result)" this means that the expansion now
doesn't fold anything anymore, a preliminary step for expanding call
statements from tuples directly.
In a final patch I'll obviously remove all the code that is proved dead
with the asserts, but wanted to see what others think about all this (and
the removal makes the patch probably noisy). No ChangeLog for that
reason.
Other cleanups that Paolo already listed are still on my list.
Ciao,
Michael.
--
Index: builtins.c
===================================================================
--- builtins.c (Revision 151906)
+++ builtins.c (Arbeitskopie)
@@ -117,7 +117,7 @@ static rtx expand_builtin_memcmp (tree,
static rtx expand_builtin_strcmp (tree, rtx, enum machine_mode);
static rtx expand_builtin_strncmp (tree, rtx, enum machine_mode);
static rtx builtin_memcpy_read_str (void *, HOST_WIDE_INT, enum machine_mode);
-static rtx expand_builtin_strcat (tree, tree, rtx, enum machine_mode);
+static rtx expand_builtin_strcat (tree, rtx, enum machine_mode);
static rtx expand_builtin_strncat (tree, rtx, enum machine_mode);
static rtx expand_builtin_strspn (tree, rtx, enum machine_mode);
static rtx expand_builtin_strcspn (tree, rtx, enum machine_mode);
@@ -2550,6 +2550,22 @@ expand_builtin_cexpi (tree exp, rtx targ
target, VOIDmode, EXPAND_NORMAL);
}
+static tree
+build_call_nofold_loc (location_t loc, tree fndecl, int n, ...)
+{
+ va_list ap;
+ tree fntype = TREE_TYPE (fndecl);
+ tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
+
+ va_start (ap, n);
+ fn = build_call_valist (TREE_TYPE (fntype), fn, n, ap);
+ va_end (ap);
+ SET_EXPR_LOCATION (fn, loc);
+ return fn;
+}
+#define build_call_nofold(...) \
+ build_call_nofold_loc (UNKNOWN_LOCATION, __VA_ARGS__)
+
/* Expand a call to one of the builtin rounding functions gcc defines
as an extension (lfloor and lceil). As these are gcc extensions we
do not need to worry about setting errno to EDOM.
@@ -2666,7 +2682,7 @@ expand_builtin_int_roundingfn (tree exp,
fallback_fndecl = build_fn_decl (name, fntype);
}
- exp = build_call_expr (fallback_fndecl, 1, arg);
+ exp = build_call_nofold (fallback_fndecl, 1, arg);
tmp = expand_normal (exp);
@@ -3016,7 +3032,7 @@ expand_builtin_pow (tree exp, rtx target
&& powi_cost (n/2) <= POWI_MAX_MULTS)
|| n == 1))
{
- tree call_expr = build_call_expr (fn, 1, narg0);
+ tree call_expr = build_call_nofold (fn, 1, narg0);
/* Use expand_expr in case the newly built call expression
was folded to a non-call. */
op = expand_expr (call_expr, subtarget, mode, EXPAND_NORMAL);
@@ -3061,7 +3077,7 @@ expand_builtin_pow (tree exp, rtx target
&& powi_cost (n/3) <= POWI_MAX_MULTS)
|| n == 1))
{
- tree call_expr = build_call_expr (fn, 1,narg0);
+ tree call_expr = build_call_nofold (fn, 1,narg0);
op = expand_builtin (call_expr, NULL_RTX, subtarget, mode, 0);
if (abs (n) % 3 == 2)
op = expand_simple_binop (mode, MULT, op, op, op,
@@ -3272,6 +3288,7 @@ expand_builtin_strstr (tree exp, rtx tar
tree result = fold_builtin_strstr (EXPR_LOCATION (exp),
CALL_EXPR_ARG (exp, 0),
CALL_EXPR_ARG (exp, 1), type);
+ gcc_assert (!result);
if (result)
return expand_expr (result, target, mode, EXPAND_NORMAL);
}
@@ -3291,6 +3308,7 @@ expand_builtin_strchr (tree exp, rtx tar
tree result = fold_builtin_strchr (EXPR_LOCATION (exp),
CALL_EXPR_ARG (exp, 0),
CALL_EXPR_ARG (exp, 1), type);
+ gcc_assert (!result);
if (result)
return expand_expr (result, target, mode, EXPAND_NORMAL);
@@ -3312,6 +3330,7 @@ expand_builtin_strrchr (tree exp, rtx ta
tree result = fold_builtin_strrchr (EXPR_LOCATION (exp),
CALL_EXPR_ARG (exp, 0),
CALL_EXPR_ARG (exp, 1), type);
+ gcc_assert (!result);
if (result)
return expand_expr (result, target, mode, EXPAND_NORMAL);
}
@@ -3331,6 +3350,7 @@ expand_builtin_strpbrk (tree exp, rtx ta
tree result = fold_builtin_strpbrk (EXPR_LOCATION (exp),
CALL_EXPR_ARG (exp, 0),
CALL_EXPR_ARG (exp, 1), type);
+ gcc_assert (!result);
if (result)
return expand_expr (result, target, mode, EXPAND_NORMAL);
}
@@ -3385,6 +3405,7 @@ expand_builtin_memcpy (tree exp, rtx tar
unsigned int expected_align = 0;
tree_ann_common_t ann;
+ gcc_assert (!result);
if (result)
{
while (TREE_CODE (result) == COMPOUND_EXPR)
@@ -3492,7 +3513,7 @@ expand_builtin_mempcpy_args (tree dest,
if (target == const0_rtx && implicit_built_in_decls[BUILT_IN_MEMCPY])
{
tree fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
- tree result = build_call_expr (fn, 3, dest, src, len);
+ tree result = build_call_nofold (fn, 3, dest, src, len);
while (TREE_CODE (result) == COMPOUND_EXPR)
{
@@ -3512,6 +3533,7 @@ expand_builtin_mempcpy_args (tree dest,
tree result = fold_builtin_memory_op (UNKNOWN_LOCATION,
dest, src, len, type, false, endp);
+ gcc_assert (!result);
if (result)
{
while (TREE_CODE (result) == COMPOUND_EXPR)
@@ -3608,6 +3630,7 @@ expand_builtin_memmove_args (tree dest,
tree result = fold_builtin_memory_op (UNKNOWN_LOCATION,
dest, src, len, type, ignore, /*endp=*/3);
+ gcc_assert (!result);
if (result)
{
STRIP_TYPE_NOPS (result);
@@ -3747,6 +3770,7 @@ expand_builtin_strcpy_args (tree fndecl,
{
tree result = fold_builtin_strcpy (UNKNOWN_LOCATION,
fndecl, dest, src, 0);
+ gcc_assert (!result);
if (result)
return expand_expr (result, target, mode, EXPAND_NORMAL);
return expand_movstr (dest, src, target, /*endp=*/0);
@@ -3774,7 +3798,7 @@ expand_builtin_stpcpy (tree exp, rtx tar
if (target == const0_rtx && implicit_built_in_decls[BUILT_IN_STRCPY])
{
tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
- tree result = build_call_expr (fn, 2, dst, src);
+ tree result = build_call_nofold (fn, 2, dst, src);
STRIP_NOPS (result);
while (TREE_CODE (result) == COMPOUND_EXPR)
@@ -3873,6 +3897,7 @@ expand_builtin_strncpy (tree exp, rtx ta
tree result = fold_builtin_strncpy (EXPR_LOCATION (exp),
fndecl, dest, src, len, slen);
+ gcc_assert (!result);
if (result)
{
while (TREE_CODE (result) == COMPOUND_EXPR)
@@ -4101,9 +4126,9 @@ expand_builtin_memset_args (tree dest, t
fndecl = get_callee_fndecl (orig_exp);
fcode = DECL_FUNCTION_CODE (fndecl);
if (fcode == BUILT_IN_MEMSET)
- fn = build_call_expr (fndecl, 3, dest, val, len);
+ fn = build_call_nofold (fndecl, 3, dest, val, len);
else if (fcode == BUILT_IN_BZERO)
- fn = build_call_expr (fndecl, 2, dest, len);
+ fn = build_call_nofold (fndecl, 2, dest, len);
else
gcc_unreachable ();
if (TREE_CODE (fn) == CALL_EXPR)
@@ -4151,6 +4176,7 @@ expand_builtin_memchr (tree exp, rtx tar
CALL_EXPR_ARG (exp, 0),
CALL_EXPR_ARG (exp, 1),
CALL_EXPR_ARG (exp, 2), type);
+ gcc_assert (!result);
if (result)
return expand_expr (result, target, mode, EXPAND_NORMAL);
}
@@ -4176,6 +4202,7 @@ expand_builtin_memcmp (tree exp, rtx tar
CALL_EXPR_ARG (exp, 0),
CALL_EXPR_ARG (exp, 1),
CALL_EXPR_ARG (exp, 2));
+ gcc_assert (!result);
if (result)
return expand_expr (result, target, mode, EXPAND_NORMAL);
}
@@ -4287,6 +4314,7 @@ expand_builtin_strcmp (tree exp, rtx tar
tree result = fold_builtin_strcmp (loc,
CALL_EXPR_ARG (exp, 0),
CALL_EXPR_ARG (exp, 1));
+ gcc_assert (!result);
if (result)
return expand_expr (result, target, mode, EXPAND_NORMAL);
}
@@ -4414,7 +4442,7 @@ expand_builtin_strcmp (tree exp, rtx tar
do_libcall:
#endif
fndecl = get_callee_fndecl (exp);
- fn = build_call_expr (fndecl, 2, arg1, arg2);
+ fn = build_call_nofold (fndecl, 2, arg1, arg2);
if (TREE_CODE (fn) == CALL_EXPR)
CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
return expand_call (fn, target, target == const0_rtx);
@@ -4441,6 +4469,7 @@ expand_builtin_strncmp (tree exp, rtx ta
CALL_EXPR_ARG (exp, 0),
CALL_EXPR_ARG (exp, 1),
CALL_EXPR_ARG (exp, 2));
+ gcc_assert (!result);
if (result)
return expand_expr (result, target, mode, EXPAND_NORMAL);
}
@@ -4544,7 +4573,7 @@ expand_builtin_strncmp (tree exp, rtx ta
/* Expand the library call ourselves using a stabilized argument
list to avoid re-evaluating the function's arguments twice. */
fndecl = get_callee_fndecl (exp);
- fn = build_call_expr (fndecl, 3, arg1, arg2, len);
+ fn = build_call_nofold (fndecl, 3, arg1, arg2, len);
if (TREE_CODE (fn) == CALL_EXPR)
CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
return expand_call (fn, target, target == const0_rtx);
@@ -4558,59 +4587,20 @@ expand_builtin_strncmp (tree exp, rtx ta
otherwise try to get the result in TARGET, if convenient. */
static rtx
-expand_builtin_strcat (tree fndecl, tree exp, rtx target, enum machine_mode mode)
+expand_builtin_strcat (tree exp, rtx target, enum machine_mode mode)
{
- location_t loc = EXPR_LOCATION (exp);
-
if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
return NULL_RTX;
else
{
- tree dst = CALL_EXPR_ARG (exp, 0);
- tree src = CALL_EXPR_ARG (exp, 1);
- const char *p = c_getstr (src);
-
- /* If the string length is zero, return the dst parameter. */
- if (p && *p == '\0')
- return expand_expr (dst, target, mode, EXPAND_NORMAL);
-
- if (optimize_insn_for_speed_p ())
- {
- /* See if we can store by pieces into (dst + strlen(dst)). */
- tree newsrc, newdst,
- strlen_fn = implicit_built_in_decls[BUILT_IN_STRLEN];
- rtx insns;
-
- /* Stabilize the argument list. */
- newsrc = builtin_save_expr (src);
- dst = builtin_save_expr (dst);
-
- start_sequence ();
-
- /* Create strlen (dst). */
- newdst = build_call_expr (strlen_fn, 1, dst);
- /* Create (dst p+ strlen (dst)). */
-
- newdst = fold_build2_loc (loc, POINTER_PLUS_EXPR,
- TREE_TYPE (dst), dst, newdst);
- newdst = builtin_save_expr (newdst);
-
- if (!expand_builtin_strcpy_args (fndecl, newdst, newsrc, target, mode))
- {
- end_sequence (); /* Stop sequence. */
- return NULL_RTX;
- }
-
- /* Output the entire sequence. */
- insns = get_insns ();
- end_sequence ();
- emit_insn (insns);
-
- return expand_expr (dst, target, mode, EXPAND_NORMAL);
- }
-
- return NULL_RTX;
+ tree result = fold_builtin_strcat (EXPR_LOCATION (exp),
+ CALL_EXPR_ARG (exp, 0),
+ CALL_EXPR_ARG (exp, 1));
+ gcc_assert (!result);
+ if (result)
+ return expand_expr (result, target, mode, EXPAND_NORMAL);
}
+ return NULL_RTX;
}
/* Expand expression EXP, which is a call to the strncat builtin.
@@ -4627,6 +4617,7 @@ expand_builtin_strncat (tree exp, rtx ta
CALL_EXPR_ARG (exp, 0),
CALL_EXPR_ARG (exp, 1),
CALL_EXPR_ARG (exp, 2));
+ gcc_assert (!result);
if (result)
return expand_expr (result, target, mode, EXPAND_NORMAL);
}
@@ -4645,6 +4636,7 @@ expand_builtin_strspn (tree exp, rtx tar
tree result = fold_builtin_strspn (EXPR_LOCATION (exp),
CALL_EXPR_ARG (exp, 0),
CALL_EXPR_ARG (exp, 1));
+ gcc_assert (!result);
if (result)
return expand_expr (result, target, mode, EXPAND_NORMAL);
}
@@ -4663,6 +4655,7 @@ expand_builtin_strcspn (tree exp, rtx ta
tree result = fold_builtin_strcspn (EXPR_LOCATION (exp),
CALL_EXPR_ARG (exp, 0),
CALL_EXPR_ARG (exp, 1));
+ gcc_assert (!result);
if (result)
return expand_expr (result, target, mode, EXPAND_NORMAL);
}
@@ -5310,6 +5303,7 @@ expand_builtin_fputs (tree exp, rtx targ
CALL_EXPR_ARG (exp, 1),
(target == const0_rtx),
unlocked, NULL_TREE);
+ gcc_assert (!result);
if (result)
return expand_expr (result, target, VOIDmode, EXPAND_NORMAL);
}
@@ -5475,7 +5469,7 @@ expand_builtin_printf (tree exp, rtx tar
|| ! POINTER_TYPE_P (TREE_TYPE (CALL_EXPR_ARG (exp, 1))))
return NULL_RTX;
if (fn_puts)
- fn = build_call_expr (fn_puts, 1, CALL_EXPR_ARG (exp, 1));
+ fn = build_call_nofold (fn_puts, 1, CALL_EXPR_ARG (exp, 1));
}
/* If the format specifier was "%c", call __builtin_putchar(arg). */
else if (strcmp (fmt_str, target_percent_c) == 0)
@@ -5484,7 +5478,7 @@ expand_builtin_printf (tree exp, rtx tar
|| TREE_CODE (TREE_TYPE (CALL_EXPR_ARG (exp, 1))) != INTEGER_TYPE)
return NULL_RTX;
if (fn_putchar)
- fn = build_call_expr (fn_putchar, 1, CALL_EXPR_ARG (exp, 1));
+ fn = build_call_nofold (fn_putchar, 1, CALL_EXPR_ARG (exp, 1));
}
else
{
@@ -5506,7 +5500,7 @@ expand_builtin_printf (tree exp, rtx tar
function. */
arg = build_int_cst (NULL_TREE, fmt_str[0]);
if (fn_putchar)
- fn = build_call_expr (fn_putchar, 1, arg);
+ fn = build_call_nofold (fn_putchar, 1, arg);
}
else
{
@@ -5521,7 +5515,7 @@ expand_builtin_printf (tree exp, rtx tar
newstr[len - 1] = 0;
arg = build_string_literal (len, newstr);
if (fn_puts)
- fn = build_call_expr (fn_puts, 1, arg);
+ fn = build_call_nofold (fn_puts, 1, arg);
}
else
/* We'd like to arrange to call fputs(string,stdout) here,
@@ -5587,7 +5581,7 @@ expand_builtin_fprintf (tree exp, rtx ta
return NULL_RTX;
arg = CALL_EXPR_ARG (exp, 2);
if (fn_fputs)
- fn = build_call_expr (fn_fputs, 2, arg, fp);
+ fn = build_call_nofold (fn_fputs, 2, arg, fp);
}
/* If the format specifier was "%c", call __builtin_fputc(arg,fp). */
else if (strcmp (fmt_str, target_percent_c) == 0)
@@ -5597,7 +5591,7 @@ expand_builtin_fprintf (tree exp, rtx ta
return NULL_RTX;
arg = CALL_EXPR_ARG (exp, 2);
if (fn_fputc)
- fn = build_call_expr (fn_fputc, 2, arg, fp);
+ fn = build_call_nofold (fn_fputc, 2, arg, fp);
}
else
{
@@ -5620,7 +5614,7 @@ expand_builtin_fprintf (tree exp, rtx ta
fprintf(stream,string) with fputs(string,stream). The fputs
builtin will take care of special cases like length == 1. */
if (fn_fputs)
- fn = build_call_expr (fn_fputs, 2, fmt, fp);
+ fn = build_call_nofold (fn_fputs, 2, fmt, fp);
}
if (!fn)
@@ -5668,7 +5662,7 @@ expand_builtin_sprintf (tree exp, rtx ta
if ((nargs > 2) || ! fn)
return NULL_RTX;
- expand_expr (build_call_expr (fn, 2, dest, fmt),
+ expand_expr (build_call_nofold (fn, 2, dest, fmt),
const0_rtx, VOIDmode, EXPAND_NORMAL);
if (target == const0_rtx)
return const0_rtx;
@@ -5698,7 +5692,7 @@ expand_builtin_sprintf (tree exp, rtx ta
else
len = NULL_TREE;
- expand_expr (build_call_expr (fn, 2, dest, arg),
+ expand_expr (build_call_nofold (fn, 2, dest, arg),
const0_rtx, VOIDmode, EXPAND_NORMAL);
if (target == const0_rtx)
@@ -6655,7 +6649,7 @@ expand_builtin (tree exp, rtx target, rt
break;
case BUILT_IN_STRCAT:
- target = expand_builtin_strcat (fndecl, exp, target, mode);
+ target = expand_builtin_strcat (exp, target, mode);
if (target)
return target;
break;
@@ -9289,6 +9283,46 @@ fold_builtin_strcpy (location_t loc, tre
build_call_expr_loc (loc, fn, 3, dest, src, len));
}
+/* Fold function call to builtin stpcpy with arguments DEST and SRC.
+ Return NULL_TREE if no simplification can be made. */
+
+static tree
+fold_builtin_stpcpy (location_t loc, tree fndecl, tree dest, tree src)
+{
+ tree fn, len, lenp1, call, type;
+
+ if (!validate_arg (dest, POINTER_TYPE)
+ || !validate_arg (src, POINTER_TYPE))
+ return NULL_TREE;
+
+ len = c_strlen (src, 1);
+ if (!len
+ || TREE_CODE (len) != INTEGER_CST)
+ return NULL_TREE;
+
+ if (optimize_function_for_size_p (cfun)
+ /* If length is zero it's small enough. */
+ && !integer_zerop (len))
+ return NULL_TREE;
+
+ fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+ if (!fn)
+ return NULL_TREE;
+
+ lenp1 = size_binop_loc (loc, PLUS_EXPR, len, ssize_int (1));
+ /* We use dest twice in building our expression. Save it from
+ multiple expansions. */
+ dest = builtin_save_expr (dest);
+ call = build_call_expr_loc (loc, fn, 3, dest, src, lenp1);
+
+ type = TREE_TYPE (TREE_TYPE (fndecl));
+ len = fold_convert_loc (loc, sizetype, len);
+ dest = fold_build2_loc (loc, POINTER_PLUS_EXPR, TREE_TYPE (dest), dest, len);
+ dest = fold_convert_loc (loc, type, dest);
+ dest = omit_one_operand_loc (loc, type, dest, call);
+ return dest;
+}
+
/* Fold function call to builtin strncpy with arguments DEST, SRC, and LEN.
If SLEN is not NULL, it represents the length of the source string.
Return NULL_TREE if no simplification can be made. */
@@ -10799,6 +10833,8 @@ fold_builtin_2 (location_t loc, tree fnd
return build_call_expr_loc (loc, fn, 2, arg0, arg1);
}
+ else
+ return fold_builtin_stpcpy (loc, fndecl, arg0, arg1);
break;
case BUILT_IN_STRCMP:
@@ -11764,6 +11800,42 @@ fold_builtin_strcat (location_t loc ATTR
if (p && *p == '\0')
return dst;
+ if (optimize_insn_for_speed_p ())
+ {
+ /* See if we can store by pieces into (dst + strlen(dst)). */
+ tree newdst, call;
+ tree strlen_fn = implicit_built_in_decls[BUILT_IN_STRLEN];
+ tree strcpy_fn = implicit_built_in_decls[BUILT_IN_STRCPY];
+
+ if (!strlen_fn || !strcpy_fn)
+ return NULL_TREE;
+
+ /* If we don't have a movstr we don't want to emit an strcpy
+ call. We have to do that if the length of the source string
+ isn't computable (in that case we can use memcpy probably
+ later expanding to a sequence of mov instructions). If we
+ have movstr instructions we can emit strcpy calls. */
+ if (!HAVE_movstr)
+ {
+ tree len = c_strlen (src, 1);
+ if (! len || TREE_SIDE_EFFECTS (len))
+ return NULL_TREE;
+ }
+
+ /* Stabilize the argument list. */
+ dst = builtin_save_expr (dst);
+
+ /* Create strlen (dst). */
+ newdst = build_call_expr_loc (loc, strlen_fn, 1, dst);
+ /* Create (dst p+ strlen (dst)). */
+
+ newdst = fold_build2_loc (loc, POINTER_PLUS_EXPR,
+ TREE_TYPE (dst), dst, newdst);
+ newdst = builtin_save_expr (newdst);
+
+ call = build_call_expr_loc (loc, strcpy_fn, 2, newdst, src);
+ return build2 (COMPOUND_EXPR, TREE_TYPE (dst), call, dst);
+ }
return NULL_TREE;
}
}
@@ -12284,7 +12356,7 @@ expand_builtin_memory_chk (tree exp, rtx
if (! fn)
return NULL_RTX;
- fn = build_call_expr (fn, 3, dest, src, len);
+ fn = build_call_nofold (fn, 3, dest, src, len);
STRIP_TYPE_NOPS (fn);
while (TREE_CODE (fn) == COMPOUND_EXPR)
{
@@ -12339,7 +12411,7 @@ expand_builtin_memory_chk (tree exp, rtx
tree fn = built_in_decls[BUILT_IN_MEMCPY_CHK];
if (!fn)
return NULL_RTX;
- fn = build_call_expr (fn, 4, dest, src, len, size);
+ fn = build_call_nofold (fn, 4, dest, src, len, size);
STRIP_TYPE_NOPS (fn);
while (TREE_CODE (fn) == COMPOUND_EXPR)
{
Index: passes.c
===================================================================
--- passes.c (Revision 151906)
+++ passes.c (Arbeitskopie)
@@ -641,7 +641,6 @@ init_optimization_passes (void)
NEXT_PASS (pass_object_sizes);
NEXT_PASS (pass_ccp);
NEXT_PASS (pass_copy_prop);
- NEXT_PASS (pass_fold_builtins);
NEXT_PASS (pass_cse_sincos);
NEXT_PASS (pass_optimize_bswap);
NEXT_PASS (pass_split_crit_edges);
@@ -709,6 +708,7 @@ init_optimization_passes (void)
NEXT_PASS (pass_dse);
NEXT_PASS (pass_forwprop);
NEXT_PASS (pass_phiopt);
+ NEXT_PASS (pass_fold_builtins);
NEXT_PASS (pass_tail_calls);
NEXT_PASS (pass_rename_ssa_copies);
NEXT_PASS (pass_uncprop);
Index: tree-inline.c
===================================================================
--- tree-inline.c (Revision 151906)
+++ tree-inline.c (Arbeitskopie)
@@ -3873,7 +3873,36 @@ fold_marked_statements (int first, struc
gimple old_stmt = gsi_stmt (gsi);
tree old_decl = is_gimple_call (old_stmt) ? gimple_call_fndecl (old_stmt) : 0;
- if (fold_stmt (&gsi))
+ if (old_decl && DECL_BUILT_IN (old_decl))
+ {
+ /* Folding builtins can create multiple instructions,
+ we need to look at all of them. */
+ gimple_stmt_iterator i2 = gsi;
+ gsi_prev (&i2);
+ if (fold_stmt (&gsi))
+ {
+ gimple new_stmt;
+ if (gsi_end_p (i2))
+ i2 = gsi_start_bb (BASIC_BLOCK (first));
+ else
+ gsi_next (&i2);
+ while (1)
+ {
+ new_stmt = gsi_stmt (i2);
+ update_stmt (new_stmt);
+ if (is_gimple_call (old_stmt)
+ || is_gimple_call (new_stmt))
+ cgraph_update_edges_for_call_stmt (old_stmt, old_decl, new_stmt);
+
+ if (maybe_clean_or_replace_eh_stmt (old_stmt, new_stmt))
+ gimple_purge_dead_eh_edges (BASIC_BLOCK (first));
+ if (new_stmt == gsi_stmt (gsi))
+ break;
+ gsi_next (&i2);
+ }
+ }
+ }
+ else if (fold_stmt (&gsi))
{
/* Re-read the statement from GSI as fold_stmt() may
have changed it. */
Index: tree-ssa-ccp.c
===================================================================
--- tree-ssa-ccp.c (Revision 151906)
+++ tree-ssa-ccp.c (Arbeitskopie)
@@ -1423,8 +1423,8 @@ evaluate_stmt (gimple stmt)
else if (code == GIMPLE_SWITCH)
simplified = gimple_switch_index (stmt);
else
- /* These cannot satisfy is_gimple_min_invariant without folding. */
- gcc_assert (code == GIMPLE_CALL || code == GIMPLE_COND);
+ /* These cannot satisfy is_gimple_min_invariant without folding. */
+ gcc_assert (code == GIMPLE_CALL || code == GIMPLE_COND);
}
is_constant = simplified && is_gimple_min_invariant (simplified);
@@ -2866,6 +2866,7 @@ fold_gimple_cond (gimple stmt)
return false;
}
+static void gimplify_and_update_call_from_tree (gimple_stmt_iterator *, tree);
/* Attempt to fold a call statement referenced by the statement iterator GSI.
The statement may be replaced by another statement, e.g., if the call
@@ -2886,7 +2887,11 @@ fold_gimple_call (gimple_stmt_iterator *
tree result = ccp_fold_builtin (stmt);
if (result)
- return update_call_from_tree (gsi, result);
+ {
+ if (!update_call_from_tree (gsi, result))
+ gimplify_and_update_call_from_tree (gsi, result);
+ return true;
+ }
}
else
{
Index: tree-ssa-dom.c
===================================================================
--- tree-ssa-dom.c (Revision 151906)
+++ tree-ssa-dom.c (Arbeitskopie)
@@ -2184,6 +2184,20 @@ optimize_stmt (basic_block bb, gimple_st
{
may_have_exposed_new_symbols |= eliminate_redundant_computations (&si);
stmt = gsi_stmt (si);
+ if (gimple_code (stmt) == GIMPLE_CALL)
+ {
+ /* Resolve __builtin_constant_p. If it hasn't been
+ folded to integer_one_node by now, it's fairly
+ certain that the value simply isn't constant. */
+ tree callee = gimple_call_fndecl (stmt);
+ if (callee
+ && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL
+ && DECL_FUNCTION_CODE (callee) == BUILT_IN_CONSTANT_P)
+ {
+ propagate_tree_value_into_stmt (&si, integer_zero_node);
+ stmt = gsi_stmt (si);
+ }
+ }
}
/* Record any additional equivalences created by this statement. */
Index: tree-ssa-propagate.c
===================================================================
--- tree-ssa-propagate.c (Revision 151906)
+++ tree-ssa-propagate.c (Arbeitskopie)
@@ -1069,6 +1069,10 @@ substitute_and_fold (prop_value_t *prop_
gimple stmt = gsi_stmt (i);
gimple old_stmt;
enum gimple_code code = gimple_code (stmt);
+ gimple_stmt_iterator oldi;
+
+ oldi = i;
+ gsi_prev (&i);
/* Ignore ASSERT_EXPRs. They are used by VRP to generate
range information for names and they are discarded
@@ -1076,10 +1080,7 @@ substitute_and_fold (prop_value_t *prop_
if (code == GIMPLE_ASSIGN
&& TREE_CODE (gimple_assign_rhs1 (stmt)) == ASSERT_EXPR)
- {
- gsi_prev (&i);
- continue;
- }
+ continue;
/* No point propagating into a stmt whose result is not used,
but instead we might be able to remove a trivially dead stmt. */
@@ -1098,7 +1099,6 @@ substitute_and_fold (prop_value_t *prop_
fprintf (dump_file, "\n");
}
prop_stats.num_dce++;
- gsi_prev (&i);
i2 = gsi_for_stmt (stmt);
gsi_remove (&i2, true);
release_defs (stmt);
@@ -1118,9 +1118,9 @@ substitute_and_fold (prop_value_t *prop_
predicate expressions. */
if (use_ranges_p)
{
- did_replace = fold_predicate_in (&i);
+ did_replace = fold_predicate_in (&oldi);
/* fold_predicate_in should not have reallocated STMT. */
- gcc_assert (gsi_stmt (i) == stmt);
+ gcc_assert (gsi_stmt (oldi) == stmt);
}
/* Only replace real uses if we couldn't fold the
@@ -1133,7 +1133,7 @@ substitute_and_fold (prop_value_t *prop_
old_stmt = stmt;
if (did_replace)
- fold_stmt (&i);
+ fold_stmt (&oldi);
/* Some statements may be simplified using ranges. For
example, division may be replaced by shifts, modulo
@@ -1142,12 +1142,12 @@ substitute_and_fold (prop_value_t *prop_
presented with a fully propagated, canonicalized
statement. */
if (use_ranges_p)
- did_replace |= simplify_stmt_using_ranges (&i);
+ did_replace |= simplify_stmt_using_ranges (&oldi);
/* Now cleanup. */
if (did_replace)
{
- stmt = gsi_stmt (i);
+ stmt = gsi_stmt (oldi);
/* If we cleaned up EH information from the statement,
remove EH edges. */
@@ -1181,8 +1181,6 @@ substitute_and_fold (prop_value_t *prop_
else
fprintf (dump_file, "Not folded\n");
}
-
- gsi_prev (&i);
}
}
More information about the Gcc-patches
mailing list