===================================================================
@@ -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.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) \
===================================================================
@@ -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 (tree lhs, tree *args)
+
+ where LHS and ARGS are as for expand_internal_call. */
===================================================================
@@ -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 (enum internal_fn, tree, tree *);
+
+#endif
===================================================================
@@ -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"
+
+/* 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> (tree lhs, tree *args)
+
+ where LHS and ARGS are as for expand_internal_call. */
+static void (*const internal_fn_expanders[]) (tree, tree *) = {
+#define DEF_INTERNAL_FN(CODE, FLAGS) expand_##CODE,
+#include "internal-fn.def"
+#undef DEF_INTERNAL_FN
+ 0
+};
+
+/* Expand a call to internal function FN. ARGS is an array of the
+ function's arguments and LHS is where the result should be stored. */
+
+void
+expand_internal_call (enum internal_fn fn, tree lhs, tree *args)
+{
+ internal_fn_expanders[(int) fn] (lhs, args);
+}
===================================================================
@@ -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;
@@ -102,6 +103,7 @@ enum gf_mask {
GF_CALL_TAILCALL = 1 << 3,
GF_CALL_VA_ARG_PACK = 1 << 4,
GF_CALL_NOTHROW = 1 << 5,
+ GF_CALL_INTERNAL = 1 << 6,
GF_OMP_PARALLEL_COMBINED = 1 << 0,
/* True on an GIMPLE_OMP_RETURN statement if the return does not require
@@ -406,7 +408,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
@@ -820,6 +825,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);
@@ -864,6 +871,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);
@@ -2004,13 +2012,35 @@ 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;
+ gcc_gimple_checking_assert (!gimple_call_internal_p (gs));
+ return gs->gimple_call.u.fntype;
}
/* Set the type of the function called by GS to FNTYPE. */
@@ -2019,7 +2049,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;
}
@@ -2029,8 +2060,12 @@ gimple_call_set_fntype (gimple gs, tree
static inline tree
gimple_call_fn (const_gimple gs)
{
+ tree op;
+
GIMPLE_CHECK (gs, GIMPLE_CALL);
- return gimple_op (gs, 1);
+ op = gimple_op (gs, 1);
+ gcc_gimple_checking_assert (op != NULL_TREE);
+ return op;
}
/* Return a pointer to the tree node representing the function called by call
@@ -2044,12 +2079,25 @@ gimple_call_fn_ptr (const_gimple gs)
}
+/* 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);
+ gs->gsbase.subcode |= GF_CALL_INTERNAL;
+ gimple_set_op (gs, 1, NULL_TREE);
+ gs->gimple_call.u.internal_fn = fn;
+}
+
+
/* Set FN to be the function called by call statement GS. */
static inline void
gimple_call_set_fn (gimple gs, tree fn)
{
GIMPLE_CHECK (gs, GIMPLE_CALL);
+ gs->gsbase.subcode &= ~GF_CALL_INTERNAL;
gimple_set_op (gs, 1, fn);
}
@@ -2071,7 +2119,12 @@ gimple_call_set_fndecl (gimple gs, tree
static inline tree
gimple_call_fndecl (const_gimple gs)
{
- tree addr = gimple_call_fn (gs);
+ tree addr;
+
+ if (gimple_call_internal_p (gs))
+ return NULL_TREE;
+
+ addr = gimple_call_fn (gs);
if (TREE_CODE (addr) == ADDR_EXPR)
{
tree fndecl = TREE_OPERAND (addr, 0);
@@ -2094,7 +2147,12 @@ gimple_call_fndecl (const_gimple gs)
static inline tree
gimple_call_return_type (const_gimple gs)
{
- tree type = gimple_call_fntype (gs);
+ tree type;
+
+ if (gimple_call_internal_p (gs))
+ return TREE_TYPE (gimple_call_lhs (gs));
+
+ type = gimple_call_fntype (gs);
/* The type returned by a function is the type of its
function type. */
===================================================================
@@ -230,7 +230,7 @@ gimple_build_call_1 (tree fn, unsigned n
gimple s = gimple_build_with_ops (GIMPLE_CALL, ERROR_MARK, nargs + 3);
if (TREE_CODE (fn) == FUNCTION_DECL)
fn = build_fold_addr_expr (fn);
- gimple_set_op (s, 1, fn);
+ gimple_call_set_fn (s, fn);
gimple_call_set_fntype (s, TREE_TYPE (TREE_TYPE (fn)));
gimple_call_reset_alias_info (s);
return s;
@@ -277,6 +277,58 @@ 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);
+ 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. */
@@ -1399,9 +1451,12 @@ walk_gimple_op (gimple stmt, walk_tree_f
if (ret)
return ret;
- ret = walk_tree (gimple_call_fn_ptr (stmt), callback_op, wi, pset);
- if (ret)
- return ret;
+ if (!gimple_call_internal_p (stmt))
+ {
+ ret = walk_tree (gimple_call_fn_ptr (stmt), callback_op, wi, pset);
+ if (ret)
+ return ret;
+ }
for (i = 0; i < gimple_call_num_args (stmt); i++)
{
@@ -1773,6 +1828,19 @@ 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_internal_p (c2)
+ && operand_equal_p (gimple_call_fn (c1), gimple_call_fn (c2), 0));
+}
+
/* Detect flags from a GIMPLE_CALL. This is just like
call_expr_flags, but for gimple tuples. */
@@ -1784,6 +1852,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,8 +1868,14 @@ gimple_call_flags (const_gimple 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));
+ tree type;
+ tree attr;
+
+ if (gimple_call_internal_p (stmt))
+ return 0;
+
+ type = gimple_call_fntype (stmt);
+ attr = lookup_attribute ("fn spec", TYPE_ATTRIBUTES (type));
if (!attr)
return 0;
@@ -1839,6 +1915,9 @@ gimple_call_return_flags (const_gimple s
tree type;
tree attr = NULL_TREE;
+ if (gimple_call_internal_p (stmt))
+ return 0;
+
if (gimple_call_flags (stmt) & ECF_MALLOC)
return ERF_NOALIAS;
@@ -2287,7 +2366,8 @@ gimple_has_side_effects (const_gimple s)
return true;
}
- if (TREE_SIDE_EFFECTS (gimple_call_fn (s)))
+ if (!gimple_call_internal_p (s)
+ && TREE_SIDE_EFFECTS (gimple_call_fn (s)))
return true;
for (i = 0; i < nargs; i++)
@@ -2332,8 +2412,9 @@ gimple_rhs_has_side_effects (const_gimpl
/* 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)))
+ if (!gimple_call_internal_p (s)
+ && (TREE_SIDE_EFFECTS (gimple_call_fn (s))
+ || TREE_THIS_VOLATILE (gimple_call_fn (s))))
{
gcc_assert (gimple_has_volatile_ops (s));
return true;
@@ -3089,7 +3170,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;
@@ -3098,7 +3178,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));
===================================================================
@@ -1831,16 +1831,39 @@ expand_gimple_cond (basic_block bb, gimp
return new_bb;
}
+/* A subroutine of expand_call_stmt. Expand GIMPLE_CALL statement STMT,
+ which is known to be to an internal function. */
+
+static void
+expand_gimple_call_internal (gimple stmt)
+{
+ tree lhs;
+ tree *args;
+ size_t i;
+
+ lhs = gimple_call_lhs (stmt);
+ args = XALLOCAVEC (tree, gimple_call_num_args (stmt));
+ for (i = 0; i < gimple_call_num_args (stmt); i++)
+ args[i] = gimple_call_arg (stmt, i);
+ expand_internal_call (gimple_call_internal_fn (stmt), lhs, args);
+}
+
/* A subroutine of expand_gimple_stmt_1, expanding one GIMPLE_CALL
statement 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_gimple_call_internal (stmt);
+ return;
+ }
+
exp = build_vl_exp (CALL_EXPR, gimple_call_num_args (stmt) + 3);
CALL_EXPR_FN (exp) = gimple_call_fn (stmt);
@@ -1885,6 +1908,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
===================================================================
@@ -8521,10 +8521,15 @@ expand_expr_real_1 (tree exp, rtx target
enum machine_mode pmode;
/* Get the signedness to be used for this variable. Ensure we get
- the same mode we got when the variable was declared. */
+ the same mode we got when the variable was declared.
+
+ Note that calls to internal functions do not result in a
+ call instruction, so promote_function_mode is not meaningful
+ in that case. */
if (code == SSA_NAME
&& (g = SSA_NAME_DEF_STMT (ssa_name))
- && gimple_code (g) == GIMPLE_CALL)
+ && gimple_code (g) == GIMPLE_CALL
+ && !gimple_call_internal_p (g))
pmode = promote_function_mode (type, mode, &unsignedp,
gimple_call_fntype (g),
2);
===================================================================
@@ -2856,7 +2856,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)))
===================================================================
@@ -224,6 +224,8 @@ gimple_check_call_args (gimple stmt, tre
/* Get argument types for verification. */
if (fndecl)
parms = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
+ else if (gimple_call_internal_p (stmt))
+ parms = NULL_TREE;
else
parms = TYPE_ARG_TYPES (gimple_call_fntype (stmt));
===================================================================
@@ -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, ')');
===================================================================
@@ -1416,8 +1416,12 @@ ipa_analyze_call_uses (struct cgraph_nod
struct ipa_node_params *info,
struct param_analysis_info *parms_info, gimple call)
{
- tree target = gimple_call_fn (call);
+ tree target;
+
+ if (gimple_call_internal_p (call))
+ return;
+ target = gimple_call_fn (call);
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)
===================================================================
@@ -3042,23 +3042,43 @@ valid_fixed_convert_types_p (tree type1,
static bool
verify_gimple_call (gimple stmt)
{
- tree fn = gimple_call_fn (stmt);
+ tree fn;
tree fntype, fndecl;
unsigned i;
- if (!is_gimple_call_addr (fn))
+ if (!gimple_call_internal_p (stmt))
{
- 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))
- {
- error ("non-function in gimple call");
- return true;
+ fn = gimple_call_fn (stmt);
+ if (!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))
+ {
+ error ("non-function in gimple call");
+ return true;
+ }
+ fntype = gimple_call_fntype (stmt);
+ if (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
+ void * call results.
+ ??? Java is completely off. Especially with functions
+ returning java.lang.Object.
+ For now simply allow arbitrary pointer type conversions. */
+ && !(POINTER_TYPE_P (TREE_TYPE (gimple_call_lhs (stmt)))
+ && POINTER_TYPE_P (TREE_TYPE (fntype))))
+ {
+ error ("invalid conversion in gimple call");
+ debug_generic_stmt (TREE_TYPE (gimple_call_lhs (stmt)));
+ debug_generic_stmt (TREE_TYPE (fntype));
+ return true;
+ }
}
fndecl = gimple_call_fndecl (stmt);
@@ -3086,24 +3106,6 @@ verify_gimple_call (gimple stmt)
return true;
}
- fntype = gimple_call_fntype (stmt);
- if (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
- void * call results.
- ??? Java is completely off. Especially with functions
- returning java.lang.Object.
- For now simply allow arbitrary pointer type conversions. */
- && !(POINTER_TYPE_P (TREE_TYPE (gimple_call_lhs (stmt)))
- && POINTER_TYPE_P (TREE_TYPE (fntype))))
- {
- error ("invalid conversion in gimple call");
- debug_generic_stmt (TREE_TYPE (gimple_call_lhs (stmt)));
- debug_generic_stmt (TREE_TYPE (fntype));
- return true;
- }
-
if (gimple_call_chain (stmt)
&& !is_gimple_val (gimple_call_chain (stmt)))
{
@@ -3121,7 +3123,7 @@ verify_gimple_call (gimple stmt)
error ("static chain in indirect gimple call");
return true;
}
- fn = TREE_OPERAND (fn, 0);
+ fn = TREE_OPERAND (gimple_call_fn (stmt), 0);
if (!DECL_STATIC_CHAIN (fn))
{
@@ -7436,6 +7438,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
===================================================================
@@ -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;
===================================================================
@@ -1723,6 +1723,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
===================================================================
@@ -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++)
{
===================================================================
@@ -4381,6 +4381,7 @@ eliminate (void)
/* Visit indirect calls and turn them into direct calls if
possible. */
if (is_gimple_call (stmt)
+ && !gimple_call_internal_p (stmt)
&& TREE_CODE (gimple_call_fn (stmt)) == SSA_NAME)
{
tree orig_fn = gimple_call_fn (stmt);
===================================================================
@@ -911,7 +911,10 @@ copy_reference_ops_from_call (gimple cal
memset (&temp, 0, sizeof (temp));
temp.type = gimple_call_return_type (call);
temp.opcode = CALL_EXPR;
- temp.op0 = gimple_call_fn (call);
+ if (gimple_call_internal_p (call))
+ temp.op0 = NULL_TREE;
+ else
+ temp.op0 = gimple_call_fn (call);
temp.op1 = gimple_call_chain (call);
temp.off = -1;
VEC_safe_push (vn_reference_op_s, heap, *result, &temp);
===================================================================
@@ -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)))
===================================================================
@@ -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;
===================================================================
@@ -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:
===================================================================
@@ -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: