Skip to content

Restore AllocOptPass in the -O1 scalar optimizer pipeline - #281

Open
rbvermaa wants to merge 1 commit into
v1.12.6+RAIfrom
rv-o1-allocopt-backport
Open

Restore AllocOptPass in the -O1 scalar optimizer pipeline#281
rbvermaa wants to merge 1 commit into
v1.12.6+RAIfrom
rv-o1-allocopt-backport

Conversation

@rbvermaa

Copy link
Copy Markdown
Member

What

Backports the else if (O.getSpeedupLevel() >= 1) branch of buildScalarOptimizerPipeline that upstream added in JuliaLang/julia#52850"Add passes to -O1 pipeline to reduce allocations in reinterpret".

Why

That branch was backported to release-1.10 (#57731) and release-1.11 (#57732) on 2025-03-11, but never landed on the 1.12 line:

Ref else if (>= 1) block
v1.11.9 present
master present
release-1.13 present
v1.12.6 absent
release-1.12 absent
backports-release-1.12 absent

We found no revert on master and no stated rationale for the omission. #52850 merged 2025-02-21 and v1.12.0-rc1 was tagged 2025-07-12, so a branch cut after the merge should have inherited it.

Effect

Without AllocOptPass at -O1, a Ref holding an immutable value which never escapes and is used only via pointer_from_objref is heap-allocated:

struct TwoWords; a::UInt64; b::UInt64; end

@noinline function load_first_word(x)
    r = Ref(x); v = UInt64(0)
    GC.@preserve r begin
        p = reinterpret(Ptr{UInt64}, pointer_from_objref(r))
        v = unsafe_load(p)
    end
    return v
end
Build -O1 -O2
1.10.11 0 0
1.11.9 0 0
1.12.6 32 0
1.12.0-rc2+RAI 32 0
1.12.6+RAI 32 0

Reproduces on stock and +RAI builds, on aarch64-darwin and x86_64-linux. In the IR the box is a real @ijl_gc_small_alloc at -O1 and absent at -O2.

raicode runs its test suite at -O1 (JULIA_COMMON_ARGS) and asserts several hot paths allocate nothing — TypeNormalization's byte-string hash and fast_reinterpret use exactly this idiom deliberately to avoid allocating. So -O1 currently gives no usable "this code does not allocate" signal. Production builds run at -O2/-O3 and are unaffected.

Risk

The added pass list is byte-identical to v1.11.9's. All six passes are already used elsewhere in src/pipeline.cpp and their headers are already included, so this adds no new dependencies. The >= 2 branch is untouched, so -O2/-O3 codegen is unchanged.

Not compiled locally (no build tree) — validation is via raicode's deps.julia.x86_64-linux build plus the -O1 allocation assertions that currently fail.

Backport the `else if (O.getSpeedupLevel() >= 1)` branch of
buildScalarOptimizerPipeline that upstream added in JuliaLang#52850
("Add passes to -O1 pipeline to reduce allocations in reinterpret").

That branch was carried to release-1.10 (JuliaLang#57731) and release-1.11 (JuliaLang#57732)
on 2025-03-11, but never landed on release-1.12 — it is present on master,
release-1.13 and v1.11.9, and absent on release-1.12, backports-release-1.12
and v1.12.6. We could not find a revert or a rationale for the omission.

Without AllocOptPass at -O1, a `Ref` holding an immutable value which never
escapes and is used only via `pointer_from_objref` is heap-allocated:

    julia 1.10.11  -O1  @allocated = 0
    julia 1.11.9   -O1  @allocated = 0
    julia 1.12.6   -O1  @allocated = 32   <-- regression
    julia 1.12.6   -O2  @allocated = 0

raicode runs its test suite at -O1 and asserts that several hot paths
(TypeNormalization's byte-string hashing and fast_reinterpret, among
others) allocate nothing, so -O1 no longer gives a usable "this code does
not allocate" signal. Production builds run at -O2/-O3 and are unaffected.

The added pass list is byte-identical to v1.11.9's. All six passes are
already used elsewhere in this file and their headers are already included,
so this adds no new dependencies.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant