Using IFUNC with template functions

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Using IFUNC with template functions

David Blaikie via cfe-dev
Hi All,

I want to have a template function as an ifunc. Find below my test program.

// Test Program
#include <iostream>

int glob_t = 2;
typedef void (*VOID_FUNC_P)(void);

template <typename T>
T add_isa1(T x, T y) {
   std::cout << "ISA1 implementation" << std::endl;
   return x + y;
}

template <typename T>
T add_isa2(T x, T y) {
   std::cout << "ISA2 implementation" << std::endl;
   return x + y;
}

template <typename T>
static VOID_FUNC_P add_resolver(void) {
   T (*T_p)(T,T) = NULL;
   switch (glob_t) {
      case 1:
              T_p = add_isa1;
              break;
      case 2:
              T_p = add_isa2;
              break;
   }
   return reinterpret_cast<VOID_FUNC_P>(T_p);
}

template VOID_FUNC_P add_resolver<int>(void);
template VOID_FUNC_P add_resolver<double>(void);

// explicit/manual instantiation of possibilities
int add(int, int) __attribute((ifunc("_Z12add_resolverIiEPFvvEv")));
double add(double, double) __attribute((ifunc("_Z12add_resolverIdEPFvvEv")));

int main()
{
   //int res = add(1,68);
   double res = add(1.68,68.01);
   std::cout << "Res = " << res << std::endl;
   return 0;
}


I have to explicitly declare the ifunc resolver function for all possible combinations of template arguments. In reality, I think it would be impractical for programmers to do this kind of manual/explicit instantiation.
I am interested to know if there any other better way to use ifuncs with template functions. If there is none, is it worth suggesting to the C++ standards?


Thanks and Regards,
Amrita H S

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Using IFUNC with template functions

David Blaikie via cfe-dev
On Wed, Nov 18, 2020 at 9:42 AM Amrita H S via cfe-dev
<[hidden email]> wrote:

>
> Hi All,
>
> I want to have a template function as an ifunc. Find below my test program.
>
> // Test Program
> #include <iostream>
>
> int glob_t = 2;
> typedef void (*VOID_FUNC_P)(void);
>
> template <typename T>
> T add_isa1(T x, T y) {
>    std::cout << "ISA1 implementation" << std::endl;
>    return x + y;
> }
>
> template <typename T>
> T add_isa2(T x, T y) {
>    std::cout << "ISA2 implementation" << std::endl;
>    return x + y;
> }
>
> template <typename T>
> static VOID_FUNC_P add_resolver(void) {
>    T (*T_p)(T,T) = NULL;
>    switch (glob_t) {
>       case 1:
>               T_p = add_isa1;
>               break;
>       case 2:
>               T_p = add_isa2;
>               break;
>    }
>    return reinterpret_cast<VOID_FUNC_P>(T_p);
> }
>
> template VOID_FUNC_P add_resolver<int>(void);
> template VOID_FUNC_P add_resolver<double>(void);
>
> // explicit/manual instantiation of possibilities
> int add(int, int) __attribute((ifunc("_Z12add_resolverIiEPFvvEv")));
> double add(double, double) __attribute((ifunc("_Z12add_resolverIdEPFvvEv")));
>
> int main()
> {
>    //int res = add(1,68);
>    double res = add(1.68,68.01);
>    std::cout << "Res = " << res << std::endl;
>    return 0;
> }
>
>
> I have to explicitly declare the ifunc resolver function for all possible combinations of template arguments. In reality, I think it would be impractical for programmers to do this kind of manual/explicit instantiation.
> I am interested to know if there any other better way to use ifuncs with template functions. If there is none, is it worth suggesting to the C++ standards?
>
>
> Thanks and Regards,
> Amrita H S

A GNU indirect function is very similar to a function pointer. For a
function pointer, the compiler produces code that loads the address
and does an indirect jump.
For an ifunc call, the compiler produces code that does a normal
function call and the PLT entry loads the address and does an indirect
jump. This is convenient in few cases because the caller does not need
to know whether it is a function/ifunc.

For your use cases, can you just use a function pointer?
_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Using IFUNC with template functions

David Blaikie via cfe-dev
In reply to this post by David Blaikie via cfe-dev
On 12/11/2020 05:34, Amrita H S via cfe-dev wrote:
> I am interested to know if there any other better way to use ifuncs with
> template functions. If there is none, is it worth suggesting to the C++
> standards?

ifunc is a GNU extension and isn't part of the C++ standard.  I think it
would be great to be able to specify an ifunc resolver for a template
function that it, itself, a template function.  I've found ifunc in
combination with templates to be a very powerful tool, exposing a single
function that is implemented by one of a small set of instantiations of
a templated function, depending on the environment.  Generalising this
to allow ifunc resolvers for template functions would be very interesting.

I'd suggest extending the ifunc attribute parser to accept <> at the end
of the identifier for the resolver to signify template arguments and
require that the resolver takes the same template arguments as the
function itself.  This is a fairly small change in the parser.  Sema
would then have to instantiate the ifunc resolver function for every
instantiation of the underlying function and CodeGen would need to mark
those all as ifunc resolvers.

There are lots of fiddly bits, but none of this sounds particularly hard.

I'd be happy to review clang patches but given that this is a GNU
extension I'd like to see consensus that GCC will either implement the
same thing or, at least, not implement something that would cause
compatibility problems.

David

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Using IFUNC with template functions

David Blaikie via cfe-dev
On Wed, Nov 18, 2020 at 06:12:58PM +0000, David Chisnall via cfe-dev wrote:
> I'd suggest extending the ifunc attribute parser to accept <> at the end of
> the identifier for the resolver to signify template arguments and require
> that the resolver takes the same template arguments as the function itself.

I'd suggest a different direction. I've mentioned a couple of times that
having a builtin for obtaining the mangled name for a function reference
would be useful. One common use case of that is dlopen, but this is
actually another. So instead of changing the ifunc attribute parser
accept expressions that can be folded to string constants and then the
mangled-name builtin.

Joerg
_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Using IFUNC with template functions

David Blaikie via cfe-dev
On 18/11/2020 20:04, Joerg Sonnenberger via cfe-dev wrote:

> On Wed, Nov 18, 2020 at 06:12:58PM +0000, David Chisnall via cfe-dev wrote:
>> I'd suggest extending the ifunc attribute parser to accept <> at the end of
>> the identifier for the resolver to signify template arguments and require
>> that the resolver takes the same template arguments as the function itself.
> I'd suggest a different direction. I've mentioned a couple of times that
> having a builtin for obtaining the mangled name for a function reference
> would be useful. One common use case of that is dlopen, but this is
> actually another. So instead of changing the ifunc attribute parser
> accept expressions that can be folded to string constants and then the
> mangled-name builtin.

As I understand it, with your suggestion, we'd then have something like:

```c++
template<typename T, int X>
__attribute__(ifunc(__builtin_mangled_name(foo_resolver<T, X>)))
foo() ...
```

When the compiler instantiates `foo`, it would try to generate the ifunc
attribute.  This would trigger evaluation of the
`__builtin_mangled_name`, which now evaluates to a constant because `T`
and `X` are known, and after that all of the machinery works as normal?

I like this more than my suggestion for several reasons:

  - It decomposes into separately useful features
  - It doesn't change anything about the ifunc attribute specifically
and so if G++ wants specific template syntax there then we aren't
committed to anything incompatible.
  - It makes it easy for the ifunc resolver to ignore or transform some
template arguments if they shouldn't affect codegen (for example,
turning parameter `T` into `sizeof(T)` if codegen only cares about the
size of the type and the type itself is used only for compile-time type
checking.

In terms of implementation, I see a couple of (not insurmountable)
difficulties:

As I recall, the parser for attributes that take strings containing
identifiers currently captures the string and resolves the identifier
later.  This would now have to capture an AST.

I think this is the only reason that attributes resolve differently for
different template instantiations.  The template instantiation machinery
would need to be told to do identifier resolution for all attributes
during instantiation.

If these problems can be addressed, this sounds like a great feature.

It might be possible to simplify the implementation by capturing the
string "__builtin_mangled_name(foo_resolver<T, X>)" in the attribute and
then re-parsing the string at template instantiation point but this may
introduce more complications that I haven't thought of.

David

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Using IFUNC with template functions

David Blaikie via cfe-dev
On Thu, Nov 19, 2020 at 10:10:41AM +0000, David Chisnall via cfe-dev wrote:

> On 18/11/2020 20:04, Joerg Sonnenberger via cfe-dev wrote:
> > On Wed, Nov 18, 2020 at 06:12:58PM +0000, David Chisnall via cfe-dev wrote:
> > > I'd suggest extending the ifunc attribute parser to accept <> at the end of
> > > the identifier for the resolver to signify template arguments and require
> > > that the resolver takes the same template arguments as the function itself.
> > I'd suggest a different direction. I've mentioned a couple of times that
> > having a builtin for obtaining the mangled name for a function reference
> > would be useful. One common use case of that is dlopen, but this is
> > actually another. So instead of changing the ifunc attribute parser
> > accept expressions that can be folded to string constants and then the
> > mangled-name builtin.
>
> As I understand it, with your suggestion, we'd then have something like:
>
> ```c++
> template<typename T, int X>
> __attribute__(ifunc(__builtin_mangled_name(foo_resolver<T, X>)))
> foo() ...
> ```
>
> When the compiler instantiates `foo`, it would try to generate the ifunc
> attribute.  This would trigger evaluation of the `__builtin_mangled_name`,
> which now evaluates to a constant because `T` and `X` are known, and after
> that all of the machinery works as normal?

Correct, that's the intention.

> I like this more than my suggestion for several reasons:
>
>  - It decomposes into separately useful features
>  - It doesn't change anything about the ifunc attribute specifically and so
> if G++ wants specific template syntax there then we aren't committed to
> anything incompatible.
>  - It makes it easy for the ifunc resolver to ignore or transform some
> template arguments if they shouldn't affect codegen (for example, turning
> parameter `T` into `sizeof(T)` if codegen only cares about the size of the
> type and the type itself is used only for compile-time type checking.

Right, the one big semantic change for the attribute handling is that
changing from a string literal to some form of evaluated expression.
Otherwise, it composes well. Everything else I agree with.

> In terms of implementation, I see a couple of (not insurmountable)
> difficulties:
>
> As I recall, the parser for attributes that take strings containing
> identifiers currently captures the string and resolves the identifier later.
> This would now have to capture an AST.
>
> I think this is the only reason that attributes resolve differently for
> different template instantiations.  The template instantiation machinery
> would need to be told to do identifier resolution for all attributes during
> instantiation.

Also agreed on this.

Joerg
_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev