summaryrefslogtreecommitdiff
path: root/gcc/gimple.c
diff options
context:
space:
mode:
authorrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>2011-04-20 08:21:25 +0000
committerrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>2011-04-20 08:21:25 +0000
commitfb049fbac341de8b83c1e9aef4855ab69697430a (patch)
tree302de9b13283837581d6bef410f79f930039eedc /gcc/gimple.c
parent8102101361cc08f95bc8b313bbba2cb6ee91ede8 (diff)
downloadgcc-fb049fbac341de8b83c1e9aef4855ab69697430a.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@172758 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/gimple.c')
-rw-r--r--gcc/gimple.c123
1 files changed, 103 insertions, 20 deletions
diff --git a/gcc/gimple.c b/gcc/gimple.c
index c6868befc59..909091bcfd0 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -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));