Skip to content

relocate_gvs!: keep Type-valued globals as identity tokens#888

Open
vchuravy wants to merge 1 commit into
mainfrom
vc/relocate-gvs-type-tokens
Open

relocate_gvs!: keep Type-valued globals as identity tokens#888
vchuravy wants to merge 1 commit into
mainfrom
vc/relocate-gvs-type-tokens

Conversation

@vchuravy

Copy link
Copy Markdown
Member

Problem

relocate_gvs! decides whether to materialize a global's value with:

if isbitstype(typeof(obj)) && sizeof(obj) > 0 && !(obj isa Bool)

Union{} slips through this guard. typeof(Union{}) is Core.TypeofBottom, an isbits singleton, so isbitstype(typeof(obj)) is true — but sizeof(Union{}) throws (The empty type does not have a definite size since it does not have instances.) because the type is uninhabited.

This surfaces when differentiating ordinary code with Enzyme.jl on Julia 1.12 (GPUCompiler v2 path): the primal module carries a julia.constgv global pointing at Union{}, and relocate_gvs! crashes while baking it in:

The empty type does not have a definite size since it does not have instances.
Stacktrace:
 [1] sizeof(x::Type)
 [2] relocate_gvs!(mod::LLVM.Module, gv_to_value::Dict{String, Ptr{Nothing}})
     @ GPUCompiler .../src/jlgen.jl:800
 [3] emit_llvm(job::GPUCompiler.CompilerJob)

Fix

Exclude obj isa Type from materialization. Type objects — like any other non-isbits object — keep their host address as an identity token (baked inttoptr), which renders the module session-dependent, exactly as intended for objects whose identity matters.

Test

Adds a relocate_gvs! unit test for a slot pointing at Union{}, asserting it is baked as an address rather than fed to materialize_box!. Verified the test crashes on master and passes with this change.

🤖 Generated with Claude Code

`relocate_gvs!` materialized any global whose value passed
`isbitstype(typeof(obj)) && sizeof(obj) > 0`. `Union{}` slips through this
guard: `typeof(Union{})` is `Core.TypeofBottom`, an isbits singleton, so
`isbitstype` returns true, but `sizeof(Union{})` throws ("The empty type does
not have a definite size...") because the type is uninhabited.

This surfaces when differentiating ordinary code with Enzyme.jl on Julia 1.12:
the primal module carries a `julia.constgv` global pointing at `Union{}`, and
`relocate_gvs!` crashes while trying to bake it in.

Exclude `obj isa Type` from materialization so type objects (like any other
non-isbits object) keep their host address as an identity token. Adds a
`relocate_gvs!` unit test covering the `Union{}` slot.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MGwB7wpCnKDbkDsyZqixvF
@vchuravy
vchuravy marked this pull request as ready for review July 22, 2026 11:55
@vchuravy
vchuravy requested a review from maleadt July 22, 2026 11:56
vchuravy added a commit to EnzymeAD/Enzyme.jl that referenced this pull request Jul 22, 2026
GPUCompiler v2's `compile_method_instance` strips `julia.constgv` initializers
for session portability and defers them to `relocate_gvs!`, which either
materializes isbits constants as device-resident boxes or leaves globals as
external declarations. Enzyme assumed the v1 form, where every constgv global
carries a baked host-pointer `inttoptr` initializer.

`try_replace_constant_load!` therefore hit `LLVM.initializer(paddr) === nothing`
and crashed in `get_base_and_offset(::Nothing)` on Julia 1.12. Guard both
branches to bail out (fall back to a real load) when the initializer is absent.

This keeps us correct but loses the folding optimization on the v2 path, and
the deeper interaction (materialized boxes defeating activity analysis,
external-declaration constgvs having no shadow) is still unresolved. Document
that with `TODO(relocatable-globals)` notes: the real fix is to make Enzyme
relocatable rather than depend on baked host addresses.

The companion `relocate_gvs!` crash on `Union{}` globals is fixed upstream in
JuliaGPU/GPUCompiler.jl#888.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MGwB7wpCnKDbkDsyZqixvF
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