Chris@10: (* Chris@10: * Copyright (c) 1997-1999 Massachusetts Institute of Technology Chris@10: * Copyright (c) 2003, 2007-11 Matteo Frigo Chris@10: * Copyright (c) 2003, 2007-11 Massachusetts Institute of Technology Chris@10: * Chris@10: * This program is free software; you can redistribute it and/or modify Chris@10: * it under the terms of the GNU General Public License as published by Chris@10: * the Free Software Foundation; either version 2 of the License, or Chris@10: * (at your option) any later version. Chris@10: * Chris@10: * This program is distributed in the hope that it will be useful, Chris@10: * but WITHOUT ANY WARRANTY; without even the implied warranty of Chris@10: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Chris@10: * GNU General Public License for more details. Chris@10: * Chris@10: * You should have received a copy of the GNU General Public License Chris@10: * along with this program; if not, write to the Free Software Chris@10: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Chris@10: * Chris@10: *) Chris@10: Chris@10: Chris@10: open Util Chris@10: open Expr Chris@10: Chris@10: let node_insert x = Assoctable.insert Expr.hash x Chris@10: let node_lookup x = Assoctable.lookup Expr.hash (==) x Chris@10: Chris@10: (************************************************************* Chris@10: * Algebraic simplifier/elimination of common subexpressions Chris@10: *************************************************************) Chris@10: module AlgSimp : sig Chris@10: val algsimp : expr list -> expr list Chris@10: end = struct Chris@10: Chris@10: open Monads.StateMonad Chris@10: open Monads.MemoMonad Chris@10: open Assoctable Chris@10: Chris@10: let fetchSimp = Chris@10: fetchState >>= fun (s, _) -> returnM s Chris@10: let storeSimp s = Chris@10: fetchState >>= (fun (_, c) -> storeState (s, c)) Chris@10: let lookupSimpM key = Chris@10: fetchSimp >>= fun table -> Chris@10: returnM (node_lookup key table) Chris@10: let insertSimpM key value = Chris@10: fetchSimp >>= fun table -> Chris@10: storeSimp (node_insert key value table) Chris@10: Chris@10: let subset a b = Chris@10: List.for_all (fun x -> List.exists (fun y -> x == y) b) a Chris@10: Chris@10: let structurallyEqualCSE a b = Chris@10: match (a, b) with Chris@10: | (Num a, Num b) -> Number.equal a b Chris@10: | (NaN a, NaN b) -> a == b Chris@10: | (Load a, Load b) -> Variable.same a b Chris@10: | (Times (a, a'), Times (b, b')) -> Chris@10: ((a == b) && (a' == b')) or Chris@10: ((a == b') && (a' == b)) Chris@10: | (CTimes (a, a'), CTimes (b, b')) -> Chris@10: ((a == b) && (a' == b')) or Chris@10: ((a == b') && (a' == b)) Chris@10: | (CTimesJ (a, a'), CTimesJ (b, b')) -> ((a == b) && (a' == b')) Chris@10: | (Plus a, Plus b) -> subset a b && subset b a Chris@10: | (Uminus a, Uminus b) -> (a == b) Chris@10: | _ -> false Chris@10: Chris@10: let hashCSE x = Chris@10: if (!Magic.randomized_cse) then Chris@10: Oracle.hash x Chris@10: else Chris@10: Expr.hash x Chris@10: Chris@10: let equalCSE a b = Chris@10: if (!Magic.randomized_cse) then Chris@10: (structurallyEqualCSE a b || Oracle.likely_equal a b) Chris@10: else Chris@10: structurallyEqualCSE a b Chris@10: Chris@10: let fetchCSE = Chris@10: fetchState >>= fun (_, c) -> returnM c Chris@10: let storeCSE c = Chris@10: fetchState >>= (fun (s, _) -> storeState (s, c)) Chris@10: let lookupCSEM key = Chris@10: fetchCSE >>= fun table -> Chris@10: returnM (Assoctable.lookup hashCSE equalCSE key table) Chris@10: let insertCSEM key value = Chris@10: fetchCSE >>= fun table -> Chris@10: storeCSE (Assoctable.insert hashCSE key value table) Chris@10: Chris@10: (* memoize both x and Uminus x (unless x is already negated) *) Chris@10: let identityM x = Chris@10: let memo x = memoizing lookupCSEM insertCSEM returnM x in Chris@10: match x with Chris@10: Uminus _ -> memo x Chris@10: | _ -> memo x >>= fun x' -> memo (Uminus x') >> returnM x' Chris@10: Chris@10: let makeNode = identityM Chris@10: Chris@10: (* simplifiers for various kinds of nodes *) Chris@10: let rec snumM = function Chris@10: n when Number.is_zero n -> Chris@10: makeNode (Num (Number.zero)) Chris@10: | n when Number.negative n -> Chris@10: makeNode (Num (Number.negate n)) >>= suminusM Chris@10: | n -> makeNode (Num n) Chris@10: Chris@10: and suminusM = function Chris@10: Uminus x -> makeNode x Chris@10: | Num a when (Number.is_zero a) -> snumM Number.zero Chris@10: | a -> makeNode (Uminus a) Chris@10: Chris@10: and stimesM = function Chris@10: | (Uminus a, b) -> stimesM (a, b) >>= suminusM Chris@10: | (a, Uminus b) -> stimesM (a, b) >>= suminusM Chris@10: | (NaN I, CTimes (a, b)) -> stimesM (NaN I, b) >>= Chris@10: fun ib -> sctimesM (a, ib) Chris@10: | (NaN I, CTimesJ (a, b)) -> stimesM (NaN I, b) >>= Chris@10: fun ib -> sctimesjM (a, ib) Chris@10: | (Num a, Num b) -> snumM (Number.mul a b) Chris@10: | (Num a, Times (Num b, c)) -> Chris@10: snumM (Number.mul a b) >>= fun x -> stimesM (x, c) Chris@10: | (Num a, b) when Number.is_zero a -> snumM Number.zero Chris@10: | (Num a, b) when Number.is_one a -> makeNode b Chris@10: | (Num a, b) when Number.is_mone a -> suminusM b Chris@10: | (a, b) when is_known_constant b && not (is_known_constant a) -> Chris@10: stimesM (b, a) Chris@10: | (a, b) -> makeNode (Times (a, b)) Chris@10: Chris@10: and sctimesM = function Chris@10: | (Uminus a, b) -> sctimesM (a, b) >>= suminusM Chris@10: | (a, Uminus b) -> sctimesM (a, b) >>= suminusM Chris@10: | (a, b) -> makeNode (CTimes (a, b)) Chris@10: Chris@10: and sctimesjM = function Chris@10: | (Uminus a, b) -> sctimesjM (a, b) >>= suminusM Chris@10: | (a, Uminus b) -> sctimesjM (a, b) >>= suminusM Chris@10: | (a, b) -> makeNode (CTimesJ (a, b)) Chris@10: Chris@10: and reduce_sumM x = match x with Chris@10: [] -> returnM [] Chris@10: | [Num a] -> Chris@10: if (Number.is_zero a) then Chris@10: returnM [] Chris@10: else returnM x Chris@10: | [Uminus (Num a)] -> Chris@10: if (Number.is_zero a) then Chris@10: returnM [] Chris@10: else returnM x Chris@10: | (Num a) :: (Num b) :: s -> Chris@10: snumM (Number.add a b) >>= fun x -> Chris@10: reduce_sumM (x :: s) Chris@10: | (Num a) :: (Uminus (Num b)) :: s -> Chris@10: snumM (Number.sub a b) >>= fun x -> Chris@10: reduce_sumM (x :: s) Chris@10: | (Uminus (Num a)) :: (Num b) :: s -> Chris@10: snumM (Number.sub b a) >>= fun x -> Chris@10: reduce_sumM (x :: s) Chris@10: | (Uminus (Num a)) :: (Uminus (Num b)) :: s -> Chris@10: snumM (Number.add a b) >>= Chris@10: suminusM >>= fun x -> Chris@10: reduce_sumM (x :: s) Chris@10: | ((Num _) as a) :: b :: s -> reduce_sumM (b :: a :: s) Chris@10: | ((Uminus (Num _)) as a) :: b :: s -> reduce_sumM (b :: a :: s) Chris@10: | a :: s -> Chris@10: reduce_sumM s >>= fun s' -> returnM (a :: s') Chris@10: Chris@10: and collectible1 = function Chris@10: | NaN _ -> false Chris@10: | Uminus x -> collectible1 x Chris@10: | _ -> true Chris@10: and collectible (a, b) = collectible1 a Chris@10: Chris@10: (* collect common factors: ax + bx -> (a+b)x *) Chris@10: and collectM which x = Chris@10: let rec findCoeffM which = function Chris@10: | Times (a, b) when collectible (which (a, b)) -> returnM (which (a, b)) Chris@10: | Uminus x -> Chris@10: findCoeffM which x >>= fun (coeff, b) -> Chris@10: suminusM coeff >>= fun mcoeff -> Chris@10: returnM (mcoeff, b) Chris@10: | x -> snumM Number.one >>= fun one -> returnM (one, x) Chris@10: and separateM xpr = function Chris@10: [] -> returnM ([], []) Chris@10: | a :: b -> Chris@10: separateM xpr b >>= fun (w, wo) -> Chris@10: (* try first factor *) Chris@10: findCoeffM (fun (a, b) -> (a, b)) a >>= fun (c, x) -> Chris@10: if (xpr == x) && collectible (c, x) then returnM (c :: w, wo) Chris@10: else Chris@10: (* try second factor *) Chris@10: findCoeffM (fun (a, b) -> (b, a)) a >>= fun (c, x) -> Chris@10: if (xpr == x) && collectible (c, x) then returnM (c :: w, wo) Chris@10: else returnM (w, a :: wo) Chris@10: in match x with Chris@10: [] -> returnM x Chris@10: | [a] -> returnM x Chris@10: | a :: b -> Chris@10: findCoeffM which a >>= fun (_, xpr) -> Chris@10: separateM xpr x >>= fun (w, wo) -> Chris@10: collectM which wo >>= fun wo' -> Chris@10: splusM w >>= fun w' -> Chris@10: stimesM (w', xpr) >>= fun t' -> Chris@10: returnM (t':: wo') Chris@10: Chris@10: and mangleSumM x = returnM x Chris@10: >>= reduce_sumM Chris@10: >>= collectM (fun (a, b) -> (a, b)) Chris@10: >>= collectM (fun (a, b) -> (b, a)) Chris@10: >>= reduce_sumM Chris@10: >>= deepCollectM !Magic.deep_collect_depth Chris@10: >>= reduce_sumM Chris@10: Chris@10: and reorder_uminus = function (* push all Uminuses to the end *) Chris@10: [] -> [] Chris@10: | ((Uminus _) as a' :: b) -> (reorder_uminus b) @ [a'] Chris@10: | (a :: b) -> a :: (reorder_uminus b) Chris@10: Chris@10: and canonicalizeM = function Chris@10: [] -> snumM Number.zero Chris@10: | [a] -> makeNode a (* one term *) Chris@10: | a -> generateFusedMultAddM (reorder_uminus a) Chris@10: Chris@10: and generateFusedMultAddM = Chris@10: let rec is_multiplication = function Chris@10: | Times (Num a, b) -> true Chris@10: | Uminus (Times (Num a, b)) -> true Chris@10: | _ -> false Chris@10: and separate = function Chris@10: [] -> ([], [], Number.zero) Chris@10: | (Times (Num a, b)) as this :: c -> Chris@10: let (x, y, max) = separate c in Chris@10: let newmax = if (Number.greater a max) then a else max in Chris@10: (this :: x, y, newmax) Chris@10: | (Uminus (Times (Num a, b))) as this :: c -> Chris@10: let (x, y, max) = separate c in Chris@10: let newmax = if (Number.greater a max) then a else max in Chris@10: (this :: x, y, newmax) Chris@10: | this :: c -> Chris@10: let (x, y, max) = separate c in Chris@10: (x, this :: y, max) Chris@10: in fun l -> Chris@10: if !Magic.enable_fma && count is_multiplication l >= 2 then Chris@10: let (w, wo, max) = separate l in Chris@10: snumM (Number.div Number.one max) >>= fun invmax' -> Chris@10: snumM max >>= fun max' -> Chris@10: mapM (fun x -> stimesM (invmax', x)) w >>= splusM >>= fun pw' -> Chris@10: stimesM (max', pw') >>= fun mw' -> Chris@10: splusM (wo @ [mw']) Chris@10: else Chris@10: makeNode (Plus l) Chris@10: Chris@10: Chris@10: and negative = function Chris@10: Uminus _ -> true Chris@10: | _ -> false Chris@10: Chris@10: (* Chris@10: * simplify patterns of the form Chris@10: * Chris@10: * ((c_1 * a + ...) + ...) + (c_2 * a + ...) Chris@10: * Chris@10: * The pattern includes arbitrary coefficients and minus signs. Chris@10: * A common case of this pattern is the butterfly Chris@10: * (a + b) + (a - b) Chris@10: * (a + b) - (a - b) Chris@10: *) Chris@10: (* this whole procedure needs much more thought *) Chris@10: and deepCollectM maxdepth l = Chris@10: let rec findTerms depth x = match x with Chris@10: | Uminus x -> findTerms depth x Chris@10: | Times (Num _, b) -> (findTerms (depth - 1) b) Chris@10: | Plus l when depth > 0 -> Chris@10: x :: List.flatten (List.map (findTerms (depth - 1)) l) Chris@10: | x -> [x] Chris@10: and duplicates = function Chris@10: [] -> [] Chris@10: | a :: b -> if List.memq a b then a :: duplicates b Chris@10: else duplicates b Chris@10: Chris@10: in let rec splitDuplicates depth d x = Chris@10: if (List.memq x d) then Chris@10: snumM (Number.zero) >>= fun zero -> Chris@10: returnM (zero, x) Chris@10: else match x with Chris@10: | Times (a, b) -> Chris@10: splitDuplicates (depth - 1) d a >>= fun (a', xa) -> Chris@10: splitDuplicates (depth - 1) d b >>= fun (b', xb) -> Chris@10: stimesM (a', b') >>= fun ab -> Chris@10: stimesM (a, xb) >>= fun xb' -> Chris@10: stimesM (xa, b) >>= fun xa' -> Chris@10: stimesM (xa, xb) >>= fun xab -> Chris@10: splusM [xa'; xb'; xab] >>= fun x -> Chris@10: returnM (ab, x) Chris@10: | Uminus a -> Chris@10: splitDuplicates depth d a >>= fun (x, y) -> Chris@10: suminusM x >>= fun ux -> Chris@10: suminusM y >>= fun uy -> Chris@10: returnM (ux, uy) Chris@10: | Plus l when depth > 0 -> Chris@10: mapM (splitDuplicates (depth - 1) d) l >>= fun ld -> Chris@10: let (l', d') = List.split ld in Chris@10: splusM l' >>= fun p -> Chris@10: splusM d' >>= fun d'' -> Chris@10: returnM (p, d'') Chris@10: | x -> Chris@10: snumM (Number.zero) >>= fun zero' -> Chris@10: returnM (x, zero') Chris@10: Chris@10: in let l' = List.flatten (List.map (findTerms maxdepth) l) Chris@10: in match duplicates l' with Chris@10: | [] -> returnM l Chris@10: | d -> Chris@10: mapM (splitDuplicates maxdepth d) l >>= fun ld -> Chris@10: let (l', d') = List.split ld in Chris@10: splusM l' >>= fun l'' -> Chris@10: let rec flattenPlusM = function Chris@10: | Plus l -> returnM l Chris@10: | Uminus x -> Chris@10: flattenPlusM x >>= mapM suminusM Chris@10: | x -> returnM [x] Chris@10: in Chris@10: mapM flattenPlusM d' >>= fun d'' -> Chris@10: splusM (List.flatten d'') >>= fun d''' -> Chris@10: mangleSumM [l''; d'''] Chris@10: Chris@10: and splusM l = Chris@10: let fma_heuristics x = Chris@10: if !Magic.enable_fma then Chris@10: match x with Chris@10: | [Uminus (Times _); Times _] -> Some false Chris@10: | [Times _; Uminus (Times _)] -> Some false Chris@10: | [Uminus (_); Times _] -> Some true Chris@10: | [Times _; Uminus (Plus _)] -> Some true Chris@10: | [_; Uminus (Times _)] -> Some false Chris@10: | [Uminus (Times _); _] -> Some false Chris@10: | _ -> None Chris@10: else Chris@10: None Chris@10: in Chris@10: mangleSumM l >>= fun l' -> Chris@10: (* no terms are negative. Don't do anything *) Chris@10: if not (List.exists negative l') then Chris@10: canonicalizeM l' Chris@10: (* all terms are negative. Negate them all and collect the minus sign *) Chris@10: else if List.for_all negative l' then Chris@10: mapM suminusM l' >>= splusM >>= suminusM Chris@10: else match fma_heuristics l' with Chris@10: | Some true -> mapM suminusM l' >>= splusM >>= suminusM Chris@10: | Some false -> canonicalizeM l' Chris@10: | None -> Chris@10: (* Ask the Oracle for the canonical form *) Chris@10: if (not !Magic.randomized_cse) && Chris@10: Oracle.should_flip_sign (Plus l') then Chris@10: mapM suminusM l' >>= splusM >>= suminusM Chris@10: else Chris@10: canonicalizeM l' Chris@10: Chris@10: (* monadic style algebraic simplifier for the dag *) Chris@10: let rec algsimpM x = Chris@10: memoizing lookupSimpM insertSimpM Chris@10: (function Chris@10: | Num a -> snumM a Chris@10: | NaN _ as x -> makeNode x Chris@10: | Plus a -> Chris@10: mapM algsimpM a >>= splusM Chris@10: | Times (a, b) -> Chris@10: (algsimpM a >>= fun a' -> Chris@10: algsimpM b >>= fun b' -> Chris@10: stimesM (a', b')) Chris@10: | CTimes (a, b) -> Chris@10: (algsimpM a >>= fun a' -> Chris@10: algsimpM b >>= fun b' -> Chris@10: sctimesM (a', b')) Chris@10: | CTimesJ (a, b) -> Chris@10: (algsimpM a >>= fun a' -> Chris@10: algsimpM b >>= fun b' -> Chris@10: sctimesjM (a', b')) Chris@10: | Uminus a -> Chris@10: algsimpM a >>= suminusM Chris@10: | Store (v, a) -> Chris@10: algsimpM a >>= fun a' -> Chris@10: makeNode (Store (v, a')) Chris@10: | Load _ as x -> makeNode x) Chris@10: x Chris@10: Chris@10: let initialTable = (empty, empty) Chris@10: let simp_roots = mapM algsimpM Chris@10: let algsimp = runM initialTable simp_roots Chris@10: end Chris@10: Chris@10: (************************************************************* Chris@10: * Network transposition algorithm Chris@10: *************************************************************) Chris@10: module Transpose = struct Chris@10: open Monads.StateMonad Chris@10: open Monads.MemoMonad Chris@10: open Littlesimp Chris@10: Chris@10: let fetchDuals = fetchState Chris@10: let storeDuals = storeState Chris@10: Chris@10: let lookupDualsM key = Chris@10: fetchDuals >>= fun table -> Chris@10: returnM (node_lookup key table) Chris@10: Chris@10: let insertDualsM key value = Chris@10: fetchDuals >>= fun table -> Chris@10: storeDuals (node_insert key value table) Chris@10: Chris@10: let rec visit visited vtable parent_table = function Chris@10: [] -> (visited, parent_table) Chris@10: | node :: rest -> Chris@10: match node_lookup node vtable with Chris@10: | Some _ -> visit visited vtable parent_table rest Chris@10: | None -> Chris@10: let children = match node with Chris@10: | Store (v, n) -> [n] Chris@10: | Plus l -> l Chris@10: | Times (a, b) -> [a; b] Chris@10: | CTimes (a, b) -> [a; b] Chris@10: | CTimesJ (a, b) -> [a; b] Chris@10: | Uminus x -> [x] Chris@10: | _ -> [] Chris@10: in let rec loop t = function Chris@10: [] -> t Chris@10: | a :: rest -> Chris@10: (match node_lookup a t with Chris@10: None -> loop (node_insert a [node] t) rest Chris@10: | Some c -> loop (node_insert a (node :: c) t) rest) Chris@10: in Chris@10: (visit Chris@10: (node :: visited) Chris@10: (node_insert node () vtable) Chris@10: (loop parent_table children) Chris@10: (children @ rest)) Chris@10: Chris@10: let make_transposer parent_table = Chris@10: let rec termM node candidate_parent = Chris@10: match candidate_parent with Chris@10: | Store (_, n) when n == node -> Chris@10: dualM candidate_parent >>= fun x' -> returnM [x'] Chris@10: | Plus (l) when List.memq node l -> Chris@10: dualM candidate_parent >>= fun x' -> returnM [x'] Chris@10: | Times (a, b) when b == node -> Chris@10: dualM candidate_parent >>= fun x' -> Chris@10: returnM [makeTimes (a, x')] Chris@10: | CTimes (a, b) when b == node -> Chris@10: dualM candidate_parent >>= fun x' -> Chris@10: returnM [CTimes (a, x')] Chris@10: | CTimesJ (a, b) when b == node -> Chris@10: dualM candidate_parent >>= fun x' -> Chris@10: returnM [CTimesJ (a, x')] Chris@10: | Uminus n when n == node -> Chris@10: dualM candidate_parent >>= fun x' -> Chris@10: returnM [makeUminus x'] Chris@10: | _ -> returnM [] Chris@10: Chris@10: and dualExpressionM this_node = Chris@10: mapM (termM this_node) Chris@10: (match node_lookup this_node parent_table with Chris@10: | Some a -> a Chris@10: | None -> failwith "bug in dualExpressionM" Chris@10: ) >>= fun l -> Chris@10: returnM (makePlus (List.flatten l)) Chris@10: Chris@10: and dualM this_node = Chris@10: memoizing lookupDualsM insertDualsM Chris@10: (function Chris@10: | Load v as x -> Chris@10: if (Variable.is_constant v) then Chris@10: returnM (Load v) Chris@10: else Chris@10: (dualExpressionM x >>= fun d -> Chris@10: returnM (Store (v, d))) Chris@10: | Store (v, x) -> returnM (Load v) Chris@10: | x -> dualExpressionM x) Chris@10: this_node Chris@10: Chris@10: in dualM Chris@10: Chris@10: let is_store = function Chris@10: | Store _ -> true Chris@10: | _ -> false Chris@10: Chris@10: let transpose dag = Chris@10: let _ = Util.info "begin transpose" in Chris@10: let (all_nodes, parent_table) = Chris@10: visit [] Assoctable.empty Assoctable.empty dag in Chris@10: let transposerM = make_transposer parent_table in Chris@10: let mapTransposerM = mapM transposerM in Chris@10: let duals = runM Assoctable.empty mapTransposerM all_nodes in Chris@10: let roots = List.filter is_store duals in Chris@10: let _ = Util.info "end transpose" in Chris@10: roots Chris@10: end Chris@10: Chris@10: Chris@10: (************************************************************* Chris@10: * Various dag statistics Chris@10: *************************************************************) Chris@10: module Stats : sig Chris@10: type complexity Chris@10: val complexity : Expr.expr list -> complexity Chris@10: val same_complexity : complexity -> complexity -> bool Chris@10: val leq_complexity : complexity -> complexity -> bool Chris@10: val to_string : complexity -> string Chris@10: end = struct Chris@10: type complexity = int * int * int * int * int * int Chris@10: let rec visit visited vtable = function Chris@10: [] -> visited Chris@10: | node :: rest -> Chris@10: match node_lookup node vtable with Chris@10: Some _ -> visit visited vtable rest Chris@10: | None -> Chris@10: let children = match node with Chris@10: Store (v, n) -> [n] Chris@10: | Plus l -> l Chris@10: | Times (a, b) -> [a; b] Chris@10: | Uminus x -> [x] Chris@10: | _ -> [] Chris@10: in visit (node :: visited) Chris@10: (node_insert node () vtable) Chris@10: (children @ rest) Chris@10: Chris@10: let complexity dag = Chris@10: let rec loop (load, store, plus, times, uminus, num) = function Chris@10: [] -> (load, store, plus, times, uminus, num) Chris@10: | node :: rest -> Chris@10: loop Chris@10: (match node with Chris@10: | Load _ -> (load + 1, store, plus, times, uminus, num) Chris@10: | Store _ -> (load, store + 1, plus, times, uminus, num) Chris@10: | Plus x -> (load, store, plus + (List.length x - 1), times, uminus, num) Chris@10: | Times _ -> (load, store, plus, times + 1, uminus, num) Chris@10: | Uminus _ -> (load, store, plus, times, uminus + 1, num) Chris@10: | Num _ -> (load, store, plus, times, uminus, num + 1) Chris@10: | CTimes _ -> (load, store, plus, times, uminus, num) Chris@10: | CTimesJ _ -> (load, store, plus, times, uminus, num) Chris@10: | NaN _ -> (load, store, plus, times, uminus, num)) Chris@10: rest Chris@10: in let (l, s, p, t, u, n) = Chris@10: loop (0, 0, 0, 0, 0, 0) (visit [] Assoctable.empty dag) Chris@10: in (l, s, p, t, u, n) Chris@10: Chris@10: let weight (l, s, p, t, u, n) = Chris@10: l + s + 10 * p + 20 * t + u + n Chris@10: Chris@10: let same_complexity a b = weight a = weight b Chris@10: let leq_complexity a b = weight a <= weight b Chris@10: Chris@10: let to_string (l, s, p, t, u, n) = Chris@10: Printf.sprintf "ld=%d st=%d add=%d mul=%d uminus=%d num=%d\n" Chris@10: l s p t u n Chris@10: Chris@10: end Chris@10: Chris@10: (* simplify the dag *) Chris@10: let algsimp v = Chris@10: let rec simplification_loop v = Chris@10: let () = Util.info "simplification step" in Chris@10: let complexity = Stats.complexity v in Chris@10: let () = Util.info ("complexity = " ^ (Stats.to_string complexity)) in Chris@10: let v = (AlgSimp.algsimp @@ Transpose.transpose @@ Chris@10: AlgSimp.algsimp @@ Transpose.transpose) v in Chris@10: let complexity' = Stats.complexity v in Chris@10: let () = Util.info ("complexity = " ^ (Stats.to_string complexity')) in Chris@10: if (Stats.leq_complexity complexity' complexity) then Chris@10: let () = Util.info "end algsimp" in Chris@10: v Chris@10: else Chris@10: simplification_loop v Chris@10: Chris@10: in Chris@10: let () = Util.info "begin algsimp" in Chris@10: let v = AlgSimp.algsimp v in Chris@10: if !Magic.network_transposition then simplification_loop v else v Chris@10: