Use of @code_warntype on a function with keyword arguments

I would like to use @code_warntype on a function with a keyword argument.
Consider the following simple example with an intentional type instability:

function myfun(a; tol = 2)
   x = (a > 42 ? a : 42.)
   return x + tol
end

@code_warntype myfun(2) returns the following:

@code_warntype myfun(2)
Variables:
  #self#::#myfun
  a::Int64

Body:
  begin 
      return $(Expr(:invoke, MethodInstance for #myfun#1(::Int64, ::Function, ::Int64), :(Main.#myfun#1), 2, :(#self#), :(a)))
  end::Union{Float64, Int64}

It seems that Julia creates an internal function #myfun#17 (maybe a barrier function?) which is invoked when myfun is called.

The following @code_warntype myfun(2, tol = 2) is much more verbose but it still does not reveal the problematic line x = (a > 42 ? a : 42.).

Variables:
  #unused#::#kw##myfun
  #temp#@_2::Array{Any,1}
  ::#myfun
  a::Int64
  #temp#@_5::Int64
  #temp#@_6::Int64
  #temp#@_7::Any
  #temp#@_8::Int64
  tol::Any

Body:
  begin 
      tol::Any = 2
      SSAValue(2) = (Base.arraylen)(#temp#@_2::Array{Any,1})::Int64
      SSAValue(3) = (Base.select_value)((Base.sle_int)(0, 1)::Bool, (Base.ashr_int)(SSAValue(2), (Base.bitcast)(UInt64, 1))::Int64, (Base.shl_int)(SSAValue(2), (Base.bitcast)(UInt64, (Base.neg_int)(1)::Int64))::Int64)::Int64
      SSAValue(5) = (Base.select_value)((Base.sle_int)(1, SSAValue(3))::Bool, SSAValue(3), (Base.sub_int)(1, 1)::Int64)::Int64
      #temp#@_8::Int64 = 1
      6: 
      unless (Base.not_int)((#temp#@_8::Int64 === (Base.add_int)(SSAValue(5), 1)::Int64)::Bool)::Bool goto 23
      SSAValue(6) = #temp#@_8::Int64
      SSAValue(7) = (Base.add_int)(#temp#@_8::Int64, 1)::Int64
      #temp#@_5::Int64 = SSAValue(6)
      #temp#@_8::Int64 = SSAValue(7)
      #temp#@_6::Int64 = (Base.sub_int)((Base.mul_int)(#temp#@_5::Int64, 2)::Int64, 1)::Int64
      #temp#@_7::Any = (Core.arrayref)(#temp#@_2::Array{Any,1}, #temp#@_6::Int64)::Any
      unless (#temp#@_7::Any === :tol)::Bool goto 17
      tol::Any = (Core.arrayref)(#temp#@_2::Array{Any,1}, (Base.add_int)(#temp#@_6::Int64, 1)::Int64)::Any
      goto 21
      17: 
      SSAValue(8) = ::#myfun
      SSAValue(9) = a::Int64
      (Base.throw)($(Expr(:new, :(Base.MethodError), :((Core.getfield)((Core.getfield)((Core.getfield)(#myfun, :name)::TypeName, :mt), :kwsorter)), :((Core.tuple)(#temp#@_2, SSAValue(8), SSAValue(9))::Tuple{Array{Any,1},#myfun,Int64}), 0xffffffffffffffff)))::Union{}
      21: 
      goto 6
      23: 
      return (Main.#myfun#1)(tol::Any, ::#myfun, a::Int64)::Any
  end::Any

Any ideas how can I use @code_warntype on these type of function?

2 Likes

I have the same question. Here is how the problem looks in julia 1.0.

julia> f(x;y=4) = instable(x,y)
f (generic function with 1 method)

julia> @code_warntype f(1)
Body::Any
1 1 ─ %1 = invoke Main.:(#f#8)(4::Int64, _1::Function, _2::Int64)::Any                                                                                                  │
  └──      return %1    

Any update on this? I have a function with keyword arguments that is being recompiled each time it is called and the macro @code_warntype is not providing useful information, just the invoke call.

Please open a new thread with a reproducible example.

f(x; y) = x + y
f_kw = Core.kwfunc(f)
x = 2
f_kw((y = 3,), f, x)

@code_warntype f_kw((y = 3,), f, x)

Or even easier, slowly descend into madness with Cthulhu.

2 Likes