Skip to content

Implement device min/max on LLVM versions that can't select llvm.minimum - #1165

Merged
luraess merged 3 commits into
mainfrom
tb/minmax-nan-old-llvm
Oct 20, 2026
Merged

luraess merged 3 commits into
mainfrom
tb/minmax-nan-old-llvm

Conversation

@maleadt

@maleadt maleadt commented Oct 19, 2026

Copy link
Copy Markdown
Member

Re-lands the part of #1148 that never reached main: #1148 was merged into its stacked base branch after that branch had already been merged.

#1117 already removed the NaN-ignoring ocml min/max overrides, so with Julia 1.13 and the external back-end, device min/max on floats match the host. But Julia 1.12 lowers them to llvm.minimum/llvm.maximum, which its in-process LLVM 18 can't select on most GPUs ("Cannot select: fminimum"). This adds an explicit comparison-based implementation for LLVM < 19, and #1148's tests: more special values and Atomix's atomic min/max on the device, and codegen checks for gfx90a/gfx942/gfx1200 with both back-ends.

Tested locally on gfx1036 (core/codegen and device/math): 194/194 on Julia 1.10, 206/206 on 1.12, 212/212 on 1.13. Without the fix, core/codegen crashes on 1.12.

Fixes #1142

Move compile_offline out of the atomic metadata testset so that other
codegen tests can compile for GPUs other than the local one too.
Julia 1.12 lowers Base.min/max on floats to llvm.minimum/maximum, which
LLVM only expands for every AMDGPU target since version 19. Since the ocml
overrides were removed (#1117), compiling float min/max with Julia 1.12's
in-process back-end fails with "Cannot select: fminimum" on most GPUs. Use
an explicit comparison with Julia's semantics (NaNs propagate, -0 < +0)
there instead.

Also extend the tests to cover more special values, Atomix's atomic
min/max, and the generated code for other GPUs and back-ends.

Fixes #1142
@github-actions

Copy link
Copy Markdown
Contributor

AMDGPU.jl Benchmarks

Details
Benchmark suite Current: 00fdba7 Previous: 0b3cee4 Ratio
amdgpu/synchronization/context/device 1820 ns 1790 ns 1.02
amdgpu/synchronization/stream/blocking 240 ns 232.5 ns 1.03
amdgpu/synchronization/stream/nonblocking 342.5 ns 345 ns 0.99
applications/bitonic_sort 1090758 ns 1120496 ns 0.97
applications/convolution 73553.5 ns 74001 ns 0.99
applications/floyd_warshall 8979620.75 ns 9041692.25 ns 0.99
applications/histogram 798016.25 ns 774031.25 ns 1.03
applications/prefix_sum 189477.5 ns 190332.75 ns 1.00
array/accumulate/Float32/1d 91046.5 ns 90656.25 ns 1.00
array/accumulate/Float32/dims=1 70761 ns 70808.5 ns 1.00
array/accumulate/Float32/dims=1L 102464 ns 105546.5 ns 0.97
array/accumulate/Float32/dims=2 105054.25 ns 105271.5 ns 1.00
array/accumulate/Float32/dims=2L 118901.75 ns 127276.75 ns 0.93
array/accumulate/Int64/1d 113794.25 ns 115419.25 ns 0.99
array/accumulate/Int64/dims=1 83811.25 ns 83676 ns 1.00
array/accumulate/Int64/dims=1L 110144 ns 110961.5 ns 0.99
array/accumulate/Int64/dims=2 108661.5 ns 108946.5 ns 1.00
array/accumulate/Int64/dims=2L 174747.5 ns 186815.25 ns 0.94
array/broadcast 57373.25 ns 33388 ns 1.72
array/construct 2510 ns 2442.5 ns 1.03
array/copy 40068.25 ns 39128 ns 1.02
array/copyto!/cpu_to_gpu 85816.25 ns 86096.25 ns 1.00
array/copyto!/gpu_to_cpu 85853.75 ns 86191.25 ns 1.00
array/copyto!/gpu_to_gpu 57255.75 ns 37893 ns 1.51
array/iteration/findall/bool 94451.5 ns 93611.25 ns 1.01
array/iteration/findall/int 104824 ns 103016.75 ns 1.02
array/iteration/findfirst/bool 56570.75 ns 55878.5 ns 1.01
array/iteration/findfirst/int 56070.75 ns 56053.25 ns 1.00
array/iteration/findmin/1d 97528.75 ns 96021.25 ns 1.02
array/iteration/findmin/2d 81188.75 ns 82588.75 ns 0.98
array/iteration/logical 91436.25 ns 91116.25 ns 1.00
array/iteration/scalar 306449.25 ns 296909.25 ns 1.03
array/permutedims/2d 61708.5 ns 49090.75 ns 1.26
array/permutedims/3d 55703.25 ns 58643.5 ns 0.95
array/permutedims/4d 51088.25 ns 62151 ns 0.82
array/random/rand/Float32 46713 ns 45763 ns 1.02
array/random/rand/Int64 39878 ns 45873 ns 0.87
array/random/rand!/Float32 49515.75 ns 65503.5 ns 0.76
array/random/rand!/Int64 48310.75 ns 48105.75 ns 1.00
array/random/randn/Float32 67421 ns 64408.25 ns 1.05
array/random/randn!/Float32 82873.75 ns 58868.5 ns 1.41
array/reductions/mapreduce/Float32/1d 70493.5 ns 69296 ns 1.02
array/reductions/mapreduce/Float32/dims=1 45783 ns 53448.25 ns 0.86
array/reductions/mapreduce/Float32/dims=1L 50380.75 ns 59493.25 ns 0.85
array/reductions/mapreduce/Float32/dims=2 51510.75 ns 60155.75 ns 0.86
array/reductions/mapreduce/Float32/dims=2L 60638.5 ns 71963.5 ns 0.84
array/reductions/mapreduce/Int64/1d 62001 ns 71308.5 ns 0.87
array/reductions/mapreduce/Int64/dims=1 43438 ns 43990.5 ns 0.99
array/reductions/mapreduce/Int64/dims=1L 56578.25 ns 64335.75 ns 0.88
array/reductions/mapreduce/Int64/dims=2 49545.75 ns 57796 ns 0.86
array/reductions/mapreduce/Int64/dims=2L 62848.5 ns 75973.75 ns 0.83
array/reductions/reduce/Float32/1d 59948.5 ns 69478.5 ns 0.86
array/reductions/reduce/Float32/dims=1 46345.75 ns 54248.5 ns 0.85
array/reductions/reduce/Float32/dims=1L 50770.5 ns 58768.25 ns 0.86
array/reductions/reduce/Float32/dims=2 51280.75 ns 59593.5 ns 0.86
array/reductions/reduce/Float32/dims=2L 60045.75 ns 71803.5 ns 0.84
array/reductions/reduce/Int64/1d 61421 ns 68288.5 ns 0.90
array/reductions/reduce/Int64/dims=1 49238.25 ns 50843.25 ns 0.97
array/reductions/reduce/Int64/dims=1L 64275.75 ns 70143.5 ns 0.92
array/reductions/reduce/Int64/dims=2 49893.25 ns 58103.5 ns 0.86
array/reductions/reduce/Int64/dims=2L 76011.25 ns 62133.5 ns 1.22
array/reverse/1d 35783 ns 39465.5 ns 0.91
array/reverse/1dL 47955.75 ns 60373.5 ns 0.79
array/reverse/1dL_inplace 57078.25 ns 78531 ns 0.73
array/reverse/1d_inplace 39325.5 ns 62158.5 ns 0.63
array/reverse/2d 48423 ns 41040.75 ns 1.18
array/reverse/2dL 73533.75 ns 78448.75 ns 0.94
array/reverse/2dL_inplace 93283.75 ns 74931.25 ns 1.24
array/reverse/2d_inplace 37423 ns 58875.75 ns 0.64
array/sorting/1d 336194.75 ns 336670 ns 1.00
gemm/tiled 1922802.75 ns 1893882.25 ns 1.02
gemm/tiled_unbounded 1939687.75 ns 1905582.5 ns 1.02
integration/byval/reference 41091 ns 37511 ns 1.10
integration/byval/slices=1 40481 ns 39661 ns 1.02
integration/byval/slices=2 149672 ns 153042 ns 0.98
integration/byval/slices=3 238223 ns 240084 ns 0.99
integration/volumerhs 4866169 ns 4960111 ns 0.98
kernel/indexing 39010.5 ns 32263 ns 1.21
kernel/indexing_checked 44688 ns 59088.25 ns 0.76
kernel/launch 1242.5 ns 1232.5 ns 1.01
kernel/rand 64603.25 ns 71428.5 ns 0.90
latency/import 1878175299 ns 1872656502 ns 1.00
latency/precompile 34296924846 ns 34344569766 ns 1.00
latency/ttfp 2302692363 ns 2288835992 ns 1.01
stencil/diffusion3d 1583310 ns 1594345.5 ns 0.99
stencil/diffusion3d_checked 1611955.5 ns 1623818.25 ns 0.99

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

@luraess
luraess merged commit 2f9834f into main Oct 20, 2026
2 checks passed
@luraess
luraess deleted the tb/minmax-nan-old-llvm branch October 20, 2026 10:57
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.

Device min/max on floats ignore NaNs, unlike Julia's min/max

2 participants