Skip to content

Commit 42e128f

Browse files
committed
Compiler: exit loops early
1 parent 8d87bba commit 42e128f

File tree

4 files changed

+1321
-1262
lines changed

4 files changed

+1321
-1262
lines changed

compiler/lib/structure.ml

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@ 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 succs enter_pc (Addr.Set.add leave_pc (Hashtbl.find succs enter_pc));
99+
Hashtbl.replace preds leave_pc (Addr.Set.add enter_pc (Hashtbl.find preds leave_pc))));
100100
{ succs; preds; reverse_post_order = !l; block_order }
101101

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