On Fri, Dec 14, 2018 at 04:59:44PM -0500, Jason Merrill wrote:
> > extern void __cxa_throw (void *, void *, void *) WEAK;
> > void
> > _ITM_cxa_throw (void *obj, void *tinfo, void *dest)
> > {
> >    // This used to be instrumented, but does not need to be anymore.
> >    __cxa_throw (obj, tinfo, dest);
> > }
> > Shall we fix libitm to use void (*dest) (void *) instead of void *dest,
> > or shall I make the verify_library_fn handle both i == 1 and i == 2
> > the same?
> 
> Fix libitm.

Ok, will do.

> Do function pointers and object pointers have the same
> representation on all the targets we support?

Not sure about this, but we have all kinds of weird targets.

> > +/* Check that user declared function FN is a function and has return
> > +   type RTYPE and argument types ARG{1,2,3}TYPE.  */
> > +
> > +static bool
> > +verify_library_fn (tree fn, const char *name, tree rtype,
> > +              tree arg1type, tree arg2type, tree arg3type)
> > +{
> 
> Do we want to skip all of this if DECL_ARTIFICIAL?

Not sure how a DECL_ARTIFICIAL fn could appear there.  This function is
only called 1) the first time we need a particular __cxa_* routine
2) and the declaration exists already (when we create it ourselves,
we don't need to check it).

> > +     /* Be less strict for __cxa_throw last 2 arguments.  */
> > +     if (i == 1 && TREE_CODE (TREE_VALUE (targs)) != POINTER_TYPE)
> > +       goto bad;
> > +     if (i == 2
> > +         && (TREE_CODE (TREE_VALUE (targs)) != POINTER_TYPE
> > +             || (TREE_CODE (TREE_TYPE (TREE_VALUE (targs)))
> > +                 != FUNCTION_TYPE)))
> 
> These seem to assume that any library function with more than one parameter
> will have pointers for the second and third parameters.
> 
> TYPE_PTROBV_P might be useful.

I can do e.g.
        if (i == 0)
          goto bad;
        /* Be less strict for second and following arguments, __cxa_throw
           needs to be more permissive.  */
        if (TYPE_PTROBV_P (TREE_VALUE (args)) && TYPE_PTROBV_P (args[i]))
          /* Both object pointers.  */;
        else if (TYPE_PTRFN_P (TREE_VALUE (args)) && TYPE_PTRFN_P (args[i]))
          /* Both function pointers.  */;
        else
          goto bad;

> > @@ -625,10 +677,22 @@ build_throw (tree exp)
> >               tree itm_fn = get_global_binding (itm_name);
> >               if (!itm_fn)
> >                 itm_fn = push_throw_library_fn (itm_name, tmp);
> > -             apply_tm_attr (itm_fn, get_identifier ("transaction_pure"));
> > -             record_tm_replacement (throw_fn, itm_fn);
> > +             else if (!verify_library_fn (itm_fn, "_ITM_cxa_throw",
> > +                                          void_type_node, ptr_type_node,
> > +                                          ptr_type_node, cleanup_type))
> > +               itm_fn = error_mark_node;
> > +             if (itm_fn != error_mark_node)
> > +               {
> > +                 apply_tm_attr (itm_fn,
> > +                                get_identifier ("transaction_pure"));
> > +                 record_tm_replacement (throw_fn, itm_fn);
> > +               }
> >             }
> >         }
> > +     else if (!verify_library_fn (throw_fn, "__cxa_throw", void_type_node,
> > +                                  ptr_type_node, ptr_type_node,
> > +                                  cleanup_type))
> > +       throw_fn = error_mark_node;
> 
> This should happen whether or not flag_tm.

It does, it is else of:
      if (!throw_fn)
        {
          tree name = get_identifier ("__cxa_throw");
          throw_fn = get_global_binding (name);
          if (!throw_fn)
            {

That said, I think what is wrong is that we have the TM handling solely
in the spots where we create the __cxa_ functions ourselves.  In all the
places, it looks like:
  tree ident = get_identifier (name);
  tree res = get_global_binding (ident);
  if (!res)
    {
      res = build_it_ourselves;
      if (tm_ecf && flag_tm)
        {
          char *tm_name = ...;
          tree tm_ident = get_identifier (tm_name);
          free (tm_name);
          tree tm_fn = get_global_binding (tm_ident);
          if (!tm_fn)
            tm_fn = build_it_ourselves;
          else
            verify;
          if (valid)
            record_tm_replacement (res, tm_fn);
        }
    }
  else
    verify;
IMHO it should look like:
  tree ident = get_identifier (name);
  tree res = get_global_binding (ident);
  if (!res)
    res = build_it_ourselves;
  else
    verify;
  if (valid && tm_ecf && flag_tm)
    {
      char *tm_name = ...;
      tree tm_ident = get_identifier (tm_name);
      tree tm_fn = get_global_binding (tm_ident);
      if (!tm_fn)
        tm_fn = build_it_ourselves;
      else
        verify;
      free (tm_name);
      if (valid)
        record_tm_replacement (res, tm_fn);
    }
So that if we e.g. have the __cxa_* prototypes, but not the TM ones,
we use user's prototypes for the former and create the latter.
Are you ok with those changes?

> Let's avoid repeating the strings "__cxa_throw" and "_ITM_cxa_throw".

Will do.

        Jakub

Reply via email to