grin-compiler / grin

GRIN is a compiler back-end for lazy and strict functional languages with whole program optimization support.
https://grin-compiler.github.io/
1.03k stars 38 forks source link

SimpleDeadParameterElimination causes "undefined variable" errors #115

Open AlexandreTunstall opened 4 years ago

AlexandreTunstall commented 4 years ago

GRIN Version: 310fdc3a184353049213d28c84980345d1ff66fd (current master)

Save the following GRIN program in src.grin and then optimise it with grin src.grin --optimize.

grinMain =
  u.box <- pure (CUnit)
  u.thunk <- store u.box
  w.box <- pure (Ffoo u.thunk u.thunk)
  w.thunk <- store w.box
  foo $ w.thunk u.thunk

foo a.thunk b.thunk =
  (Ffoo c.thunk d.thunk) <- fetch a.thunk
  (CUnit) <- fetch d.thunk
  out.prim_int <- pure 0
  _prim_int_print $ out.prim_int

Optimisation will fail with output:

 PipelineStep: Optimize                                                                       PHASE #1
  PipelineStep: T BindNormalisation                                                           had effect: None (0.001351 ms)
  PipelineStep: T SimpleDeadFunctionElimination                                               had effect: ExpChanged (0.001667 ms)
  PipelineStep: SaveGrin (Rel "SimpleDeadFunctionElimination.grin")                           (0.311913 ms)
  PipelineStep: T SimpleDeadParameterElimination                                              had effect: ExpChanged (0.001111 ms)
  PipelineStep: SaveGrin (Rel "SimpleDeadParameterElimination.grin")                          (0.223380 ms)
 error after SimpleDeadParameterElimination:
undefined variable: d.thunk

illegal code

(Note: SimpleDeadFunctionElimination reports had effect: ExpChanged yet its output is identical to the original program.)

The SimpleDeadParameterElimination step eliminates b.thunk and d.thunk, but (CUnit) <- fetch d.thunk is left intact. Below is .output/002.SimpleDeadParameterElimination

grinMain =
  u.box <- pure (CUnit)
  u.thunk <- store u.box
  w.box <- pure (Ffoo u.thunk)
  w.thunk <- store w.box
  foo $ w.thunk

foo a.thunk =
  (Ffoo c.thunk) <- fetch a.thunk
  (CUnit) <- fetch d.thunk
  out.prim_int <- pure 0
  _prim_int_print $ out.prim_int

Linting src.grin with --lint shows that the program is correct, so this appears to be due to either a bug in the linter, or a bug in SimpleDeadParameterElimination.

This problem initially arose when I was trying to optimise a generated program (which is also correct according to the linter). That generated program is 282 lines long, so I opted to hand-write a minimal example instead.