Skip to content

Commit 7d1a2c3

Browse files
authored
Merge pull request #1156 from bloomberg/int64_side_effect
fix #1154, no inlining when operands have side effect
2 parents d4d779b + dd95b98 commit 7d1a2c3

24 files changed

+430
-113
lines changed

jscomp/all.depend

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -380,8 +380,8 @@ core/js_exp_make.cmx : ext/literals.cmx core/lam_compile_util.cmx \
380380
core/js_op_util.cmx core/js_fun_env.cmx common/js_config.cmx \
381381
core/js_call_info.cmx core/js_analyzer.cmx core/j.cmx ext/ext_string.cmx \
382382
ext/ext_pervasives.cmx ext/ext_ident.cmx core/js_exp_make.cmi
383-
core/js_long.cmx : core/js_exp_make.cmx common/js_config.cmx core/j.cmx \
384-
core/js_long.cmi
383+
core/js_long.cmx : core/js_exp_make.cmx common/js_config.cmx \
384+
core/js_analyzer.cmx core/j.cmx core/js_long.cmi
385385
core/js_of_lam_exception.cmx : ext/literals.cmx core/js_exp_make.cmx \
386386
common/js_config.cmx core/j.cmx core/js_of_lam_exception.cmi
387387
core/js_of_lam_module.cmx : core/js_exp_make.cmx core/j.cmx \
@@ -427,7 +427,8 @@ core/js_pass_flatten_and_mark_dead.cmx : core/js_stmt_make.cmx \
427427
ext/ident_hashtbl.cmx common/ext_log.cmx ext/ext_list.cmx \
428428
ext/ext_ident.cmx core/js_pass_flatten_and_mark_dead.cmi
429429
core/js_ast_util.cmx : ext/literals.cmx core/js_stmt_make.cmx \
430-
core/js_exp_make.cmx core/j.cmx ext/ext_ident.cmx core/js_ast_util.cmi
430+
core/js_exp_make.cmx core/js_analyzer.cmx core/j.cmx ext/ext_ident.cmx \
431+
core/js_ast_util.cmi
431432
core/lam_dce.cmx : core/lam_group.cmx core/lam_analysis.cmx core/lam.cmx \
432433
ext/ident_set.cmx ext/ident_hashtbl.cmx ext/ident_hash_set.cmx \
433434
ext/ext_pervasives.cmx ext/ext_ident.cmx core/lam_dce.cmi
@@ -467,7 +468,7 @@ core/js_dump.cmx : ext/literals.cmx core/lam_module_ident.cmx \
467468
core/js_pass_debug.cmx : core/js_dump.cmx common/js_config.cmx core/j.cmx \
468469
ext/ext_pervasives.cmx ext/ext_filename.cmx core/js_pass_debug.cmi
469470
core/js_of_lam_option.cmx : core/js_exp_make.cmx common/js_config.cmx \
470-
core/js_ast_util.cmx core/j.cmx core/js_of_lam_option.cmi
471+
core/js_analyzer.cmx core/j.cmx core/js_of_lam_option.cmi
471472
core/js_output.cmx : core/lam_compile_defs.cmx core/lam_analysis.cmx \
472473
core/lam.cmx core/js_stmt_make.cmx core/js_exp_make.cmx core/js_dump.cmx \
473474
core/js_analyzer.cmx core/j.cmx core/js_output.cmi

jscomp/bin/bsdep.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ val version : string
55

66
end = struct
77
#1 "bs_version.ml"
8-
let version = "1.4.3"
8+
let version = "1.4.2"
99

1010
end
1111
module Terminfo : sig

jscomp/bin/bsppx.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9114,7 +9114,7 @@ val version : string
91149114

91159115
end = struct
91169116
#1 "bs_version.ml"
9117-
let version = "1.4.3"
9117+
let version = "1.4.2"
91189118

91199119
end
91209120
module Ast_ffi_types : sig

jscomp/bin/whole_compiler.ml

Lines changed: 55 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ val version : string
55

66
end = struct
77
#1 "bs_version.ml"
8-
let version = "1.4.3"
8+
let version = "1.4.2"
99

1010
end
1111
module Terminfo : sig
@@ -66066,6 +66066,13 @@ val rev_toplevel_flatten : J.block -> J.block
6606666066

