Skip to content

Libtask doesn't gracefully handle sometimes-defined variables #204

@penelopeysm

Description

@penelopeysm

In the following MWE:

using Libtask

function g(y)
    produce(y + 1)
end
Libtask.might_produce(::Type{Tuple{typeof(g),Int}}) = true

function f(x)
    if x == 1
        y = 2
    end
    # `g` must produce.
    # Also, there must be at least two calls to `produce` in the function.
    g(y)
    g(y)
    return 1
end

f(1)

t = TapedTask(nothing, f, 1)

f(1) generates this IR:

2 1%1 = (_2 === 1)::Bool
  └──      goto #3 if not %1
  2nothing::Nothing
5 3%4 = φ (#2 => true, #1 => false)::Bool$(Expr(:throw_undef_if_not, :y, :(%4)))::Any
  │        invoke Main.produce(3::Int64)::Int64
6$(Expr(:throw_undef_if_not, :y, :(%4)))::Any
  │        invoke Main.produce(3::Int64)::Int64
7 └──      return 1

which Libtask transforms into this IR:

2 1%1  = (Libtask.resume_block_is)(_1, 14)::Any%2  = (Libtask.resume_block_is)(_1, 11)::Any
  └──       nothing::Any
  2 ─       goto #8 if not %1
  3 ─       goto #9 if not %2
  4 ─       goto #5
  5%7  = (_3 === 1)::Bool
  │         (Libtask.set_ref_at!)(_1, 1, %7)::Any%9  = (Libtask.get_ref_at)(_1, 1)::Any
  └──       goto #7 if not %9
  6nothing::Nothing
  └──       goto #7
  7%13 = φ (#6 => true, #5 => false)::Any%14 = (Libtask.deref_phi)(_1, %13)::Any
  │         (Libtask.set_ref_at!)(_1, 2, %14)::Any
5$(Expr(:throw_undef_if_not, :y, :(%14)))::Any
2 │         (Libtask.set_resume_block!)(_1, 14)::Any%18 = (Libtask.ProducedValue)(3)::Any
  └──       return %18
6 8$(Expr(:throw_undef_if_not, :y, :(%14)))::Any
2 │         (Libtask.set_resume_block!)(_1, 11)::Any%22 = (Libtask.ProducedValue)(3)::Any
  └──       return %22
  9 ─       (Libtask.set_resume_block!)(_1, -1)::Any
7 └──       return 1

which errors with

Basic Block 7 does not dominate block 8 (tried to use value %14 at %20)

when constructing a TapedTask. The issue is that Libtask inserts resume points before the :throw_undef_if_not expressions, which means that if the function is resumed from one of these points, %14 isn't defined (because the check that defines it was run earlier).

This is the same issue as #200, but minimised to remove the Turing dep.

I'm opening a separate issue because there's an downstream fix for the Turing model at TuringLang/DynamicPPL.jl#1110, and I think that's easier to merge and release than a more general fix for this kind of thing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions