Skip to content

JIT: register operand must be loaded before the typed reference check #24386

Open

Description

@waroad

With the tracing JIT and low hot thresholds, a by-ref foreach over an array argument plus a function using global and static, called from a hot loop, hits an assertion in ir_gcm_schedule_late() when the trace is compiled.

<?php
function arrays($a) {
    foreach ($a as &$v) $v += 1;
}
function counter($n) {
    global $g;
    static $total = 0;
    $g += $n;
    $total += $n;
}
for ($i = 0; $i < 100; $i++) {
    arrays([4]);
    counter(2);
}
php -n -d opcache.enable_cli=1 -d opcache.file_update_protection=0 -d opcache.jit_buffer_size=64M -d opcache.protect_memory=1 -d opcache.jit=tracing -d opcache.jit_hot_func=2 -d opcache.jit_hot_loop=2 -d opcache.jit_hot_return=2 -d opcache.jit_hot_side_exit=2 input.php
php: ext/opcache/jit/ir/ir_gcm.c:579: ir_gcm_schedule_late: Assertion `ir_gcm_dominates(ctx, ctx->cfg_map[ref], lca) && "Early placement doesn't dominate the late"' failed.

I expected the script to run and exit normally, as it does on the release build and with opcache.jit=0.

It reproduces at 5ccc56b (latest upstream when checked). It is assertion-only: the build with assertions enabled aborts (rc 134, SIGABRT), the release build exits 0 with correct output. The same assertion was reported in #17190 (closed); I did not check whether it is the same cause. opcache.jit=1252, 1253 and 0153 with the same thresholds also fail; jit=function does not. With the default hot thresholds the loop never gets hot and nothing fails.

Looks like the trace IR built in zend_jit_trace.c/zend_jit_ir.c has a value used in a block that its early-scheduled block does not dominate, which ir_gcm_schedule_late() then catches. I did not find the exact node. It still fails with PR #24298 (Update IR) applied. PR #18392 (JIT: Don't reuse IP register for EX(call)) may be related; not tested here, its diff does not apply on the latest commit.

Found with an LLM-based testing tool; I used Claude to reduce it and look for the cause.

Activity

  1. self-assigned this
    on Oct 17, 2026
  2. changed the title [-]JIT: ir_gcm_schedule_late assertion "Early placement doesn't dominate the late" with tracing JIT[/-] [+]JIT: register operand must be loaded before the typed reference check[/+] on Oct 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions