Re: [PATCH] unroll: Make unrolled, unrolled_full and unrolled_none function-like
From: Alexander Lobakin
Date: Mon Oct 26 2026 - 12:00:02 EST
From: David Laight <david.laight.linux@xxxxxxxxx>
Date: Fri, 23 Oct 2026 17:38:45 +0100
> On Fri, 23 Oct 2026 15:42:28 +0200
> Alexander Lobakin <aleksander.lobakin@xxxxxxxxx> wrote:
>
>> From: Tzu-Ching Yang <shingekinocore@xxxxxxxxx>
>> Date: Thu, 22 Oct 2026 19:09:59 +0800
>>
>>> On Thu, Oct 22, 2026 at 10:01:40AM +0100, David Laight wrote:
>>>> Is it possible to make the syntax:
>>>> unrolled_for(....)
>>>>
>>>> Or is that made 'all hard and difficult' because he setting is sticky?
>>>
>>> The pragma binds only to the loop that follows it, so it can go inside
>>> the macro:
>>>
>>> #define unrolled_full_for(...) \
>>> __pick_unrolled(clang loop unroll(full), GCC unroll 65534) \
>>> for (__VA_ARGS__)
>>>
>>> unrolled_full_for (int i = 0, j = 7; i < 8; i++, j--)
>>> s += a[i] * b[j];
>>>
>>> GCC 8 to 16 and Clang 17 to 23 unroll this fully, and the same works
>>> with break and continue in the body, nested loops and a loop inside
>>> another macro. The count form has the same shape:
>>>
>>> unrolled_count_for (4, int i = 0; i < n; i++)
>>> s += a[i];
>>>
>>> As a fourth option, the _for forms would replace the four unrolled*
>>> macros: no clash with identifiers, and the loop reads like
>>> for_each_*(); the cost is a new loop spelling at every user. Olek,
>>> Eric, would you prefer this over options 1 to 3 from my earlier reply?
>>
>> I had considered this option in the past, but IIRC the unrolled
>> attribute can also apply to `while` etc, this would limit it to
>> `for` only.
>
> Is that really useful?
> Partially unrolling a variable iteration count loop most likely just
> trashes the I-cache.
> (The unroll can't use simd instructions because they aren't normally
> available in kernel - ok, some cpu have a 'load pair'.)
In XSk xmit code, we have loops with the number of iterations being a
variable (number of packets queued by the userspace program), but using
unrolling by 8 packets helps there a lot if iterations are really
independent from each other (except the counter itself).
Pick a lower or bigger value and the performance (which can sometimes
reach 90 Mpps if everything is optimized to the top) will drop,
`unrolled_full` is not an option (not a compile-time constant), leave it
without any manual unrolling and the compiler won't do anything ('cause
not a compile-time constant).
> The only exception is very short loops where unrolling once can help
> because the cpu cant execute a single clock loop.
> The compiler is likely to make a pigs breakfast of those loops
> so they end up in asm anyway - look at the xor parity code.
Thanks,
Olek