JuliaGPU / JuliaGPU/Metal.jl

Inversion of `ComplexF32` numbers uses `Float64` numbers and fails to compile

Open
#871 2 comments 0 reactions 0 assignees View on GitHub
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.