Skip to content

Performance: v2.0 targets and the codegen roadmap to reach them — typed code ≥ 3x Zend, untyped ≤ 1.5x slower, web request ≥ php-fpm: inline caches for property/method access, escape analysis for arrays/strings, guarded speculation, per-function O1 by default (lib/JIT.php, lib/JIT/Builtin/Type/Object_.php, lib/JIT/Analyzer.php) #36386

Description

@PurHur

Category

Foundation: · performance program, codegen half · child of #36379

Targets (measured by #7, in the pinned image, geometric mean unless stated)

workload today (2026-09-01 audit) v2.0 target
typed recursion / arithmetic (fibo, nbody) 1.1x Zend (regressed from 9x) ≥ 3x faster
untyped calls / loops (simple, closures) 2.5x slower ≤ 1.5x slower
strings / arrays / objects (str-builder, assoc-heavy, object-graph) 10–500x slower or OOM ≤ 1.5x slower
web request (phpc fcgi vs php-fpm) unmeasured ≥ 1x req/s, ≤ 0.5x memory
startup (hello) 2x faster keep

Roadmap (each item its own PR series, each gated by #7 and the differential sweeps)

  1. Land and verify wave 1's codegen items on the v2 suite: native-long hot path (Perf: typed int arithmetic boxes every result since overflow promotion — fibo(30) 8x slower than the 2026-07-28 build (lib/JIT/JitLongArithOverflow.php) #36189), __value__copy outline (Codegen: every boxed assignment open-codes a 15-block type switch with duplicated error blocks — 111k-line IR module and 51 KB helper functions for a 4-line script (lib/JIT/JitValueBox.php) #36193), light pass pipeline (Codegen: no LLVM pass ever runs at the default level — 40 alwaysinline runtime accessors stay real calls, MCJIT never optimises, and the per-function pass manager is mis-wired to a non-existent symbol (lib/JIT/Context.php runModuleOptimizationPasses, vendor/ircmaxell/php-llvm) #36213 — currently crashes every build on old trees, CI: master is unbuildable both from a clean checkout and on already-patched trees — the #36250 guard demands exactly one replaceVariablesByCfgWalk (a correctly patched file has two) and the pass-manager patch no longer lands on old trees, so every AOT build dies in the new light-opt step (script/apply-patches.sh, patches/php-cfg-simplifier-use-chain.patch, patches/php-llvm-module-createfunctionpassmanager.patch) (re-#36250, re-#36213, re-#36229) #36377), 16-byte __value__ (Runtime: __value__ is 9 bytes / align 1 so every i64/double payload access is an over-aligned (UB) load, and packed arrays allocate 16 B/slot but stride 9 (lib/JIT/Builtin/Type/Value.php, lib/JIT/Builtin/Type/HashTable.php) #36214), string addref (Runtime: every string copy is an eager memcpy — __string__separate ignores the refcount, no copy-on-write (lib/JIT/Builtin/Type/String_.php, lib/JIT/JitValueBox.php) #36192), {main} ownership (AOT: every array or string mutation in {main} scope is O(n²) in time and memory — refcounts never decrement in main, so separateContainerForWrite copies the whole table on every store (16k appends: 6.1 s in main vs 0.011 s inside a function) (lib/JIT/Builtin/Refcount.php phpc_destruct_delref_allowed, lib/JIT/HashTableWriteLlvm.php:1694) #36252).
  2. Inline caches for property and method access: __object__ slots are compile-time indexed for the declaring class; for polymorphic receivers emit a per-site (class-id → slot/function) cache with a generic fallback (the shape V8/Zend use). Target: object-graph within 1.5x.
  3. Escape analysis for locals: arrays/strings that never escape a function (no return, no store into a container/property/global, no by-ref, no closure capture) become stack allocations with no refcount traffic; Analyzer::canEscape exists for fixed-size int arrays — generalise.
  4. Guarded speculation (Perf: untyped loop counters and untyped user calls run boxed through __value__ with per-op type dispatch — add guarded speculation (unboxed i64 loop phis, unboxed call arguments) with the generic path as bail-out (lib/JIT.php, lib/JIT/JitValueNumeric.php, lib/JIT/Call/Native.php) (re-#23483) #36217 landed tag caching only): unboxed i64/double loop phis with a bail-out arm; specialised clones for hot untyped functions when all call sites agree on argument kinds.
  5. Per-function O1 by default with the function pass manager (Codegen: no LLVM pass ever runs at the default level — 40 alwaysinline runtime accessors stay real calls, MCJIT never optimises, and the per-function pass manager is mis-wired to a non-existent symbol (lib/JIT/Context.php runModuleOptimizationPasses, vendor/ircmaxell/php-llvm) #36213 step 3), whole-module O2 only for release builds; measure build-time cost on Stdlib: binary/octal radix conversion and PHPT specs #9's gate.
  6. String builder shape: .= in a loop with a refcount-1 destination appends in place (Runtime: .= is O(n²) — every append reallocates and memcpys both sides; no capacity field, no runtime interning (lib/JIT/Builtin/Type/String_.pre concat, lib/JIT/Builtin/Type/String_.php:928) #36216 partial landed geometric growth), implode/sprintf/json_encode write into a sized buffer.
  7. Calling convention: typed params/returns already native; add native ABI for ?int/?string/int|float (tag + payload in two registers) so nullable-typed code stops boxing.

Done when

  • Each roadmap item has its own child issue with a before/after row from Stdlib: empty construct, fmod, and float min/max #7 in the PR
  • v2.0 targets met on the v2 suite for 3 consecutive nightlies; docs/pages/bench.html shows the history
  • No item ships without script/differential-sweep.sh --aot --repeat 3 unchanged and compliance name-sets unchanged

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    MOST IMPORTANTThis are the most important targetsarea:compilerCompiler / CFG / JITenhancementNew feature or requestimplementation-readySpec complete: repro, php-src ref, done-when — safe for workers to claimphase-3:aotPhase 3 – AOT deployment

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions