Using IFUNC with template functions

Hi All,

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

// Test Program
#include

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

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

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

template
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(void);
template VOID_FUNC_P add_resolver(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?

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

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

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

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

> > 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:

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