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

Brendan Jackman <[email protected]>
Newsgroups org.kernel.vger.linux-toolchains,org.kernel.vger.kvm,org.kernel.vger.linux-kernel,org.kvack.linux-mm
Message-ID <CA+i-1C1z35M8wA_4AwMq7--c1OgjNoLGTkn4+Td5gKg7QQAzWw@mail.gmail.com>
On Fri, 1 Nov 2024 at 21:27, Thomas Gleixner <[email protected]> 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?
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.