6606766067
val is_constant : J.expression -> bool
6606866068

66069+
66070+
(** Simple expression,
66071+
no computation involved so that it is okay to be duplicated
66072+
*)
66073+
66074+
val is_simple_no_side_effect_expression
66075+
: J.expression -> bool
6606966076
end = struct
6607066077
#1 "js_analyzer.ml"
6607166078
(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
@@ -66321,6 +66328,16 @@ let rec is_constant (x : J.expression) =
6632166328
is_constant a && is_constant b
6632266329
| _ -> false
6632366330

66331+
66332+
let rec is_simple_no_side_effect_expression (e : J.expression) =
66333+
match e.expression_desc with
66334+
| Var _
66335+
| Bool _
66336+
| Str _
66337+
| Number _ -> true
66338+
| Dot (e, (_ : string), _) -> is_simple_no_side_effect_expression e
66339+
| _ -> false
66340+
6632466341
end
6632566342
module Js_op_util : sig
6632666343
#1 "js_op_util.mli"
@@ -85774,10 +85791,7 @@ module Js_ast_util : sig
8577485791
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
8577585792

8577685793

85777-
(** Simple expression,
85778-
no computation involved so that it is okay to be duplicated
85779-
*)
85780-
val is_simple_expression : J.expression -> bool
85794+
8578185795

8578285796

8578385797

@@ -85819,18 +85833,10 @@ module E = Js_exp_make
8581985833

8582085834
module S = Js_stmt_make
8582185835

85822-
let rec is_simple_expression (e : J.expression) =
85823-
match e.expression_desc with
85824-
| Var _
85825-
| Bool _
85826-
| Str _
85827-
| Number _ -> true
85828-
| Dot (e, _, _) -> is_simple_expression e
85829-
| _ -> false
8583085836

8583185837
let rec named_expression (e : J.expression)
8583285838
: (J.statement * Ident.t) option =
85833-
if is_simple_expression e then
85839+
if Js_analyzer.is_simple_no_side_effect_expression e then
8583485840
None
8583585841
else
8583685842
let obj = Ext_ident.create Literals.tmp in
@@ -87163,22 +87169,22 @@ let int64_call (fn : string) args =
8716387169
(* TODO: make layout easier to change later *)
8716487170
let record_info = Lambda.Blk_record [| "hi"; "lo"|]
8716587171
let make_const ~lo ~hi =
87166-
E.make_block
87167-
~comment:"int64" (E.zero_int_literal)
87168-
record_info
87169-
[E.int hi; E.to_uint32 @@ E.int lo ; ]
87170-
(* If we use unsigned int for lo field,
87171-
then we can not use [E.int] which is
87172-
assumed to to be signed int.
87173-
Or we can use [Int64] to encode
87174-
in the ast node?
87175-
*)
87176-
Immutable
87172+
E.make_block
87173+
~comment:"int64" (E.zero_int_literal)
87174+
record_info
87175+
[E.int hi; E.to_uint32 @@ E.int lo ; ]
87176+
(* If we use unsigned int for lo field,
87177+
then we can not use [E.int] which is
87178+
assumed to to be signed int.
87179+
Or we can use [Int64] to encode
87180+
in the ast node?
87181+
*)
87182+
Immutable
8717787183
let make ~lo ~hi =
87178-
E.make_block
87179-
~comment:"int64" (E.zero_int_literal)
87180-
record_info [ hi; E.to_uint32 lo ]
87181-
Immutable
87184+
E.make_block
87185+
~comment:"int64" (E.zero_int_literal)
87186+
record_info [ hi; E.to_uint32 lo ]
87187+
Immutable
8718287188
let get_lo x = E.index x 1l
8718387189
let get_hi x = E.index x 0l
8718487190

@@ -87193,8 +87199,8 @@ let of_const (v : Int64.t) =
8719387199

8719487200
let to_int32 args =
8719587201
begin match args with
87196-
| [v] -> E.to_int32 @@ get_lo v
87197-
| _ -> assert false
87202+
| [v] -> E.to_int32 @@ get_lo v
87203+
| _ -> assert false
8719887204
end
8719987205

8720087206
let of_int32 (args : J.expression list) =
@@ -87230,16 +87236,25 @@ let mul args =
8723087236
let div args =
8723187237
int64_call "div" args
8723287238

87233-
let bit_op op args =
87239+
87240+
(** Note if operands are not pure, we need hold shared value,
87241+
which is a statement [var x = ... ; x ], it does not fit
87242+
current pipe-line fall back to a function call
87243+
*)
87244+
let bit_op op runtime_call args =
8723487245
match args with
8723587246
| [l;r] ->
87236-
make ~lo:(op (get_lo l) (get_lo r))
87237-
~hi:(op (get_hi l) (get_hi r))
87247+
(* Int64 is a block in ocaml, a little more conservative in inlining *)
87248+
if Js_analyzer.is_simple_no_side_effect_expression l &&
87249+
Js_analyzer.is_simple_no_side_effect_expression r then
87250+
make ~lo:(op (get_lo l) (get_lo r))
87251+
~hi:(op (get_hi l) (get_hi r))
87252+
else int64_call runtime_call args
8723887253
| _ -> assert false
8723987254

87240-
let xor = bit_op E.int32_bxor
87241-
let or_ = bit_op E.int32_bor
87242-
let and_ = bit_op E.int32_band
87255+
let xor = bit_op E.int32_bxor "xor"
87256+
let or_ = bit_op E.int32_bor "or_"
87257+
let and_ = bit_op E.int32_band "and_"
8724387258

8724487259

8724587260
let lsl_ args =
@@ -87297,9 +87312,9 @@ let to_float (args : J.expression list ) =
8729787312
(* {expression_desc = Number (Int {i = hi; _}) }; *)
8729887313
(* ], _, _, _); _ }] *)
8729987314
(* -> *)
87300-
87315+
8730187316
| [ _ ] ->
87302-
int64_call "to_float" args
87317+
int64_call "to_float" args
8730387318
| _ ->
8730487319
assert false
8730587320

