-
Notifications
You must be signed in to change notification settings - Fork 471
Option optimization: do not create redundant local vars #7915
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
Conversation
2255817
to
eb96936
Compare
rescript
@rescript/darwin-arm64
@rescript/darwin-x64
@rescript/linux-arm64
@rescript/linux-x64
@rescript/runtime
@rescript/win32-x64
commit: |
compiler/core/lam_util.ml
Outdated
in | ||
(* Helper for spotting RHS expressions that are safe to inline everywhere. | ||
These are the obviously pure shapes where substituting the original value | ||
cannot introduce extra work or side effects. *) |
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.
I don't understand. "does not have side effects" is enough of a description? If so isn't there a function already.
Otherwise, let's keep it as is.
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.
Btw some_not_nest could have side effects in the expression inside right?
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.
Yes, good catch, updated
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.
Oh no whitespace changes all over the file, one moment
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.
Ok should be fine now
7f61e48
to
66d9910
Compare
compiler/core/lam_util.ml
Outdated
| Lam_primitive.Pmakeblock _ -> true | ||
| _ -> false | ||
in | ||
let is_safe_to_inline (lam : Lam.t) = |
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.
OK now this is a very special case of Lam_analysis.no_side_effects
: why not just use Lam_analysis.no_side_effects
. Unless we know that's wrong. I would just test it see what happens.
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.
Specifically, Lam_analysis.no_side_effects
implies is_safe_to_inline
as the code is written today.
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.
Hmm, if I change is_safe_to_inline
to Lam_analysis.no_side_effects
, I get many changes because functions are reordered in the output. But this one doesn't look too good:
function swapUnsafe(xs, i, j) {
let tmp = xs[i];
xs[i] = xs[j];
xs[j] = tmp;
}
->
function swapUnsafe(xs, i, j) {
xs[i] = xs[j];
xs[j] = xs[i];
}
But this means that we shouldn't rely on Lam_analysis.no_side_effects
for the payload of Psome_not_nest
either.
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.
OK then I think the transformation needs to be explained in clear terms in the code.
Then each case needs to justify why it is OK (in comments) so it's evident that it's safe.
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.
Let me add more detailed comments in a second.
731663d
to
6dca3a9
Compare
6dca3a9
to
61f75df
Compare
Signed-off-by: Cristiano Calcagno <[email protected]>
@cknitt see comments I've added. |
We keep |
For reference, here is a fully spelled out (** [is_store_invariant lam] holds when re-evaluating [lam] after arbitrary
heap updates yields the same value as the original eager evaluation. This
is the property required before upgrading a [Strict] or [StrictOpt] binding
to [Alias]. *)
let rec is_store_invariant ?(env = Ident.Set.empty) (lam : Lam.t) : bool =
let all l = Ext_list.for_all l (is_store_invariant ~env) in
match lam with
| Lconst _ -> true
| Lvar v -> Ident.Set.mem v env
| Lglobal_module _ -> true
| Lfunction _ -> false
| Lprim { primitive; args; _ } -> (
match primitive, args with
| ( Paddint | Psubint | Pmulint | Pnegint | Pnotint | Pandint | Porint
| Pxorint | Plslint | Plsrint | Pasrint | Pintcomp _ | Pintorder
| Pintmin | Pintmax
| Pintoffloat | Pfloatofint | Pnegfloat | Paddfloat | Psubfloat
| Pmulfloat | Pdivfloat | Pmodfloat | Ppowfloat | Pfloatcomp _
| Pfloatorder | Pfloatmin | Pfloatmax
| Pnegbigint | Paddbigint | Psubbigint | Pmulbigint | Pdivbigint
| Pmodbigint | Ppowbigint | Pnotbigint | Pandbigint | Porbigint
| Pxorbigint | Plslbigint | Pasrbigint | Pbigintcomp _
| Pbigintorder | Pbigintmin | Pbigintmax
| Pstringlength | Pstringrefu | Pstringrefs | Pstringcomp _
| Pstringorder | Pstringmin | Pstringmax
| Pboolcomp _ | Pboolmin | Pboolmax | Psequand | Psequor | Pnot
| Pobjorder | Pobjmin | Pobjmax | Pobjtag | Pobjsize | Phash
| Phash_mixstring | Phash_mixint | Phash_finalmix
| Ptypeof | Pis_null | Pis_not_none | Pis_undefined | Pis_null_undefined
| Pnull_to_opt | Pnull_undefined_to_opt | Pval_from_option
| Pval_from_option_not_nest | Psome | Psome_not_nest | Pfn_arity ), _ ->
all args
| Pfield (_, Fld_module _), [ (Lglobal_module _ | Lvar _) as base ] ->
is_store_invariant ~env base
| Praw_js_code {code_info = Exp (Js_literal _ | Js_function _); _}, _ ->
all args
| _ -> false)
| Llet (kind, id, rhs, body) ->
let rhs_inv = is_store_invariant ~env rhs in
let env' =
if rhs_inv && (kind = Alias || kind = StrictOpt || kind = Strict) then
Ident.Set.add id env
else env
in
rhs_inv && is_store_invariant ~env:env' body
| Lletrec _ -> false
| Lsequence (a, b) -> is_store_invariant ~env a && is_store_invariant ~env b
| Lifthenelse (c, t, e) ->
is_store_invariant ~env c
&& is_store_invariant ~env t
&& is_store_invariant ~env e
| Lswitch (scrut, cases) ->
is_store_invariant ~env scrut
&& Ext_list.for_all_snd cases.sw_consts (is_store_invariant ~env)
&& Ext_list.for_all_snd cases.sw_blocks (is_store_invariant ~env)
&& Ext_option.for_all cases.sw_failaction (is_store_invariant ~env)
| Lstringswitch (scrut, branches, default) ->
is_store_invariant ~env scrut
&& Ext_list.for_all_snd branches (is_store_invariant ~env)
&& Ext_option.for_all default (is_store_invariant ~env)
| Lstaticraise (_, args) -> all args
| Lstaticcatch (body, _, handler) ->
is_store_invariant ~env body && is_store_invariant ~env handler
| Lapply _ -> false
| Ltrywith (body, _, handler) ->
is_store_invariant ~env body && is_store_invariant ~env handler
| Lwhile _ | Lfor _ | Lassign _ -> false |
Made option temporaries created by the compiler’s “non-nested some” helper collapse into simple aliases, so the optimizer no longer leaves behind redundant local variables.