Skip to content

Fix leakage of device-only methods into the global method table on Julia 1.13 - #3248

Merged
maleadt merged 2 commits into
mainfrom
tb/device-functions-1.13
Aug 26, 2026
Merged

maleadt merged 2 commits into
mainfrom
tb/device-functions-1.13

Conversation

@maleadt

@maleadt maleadt commented Aug 26, 2026

Copy link
Copy Markdown
Member

Fixes the Julia 1.13 recurrence of JuliaGPU/GPUCompiler.jl#611: ahead-of-time compilation of anything loading CUDA.jl (PackageCompiler.jl, juliac) aborts with LLVM ERROR: Cannot select: intrinsic %llvm.nvvm.membar.gl, or invalid instruction mnemonic 'exit' followed by a segfault. Two culprits:

  1. julia#62236 (in 1.13 since rc1, also on master) changed the expansion of @doc to if true; var"#val" = (f() = …); end. @device_functions macro-expanded its block first and then wrapped top-level definitions in @device_function, without descending into if, so every documented device function (sync_threads, threadfence*, clock, sync_warp, … 12 in total) silently kept its real llvmcall body in the global method table. Support Julia 1.13 #3020 had matched the previous 1.13 shape of the expansion and broke again when it changed. On 1.12 all 70 device functions are correctly stubbed; on 1.13-rc3, 12 are not.
  2. exit, nanosleep, global_random_keys/global_random_counters, CG.barrier_arrive/barrier_wait and map_shared_rank were never marked as device functions at all. exit() (@asmcall("exit;")) is enough to abort a sysimage build even with (1) fixed.

