Skip to content

@code_typed output is different from the actual IR for recursive Fibonacci function #36721

Open
@xitology

Description

@xitology

If I define a simple recursive Fibonacci function and apply @code_typed, I can see that Julia unrolled one level of recursion:

julia> fib(n) = n <= 1 ? n : fib(n-1) + fib(n-2)
fib (generic function with 1 method)

julia> @code_typed fib(10)
CodeInfo(
1 ─ %1  = Base.sle_int(n, 1)::Bool
└──       goto #3 if not %1
2 ─       return n
3 ─ %4  = Base.sub_int(n, 1)::Int64
│   %5  = Base.sle_int(%4, 1)::Bool
└──       goto #5 if not %5
4 ─       goto #6
5 ─ %8  = Base.sub_int(%4, 1)::Int64
│   %9  = invoke Main.fib(%8::Int64)::Int64
│   %10 = Base.sub_int(%4, 2)::Int64
│   %11 = invoke Main.fib(%10::Int64)::Int64
│   %12 = Base.add_int(%9, %11)::Int64
└──       goto #6
6 ┄ %14 = φ (#4 => %4, #5 => %12)::Int64
│   %15 = Base.sub_int(n, 2)::Int64
│   %16 = Base.sle_int(%15, 1)::Bool
└──       goto #8 if not %16
7 ─       goto #9
8 ─ %19 = Base.sub_int(%15, 1)::Int64
│   %20 = invoke Main.fib(%19::Int64)::Int64
│   %21 = Base.sub_int(%15, 2)::Int64
│   %22 = invoke Main.fib(%21::Int64)::Int64
│   %23 = Base.add_int(%20, %22)::Int64
└──       goto #9
9 ┄ %25 = φ (#7 => %15, #8 => %23)::Int64
│   %26 = Base.add_int(%14, %25)::Int64
└──       return %26
) => Int64

However in the actual IR, the recursion is not unrolled:

julia> c = first(first(methods(fib)).specializations).cache;

julia> Base._uncompressed_ir(c, c.inferred)
CodeInfo(
    @ REPL[1]:1 within `fib'
   ┌ @ int.jl:442 within `<='
1 ─│ %1 = Base.sle_int(n, 1)::Bool
│  └
└──      goto #3 if not %1
2 ─      return n
   ┌ @ int.jl:86 within `-'
3 ─│ %4 = Base.sub_int(n, 1)::Int64
│  └
│   %5 = invoke Main.fib(%4::Int64)::Int64
│  ┌ @ int.jl:86 within `-'
│  │ %6 = Base.sub_int(n, 2)::Int64
│  └
│   %7 = invoke Main.fib(%6::Int64)::Int64
│  ┌ @ int.jl:87 within `+'
│  │ %8 = Base.add_int(%5, %7)::Int64
│  └
└──      return %8
)

It was really unexpected that the output of @code_typed can differ from the actual inferred code. If it's unavoidable, it would be nice to have a warning in the documentation.

It was tested under the latest master and 1.5.0-rc1.0.

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