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

Switch from IRTools to CodeInfo #126

Merged
merged 20 commits into from
Mar 2, 2022
Merged

Switch from IRTools to CodeInfo #126

merged 20 commits into from
Mar 2, 2022

Conversation

KDr2
Copy link
Member

@KDr2 KDr2 commented Feb 23, 2022

Fix #117

@KDr2
Copy link
Member Author

KDr2 commented Feb 23, 2022

It turns out CodeInfo differs REALLY A LOT between versions...

@yebai
Copy link
Member

yebai commented Feb 23, 2022

It turns out CodeInfo differs REALLY A LOT between versions...

Let's focus on Julia >=1.7 in this PR.

@KDr2
Copy link
Member Author

KDr2 commented Feb 23, 2022

Take function g below as an exmaple:

function g(x, y)
  if x>y
    r= string(sin(x))
  else
    r= sin(x) * cos(y)
  end
  return r
end

Its CodeInfo under 1.6:

 :(Base.slt_int(_3, _2))
 :(goto %7 if not %1)
 :(Base.sitofp(Float64, _2))
 :($(Expr(:invoke, MethodInstance for sin(::Float64), :(Base.Math.sin), :(%3))))
 :($(Expr(:invoke, MethodInstance for string(::Float64), :(Main.string), :(%4))))
 :(goto %12)
 :(Base.sitofp(Float64, _2))
 :($(Expr(:invoke, MethodInstance for sin(::Float64), :(Base.Math.sin), :(%7))))
 :(Base.sitofp(Float64, _3))
 :($(Expr(:invoke, MethodInstance for cos(::Float64), :(Base.Math.cos), :(%9))))
 :(Base.mul_float(%8, %10))
 :(φ (%6 => %5, %11 => %11))
 :(return %12)

Under 1.7

 Core.NewvarNode(:(_4))
 :(_2 > _3)
 :(goto %7 if not %2)
 :(Main.sin(_2))
 :(_4 = Main.string(%4))
 :(goto %10)
 :(Main.sin(_2))
 :(Main.cos(_3))
 :(_4 = %7 * %8)
 :(return _4)

Under 1.8:
CodeInfoToosl.jl throws en error while getting its CodeInfo, code fetched by @code_lwoered:

julia> @code_lowered g(1.,2.)
CodeInfo(
1 ─      Core.NewvarNode(:(r))
│   %2 = x > y
└──      goto #3 if not %2
2 ─ %4 = Main.sin(x)
│        r = Main.string(%4)
└──      goto #4
3 ─ %7 = Main.sin(x)
│   %8 = Main.cos(y)
└──      r = %7 * %8
4 ┄      return r
)

Conclusion:

  • CodeInfo changed a lot between v1.6 and v1.7
  • CodeInfoTools.jl doesn't work on v1.8

@yebai
Copy link
Member

yebai commented Feb 23, 2022

CodeInfo changed a lot between v1.6 and v1.7

Good to know, probably due to the major compiler refactoring in 1.7.

CodeInfoTools.jl doesn't work on v1.8

Maybe raise an issue on the CodeInfoTools package, or help fix it if not major?

@KDr2
Copy link
Member Author

KDr2 commented Feb 23, 2022

Maybe we can remove the dependency of CodeInfoTools.jl too, all we want is to get the CodeInfo yet, but not to update the CodeInfo, so maybe there's a simple way to do that.

@yebai
Copy link
Member

yebai commented Feb 23, 2022

Maybe we can remove the dependency of CodeInfoTools.jl too, all we want is to get the CodeInfo yet, but not to update the CodeInfo, so maybe there's a simple way to do that.

We will likely need to update CodeInfo in the future, e.g. when we inline all the instructions. So we will probably build up a set of utilities for manipulating CodeInfo, which will be similar to CodeInfoTools. If that's the case, it might be better to depend on CodeInfoTools and help to improve it.

I took a quick look at the 1.8 error, and it appears that Julia has a simple function signature change between 1.7 and 1.8. It should be possible to fix that quickly.

@yebai
Copy link
Member

yebai commented Feb 23, 2022

CC @femtomc

Project.toml Show resolved Hide resolved
Project.toml Outdated Show resolved Hide resolved
src/tapedfunction.jl Outdated Show resolved Hide resolved
src/tapedfunction.jl Outdated Show resolved Hide resolved
src/tapedfunction.jl Outdated Show resolved Hide resolved
@femtomc
Copy link

femtomc commented Feb 23, 2022

Re — open issue in CodeInfoTools with stacktrace for failure on > 1.8.

@KDr2
Copy link
Member Author

KDr2 commented Feb 23, 2022

Re — open issue in CodeInfoTools with stacktrace for failure on > 1.8.

I opened 2 related issues:

@KDr2
Copy link
Member Author

KDr2 commented Feb 23, 2022

All tests passed with JuliaCompilerPlugins/CodeInfoTools.jl#14.

@femtomc
Copy link

femtomc commented Feb 23, 2022