@@ -88962,7 +88977,7 @@ let get_default_undefined (arg : J.expression) : J.expression =
8896288977
| Array ([x],_)
8896388978
| Caml_block([x],_,_,_) -> x (* invariant: option encoding *)
8896488979
| _ ->
88965-
if Js_ast_util.is_simple_expression arg then
88980+
if Js_analyzer.is_simple_no_side_effect_expression arg then
8896688981
E.econd arg (E.index arg 0l) E.undefined
8896788982
else E.runtime_call Js_config.js_primitive "option_get" [arg]
8896888983

jscomp/core/js_analyzer.ml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,3 +250,13 @@ let rec is_constant (x : J.expression) =
250250
| Bin (op, a, b) ->
251251
is_constant a && is_constant b
252252
| _ -> false
253+
254+
255+
let rec is_simple_no_side_effect_expression (e : J.expression) =
256+
match e.expression_desc with
257+
| Var _
258+
| Bool _
259+
| Str _
260+
| Number _ -> true
261+
| Dot (e, (_ : string), _) -> is_simple_no_side_effect_expression e
262+
| _ -> false

jscomp/core/js_analyzer.mli

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,11 @@ val rev_toplevel_flatten : J.block -> J.block
7373
(** return the block in reverse order *)
7474

7575
val is_constant : J.expression -> bool
76+
77+
78+
(** Simple expression,
79+
no computation involved so that it is okay to be duplicated
80+
*)
81+
82+
val is_simple_no_side_effect_expression
83+
: J.expression -> bool

jscomp/core/js_ast_util.ml

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,10 @@ module E = Js_exp_make
3131

3232
module S = Js_stmt_make
3333

34-
let rec is_simple_expression (e : J.expression) =
35-
match e.expression_desc with
36-
| Var _
37-
| Bool _
38-
| Str _
39-
| Number _ -> true
40-
| Dot (e, _, _) -> is_simple_expression e
41-
| _ -> false
4234

4335
let rec named_expression (e : J.expression)
4436
: (J.statement * Ident.t) option =
45-
if is_simple_expression e then
37+
if Js_analyzer.is_simple_no_side_effect_expression e then
4638
None
4739
else
4840
let obj = Ext_ident.create Literals.tmp in

jscomp/core/js_ast_util.mli

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,7 @@
2323
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
2424

2525

26-
(** Simple expression,
27-
no computation involved so that it is okay to be duplicated
28-
*)
29-
val is_simple_expression : J.expression -> bool
26+
3027

