Re: [PATCH 01/26] mm: asi: Make some utility functions noinstr compatible

From: Brendan Jackman
Date: Fri Dec 13 2024 - 09:45:33 EST


On Fri, 1 Nov 2024 at 21:27, Thomas Gleixner <tglx@xxxxxxxxxxxxx> wrote:
> On Thu, Oct 31 2024 at 18:44, Junaid Shahid wrote:
> What actually works by some definition of "works" is:
>
> static __always_inline void __foo(void) { }
>
> static inline void foo(void)
> {
> __(foo);
> }
>
> static inline noinstr void foo_noinstr(void)
> {
> __(foo);
> }
>
> The problem is that both GCC and clang optimize foo[_noinstr]() away and
> then follow the __always_inline directive of __foo() even if I make
> __foo() insanely large and have a gazillion of different functions
> marked noinline invoking foo() or foo_noinstr(), unless I add -fno-inline
> to the command line.

In this experiment did you modify the definition of noinstr to remove
noinline? Otherwise I always get out-of-line calls (as you'd expect
from the noinline).

> Which means it's not much different from just having '__always_inline
> foo()' without the wrappers....
>
> Compilers clearly lack a --do-what-I-mean command line option.
>
> Now if I'm truly nasty then both compilers do what I mean even without a
> magic command line option:
>
> static __always_inline void __foo(void) { }
>
> static __maybe_unused void foo(void)
> {
> __(foo);
> }
>
> static __maybe_unused noinstr void foo_noinstr(void)
> {
> __(foo);
> }

I don't see any difference with __maybe_unused: if the noinline is
there it's never inlined, otherwise with the wrapper technique it's
always inlined regardless of __maybe_unused:

static __always_inline void __big(void)
{
asm volatile(
"nop; nop; nop; nop; nop; nop; nop; nop; nop;"
// and so on
"nop; nop; nop; nop; nop; nop; nop; nop; nop;"
);
}

static inline __section(".noinstr.text") void big_noinstr(void)
{
__big();
}

When I call big_noinstr() from a noinstr function I see:

Dump of assembler code for function asi_exit:
0xffffffff811e0080 <+0>: endbr64
0xffffffff811e0084 <+4>: nop
0xffffffff811e0085 <+5>: nop
...and so on

I'm using GCC 14.2.0.

(I thought maybe this was because I used asm volatile nops to embiggen
the function but I see the same thing with a big stream of volatile C
statements).

I think we might have no choice but to always use
__always_inline/noinline for code that's called from both sections -
seems there's no way to tell the compiler "I don't care if you inline
it, but it we can't cross a section boundary". Am I missing anything?