Re — inlining transforms should likely not live in CodeInfoTools. Ideally, the plugin (speculative) interface should be used to do this. It’s still WIP tho.

also, tracking types and things that are required to do inlining is possible in CodeInfoTools (just like IRTools) but there’s no really code to do that yet

@rikhuijzer
Copy link
Contributor

The tests currently fail on the Turing test suite with the following errors (maybe more)

┌ Error: Unknown IR code:
│   typeof(line) = Core.SlotNumber
│   line = :(_28)
└ @ Libtask ~/git/Libtask.jl/src/tapedfunction.jl:291

and

dynamic model: Error During Test at /home/rik/git/Turing.jl/test/test_utils/staging.jl:42
  Got exception outside of a @test
  MethodError: no method matching iterate(::Nothing)
  Closest candidates are:
    iterate(::Union{LinRange, StepRangeLen}) at /nix/store/y46fn31jpgwkzj6hi1xjv0246x5w5dig-julia-bin-1.7.2/share/julia/base/range.jl:826
    iterate(::Union{LinRange, StepRangeLen}, ::Integer) at /nix/store/y46fn31jpgwkzj6hi1xjv0246x5w5dig-julia-bin-1.7.2/share/julia/base/range.jl:826
    iterate(::T) where T<:Union{Base.KeySet{<:Any, <:Dict}, Base.ValueIterator{<:Dict}} at /nix/store/y46fn31jpgwkzj6hi1xjv0246x5w5dig-julia-bin-1.7.2/share/julia/base/dict.jl:695
    ...
  Stacktrace:
    [1] consume(ttask::TapedTask{var"#imm#31"})
      @ Libtask ~/git/Libtask.jl/src/tapedtask.jl:144

@KDr2
Copy link
Member Author

KDr2 commented Feb 24, 2022

The tests currently fail on the Turing test suite with the following errors (maybe more)

Hope 2e96940 fixes them.

PS: Why our IntegrationTest doesn't show the errors?

@yebai
Copy link
Member

yebai commented Feb 24, 2022

Many thanks, @femtomc would you like to make a release of CodeInfoTools so that tests can pass here?

@devmotion
Copy link
Member

PS: Why our IntegrationTest doesn't show the errors?

Because Turing is not compatible with Libtask 0.7 or 0.8, and hence it is not possible to run them:
https://github.com/TuringLang/Libtask.jl/runs/5321568590?check_suite_focus=true#step:6:18

@rikhuijzer
Copy link
Contributor

Because Turing is not compatible with Libtask 0.7 or 0.8, and hence it is not possible to run them:
https://github.com/TuringLang/Libtask.jl/runs/5321568590?check_suite_focus=true#step:6:18

We could add a bit of logic to the CI which removes the compat entry from Turing for these integration tests? Would require only a few lines of code. Ping me if I need to open a PR for this on this repo.

@yebai
Copy link
Member

yebai commented Feb 24, 2022

We could add a bit of logic to the CI which removes the compat entry from Turing for these integration tests? Would require only a few lines of code. Ping me if I need to open a PR for this on this repo.

Seconded - that would be nice! @rikhuijzer

@devmotion
Copy link
Member

We could add a bit of logic to the CI which removes the compat entry from Turing for these integration tests? Would require only a few lines of code. Ping me if I need to open a PR for this on this repo.

I think we shouldn't do this. The point of breaking releases is to mark that there are breaking changes - so one can't expect downstream packages to work. And if downstream packages are broken it's not an issue since they explicitly state that they might not be compatible with this breaking release and also the package manager will never install them before the compat bound is updated.

@devmotion
Copy link
Member

And if you are about to make a breaking release you can already now only bump the version in the final commit before the PR is merged - then the downstream packages will be tested and you will see test errors. In this PR the issue is that Turing is not even compatible with Libtask 0.7 though.

Project.toml Outdated Show resolved Hide resolved
@KDr2 KDr2 requested a review from devmotion February 26, 2022 04:36
Copy link
Member

@devmotion devmotion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added some comments and suggestions. Overall it looks good, I can't comment too much on CodeInfoTools/IRTools specifics but I think it makes sense to move to the more stable and more lightweight alternative since it does not seem to increase complexity here.

Three more general comments:

  • We should remember to bump the version to 0.8 (or add it as the final commit in this PR once all tests, including Turing, pass)
  • We should try to add support for Julia 1.6 in a follow-up PR since it's the LTS version and supported by CodeInfoTools and all downstream packages
  • I think the extraction of the hardcoded isa statements in functions could be improved (in principle, it makes sense IMO): there is some code duplication and I think the Val argument should be removed (instead one could use branches in a (single!) function for Expr, possible calling other internal functions such as _expr_new...).

