The following fixes us to not transform loops into memcpy or memset or not transform malloc + memset into calloc if we implement that functionality itself (and thus we "alias" the symbol we'd call when emitting a call to the builtin).
Bootstrap and regtest pending on x86_64-unknown-linux-gnu. The code is pretty awkward as builtins have no cgraph node and their assembler name is still the "wrong" one appearantly. Ok? Any better way to implement this? Thanks, Richard. 2016-02-22 Richard Biener <rguent...@suse.de> PR tree-optimization/56888 * cgraph.c (cgraph_node::aliases): New function. * cgraph.h (cgraph_node::aliases): Declare. * tree-loop-distribution.c: Include cgraph.h. (classify_partition): Check whether the current function aliases memset, memcpy or memmove. * tree-ssa-strlen.c (handle_builtin_memset): Check whether the current function aliases calloc. Index: gcc/cgraph.c =================================================================== *** gcc/cgraph.c (revision 233598) --- gcc/cgraph.c (working copy) *************** cgraph_node::has_thunk_p (cgraph_node *n *** 3541,3544 **** --- 3541,3564 ---- return false; } + /* Return true if NODE aliases FN. */ + + bool + cgraph_node::aliases (enum built_in_function fn) + { + tree fndecl = builtin_decl_implicit (fn); + if (! fndecl || ! DECL_ASSEMBLER_NAME_SET_P (fndecl)) + return false; + + /* ??? Builtins with aliases are weird. */ + cgraph_node *fnnode + = cgraph_node::get_for_asmname (DECL_ASSEMBLER_NAME (fndecl)); + if (! fnnode) + return false; + + fndecl = fnnode->ultimate_alias_target ()->decl; + return symbol_table::decl_assembler_name_equal (decl, + DECL_ASSEMBLER_NAME (fndecl)); + } + #include "gt-cgraph.h" Index: gcc/cgraph.h =================================================================== *** gcc/cgraph.h (revision 233598) --- gcc/cgraph.h (working copy) *************** public: *** 1181,1186 **** --- 1181,1189 ---- /* Return true if function should be optimized for size. */ bool optimize_for_size_p (void); + /* Return true if NODE aliases the specified builtin. */ + bool aliases (enum built_in_function); + /* Dump the callgraph to file F. */ static void dump_cgraph (FILE *f); Index: gcc/tree-loop-distribution.c =================================================================== *** gcc/tree-loop-distribution.c (revision 233598) --- gcc/tree-loop-distribution.c (working copy) *************** along with GCC; see the file COPYING3. *** 64,69 **** --- 64,70 ---- #include "cfgloop.h" #include "tree-scalar-evolution.h" #include "tree-vectorizer.h" + #include "cgraph.h" /* A Reduced Dependence Graph (RDG) vertex representing a statement. */ *************** classify_partition (loop_p loop, struct *** 1078,1083 **** --- 1079,1086 ---- || !dominated_by_p (CDI_DOMINATORS, loop->latch, gimple_bb (stmt))) return; + if (cgraph_node::get (cfun->decl)->aliases (BUILT_IN_MEMSET)) + return; partition->kind = PKIND_MEMSET; partition->main_dr = single_store; partition->niter = nb_iter; *************** classify_partition (loop_p loop, struct *** 1135,1140 **** --- 1138,1146 ---- } free_dependence_relation (ddr); loops.release (); + if (cgraph_node::get (cfun->decl)->aliases (BUILT_IN_MEMCPY) + || cgraph_node::get (cfun->decl)->aliases (BUILT_IN_MEMMOVE)) + return; partition->kind = PKIND_MEMCPY; partition->main_dr = single_store; partition->secondary_dr = single_load; Index: gcc/tree-ssa-strlen.c =================================================================== *** gcc/tree-ssa-strlen.c (revision 233598) --- gcc/tree-ssa-strlen.c (working copy) *************** handle_builtin_memset (gimple_stmt_itera *** 1817,1823 **** if (code1 == BUILT_IN_CALLOC) /* Not touching stmt1 */ ; else if (code1 == BUILT_IN_MALLOC ! && operand_equal_p (gimple_call_arg (stmt1, 0), size, 0)) { gimple_stmt_iterator gsi1 = gsi_for_stmt (stmt1); update_gimple_call (&gsi1, builtin_decl_implicit (BUILT_IN_CALLOC), 2, --- 1817,1824 ---- if (code1 == BUILT_IN_CALLOC) /* Not touching stmt1 */ ; else if (code1 == BUILT_IN_MALLOC ! && operand_equal_p (gimple_call_arg (stmt1, 0), size, 0) ! && ! cgraph_node::get (cfun->decl)->aliases (BUILT_IN_CALLOC)) { gimple_stmt_iterator gsi1 = gsi_for_stmt (stmt1); update_gimple_call (&gsi1, builtin_decl_implicit (BUILT_IN_CALLOC), 2, Index: gcc/testsuite/gcc.dg/pr56888.c =================================================================== *** gcc/testsuite/gcc.dg/pr56888.c (revision 0) --- gcc/testsuite/gcc.dg/pr56888.c (working copy) *************** *** 0 **** --- 1,21 ---- + /* { dg-do compile } */ + /* { dg-options "-O2 -ftree-loop-distribute-patterns -fdump-tree-optimized" } */ + /* { dg-require-alias "" } */ + /* { dg-require-weak "" } */ + + typedef __SIZE_TYPE__ size_t; + extern void * + memset (void *s, int c, size_t n) __attribute__ ((weak, alias("_memset"))); + + void * + _memset(void *s, int c, size_t n) + { + char *q = (char *)s; + while (n != 0) + { + *(q++) = c; + n--; + } + } + + /* { dg-final { scan-tree-dump-not "__builtin_memset" "optimized" } } */