3128

3229

jscomp/core/js_long.ml

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -37,22 +37,22 @@ let int64_call (fn : string) args =
3737
(* TODO: make layout easier to change later *)
3838
let record_info = Lambda.Blk_record [| "hi"; "lo"|]
3939
let make_const ~lo ~hi =
40-
E.make_block
41-
~comment:"int64" (E.zero_int_literal)
42-
record_info
43-
[E.int hi; E.to_uint32 @@ E.int lo ; ]
44-
(* If we use unsigned int for lo field,
45-
then we can not use [E.int] which is
46-
assumed to to be signed int.
47-
Or we can use [Int64] to encode
48-
in the ast node?
49-
*)
50-
Immutable
40+
E.make_block
41+
~comment:"int64" (E.zero_int_literal)
42+
record_info
43+
[E.int hi; E.to_uint32 @@ E.int lo ; ]
44+
(* If we use unsigned int for lo field,
45+
then we can not use [E.int] which is
46+
assumed to to be signed int.
47+
Or we can use [Int64] to encode
48+
in the ast node?
49+
*)
50+
Immutable
5151
let make ~lo ~hi =
52-
E.make_block
53-
~comment:"int64" (E.zero_int_literal)
54-
record_info [ hi; E.to_uint32 lo ]
55-
Immutable
52+
E.make_block
53+
~comment:"int64" (E.zero_int_literal)
54+
record_info [ hi; E.to_uint32 lo ]
55+
Immutable
5656
let get_lo x = E.index x 1l
5757
let get_hi x = E.index x 0l
5858

@@ -67,8 +67,8 @@ let of_const (v : Int64.t) =
6767

6868
let to_int32 args =
6969
begin match args with
70-
| [v] -> E.to_int32 @@ get_lo v
71-
| _ -> assert false
70+
| [v] -> E.to_int32 @@ get_lo v
71+
| _ -> assert false
7272
end
7373

7474
let of_int32 (args : J.expression list) =
@@ -104,16 +104,25 @@ let mul args =
104104
let div args =
105105
int64_call "div" args
106106

107-
let bit_op op args =
107+
108+
(** Note if operands are not pure, we need hold shared value,
109+
which is a statement [var x = ... ; x ], it does not fit
110+
current pipe-line fall back to a function call
111+
*)
112+
let bit_op op runtime_call args =
108113
match args with
109114
| [l;r] ->
110-
make ~lo:(op (get_lo l) (get_lo r))
111-
~hi:(op (get_hi l) (get_hi r))
115+
(* Int64 is a block in ocaml, a little more conservative in inlining *)
116+
if Js_analyzer.is_simple_no_side_effect_expression l &&
117+
Js_analyzer.is_simple_no_side_effect_expression r then
118+
make ~lo:(op (get_lo l) (get_lo r))
119+
~hi:(op (get_hi l) (get_hi r))
120+
else int64_call runtime_call args
112121
| _ -> assert false
113122

114-
let xor = bit_op E.int32_bxor
115-
let or_ = bit_op E.int32_bor
116-
let and_ = bit_op E.int32_band
123+
let xor = bit_op E.int32_bxor "xor"
124+
let or_ = bit_op E.int32_bor "or_"
125+
let and_ = bit_op E.int32_band "and_"
117126

118127

119128
let lsl_ args =
@@ -171,8 +180,8 @@ let to_float (args : J.expression list ) =
171180
(* {expression_desc = Number (Int {i = hi; _}) }; *)
172181
(* ], _, _, _); _ }] *)
173182
(* -> *)
174-
183+
175184
| [ _ ] ->
176-
int64_call "to_float" args
185+
int64_call "to_float" args
177186
| _ ->
178187
assert false

jscomp/core/js_of_lam_option.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ let get_default_undefined (arg : J.expression) : J.expression =
5050
| Array ([x],_)
5151
| Caml_block([x],_,_,_) -> x (* invariant: option encoding *)
5252
| _ ->
53-
if Js_ast_util.is_simple_expression arg then
53+
if Js_analyzer.is_simple_no_side_effect_expression arg then
5454
E.econd arg (E.index arg 0l) E.undefined
5555
else E.runtime_call Js_config.js_primitive "option_get" [arg]
5656

0 commit comments

Comments
 (0)