* [PATCH 0/3] container_of: refactors
@ 2026-07-14 18:18 Vincent Mailhol
2026-07-14 18:18 ` [PATCH 1/3] container_of: apply typeof_member() to container_of() Vincent Mailhol
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: Vincent Mailhol @ 2026-07-14 18:18 UTC (permalink / raw)
To: Greg Kroah-Hartman, Andrew Morton
Cc: Rasmus Villemoes, Sakari Ailus, Nick Desaulniers,
Alexander Lobakin, Arnd Bergmann, David Sterba, Ivo van Doorn,
Alexey Dobriyan, linux-kernel, Vincent Mailhol
This series refactors the container_of() function-like macro to improve
readability and remove a sparse/W=2 shadow warning. Further details in
each patch.
While I was expecting this series to be boring and purely cosmetic, the
bloat-o-meter stats gave some unexpected results:
$ ./scripts/bloat-o-meter vmlinux7.2-rc3_before.o vmlinux7.2-rc3_after.o
add/remove: 0/0 grow/shrink: 133/93 up/down: 5914901/-14344137 (-8429236)
< ... 227 lines redacted >
Total: Before=2641674349, After=2633245113, chg -0.32%
(done on v7.2-rc3 with GCC 15.3.0 on an x86_64 defconfig)
Upon analysis, this change in size can be tracked down to places where
container_of() is used in combination with __builtin_constant_p().
Here is a minimal reproducer:
struct foo {
int a;
};
#define to_foo(a_ptr) container_of(a_ptr, struct foo, a)
int f(int *a)
{
return __builtin_constant_p(to_foo(a)->a) || a;
}
The assembly code before this series...:
xor eax, eax
test rdi, rdi
setne al
ret
...and after:
mov eax, 1
ret
Link: https://godbolt.org/z/fenbGexjY
__builtin_constant_p(to_foo(a)->a) evaluates to false but gives the
optimiser the hint that pointer a is not NULL because of the
assumption that no undefined behaviour occurs. With this, the
expression:
__builtin_constant_p(to_foo(a)->a) || a
could be evaluated as true by the optimiser.
But the small variation in container_of() makes it that the optimiser
currently misses this optimisation but manages to do it after the
simplification of patch #3 of this series.
When __builtin_constant_p()'s argument is not trivially a compile time
constant, the result of __builtin_constant_p() comes late in the
evaluation process. And if it comes too late, after some other
optimisations were already done, the compiler will not retry and simply
miss these optimisations.
Note that the above example is very fragile and the results shown in
the godbolt link might not be reproducible under very small
variations.
Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
---
Vincent Mailhol (3):
container_of: apply typeof_member() to container_of()
container_of: remove useless pair of parentheses
container_of: remove local __mptr variable
include/linux/container_of.h | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
---
base-commit: a13c140cc289c0b7b3770bce5b3ad42ab35074aa
change-id: 20260110-containerof_refactor-63acf8118a18
Best regards,
--
Vincent Mailhol <mailhol@kernel.org>
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/3] container_of: apply typeof_member() to container_of()
2026-07-14 18:18 [PATCH 0/3] container_of: refactors Vincent Mailhol
@ 2026-07-14 18:18 ` Vincent Mailhol
2026-07-14 18:18 ` [PATCH 2/3] container_of: remove useless pair of parentheses Vincent Mailhol
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: Vincent Mailhol @ 2026-07-14 18:18 UTC (permalink / raw)
To: Greg Kroah-Hartman, Andrew Morton
Cc: Rasmus Villemoes, Sakari Ailus, Nick Desaulniers,
Alexander Lobakin, Arnd Bergmann, David Sterba, Ivo van Doorn,
Alexey Dobriyan, linux-kernel, Vincent Mailhol
container_of() uses the construct below:
((type *)0)->member
to retrieve the type of the structure's member and then ensure that it
matches the type of the given pointer.
This construct being rather difficult to understand, the typeof_member()
macro was created to encapsulate it and give it a descriptive name.
Apply typeof_member() to container_of() to make it easier to read and
understand what this macro does.
Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
---
include/linux/container_of.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/linux/container_of.h b/include/linux/container_of.h
index 1f6ebf27d962..28500a62ab7e 100644
--- a/include/linux/container_of.h
+++ b/include/linux/container_of.h
@@ -18,7 +18,7 @@
*/
#define container_of(ptr, type, member) ({ \
void *__mptr = (void *)(ptr); \
- static_assert(__same_type(*(ptr), ((type *)0)->member) || \
+ static_assert(__same_type(*(ptr), typeof_member(type, member)) || \
__same_type(*(ptr), void), \
"pointer type mismatch in container_of()"); \
((type *)(__mptr - offsetof(type, member))); })
--
2.54.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/3] container_of: remove useless pair of parentheses
2026-07-14 18:18 [PATCH 0/3] container_of: refactors Vincent Mailhol
2026-07-14 18:18 ` [PATCH 1/3] container_of: apply typeof_member() to container_of() Vincent Mailhol
@ 2026-07-14 18:18 ` Vincent Mailhol
2026-07-14 18:18 ` [PATCH 3/3] container_of: remove local __mptr variable Vincent Mailhol
2026-07-15 4:54 ` [PATCH 0/3] container_of: refactors Greg Kroah-Hartman
3 siblings, 0 replies; 6+ messages in thread
From: Vincent Mailhol @ 2026-07-14 18:18 UTC (permalink / raw)
To: Greg Kroah-Hartman, Andrew Morton
Cc: Rasmus Villemoes, Sakari Ailus, Nick Desaulniers,
Alexander Lobakin, Arnd Bergmann, David Sterba, Ivo van Doorn,
Alexey Dobriyan, linux-kernel, Vincent Mailhol
The last expression in container_of() doesn't need an extra pair of
parenthesis. Remove it.
Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
---
include/linux/container_of.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/linux/container_of.h b/include/linux/container_of.h
index 28500a62ab7e..68153170db32 100644
--- a/include/linux/container_of.h
+++ b/include/linux/container_of.h
@@ -21,7 +21,7 @@
static_assert(__same_type(*(ptr), typeof_member(type, member)) || \
__same_type(*(ptr), void), \
"pointer type mismatch in container_of()"); \
- ((type *)(__mptr - offsetof(type, member))); })
+ (type *)(__mptr - offsetof(type, member)); })
/**
* container_of_const - cast a member of a structure out to the containing
--
2.54.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 3/3] container_of: remove local __mptr variable
2026-07-14 18:18 [PATCH 0/3] container_of: refactors Vincent Mailhol
2026-07-14 18:18 ` [PATCH 1/3] container_of: apply typeof_member() to container_of() Vincent Mailhol
2026-07-14 18:18 ` [PATCH 2/3] container_of: remove useless pair of parentheses Vincent Mailhol
@ 2026-07-14 18:18 ` Vincent Mailhol
2026-07-15 4:54 ` [PATCH 0/3] container_of: refactors Greg Kroah-Hartman
3 siblings, 0 replies; 6+ messages in thread
From: Vincent Mailhol @ 2026-07-14 18:18 UTC (permalink / raw)
To: Greg Kroah-Hartman, Andrew Morton
Cc: Rasmus Villemoes, Sakari Ailus, Nick Desaulniers,
Alexander Lobakin, Arnd Bergmann, David Sterba, Ivo van Doorn,
Alexey Dobriyan, linux-kernel, Vincent Mailhol
container_of() can be called in a nested manner to retrieve the grand
parent structure as illustrated below:
struct foo {
int a;
};
struct bar {
struct foo foo;
};
#define to_foo(a_ptr) container_of(a_ptr, struct foo, a)
#define to_bar(a_ptr) container_of(to_foo(a_ptr), struct bar, foo)
The issue is that the above construct will cause __mptr, the local
variable of container_of(), to shadow itself because of the nested
call. This then triggers a warning in sparse and W=2 builds.
While this warning is benign, it still causes some overhead as proven by
below list of commits in which people made local workarounds:
- commit 7eab14de73a8 ("mdio, phy: fix -Wshadow warnings triggered by
nested container_of()")
- commit 8d8c3131248d ("clk: define to_clk_regmap() as inline
function")
- commit bfb972c5e1cb ("IB/verbs: avoid nested container_of()")
- commit 093adbcedf12 ("btrfs: switch helper macros to static inlines
in sysfs.h")
- commit c1d35dfa0f7d ("rt2x00: Fix sparse warning on nested
container_of()")
(the list is probably not exhaustive).
As a matter of fact, the local variable __mptr is only used once in
container_of(). As such, it is not strictly needed. Inline that local
__mptr variable to remove once and for all the risk of variable
shadowing when nesting container_of() and prevent people from writing
further local fixes.
Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
---
include/linux/container_of.h | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/include/linux/container_of.h b/include/linux/container_of.h
index 68153170db32..28db38e9ee3e 100644
--- a/include/linux/container_of.h
+++ b/include/linux/container_of.h
@@ -17,11 +17,10 @@
* Do not use container_of() in new code.
*/
#define container_of(ptr, type, member) ({ \
- void *__mptr = (void *)(ptr); \
static_assert(__same_type(*(ptr), typeof_member(type, member)) || \
__same_type(*(ptr), void), \
"pointer type mismatch in container_of()"); \
- (type *)(__mptr - offsetof(type, member)); })
+ (type *)((void *)(ptr) - offsetof(type, member)); })
/**
* container_of_const - cast a member of a structure out to the containing
--
2.54.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH 0/3] container_of: refactors
2026-07-14 18:18 [PATCH 0/3] container_of: refactors Vincent Mailhol
` (2 preceding siblings ...)
2026-07-14 18:18 ` [PATCH 3/3] container_of: remove local __mptr variable Vincent Mailhol
@ 2026-07-15 4:54 ` Greg Kroah-Hartman
2026-07-15 5:33 ` Vincent Mailhol
3 siblings, 1 reply; 6+ messages in thread
From: Greg Kroah-Hartman @ 2026-07-15 4:54 UTC (permalink / raw)
To: Vincent Mailhol
Cc: Andrew Morton, Rasmus Villemoes, Sakari Ailus, Nick Desaulniers,
Alexander Lobakin, Arnd Bergmann, David Sterba, Ivo van Doorn,
Alexey Dobriyan, linux-kernel
On Tue, Jul 14, 2026 at 08:18:00PM +0200, Vincent Mailhol wrote:
> This series refactors the container_of() function-like macro to improve
> readability and remove a sparse/W=2 shadow warning. Further details in
> each patch.
>
> While I was expecting this series to be boring and purely cosmetic, the
> bloat-o-meter stats gave some unexpected results:
>
> $ ./scripts/bloat-o-meter vmlinux7.2-rc3_before.o vmlinux7.2-rc3_after.o
> add/remove: 0/0 grow/shrink: 133/93 up/down: 5914901/-14344137 (-8429236)
> < ... 227 lines redacted >
> Total: Before=2641674349, After=2633245113, chg -0.32%
>
> (done on v7.2-rc3 with GCC 15.3.0 on an x86_64 defconfig)
>
> Upon analysis, this change in size can be tracked down to places where
> container_of() is used in combination with __builtin_constant_p().
>
> Here is a minimal reproducer:
>
> struct foo {
> int a;
> };
>
> #define to_foo(a_ptr) container_of(a_ptr, struct foo, a)
>
> int f(int *a)
> {
> return __builtin_constant_p(to_foo(a)->a) || a;
> }
>
> The assembly code before this series...:
>
> xor eax, eax
> test rdi, rdi
> setne al
> ret
>
> ...and after:
>
> mov eax, 1
> ret
>
> Link: https://godbolt.org/z/fenbGexjY
>
> __builtin_constant_p(to_foo(a)->a) evaluates to false but gives the
> optimiser the hint that pointer a is not NULL because of the
> assumption that no undefined behaviour occurs. With this, the
> expression:
>
> __builtin_constant_p(to_foo(a)->a) || a
>
> could be evaluated as true by the optimiser.
>
> But the small variation in container_of() makes it that the optimiser
> currently misses this optimisation but manages to do it after the
> simplification of patch #3 of this series.
>
> When __builtin_constant_p()'s argument is not trivially a compile time
> constant, the result of __builtin_constant_p() comes late in the
> evaluation process. And if it comes too late, after some other
> optimisations were already done, the compiler will not retry and simply
> miss these optimisations.
>
> Note that the above example is very fragile and the results shown in
> the godbolt link might not be reproducible under very small
> variations.
>
> Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
"fun" thing is, clang gets this right without your change, so this only
seems to help the gcc users.
Anyway, very nice optimizations, thanks for this! I'll queue these up
later today.
greg k-h
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 0/3] container_of: refactors
2026-07-15 4:54 ` [PATCH 0/3] container_of: refactors Greg Kroah-Hartman
@ 2026-07-15 5:33 ` Vincent Mailhol
0 siblings, 0 replies; 6+ messages in thread
From: Vincent Mailhol @ 2026-07-15 5:33 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Andrew Morton, Rasmus Villemoes, Sakari Ailus, Nick Desaulniers,
Alexander Lobakin, Arnd Bergmann, David Sterba, Ivo van Doorn,
Alexey Dobriyan, linux-kernel
On 15/07/2026 at 06:54, Greg Kroah-Hartman wrote:
> On Tue, Jul 14, 2026 at 08:18:00PM +0200, Vincent Mailhol wrote:
>> This series refactors the container_of() function-like macro to improve
>> readability and remove a sparse/W=2 shadow warning. Further details in
>> each patch.
>>
>> While I was expecting this series to be boring and purely cosmetic, the
>> bloat-o-meter stats gave some unexpected results:
>>
>> $ ./scripts/bloat-o-meter vmlinux7.2-rc3_before.o vmlinux7.2-rc3_after.o
>> add/remove: 0/0 grow/shrink: 133/93 up/down: 5914901/-14344137 (-8429236)
>> < ... 227 lines redacted >
>> Total: Before=2641674349, After=2633245113, chg -0.32%
>>
>> (done on v7.2-rc3 with GCC 15.3.0 on an x86_64 defconfig)
>>
>> Upon analysis, this change in size can be tracked down to places where
>> container_of() is used in combination with __builtin_constant_p().
>>
>> Here is a minimal reproducer:
>>
>> struct foo {
>> int a;
>> };
>>
>> #define to_foo(a_ptr) container_of(a_ptr, struct foo, a)
>>
>> int f(int *a)
>> {
>> return __builtin_constant_p(to_foo(a)->a) || a;
>> }
>>
>> The assembly code before this series...:
>>
>> xor eax, eax
>> test rdi, rdi
>> setne al
>> ret
>>
>> ...and after:
>>
>> mov eax, 1
>> ret
>>
>> Link: https://godbolt.org/z/fenbGexjY
>>
>> __builtin_constant_p(to_foo(a)->a) evaluates to false but gives the
>> optimiser the hint that pointer a is not NULL because of the
>> assumption that no undefined behaviour occurs. With this, the
>> expression:
>>
>> __builtin_constant_p(to_foo(a)->a) || a
>>
>> could be evaluated as true by the optimiser.
>>
>> But the small variation in container_of() makes it that the optimiser
>> currently misses this optimisation but manages to do it after the
>> simplification of patch #3 of this series.
>>
>> When __builtin_constant_p()'s argument is not trivially a compile time
>> constant, the result of __builtin_constant_p() comes late in the
>> evaluation process. And if it comes too late, after some other
>> optimisations were already done, the compiler will not retry and simply
>> miss these optimisations.
>>
>> Note that the above example is very fragile and the results shown in
>> the godbolt link might not be reproducible under very small
>> variations.
>>
>> Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
>
> "fun" thing is, clang gets this right without your change, so this only
> seems to help the gcc users.
Indeed. I forgot to mention it, but I also observed that clang is not
impacted by these weird __builtin_constant_p() intricacies.
One lesson learned it that in GCC __builtin_constant_p() can become an
optimisation killer.
> Anyway, very nice optimizations, thanks for this! I'll queue these up
> later today.
Thanks!
Yours sincerely,
Vincent Mailhol
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-07-15 5:33 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-14 18:18 [PATCH 0/3] container_of: refactors Vincent Mailhol
2026-07-14 18:18 ` [PATCH 1/3] container_of: apply typeof_member() to container_of() Vincent Mailhol
2026-07-14 18:18 ` [PATCH 2/3] container_of: remove useless pair of parentheses Vincent Mailhol
2026-07-14 18:18 ` [PATCH 3/3] container_of: remove local __mptr variable Vincent Mailhol
2026-07-15 4:54 ` [PATCH 0/3] container_of: refactors Greg Kroah-Hartman
2026-07-15 5:33 ` Vincent Mailhol
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.