Skip to content

Commit ef43141

Browse files
authored
feat(compiler): Lower stack usage (#1542)
1 parent a34d8b9 commit ef43141

File tree

11 files changed

+697
-449
lines changed

11 files changed

+697
-449
lines changed

compiler/src/codegen/transl_anf.re

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,8 @@ let compile_lambda =
580580
// of recursive functions to be garbage-collectible, since
581581
// Grain's garbage collector does not currently collect
582582
// cyclic reference chains)
583-
let used_var_set = Ident.Set.remove(id, Anf_utils.anf_free_vars(body));
583+
let used_var_set =
584+
Ident.Set.remove(id, Analyze_free_vars.anf_free_vars(body));
584585
let arg_vars = List.map(((arg, _)) => arg, args);
585586
let global_vars =
586587
Ident.fold_all((id, _, acc) => [id, ...acc], global_table^, []);

compiler/src/compile.re

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,8 +337,6 @@ let save_mashed = (f, outfile) =>
337337
| _ => failwith("Should be impossible")
338338
};
339339

340-
let free_vars = anfed => Ident.Set.elements @@ Anf_utils.anf_free_vars(anfed);
341-
342340
let report_error = loc =>
343341
Location.(
344342
Printf.(

compiler/src/middle_end/analyze_closure_scoped_vars.re

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ module CSVArg: Anf_iterator.IterArgument = {
1515
switch (desc) {
1616
| CLambda(_) =>
1717
closure_scoped_vars :=
18-
Ident.Set.union(closure_scoped_vars^, Anf_utils.comp_free_vars(c))
18+
Ident.Set.union(
19+
closure_scoped_vars^,
20+
Analyze_free_vars.comp_free_vars(c),
21+
)
1922
| _ => ()
2023
};
2124

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
open Anftree;
2+
open Anf_iterator;
3+
open Grain_typed;
4+
5+
type analysis +=
6+
| FreeVars(Ident.Set.t);
7+
8+
let rec get_free_vars = lst =>
9+
switch (lst) {
10+
| [] => None
11+
| [FreeVars(x), ..._] => Some(x)
12+
| [_, ...tl] => get_free_vars(tl)
13+
};
14+
15+
let imm_expression_free_vars = ({imm_analyses}) =>
16+
get_free_vars(imm_analyses^);
17+
18+
let comp_expression_free_vars = ({comp_analyses}) =>
19+
get_free_vars(comp_analyses^);
20+
let anf_expression_free_vars = ({anf_analyses}) =>
21+
get_free_vars(anf_analyses^);
22+
23+
/* Quick accessors for known-existing values */
24+
let imm_free_vars = c => Option.get(imm_expression_free_vars(c));
25+
let comp_free_vars = c => Option.get(comp_expression_free_vars(c));
26+
let anf_free_vars = a => Option.get(anf_expression_free_vars(a));
27+
28+
let push_free_vars = (lref, p) => lref := [FreeVars(p), ...lref^];
29+
30+
module FreeVarsArg: Anf_iterator.IterArgument = {
31+
include Anf_iterator.DefaultIterArgument;
32+
33+
let leave_imm_expression = ({imm_desc: desc, imm_analyses: analyses}) =>
34+
push_free_vars(analyses) @@
35+
(
36+
switch (desc) {
37+
| ImmId(x) => Ident.Set.singleton(x)
38+
| _ => Ident.Set.empty
39+
}
40+
);
41+
42+
let leave_comp_expression = ({comp_desc: desc, comp_analyses: analyses}) =>
43+
push_free_vars(analyses) @@
44+
(
45+
switch (desc) {
46+
| CLambda(_, args, (body, _)) =>
47+
Ident.Set.diff(
48+
anf_free_vars(body),
49+
Ident.Set.of_list(List.map(((arg, _)) => arg, args)),
50+
)
51+
| CIf(cond, thn, els) =>
52+
Ident.Set.union(imm_free_vars(cond)) @@
53+
Ident.Set.union(anf_free_vars(thn), anf_free_vars(els))
54+
| CFor(cond, inc, body) =>
55+
let cond =
56+
Option.fold(~none=Ident.Set.empty, ~some=anf_free_vars, cond);
57+
let inc =
58+
Option.fold(~none=Ident.Set.empty, ~some=anf_free_vars, inc);
59+
let body = anf_free_vars(body);
60+
Ident.Set.union(cond, Ident.Set.union(inc, body));
61+
| CContinue
62+
| CBreak => Ident.Set.empty
63+
| CSwitch(arg, branches, _) =>
64+
List.fold_left(
65+
(acc, (_, b)) => Ident.Set.union(anf_free_vars(b), acc),
66+
imm_free_vars(arg),
67+
branches,
68+
)
69+
| CPrim0(_) => Ident.Set.empty
70+
| CPrim1(_, arg) => imm_free_vars(arg)
71+
| CPrim2(_, arg1, arg2) =>
72+
Ident.Set.union(imm_free_vars(arg1), imm_free_vars(arg2))
73+
| CPrimN(_, args) =>
74+
List.fold_left(
75+
(acc, a) => Ident.Set.union(imm_free_vars(a), acc),
76+
Ident.Set.empty,
77+
args,
78+
)
79+
| CBoxAssign(arg1, arg2) =>
80+
Ident.Set.union(imm_free_vars(arg1), imm_free_vars(arg2))
81+
| CAssign(arg1, arg2) =>
82+
Ident.Set.union(imm_free_vars(arg1), imm_free_vars(arg2))
83+
| CLocalAssign(arg1, arg2) => imm_free_vars(arg2)
84+
| CApp((fn, _), args, _) =>
85+
List.fold_left(
86+
(acc, a) => Ident.Set.union(imm_free_vars(a), acc),
87+
imm_free_vars(fn),
88+
args,
89+
)
90+
| CAppBuiltin(_, _, args) =>
91+
List.fold_left(
92+
(acc, a) => Ident.Set.union(imm_free_vars(a), acc),
93+
Ident.Set.empty,
94+
args,
95+
)
96+
| CTuple(args)
97+
| CArray(args)
98+
| CAdt(_, _, args) =>
99+
List.fold_left(
100+
(acc, a) => Ident.Set.union(imm_free_vars(a), acc),
101+
Ident.Set.empty,
102+
args,
103+
)
104+
| CArrayGet(arg1, arg2) =>
105+
List.fold_left(
106+
(acc, a) => Ident.Set.union(imm_free_vars(a), acc),
107+
Ident.Set.empty,
108+
[arg1, arg2],
109+
)
110+
| CArraySet(arg1, arg2, arg3) =>
111+
List.fold_left(
112+
(acc, a) => Ident.Set.union(imm_free_vars(a), acc),
113+
Ident.Set.empty,
114+
[arg1, arg2, arg3],
115+
)
116+
| CRecord(_, args) =>
117+
List.fold_left(
118+
(acc, (_, a)) => Ident.Set.union(imm_free_vars(a), acc),
119+
Ident.Set.empty,
120+
args,
121+
)
122+
| CGetTupleItem(_, arg)
123+
| CGetAdtItem(_, arg)
124+
| CGetAdtTag(arg)
125+
| CGetRecordItem(_, arg) => imm_free_vars(arg)
126+
| CSetRecordItem(_, arg1, arg2)
127+
| CSetTupleItem(_, arg1, arg2) =>
128+
Ident.Set.union(imm_free_vars(arg1), imm_free_vars(arg2))
129+
| CNumber(_)
130+
| CInt32(_)
131+
| CInt64(_)
132+
| CFloat32(_)
133+
| CFloat64(_)
134+
| CBytes(_)
135+
| CString(_)
136+
| CChar(_) => Ident.Set.empty
137+
| CImmExpr(i) => imm_free_vars(i)
138+
}
139+
);
140+
141+
let leave_anf_expression = ({anf_desc: desc, anf_analyses: analyses}) =>
142+
push_free_vars(analyses) @@
143+
(
144+
switch (desc) {
145+
| AESeq(fst, rest) =>
146+
Ident.Set.union(comp_free_vars(fst), anf_free_vars(rest))
147+
| AEComp(c) => comp_free_vars(c)
148+
| AELet(_, recflag, _, binds, body) =>
149+
let bind_env =
150+
List.fold_left(
151+
(acc, (id, _)) => Ident.Set.add(id, acc),
152+
Ident.Set.empty,
153+
binds,
154+
);
155+
let free_in_binds =
156+
switch (recflag) {
157+
| Recursive =>
158+
List.fold_left(
159+
(acc, (_, bind_body)) =>
160+
Ident.Set.union(
161+
acc,
162+
Ident.Set.diff(comp_free_vars(bind_body), bind_env),
163+
),
164+
Ident.Set.empty,
165+
binds,
166+
)
167+
| Nonrecursive =>
168+
List.fold_left(
169+
(acc, (_, bind_body)) =>
170+
Ident.Set.union(acc, comp_free_vars(bind_body)),
171+
Ident.Set.empty,
172+
binds,
173+
)
174+
};
175+
Ident.Set.union(
176+
free_in_binds,
177+
Ident.Set.diff(anf_free_vars(body), bind_env),
178+
);
179+
}
180+
);
181+
};
182+
183+
module FreeVarsIterator = Anf_iterator.MakeIter(FreeVarsArg);
184+
185+
let analyze = anfprog => {
186+
FreeVarsIterator.iter_anf_program(anfprog);
187+
};
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
open Anftree;
2+
open Grain_typed;
3+
4+
let anf_free_vars: anf_expression => Ident.Set.t;
5+
let comp_free_vars: comp_expression => Ident.Set.t;
6+
7+
let analyze: Analysis_pass.t;

0 commit comments

Comments
 (0)