diff options
Diffstat (limited to 'gcc/gimple.c')
-rw-r--r-- | gcc/gimple.c | 123 |
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)); |