|
|
@@ -0,0 +1,147 @@
|
|
|
+(**
|
|
|
+ * The compiler sometimes generates variables of the form foo$1, to make sure
|
|
|
+ * that expressions are only executed once. In many cases, this leads to
|
|
|
+ * over-complex constructions, for example when converting for-loops to
|
|
|
+ * while-loops. We use the knowledge of these variables being constant by
|
|
|
+ * propagation the constant values to their occurrences, and then apply
|
|
|
+ * arithmetic simplification to operators to reduce the size and complexity of
|
|
|
+ * the generated code. Note that this can only be applied to constants. For
|
|
|
+ * variables in general, some form of liveness analysis would be required (e.g.
|
|
|
+ * Static Single Assignment form). Expressions can only be propagated when they
|
|
|
+ * have no side effects, i.e. when they do not contain function calls.
|
|
|
+ *)
|
|
|
+open Ast
|
|
|
+open Util
|
|
|
+
|
|
|
+let is_const_name name =
|
|
|
+ Str.string_match (Str.regexp "[^\\$]+\\$\\$[0-9]+") name 0
|
|
|
+
|
|
|
+let is_const = function
|
|
|
+ | BoolConst _ | IntConst _ | FloatConst _ -> true
|
|
|
+ | _ -> false
|
|
|
+
|
|
|
+let eval_monop = function
|
|
|
+ | (Not, BoolConst (value, _), loc) -> BoolConst (not value, loc)
|
|
|
+ | (Neg, IntConst (value, _), loc) -> IntConst (-value, loc)
|
|
|
+ | (Neg, FloatConst (value, _), loc) -> FloatConst (-.value, loc)
|
|
|
+ | (op, opnd, loc) -> Monop (op, opnd, loc)
|
|
|
+
|
|
|
+let eval_binop = function
|
|
|
+ (* Arithmetic *)
|
|
|
+ | (Add, IntConst (left, _), IntConst (right, _), loc) ->
|
|
|
+ IntConst (left + right, loc)
|
|
|
+ | (Add, FloatConst (left, _), FloatConst (right, _), loc) ->
|
|
|
+ FloatConst (left +. right, loc)
|
|
|
+
|
|
|
+ | (Sub, IntConst (left, _), IntConst (right, _), loc) ->
|
|
|
+ IntConst (left - right, loc)
|
|
|
+ | (Sub, FloatConst (left, _), FloatConst (right, _), loc) ->
|
|
|
+ FloatConst (left -. right, loc)
|
|
|
+
|
|
|
+ | (Mul, IntConst (left, _), IntConst (right, _), loc) ->
|
|
|
+ IntConst (left * right, loc)
|
|
|
+ | (Mul, FloatConst (left, _), FloatConst (right, _), loc) ->
|
|
|
+ FloatConst (left *. right, loc)
|
|
|
+
|
|
|
+ | (Div, IntConst (left, _), IntConst (right, _), loc) ->
|
|
|
+ IntConst (left / right, loc)
|
|
|
+ | (Div, FloatConst (left, _), FloatConst (right, _), loc) ->
|
|
|
+ FloatConst (left /. right, loc)
|
|
|
+
|
|
|
+ | (Mod, IntConst (left, _), IntConst (right, _), loc) ->
|
|
|
+ IntConst (left mod right, loc)
|
|
|
+
|
|
|
+ (* Relational *)
|
|
|
+ | (Eq, IntConst (left, _), IntConst (right, _), loc) ->
|
|
|
+ BoolConst (left = right, loc)
|
|
|
+ | (Eq, FloatConst (left, _), FloatConst (right, _), loc) ->
|
|
|
+ BoolConst (left = right, loc)
|
|
|
+
|
|
|
+ | (Ne, IntConst (left, _), IntConst (right, _), loc) ->
|
|
|
+ BoolConst (left != right, loc)
|
|
|
+ | (Ne, FloatConst (left, _), FloatConst (right, _), loc) ->
|
|
|
+ BoolConst (left != right, loc)
|
|
|
+
|
|
|
+ | (Gt, IntConst (left, _), IntConst (right, _), loc) ->
|
|
|
+ BoolConst (left > right, loc)
|
|
|
+ | (Gt, FloatConst (left, _), FloatConst (right, _), loc) ->
|
|
|
+ BoolConst (left > right, loc)
|
|
|
+
|
|
|
+ | (Lt, IntConst (left, _), IntConst (right, _), loc) ->
|
|
|
+ BoolConst (left < right, loc)
|
|
|
+ | (Lt, FloatConst (left, _), FloatConst (right, _), loc) ->
|
|
|
+ BoolConst (left < right, loc)
|
|
|
+
|
|
|
+ | (Ge, IntConst (left, _), IntConst (right, _), loc) ->
|
|
|
+ BoolConst (left >= right, loc)
|
|
|
+ | (Ge, FloatConst (left, _), FloatConst (right, _), loc) ->
|
|
|
+ BoolConst (left >= right, loc)
|
|
|
+
|
|
|
+ | (Le, IntConst (left, _), IntConst (right, _), loc) ->
|
|
|
+ BoolConst (left <= right, loc)
|
|
|
+ | (Le, FloatConst (left, _), FloatConst (right, _), loc) ->
|
|
|
+ BoolConst (left <= right, loc)
|
|
|
+
|
|
|
+ (* Logical *)
|
|
|
+ | (And, BoolConst (left, _), BoolConst (right, _), loc) ->
|
|
|
+ BoolConst (left && right, loc)
|
|
|
+ | (Or, BoolConst (left, _), BoolConst (right, _), loc) ->
|
|
|
+ BoolConst (left || right, loc)
|
|
|
+
|
|
|
+ | (op, left, right, loc) -> Binop (op, left, right, loc)
|
|
|
+
|
|
|
+let rec propagate consts node =
|
|
|
+ let propagate = propagate consts in
|
|
|
+ match node with
|
|
|
+
|
|
|
+ (* Constant assignments are added to constants table *)
|
|
|
+ | Assign (name, None, value, loc) when is_const_name name ->
|
|
|
+ let value = propagate value in
|
|
|
+ if is_const value then (
|
|
|
+ Hashtbl.add consts name value;
|
|
|
+ DummyNode
|
|
|
+ ) else
|
|
|
+ Assign (name, None, value, loc)
|
|
|
+
|
|
|
+ (* Variables that are in the constant table are replaced with their constant
|
|
|
+ * value *)
|
|
|
+ | Var (name, loc) when Hashtbl.mem consts name ->
|
|
|
+ Hashtbl.find consts name
|
|
|
+
|
|
|
+ (* Apply arithmetic simplification to constant operands *)
|
|
|
+ | Monop (op, opnd, loc) ->
|
|
|
+ let opnd = propagate opnd in
|
|
|
+ if is_const opnd
|
|
|
+ then eval_monop (op, opnd, loc)
|
|
|
+ else Monop (op, opnd, loc)
|
|
|
+
|
|
|
+ | Binop (op, left, right, loc) ->
|
|
|
+ let left = propagate left in
|
|
|
+ let right = propagate right in
|
|
|
+ if is_const left && is_const right
|
|
|
+ then eval_binop (op, left, right, loc)
|
|
|
+ else Binop (op, left, right, loc)
|
|
|
+
|
|
|
+ | Cond (cond, texp, fexp, loc) ->
|
|
|
+ let cond = propagate cond in
|
|
|
+ let texp = propagate texp in
|
|
|
+ let fexp = propagate fexp in
|
|
|
+ (match cond with
|
|
|
+ | BoolConst (value, _) -> if value then texp else fexp
|
|
|
+ | _ -> Cond (cond, texp, fexp, loc)
|
|
|
+ )
|
|
|
+
|
|
|
+ | node -> transform_children propagate node
|
|
|
+
|
|
|
+let rec prune_vardecs consts = function
|
|
|
+ | VarDec (ctype, name, init, loc) when Hashtbl.mem consts name -> Block []
|
|
|
+ | node -> transform_children (prune_vardecs consts) node
|
|
|
+
|
|
|
+let rec phase input =
|
|
|
+ prerr_endline "- Constant propagation";
|
|
|
+ match input with
|
|
|
+ | Ast node ->
|
|
|
+ let consts = (Hashtbl.create 32) in
|
|
|
+ let node = propagate consts node in
|
|
|
+ Ast (prune_vardecs consts node)
|
|
|
+ | _ -> raise (InvalidInput "constant propagation")
|