On 5/21/21 9:00 AM, Florian Weimer via Gcc-help wrote:
Is it possible to declare an extern function pure for just some
arguments?
To clarify, let's assume I have a function
extern int *func (int);
and I want it to be pure for func (0), func (1), func (3), but not for
func (2). Is this possible?
Will something like this work?
static inline int *
func (int i)
{
if (i == 2)
{
extern int *func_alias_1 (int) __asm__ ("func");
return func_alias_1 (i);
}
else
{
extern int *func_alias_2 (int) __asm__ ("func") __attribute__ ((pure));
return func_alias_2 (i);
}
}
It's tricky but I'd say it should work provided func() is declared with
attribute always_inline to make sure all calls to the wrapper function
are inlined. Without it, some calls may not be treated as pure, and
some might be recursive. The asm renaming is done very late so it
shouldn't matter for the attribute.
Expanding your test case a bit is a good experiment (the tree dumps
show what happens when):
extern int a[];
static inline int *
func (int i)
{
if (i == 2)
{
extern int *func_alias_1 (int) __asm__ ("func");
return func_alias_1 (i);
}
else
{
extern int *func_alias_2 (int) __asm__ ("func") __attribute__
((pure));
return func_alias_2 (i);
}
}
int* f1 ()
{
int t = a[1];
int *p = func (1); // pure call
if (t != a[1]) // folded to false
__builtin_abort ();
return p;
}
int* f2 ()
{
int t = a[1];
int *p = func (2); // not a pure call
if (t != a[1]) // not folded
__builtin_abort ();
return p;
}
Attribute pure is considered during Gimplification as well during
later stages. The former clears the side-effects bit for a call
so that might mean that some very early optimizations that depend
on the side-effects bit being clear won't happen.
Martin