Skip to content

Commit 5f01da5

Browse files
committed
Compiler: exit loops early
1 parent 81e4a44 commit 5f01da5

File tree

6 files changed

+1326
-1267
lines changed

6 files changed

+1326
-1267
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## Features/Changes
44
* Compiler: global dead code elimination (Micah Cantor, #1503)
55
* Compiler: change control-flow compilation strategy (#1496)
6+
* Compiler: loop no longer absorb the whole continuation
67
* Compiler: Dead code elimination of unused references (#2076)
78
* Compiler: reduce memory consumption (#1516)
89
* Compiler: support for es6 import and export construct

compiler/lib/generate.ml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,12 @@
2020

2121
(*XXX
2222
Patterns:
23-
=> loops should avoid absorbing the whole continuation...
24-
(detect when the continuation does not loop anymore and close
25-
the loop at this point)
2623
=> should have special code for switches that include the preceding
2724
if statement when possible
2825
=> if e1 then {if e2 then P else Q} else {if e3 then P else Q}
2926
=> if e then return e1; return e2
3027
=> if e then var x = e1; else var x = e2;
3128
=> while (true) {.... if (e) continue; break; }
32-
33-
- CLEAN UP!!!
3429
*)
3530

3631
open! Stdlib

compiler/lib/structure.ml

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,14 @@ let build_graph blocks pc =
9595
if leave_try_body block_order preds blocks leave_pc
9696
then (
9797
(* Add an edge to limit the [try] body *)
98-
Hashtbl.add succs enter_pc (Addr.Set.add leave_pc (Hashtbl.find succs enter_pc));
99-
Hashtbl.add preds leave_pc (Addr.Set.add enter_pc (Hashtbl.find preds leave_pc))));
98+
Hashtbl.replace
99+
succs
100+
enter_pc
101+
(Addr.Set.add leave_pc (Hashtbl.find succs enter_pc));
102+
Hashtbl.replace
103+
preds
104+
leave_pc
105+
(Addr.Set.add enter_pc (Hashtbl.find preds leave_pc))));
100106
{ succs; preds; reverse_post_order = !l; block_order }
101107

102108
let dominator_tree g =
@@ -166,3 +172,80 @@ let dominance_frontier g idom =
166172
g.preds;
167173
frontiers
168174
*)
175+
176+
(* Compute a map from each block to the set of loops it belongs to *)
177+
let mark_loops g =
178+
let in_loop = Hashtbl.create 16 in
179+
Hashtbl.iter
180+
(fun pc preds ->
181+
let rec mark_loop pc' =
182+
if not (Addr.Set.mem pc (get_edges in_loop pc'))
183+
then (
184+
add_edge in_loop pc' pc;
185+
if pc' <> pc then Addr.Set.iter mark_loop (Hashtbl.find g.preds pc'))
186+
in
187+
Addr.Set.iter (fun pc' -> if is_backward g pc' pc then mark_loop pc') preds)
188+
g.preds;
189+
in_loop
190+
191+
let rec measure blocks g pc limit =
192+
let b = Addr.Map.find pc blocks in
193+
let limit = limit - List.length b.body in
194+
if limit < 0
195+
then limit
196+
else
197+
Addr.Set.fold
198+
(fun pc limit -> if limit < 0 then limit else measure blocks g pc limit)
199+
(get_edges g.succs pc)
200+
limit
201+
202+
let is_small blocks g pc = measure blocks g pc 20 >= 0
203+
204+
let shrink_loops blocks ({ succs; preds; reverse_post_order; _ } as g) =
205+
let add_edge pred succ =
206+
Hashtbl.replace succs pred (Addr.Set.add succ (Hashtbl.find succs pred));
207+
Hashtbl.replace preds succ (Addr.Set.add pred (Hashtbl.find preds succ))
208+
in
209+
let in_loop = mark_loops g in
210+
let dom = dominator_tree g in
211+
let root = List.hd reverse_post_order in
212+
let rec traverse ignored pc =
213+
let succs = get_edges dom pc in
214+
let loops = get_edges in_loop pc in
215+
let block = Addr.Map.find pc blocks in
216+
Addr.Set.iter
217+
(fun pc' ->
218+
(* Whatever is in the scope of an exception handler should not be
219+
moved outside *)
220+
let ignored =
221+
match fst block.branch with
222+
| Pushtrap ((body_pc, _), _, _, _) when pc' = body_pc ->
223+
Addr.Set.union ignored loops
224+
| _ -> ignored
225+
in
226+
let loops' = get_edges in_loop pc' in
227+
let left_loops = Addr.Set.diff (Addr.Set.diff loops loops') ignored in
228+
(* If we leave a loop, we add an edge from a predecessor of
229+
the loop header to the current block, so that it is
230+
considered outside of the loop. *)
231+
if not (Addr.Set.is_empty left_loops || is_small blocks g pc')
232+
then
233+
Addr.Set.iter
234+
(fun pc0 ->
235+
match
236+
Addr.Set.find_first
237+
(fun pc -> is_forward g pc pc0)
238+
(get_edges g.preds pc0)
239+
with
240+
| pc -> add_edge pc pc'
241+
| exception Not_found -> ())
242+
left_loops;
243+
traverse ignored pc')
244+
succs
245+
in
246+
traverse Addr.Set.empty root
247+
248+
let build_graph blocks pc =
249+
let g = build_graph blocks pc in
250+
shrink_loops blocks g;
251+
g

compiler/tests-compiler/gh1007.ml

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -319,9 +319,11 @@ let () = M.myfun M.x
319319
len = 0,
320320
param = l;
321321
for(;;){
322-
if(! param){if(2 <= len) sort(len, l); var x$0 = next; break;}
322+
if(! param) break;
323323
var l$0 = param[2], len$0 = len + 1 | 0, len = len$0, param = l$0;
324324
}
325+
if(2 <= len) sort(len, l);
326+
var x$0 = next;
325327
}
326328
}
327329
//end |}]
@@ -625,14 +627,15 @@ let () = M.run ()
625627
even = closures$0[1],
626628
param$0 = even(i);
627629
for(;;){
628-
if(759635106 <= param$0[1]){
629-
var _g_ = i + 1 | 0;
630-
if(4 !== i){var i = _g_; break;}
631-
var _f_ = caml_call1(list_rev, delayed[1]);
632-
return caml_call2(list_iter, function(f){return caml_call1(f, 0);}, _f_);
633-
}
630+
if(759635106 <= param$0[1]) break;
634631
var f = param$0[2], param$0 = f(0);
635632
}
633+
var _g_ = i + 1 | 0;
634+
if(4 === i){
635+
var _f_ = caml_call1(list_rev, delayed[1]);
636+
return caml_call2(list_iter, function(f){return caml_call1(f, 0);}, _f_);
637+
}
638+
var i = _g_;
636639
}
637640
}
638641
//end |}]

compiler/tests-compiler/loops.ml

Lines changed: 56 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,10 @@ let rec fun_with_loop acc = function
100100
for(;;){
101101
a[1] = [0, 1, a[1]];
102102
var _a_ = i + 1 | 0;
103-
if(10 === i){var acc$1 = [0, x, a[1]], acc$0 = acc$1, param$0 = xs; break;}
103+
if(10 === i) break;
104104
var i = _a_;
105105
}
106+
var acc$1 = [0, x, a[1]], acc$0 = acc$1, param$0 = xs;
106107
}
107108
}
108109
//end
@@ -130,19 +131,15 @@ let for_for_while () =
130131
var k = 1;
131132
for(;;){
132133
var j = 1;
133-
a:
134-
for(;;)
135-
for(;;){
136-
if(10 <= runtime.caml_mul(k, j)){
137-
var _b_ = j + 1 | 0;
138-
if(10 !== j){var j = _b_; break;}
139-
var _a_ = k + 1 | 0;
140-
if(10 === k) return 0;
141-
var k = _a_;
142-
break a;
143-
}
144-
id[1]++;
145-
}
134+
for(;;){
135+
for(;;){if(10 <= runtime.caml_mul(k, j)) break; id[1]++;}
136+
var _b_ = j + 1 | 0;
137+
if(10 === j) break;
138+
var j = _b_;
139+
}
140+
var _a_ = k + 1 | 0;
141+
if(10 === k) return 0;
142+
var k = _a_;
146143
}
147144
}
148145
//end |}]
@@ -314,26 +311,25 @@ in loop x
314311
var x$1 = x;
315312
for(;;){
316313
if(0 === x$1) return 1;
317-
if(1 === x$1){
318-
var x$0 = 2;
319-
for(;;){
320-
a:
321-
{
322-
if(3 >= x$0 >>> 0)
323-
switch(x$0){
324-
case 0:
325-
var _a_ = 1; break a;
326-
case 2:
327-
var n = caml_call1(Stdlib_Random[5], 2), _a_ = n + n | 0; break a;
328-
case 3:
329-
var n$0 = caml_call1(Stdlib_Random[5], 2), x$0 = n$0; continue;
330-
}
331-
var _a_ = 2;
314+
if(1 === x$1) break;
315+
var x$2 = x$1 + 1 | 0, x$1 = x$2;
316+
}
317+
var x$0 = 2;
318+
for(;;){
319+
a:
320+
{
321+
if(3 >= x$0 >>> 0)
322+
switch(x$0){
323+
case 0:
324+
var _a_ = 1; break a;
325+
case 2:
326+
var n = caml_call1(Stdlib_Random[5], 2), _a_ = n + n | 0; break a;
327+
case 3:
328+
var n$0 = caml_call1(Stdlib_Random[5], 2), x$0 = n$0; continue;
332329
}
333-
return _a_ + 2 | 0;
334-
}
330+
var _a_ = 2;
335331
}
336-
var x$2 = x$1 + 1 | 0, x$1 = x$2;
332+
return _a_ + 2 | 0;
337333
}
338334
}
339335
//end |}]
@@ -455,42 +451,39 @@ let add_substitute =
455451
a:
456452
{
457453
if(40 !== opening && 123 !== opening){
458-
var
459-
start = start$0 + 1 | 0,
460-
lim$0 = caml_ml_string_length(s),
461-
i$2 = start;
462-
for(;;){
463-
b:
454+
var start = start$0 + 1 | 0, lim$0 = caml_ml_string_length(s);
455+
b:
456+
{
457+
c:
464458
{
465-
if(lim$0 > i$2){
466-
var match = caml_string_get(s, i$2);
467-
c:
468-
{
459+
d:
460+
{
461+
var i$2 = start;
462+
for(;;){
463+
if(lim$0 <= i$2) break c;
464+
var match = caml_string_get(s, i$2);
469465
if(91 <= match){
470466
if(97 <= match){
471-
if(123 > match) break c;
467+
if(123 <= match) break d;
472468
}
473-
else if(95 === match) break c;
469+
else if(95 !== match) break d;
474470
}
475471
else if(58 <= match){
476-
if(65 <= match) break c;
472+
if(65 > match) break;
477473
}
478-
else if(48 <= match) break c;
479-
var stop$0 = i$2;
480-
break b;
474+
else if(48 > match) break d;
475+
var i$3 = i$2 + 1 | 0, i$2 = i$3;
481476
}
482-
var i$3 = i$2 + 1 | 0, i$2 = i$3;
483-
continue;
484477
}
485-
var stop$0 = lim$0;
478+
var stop$0 = i$2;
479+
break b;
486480
}
487-
var
488-
match$0 =
489-
[0,
490-
caml_call3(string_sub, s, start$0, stop$0 - start$0 | 0),
491-
stop$0];
492-
break a;
481+
var stop$0 = lim$0;
493482
}
483+
var
484+
match$0 =
485+
[0, caml_call3(string_sub, s, start$0, stop$0 - start$0 | 0), stop$0];
486+
break a;
494487
}
495488
var new_start = start$0 + 1 | 0, k$2 = 0;
496489
if(40 === opening)
@@ -506,19 +499,17 @@ let add_substitute =
506499
if(caml_string_get(s, stop) === opening)
507500
var i = stop + 1 | 0, k$0 = k + 1 | 0, k = k$0, stop = i;
508501
else if(caml_string_get(s, stop) === closing){
509-
if(0 === k){
510-
var
511-
match$0 =
512-
[0,
513-
caml_call3(string_sub, s, new_start, (stop - start$0 | 0) - 1 | 0),
514-
stop + 1 | 0];
515-
break;
516-
}
502+
if(0 === k) break;
517503
var i$0 = stop + 1 | 0, k$1 = k - 1 | 0, k = k$1, stop = i$0;
518504
}
519505
else
520506
var i$1 = stop + 1 | 0, stop = i$1;
521507
}
508+
var
509+
match$0 =
510+
[0,
511+
caml_call3(string_sub, s, new_start, (stop - start$0 | 0) - 1 | 0),
512+
stop + 1 | 0];
522513
}
523514
var next_i = match$0[2], ident = match$0[1];
524515
caml_call2(add_string, b, caml_call1(f, ident));

0 commit comments

Comments
 (0)