Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:127924 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by lists.php.net (Postfix) with ESMTPS id 3D81B1A00BC for ; Mon, 7 Jul 2025 05:48:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1751867219; bh=2UJ2RpOnD2AA6PYP0meHVHPfhdcmbmBOe2DHsFQHeZo=; h=From:Date:Subject:To:From; b=fJC0NuQStxE+5+HVwcUytsb6IeH2uJArulOdAInF+KbfupjxwgZOqGo0cyVCwErjk cih2jEWJxIrS92rIPHv6JRUFKjEN3N3iyqO7jDNeOl4c2/5NZui3PpzPYeK/n06DEi VuylVDlg9qfPxlB80YsjMKnMPB1oztOCxUW9mgE6F8w/cM8ahMV9o5x5Bubqpy66iw jSNWzHDJ2rmlLO6UzsGU2Z7iG641dCBIcKUBvMmE998jClyurUNVub2E4L71Q+WTCJ YojlMuB8QAzX/HKMgpnNPdbf9MoqwCp1sbXQSY3XO/uhq/YGlLD9xLvKxZN9VwqL5V J2YMeFCZaX6/Q== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 3B19518005B for ; Mon, 7 Jul 2025 05:46:59 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-0.2 required=5.0 tests=BAYES_20,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,FREEMAIL_FROM, HTML_MESSAGE,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL, SPF_HELO_NONE,SPF_PASS autolearn=no autolearn_force=no version=4.0.1 X-Spam-Virus: Error (Cannot connect to unix socket '/var/run/clamav/clamd.ctl': connect: Connection refused) X-Envelope-From: Received: from mail-qt1-f182.google.com (mail-qt1-f182.google.com [209.85.160.182]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Mon, 7 Jul 2025 05:46:59 +0000 (UTC) Received: by mail-qt1-f182.google.com with SMTP id d75a77b69052e-4a5851764e1so67397171cf.2 for ; Sun, 06 Jul 2025 22:48:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1751867329; x=1752472129; darn=lists.php.net; h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=LCSgchqV4I4dMRHZWxkgawBQ07CK1/zIk1xcBAmhahU=; b=kR8f/jg6hgCaRBet2MZWH2rY3OQJzUjX833e229N2q4aP6kcju63Hocn8N0Ew13CmT U3NRQp8Ei6jXEQ2FJsq9lgYjpBCYJXdN+c6Oyvfg3x51bK4f40ANHOIxR2LSNft55Isd 0ylOWfMDci6iAS1VDo9NqGorgnEJFlGYnA/FmRdjfRyGVRvJdtzUGfpVDOllL/taERZ2 PMGLjQwcamr3ExtDlR56flI4Mj5C34sICWRF3t1mM4GfrVxE/4jL6clSaRntAbAMOOmt xAGXIxZ4nrsLYcjU745NtT36/MckHlaS/2EKOKlj3npv2Ydr5oBIEXplS18+TLCyJau1 zgKQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1751867329; x=1752472129; h=to:subject:message-id:date:from:mime-version:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=LCSgchqV4I4dMRHZWxkgawBQ07CK1/zIk1xcBAmhahU=; b=WCQLxdAo/aGaCAUws4eQPA4hrYcYsXc34N6oCe4k+spTck/btXwHb5UNV+kgyO3287 hddyt4b9BP0P79Hj1Jt2YRHHwPJ/sBX7FI8KxRI6V8QjKichk9tIndDF37ANJN3WT79n D9MKW4K8/2wWMKkjYkYztFNUWsItYrR8Cv4iXlBHnKQ3iGHkpVD1T1g6l0QZ95BpLfZN eLGWNWhZiB8l6mYT0Zj8LQd2GNKdzEas2YJmXsMhxkciAOY0IQg3uw/KOxsMM/F4gWiq NN75Eb07GcleMOyjfLbEEBMW6kxuZepMI4q8I9sLi0ct1Mkz+y82OcZIusE1+aLqm9Wv Q05Q== X-Gm-Message-State: AOJu0YwxNBDnLQbhbrujVcrhNZqUyBEDD9ade0oiq6kZPcKwRUT8zclk wyG7NJERWxZMcmqULI+FT0ruEHPZzgKRD9mgE6STUBh0gk4C2KVkbgwt5PwALnn6L+RQ+0edbgZ d0FVni1mHQYOr86UspKUQhtpt9Fhif3qRZ0ZAvSL5jA== X-Gm-Gg: ASbGncubV4U5+uOI9K8vVSHRWzKTwmlSsr7EEt9xycKV7OP7nwYz1Lz+jRVi03suXD4 q5mK+voQHxxELxj8Y1bLxlRjVg3P3mXlIR8jlo99BtDz0hZOk70Z7kG4+X/qNUR+pSmoGp7HFmp UV5s2HbidHc1Fl8yw5KtXsCh6SDaRzK1xkTYLdH4dx7L0= X-Google-Smtp-Source: AGHT+IEQeO/6AjXnz/2S0K6PDpGvoiAd9yi5cm6gFV5dyhpwSGKAHpVAdWUs9EttNhr319x2BcAAqp9zvNiNMtCrxEM= X-Received: by 2002:a05:622a:529a:b0:4a6:fa39:63ac with SMTP id d75a77b69052e-4a9a68f186cmr117844311cf.13.1751867328886; Sun, 06 Jul 2025 22:48:48 -0700 (PDT) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 Date: Mon, 7 Jul 2025 09:48:37 +0400 X-Gm-Features: Ac12FXwye_QS0b-DGy1nWOHccI56xKlE0z4QbmtDsooUG3MatKbYY4qWWGZSfF8 Message-ID: Subject: [PHP-DEV] [RFC Idea] Proposal: Loop Unrolling in Userland via #[Unroll(N)] Attribute To: PHP internals Content-Type: multipart/alternative; boundary="000000000000d4fc630639506562" From: khaledalam.net@gmail.com (Khaled Alam) --000000000000d4fc630639506562 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hello internals, I=E2=80=99d like to share an early proposal idea that introduces the abilit= y to express *loop unrolling* directly from userland using a simple attribute syntax: *#[Unroll(N)]*. Motivation Loop unrolling is a well-known optimization strategy used by compilers to reduce the overhead of conditional jumps and improve CPU pipelining by expanding the loop body multiple times. In PHP, we often hand-unroll loops for performance gains in hot paths, like so: for ($i =3D 0; $i < $n; $i +=3D 4) { $sum +=3D $array[$i] + $array[$i + 1] + $array[$i + 2] + $array[$i + 3]= ; } This is tedious and error-prone, especially when the logic is more complex. Idea: #[Unroll(N)] Syntax What if PHP allowed users to annotate loops like this? #[Unroll(4)]for ($i =3D 0; $i < $n; $i++) { $sum +=3D $array[$i]; } And the compiler could then *transform* this into an equivalent unrolled version at compile time, removing the need for manual duplication and keeping the source readable. Proof-of-Concept In a patched version of the PHP compiler, we implemented a special-case optimization for exactly this loop pattern: https://3v4l.org/T23MH

Hello internals,

I=E2=80=99d like to share an early proposal idea that introduces the abi= lity to express loop unrolling directly from userland usin= g a simple attribute syntax: #[Unroll(N)].

Motivation

Loop unrolling is a well-known optimization strategy used by compilers t= o reduce the overhead of conditional jumps and improve CPU pipelining by ex= panding the loop body multiple times.

In PHP, we often hand-unroll loops for performance gains in hot paths, l= ike so:


for ($i<= /span> =3D 0; $i < $n; $i +=3D 4) { $sum +=3D $array[$i] + $ar= ray[$i + 1] + $array[$i= + 2] + $array[$i + 3]; }

This is tedious and error-prone, especially when the logic is more compl= ex.

Idea: #[Unroll(N)] Syntax

What if PHP allowed users to annotate loops like this?

#[Unroll(4)] for ($i =3D 0; $i < = $n; $i++) { $sum +=3D $array[$i]; }

And the compiler could then transform this into an equivalent u= nrolled version at compile time, removing the need for manual duplication a= nd keeping the source readable.

Proof-of-Concept

In a patched version of the PHP compiler, we implemented a special-case = optimization for exactly this loop pattern:

https://3v4l.org/T23MH

<?php
// Proposal idea of enab= ling the unrolling in the userland.

function = measure(string $label, callable $fn)= : void {
$start =3D hrtime(true);
$result =3D $fn();
$end = =3D hrtime(true);
= $elapsed =3D ($end - $start) / 1e9;
echo "Sum: {$result}, {$label<= /span>}: " . number_form= at($elapsed, 6) . &= quot; seconds\n";
}

$array =3D range(1, 1e6);
=
$n =3D count($array);

measure("Normal for loop", function () use (= $array, $n) {
$sum =3D 0;
for ($i =3D 0; $i < $n; $i++) {
$sum +=3D $array= [$i];
}
return $sum;
}); // Sum: 500000500000, Normal for loop: 0.047172 seconds=

measure("Manual Unrolled x4", function () use ($array<= /span>, $n) {
<= span style=3D"color:rgb(200,200,200)">$sum =3D 0;
for ($i =3D 0; $i < $n; $i +=3D 4) {
$sum +=3D $array[$i] + $array[$= i + 1] + $array[$i + 2] + $array[$i + 3];
}
return $sum;
}); // Sum: 500000500000, Manual Unrolled x4:= 0.042200 seconds

measure("Manual Unrol= led x8", function = () use ($array, $n) {
$sum = =3D 0;
for ($i =3D 0; $i < $n; $i += =3D 8) {
$sum +=3D $array[$i] + $array[$i + 1] + $array[$i + 2] + $array[<= span style=3D"color:rgb(200,200,200)">$i + 3]
+ $array[$i + 4] + $array[$i<= /span> + 5] + $array[$i + 6] + $array[$i + 7];
<= div> }
return= $sum;
}); // Sum: 500000500000, Manual Unrolled x8: 0.0= 36472 seconds

//= Attributed Unroll - this is handled by your modified compiler
=
measure("Attributed Unrolled #[Unroll(4)]",= function () use ($ar= ray, $n) {
= $sum =3D 0;
// @TODO: KhaledAlam: Unrolling logic of zend_compile_for( )
// #[Unroll(4)]
for ($i =3D 0; $i < $n; $i++) {
$sum +=3D $array[$i];
}
=
return $sum;
}); // Sum: 0, Attributed Unrolled #[Unroll(4)] expected to be l= ess than normal loop
um: 500000500000, Normal for loop: 0.006646 seconds Sum: 500000500000, Manual Unrolled x4: 0.005646 seconds Sum: 500000500000, Manual Unrolled x8: 0.004885 seconds Sum: 500000500000, Attributed Unrolled #[Unroll(4)]: expected to be less th= an normal loop

Limitations & Scope

This is not a full RFC yet, just an idea seeking feedback. Current limit= ations:

  • No generic AST replacement yet, just a special-case demo.

  • Doesn't handle complex control flow, non-trivial statements, or mult= i-variable iteration.

  • Attribute is ignored in production PHP,=C2=A0requires patched compiler.<= /p>

Open Questions

  • Is there interest in allowing user-directed optimizations like = this?

  • Would PHP be willing to expand attribute-driven compiler behavior in thi= s direction?

  • What are the risks in exposing low-level optimizations to users?

  • Could this be generalized in the JIT instead?

Source & Demo

Happy to share an initial POC underdevelopment patch[0] if there's i= nterest.

Looking forward to your thoughts.

Best regards,
Khaled Alam

[0]=C2=A0https://gist.github.com= /khaledalam/2f2237733e1cc3ec74d597b1b20d94df


=
--000000000000d4fc630639506562--