Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IncrementalCompact re-iteration is broken #46945

Closed
maleadt opened this issue Sep 28, 2022 · 4 comments · Fixed by #46952
Closed

IncrementalCompact re-iteration is broken #46945

maleadt opened this issue Sep 28, 2022 · 4 comments · Fixed by #46952
Labels
compiler:optimizer Optimization passes (mostly in base/compiler/ssair/)

Comments

@maleadt
Copy link
Member

maleadt commented Sep 28, 2022

Normally it should be possible to (partially) iterate an object, and iterate anew using a different iterator. This is not the case with IncrementalCompact.

Set-up, on latest master:

julia> foo(i) = i == 1 ? 1 : 2
foo (generic function with 1 method)

julia> ir = only(Base.code_ircode(foo, (Int,)))[1]
1 1%1 = (_2 === 1)::Bool                                                                 │╻ ==
  └──      goto #3 if not %1                                                                │
  2return 13return 2                                                                         │


julia> compact = Core.Compiler.IncrementalCompact(ir)
──────────────────────────────────────────────────────────────────────────────────────────────────
1 1%1 = (_2 === 1)::Bool                                                                 │╻ ==
  └──      goto #3 if not %1                                                                │
  2return 13return 2

Let's iterate a bit:

julia> x = Core.Compiler.iterate(compact)
(Pair{Pair{Int64, Int64}, Any}(1 => 1, :(_2 === 1)), (2, 1))

julia> compact
1 1%1 = (_2 === 1)::Bool                                                                 │╻ ==
──────────────────────────────────────────────────────────────────────────────────────────────────
  └──      goto #3 if not %1                                                                │
  2return 13return 2                                                                         │


julia> x = Core.Compiler.iterate(compact, x[2])
(Pair{Pair{Int64, Int64}, Any}(2 => 2, :(goto %3 if not %1)), (3, 2))

julia> compact
1 1%1 = (_2 === 1)::Bool                                                                 │╻ ==
  └──      goto #3 if not %1                                                                │
──────────────────────────────────────────────────────────────────────────────────────────────────
  2return 13return 2

The same, but with a new iterator:

julia> x = Core.Compiler.iterate(compact)
(Pair{Pair{Int64, Int64}, Any}(3 => 3, :(return 1)), (4, 1))

julia> compact
1 1%1 = (_2 === 1)::Bool                                                                 │╻ ==
  └──      goto #3 if not %1                                                                │
  2return 1                                                                         │
──────────────────────────────────────────────────────────────────────────────────────────────────
  3return 2                                                                         │


julia> x = Core.Compiler.iterate(compact, x[2])
(Pair{Pair{Int64, Int64}, Any}(4 => 4, :(return 2)), (5, 1))

julia> x = Core.Compiler.iterate(compact, x[2])

julia> compact
1 1%1 = (_2 === 1)::Bool                                                                 │╻ ==
  └──      goto #3 if not %1                                                                │
  2return 13return 2                                                                         │
──────────────────────────────────────────────────────────────────────────────────────────────────

So this second iteration resumed where the previous iterator left off, which is wrong, but it also breaks the resulting IR's CFG:

julia> Core.Compiler.complete(compact)
1 1%1 = (_2 === 1)::Bool                                                                 │╻ ==
  └──      goto #3 if not %1                                                                │
  !!! ─      return 1!!! ─      return 2

The !!!s don't occur if I only iterate using a single iterator.

@maleadt maleadt added the compiler:optimizer Optimization passes (mostly in base/compiler/ssair/) label Sep 28, 2022
@vtjnash
Copy link
Member

vtjnash commented Sep 28, 2022

Normally it should be possible to (partially) iterate an object, and iterate anew using a different iterator

This is sometimes true, but stateful iterators exist and aren't required to obey it

@vtjnash vtjnash closed this as completed Sep 28, 2022
@maleadt
Copy link
Member Author

maleadt commented Sep 28, 2022

Stateful iterators exist and aren't required to obey it

Can you give an other example? I take it that would mean it's OK for the second iterator to resume at the point the first left off. I can understand that, but the fact that the completed IR is broken afterwards still seems like a bug.

@vtjnash
Copy link
Member

vtjnash commented Sep 28, 2022

It is rare to have an iterator that is also mutating, but that is the explicit purpose of this iterator

@maleadt
Copy link
Member Author

maleadt commented Sep 28, 2022

I'm not saying it shouldn't mutate, I'm saying that it shouldn't corrupt the IR when using multiple of these stateful iterators. I think this is a legit issue, because of the state is initialized (it disregards the running bb counter). I agree it's rare though (esp. because it's still easy to corrupt the IR when using multiple of these iterators), but it seems like a simple change to fix this at least.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler:optimizer Optimization passes (mostly in base/compiler/ssair/)
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants