On Tue, Apr 19, 2011 at 3:14 PM, Richard Sandiford <richard.sandif...@linaro.org> wrote: > Richard Guenther <richard.guent...@gmail.com> writes: >>> We really should be able to treat calls to pure internal functions >>> like calls to pure "real" functions though. >>> >>> TBH, I think this is an example of why trying to so hard to avoid a tree >>> code for the internal function is working against us. Most of the patch >>> feels like sprinkling hacks around the code base just because we don't >>> have a real tree representation for what we're calling. Any new code >>> that handles calls is going to have to remember to make the same >>> distinction. >> >> Most code either doesn't care about the callee or only handles calls >> to a specific function and thus already checks whether gimple_call_fndecl () >> returns NULL. The patch doesn't feel like it adds hacks everywhere, >> instead it is quite small (smaller than I thought at least). > > OK, just testing your resolve :-) > > Here's a revised patch, updated this morning. Main changes: > > * gimple_call_fn and gimple_call_fntype can be called unconditionally. > They return null for internal functions. > > * gimple_call_set_fn, gimple_call_set_fntype and gimple_call_set_fndecl > assert that the call isn't to an internal function. > > * gimple_call_set_internal_fn asserts the opposite. > > * verify_gimple_call checks internalness vs. nullness. This shouldn't > trigger with the asserts above, but it's there Just In Case. > > * I've not moved code around in verify_gimple_call but added null checks > instead. > > * Some other places also check for nullness rather than specifically for > internal calls. > > * gimple_call_same_target_p uses the expression you suggested. > > * The expanders now take the gimple call statement rather than the > tree operands. > > * I've made the value-numbering changes you suggested. > > I didn't factor out the dumping code because the three cases are > doing different things (one raw dump, one pretty dump to a buffer, > and one pretty dump to a file). > > Tested on x86_64-linux-gnu and arm-linux-gnueabi. OK to install?
Ok with me. Diego, can you have a 2nd eye? Thanks, Richard. > Richard > > > gcc/ > * Makefile.in (INTERNAL_FN_DEF, INTERNAL_FN_H): Define. > (GIMPLE_H): Include $(INTERNAL_FN_H). > (OBJS-common): Add internal-fn.o. > (internal-fn.o): New rule. > * internal-fn.def: New file. > * internal-fn.h: Likewise. > * internal-fn.c: Likewise. > * gimple.h: Include internal-fn.h. > (GF_CALL_INTERNAL): New gf_mask. > (gimple_statement_call): Put fntype into a union with a new > internal_fn field. > (gimple_build_call_internal): Declare. > (gimple_build_call_internal_vec): Likewise. > (gimple_call_same_target_p): Likewise. > (gimple_call_internal_p): New function. > (gimple_call_internal_fn): Likewise. > (gimple_call_fntype): Return null for internal calls. > (gimple_call_set_fntype): Assert that the function is not internal. > (gimple_call_set_fn): Likewise. > (gimple_call_set_fndecl): Likewise. > (gimple_call_set_internal_fn): New function. > (gimple_call_addr_fndecl): Handle null functions. > (gimple_call_return_type): Likewise null types. > * gimple.c (gimple_build_call_internal_1): New function. > (gimple_build_call_internal): Likewise. > (gimple_build_call_internal_vec): Likewise. > (gimple_call_same_target_p): Likewise. > (gimple_call_flags): Handle calls to internal functions. > (gimple_call_fnspec): New function. > (gimple_call_arg_flags, gimple_call_return_flags): Use it. > (gimple_has_side_effects): Handle null functions. > (gimple_rhs_has_side_effects): Likewise. > (gimple_call_copy_skip_args): Handle calls to internal functions. > * cfgexpand.c (expand_call_stmt): Likewise. > * expr.c (expand_expr_real_1): Assert that the call isn't internal. > * gimple-fold.c (gimple_fold_call): Handle null functions. > (gimple_fold_stmt_to_constant_1): Don't fold > calls to internal functions. > * gimple-low.c (gimple_check_call_args): Handle calls to internal > functions. > * gimple-pretty-print.c (dump_gimple_call): Likewise. > * ipa-prop.c (ipa_analyze_call_uses): Handle null functions. > * tree-cfg.c (verify_gimple_call): Handle calls to internal functions. > (do_warn_unused_result): Likewise. > * tree-eh.c (same_handler_p): Use gimple_call_same_target_p. > * tree-ssa-ccp.c (ccp_fold_stmt): Handle calls to internal functions. > * tree-ssa-dom.c (hashable_expr): Use the gimple statement to record > the target of a call. > (initialize_hash_element): Update accordingly. > (hashable_expr_equal_p): Use gimple_call_same_target_p. > (iterative_hash_hashable_expr): Handle calls to internal functions. > (print_expr_hash_elt): Likewise. > * tree-ssa-pre.c (can_value_number_call): Likewise. > (eliminate): Handle null functions. > * tree-ssa-sccvn.c (visit_use): Handle calls to internal functions. > * tree-ssa-structalias.c (get_fi_for_callee): Likewise. > (find_func_aliases): Likewise. > * value-prof.c (gimple_ic_transform): Likewise. > (gimple_indirect_call_to_profile): Likewise. > * lto-streamer-in.c (input_gimple_stmt): Likewise. > * lto-streamer-out.c (output_gimple_stmt): Likewise. > > Index: gcc/Makefile.in > =================================================================== > --- gcc/Makefile.in 2011-04-19 10:27:24.000000000 +0100 > +++ gcc/Makefile.in 2011-04-19 10:56:05.000000000 +0100 > @@ -893,6 +893,8 @@ RTL_ERROR_H = $(RTL_H) $(DIAGNOSTIC_CORE > READ_MD_H = $(OBSTACK_H) $(HASHTAB_H) read-md.h > PARAMS_H = params.h params.def > BUILTINS_DEF = builtins.def sync-builtins.def omp-builtins.def > +INTERNAL_FN_DEF = internal-fn.def > +INTERNAL_FN_H = internal-fn.h $(INTERNAL_FN_DEF) > TREE_H = tree.h all-tree.def tree.def c-family/c-common.def \ > $(lang_tree_files) $(MACHMODE_H) tree-check.h $(BUILTINS_DEF) \ > $(INPUT_H) statistics.h $(VEC_H) treestruct.def $(HASHTAB_H) \ > @@ -901,8 +903,8 @@ TREE_H = tree.h all-tree.def tree.def c- > REGSET_H = regset.h $(BITMAP_H) hard-reg-set.h > BASIC_BLOCK_H = basic-block.h $(PREDICT_H) $(VEC_H) $(FUNCTION_H) cfghooks.h > GIMPLE_H = gimple.h gimple.def gsstruct.def pointer-set.h $(VEC_H) \ > - $(GGC_H) $(BASIC_BLOCK_H) $(TARGET_H) tree-ssa-operands.h \ > - tree-ssa-alias.h vecir.h > + vecir.h $(GGC_H) $(BASIC_BLOCK_H) $(TARGET_H) tree-ssa-operands.h \ > + tree-ssa-alias.h $(INTERNAL_FN_H) > GCOV_IO_H = gcov-io.h gcov-iov.h auto-host.h > COVERAGE_H = coverage.h $(GCOV_IO_H) > DEMANGLE_H = $(srcdir)/../include/demangle.h > @@ -1274,6 +1276,7 @@ OBJS-common = \ > init-regs.o \ > input.o \ > integrate.o \ > + internal-fn.o \ > intl.o \ > ira.o \ > ira-build.o \ > @@ -2759,6 +2762,8 @@ tree-object-size.o: tree-object-size.c $ > $(TM_H) $(TREE_H) $(DIAGNOSTIC_CORE_H) $(DIAGNOSTIC_H) $(TREE_FLOW_H) \ > $(TREE_PASS_H) tree-ssa-propagate.h tree-pretty-print.h \ > gimple-pretty-print.h > +internal-fn.o : internal-fn.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ > + $(INTERNAL_FN_H) $(TREE_H) $(EXPR_H) $(OPTABS_H) $(GIMPLE_H) > gimple.o : gimple.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \ > $(GGC_H) $(GIMPLE_H) $(DIAGNOSTIC_CORE_H) $(DIAGNOSTIC_H) gt-gimple.h \ > $(TREE_FLOW_H) value-prof.h $(FLAGS_H) $(DEMANGLE_H) \ > Index: gcc/internal-fn.def > =================================================================== > --- /dev/null 2011-03-23 08:42:11.268792848 +0000 > +++ gcc/internal-fn.def 2011-04-19 11:04:08.000000000 +0100 > @@ -0,0 +1,39 @@ > +/* Internal functions. > + Copyright (C) 2011 Free Software Foundation, Inc. > + > +This file is part of GCC. > + > +GCC is free software; you can redistribute it and/or modify it under > +the terms of the GNU General Public License as published by the Free > +Software Foundation; either version 3, or (at your option) any later > +version. > + > +GCC is distributed in the hope that it will be useful, but WITHOUT ANY > +WARRANTY; without even the implied warranty of MERCHANTABILITY or > +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License > +for more details. > + > +You should have received a copy of the GNU General Public License > +along with GCC; see the file COPYING3. If not see > +<http://www.gnu.org/licenses/>. */ > + > +/* This file specifies a list of internal "functions". These functions > + differ from built-in functions in that they have no linkage and cannot > + be called directly by the user. They represent operations that are only > + synthesised by GCC itself. > + > + Internal functions are used instead of tree codes if the operation > + and its operands are more naturally represented as a GIMPLE_CALL > + than a GIMPLE_ASSIGN. > + > + Each entry in this file has the form: > + > + DEF_INTERNAL_FN (NAME, FLAGS) > + > + where NAME is the name of the function and FLAGS is a set of > + ECF_* flags. Each entry must have a corresponding expander > + of the form: > + > + void expand_NAME (gimple stmt) > + > + where STMT is the statement that performs the call. */ > Index: gcc/internal-fn.h > =================================================================== > --- /dev/null 2011-03-23 08:42:11.268792848 +0000 > +++ gcc/internal-fn.h 2011-04-19 10:56:05.000000000 +0100 > @@ -0,0 +1,51 @@ > +/* Internal functions. > + Copyright (C) 2011 Free Software Foundation, Inc. > + > +This file is part of GCC. > + > +GCC is free software; you can redistribute it and/or modify it under > +the terms of the GNU General Public License as published by the Free > +Software Foundation; either version 3, or (at your option) any later > +version. > + > +GCC is distributed in the hope that it will be useful, but WITHOUT ANY > +WARRANTY; without even the implied warranty of MERCHANTABILITY or > +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License > +for more details. > + > +You should have received a copy of the GNU General Public License > +along with GCC; see the file COPYING3. If not see > +<http://www.gnu.org/licenses/>. */ > + > +#ifndef GCC_INTERNAL_FN_H > +#define GCC_INTERNAL_FN_H > + > +enum internal_fn { > +#define DEF_INTERNAL_FN(CODE, FLAGS) IFN_##CODE, > +#include "internal-fn.def" > +#undef DEF_INTERNAL_FN > + IFN_LAST > +}; > + > +/* Return the name of internal function FN. The name is only meaningful > + for dumps; it has no linkage. */ > + > +static inline const char * > +internal_fn_name (enum internal_fn fn) > +{ > + extern const char *const internal_fn_name_array[]; > + return internal_fn_name_array[(int) fn]; > +} > + > +/* Return the ECF_* flags for function FN. */ > + > +static inline int > +internal_fn_flags (enum internal_fn fn) > +{ > + extern const int internal_fn_flags_array[]; > + return internal_fn_flags_array[(int) fn]; > +} > + > +extern void expand_internal_call (gimple stmt); > + > +#endif > Index: gcc/internal-fn.c > =================================================================== > --- /dev/null 2011-03-23 08:42:11.268792848 +0000 > +++ gcc/internal-fn.c 2011-04-19 11:04:08.000000000 +0100 > @@ -0,0 +1,64 @@ > +/* Internal functions. > + Copyright (C) 2011 Free Software Foundation, Inc. > + > +This file is part of GCC. > + > +GCC is free software; you can redistribute it and/or modify it under > +the terms of the GNU General Public License as published by the Free > +Software Foundation; either version 3, or (at your option) any later > +version. > + > +GCC is distributed in the hope that it will be useful, but WITHOUT ANY > +WARRANTY; without even the implied warranty of MERCHANTABILITY or > +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License > +for more details. > + > +You should have received a copy of the GNU General Public License > +along with GCC; see the file COPYING3. If not see > +<http://www.gnu.org/licenses/>. */ > + > +#include "config.h" > +#include "system.h" > +#include "coretypes.h" > +#include "internal-fn.h" > +#include "tree.h" > +#include "expr.h" > +#include "optabs.h" > +#include "gimple.h" > + > +/* The names of each internal function, indexed by function number. */ > +const char *const internal_fn_name_array[] = { > +#define DEF_INTERNAL_FN(CODE, FLAGS) #CODE, > +#include "internal-fn.def" > +#undef DEF_INTERNAL_FN > + "<invalid-fn>" > +}; > + > +/* The ECF_* flags of each internal function, indexed by function number. */ > +const int internal_fn_flags_array[] = { > +#define DEF_INTERNAL_FN(CODE, FLAGS) FLAGS, > +#include "internal-fn.def" > +#undef DEF_INTERNAL_FN > + 0 > +}; > + > +/* Routines to expand each internal function, indexed by function number. > + Each routine has the prototype: > + > + expand_<NAME> (gimple stmt) > + > + where STMT is the statement that performs the call. */ > +static void (*const internal_fn_expanders[]) (gimple) = { > +#define DEF_INTERNAL_FN(CODE, FLAGS) expand_##CODE, > +#include "internal-fn.def" > +#undef DEF_INTERNAL_FN > + 0 > +}; > + > +/* Expand STMT, which is a call to internal function FN. */ > + > +void > +expand_internal_call (gimple stmt) > +{ > + internal_fn_expanders[(int) gimple_call_internal_fn (stmt)] (stmt); > +} > Index: gcc/gimple.h > =================================================================== > --- gcc/gimple.h 2011-04-19 10:27:24.000000000 +0100 > +++ gcc/gimple.h 2011-04-19 10:56:05.000000000 +0100 > @@ -30,6 +30,7 @@ #define GCC_GIMPLE_H > #include "basic-block.h" > #include "tree-ssa-operands.h" > #include "tree-ssa-alias.h" > +#include "internal-fn.h" > > struct gimple_seq_node_d; > typedef struct gimple_seq_node_d *gimple_seq_node; > @@ -103,6 +104,7 @@ enum gf_mask { > GF_CALL_VA_ARG_PACK = 1 << 4, > GF_CALL_NOTHROW = 1 << 5, > GF_CALL_ALLOCA_FOR_VAR = 1 << 6, > + GF_CALL_INTERNAL = 1 << 7, > GF_OMP_PARALLEL_COMBINED = 1 << 0, > > /* True on an GIMPLE_OMP_RETURN statement if the return does not require > @@ -407,7 +409,10 @@ struct GTY(()) gimple_statement_call > struct pt_solution call_clobbered; > > /* [ WORD 13 ] */ > - tree fntype; > + union GTY ((desc ("%1.membase.opbase.gsbase.subcode & GF_CALL_INTERNAL"))) > { > + tree GTY ((tag ("0"))) fntype; > + enum internal_fn GTY ((tag ("GF_CALL_INTERNAL"))) internal_fn; > + } u; > > /* [ WORD 14 ] > Operand vector. NOTE! This must always be the last field > @@ -821,6 +826,8 @@ #define gimple_build_debug_bind(var,val, > > gimple gimple_build_call_vec (tree, VEC(tree, heap) *); > gimple gimple_build_call (tree, unsigned, ...); > +gimple gimple_build_call_internal (enum internal_fn, unsigned, ...); > +gimple gimple_build_call_internal_vec (enum internal_fn, VEC(tree, heap) *); > gimple gimple_build_call_from_tree (tree); > gimple gimplify_assign (tree, tree, gimple_seq *); > gimple gimple_build_cond (enum tree_code, tree, tree, tree, tree); > @@ -865,6 +872,7 @@ gimple_seq gimple_seq_alloc (void); > void gimple_seq_free (gimple_seq); > void gimple_seq_add_seq (gimple_seq *, gimple_seq); > gimple_seq gimple_seq_copy (gimple_seq); > +bool gimple_call_same_target_p (const_gimple, const_gimple); > int gimple_call_flags (const_gimple); > int gimple_call_return_flags (const_gimple); > int gimple_call_arg_flags (const_gimple, unsigned); > @@ -2006,13 +2014,36 @@ gimple_call_set_lhs (gimple gs, tree lhs > } > > > +/* Return true if call GS calls an internal-only function, as enumerated > + by internal_fn. */ > + > +static inline bool > +gimple_call_internal_p (const_gimple gs) > +{ > + GIMPLE_CHECK (gs, GIMPLE_CALL); > + return (gs->gsbase.subcode & GF_CALL_INTERNAL) != 0; > +} > + > + > +/* Return the target of internal call GS. */ > + > +static inline enum internal_fn > +gimple_call_internal_fn (const_gimple gs) > +{ > + gcc_gimple_checking_assert (gimple_call_internal_p (gs)); > + return gs->gimple_call.u.internal_fn; > +} > + > + > /* Return the function type of the function called by GS. */ > > static inline tree > gimple_call_fntype (const_gimple gs) > { > GIMPLE_CHECK (gs, GIMPLE_CALL); > - return gs->gimple_call.fntype; > + if (gimple_call_internal_p (gs)) > + return NULL_TREE; > + return gs->gimple_call.u.fntype; > } > > /* Set the type of the function called by GS to FNTYPE. */ > @@ -2021,7 +2052,8 @@ gimple_call_fntype (const_gimple gs) > gimple_call_set_fntype (gimple gs, tree fntype) > { > GIMPLE_CHECK (gs, GIMPLE_CALL); > - gs->gimple_call.fntype = fntype; > + gcc_gimple_checking_assert (!gimple_call_internal_p (gs)); > + gs->gimple_call.u.fntype = fntype; > } > > > @@ -2052,6 +2084,7 @@ gimple_call_fn_ptr (const_gimple gs) > gimple_call_set_fn (gimple gs, tree fn) > { > GIMPLE_CHECK (gs, GIMPLE_CALL); > + gcc_gimple_checking_assert (!gimple_call_internal_p (gs)); > gimple_set_op (gs, 1, fn); > } > > @@ -2062,16 +2095,29 @@ gimple_call_set_fn (gimple gs, tree fn) > gimple_call_set_fndecl (gimple gs, tree decl) > { > GIMPLE_CHECK (gs, GIMPLE_CALL); > + gcc_gimple_checking_assert (!gimple_call_internal_p (gs)); > gimple_set_op (gs, 1, build_fold_addr_expr_loc (gimple_location (gs), > decl)); > } > > + > +/* Set internal function FN to be the function called by call statement GS. > */ > + > +static inline void > +gimple_call_set_internal_fn (gimple gs, enum internal_fn fn) > +{ > + GIMPLE_CHECK (gs, GIMPLE_CALL); > + gcc_gimple_checking_assert (gimple_call_internal_p (gs)); > + gs->gimple_call.u.internal_fn = fn; > +} > + > + > /* Given a valid GIMPLE_CALL function address return the FUNCTION_DECL > associated with the callee if known. Otherwise return NULL_TREE. */ > > static inline tree > gimple_call_addr_fndecl (const_tree fn) > { > - if (TREE_CODE (fn) == ADDR_EXPR) > + if (fn && TREE_CODE (fn) == ADDR_EXPR) > { > tree fndecl = TREE_OPERAND (fn, 0); > if (TREE_CODE (fndecl) == MEM_REF > @@ -2102,6 +2148,9 @@ gimple_call_return_type (const_gimple gs > { > tree type = gimple_call_fntype (gs); > > + if (type == NULL_TREE) > + return TREE_TYPE (gimple_call_lhs (gs)); > + > /* The type returned by a function is the type of its > function type. */ > return TREE_TYPE (type); > Index: gcc/gimple.c > =================================================================== > --- gcc/gimple.c 2011-04-19 10:27:24.000000000 +0100 > +++ gcc/gimple.c 2011-04-19 10:56:05.000000000 +0100 > @@ -277,6 +277,59 @@ gimple_build_call (tree fn, unsigned nar > } > > > +/* Helper for gimple_build_call_internal and gimple_build_call_internal_vec. > + Build the basic components of a GIMPLE_CALL statement to internal > + function FN with NARGS arguments. */ > + > +static inline gimple > +gimple_build_call_internal_1 (enum internal_fn fn, unsigned nargs) > +{ > + gimple s = gimple_build_with_ops (GIMPLE_CALL, ERROR_MARK, nargs + 3); > + s->gsbase.subcode |= GF_CALL_INTERNAL; > + gimple_call_set_internal_fn (s, fn); > + gimple_call_reset_alias_info (s); > + return s; > +} > + > + > +/* Build a GIMPLE_CALL statement to internal function FN. NARGS is > + the number of arguments. The ... are the arguments. */ > + > +gimple > +gimple_build_call_internal (enum internal_fn fn, unsigned nargs, ...) > +{ > + va_list ap; > + gimple call; > + unsigned i; > + > + call = gimple_build_call_internal_1 (fn, nargs); > + va_start (ap, nargs); > + for (i = 0; i < nargs; i++) > + gimple_call_set_arg (call, i, va_arg (ap, tree)); > + va_end (ap); > + > + return call; > +} > + > + > +/* Build a GIMPLE_CALL statement to internal function FN with the arguments > + specified in vector ARGS. */ > + > +gimple > +gimple_build_call_internal_vec (enum internal_fn fn, VEC(tree, heap) *args) > +{ > + unsigned i, nargs; > + gimple call; > + > + nargs = VEC_length (tree, args); > + call = gimple_build_call_internal_1 (fn, nargs); > + for (i = 0; i < nargs; i++) > + gimple_call_set_arg (call, i, VEC_index (tree, args, i)); > + > + return call; > +} > + > + > /* Build a GIMPLE_CALL statement from CALL_EXPR T. Note that T is > assumed to be in GIMPLE form already. Minimal checking is done of > this fact. */ > @@ -1778,6 +1831,20 @@ gimple_has_body_p (tree fndecl) > return (gimple_body (fndecl) || (fn && fn->cfg)); > } > > +/* Return true if calls C1 and C2 are known to go to the same function. */ > + > +bool > +gimple_call_same_target_p (const_gimple c1, const_gimple c2) > +{ > + if (gimple_call_internal_p (c1)) > + return (gimple_call_internal_p (c2) > + && gimple_call_internal_fn (c1) == gimple_call_internal_fn (c2)); > + else > + return (gimple_call_fn (c1) == gimple_call_fn (c2) > + || (gimple_call_fndecl (c1) > + && gimple_call_fndecl (c1) == gimple_call_fndecl (c2))); > +} > + > /* Detect flags from a GIMPLE_CALL. This is just like > call_expr_flags, but for gimple tuples. */ > > @@ -1789,6 +1856,8 @@ gimple_call_flags (const_gimple stmt) > > if (decl) > flags = flags_from_decl_or_type (decl); > + else if (gimple_call_internal_p (stmt)) > + flags = internal_fn_flags (gimple_call_internal_fn (stmt)); > else > flags = flags_from_decl_or_type (gimple_call_fntype (stmt)); > > @@ -1798,18 +1867,32 @@ gimple_call_flags (const_gimple stmt) > return flags; > } > > +/* Return the "fn spec" string for call STMT. */ > + > +static tree > +gimple_call_fnspec (const_gimple stmt) > +{ > + tree type, attr; > + > + type = gimple_call_fntype (stmt); > + if (!type) > + return NULL_TREE; > + > + attr = lookup_attribute ("fn spec", TYPE_ATTRIBUTES (type)); > + if (!attr) > + return NULL_TREE; > + > + return TREE_VALUE (TREE_VALUE (attr)); > +} > + > /* Detects argument flags for argument number ARG on call STMT. */ > > int > gimple_call_arg_flags (const_gimple stmt, unsigned arg) > { > - tree type = gimple_call_fntype (stmt); > - tree attr = lookup_attribute ("fn spec", TYPE_ATTRIBUTES (type)); > - if (!attr) > - return 0; > + tree attr = gimple_call_fnspec (stmt); > > - attr = TREE_VALUE (TREE_VALUE (attr)); > - if (1 + arg >= (unsigned) TREE_STRING_LENGTH (attr)) > + if (!attr || 1 + arg >= (unsigned) TREE_STRING_LENGTH (attr)) > return 0; > > switch (TREE_STRING_POINTER (attr)[1 + arg]) > @@ -1841,19 +1924,13 @@ gimple_call_arg_flags (const_gimple stmt > int > gimple_call_return_flags (const_gimple stmt) > { > - tree type; > - tree attr = NULL_TREE; > + tree attr; > > if (gimple_call_flags (stmt) & ECF_MALLOC) > return ERF_NOALIAS; > > - type = gimple_call_fntype (stmt); > - attr = lookup_attribute ("fn spec", TYPE_ATTRIBUTES (type)); > - if (!attr) > - return 0; > - > - attr = TREE_VALUE (TREE_VALUE (attr)); > - if (TREE_STRING_LENGTH (attr) < 1) > + attr = gimple_call_fnspec (stmt); > + if (!attr || TREE_STRING_LENGTH (attr) < 1) > return 0; > > switch (TREE_STRING_POINTER (attr)[0]) > @@ -2278,6 +2355,7 @@ gimple_has_side_effects (const_gimple s) > if (is_gimple_call (s)) > { > unsigned nargs = gimple_call_num_args (s); > + tree fn; > > if (!(gimple_call_flags (s) & (ECF_CONST | ECF_PURE))) > return true; > @@ -2292,7 +2370,8 @@ gimple_has_side_effects (const_gimple s) > return true; > } > > - if (TREE_SIDE_EFFECTS (gimple_call_fn (s))) > + fn = gimple_call_fn (s); > + if (fn && TREE_SIDE_EFFECTS (fn)) > return true; > > for (i = 0; i < nargs; i++) > @@ -2331,14 +2410,15 @@ gimple_rhs_has_side_effects (const_gimpl > if (is_gimple_call (s)) > { > unsigned nargs = gimple_call_num_args (s); > + tree fn; > > if (!(gimple_call_flags (s) & (ECF_CONST | ECF_PURE))) > return true; > > /* We cannot use gimple_has_volatile_ops here, > because we must ignore a volatile LHS. */ > - if (TREE_SIDE_EFFECTS (gimple_call_fn (s)) > - || TREE_THIS_VOLATILE (gimple_call_fn (s))) > + fn = gimple_call_fn (s); > + if (fn && (TREE_SIDE_EFFECTS (fn) || TREE_THIS_VOLATILE (fn))) > { > gcc_assert (gimple_has_volatile_ops (s)); > return true; > @@ -3094,7 +3174,6 @@ canonicalize_cond_expr_cond (tree t) > gimple_call_copy_skip_args (gimple stmt, bitmap args_to_skip) > { > int i; > - tree fn = gimple_call_fn (stmt); > int nargs = gimple_call_num_args (stmt); > VEC(tree, heap) *vargs = VEC_alloc (tree, heap, nargs); > gimple new_stmt; > @@ -3103,7 +3182,11 @@ gimple_call_copy_skip_args (gimple stmt, > if (!bitmap_bit_p (args_to_skip, i)) > VEC_quick_push (tree, vargs, gimple_call_arg (stmt, i)); > > - new_stmt = gimple_build_call_vec (fn, vargs); > + if (gimple_call_internal_p (stmt)) > + new_stmt = gimple_build_call_internal_vec (gimple_call_internal_fn > (stmt), > + vargs); > + else > + new_stmt = gimple_build_call_vec (gimple_call_fn (stmt), vargs); > VEC_free (tree, heap, vargs); > if (gimple_call_lhs (stmt)) > gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt)); > Index: gcc/cfgexpand.c > =================================================================== > --- gcc/cfgexpand.c 2011-04-19 10:27:24.000000000 +0100 > +++ gcc/cfgexpand.c 2011-04-19 10:56:05.000000000 +0100 > @@ -1837,10 +1837,16 @@ expand_gimple_cond (basic_block bb, gimp > static void > expand_call_stmt (gimple stmt) > { > - tree exp, decl, lhs = gimple_call_lhs (stmt); > + tree exp, decl, lhs; > bool builtin_p; > size_t i; > > + if (gimple_call_internal_p (stmt)) > + { > + expand_internal_call (stmt); > + return; > + } > + > exp = build_vl_exp (CALL_EXPR, gimple_call_num_args (stmt) + 3); > > CALL_EXPR_FN (exp) = gimple_call_fn (stmt); > @@ -1890,6 +1896,7 @@ expand_call_stmt (gimple stmt) > SET_EXPR_LOCATION (exp, gimple_location (stmt)); > TREE_BLOCK (exp) = gimple_block (stmt); > > + lhs = gimple_call_lhs (stmt); > if (lhs) > expand_assignment (lhs, exp, false); > else > Index: gcc/expr.c > =================================================================== > --- gcc/expr.c 2011-04-19 10:56:05.000000000 +0100 > +++ gcc/expr.c 2011-04-19 10:56:05.000000000 +0100 > @@ -8528,9 +8528,12 @@ expand_expr_real_1 (tree exp, rtx target > if (code == SSA_NAME > && (g = SSA_NAME_DEF_STMT (ssa_name)) > && gimple_code (g) == GIMPLE_CALL) > - pmode = promote_function_mode (type, mode, &unsignedp, > - gimple_call_fntype (g), > - 2); > + { > + gcc_assert (!gimple_call_internal_p (g)); > + pmode = promote_function_mode (type, mode, &unsignedp, > + gimple_call_fntype (g), > + 2); > + } > else > pmode = promote_decl_mode (exp, &unsignedp); > gcc_assert (GET_MODE (decl_rtl) == pmode); > Index: gcc/gimple-fold.c > =================================================================== > --- gcc/gimple-fold.c 2011-04-19 10:27:24.000000000 +0100 > +++ gcc/gimple-fold.c 2011-04-19 11:05:02.000000000 +0100 > @@ -1473,7 +1473,8 @@ gimple_fold_call (gimple_stmt_iterator * > > /* Check for virtual calls that became direct calls. */ > callee = gimple_call_fn (stmt); > - if (TREE_CODE (callee) == OBJ_TYPE_REF > + if (callee > + && TREE_CODE (callee) == OBJ_TYPE_REF > && gimple_call_addr_fndecl (OBJ_TYPE_REF_EXPR (callee)) != NULL_TREE) > { > gimple_call_set_fn (stmt, OBJ_TYPE_REF_EXPR (callee)); > @@ -2873,7 +2874,13 @@ gimple_fold_stmt_to_constant_1 (gimple s > > case GIMPLE_CALL: > { > - tree fn = (*valueize) (gimple_call_fn (stmt)); > + tree fn; > + > + if (gimple_call_internal_p (stmt)) > + /* No folding yet for these functions. */ > + return NULL_TREE; > + > + fn = (*valueize) (gimple_call_fn (stmt)); > if (TREE_CODE (fn) == ADDR_EXPR > && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL > && DECL_BUILT_IN (TREE_OPERAND (fn, 0))) > Index: gcc/gimple-low.c > =================================================================== > --- gcc/gimple-low.c 2011-04-19 10:27:24.000000000 +0100 > +++ gcc/gimple-low.c 2011-04-19 10:56:05.000000000 +0100 > @@ -219,6 +219,10 @@ gimple_check_call_args (gimple stmt, tre > tree parms, p; > unsigned int i, nargs; > > + /* Calls to internal functions always match their signature. */ > + if (gimple_call_internal_p (stmt)) > + return true; > + > nargs = gimple_call_num_args (stmt); > > /* Get argument types for verification. */ > Index: gcc/gimple-pretty-print.c > =================================================================== > --- gcc/gimple-pretty-print.c 2011-04-19 10:27:24.000000000 +0100 > +++ gcc/gimple-pretty-print.c 2011-04-19 10:56:05.000000000 +0100 > @@ -616,8 +616,12 @@ dump_gimple_call (pretty_printer *buffer > > if (flags & TDF_RAW) > { > - dump_gimple_fmt (buffer, spc, flags, "%G <%T, %T", > - gs, gimple_call_fn (gs), lhs); > + if (gimple_call_internal_p (gs)) > + dump_gimple_fmt (buffer, spc, flags, "%G <%s, %T", gs, > + internal_fn_name (gimple_call_internal_fn (gs)), > lhs); > + else > + dump_gimple_fmt (buffer, spc, flags, "%G <%T, %T", > + gs, gimple_call_fn (gs), lhs); > if (gimple_call_num_args (gs) > 0) > { > pp_string (buffer, ", "); > @@ -637,7 +641,10 @@ dump_gimple_call (pretty_printer *buffer > > pp_space (buffer); > } > - print_call_name (buffer, gimple_call_fn (gs), flags); > + if (gimple_call_internal_p (gs)) > + pp_string (buffer, internal_fn_name (gimple_call_internal_fn (gs))); > + else > + print_call_name (buffer, gimple_call_fn (gs), flags); > pp_string (buffer, " ("); > dump_gimple_call_args (buffer, gs, flags); > pp_character (buffer, ')'); > Index: gcc/ipa-prop.c > =================================================================== > --- gcc/ipa-prop.c 2011-04-19 10:27:24.000000000 +0100 > +++ gcc/ipa-prop.c 2011-04-19 10:56:05.000000000 +0100 > @@ -1406,6 +1406,8 @@ ipa_analyze_call_uses (struct cgraph_nod > { > tree target = gimple_call_fn (call); > > + if (!target) > + return; > if (TREE_CODE (target) == SSA_NAME) > ipa_analyze_indirect_call_uses (node, info, parms_info, call, target); > else if (TREE_CODE (target) == OBJ_TYPE_REF) > Index: gcc/tree-cfg.c > =================================================================== > --- gcc/tree-cfg.c 2011-04-19 10:27:24.000000000 +0100 > +++ gcc/tree-cfg.c 2011-04-19 10:56:05.000000000 +0100 > @@ -3046,16 +3046,35 @@ verify_gimple_call (gimple stmt) > tree fntype, fndecl; > unsigned i; > > - if (!is_gimple_call_addr (fn)) > + if (gimple_call_internal_p (stmt)) > + { > + if (fn) > + { > + error ("gimple call has two targets"); > + debug_generic_stmt (fn); > + return true; > + } > + } > + else > + { > + if (!fn) > + { > + error ("gimple call has no target"); > + return true; > + } > + } > + > + if (fn && !is_gimple_call_addr (fn)) > { > error ("invalid function in gimple call"); > debug_generic_stmt (fn); > return true; > } > > - if (!POINTER_TYPE_P (TREE_TYPE (fn)) > - || (TREE_CODE (TREE_TYPE (TREE_TYPE (fn))) != FUNCTION_TYPE > - && TREE_CODE (TREE_TYPE (TREE_TYPE (fn))) != METHOD_TYPE)) > + if (fn > + && (!POINTER_TYPE_P (TREE_TYPE (fn)) > + || (TREE_CODE (TREE_TYPE (TREE_TYPE (fn))) != FUNCTION_TYPE > + && TREE_CODE (TREE_TYPE (TREE_TYPE (fn))) != METHOD_TYPE))) > { > error ("non-function in gimple call"); > return true; > @@ -3087,7 +3106,8 @@ verify_gimple_call (gimple stmt) > } > > fntype = gimple_call_fntype (stmt); > - if (gimple_call_lhs (stmt) > + if (fntype > + && gimple_call_lhs (stmt) > && !useless_type_conversion_p (TREE_TYPE (gimple_call_lhs (stmt)), > TREE_TYPE (fntype)) > /* ??? At least C++ misses conversions at assignments from > @@ -7436,6 +7456,8 @@ do_warn_unused_result (gimple_seq seq) > case GIMPLE_CALL: > if (gimple_call_lhs (g)) > break; > + if (gimple_call_internal_p (g)) > + break; > > /* This is a naked call, as opposed to a GIMPLE_CALL with an > LHS. All calls whose value is ignored should be > Index: gcc/tree-eh.c > =================================================================== > --- gcc/tree-eh.c 2011-04-19 10:27:24.000000000 +0100 > +++ gcc/tree-eh.c 2011-04-19 10:56:05.000000000 +0100 > @@ -2743,7 +2743,7 @@ same_handler_p (gimple_seq oneh, gimple_ > || gimple_call_lhs (twos) > || gimple_call_chain (ones) > || gimple_call_chain (twos) > - || !operand_equal_p (gimple_call_fn (ones), gimple_call_fn (twos), 0) > + || !gimple_call_same_target_p (ones, twos) > || gimple_call_num_args (ones) != gimple_call_num_args (twos)) > return false; > > Index: gcc/tree-ssa-ccp.c > =================================================================== > --- gcc/tree-ssa-ccp.c 2011-04-19 10:27:24.000000000 +0100 > +++ gcc/tree-ssa-ccp.c 2011-04-19 10:56:05.000000000 +0100 > @@ -1722,6 +1722,11 @@ ccp_fold_stmt (gimple_stmt_iterator *gsi > return true; > } > > + /* Internal calls provide no argument types, so the extra laxity > + for normal calls does not apply. */ > + if (gimple_call_internal_p (stmt)) > + return false; > + > /* Propagate into the call arguments. Compared to replace_uses_in > this can use the argument slot types for type verification > instead of the current argument type. We also can safely > Index: gcc/tree-ssa-dom.c > =================================================================== > --- gcc/tree-ssa-dom.c 2011-04-19 10:27:24.000000000 +0100 > +++ gcc/tree-ssa-dom.c 2011-04-19 10:56:05.000000000 +0100 > @@ -64,7 +64,7 @@ struct hashable_expr > struct { enum tree_code op; tree opnd; } unary; > struct { enum tree_code op; tree opnd0, opnd1; } binary; > struct { enum tree_code op; tree opnd0, opnd1, opnd2; } ternary; > - struct { tree fn; bool pure; size_t nargs; tree *args; } call; > + struct { gimple fn_from; bool pure; size_t nargs; tree *args; } call; > } ops; > }; > > @@ -258,7 +258,7 @@ initialize_hash_element (gimple stmt, tr > > expr->type = TREE_TYPE (gimple_call_lhs (stmt)); > expr->kind = EXPR_CALL; > - expr->ops.call.fn = gimple_call_fn (stmt); > + expr->ops.call.fn_from = stmt; > > if (gimple_call_flags (stmt) & (ECF_CONST | ECF_PURE)) > expr->ops.call.pure = true; > @@ -422,8 +422,8 @@ hashable_expr_equal_p (const struct hash > > /* If the calls are to different functions, then they > clearly cannot be equal. */ > - if (! operand_equal_p (expr0->ops.call.fn, > - expr1->ops.call.fn, 0)) > + if (!gimple_call_same_target_p (expr0->ops.call.fn_from, > + expr1->ops.call.fn_from)) > return false; > > if (! expr0->ops.call.pure) > @@ -503,9 +503,15 @@ iterative_hash_hashable_expr (const stru > { > size_t i; > enum tree_code code = CALL_EXPR; > + gimple fn_from; > > val = iterative_hash_object (code, val); > - val = iterative_hash_expr (expr->ops.call.fn, val); > + fn_from = expr->ops.call.fn_from; > + if (gimple_call_internal_p (fn_from)) > + val = iterative_hash_hashval_t > + ((hashval_t) gimple_call_internal_fn (fn_from), val); > + else > + val = iterative_hash_expr (gimple_call_fn (fn_from), val); > for (i = 0; i < expr->ops.call.nargs; i++) > val = iterative_hash_expr (expr->ops.call.args[i], val); > } > @@ -565,8 +571,14 @@ print_expr_hash_elt (FILE * stream, cons > { > size_t i; > size_t nargs = element->expr.ops.call.nargs; > + gimple fn_from; > > - print_generic_expr (stream, element->expr.ops.call.fn, 0); > + fn_from = element->expr.ops.call.fn_from; > + if (gimple_call_internal_p (fn_from)) > + fputs (internal_fn_name (gimple_call_internal_fn (fn_from)), > + stream); > + else > + print_generic_expr (stream, gimple_call_fn (fn_from), 0); > fprintf (stream, " ("); > for (i = 0; i < nargs; i++) > { > Index: gcc/tree-ssa-pre.c > =================================================================== > --- gcc/tree-ssa-pre.c 2011-04-19 10:27:24.000000000 +0100 > +++ gcc/tree-ssa-pre.c 2011-04-19 10:56:05.000000000 +0100 > @@ -2657,11 +2657,13 @@ compute_antic (void) > } > > /* Return true if we can value number the call in STMT. This is true > - if we have a pure or constant call. */ > + if we have a pure or constant call to a real function. */ > > static bool > can_value_number_call (gimple stmt) > { > + if (gimple_call_internal_p (stmt)) > + return false; > if (gimple_call_flags (stmt) & (ECF_PURE | ECF_CONST)) > return true; > return false; > @@ -4384,6 +4386,8 @@ eliminate (void) > { > tree orig_fn = gimple_call_fn (stmt); > tree fn; > + if (!orig_fn) > + continue; > if (TREE_CODE (orig_fn) == SSA_NAME) > fn = VN_INFO (orig_fn)->valnum; > else if (TREE_CODE (orig_fn) == OBJ_TYPE_REF > Index: gcc/tree-ssa-sccvn.c > =================================================================== > --- gcc/tree-ssa-sccvn.c 2011-04-19 10:27:24.000000000 +0100 > +++ gcc/tree-ssa-sccvn.c 2011-04-19 10:56:05.000000000 +0100 > @@ -3125,7 +3125,8 @@ visit_use (tree use) > /* ??? We should handle stores from calls. */ > else if (TREE_CODE (lhs) == SSA_NAME) > { > - if (gimple_call_flags (stmt) & (ECF_PURE | ECF_CONST)) > + if (!gimple_call_internal_p (stmt) > + && gimple_call_flags (stmt) & (ECF_PURE | ECF_CONST)) > changed = visit_reference_op_call (lhs, stmt); > else > changed = defs_to_varying (stmt); > Index: gcc/tree-ssa-structalias.c > =================================================================== > --- gcc/tree-ssa-structalias.c 2011-04-19 10:27:24.000000000 +0100 > +++ gcc/tree-ssa-structalias.c 2011-04-19 10:56:05.000000000 +0100 > @@ -4026,6 +4026,8 @@ get_fi_for_callee (gimple call) > { > tree decl; > > + gcc_assert (!gimple_call_internal_p (call)); > + > /* If we can directly resolve the function being called, do so. > Otherwise, it must be some sort of indirect expression that > we should still be able to handle. */ > @@ -4319,6 +4321,7 @@ find_func_aliases (gimple origt) > /* Fallthru to general call handling. */; > } > if (!in_ipa_mode > + || gimple_call_internal_p (t) > || (fndecl > && (!(fi = lookup_vi_for_tree (fndecl)) > || !fi->is_fn_info))) > Index: gcc/value-prof.c > =================================================================== > --- gcc/value-prof.c 2011-04-19 10:27:24.000000000 +0100 > +++ gcc/value-prof.c 2011-04-19 10:56:05.000000000 +0100 > @@ -1258,6 +1258,9 @@ gimple_ic_transform (gimple stmt) > if (gimple_call_fndecl (stmt) != NULL_TREE) > return false; > > + if (gimple_call_internal_p (stmt)) > + return false; > + > histogram = gimple_histogram_value_of_type (cfun, stmt, > HIST_TYPE_INDIR_CALL); > if (!histogram) > return false; > @@ -1649,6 +1652,7 @@ gimple_indirect_call_to_profile (gimple > tree callee; > > if (gimple_code (stmt) != GIMPLE_CALL > + || gimple_call_internal_p (stmt) > || gimple_call_fndecl (stmt) != NULL_TREE) > return; > > Index: gcc/lto-streamer-in.c > =================================================================== > --- gcc/lto-streamer-in.c 2011-04-19 10:27:24.000000000 +0100 > +++ gcc/lto-streamer-in.c 2011-04-19 10:56:05.000000000 +0100 > @@ -1063,7 +1063,13 @@ input_gimple_stmt (struct lto_input_bloc > } > } > if (is_gimple_call (stmt)) > - gimple_call_set_fntype (stmt, lto_input_tree (ib, data_in)); > + { > + if (gimple_call_internal_p (stmt)) > + gimple_call_set_internal_fn > + (stmt, (enum internal_fn) lto_input_sleb128 (ib)); > + else > + gimple_call_set_fntype (stmt, lto_input_tree (ib, data_in)); > + } > break; > > case GIMPLE_NOP: > Index: gcc/lto-streamer-out.c > =================================================================== > --- gcc/lto-streamer-out.c 2011-04-19 10:27:24.000000000 +0100 > +++ gcc/lto-streamer-out.c 2011-04-19 10:56:05.000000000 +0100 > @@ -1760,7 +1760,12 @@ output_gimple_stmt (struct output_block > lto_output_tree_ref (ob, op); > } > if (is_gimple_call (stmt)) > - lto_output_tree_ref (ob, gimple_call_fntype (stmt)); > + { > + if (gimple_call_internal_p (stmt)) > + output_sleb128 (ob, (int) gimple_call_internal_fn (stmt)); > + else > + lto_output_tree_ref (ob, gimple_call_fntype (stmt)); > + } > break; > > case GIMPLE_NOP: >