(* SIMPLIFICATION PASSES *) (* Order of simplifications : - cascade slices and selects - simplify stupid things (a xor 0 = a, a and 0 = 0, etc.) transform k = SLICE i i var into k = SELECT i var - transform k = SELECT 0 var into k = var when var is also one bit - look for variables with same equation, put the second to identity - eliminate k' for each equation k' = k - eliminate dead equations These simplifications are run on a topologically sorted list of equations (see main.ml) *) open Netlist_ast module Sset = Set.Make(String) (* Simplify cascade slicing/selecting *) let cascade_slices p = let slices = Hashtbl.create 42 in let eqs_new = List.map (fun (n, eq) -> (n, match eq with | Eslice(u, v, Avar(x)) -> let nu, nx = if Hashtbl.mem slices x then begin let ku, kx = Hashtbl.find slices x in (ku + u, kx) end else (u, x) in Hashtbl.add slices n (nu, nx); Eslice(nu, v, Avar(nx)) | Eselect(u, Avar(x)) -> begin try let ku, kx = Hashtbl.find slices x in Eselect(ku + u, Avar(kx)) with Not_found -> Eselect(u, Avar(x)) end | _ -> eq)) p.p_eqs in { p_eqs = eqs_new; p_inputs = p.p_inputs; p_outputs = p.p_outputs; p_vars = p.p_vars; } (* Simplifies some trivial arithmetic possibilites : a and 1 = a a and 0 = 0 a or 1 = 1 a or 0 = a a xor 0 = a slice i i x = select i x *) let arith_simplify p = { p_eqs = List.map (fun (n, eq) -> match eq with | Ebinop(Or, Aconst(VBit(false)), x) -> (n, Earg(x)) | Ebinop(Or, Aconst(VBit(true)), x) -> (n, Earg(Aconst(VBit(true)))) | Ebinop(Or, x, Aconst(VBit(false))) -> (n, Earg(x)) | Ebinop(Or, x, Aconst(VBit(true))) -> (n, Earg(Aconst(VBit(true)))) | Ebinop(And, Aconst(VBit(false)), x) -> (n, Earg(Aconst(VBit(false)))) | Ebinop(And, Aconst(VBit(true)), x) -> (n, Earg(x)) | Ebinop(And, x, Aconst(VBit(false))) -> (n, Earg(Aconst(VBit(false)))) | Ebinop(And, x, Aconst(VBit(true))) -> (n, Earg(x)) | Ebinop(Xor, Aconst(VBit(false)), x) -> (n, Earg(x)) | Ebinop(Xor, x, Aconst(VBit(false))) -> (n, Earg(x)) | Eslice(i, j, k) when i = j -> (n, Eselect(i, k)) | _ -> (n, eq)) p.p_eqs; p_inputs = p.p_inputs; p_outputs = p.p_outputs; p_vars = p.p_vars; } (* if x is one bit, then : select 0 x = x *) let select_to_id p = { p_eqs = List.map (fun (n, eq) -> match eq with | Eselect(0, Avar(id)) when Env.find id p.p_vars = TBit || Env.find id p.p_vars = TBitArray(1) -> (n, Earg(Avar(id))) | _ -> (n, eq)) p.p_eqs; p_inputs = p.p_inputs; p_outputs = p.p_outputs; p_vars = p.p_vars; } (* If a = eqn(v1, v2, ...) and b = eqn(v1, v2, ...) <- the same equation then say b = a *) let same_eq_simplify p = let id_outputs = (List.fold_left (fun x k -> Sset.add k x) Sset.empty p.p_outputs) in let eq_map = Hashtbl.create 42 in List.iter (fun (n, eq) -> if Sset.mem n id_outputs then Hashtbl.add eq_map eq n) p.p_eqs; let simplify_eq (n, eq) = if Sset.mem n id_outputs then (n, eq) else if Hashtbl.mem eq_map eq then (n, Earg(Avar(Hashtbl.find eq_map eq))) else begin Hashtbl.add eq_map eq n; (n, eq) end in let eq2 = List.map simplify_eq p.p_eqs in { p_eqs = eq2; p_inputs = p.p_inputs; p_outputs = p.p_outputs; p_vars = p.p_vars; } (* Replace one specific variable by another argument in the arguments of all equations (possibly a constant, possibly another variable) *) let eliminate_var var rep p = let rep_arg = function | Avar(i) when i = var -> rep | k -> k in let rep_eqs = List.map (fun (n, eq) -> (n, match eq with | Earg(a) -> Earg(rep_arg a) | Ereg(i) when i = var -> begin match rep with | Avar(j) -> Ereg(j) | Aconst(k) -> Earg(Aconst(k)) end | Ereg(j) -> Ereg(j) | Enot(a) -> Enot(rep_arg a) | Ebinop(o, a, b) -> Ebinop(o, rep_arg a, rep_arg b) | Emux(a, b, c) -> Emux(rep_arg a, rep_arg b, rep_arg c) | Erom(u, v, a) -> Erom(u, v, rep_arg a) | Eram(u, v, a, b, c, d) -> Eram(u, v, rep_arg a, rep_arg b, rep_arg c, rep_arg d) | Econcat(a, b) -> Econcat(rep_arg a, rep_arg b) | Eslice(u, v, a) -> Eslice(u, v, rep_arg a) | Eselect(u, a) -> Eselect(u, rep_arg a) )) p.p_eqs in { p_eqs = List.fold_left (fun x (n, eq) -> if n = var then x else (n, eq)::x) [] rep_eqs; p_inputs = p.p_inputs; p_outputs = p.p_outputs; p_vars = Env.remove var p.p_vars; } (* Remove all equations of type : a = b a = const (except if a is an output variable) *) let rec eliminate_id p = let id_outputs = (List.fold_left (fun x k -> Sset.add k x) Sset.empty p.p_outputs) in let rep = List.fold_left (fun x (n, eq) -> if x = None && (not (Sset.mem n id_outputs)) then match eq with | Earg(rarg) -> Some(n, rarg) | _ -> None else x) None p.p_eqs in match rep with | None -> p, false | Some(n, rep) -> fst (eliminate_id (eliminate_var n rep p)), true (* Eliminate dead equations *) let eliminate_dead p = p, false (* TODO *) (* a bit like a topological sort... *) (* Apply all the simplification passes, in the order given in the header of this file *) let rec simplify p = let p1 = cascade_slices p in let p2 = arith_simplify p1 in let p3 = select_to_id p2 in let p4 = same_eq_simplify p3 in let p5, use5 = eliminate_id p4 in let p6, use6 = eliminate_dead p5 in let pp = p6 in if use5 || use6 then simplify pp else pp