+2013-04-19 Martin Jambor <mjambor@suse.cz>
+
+ PR tree-optimization/56718
+ * ipa-cp.c (ipa_value_from_known_type_jfunc): Moved...
+ * ipa-prop.c (ipa_binfo_from_known_type_jfunc): ...here, renamed
+ and made public. Adjusted all callers.
+ (ipa_intraprocedural_devirtualization): New function.
+ * ipa-prop.h (ipa_binfo_from_known_type_jfunc): Declare.
+ (ipa_intraprocedural_devirtualization): Likewise.
+ * Makefile.in (tree-ssa-pre.o): Add ipa-prop.h to dependencies.
+
2013-04-19 Richard Biener <rguenther@suse.de>
PR tree-optimization/57000
$(TM_H) coretypes.h $(TREE_PASS_H) $(FLAGS_H) langhooks.h \
$(CFGLOOP_H) alloc-pool.h $(BASIC_BLOCK_H) $(BITMAP_H) $(HASH_TABLE_H) \
$(GIMPLE_H) $(TREE_INLINE_H) tree-iterator.h tree-ssa-sccvn.h $(PARAMS_H) \
- $(DBGCNT_H) tree-scalar-evolution.h $(GIMPLE_PRETTY_PRINT_H) domwalk.h
+ $(DBGCNT_H) tree-scalar-evolution.h $(GIMPLE_PRETTY_PRINT_H) domwalk.h \
+ $(IPA_PROP_H)
tree-ssa-sccvn.o : tree-ssa-sccvn.c $(TREE_FLOW_H) $(CONFIG_H) \
$(SYSTEM_H) $(TREE_H) $(DIAGNOSTIC_H) \
$(TM_H) coretypes.h $(DUMPFILE_H) $(FLAGS_H) $(CFGLOOP_H) \
return NULL_TREE;
}
-/* Extract the acual BINFO being described by JFUNC which must be a known type
- jump function. */
-
-static tree
-ipa_value_from_known_type_jfunc (struct ipa_jump_func *jfunc)
-{
- tree base_binfo = TYPE_BINFO (ipa_get_jf_known_type_base_type (jfunc));
- if (!base_binfo)
- return NULL_TREE;
- return get_binfo_at_offset (base_binfo,
- ipa_get_jf_known_type_offset (jfunc),
- ipa_get_jf_known_type_component_type (jfunc));
-}
-
/* Determine whether JFUNC evaluates to a known value (that is either a
constant or a binfo) and if so, return it. Otherwise return NULL. INFO
describes the caller node so that pass-through jump functions can be
if (jfunc->type == IPA_JF_CONST)
return ipa_get_jf_constant (jfunc);
else if (jfunc->type == IPA_JF_KNOWN_TYPE)
- return ipa_value_from_known_type_jfunc (jfunc);
+ return ipa_binfo_from_known_type_jfunc (jfunc);
else if (jfunc->type == IPA_JF_PASS_THROUGH
|| jfunc->type == IPA_JF_ANCESTOR)
{
if (jfunc->type == IPA_JF_KNOWN_TYPE)
{
- val = ipa_value_from_known_type_jfunc (jfunc);
+ val = ipa_binfo_from_known_type_jfunc (jfunc);
if (!val)
return set_lattice_contains_variable (dest_lat);
}
jfunc->value.ancestor.agg_preserved = agg_preserved;
}
+/* Extract the acual BINFO being described by JFUNC which must be a known type
+ jump function. */
+
+tree
+ipa_binfo_from_known_type_jfunc (struct ipa_jump_func *jfunc)
+{
+ tree base_binfo = TYPE_BINFO (jfunc->value.known_type.base_type);
+ if (!base_binfo)
+ return NULL_TREE;
+ return get_binfo_at_offset (base_binfo,
+ jfunc->value.known_type.offset,
+ jfunc->value.known_type.component_type);
+}
+
/* Structure to be passed in between detect_type_change and
check_stmt_for_type_change. */
pop_cfun ();
}
+/* Given a statement CALL which must be a GIMPLE_CALL calling an OBJ_TYPE_REF
+ attempt a type-based devirtualization. If successful, return the
+ target function declaration, otherwise return NULL. */
+
+tree
+ipa_intraprocedural_devirtualization (gimple call)
+{
+ tree binfo, token, fndecl;
+ struct ipa_jump_func jfunc;
+ tree otr = gimple_call_fn (call);
+
+ jfunc.type = IPA_JF_UNKNOWN;
+ compute_known_type_jump_func (OBJ_TYPE_REF_OBJECT (otr), &jfunc,
+ call);
+ if (jfunc.type != IPA_JF_KNOWN_TYPE)
+ return NULL_TREE;
+ binfo = ipa_binfo_from_known_type_jfunc (&jfunc);
+ if (!binfo)
+ return NULL_TREE;
+ token = OBJ_TYPE_REF_TOKEN (otr);
+ fndecl = gimple_get_virt_method_for_binfo (tree_low_cst (token, 1),
+ binfo);
+ return fndecl;
+}
/* Update the jump function DST when the call graph edge corresponding to SRC is
is being inlined, knowing that DST is of type ancestor and src of known
vec<tree> ,
vec<ipa_agg_jump_function_p> );
struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, tree);
+tree ipa_binfo_from_known_type_jfunc (struct ipa_jump_func *);
+tree ipa_intraprocedural_devirtualization (gimple);
/* Functions related to both. */
void ipa_analyze_node (struct cgraph_node *);
+2013-04-19 Martin Jambor <mjambor@suse.cz>
+
+ PR tree-optimization/56718
+ * g++.dg/ipa/imm-devirt-1.C: New test.
+ * g++.dg/ipa/imm-devirt-2.C: Likewise.
+
2013-04-19 Richard Biener <rguenther@suse.de>
PR tree-optimization/57000
--- /dev/null
+/* Verify that virtual calls are folded even early inlining puts them into one
+ function with the definition. */
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-fre1-details" } */
+
+extern "C" void abort (void);
+
+class A
+{
+public:
+ int data;
+ virtual int foo (int i);
+};
+
+
+class B : public A
+{
+public:
+ __attribute__ ((noinline)) B();
+ virtual int foo (int i);
+};
+
+int __attribute__ ((noinline)) A::foo (int i)
+{
+ return i + 1;
+}
+
+int __attribute__ ((noinline)) B::foo (int i)
+{
+ return i + 2;
+}
+
+int __attribute__ ((noinline,noclone)) get_input(void)
+{
+ return 1;
+}
+
+__attribute__ ((noinline)) B::B()
+{
+}
+
+static inline int middleman_1 (class A *obj, int i)
+{
+ return obj->foo (i);
+}
+
+static inline int middleman_2 (class B *obj, int i)
+{
+ return middleman_1 (obj, i);
+}
+
+int main (int argc, char *argv[])
+{
+ class B b;
+
+ if (middleman_2 (&b, get_input ()) != 3)
+ abort ();
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump "Replacing call target with foo" "fre1" } } */
+/* { dg-final { cleanup-tree-dump "fre1" } } */
--- /dev/null
+/* Verify that virtual calls are folded even early inlining puts them into one
+ function with the definition. */
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-fre1-details" } */
+
+extern "C" void abort (void);
+
+class Distraction
+{
+public:
+ float f;
+ double d;
+ Distraction ()
+ {
+ f = 8.3;
+ d = 10.2;
+ }
+ virtual float bar (float z);
+};
+
+class A
+{
+public:
+ int data;
+ virtual int foo (int i);
+};
+
+class B : public A
+{
+public:
+ int data_2;
+ virtual int foo (int i);
+ virtual int baz (int i);
+};
+
+
+class C : public Distraction, public B
+{
+public:
+ __attribute__ ((noinline)) C();
+ virtual int foo (int i);
+};
+
+float __attribute__ ((noinline)) Distraction::bar (float z)
+{
+ f += z;
+ return f/2;
+}
+
+int __attribute__ ((noinline)) A::foo (int i)
+{
+ return i + 1;
+}
+
+int __attribute__ ((noinline)) B::foo (int i)
+{
+ return i + 2;
+}
+
+int __attribute__ ((noinline)) B::baz (int i)
+{
+ return i * 15;
+}
+
+int __attribute__ ((noinline)) C::foo (int i)
+{
+ return i + 3;
+}
+
+int __attribute__ ((noinline,noclone)) get_input(void)
+{
+ return 1;
+}
+
+static inline int middleman (class A *obj, int i)
+{
+ return obj->foo (i);
+}
+
+__attribute__ ((noinline)) C::C()
+{
+}
+
+int main (int argc, char *argv[])
+{
+ class C c;
+
+ if (middleman (&c, get_input ()) != 4)
+ abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump "Replacing call target" "fre1" } } */
+/* { dg-final { cleanup-tree-dump "fre1" } } */
#include "params.h"
#include "dbgcnt.h"
#include "domwalk.h"
+#include "ipa-prop.h"
/* TODO:
fn = VN_INFO (orig_fn)->valnum;
else if (TREE_CODE (orig_fn) == OBJ_TYPE_REF
&& TREE_CODE (OBJ_TYPE_REF_EXPR (orig_fn)) == SSA_NAME)
- fn = VN_INFO (OBJ_TYPE_REF_EXPR (orig_fn))->valnum;
+ {
+ fn = VN_INFO (OBJ_TYPE_REF_EXPR (orig_fn))->valnum;
+ if (!gimple_call_addr_fndecl (fn))
+ {
+ fn = ipa_intraprocedural_devirtualization (stmt);
+ if (fn)
+ fn = build_fold_addr_expr (fn);
+ }
+ }
else
continue;
if (gimple_call_addr_fndecl (fn) != NULL_TREE