|
|
Subscribe / Log in / New account

Moving the kernel to modern C

Moving the kernel to modern C

Posted Feb 24, 2022 20:09 UTC (Thu) by nybble41 (subscriber, #55106)
In reply to: Moving the kernel to modern C by Paf
Parent article: Moving the kernel to modern C

It should be cost-free in any case where the iteration variable isn't accessed after the loop, since the compiler would eliminate the dead store. The code change is also fairly trivial: just edit the condition from "&pos->member != (head)" to "(&pos->member != (head)) || ((pos = NULL))".

Unfortunately this alone doesn't handle loops which exit early due to "break" or "goto". The "goto" case is unavoidable, but the "break" case can be dealt with by wrapping the macro in a second, trivial loop as shown in this example[0]. Note that the generated code (for gcc 5.1 with -O2) is *identical* between the version with the extra loop (traverse1) and the original version which does not set the iterator to NULL after the loop (traverse2). The initialization of the iterator to the flag state (-1), the condition for the outer loop, and the store of NULL to the iterator after the loop are all successfully eliminated.

[0] https://godbolt.org/z/4obYManzc


to post comments

Moving the kernel to modern C

Posted Feb 24, 2022 20:48 UTC (Thu) by iabervon (subscriber, #722) [Link] (3 responses)

It might work to have:

extern unsigned long list_iterator_live_after_loop;

and "|| ((pos = (void *) list_iterator_live_after_loop), 0)"

I didn't try changing the kernel macro that way, but my little test code doesn't link if the iterator is used after the loop, but does link and work if it's not used. As I recall, the kernel is already using that sort of trick to use compiler optimization to remove an error message only if the compiler can disprove it.

Moving the kernel to modern C

Posted Feb 25, 2022 22:20 UTC (Fri) by NYKevin (subscriber, #129325) [Link] (2 responses)

Unfortunately, this is probably UB: https://en.cppreference.com/w/c/language/extern

> The entire program may have zero or one external definition of every identifier with external linkage.
>
> If an identifier with external linkage is used in any expression other than a non-VLA, (since C99) sizeof, or _Alignof (since C11), there must be one and only one external definition for that identifier somewhere in the entire program.

There's no exception for short-circuit operators. If you use it at compile time, for anything other than sizeof, then it has to exist (have storage allocated somewhere).

Moving the kernel to modern C

Posted Feb 26, 2022 0:56 UTC (Sat) by khim (subscriber, #9252) [Link] (1 responses)

It's an UB according to the standard. But Linus very rarely is concerned with that: he tends to accept such stupidity only when there are no way convince compiler to stop breaking sane (from Linux developer's POV!) code.

It's one of the reasons about why GCC is the only supported compiler, BTW.

And GCC not just supports that feature, it even provides __attribute__((__error(msg))) extensions to make error messages more explicit. And GLibC uses it to define __errordecl macro.

Moving the kernel to modern C

Posted Feb 26, 2022 2:34 UTC (Sat) by foom (subscriber, #14868) [Link]

And this sort of bad idea is why the kernel is only possible to compile with optimizations enabled.

It would be a lot better if Linux used c++ constexpr functions and templates for compile time evaluation semantics, instead of abusing the optimizer to very poorly emulate them.

Moving the kernel to modern C

Posted Feb 25, 2022 1:19 UTC (Fri) by ianloic (subscriber, #54050) [Link]

It's kind of fascinating how small the cost is, even when using the pointer afterwards: https://godbolt.org/z/cbv4fqan3


Copyright © 2025, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds