On Wed, 2021-08-04 at 21:32 +0530, Ankur Saini wrote:
[...snip...]
>
> - From observation, a typical vfunc call that isn't devirtualised by
> the compiler's front end looks something like this
> "OBJ_TYPE_REF(_2;(struct A)a_ptr_5(D)->0) (a_ptr_5(D))"
> where "a_ptr_5(D)" is pointer that is being used to call the virtual
> function.
>
> - We can access it's region to see what is the type of the object the
> pointer is actually pointing to.
>
> - This is then used to find a call with DECL_CONTEXT of the object
> from the all the possible targets of that polymorphic call.
[...]
>
> Patch file ( prototype ) :
>
> + /* Call is possibly a polymorphic call.
> +
> + In such case, use devirtisation tools to find
> + possible callees of this function call. */
> +
> + function *fun = get_current_function ();
> + gcall *stmt = const_cast<gcall *> (call);
> + cgraph_edge *e = cgraph_node::get (fun->decl)->get_edge (stmt);
> + if (e->indirect_info->polymorphic)
> + {
> + void *cache_token;
> + bool final;
> + vec <cgraph_node *> targets
> + = possible_polymorphic_call_targets (e, &final, &cache_token, true);
> + if (!targets.is_empty ())
> + {
> + tree most_propbable_taget = NULL_TREE;
> + if(targets.length () == 1)
> + return targets[0]->decl;
> +
> + /* From the current state, check which subclass the pointer that
> + is being used to this polymorphic call points to, and use to
> + filter out correct function call. */
> + tree t_val = gimple_call_arg (call, 0);
Maybe rename to "this_expr"?
> + const svalue *sval = get_rvalue (t_val, ctxt);
and "this_sval"?
...assuming that that's what the value is.
Probably should reject the case where there are zero arguments.
> +
> + const region *reg
> + = [&]()->const region *
> + {
> + switch (sval->get_kind ())
> + {
> + case SK_INITIAL:
> + {
> + const initial_svalue *initial_sval
> + = sval->dyn_cast_initial_svalue ();
> + return initial_sval->get_region ();
> + }
> + break;
> + case SK_REGION:
> + {
> + const region_svalue *region_sval
> + = sval->dyn_cast_region_svalue ();
> + return region_sval->get_pointee ();
> + }
> + break;
> +
> + default:
> + return NULL;
> + }
> + } ();
I think the above should probably be a subroutine.
That said, it's not clear to me what it's doing, or that this is correct.
I'm guessing that you need to see if
*((void **)this)
is a vtable pointer (or something like that), and, if so, which class
it is for.
Is there a way of getting the vtable pointer as an svalue?
> + gcc_assert (reg);
> +
> + tree known_possible_subclass_type;
> + known_possible_subclass_type = reg->get_type ();
> + if (reg->get_kind () == RK_FIELD)
> + {
> + const field_region* field_reg = reg->dyn_cast_field_region ();
> + known_possible_subclass_type
> + = DECL_CONTEXT (field_reg->get_field ());
> + }
> +
> + for (cgraph_node *x : targets)
> + {
> + if (DECL_CONTEXT (x->decl) == known_possible_subclass_type)
> + most_propbable_taget = x->decl;
> + }
> + return most_propbable_taget;
> + }
> + }
> +
> return NULL_TREE;
> }
Dave