From 0f59171d711aaa9623e2ebc708324299662e55bd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 22 Jun 2004 17:26:04 -0700 Subject: [PATCH] tree.def (VTABLE_REF): Remove. * tree.def (VTABLE_REF): Remove. (OBJ_TYPE_REF): New. (TRY_CATCH_EXPR, TRY_FINALLY_EXPR): Set type 's'. * expr.c (expand_expr_real_1): Replace VTABLE_REF with OBJ_TYPE_REF. * fold-const.c (non_lvalue): Likewise. * gimplify.c (gimplify_expr): Likewise. (gimplify_call_expr): Use is_gimple_call_addr. * langhooks-def.h (LANG_HOOKS_FOLD_OBJ_TYPE_REF): New. * langhooks.h (fold_obj_type_ref): New. * tree-gimple.c (is_gimple_call_addr): New. * tree-gimple.h (is_gimple_call_addr): Declare. * tree-inline.c (inlinable_function_p): Fix merge error. (estimate_num_insns_1): Replace VTABLE_REF with OBJ_TYPE_REF. * tree-pretty-print.c (dump_generic_node): Likewise. (print_call_name): Handle OBJ_TYPE_REF. * tree-ssa-ccp.c (fold_stmt): Fold OBJ_TYPE_REF. * tree-ssa-operands.c (get_expr_operands): Handle OBJ_TYPE_REF. * tree.h (OBJ_TYPE_REF_EXPR): New. (OBJ_TYPE_REF_OBJECT, OBJ_TYPE_REF_TOKEN): New. * doc/c-tree.texi (VTABLE_REF): Remove. * objc/objc-act.c (build_objc_method_call): Build an OBJ_TYPE_REF. cp/ * class.c (build_vfn_ref): Take a pointer not object. Build an OBJ_TYPE_REF. (cp_fold_obj_type_ref): New. * call.c (build_over_call): Update build_vfn_ref call. * cp-lang.c (LANG_HOOKS_FOLD_OBJ_TYPE_REF): New. * cp-tree.h (cp_fold_obj_type_ref): Declare. testsuite/ * g++.dg/opt/devirt1.C: New. From-SVN: r83531 --- gcc/ChangeLog | 24 +++++++++++++++++ gcc/cp/ChangeLog | 9 +++++++ gcc/cp/call.c | 2 +- gcc/cp/class.c | 41 +++++++++++++++++++++++++++--- gcc/cp/cp-lang.c | 2 ++ gcc/cp/cp-tree.h | 1 + gcc/doc/c-tree.texi | 12 --------- gcc/expr.c | 38 ++------------------------- gcc/fold-const.c | 2 +- gcc/gimplify.c | 17 ++++++++----- gcc/langhooks-def.h | 2 ++ gcc/langhooks.h | 4 +++ gcc/objc/objc-act.c | 37 +++++++++++++-------------- gcc/testsuite/ChangeLog | 6 ++++- gcc/testsuite/g++.dg/opt/devirt1.C | 7 +++++ gcc/tree-gimple.c | 12 ++++++++- gcc/tree-gimple.h | 2 ++ gcc/tree-inline.c | 8 +----- gcc/tree-pretty-print.c | 16 +++++++----- gcc/tree-ssa-ccp.c | 34 ++++++++++++++++++++++--- gcc/tree-ssa-operands.c | 3 ++- gcc/tree.def | 21 +++++++++------ gcc/tree.h | 5 ++++ 23 files changed, 196 insertions(+), 109 deletions(-) create mode 100644 gcc/testsuite/g++.dg/opt/devirt1.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 33baa770363..d53095a9c71 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,27 @@ +2004-06-22 Richard Henderson + + * tree.def (VTABLE_REF): Remove. + (OBJ_TYPE_REF): New. + (TRY_CATCH_EXPR, TRY_FINALLY_EXPR): Set type 's'. + * expr.c (expand_expr_real_1): Replace VTABLE_REF with OBJ_TYPE_REF. + * fold-const.c (non_lvalue): Likewise. + * gimplify.c (gimplify_expr): Likewise. + (gimplify_call_expr): Use is_gimple_call_addr. + * langhooks-def.h (LANG_HOOKS_FOLD_OBJ_TYPE_REF): New. + * langhooks.h (fold_obj_type_ref): New. + * tree-gimple.c (is_gimple_call_addr): New. + * tree-gimple.h (is_gimple_call_addr): Declare. + * tree-inline.c (inlinable_function_p): Fix merge error. + (estimate_num_insns_1): Replace VTABLE_REF with OBJ_TYPE_REF. + * tree-pretty-print.c (dump_generic_node): Likewise. + (print_call_name): Handle OBJ_TYPE_REF. + * tree-ssa-ccp.c (fold_stmt): Fold OBJ_TYPE_REF. + * tree-ssa-operands.c (get_expr_operands): Handle OBJ_TYPE_REF. + * tree.h (OBJ_TYPE_REF_EXPR): New. + (OBJ_TYPE_REF_OBJECT, OBJ_TYPE_REF_TOKEN): New. + * doc/c-tree.texi (VTABLE_REF): Remove. + * objc/objc-act.c (build_objc_method_call): Build an OBJ_TYPE_REF. + 2004-06-22 Richard Henderson PR middle-end/16026 diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 1f2eda9b6a0..f67eb221408 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2004-06-22 Richard Henderson + + * class.c (build_vfn_ref): Take a pointer not object. Build + an OBJ_TYPE_REF. + (cp_fold_obj_type_ref): New. + * call.c (build_over_call): Update build_vfn_ref call. + * cp-lang.c (LANG_HOOKS_FOLD_OBJ_TYPE_REF): New. + * cp-tree.h (cp_fold_obj_type_ref): Declare. + 2004-06-21 Jason Merrill PR c++/16112 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 0c247b8127a..2a659cce1ef 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -4835,7 +4835,7 @@ build_over_call (struct z_candidate *cand, int flags) if (DECL_CONTEXT (fn) && TYPE_JAVA_INTERFACE (DECL_CONTEXT (fn))) fn = build_java_interface_fn_ref (fn, *p); else - fn = build_vfn_ref (build_indirect_ref (*p, 0), DECL_VINDEX (fn)); + fn = build_vfn_ref (*p, DECL_VINDEX (fn)); TREE_TYPE (fn) = t; } else if (DECL_INLINE (fn)) diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 1853d4faadf..d58577f496f 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -542,13 +542,15 @@ build_vtbl_ref (tree instance, tree idx) return aref; } -/* Given an object INSTANCE, return an expression which yields a - function pointer corresponding to vtable element INDEX. */ +/* Given a stable object pointer INSTANCE_PTR, return an expression which + yields a function pointer corresponding to vtable element INDEX. */ tree -build_vfn_ref (tree instance, tree idx) +build_vfn_ref (tree instance_ptr, tree idx) { - tree aref = build_vtbl_ref_1 (instance, idx); + tree aref; + + aref = build_vtbl_ref_1 (build_indirect_ref (instance_ptr, 0), idx); /* When using function descriptors, the address of the vtable entry is treated as a function pointer. */ @@ -556,6 +558,9 @@ build_vfn_ref (tree instance, tree idx) aref = build1 (NOP_EXPR, TREE_TYPE (aref), build_unary_op (ADDR_EXPR, aref, /*noconvert=*/1)); + /* Remember this as a method reference, for later devirtualization. */ + aref = build (OBJ_TYPE_REF, TREE_TYPE (aref), aref, instance_ptr, idx); + return aref; } @@ -7912,3 +7917,31 @@ build_rtti_vtbl_entries (tree binfo, vtbl_init_data* vid) *vid->last_init = build_tree_list (NULL_TREE, init); vid->last_init = &TREE_CHAIN (*vid->last_init); } + +/* Fold a OBJ_TYPE_REF expression to the address of a function. + KNOWN_TYPE carries the true type of OBJ_TYPE_REF_OBJECT(REF). */ + +tree +cp_fold_obj_type_ref (tree ref, tree known_type) +{ + HOST_WIDE_INT index = tree_low_cst (OBJ_TYPE_REF_TOKEN (ref), 1); + HOST_WIDE_INT i = 0; + tree v = TYPE_BINFO_VIRTUALS (known_type); + tree fndecl; + + while (i != index) + { + i += (TARGET_VTABLE_USES_DESCRIPTORS + ? TARGET_VTABLE_USES_DESCRIPTORS : 1); + v = TREE_CHAIN (v); + } + + fndecl = BV_FN (v); + +#ifdef ENABLE_CHECKING + if (!tree_int_cst_equal (OBJ_TYPE_REF_TOKEN (ref), DECL_VINDEX (fndecl))) + abort (); +#endif + + return build_address (fndecl); +} diff --git a/gcc/cp/cp-lang.c b/gcc/cp/cp-lang.c index 757ca08e845..5af5b97333d 100644 --- a/gcc/cp/cp-lang.c +++ b/gcc/cp/cp-lang.c @@ -182,6 +182,8 @@ static void cxx_initialize_diagnostics (diagnostic_context *); #define LANG_HOOKS_REGISTER_BUILTIN_TYPE c_register_builtin_type #undef LANG_HOOKS_GIMPLIFY_EXPR #define LANG_HOOKS_GIMPLIFY_EXPR cp_gimplify_expr +#undef LANG_HOOKS_FOLD_OBJ_TYPE_REF +#define LANG_HOOKS_FOLD_OBJ_TYPE_REF cp_fold_obj_type_ref /* Each front end provides its own hooks, for toplev.c. */ const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index e29e084e0bb..36d98c60195 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3678,6 +3678,7 @@ extern tree get_vtt_name (tree); extern tree get_primary_binfo (tree); extern void debug_class (tree); extern void debug_thunks (tree); +extern tree cp_fold_obj_type_ref (tree, tree); /* in cvt.c */ extern tree convert_to_reference (tree, tree, int, int, tree); diff --git a/gcc/doc/c-tree.texi b/gcc/doc/c-tree.texi index dae858a4292..92e87aa4157 100644 --- a/gcc/doc/c-tree.texi +++ b/gcc/doc/c-tree.texi @@ -1742,7 +1742,6 @@ This macro returns the attributes on the type @var{type}. @tindex SAVE_EXPR @tindex TARGET_EXPR @tindex AGGR_INIT_EXPR -@tindex VTABLE_REF @tindex VA_ARG_EXPR The internal representation for expressions is for the most part quite @@ -2345,17 +2344,6 @@ list. In either case, the expression is void. -@item VTABLE_REF -A @code{VTABLE_REF} indicates that the interior expression computes -a value that is a vtable entry. It is used with @option{-fvtable-gc} -to track the reference through to front end to the middle end, at -which point we transform this to a @code{REG_VTABLE_REF} note, which -survives the balance of code generation. - -The first operand is the expression that computes the vtable reference. -The second operand is the @code{VAR_DECL} of the vtable. The third -operand is an @code{INTEGER_CST} of the byte offset into the vtable. - @item VA_ARG_EXPR This node is used to implement support for the C/C++ variable argument-list mechanism. It represents expressions like @code{va_arg (ap, type)}. diff --git a/gcc/expr.c b/gcc/expr.c index 989a5fa6dca..259eac1c989 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -7495,42 +7495,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, return target; } - case VTABLE_REF: - { - rtx insn, before = get_last_insn (), vtbl_ref; - - /* Evaluate the interior expression. */ - subtarget = expand_expr (TREE_OPERAND (exp, 0), target, - tmode, modifier); - - /* Get or create an instruction off which to hang a note. */ - if (REG_P (subtarget)) - { - target = subtarget; - insn = get_last_insn (); - if (insn == before) - abort (); - if (! INSN_P (insn)) - insn = prev_nonnote_insn (insn); - } - else - { - target = gen_reg_rtx (GET_MODE (subtarget)); - insn = emit_move_insn (target, subtarget); - } - - /* Collect the data for the note. */ - vtbl_ref = XEXP (DECL_RTL (TREE_OPERAND (exp, 1)), 0); - vtbl_ref = plus_constant (vtbl_ref, - tree_low_cst (TREE_OPERAND (exp, 2), 0)); - /* Discard the initial CONST that was added. */ - vtbl_ref = XEXP (vtbl_ref, 0); - - REG_NOTES (insn) - = gen_rtx_EXPR_LIST (REG_VTABLE_REF, vtbl_ref, REG_NOTES (insn)); - - return target; - } + case OBJ_TYPE_REF: + return expand_expr (OBJ_TYPE_REF_EXPR (exp), target, tmode, modifier); /* Intended for a reference to a buffer of a file-object in Pascal. But it's not certain that a special tree code will really be diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 3d4cccaaa6b..8a09795c624 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -2022,7 +2022,7 @@ non_lvalue (tree x) case ARRAY_RANGE_REF: case BIT_FIELD_REF: case BUFFER_REF: - case VTABLE_REF: + case OBJ_TYPE_REF: case REALPART_EXPR: case IMAGPART_EXPR: diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 36492720ff9..f65dd4cdbcd 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -2179,7 +2179,7 @@ gimplify_call_expr (tree *expr_p, tree *pre_p, bool (*gimple_test_f) (tree)) the calling expression must occur before the actual call. Force gimplify_expr to use an internal post queue. */ ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, NULL, - is_gimple_val, fb_rvalue); + is_gimple_call_addr, fb_rvalue); if (PUSH_ARGS_REVERSED) TREE_OPERAND (*expr_p, 1) = nreverse (TREE_OPERAND (*expr_p, 1)); @@ -3709,12 +3709,15 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p, ret = GS_ALL_DONE; break; - case VTABLE_REF: - /* This moves much of the actual computation out of the - VTABLE_REF. Perhaps this should be revisited once we want to - do clever things with VTABLE_REFs. */ - ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, - is_gimple_min_lval, fb_lvalue); + case OBJ_TYPE_REF: + { + enum gimplify_status r0, r1; + r0 = gimplify_expr (&OBJ_TYPE_REF_OBJECT (*expr_p), pre_p, post_p, + is_gimple_val, fb_rvalue); + r1 = gimplify_expr (&OBJ_TYPE_REF_EXPR (*expr_p), pre_p, post_p, + is_gimple_val, fb_rvalue); + ret = MIN (r0, r1); + } break; case MIN_EXPR: diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h index cf52b87e027..60642990794 100644 --- a/gcc/langhooks-def.h +++ b/gcc/langhooks-def.h @@ -200,6 +200,7 @@ extern int lhd_gimplify_expr (tree *, tree *, tree *); /* Hooks for tree gimplification. */ #define LANG_HOOKS_GIMPLIFY_EXPR lhd_gimplify_expr +#define LANG_HOOKS_FOLD_OBJ_TYPE_REF NULL #define LANG_HOOKS_GIMPLE_BEFORE_INLINING true /* Tree dump hooks. */ @@ -315,6 +316,7 @@ extern tree lhd_make_node (enum tree_code); LANG_HOOKS_DECLS, \ LANG_HOOKS_FOR_TYPES_INITIALIZER, \ LANG_HOOKS_GIMPLIFY_EXPR, \ + LANG_HOOKS_FOLD_OBJ_TYPE_REF, \ LANG_HOOKS_GIMPLE_BEFORE_INLINING \ } diff --git a/gcc/langhooks.h b/gcc/langhooks.h index 880ed7c2380..a8c0ccac2a7 100644 --- a/gcc/langhooks.h +++ b/gcc/langhooks.h @@ -419,6 +419,10 @@ struct lang_hooks enum gimplify_status, though we can't see that type here. */ int (*gimplify_expr) (tree *, tree *, tree *); + /* Fold an OBJ_TYPE_REF expression to the address of a function. + KNOWN_TYPE carries the true type of the OBJ_TYPE_REF_OBJECT. */ + tree (*fold_obj_type_ref) (tree, tree); + /* True if the front end has gimplified the function before running the inliner, false if the front end generates GENERIC directly. */ bool gimple_before_inlining; diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index bf739565cad..9664273529d 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -5866,6 +5866,7 @@ build_objc_method_call (int super_flag, tree method_prototype, (ret_type, get_arg_type_list (method_prototype, METHOD_REF, super_flag))); + tree method, t; lookup_object = build_c_cast (rcv_p, lookup_object); @@ -5886,38 +5887,33 @@ build_objc_method_call (int super_flag, tree method_prototype, method_params = tree_cons (NULL_TREE, lookup_object, tree_cons (NULL_TREE, selector, method_params)); - TREE_USED (sender) = 1; - assemble_external (sender); - /* We want to cast the sender, not convert it. */ - return build_function_call (build_c_cast (sender_cast, sender), - method_params); + method = build_fold_addr_expr (sender); } else { /* This is the portable (GNU) way. */ - tree method, object; + tree object; /* First, call the lookup function to get a pointer to the method, then cast the pointer, then call it with the method arguments. Use SAVE_EXPR to avoid evaluating the receiver twice. */ lookup_object = save_expr (lookup_object); object = (super_flag ? self_decl : lookup_object); - TREE_USED (sender) = 1; - assemble_external (sender); - method - = build_function_call (sender, - tree_cons (NULL_TREE, lookup_object, - tree_cons (NULL_TREE, selector, - NULL_TREE))); + + t = tree_cons (NULL_TREE, selector, NULL_TREE); + t = tree_cons (NULL_TREE, lookup_object, t); + method = build_function_call (sender, t); /* Pass the object to the method. */ - TREE_USED (method) = 1; - assemble_external (method); - return build_function_call - (build_c_cast (sender_cast, method), - tree_cons (NULL_TREE, object, - tree_cons (NULL_TREE, selector, method_params))); + method_params = tree_cons (NULL_TREE, object, + tree_cons (NULL_TREE, selector, + method_params)); } + + /* ??? Selector is not at this point something we can use inside + the compiler itself. Set it to garbage for the nonce. */ + t = build (OBJ_TYPE_REF, sender_cast, method, lookup_object, size_zero_node); + return build_function_call (t, method_params); } static void @@ -7607,7 +7603,8 @@ comp_method_with_proto (tree method, tree proto) function1_template = make_node (FUNCTION_TYPE); /* Install argument types - normally set by build_function_type. */ - TYPE_ARG_TYPES (function1_template) = get_arg_type_list (proto, METHOD_DEF, 0); + TYPE_ARG_TYPES (function1_template) + = get_arg_type_list (proto, METHOD_DEF, 0); /* install return type */ TREE_TYPE (function1_template) = groktypename (TREE_TYPE (proto)); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ab024eccbea..de2afeab752 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,4 +1,8 @@ -2004-06-22 Kelley Cook +2006-06-22 Richard Henderson + + * g++.dg/opt/devirt1.C: New. + +2004-06-22 Kelley Cook * g++.dg/opt/pr15551.C: New testcase. diff --git a/gcc/testsuite/g++.dg/opt/devirt1.C b/gcc/testsuite/g++.dg/opt/devirt1.C new file mode 100644 index 00000000000..617db050434 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/devirt1.C @@ -0,0 +1,7 @@ +// { dg-do compile } +// { dg-options "-O" } +// { dg-final { scan-assembler "xyzzy" } } + +struct S { S(); virtual void xyzzy(); }; +inline void foo(S *s) { s->xyzzy(); } +void bar() { S s; foo(&s); } diff --git a/gcc/tree-gimple.c b/gcc/tree-gimple.c index 7c992b36adc..2deee183964 100644 --- a/gcc/tree-gimple.c +++ b/gcc/tree-gimple.c @@ -111,7 +111,7 @@ Boston, MA 02111-1307, USA. */ op0 -> lhs op1 -> rhs call-stmt: CALL_EXPR - op0 -> ID | '&' ID + op0 -> ID | '&' ID | OBJ_TYPE_REF op1 -> arglist addr-expr-arg : compref | ID @@ -158,6 +158,7 @@ Boston, MA 02111-1307, USA. */ | unop val | val binop val | '(' cast ')' val + | method_ref (cast here stands for all valid C typecasts) @@ -240,6 +241,7 @@ is_gimple_rhs (tree t) case STRING_CST: case COMPLEX_CST: case VECTOR_CST: + case OBJ_TYPE_REF: return 1; default: @@ -493,6 +495,14 @@ is_gimple_cast (tree t) || TREE_CODE (t) == FIX_ROUND_EXPR); } +/* Return true if T is a valid op0 of a CALL_EXPR. */ + +bool +is_gimple_call_addr (tree t) +{ + return (TREE_CODE (t) == OBJ_TYPE_REF + || is_gimple_val (t)); +} /* If T makes a function call, return the corresponding CALL_EXPR operand. Otherwise, return NULL_TREE. */ diff --git a/gcc/tree-gimple.h b/gcc/tree-gimple.h index 98f46951af4..9e6209d7afa 100644 --- a/gcc/tree-gimple.h +++ b/gcc/tree-gimple.h @@ -75,6 +75,8 @@ extern bool is_gimple_constructor_elt (tree); /* Returns true iff T is a variable that does not need to live in memory. */ extern bool is_gimple_non_addressable (tree t); +/* Returns true iff T is a valid call address expression. */ +bool is_gimple_call_addr (tree); /* If T makes a function call, returns the CALL_EXPR operand. */ extern tree get_call_expr_in (tree t); diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index deb73605ca2..1d6e4c4dbae 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -1136,12 +1136,6 @@ inlinable_function_p (tree fn) else if (!DECL_INLINE (fn) && !flag_unit_at_a_time) inlinable = false; -#ifdef INLINER_FOR_JAVA - /* Synchronized methods can't be inlined. This is a bug. */ - else if (METHOD_SYNCHRONIZED (fn)) - inlinable = false; -#endif /* INLINER_FOR_JAVA */ - else if (inline_forbidden_p (fn)) { /* See if we should warn about uninlinable functions. Previously, @@ -1203,7 +1197,7 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data) case BUFFER_REF: case ARRAY_REF: case ARRAY_RANGE_REF: - case VTABLE_REF: + case OBJ_TYPE_REF: case EXC_PTR_EXPR: /* ??? */ case FILTER_EXPR: /* ??? */ case COMPOUND_EXPR: diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index 52aa1819417..6ebf07564c7 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -1367,14 +1367,15 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, pp_character (buffer, ':'); break; - case VTABLE_REF: - pp_string (buffer, "VTABLE_REF <("); - dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); - pp_string (buffer, "),"); - dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false); - pp_character (buffer, ','); - dump_generic_node (buffer, TREE_OPERAND (node, 2), spc, flags, false); + case OBJ_TYPE_REF: + pp_string (buffer, "OBJ_TYPE_REF("); + dump_generic_node (buffer, OBJ_TYPE_REF_EXPR (node), spc, flags, false); + pp_character (buffer, ';'); + dump_generic_node (buffer, OBJ_TYPE_REF_OBJECT (node), spc, flags, false); + pp_character (buffer, '-'); pp_character (buffer, '>'); + dump_generic_node (buffer, OBJ_TYPE_REF_TOKEN (node), spc, flags, false); + pp_character (buffer, ')'); break; case PHI_NODE: @@ -1880,6 +1881,7 @@ print_call_name (pretty_printer *buffer, tree node) break; case SSA_NAME: + case OBJ_TYPE_REF: dump_generic_node (buffer, op0, 0, 0, false); break; diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index 658a2cb9061..ef0c12be378 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -2037,13 +2037,41 @@ fold_stmt (tree *stmt_p) return changed; result = NULL_TREE; - /* Check for builtins that CCP can handle using information not - available in the generic fold routines. */ if (TREE_CODE (rhs) == CALL_EXPR) { - tree callee = get_callee_fndecl (rhs); + tree callee; + + /* Check for builtins that CCP can handle using information not + available in the generic fold routines. */ + callee = get_callee_fndecl (rhs); if (callee && DECL_BUILT_IN (callee)) result = ccp_fold_builtin (stmt, rhs); + else + { + /* Check for resolvable OBJ_TYPE_REF. The only sorts we can resolve + here are when we've propagated the address of a decl into the + object slot. */ + /* ??? Should perhaps do this in fold proper. However, doing it + there requires that we create a new CALL_EXPR, and that requires + copying EH region info to the new node. Easier to just do it + here where we can just smash the call operand. */ + callee = TREE_OPERAND (rhs, 0); + if (TREE_CODE (callee) == OBJ_TYPE_REF + && lang_hooks.fold_obj_type_ref + && TREE_CODE (OBJ_TYPE_REF_OBJECT (callee)) == ADDR_EXPR + && DECL_P (TREE_OPERAND (OBJ_TYPE_REF_OBJECT (callee), 0))) + { + tree t; + + t = TREE_TYPE (TREE_OPERAND (OBJ_TYPE_REF_OBJECT (callee), 0)); + t = lang_hooks.fold_obj_type_ref (callee, t); + if (t) + { + TREE_OPERAND (rhs, 0) = t; + changed = true; + } + } + } } /* If we couldn't fold the RHS, hand over to the generic fold routines. */ diff --git a/gcc/tree-ssa-operands.c b/gcc/tree-ssa-operands.c index 08330abd51f..68da398c9ef 100644 --- a/gcc/tree-ssa-operands.c +++ b/gcc/tree-ssa-operands.c @@ -1169,7 +1169,8 @@ get_expr_operands (tree stmt, tree *expr_p, int flags, voperands_t prev_vops) || code == TRUTH_AND_EXPR || code == TRUTH_OR_EXPR || code == TRUTH_XOR_EXPR - || code == COMPOUND_EXPR) + || code == COMPOUND_EXPR + || code == OBJ_TYPE_REF) { tree op0 = TREE_OPERAND (expr, 0); tree op1 = TREE_OPERAND (expr, 1); diff --git a/gcc/tree.def b/gcc/tree.def index 12a6394c5b1..57596a2b458 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -387,12 +387,17 @@ DEFTREECODE (ARRAY_REF, "array_ref", 'r', 4) of the range is taken from the type of the expression. */ DEFTREECODE (ARRAY_RANGE_REF, "array_range_ref", 'r', 4) -/* Vtable indexing. Carries data useful for emitting information - for vtable garbage collection. - Operand 0: an array_ref (or equivalent expression) - Operand 1: the vtable base (must be a var_decl) - Operand 2: index into vtable (must be an integer_cst). */ -DEFTREECODE (VTABLE_REF, "vtable_ref", 'r', 3) +/* Used to represent lookup of runtime type dependent data. Often this is + a reference to a vtable, but it needn't be. Operands are: + OBJ_TYPE_REF_EXPR: An expression that evaluates the value to use. + OBJ_TYPE_REF_OBJECT: Is the object on whose behalf the lookup is + being performed. Through this the optimizers may be able to statically + determine the dynamic type of the object. + OBJ_TYPE_REF_TOKEN: Something front-end specific used to resolve the + reference to something simpler, usually to the address of a DECL. + Never touched by the middle-end. Good choices would be either an + identifier or a vtable index. */ +DEFTREECODE (OBJ_TYPE_REF, "obj_type_ref", 'e', 3) /* The exception object from the runtime. */ DEFTREECODE (EXC_PTR_EXPR, "exc_ptr_expr", 'e', 0) @@ -790,12 +795,12 @@ DEFTREECODE (VA_ARG_EXPR, "va_arg_expr", 'e', 1) This differs from TRY_FINALLY_EXPR in that operand 2 is not evaluated on a normal or jump exit, only on an exception. */ -DEFTREECODE (TRY_CATCH_EXPR, "try_catch_expr", 'e', 2) +DEFTREECODE (TRY_CATCH_EXPR, "try_catch_expr", 's', 2) /* Evaluate the first operand. The second operand is a cleanup expression which is evaluated on any exit (normal, exception, or jump out) from this expression. */ -DEFTREECODE (TRY_FINALLY_EXPR, "try_finally", 'e', 2) +DEFTREECODE (TRY_FINALLY_EXPR, "try_finally", 's', 2) /* These types of expressions have no useful value, and always have side effects. */ diff --git a/gcc/tree.h b/gcc/tree.h index 9b753a341f6..c404b84d1bc 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1114,6 +1114,11 @@ struct tree_vec GTY(()) #define EH_FILTER_FAILURE(NODE) TREE_OPERAND (EH_FILTER_EXPR_CHECK (NODE), 1) #define EH_FILTER_MUST_NOT_THROW(NODE) TREE_STATIC (EH_FILTER_EXPR_CHECK (NODE)) +/* OBJ_TYPE_REF accessors. */ +#define OBJ_TYPE_REF_EXPR(NODE) TREE_OPERAND (OBJ_TYPE_REF_CHECK (NODE), 0) +#define OBJ_TYPE_REF_OBJECT(NODE) TREE_OPERAND (OBJ_TYPE_REF_CHECK (NODE), 1) +#define OBJ_TYPE_REF_TOKEN(NODE) TREE_OPERAND (OBJ_TYPE_REF_CHECK (NODE), 2) + struct tree_exp GTY(()) { struct tree_common common; -- 2.30.2