Makefile.in (INTERNAL_FN_DEF, [...]): Define.

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.

From-SVN: r172758
This commit is contained in:
Richard Sandiford 2011-04-20 08:21:25 +00:00 committed by Richard Sandiford
parent 7da29ed0cb
commit 25583c4f45
23 changed files with 497 additions and 51 deletions

View File

@ -1,3 +1,67 @@
2011-04-20 Richard Sandiford <richard.sandiford@linaro.org>
* 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.
2011-04-19 Jan Hubicka <jh@suse.cz>
* ipa-inline-transform.c (save_inline_function_body): Add comments.

View File

@ -893,6 +893,8 @@ RTL_ERROR_H = $(RTL_H) $(DIAGNOSTIC_CORE_H)
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-family/c-common.def \
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 \
@ -2760,6 +2763,8 @@ tree-object-size.o: tree-object-size.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(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) \

View File

@ -1837,10 +1837,16 @@ expand_gimple_cond (basic_block bb, gimple stmt)
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

View File

@ -8528,9 +8528,12 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
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);

View File

@ -1541,7 +1541,7 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace)
/* 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)
{
tree binfo, fndecl, delta, obj;
HOST_WIDE_INT token;
@ -2958,7 +2958,13 @@ gimple_fold_stmt_to_constant_1 (gimple stmt, tree (*valueize) (tree))
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)))

View File

@ -219,6 +219,10 @@ gimple_check_call_args (gimple stmt, tree fndecl)
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. */

View File

@ -616,8 +616,12 @@ dump_gimple_call (pretty_printer *buffer, gimple gs, int spc, int flags)
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, gimple gs, int spc, int flags)
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, ')');

View File

@ -277,6 +277,59 @@ gimple_build_call (tree fn, unsigned nargs, ...)
}
/* 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, unsigned arg)
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_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;
/* 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 @@ gimple
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, bitmap args_to_skip)
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));

View File

@ -30,6 +30,7 @@ along with GCC; see the file COPYING3. If not see
#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 @@ gimple gimple_build_debug_bind_stat (tree, tree, gimple MEM_STAT_DECL);
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);
@ -2007,13 +2015,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. */
@ -2022,7 +2053,8 @@ static inline void
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;
}
@ -2053,6 +2085,7 @@ static inline void
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);
}
@ -2063,16 +2096,29 @@ static inline void
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
@ -2103,6 +2149,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);

64
gcc/internal-fn.c Normal file
View File

@ -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);
}

39
gcc/internal-fn.def Normal file
View File

@ -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. */

51
gcc/internal-fn.h Normal file
View File

@ -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);
#endif

View File

@ -1456,6 +1456,8 @@ ipa_analyze_call_uses (struct cgraph_node *node,
{
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)

View File

@ -1063,7 +1063,13 @@ input_gimple_stmt (struct lto_input_block *ib, struct data_in *data_in,
}
}
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:

View File

@ -1760,7 +1760,12 @@ output_gimple_stmt (struct output_block *ob, gimple stmt)
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:

View File

@ -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

View File

@ -2743,7 +2743,7 @@ same_handler_p (gimple_seq oneh, gimple_seq twoh)
|| 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;

View File

@ -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

View File

@ -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, tree lhs,
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 hashable_expr *expr0,
/* 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 struct hashable_expr *expr, hashval_t val)
{
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, const struct expr_hash_elt *element)
{
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++)
{

View File

@ -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

View File

@ -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);

View File

@ -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)))

View File

@ -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 stmt, histogram_values *values)
tree callee;
if (gimple_code (stmt) != GIMPLE_CALL
|| gimple_call_internal_p (stmt)
|| gimple_call_fndecl (stmt) != NULL_TREE)
return;