src/tapedfunction.jl Outdated Show resolved Hide resolved
src/tapedfunction.jl Outdated Show resolved Hide resolved
src/tapedfunction.jl Outdated Show resolved Hide resolved
src/tapedfunction.jl Outdated Show resolved Hide resolved
src/tapedfunction.jl Outdated Show resolved Hide resolved
src/tapedfunction.jl Outdated Show resolved Hide resolved
src/tapedfunction.jl Outdated Show resolved Hide resolved
src/tapedfunction.jl Outdated Show resolved Hide resolved
src/tapedfunction.jl Outdated Show resolved Hide resolved
src/tapedfunction.jl Outdated Show resolved Hide resolved
@KDr2
Copy link
Member Author

KDr2 commented Feb 26, 2022

I think it's not a good idea to support Julia v1.6 with the new compiler facilities, it will be a great cost, I took a glance at the CodeInfo in v1.6, it's much more complicated (I'm not sure if this word is precise).

How about letting Libtask v0.7.x (an LTS version as well?) keep using IRTools.jl and letting Julia prior to v1.7 use that version.

@rikhuijzer
Copy link
Contributor

How about letting Libtask v0.7.x (an LTS version as well?) keep using IRTools.jl and letting Julia prior to v1.7 use that version.

I think it’s a massive technical burden to maintain two versions in parallel

@devmotion
Copy link
Member

Yes, and in particular versions that are so different. E.g., in SpecialFunctions we backport all bug fixes to SpecialFunctions 1 to ensure that they also reach packages that have not updated their compat entry (since SpecialFunctions is such a core package and so many other packages depend on it), and that's easy since the breaking change in SpecialFunctions 2.0.0 was only the removal of the type piracy factorial(::Number). However, if Libtask 0.7 depends on IRTools and 0.8 on CodeInfoTools, then I assume it will be much more difficult to backport bug fixes and import performance improvements.

@devmotion
Copy link
Member

Is there a specific reason why it is difficult to support 1.6 but 1.8 works fine even though the CodeInfo is different from the one in 1.7 in both cases? In any case, I think it's fine to add support for 1.6 in a follow-up PR - but I also think it would be good to properly support, and hence also publish updates for, the LTS version.

@yebai
Copy link
Member

yebai commented Feb 26, 2022

Is there a specific reason why it is difficult to support 1.6 but 1.8 works fine even though the CodeInfo is different from the one in 1.7 in both cases?

There is a major compiler refactoring between 1.6 and 1.7. The CodeInfo data structures are quite similar for 1.7 and 1.8.

In any case, I think it's fine to add support for 1.6 in a follow-up PR - but I also think it would be good to properly support, and hence also publish updates for, the LTS version.

The old Libtask mechanism does support Julia 1.6 very well. The new tape-based mechanism is introduced for Julia 1.7. It is (partially) motivated by the high maintenance burden of Libtask for new Julia releases. It might not add too much value by backporting the new mechanism for previous Julia releases, since the old implementation works quite well.

Copy link
Member

@devmotion devmotion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should not even use Val for the Expr case. Unrelated of the Expr case, I think it is more natural to pass ir, taped, and boxes (not _box) as arguments to a function instead of constructing a callable. It seems there are also some undefined variables, so it seems not all functions are tested?

src/tapedfunction.jl Outdated Show resolved Hide resolved
src/tapedfunction.jl Outdated Show resolved Hide resolved
src/tapedfunction.jl Outdated Show resolved Hide resolved
src/tapedfunction.jl Outdated Show resolved Hide resolved
src/tapedfunction.jl Outdated Show resolved Hide resolved
src/tapedfunction.jl Outdated Show resolved Hide resolved
src/tapedfunction.jl Outdated Show resolved Hide resolved
src/tapedfunction.jl Outdated Show resolved Hide resolved
src/tapedfunction.jl Outdated Show resolved Hide resolved
src/tapedfunction.jl Outdated Show resolved Hide resolved
Copy link
Member

@yebai yebai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, @KDr2 - excellent work. I have some minor comments below, mostly about clarity.

In addition, the function names arg_boxer and args_initializer are a bit misleading. These two functions both refer to args but mean different things. The former refers to args for each instruction, while the latter refers to the args to a TapedFunction. Maybe we should make the distinction clearer.

src/tapedfunction.jl Outdated Show resolved Hide resolved
src/tapedfunction.jl Outdated Show resolved Hide resolved
src/tapedfunction.jl Show resolved Hide resolved
src/tapedfunction.jl Outdated Show resolved Hide resolved
src/tapedfunction.jl Outdated Show resolved Hide resolved
src/tapedfunction.jl Outdated Show resolved Hide resolved
src/tapedfunction.jl Show resolved Hide resolved
@KDr2
Copy link
Member Author

KDr2 commented Feb 27, 2022

In addition, the function names arg_boxer and args_initializer are a bit misleading.

I renamed arg_boxer to var_boxer.

@yebai yebai force-pushed the master branch 9 times, most recently from 4a0af2f to a95702e Compare February 27, 2022 20:51
@yebai yebai merged commit 0e00d76 into master Mar 2, 2022
@delete-merged-branch delete-merged-branch bot deleted the ir-code-info branch March 2, 2022 21:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Replace IRTools with CodeInfoTools
5 participants