constant_propagation.ml 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. (**
  2. * The compiler sometimes generates variables of the form foo$1, to make sure
  3. * that expressions are only executed once. In many cases, this leads to
  4. * over-complex constructions, for example when converting for-loops to
  5. * while-loops. We use the knowledge of these variables being constant by
  6. * propagation the constant values to their occurrences, and then apply
  7. * arithmetic simplification to operators to reduce the size and complexity of
  8. * the generated code. Note that this can only be applied to constants. For
  9. * variables in general, some form of liveness analysis would be required (e.g.
  10. * Static Single Assignment form). Expressions can only be propagated when they
  11. * have no side effects, i.e. when they do not contain function calls.
  12. *)
  13. open Ast
  14. open Util
  15. let is_const_name name =
  16. Str.string_match (Str.regexp "[^\\$]+\\$\\$[0-9]+") name 0
  17. let is_const = function
  18. | BoolConst _ | IntConst _ | FloatConst _ -> true
  19. | _ -> false
  20. let eval_monop = function
  21. | (Not, BoolConst (value, _), loc) -> BoolConst (not value, loc)
  22. | (Neg, IntConst (value, _), loc) -> IntConst (-value, loc)
  23. | (Neg, FloatConst (value, _), loc) -> FloatConst (-.value, loc)
  24. | (op, opnd, loc) -> Monop (op, opnd, loc)
  25. let eval_binop = function
  26. (* Arithmetic *)
  27. | (Add, IntConst (left, _), IntConst (right, _), loc) ->
  28. IntConst (left + right, loc)
  29. | (Add, FloatConst (left, _), FloatConst (right, _), loc) ->
  30. FloatConst (left +. right, loc)
  31. | (Sub, IntConst (left, _), IntConst (right, _), loc) ->
  32. IntConst (left - right, loc)
  33. | (Sub, FloatConst (left, _), FloatConst (right, _), loc) ->
  34. FloatConst (left -. right, loc)
  35. | (Mul, IntConst (left, _), IntConst (right, _), loc) ->
  36. IntConst (left * right, loc)
  37. | (Mul, FloatConst (left, _), FloatConst (right, _), loc) ->
  38. FloatConst (left *. right, loc)
  39. | (Div, IntConst (left, _), IntConst (right, _), loc) ->
  40. IntConst (left / right, loc)
  41. | (Div, FloatConst (left, _), FloatConst (right, _), loc) ->
  42. FloatConst (left /. right, loc)
  43. | (Mod, IntConst (left, _), IntConst (right, _), loc) ->
  44. IntConst (left mod right, loc)
  45. (* Relational *)
  46. | (Eq, IntConst (left, _), IntConst (right, _), loc) ->
  47. BoolConst (left = right, loc)
  48. | (Eq, FloatConst (left, _), FloatConst (right, _), loc) ->
  49. BoolConst (left = right, loc)
  50. | (Ne, IntConst (left, _), IntConst (right, _), loc) ->
  51. BoolConst (left != right, loc)
  52. | (Ne, FloatConst (left, _), FloatConst (right, _), loc) ->
  53. BoolConst (left != right, loc)
  54. | (Gt, IntConst (left, _), IntConst (right, _), loc) ->
  55. BoolConst (left > right, loc)
  56. | (Gt, FloatConst (left, _), FloatConst (right, _), loc) ->
  57. BoolConst (left > right, loc)
  58. | (Lt, IntConst (left, _), IntConst (right, _), loc) ->
  59. BoolConst (left < right, loc)
  60. | (Lt, FloatConst (left, _), FloatConst (right, _), loc) ->
  61. BoolConst (left < right, loc)
  62. | (Ge, IntConst (left, _), IntConst (right, _), loc) ->
  63. BoolConst (left >= right, loc)
  64. | (Ge, FloatConst (left, _), FloatConst (right, _), loc) ->
  65. BoolConst (left >= right, loc)
  66. | (Le, IntConst (left, _), IntConst (right, _), loc) ->
  67. BoolConst (left <= right, loc)
  68. | (Le, FloatConst (left, _), FloatConst (right, _), loc) ->
  69. BoolConst (left <= right, loc)
  70. (* Logical *)
  71. | (And, BoolConst (left, _), BoolConst (right, _), loc) ->
  72. BoolConst (left && right, loc)
  73. | (Or, BoolConst (left, _), BoolConst (right, _), loc) ->
  74. BoolConst (left || right, loc)
  75. | (op, left, right, loc) -> Binop (op, left, right, loc)
  76. let rec propagate consts node =
  77. let propagate = propagate consts in
  78. match node with
  79. (* Constant assignments are added to constants table *)
  80. | Assign (name, None, value, loc) when is_const_name name ->
  81. let value = propagate value in
  82. if is_const value then (
  83. Hashtbl.add consts name value;
  84. DummyNode
  85. ) else
  86. Assign (name, None, value, loc)
  87. (* Variables that are in the constant table are replaced with their constant
  88. * value *)
  89. | Var (name, loc) when Hashtbl.mem consts name ->
  90. Hashtbl.find consts name
  91. (* Apply arithmetic simplification to constant operands *)
  92. | Monop (op, opnd, loc) ->
  93. let opnd = propagate opnd in
  94. if is_const opnd
  95. then eval_monop (op, opnd, loc)
  96. else Monop (op, opnd, loc)
  97. | Binop (op, left, right, loc) ->
  98. let left = propagate left in
  99. let right = propagate right in
  100. if is_const left && is_const right
  101. then eval_binop (op, left, right, loc)
  102. else Binop (op, left, right, loc)
  103. | Cond (cond, texp, fexp, loc) ->
  104. let cond = propagate cond in
  105. let texp = propagate texp in
  106. let fexp = propagate fexp in
  107. (match cond with
  108. | BoolConst (value, _) -> if value then texp else fexp
  109. | _ -> Cond (cond, texp, fexp, loc)
  110. )
  111. | node -> transform_children propagate node
  112. let rec prune_vardecs consts = function
  113. | VarDec (ctype, name, init, loc) when Hashtbl.mem consts name -> Block []
  114. | node -> transform_children (prune_vardecs consts) node
  115. let rec phase input =
  116. prerr_endline "- Constant propagation";
  117. match input with
  118. | Ast node ->
  119. let consts = (Hashtbl.create 32) in
  120. let node = propagate consts node in
  121. Ast (prune_vardecs consts node)
  122. | _ -> raise (InvalidInput "constant propagation")