| 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 |