Skip to content

Tracing JIT: second ($d & 1) === 0 in a loop iteration evaluates to true for odd $d after side traces are compiled #24482

Closed

Description

@gitKBDL

Description

The following code:

<?php
function f(array $k): array {
    $out = [0, 0, 0, 0];
    for ($i = 0; $i < 1000; ++$i) {
        for ($d = 0; $d < 4; ++$d) {
            $a = $k[$d < 2 ? 0 : 1];
            $b = $k[($d & 1) === 0 ? 2 : 3];
            if (($d & 1) === 0) {
                ++$out[$d];          // only $d = 0 and $d = 2 can get here
            }
        }
    }
    return $out;
}
echo json_encode(f([0, 1, 2, 3])), "\n";

Run with:

php -d opcache.enable_cli=1 -d opcache.jit=tracing -d opcache.jit_buffer_size=64M test.php

Resulted in this output:

[1000,0,1000,984]

But I expected this output instead:

[1000,0,1000,0]

The second ($d & 1) === 0 of an iteration comes out true for $d = 3 once the side traces are compiled (984 of the 1000 iterations; the first 16 are right).

What we found while narrowing it down (official Docker images php:8.5-cli, php:8.4-cli, php:8.3-cli, x86_64):

  • PHP 8.5.11 (NTS and ZTS): wrong with opcache.jit=tracing, 1254, 1253, 1255, 1154. Right with 1054 (no register allocation) and with the JIT off. opcache.optimization_level makes no difference, even 0.
  • PHP 8.4.26: wrong too ([1000,983,1000,987]).
  • PHP 8.3.35: right.
  • The wrong second test is always the same arithmetic result compared with the literal 0: ($d & 1) === 0, !== 0, == 0, > 0, <= 0, 0 === ($d & 1), $d % 2 === 0, ($d ^ 1) === 0, ($d - 1) === 0. It is right when it is compared with another constant (=== 1), when the result is kept in a variable and that is tested twice, when the loop variable itself is tested ($d === 0), and when the tests are in different functions.
  • Something must read an array in a branch of the first test ($k[... ? 2 : 3], or if (...) { $b = $k[2]; } else { $b = $k[3]; }). With $b = (...) ? 2 : 3 or if (...) { $b = 1; } it is right.
  • The $d < 2 branch before it is not always needed: with ($d ^ 1) === 0 the second test is wrong without it.

PHP Version

PHP 8.5.11 (cli) (NTS), official php:8.5-cli image
PHP 8.4.26 (cli) (NTS), official php:8.4-cli image

Operating System

Debian (official Docker images), x86_64

Activity

  1. iliaal commented on Oct 22, 2026

    @iliaal
    Member

    Fixed by #23711.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions