OLD | NEW |
| (Empty) |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 import 'sexpr_unstringifier.dart'; | |
6 import "package:expect/expect.dart"; | |
7 import 'package:compiler/src/cps_ir/cps_ir_nodes.dart'; | |
8 import 'package:compiler/src/cps_ir/cps_ir_nodes_sexpr.dart'; | |
9 import 'package:compiler/src/cps_ir/optimizers.dart'; | |
10 | |
11 // The tests in this file that ensure shrinking reductions work as expected. | |
12 // Reductions and their corresponding names are taken from | |
13 // 'Compiling with Continuations, Continued' by Andrew Kennedy. | |
14 | |
15 // Basic dead-val: letprim x = V in K -> K (x not free in K). | |
16 // | |
17 // int main() { | |
18 // int i = 42; | |
19 // return 0; | |
20 // } | |
21 | |
22 String DEAD_VAL_IN = """ | |
23 (FunctionDefinition main () () return | |
24 (LetPrim (v0 (Constant (Int 42))) | |
25 (LetPrim (v1 (Constant (Int 0))) | |
26 (InvokeContinuation return (v1))))) | |
27 """; | |
28 String DEAD_VAL_OUT = """ | |
29 (FunctionDefinition main () () return | |
30 (LetPrim (v0 (Constant (Int 0))) | |
31 (InvokeContinuation return (v0)))) | |
32 """; | |
33 | |
34 // Iterative dead-val. No optimizations possible since the continuation to | |
35 // InvokeMethod must have one argument, even if it is unused. | |
36 // | |
37 // int main() { | |
38 // int i = 42; | |
39 // int j = i + 1; | |
40 // return 0; | |
41 // } | |
42 | |
43 String ITERATIVE_DEAD_VAL1_IN = """ | |
44 (FunctionDefinition main () () return | |
45 (LetPrim (v0 (Constant (Int 42))) | |
46 (LetPrim (v1 (Constant (Int 1))) | |
47 (LetCont ((k0 (v2) | |
48 (LetPrim (v3 (Constant (Int 0))) | |
49 (InvokeContinuation return (v3))))) | |
50 (InvokeMethod v0 + (v1) k0))))) | |
51 """; | |
52 String ITERATIVE_DEAD_VAL1_OUT = ITERATIVE_DEAD_VAL1_IN; | |
53 | |
54 // Iterative dead-val. IR written by hand. | |
55 | |
56 String ITERATIVE_DEAD_VAL2_IN = """ | |
57 (FunctionDefinition main () () return | |
58 (LetPrim (v0 (Constant (Int 42))) | |
59 (LetPrim (v1 | |
60 (CreateFunction | |
61 (FunctionDefinition f () (i) return | |
62 (InvokeContinuation return (v0))))) | |
63 (LetPrim (v2 (Constant (Int 0))) | |
64 (InvokeContinuation return (v2)))))) | |
65 """; | |
66 String ITERATIVE_DEAD_VAL2_OUT = """ | |
67 (FunctionDefinition main () () return | |
68 (LetPrim (v0 (Constant (Int 0))) | |
69 (InvokeContinuation return (v0)))) | |
70 """; | |
71 | |
72 // Basic dead-cont: letcont k x = L in K -> K (k not free in K). | |
73 // IR written by hand. | |
74 | |
75 String DEAD_CONT_IN = """ | |
76 (FunctionDefinition main () () return | |
77 (LetPrim (v4 (Constant (Int 0))) | |
78 (LetCont ((k0 (v0) | |
79 (InvokeConstructor List () return))) | |
80 (LetCont ((k1 (v1) | |
81 (LetCont ((k2 (v2) | |
82 (LetPrim (v3 (Constant (Int 0))) | |
83 (InvokeContinuation return (v3))))) | |
84 (InvokeStatic print (v4) k2)))) | |
85 (InvokeStatic print (v4) k1))))) | |
86 """; | |
87 String DEAD_CONT_OUT = """ | |
88 (FunctionDefinition main () () return | |
89 (LetPrim (v0 (Constant (Int 0))) | |
90 (LetCont ((k0 (v1) | |
91 (LetCont ((k1 (v2) | |
92 (LetPrim (v3 (Constant (Int 0))) | |
93 (InvokeContinuation return (v3))))) | |
94 (InvokeStatic print (v0) k1)))) | |
95 (InvokeStatic print (v0) k0)))) | |
96 """; | |
97 | |
98 // Iterative dead-cont. IR written by hand. | |
99 | |
100 String ITERATIVE_DEAD_CONT_IN = """ | |
101 (FunctionDefinition main () () return | |
102 (LetPrim (v4 (Constant (Int 0))) | |
103 (LetCont ((k0 (v0) | |
104 (InvokeConstructor List () return))) | |
105 (LetCont ((k3 (v5) | |
106 (InvokeContinuation k0 (v5)))) | |
107 (LetCont ((k1 (v1) | |
108 (LetCont ((k2 (v2) | |
109 (LetPrim (v3 (Constant (Int 0))) | |
110 (InvokeContinuation return (v3))))) | |
111 (InvokeStatic print (v4) k2)))) | |
112 (InvokeStatic print (v4) k1)))))) | |
113 """; | |
114 String ITERATIVE_DEAD_CONT_OUT = """ | |
115 (FunctionDefinition main () () return | |
116 (LetPrim (v0 (Constant (Int 0))) | |
117 (LetCont ((k0 (v1) | |
118 (LetCont ((k1 (v2) | |
119 (LetPrim (v3 (Constant (Int 0))) | |
120 (InvokeContinuation return (v3))))) | |
121 (InvokeStatic print (v0) k1)))) | |
122 (InvokeStatic print (v0) k0)))) | |
123 """; | |
124 | |
125 // Beta-cont-lin: letcont k x = K in C[k y] -> C[K[y/x]] (k not free in C). | |
126 // IR written by hand. | |
127 | |
128 String BETA_CONT_LIN_IN = """ | |
129 (FunctionDefinition main () () return | |
130 (LetCont ((k0 (v0) | |
131 (LetCont ((k1 (v1) | |
132 (LetCont ((k2 (v2) | |
133 (LetPrim (v3 (Constant (Int 0))) | |
134 (InvokeContinuation return (v3))))) | |
135 (InvokeStatic print (v0) k2)))) | |
136 (InvokeStatic print (v0) k1)))) | |
137 (LetPrim (v4 (Constant (Int 0))) | |
138 (InvokeContinuation k0 (v4))))) | |
139 """; | |
140 String BETA_CONT_LIN_OUT = """ | |
141 (FunctionDefinition main () () return | |
142 (LetPrim (v0 (Constant (Int 0))) | |
143 (LetCont ((k0 (v1) | |
144 (LetCont ((k1 (v2) | |
145 (LetPrim (v3 (Constant (Int 0))) | |
146 (InvokeContinuation return (v3))))) | |
147 (InvokeStatic print (v0) k1)))) | |
148 (InvokeStatic print (v0) k0)))) | |
149 """; | |
150 | |
151 // Beta-cont-lin with recursive continuation. IR written by hand. | |
152 | |
153 String RECURSIVE_BETA_CONT_LIN_IN = """ | |
154 (FunctionDefinition main () () return | |
155 (LetCont ((rec k0 (v0) | |
156 (InvokeContinuation rec k0 (v0)))) | |
157 (LetPrim (v1 (Constant (Int 0))) | |
158 (InvokeContinuation k0 (v1))))) | |
159 """; | |
160 String RECURSIVE_BETA_CONT_LIN_OUT = RECURSIVE_BETA_CONT_LIN_IN; | |
161 | |
162 // Beta-cont-lin used inside body. IR written by hand. | |
163 | |
164 String USED_BETA_CONT_LIN_IN = """ | |
165 (FunctionDefinition main () () return | |
166 (LetPrim (v0 (Constant (Int 0))) | |
167 (LetCont ((k0 (v1) | |
168 (LetCont ((k1 (v2) | |
169 (LetCont ((k2 (v3) | |
170 (LetPrim (v4 (Constant (Int 0))) | |
171 (InvokeContinuation return (v4))))) | |
172 (InvokeStatic print (v1) k2)))) | |
173 (InvokeStatic print (v1) k1)))) | |
174 (LetPrim (v5 | |
175 (CreateFunction | |
176 (FunctionDefinition f () () return | |
177 (InvokeContinuation return (v1))))) | |
178 (InvokeContinuation k0 (v0)))))) | |
179 """; | |
180 String USED_BETA_CONT_LIN_OUT = """ | |
181 (FunctionDefinition main () () return | |
182 (LetPrim (v0 (Constant (Int 0))) | |
183 (LetCont ((k0 (v1) | |
184 (LetCont ((k1 (v2) | |
185 (LetPrim (v3 (Constant (Int 0))) | |
186 (InvokeContinuation return (v3))))) | |
187 (InvokeStatic print (v0) k1)))) | |
188 (InvokeStatic print (v0) k0)))) | |
189 """; | |
190 | |
191 // Eta-cont: letcont k x = j x in K -> K[j/k]. | |
192 // IR written by hand. | |
193 // | |
194 // This test is incorrectly named: with the current implementation, there is no | |
195 // eta reduction. Instead, dead-parameter, beta-cont-lin, and dead-val | |
196 // reductions are performed, which in turn creates a second beta-cont-lin | |
197 // reduction. | |
198 // | |
199 // TODO(kmillikin): To test continuation eta reduction, use eta redexes that are | |
200 // not overlapping beta redexes. | |
201 String ETA_CONT_IN = """ | |
202 (FunctionDefinition main () () return | |
203 (LetPrim (v0 (Constant (Int 0))) | |
204 (LetCont ((rec k0 (v1) | |
205 (InvokeContinuation return (v0)))) | |
206 (LetCont ((k1 (v2) | |
207 (InvokeContinuation k0 (v2)))) | |
208 (LetPrim (v3 | |
209 (CreateFunction | |
210 (FunctionDefinition f () () return | |
211 (InvokeContinuation k0 (v0))))) | |
212 (InvokeContinuation k1 (v0))))))) | |
213 """; | |
214 String ETA_CONT_OUT = """ | |
215 (FunctionDefinition main () () return | |
216 (LetPrim (v0 (Constant (Int 0))) | |
217 (InvokeContinuation return (v0)))) | |
218 """; | |
219 | |
220 // Dead-parameter: | |
221 // letcont k x = E0 in E1 -> letcont k () = E0 in E1, | |
222 // if x does not occur free in E0. | |
223 | |
224 // Parameter v1 is unused in k0. | |
225 String DEAD_PARAMETER_IN = """ | |
226 (FunctionDefinition main () (x) return | |
227 (LetCont ((k0 (v0 v1 v2) | |
228 (InvokeStatic foo (v0 v2) return))) | |
229 (LetCont ((k1 () | |
230 (LetPrim (v3 (Constant (Int 0))) | |
231 (LetPrim (v4 (Constant (Int 1))) | |
232 (LetPrim (v5 (Constant (Int 2))) | |
233 (InvokeContinuation k0 (v3 v4 v5)))))) | |
234 (k2 () | |
235 (LetPrim (v6 (Constant (Int 3))) | |
236 (LetPrim (v7 (Constant (Int 4))) | |
237 (LetPrim (v8 (Constant (Int 5))) | |
238 (InvokeContinuation k0 (v6 v7 v8))))))) | |
239 (Branch (IsTrue x) k1 k2)))) | |
240 """; | |
241 String DEAD_PARAMETER_OUT = """ | |
242 (FunctionDefinition main () (x) return | |
243 (LetCont ((k0 (v0 v1) | |
244 (InvokeStatic foo (v0 v1) return))) | |
245 (LetCont ((k1 () | |
246 (LetPrim (v2 (Constant (Int 0))) | |
247 (LetPrim (v3 (Constant (Int 2))) | |
248 (InvokeContinuation k0 (v2 v3))))) | |
249 (k2 () | |
250 (LetPrim (v4 (Constant (Int 3))) | |
251 (LetPrim (v5 (Constant (Int 5))) | |
252 (InvokeContinuation k0 (v4 v5)))))) | |
253 (Branch (IsTrue x) k1 k2)))) | |
254 """; | |
255 | |
256 // Create an eta-cont redex: | |
257 // Dead parameter reductions can create an eta-cont redex by removing unused | |
258 // continuation parameters and thus creating the eta redex. | |
259 String CREATE_ETA_CONT_IN = """ | |
260 (FunctionDefinition main () (x) return | |
261 (LetCont ((rec loop (v0) | |
262 (InvokeContinuation rec loop (v0)))) | |
263 (LetCont ((created (v1 v2 v3) | |
264 (InvokeContinuation loop (v2)))) | |
265 (LetCont ((then () | |
266 (LetPrim (v4 (Constant (Int 0))) | |
267 (LetPrim (v5 (Constant (Int 1))) | |
268 (LetPrim (v6 (Constant (Int 2))) | |
269 (InvokeContinuation created (v4 v5 v6)))))) | |
270 (else () | |
271 (LetPrim (v6 (Constant (Int 3))) | |
272 (LetPrim (v7 (Constant (Int 4))) | |
273 (LetPrim (v8 (Constant (Int 5))) | |
274 (InvokeContinuation created (v6 v7 v8))))))) | |
275 (Branch (IsTrue x) then else))))) | |
276 """; | |
277 String CREATE_ETA_CONT_OUT = """ | |
278 (FunctionDefinition main () (x) return | |
279 (LetCont ((rec k0 (v0) | |
280 (InvokeContinuation rec k0 (v0)))) | |
281 (LetCont ((k1 () | |
282 (LetPrim (v1 (Constant (Int 1))) | |
283 (InvokeContinuation k0 (v1)))) | |
284 (k2 () | |
285 (LetPrim (v2 (Constant (Int 4))) | |
286 (InvokeContinuation k0 (v2))))) | |
287 (Branch (IsTrue x) k1 k2)))) | |
288 """; | |
289 | |
290 | |
291 | |
292 // Beta-fun-lin and eta-fun might not apply to us, since | |
293 // a. in (InvokeMethod v0 call k0), v0 might carry state, and | |
294 // b. there is no way to generate static nested functions that we could | |
295 // use InvokeStatic on. | |
296 | |
297 /// Normalizes whitespace by replacing all whitespace sequences by a single | |
298 /// space and trimming leading and trailing whitespace. | |
299 String normalizeSExpr(String input) { | |
300 return input.replaceAll(new RegExp(r'[ \n\t]+'), ' ').trim(); | |
301 } | |
302 | |
303 /// Parses the given input IR, runs an optimization pass over it, and compares | |
304 /// the stringification of the result against the expected output. | |
305 void testShrinkingReducer(String input, String expectedOutput) { | |
306 final unstringifier = new SExpressionUnstringifier(); | |
307 final stringifier = new SExpressionStringifier(); | |
308 final optimizer = new ShrinkingReducer(); | |
309 | |
310 FunctionDefinition f = unstringifier.unstringify(input); | |
311 optimizer.rewrite(f); | |
312 | |
313 String expected = normalizeSExpr(expectedOutput); | |
314 String actual = normalizeSExpr(stringifier.visit(f)); | |
315 | |
316 Expect.equals(expected, actual); | |
317 } | |
318 | |
319 void main() { | |
320 testShrinkingReducer(DEAD_VAL_IN, DEAD_VAL_OUT); | |
321 testShrinkingReducer(ITERATIVE_DEAD_VAL1_IN, ITERATIVE_DEAD_VAL1_OUT); | |
322 testShrinkingReducer(ITERATIVE_DEAD_VAL2_IN, ITERATIVE_DEAD_VAL2_OUT); | |
323 testShrinkingReducer(DEAD_CONT_IN, DEAD_CONT_OUT); | |
324 testShrinkingReducer(ITERATIVE_DEAD_CONT_IN, ITERATIVE_DEAD_CONT_OUT); | |
325 testShrinkingReducer(BETA_CONT_LIN_IN, BETA_CONT_LIN_OUT); | |
326 testShrinkingReducer(RECURSIVE_BETA_CONT_LIN_IN, RECURSIVE_BETA_CONT_LIN_OUT); | |
327 testShrinkingReducer(USED_BETA_CONT_LIN_IN, USED_BETA_CONT_LIN_OUT); | |
328 testShrinkingReducer(ETA_CONT_IN, ETA_CONT_OUT); | |
329 testShrinkingReducer(DEAD_PARAMETER_IN, DEAD_PARAMETER_OUT); | |
330 testShrinkingReducer(CREATE_ETA_CONT_IN, CREATE_ETA_CONT_OUT); | |
331 } | |
OLD | NEW |