`@device_functions` macro-expanded its block first and then wrapped every
top-level definition in `@device_function`. Julia 1.13 (julia#62236) now
expands `@doc` into `if true; var"#val" = (f() = ...); end`, which the
rewrite did not descend into, so every documented device function
(`sync_threads`, `threadfence`, `clock`, ...) silently ended up in the
global method table with its GPU-only body. Ahead-of-time compilation
then fails with `LLVM ERROR: Cannot select: intrinsic %llvm.nvvm.membar.gl`
(JuliaGPU/GPUCompiler.jl#611). An earlier workaround (#3020) matched the
previous 1.13 shape of the expansion and broke again when it changed.

Rewrite definitions before expansion instead: docstring macrocalls are
entered directly, other macros are expanded per statement, and as a
fallback the walker also descends into `if` blocks and temporary
assignments. `@device_function` marks its CPU stub with `@__doc__` so
docstrings still attach to the function binding.

Add a source-driven test that every definition inside
`@device_function(s)` has an erroring CPU stub and no global method at
the definition's own location, which is what an escaped definition
looks like.
`exit`, `nanosleep`, the RNG state accessors, the cooperative-groups
grid barriers and `map_shared_rank` contain inline PTX or NVPTX
intrinsics but were plain global methods. Julia's compile-all pass
(`--output-o`: PackageCompiler.jl, juliac) compiles every method with a
concrete signature whether or not it is called, so e.g. `exit()` aborted
sysimage builds with `invalid instruction mnemonic 'exit'`
(JuliaGPU/GPUCompiler.jl#611).
@codecov

codecov Bot commented Aug 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.66%. Comparing base (f1c2dcb) to head (8ebcdf4).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3248      +/-   ##
==========================================
- Coverage   92.66%   92.66%   -0.01%     
==========================================
  Files         184      184              
  Lines       16176    16176              
==========================================
- Hits        14990    14989       -1     
- Misses       1186     1187       +1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions

Copy link
Copy Markdown
Contributor

CUDA.jl Benchmarks

Details
Benchmark suite Current: 8ebcdf4 Previous: f1c2dcb Ratio
array/accumulate/Float32/1d 97932 ns 97757 ns 1.00
array/accumulate/Float32/dims=1 71460 ns 72251 ns 0.99
array/accumulate/Float32/dims=1L 1599758 ns 1599352 ns 1.00
array/accumulate/Float32/dims=2 137293 ns 137934 ns 1.00
array/accumulate/Float32/dims=2L 660090 ns 659774 ns 1.00
array/accumulate/Int64/1d 117989 ns 117850 ns 1.00
array/accumulate/Int64/dims=1 75649 ns 76396 ns 0.99
array/accumulate/Int64/dims=1L 1716148 ns 1715658 ns 1.00
array/accumulate/Int64/dims=2 148426 ns 148676 ns 1.00
array/accumulate/Int64/dims=2L 987390 ns 987161 ns 1.00
array/broadcast 17939 ns 17712 ns 1.01
array/broadcast launch 9200 ns 8751.333333333334 ns 1.05
array/construct 865.2222222222222 ns 874.6607142857143 ns 0.99
array/copy 16088 ns 16385 ns 0.98
array/copyto!/cpu_to_gpu 208375 ns 208209 ns 1.00
array/copyto!/gpu_to_cpu 241010 ns 240797 ns 1.00
array/copyto!/gpu_to_gpu 9154.333333333334 ns 8958.666666666666 ns 1.02
array/iteration/findall/bool 133012 ns 132638 ns 1.00
array/iteration/findall/int 147686 ns 146498 ns 1.01
array/iteration/findfirst/bool 69002 ns 68518 ns 1.01
array/iteration/findfirst/int 70681 ns 70195 ns 1.01
array/iteration/findmin/1d 70057 ns 64408 ns 1.09
array/iteration/findmin/2d 100175 ns 99376 ns 1.01
array/iteration/logical 190661 ns 187866 ns 1.01
array/iteration/scalar 63928 ns 62527 ns 1.02
array/permutedims/2d 48848 ns 48266 ns 1.01
array/permutedims/3d 49999 ns 50042 ns 1.00
array/permutedims/4d 49997 ns 49777 ns 1.00
array/random/rand/Float32 11122 ns 11710 ns 0.95
array/random/rand/Int64 20693 ns 22484 ns 0.92
array/random/rand!/Float32 7774 ns 7826.75 ns 0.99
array/random/rand!/Int64 20294 ns 19938 ns 1.02
array/random/randn/Float32 33299 ns 32948 ns 1.01
array/random/randn!/Float32 23083 ns 23411 ns 0.99
array/reductions/mapreduce/Float32/1d 32529 ns 32707 ns 0.99
array/reductions/mapreduce/Float32/dims=1 37666 ns 37678 ns 1.00
array/reductions/mapreduce/Float32/dims=1L 50682 ns 50368 ns 1.01
array/reductions/mapreduce/Float32/dims=2 54936 ns 54900 ns 1.00
array/reductions/mapreduce/Float32/dims=2L 67507 ns 67068 ns 1.01
array/reductions/mapreduce/Int64/1d 40228 ns 39790 ns 1.01
array/reductions/mapreduce/Int64/dims=1 40753 ns 40639 ns 1.00
array/reductions/mapreduce/Int64/dims=1L 88633 ns 88392 ns 1.00
array/reductions/mapreduce/Int64/dims=2 57505 ns 57524 ns 1.00
array/reductions/mapreduce/Int64/dims=2L 83674 ns 82933 ns 1.01
array/reductions/reduce/Float32/1d 33123 ns 32599 ns 1.02
array/reductions/reduce/Float32/dims=1 37526 ns 37807 ns 0.99
array/reductions/reduce/Float32/dims=1L 50490 ns 50239 ns 1.00
array/reductions/reduce/Float32/dims=2 54931 ns 55233 ns 0.99
array/reductions/reduce/Float32/dims=2L 68837 ns 68967 ns 1.00
array/reductions/reduce/Int64/1d 40331 ns 39454 ns 1.02
array/reductions/reduce/Int64/dims=1 40344 ns 40134 ns 1.01
array/reductions/reduce/Int64/dims=1L 88652 ns 88225 ns 1.00
array/reductions/reduce/Int64/dims=2 57049 ns 57175 ns 1.00
array/reductions/reduce/Int64/dims=2L 82976 ns 82630 ns 1.00
array/reverse/1d 16898 ns 16492 ns 1.02
array/reverse/1dL 69649 ns 69275 ns 1.01
array/reverse/1dL_inplace 67447 ns 67321 ns 1.00
array/reverse/1d_inplace 8523 ns 10129.333333333334 ns 0.84
array/reverse/2d 19910 ns 20001 ns 1.00
array/reverse/2dL 73368 ns 73440 ns 1.00
array/reverse/2dL_inplace 67199 ns 67081 ns 1.00
array/reverse/2d_inplace 12067 ns 10270 ns 1.17
array/sorting/1d 2647715 ns 2656268 ns 1.00
array/sorting/2d 1029051 ns 1029271 ns 1.00
array/sorting/by 3183258 ns 3181708 ns 1.00
cuda/synchronization/context/auto 1042.7 ns 1011.2 ns 1.03
cuda/synchronization/context/blocking 806.9032258064516 ns 775.875 ns 1.04
cuda/synchronization/context/nonblocking 5873.833333333333 ns 5740.5 ns 1.02
cuda/synchronization/stream/auto 898.0909090909091 ns 856.6833333333333 ns 1.05
cuda/synchronization/stream/blocking 687.503355704698 ns 655.3548387096774 ns 1.05
cuda/synchronization/stream/nonblocking 5594.285714285715 ns 5544 ns 1.01
integration/byval/reference 147971 ns 147726 ns 1.00
integration/byval/slices=1 148821 ns 148600 ns 1.00
integration/byval/slices=2 291885 ns 291478 ns 1.00
integration/byval/slices=3 434718 ns 434349 ns 1.00
integration/cudadevrt 105171 ns 104975 ns 1.00
integration/volumerhs 9143880 ns 9136526 ns 1.00
kernel/indexing 13022 ns 12801 ns 1.02
kernel/indexing_checked 13662 ns 13502 ns 1.01
kernel/launch 2099.6666666666665 ns 2195.5555555555557 ns 0.96
kernel/occupancy 716 ns 820.3666666666667 ns 0.87
kernel/rand 17434 ns 13730 ns 1.27
latency/import 4114603153 ns 4095440314 ns 1.00
latency/precompile 4867534908 ns 4856791188 ns 1.00
latency/ttfp 4587984019 ns 4540682922 ns 1.01

This comment was automatically generated by workflow using github-action-benchmark.

@maleadt
maleadt merged commit 46ca9ca into main Aug 26, 2026
1 check passed
@maleadt
maleadt deleted the tb/device-functions-1.13 branch August 26, 2026 12:01
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