FluxML / IRTools.jl

Mike's Little Intermediate Representation
MIT License
111 stars 36 forks source link

Calling `functional` with IR for `Dict` `getindex` raises `AssertionError` #100

Open rtjoa opened 2 years ago

rtjoa commented 2 years ago

The following example fails this assert on Julia v1.7.2, IRTools v0.4.6:

using IRTools: IR, functional

ir = IR(typeof(getindex), Dict{String, String}, String)
functional(ir)
MikeInnes commented 2 years ago

The use of @inbounds return ... here leads to a redundant trailing block in the IR:

``` 1: (%1, %2, %3) %4 = Base.ht_keyindex(%2, %3) %5 = $(Expr(:inbounds, true)) %6 = %4 < 0 br 3 unless %6 2: %7 = Base.KeyError(%3) %8 = Base.throw(%7) return %8 3: %9 = Base.getproperty(%2, :vals) %10 = Base.getindex(%9, %4) %11 = Core.typeassert(%10, $(QuoteNode(String))) return %11 4: %12 = $(Expr(:inbounds, :pop)) ```

ie block 4 isn't reachable here, and violates our assumptions by not branching anywhere. I guess the Julia compiler has some way to handle this case. I know little about how the :inbounds expression works so I'm not sure if it's safe to simply drop the :pop; for functional we could just remove all :inbounds expressions.

I've been meaning to build some tools for stripping unreachable code, so when I do I'll try to fix this issue as well.

guyvdbroeck commented 1 year ago

There appear to be more general issues with functional, for example the following code also errors while every block is reachable:

using IRTools: IR, functional
f(x,y) = x && y && error()
ir = IR(typeof(f), Bool, Bool)
functional(ir)

The issue is with the 3 branches in the generated IR:

ir = 1: (%1, %2, %3)
  br 4 unless %2
  br 3 unless %3
  br 2
2:
  %4 = Main.error()
  return %4
3:
  return false
4:
  return false