Inversion of `ComplexF32` numbers uses `Float64` numbers and fails to compile
- Dominant language
- Julia
- Stars
- 463
- Forks
- 68
- Avg merge
- 1d 19m
- Merged PRs (30d)
- 32
Description
Hello! Working with Metal.jl I have encountered the following issue. When computing the inverse of `ComplexF32` numbers, some `Float64` numbers seem to sneak in and cause Metal.jl to throw an error.
Here's a minimal example:
```julia
using Metal
function mwe(T)
d = mtl(rand(T, 2, 2))
return inv.(d)
end
```
If `T = Float32`, everything works fine. If `T = ComplexF32` instead, I get the following error:
```
julia> mwe(ComplexF32)
ERROR: InvalidIRError: compiling MethodInstance for (::Metal.var"#broadcast_2d#_copyto!##2")(::MtlDeviceMatrix{ComplexF32, 1}, ::Base.Broadcast.Broadcasted{Metal.MtlArrayStyle{…}, Tuple{…}, typeof(inv), Tuple{…}}) resulted in invalid LLVM IR
Reason: unsupported use of double value
Stacktrace:
[1] Float64
@ ./float.jl:345
[2] convert
@ ./number.jl:7
[3] Complex
@ ./complex.jl:14
[4] Complex
@ ./complex.jl:43
[5] convert
@ ./number.jl:7
[6] widen
@ ./operators.jl:946
[7] inv
@ ./complex.jl:474
[8] _broadcast_getindex_evalf
@ ./broadcast.jl:699
[9] _broadcast_getindex
@ ./broadcast.jl:672
[10] _getindex
@ ./broadcast.jl:620
[11] getindex
@ ./broadcast.jl:616
[12] broadcast_2d
@ ~/.julia/packages/Metal/TF981/src/broadcast.jl:119
Reason: unsupported use of double value
Stacktrace:
[1] Float64
@ ./float.jl:345
[2] convert
@ ./number.jl:7
[3] Complex
@ ./complex.jl:14
[4] Complex
@ ./complex.jl:43
[5] convert
@ ./number.jl:7
[6] widen
@ ./operators.jl:946
[7] inv
@ ./complex.jl:474
[8] _broadcast_getindex_evalf
@ ./broadcast.jl:699
[9] _broadcast_getindex
@ ./broadcast.jl:672
[10] _getindex
@ ./broadcast.jl:620
[11] getindex
@ ./broadcast.jl:616
[12] broadcast_2d
@ ~/.julia/packages/Metal/TF981/src/broadcast.jl:119
Reason: unsupported use of double value
Stacktrace:
[1] abs
@ ./float.jl:699
[2] isinf
@ ./float.jl:724
[3] inv
@ ./complex.jl:475
[4] _broadcast_getindex_evalf
@ ./broadcast.jl:699
[5] _broadcast_getindex
@ ./broadcast.jl:672
[6] _getindex
@ ./broadcast.jl:620
[7] getindex
@ ./broadcast.jl:616
[8] broadcast_2d
@ ~/.julia/packages/Metal/TF981/src/broadcast.jl:119
Reason: unsupported use of double value
Stacktrace:
[1] isinf
@ ./float.jl:724
[2] inv
@ ./complex.jl:475
[3] _broadcast_getindex_evalf
@ ./broadcast.jl:699
[4] _broadcast_getindex
@ ./broadcast.jl:672
[5] _getindex
@ ./broadcast.jl:620
[6] getindex
@ ./broadcast.jl:616
[7] broadcast_2d
@ ~/.julia/packages/Metal/TF981/src/broadcast.jl:119
Reason: unsupported use of double value
Stacktrace:
[1] abs
@ ./float.jl:699
[2] isinf
@ ./float.jl:724
[3] inv
@ ./complex.jl:475
[4] _broadcast_getindex_evalf
@ ./broadcast.jl:699
[5] _broadcast_getindex
@ ./broadcast.jl:672
[6] _getindex
@ ./broadcast.jl:620
[7] getindex
@ ./broadcast.jl:616
[8] broadcast_2d
@ ~/.julia/packages/Metal/TF981/src/broadcast.jl:119
Reason: unsupported use of double value
Stacktrace:
[1] isinf
@ ./float.jl:724
[2] inv
@ ./complex.jl:475
[3] _broadcast_getindex_evalf
@ ./broadcast.jl:699
[4] _broadcast_getindex
@ ./broadcast.jl:672
[5] _getindex
@ ./broadcast.jl:620
[6] getindex
@ ./broadcast.jl:616
[7] broadcast_2d
@ ~/.julia/packages/Metal/TF981/src/broadcast.jl:119
Reason: unsupported use of double value
Stacktrace:
[1] muladd
@ ./float.jl:500
[2] inv
@ ./complex.jl:476
[3] _broadcast_getindex_evalf
@ ./broadcast.jl:699
[4] _broadcast_getindex
@ ./broadcast.jl:672
[5] _getindex
@ ./broadcast.jl:620
[6] getindex
@ ./broadcast.jl:616
[7] broadcast_2d
@ ~/.julia/packages/Metal/TF981/src/broadcast.jl:119
Reason: unsupported use of double value
Stacktrace:
[1] *
@ ./float.jl:497
[2] literal_pow
@ ./intfuncs.jl:437
[3] inv
@ ./complex.jl:476
[4] _broadcast_getindex_evalf
@ ./broadcast.jl:699
[5] _broadcast_getindex
@ ./broadcast.jl:672
[6] _getindex
@ ./broadcast.jl:620
[7] getindex
@ ./broadcast.jl:616
[8] broadcast_2d
@ ~/.julia/packages/Metal/TF981/src/broadcast.jl:119
Reason: unsupported use of double value
Stacktrace:
[1] muladd
@ ./float.jl:500
[2] inv
@ ./complex.jl:476
[3] _broadcast_getindex_evalf
@ ./broadcast.jl:699
[4] _broadcast_getindex
@ ./broadcast.jl:672
[5] _getindex
@ ./broadcast.jl:620
[6] getindex
@ ./broadcast.jl:616
[7] broadcast_2d
@ ~/.julia/packages/Metal/TF981/src/broadcast.jl:119
Reason: unsupported use of double value
Stacktrace:
[1] /
@ ./float.jl:498
[2] inv
@ ./number.jl:255
[3] inv
@ ./complex.jl:476
[4] _broadcast_getindex_evalf
@ ./broadcast.jl:699
[5] _broadcast_getindex
@ ./broadcast.jl:672
[6] _getindex
@ ./broadcast.jl:620
[7] getindex
@ ./broadcast.jl:616
[8] broadcast_2d
@ ~/.julia/packages/Metal/TF981/src/broadcast.jl:119
Reason: unsupported use of double value
Stacktrace:
[1] -
@ ./float.jl:493
[2] inv
@ ./complex.jl:477
[3] _broadcast_getindex_evalf
@ ./broadcast.jl:699
[4] _broadcast_getindex
@ ./broadcast.jl:672
[5] _getindex
@ ./broadcast.jl:620
[6] getindex
@ ./broadcast.jl:616
[7] broadcast_2d
@ ~/.julia/packages/Metal/TF981/src/broadcast.jl:119
Reason: unsupported use of double value
Stacktrace:
[1] *
@ ./float.jl:497
[2] inv
@ ./complex.jl:477
[3] _broadcast_getindex_evalf
@ ./broadcast.jl:699
[4] _broadcast_getindex
@ ./broadcast.jl:672
[5] _getindex
@ ./broadcast.jl:620
[6] getindex
@ ./broadcast.jl:616
[7] broadcast_2d
@ ~/.julia/packages/Metal/TF981/src/broadcast.jl:119
Reason: unsupported use of double value
Stacktrace:
[1] Float32
@ ./float.jl:342
[2] convert
@ ./number.jl:7
[3] Complex
@ ./complex.jl:14
[4] Complex
@ ./complex.jl:43
[5] convert
@ ./number.jl:7
[6] oftype
@ ./essentials.jl:666
[7] inv
@ ./complex.jl:477
[8] _broadcast_getindex_evalf
@ ./broadcast.jl:699
[9] _broadcast_getindex
@ ./broadcast.jl:672
[10] _getindex
@ ./broadcast.jl:620
[11] getindex
@ ./broadcast.jl:616
[12] broadcast_2d
@ ~/.julia/packages/Metal/TF981/src/broadcast.jl:119
Reason: unsupported use of double value
Stacktrace:
[1] *
@ ./float.jl:497
[2] inv
@ ./complex.jl:477
[3] _broadcast_getindex_evalf
@ ./broadcast.jl:699
[4] _broadcast_getindex
@ ./broadcast.jl:672
[5] _getindex
@ ./broadcast.jl:620
[6] getindex
@ ./broadcast.jl:616
[7] broadcast_2d
@ ~/.julia/packages/Metal/TF981/src/broadcast.jl:119
Reason: unsupported use of double value
Stacktrace:
[1] Float32
@ ./float.jl:342
[2] convert
@ ./number.jl:7
[3] Complex
@ ./complex.jl:14
[4] Complex
@ ./complex.jl:43
[5] convert
@ ./number.jl:7
[6] oftype
@ ./essentials.jl:666
[7] inv
@ ./complex.jl:477
[8] _broadcast_getindex_evalf
@ ./broadcast.jl:699
[9] _broadcast_getindex
@ ./broadcast.jl:672
[10] _getindex
@ ./broadcast.jl:620
[11] getindex
@ ./broadcast.jl:616
[12] broadcast_2d
@ ~/.julia/packages/Metal/TF981/src/broadcast.jl:119
Hint: catch this exception as `err` and call `code_typed(err; interactive = true)` to introspect the erroneous code with Cthulhu.jl
Stacktrace:
[1] check_ir(job::GPUCompiler.CompilerJob{GPUCompiler.MetalCompilerTarget, Metal.MetalCompilerParams}, args::LLVM.Module)
@ GPUCompiler ~/.julia/packages/GPUCompiler/QgckP/src/validation.jl:170
[2] emit_llvm(job::GPUCompiler.CompilerJob; kwargs::@Kwargs{})
@ GPUCompiler ~/.julia/packages/GPUCompiler/QgckP/src/driver.jl:455
[3] emit_llvm(job::GPUCompiler.CompilerJob)
@ GPUCompiler ~/.julia/packages/GPUCompiler/QgckP/src/driver.jl:200
[4] compile_unhooked(output::Symbol, job::GPUCompiler.CompilerJob; kwargs::@Kwargs{})
@ GPUCompiler ~/.julia/packages/GPUCompiler/QgckP/src/driver.jl:101
[5] compile_unhooked
@ ~/.julia/packages/GPUCompiler/QgckP/src/driver.jl:80 [inlined]
[6] #compile#118
@ ~/.julia/packages/GPUCompiler/QgckP/src/driver.jl:67 [inlined]
[7] compile(target::Symbol, job::GPUCompiler.CompilerJob)
@ GPUCompiler ~/.julia/packages/GPUCompiler/QgckP/src/driver.jl:55
[8] #invoke_frozen#19
@ ~/.julia/packages/Metal/TF981/src/initialization.jl:15 [inlined]
[9] invoke_frozen
@ ~/.julia/packages/Metal/TF981/src/initialization.jl:13 [inlined]
[10] macro expansion
@ ~/.julia/packages/Metal/TF981/src/compiler/compilation.jl:436 [inlined]
[11] macro expansion
@ ~/.julia/packages/ObjectiveC/ectoz/src/os.jl:264 [inlined]
[12] (::Metal.var"#compile##0#compile##1"{GPUCompiler.CompilerJob{GPUCompiler.MetalCompilerTarget, Metal.MetalCompilerParams}})(ctx::LLVM.Context)
@ Metal ~/.julia/packages/Metal/TF981/src/compiler/compilation.jl:435
[13] JuliaContext(f::Metal.var"#compile##0#compile##1"{GPUCompiler.CompilerJob{GPUCompiler.MetalCompilerTarget, Metal.MetalCompilerParams}}; kwargs::@Kwargs{})
@ GPUCompiler ~/.julia/packages/GPUCompiler/QgckP/src/driver.jl:34
[14] JuliaContext(f::Function)
@ GPUCompiler ~/.julia/packages/GPUCompiler/QgckP/src/driver.jl:25
[15] compile(job::GPUCompiler.CompilerJob)
@ Metal ~/.julia/packages/Metal/TF981/src/compiler/compilation.jl:434
[16] actual_compilation(cache::Dict{…}, src::Core.MethodInstance, world::UInt64, cfg::GPUCompiler.CompilerConfig{…}, compiler::typeof(Metal.compile), linker::typeof(Metal.link))
@ GPUCompiler ~/.julia/packages/GPUCompiler/QgckP/src/execution.jl:245
[17] cached_compilation(cache::Dict{…}, src::Core.MethodInstance, cfg::GPUCompiler.CompilerConfig{…}, compiler::Function, linker::Function)
@ GPUCompiler ~/.julia/packages/GPUCompiler/QgckP/src/execution.jl:159
[18] macro expansion
@ ~/.julia/packages/Metal/TF981/src/compiler/execution.jl:199 [inlined]
[19] macro expansion
@ ./lock.jl:376 [inlined]
[20] mtlfunction(f::Metal.var"#broadcast_2d#_copyto!##2", tt::Type{Tuple{MtlDeviceMatrix{…}, Base.Broadcast.Broadcasted{…}}}; name::Nothing, kwargs::@Kwargs{})
@ Metal ~/.julia/packages/Metal/TF981/src/compiler/execution.jl:194
[21] mtlfunction
@ ~/.julia/packages/Metal/TF981/src/compiler/execution.jl:192 [inlined]
[22] macro expansion
@ ~/.julia/packages/Metal/TF981/src/compiler/execution.jl:89 [inlined]
[23] _copyto!
@ ~/.julia/packages/Metal/TF981/src/broadcast.jl:128 [inlined]
[24] copyto!
@ ~/.julia/packages/Metal/TF981/src/broadcast.jl:52 [inlined]
[25] copy
@ ~/.julia/packages/GPUArrays/VNJ6B/src/host/broadcast.jl:34 [inlined]
[26] materialize(bc::Base.Broadcast.Broadcasted{Metal.MtlArrayStyle{2, Metal.PrivateStorage}, Nothing, typeof(inv), Tuple{MtlMatrix{ComplexF32, Metal.PrivateStorage}}})
@ Base.Broadcast ./broadcast.jl:894
[27] mwe(T::Type)
@ Main ~/Projects/mwe.jl:4
[28] top-level scope
@ REPL[3]:1
[29] top-level scope
@ ~/.julia/packages/Metal/TF981/src/initialization.jl:110
Some type information was truncated. Use `show(err)` to see complete types.
```
The stacktrace is huge, but “Reason: unsupported use of double value” appears frequently. In [this Julia Discourse thread](https://discourse.julialang.org/t/inverting-complexf32-with-metal-jl-throws-an-error/137991/2?u=phx) it was suggested that `widen` is the culprit.
Adding `@fastmath` before `inv.(d)` in the function above makes `mwe` work, but it doesn’t seem like a proper solution. I won’t always be able to do this, for example if `inv` is called inside a package function.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with the Metal broadcast path at src/broadcast.jl:119 and compare the Julia Base inv, widen, and complex arithmetic frames shown in the stack trace. Reproduce the mwe example with Float32 and ComplexF32, then trace how compilation handles the latter without @fastmath. Done means inv.(d) compiles for ComplexF32 without unsupported double values.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- julia
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 45/100