-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
Allow constant-folding intrinsics that are non-pure for inference only #31193
Conversation
Yep, this seems like a good step down the road of making a proper |
# invalid intrinsic | ||
return nothing | ||
end | ||
(min, max, _) = T_IFUNC[iidx] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like you're trying to do error checking here, then only get around to doing half of it? I think we can reuse most of pure_eval_call
here, rather than implementing an arbitrary subset of it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, oops that code got lost somewhere. I don't think pure_eval_call
handles intrinsics though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
huh, that seems sort of a little bit silly. I didn't realize we had a third copy of that code sitting around too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So should I add support for intrinsics to pure_eval_call then? I would kind of like to avoid the try/catch since we do have nothrow modeling for intrinsics.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In any case, I've just added the error check here for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it's probably OK to reuse that support, although a bit less general (can't handle some functions where it might throw, but computing that set is pretty tedious—e.g. sizeof_tfunc
). But it doesn't look like you've got any calls to the no-throw predicate right now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems to still be missing a call to the nothrow-test or a try/catch to handle it?
Any constants produced during inference must be *exact* (in the === to what would have been produced at runtime sense). As a result, we disallow constant folding the sqrt intrinsic, since we can't guarantee that this will be the case (depending on what LLVM decides to do). However, this does not apply to the optimizer (and in fact we do it all the time by inlining pure functions here). Thus, for code size, inlining heuristics and non-LLVM backends, enable the optimizer to constant fold sqrt. Before: ``` julia> f() = sqrt(2) f (generic function with 1 method) julia> @code_typed f() CodeInfo( 1 ─ %1 = Base.Math.sqrt_llvm(2.0)::Float64 └── return %1 ) => Float64 julia> @code_typed optimize=false f() CodeInfo( 1 ─ %1 = Main.sqrt(2)::Float64 └── return %1 ) => Float64 ``` After ``` julia> @code_typed f() CodeInfo( 1 ─ return 1.4142135623730951 ) => Float64 julia> @code_typed optimize=false f() CodeInfo( 1 ─ %1 = Main.sqrt(2)::Float64 └── return %1 ) => Float64 ``` Note that we are not able to infer `Const`, but still inline the constant in the optimized version of the IR.
Playing with this, an interesting phenomenon that comes us is that other intrinsics in the same function become eligible for constant folding, but since they weren't constant at inference time they don't. I guess that means inlining needs to re-check if all the arguments are constant. |
Yes, in part that's why I want this to eventually handle as much as the other |
f === Intrinsics.cglobal) # cglobal lookup answer changes at runtime | ||
end | ||
|
||
# whether `f` is pure for inference | ||
is_pure_intrinsic_optimize_only(f) = f === Intrinsics.sqrt_llvm # this one may differ by a few ulps at runtime |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This list should have all of the _fast
intrinsics too plus muladd_float
. I thought I had remembered to add those to the is_pure_intrinsic_infer
list originally, but seems like somehow only sqrt_llvm
actually made it on the list—which is arguably the least likely one to actually be a problem.
# invalid intrinsic | ||
return nothing | ||
end | ||
(min, max, _) = T_IFUNC[iidx] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems to still be missing a call to the nothrow-test or a try/catch to handle it?
Can this be resurrected? |
We also need to mark `muladd` as IPO-in`:consistent, but it requires to revive #31193 to preserve the currently available optimizations so left for a future PR.
We also need to mark `muladd` as IPO-in`:consistent, but it requires to revive #31193 to preserve the currently available optimizations so left for a future PR.
We also need to mark `muladd` as not IPO-`:consistent, but it requires to revive #31193 to preserve the currently available optimizations so I left it as TODO for now.
We also need to mark `muladd` as not IPO-`:consistent, but it requires to revive #31193 to preserve the currently available optimizations so I left it as TODO for now.
We also need to mark `muladd` as not IPO-`:consistent, but it requires to revive JuliaLang#31193 to preserve the currently available optimizations so I left it as TODO for now.
We also need to mark `muladd` as not IPO-`:consistent, but it requires to revive JuliaLang#31193 to preserve the currently available optimizations so I left it as TODO for now.
This particular case was fixed in #43786. We also have the effect system now that says things about this more rigorously, though we don't use it yet here. Regardless, this particular change is outdated. |
Any constants produced during inference must be exact (in the === to
what would have been produced at runtime sense). As a result, we disallow
constant folding the sqrt intrinsic, since we can't guarantee that this
will be the case (depending on what LLVM decides to do). However, this does
not apply to the optimizer (and in fact we do it all the time by inlining
pure functions here). Thus, for code size, inlining heuristics and non-LLVM
backends, enable the optimizer to constant fold sqrt.
Before:
After
Note that we are not able to infer
Const
, but still inline theconstant in the optimized version of the IR.