Skip to content

Regression in julia v1.12 in optimisation of recursive function #58831

Open
@giordano

Description

@giordano

While looking into JuliaArrays/FixedSizeArrays.jl#142 I realised that in julia v1.12 there's a regression in optimisation of some recursive functions

julia> @noinline function mapreduce_impl(f, op, A::DenseArray,
                                         ifirst::Integer, ilast::Integer, blksize::Int)
           if ifirst == ilast ||  ilast - ifirst < blksize
               return zero(eltype(A))
           else
               imid = ifirst + (ilast - ifirst) >> 1
               v1 = mapreduce_impl(f, op, A, ifirst, imid, blksize)
               v2 = mapreduce_impl(f, op, A, imid+1, ilast, blksize)
               return op(v1, v2)
           end
       end
mapreduce_impl (generic function with 1 method)

julia> code_llvm(mapreduce_impl, (typeof(identity), typeof(+), Vector{Float64}, Int, Int, Int); )
; Function Signature: mapreduce_impl(typeof(Base.identity), typeof(Base.:(+)), Array{Float64, 1}, Int64, Int64, Int64)
;  @ REPL[6]:1 within `mapreduce_impl`
; Function Attrs: noinline
define double @julia_mapreduce_impl_2304(ptr noundef nonnull align 8 dereferenceable(24) %"A::Array", i64 signext %"ifirst::Int64", i64 signext %"ilast::Int64", i64 signext %"blksize::Int64") local_unnamed_addr #0 {
top:
;  @ REPL[6]:3 within `mapreduce_impl`
; ┌ @ promotion.jl:637 within `==`
   %.not = icmp eq i64 %"ifirst::Int64", %"ilast::Int64"
; └
  br i1 %.not, label %common.ret, label %L4

L4:                                               ; preds = %top
; ┌ @ int.jl:86 within `-`
   %0 = sub i64 %"ilast::Int64", %"ifirst::Int64"
; └
; ┌ @ int.jl:83 within `<`
   %.not2 = icmp slt i64 %0, %"blksize::Int64"
; └
  br i1 %.not2, label %common.ret, label %L8

common.ret:                                       ; preds = %L8, %L4, %top
;  @ REPL[6] within `mapreduce_impl`
  ret double 0.000000e+00

L8:                                               ; preds = %L4
;  @ REPL[6]:6 within `mapreduce_impl`
; ┌ @ int.jl:542 within `>>` @ int.jl:535
   %1 = ashr i64 %0, 1
; └
; ┌ @ int.jl:87 within `+`
   %2 = add i64 %1, %"ifirst::Int64"
; └
;  @ REPL[6]:7 within `mapreduce_impl`
  %3 = call double @j_mapreduce_impl_2307(ptr nonnull @"jl_global#2308.jit", ptr nonnull %"A::Array", i64 signext %"ifirst::Int64", i64 signext %2, i64 signext %"blksize::Int64")
;  @ REPL[6]:8 within `mapreduce_impl`
; ┌ @ int.jl:87 within `+`
   %4 = add i64 %2, 1
; └
  %5 = call double @j_mapreduce_impl_2307(ptr nonnull @"jl_global#2308.jit", ptr nonnull %"A::Array", i64 signext %4, i64 signext %"ilast::Int64", i64 signext %"blksize::Int64")
;  @ REPL[6]:9 within `mapreduce_impl`
  br label %common.ret
}

In Julia v1.11.5 the function is just reduced to 0:

julia> code_llvm(mapreduce_impl, (typeof(identity), typeof(+), Vector{Float64}, Int, Int, Int); )
; Function Signature: mapreduce_impl(typeof(Base.identity), typeof(Base.:(+)), Array{Float64, 1}, Int64, Int64, Int64)
;  @ REPL[1]:1 within `mapreduce_impl`
; Function Attrs: noinline
define double @julia_mapreduce_impl_437(ptr noundef nonnull align 8 dereferenceable(24) %"A::Array", i64 signext %"ifirst::Int64", i64 signext %"ilast::Int64", i64 signext %"blksize::Int64") #0 {
top:
;  @ REPL[1] within `mapreduce_impl`
  ret double 0.000000e+00
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions