From 7fa612c837ddd62fda74341f8e2e8c544bcb6627 Mon Sep 17 00:00:00 2001 From: oflatt Date: Wed, 22 May 2024 11:01:09 -0700 Subject: [PATCH 01/47] improve block fusing --- src/rvsdg/optimize_direct_jumps.rs | 83 +++++++++---------- ...mize_direct_jumps__add_block_ind_test.snap | 2 +- ...state_mem_to_cfg_more_blocks_snapshot.snap | 12 +-- ...ests__rvsdg_state_mem_to_cfg_snapshot.snap | 2 +- 4 files changed, 47 insertions(+), 52 deletions(-) diff --git a/src/rvsdg/optimize_direct_jumps.rs b/src/rvsdg/optimize_direct_jumps.rs index a89c92748..577ea7109 100644 --- a/src/rvsdg/optimize_direct_jumps.rs +++ b/src/rvsdg/optimize_direct_jumps.rs @@ -8,7 +8,7 @@ use hashbrown::HashMap; use petgraph::{ graph::EdgeIndex, stable_graph::{NodeIndex, StableDiGraph, StableGraph}, - visit::{Bfs, EdgeRef}, + visit::{DfsPostOrder, EdgeRef}, Direction, }; @@ -19,10 +19,13 @@ use crate::Optimizer; impl SimpleCfgFunction { pub fn optimize_jumps(&self) -> Self { - self.single_in_single_out().collapse_empty_blocks() + self.fuse_down().collapse_empty_blocks() } - fn single_in_single_out(&self) -> SimpleCfgFunction { + /// Find cases where a block jumps directly to another block A -> B where B + /// A has only one outgoing edge and B has one incoming edge + /// Turn it into one block AB + fn fuse_down(&self) -> SimpleCfgFunction { let mut resulting_graph: StableGraph = StableDiGraph::new(); // a map from nodes in the old graph to nodes in the @@ -34,52 +37,53 @@ impl SimpleCfgFunction { // we use a bfs so that previous nodes are mapped to new nodes // before their children. // This ensures that `node_mapping[&previous]` succeeds. - let mut bfs = Bfs::new(&self.graph, self.entry); + let mut dfs = DfsPostOrder::new(&self.graph, self.entry); let mut edges_to_add = vec![]; // copy the graph without the edges // also choose which nodes get fused to which // by re-assigning in the node map - while let Some(node) = bfs.next(&self.graph) { - let mut collapse_node = false; - let edges = self + while let Some(node) = dfs.next(&self.graph) { + let outgoing_from_node = self .graph - .edges_directed(node, Direction::Incoming) + .edges_directed(node, Direction::Outgoing) .collect::>(); - // single incoming edge to node - if let &[single_edge] = edges.as_slice() { - let previous = single_edge.source(); - let previous_outgoing = self + let target = if let &[single_edge] = outgoing_from_node.as_slice() { + let target = single_edge.target(); + let incoming_to_next = self .graph - .edges_directed(previous, Direction::Outgoing) - .collect::>(); - // single outgoing edge from previous - // and two distinct nodes - if previous_outgoing.len() == 1 && previous != node { - let previous_new = node_mapping[&previous]; - - // this node will be mapped to the previous - node_mapping.insert(node, previous_new); - - // add instructions to the end of the previous node - resulting_graph[previous_new] - .instrs - .extend(self.graph[node].instrs.to_vec()); - resulting_graph[previous_new] - .footer - .extend(self.graph[node].footer.to_vec()); - - collapse_node = true; + .edges_directed(target, Direction::Incoming) + .count(); + if incoming_to_next == 1 { + Some(target) + } else { + None } - } - - if !collapse_node { + } else { + None + }; + // single outgoing edge + if let Some(next) = target { + let new_target = node_mapping[&next]; + + // this node will be mapped to the previous + node_mapping.insert(node, new_target); + + // add instructions to the beginning of the next node + let mut new_instrs = self.graph[node].instrs.to_vec(); + let mut new_footer = self.graph[node].footer.to_vec(); + new_instrs.extend(resulting_graph[new_target].instrs.to_vec()); + new_footer.extend(resulting_graph[new_target].footer.to_vec()); + + resulting_graph[new_target].instrs = new_instrs; + resulting_graph[new_target].footer = new_footer; + } else { // add the node let new_node = resulting_graph.add_node(self.graph[node].clone()); node_mapping.insert(node, new_node); - edges_to_add.extend(self.graph.edges_directed(node, Direction::Incoming)); + edges_to_add.extend(self.graph.edges_directed(node, Direction::Outgoing)); } } @@ -89,15 +93,6 @@ impl SimpleCfgFunction { resulting_graph.add_edge(source, target, edge.weight().clone()); } - let mut label_mapping = HashMap::::new(); - for (old, new) in node_mapping.iter() { - let old_entry = label_mapping.insert( - self.graph[*old].name.to_string(), - resulting_graph[*new].name.to_string(), - ); - assert!(old_entry.is_none(), "Duplicate labels in graph"); - } - SimpleCfgFunction { name: self.name.clone(), args: self.args.clone(), diff --git a/src/rvsdg/snapshots/eggcc__rvsdg__optimize_direct_jumps__add_block_ind_test.snap b/src/rvsdg/snapshots/eggcc__rvsdg__optimize_direct_jumps__add_block_ind_test.snap index 45a30ebfe..5c116d6e3 100644 --- a/src/rvsdg/snapshots/eggcc__rvsdg__optimize_direct_jumps__add_block_ind_test.snap +++ b/src/rvsdg/snapshots/eggcc__rvsdg__optimize_direct_jumps__add_block_ind_test.snap @@ -3,7 +3,7 @@ source: src/rvsdg/optimize_direct_jumps.rs expression: cfg.optimize_jumps().to_bril().to_string() --- @main { -.entry___: +.exit___: v0: int = const 1; v1: int = const 2; v2: int = add v0 v1; diff --git a/src/rvsdg/snapshots/eggcc__rvsdg__tests__rvsdg_state_mem_to_cfg_more_blocks_snapshot.snap b/src/rvsdg/snapshots/eggcc__rvsdg__tests__rvsdg_state_mem_to_cfg_more_blocks_snapshot.snap index 8acca5418..db37e57b9 100644 --- a/src/rvsdg/snapshots/eggcc__rvsdg__tests__rvsdg_state_mem_to_cfg_more_blocks_snapshot.snap +++ b/src/rvsdg/snapshots/eggcc__rvsdg__tests__rvsdg_state_mem_to_cfg_more_blocks_snapshot.snap @@ -3,24 +3,24 @@ source: src/rvsdg/tests.rs expression: prog.to_string() --- @main { -.__0__: +.__21__: v1: int = const 1; v4: ptr = alloc v1; v7: int = const 10; store v4 v7; v11: int = load v4; v14: bool = lt v11 v7; - br v14 .__33__ .__22__; -.__33__: + br v14 .__39__ .__32__; +.__39__: print v11; free v4; v31: int = id v7; - jmp .__40__; -.__22__: + jmp .__42__; +.__32__: v24: int = add v11 v1; free v4; print v24; v31: int = id v7; -.__40__: +.__42__: print v31; } diff --git a/src/rvsdg/snapshots/eggcc__rvsdg__tests__rvsdg_state_mem_to_cfg_snapshot.snap b/src/rvsdg/snapshots/eggcc__rvsdg__tests__rvsdg_state_mem_to_cfg_snapshot.snap index 1449554d9..b229c675d 100644 --- a/src/rvsdg/snapshots/eggcc__rvsdg__tests__rvsdg_state_mem_to_cfg_snapshot.snap +++ b/src/rvsdg/snapshots/eggcc__rvsdg__tests__rvsdg_state_mem_to_cfg_snapshot.snap @@ -3,7 +3,7 @@ source: src/rvsdg/tests.rs expression: prog.to_string() --- @main { -.__0__: +.__16__: v1: int = const 1; v4: ptr = alloc v1; v8: int = const 10; From a34c3003d291a866575177f45ce746a9e2d58ae1 Mon Sep 17 00:00:00 2001 From: oflatt Date: Wed, 22 May 2024 11:38:01 -0700 Subject: [PATCH 02/47] makefile simpler, fix bug --- Makefile | 9 ++++++--- src/rvsdg/optimize_direct_jumps.rs | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 0a05c241a..d828f989f 100644 --- a/Makefile +++ b/Makefile @@ -5,16 +5,19 @@ DIRS = . dag_in_context all: nits test test: - $(foreach dir,$(DIRS),(cd $(dir) && cargo insta test --release --unreferenced=reject) &&) : + cargo insta test --release --unreferenced=reject + cd dag_in_context && cargo insta test --release --unreferenced=reject test-clean: - $(foreach dir,$(DIRS),(cd $(dir) && cargo insta test --release --unreferenced=delete) &&) : + cargo insta test --release --unreferenced=delete + cd dag_in_context && cargo insta test --release --unreferenced=delete nits: npx prettier infra/nightly-resources/*.js --check @rustup component add clippy @rustup component add rustfmt - $(foreach dir,$(DIRS),(cd $(dir) && cargo clippy --tests -- -D warnings && cargo fmt --check) &&) : + cargo clippy --tests -- -D warnings && cargo fmt --check + cd dag_in_context && cargo clippy --tests -- -D warnings && cargo fmt --check diff --git a/src/rvsdg/optimize_direct_jumps.rs b/src/rvsdg/optimize_direct_jumps.rs index 577ea7109..7809dfd77 100644 --- a/src/rvsdg/optimize_direct_jumps.rs +++ b/src/rvsdg/optimize_direct_jumps.rs @@ -55,7 +55,7 @@ impl SimpleCfgFunction { .graph .edges_directed(target, Direction::Incoming) .count(); - if incoming_to_next == 1 { + if incoming_to_next == 1 && target != node { Some(target) } else { None From 4e0a03405f1a7f844ee349f7fcd31cf83bbbb1bb Mon Sep 17 00:00:00 2001 From: Kirsten <32720576+kirstenmg@users.noreply.github.com> Date: Wed, 22 May 2024 14:54:09 -0700 Subject: [PATCH 03/47] Temp commit for debug --- dag_in_context/out.egg | 3725 ++++++++++++++++ .../src/optimizations/loop_unroll.egg | 59 +- .../src/optimizations/switch_rewrites.egg | 2 +- dag_in_context/src/schedule.rs | 2 +- out.egg | 3854 +++++++++++++++++ tests/passing/small/peel_twice.bril | 13 + .../small/peel_twice_precalc_pred.bril | 12 + 7 files changed, 7663 insertions(+), 4 deletions(-) create mode 100644 dag_in_context/out.egg create mode 100644 out.egg create mode 100644 tests/passing/small/peel_twice.bril create mode 100644 tests/passing/small/peel_twice_precalc_pred.bril diff --git a/dag_in_context/out.egg b/dag_in_context/out.egg new file mode 100644 index 000000000..dcc5f9426 --- /dev/null +++ b/dag_in_context/out.egg @@ -0,0 +1,3725 @@ + Compiling dag_in_context v0.1.0 (/Users/kirsten/GitHub/eggcc/dag_in_context) +warning: unused import: `crate::egglog_test` + --> src/optimizations/loop_unroll.rs:34:9 + | +34 | use crate::egglog_test; + | ^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unused_imports)]` on by default + +warning: unused import: `crate::egglog_test_and_print_program` + --> src/optimizations/loop_unroll.rs:1:5 + | +1 | use crate::egglog_test_and_print_program; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unused_imports)]` on by default + +warning: unused variable: `expected` + --> src/optimizations/loop_unroll.rs:61:9 + | +61 | let expected = parallel!(int(2), int(1)).with_arg_types(emptyt(), tuplet!(intt(), intt())); + | ^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_expected` + | + = note: `#[warn(unused_variables)]` on by default + +warning: `dag_in_context` (lib) generated 1 warning (run `cargo fix --lib -p dag_in_context` to apply 1 suggestion) +warning: `dag_in_context` (lib test) generated 2 warnings (run `cargo fix --lib -p dag_in_context --tests` to apply 2 suggestions) + Finished release [optimized] target(s) in 5.98s + Running unittests src/lib.rs (target/release/deps/dag_in_context-90c12cb0a35ca697) +; Every term is an `Expr` or a `ListExpr`. +(datatype Expr) +; Used for constructing a list of branches for `Switch`es +; or a list of functions in a `Program`. +(datatype ListExpr (Cons Expr ListExpr) (Nil)) + +; ================================= +; Types +; ================================= + +(sort TypeList) + +(datatype BaseType + (IntT) + (BoolT) + (FloatT) + ; a pointer to a memory region with a particular type + (PointerT BaseType) + (StateT)) + + +(datatype Type + ; a primitive type + (Base BaseType) + ; a typed tuple. Use an empty tuple as a unit type. + ; state edge also has unit type + (TupleT TypeList) +) + +(function TNil () TypeList) +(function TCons (BaseType TypeList) TypeList) ; Head element should never be a tuple + + +; ================================= +; Assumptions +; ================================= + +(datatype Assumption + ; Assume nothing + (InFunc String) + ; The term is in a loop with `input` and `pred_output`. + ; InLoop is a special context because it describes the argument of the loop. It is a *scope context*. + ; input pred_output + (InLoop Expr Expr) + ; Branch of the switch, and what the predicate is, and what the input is + (InSwitch i64 Expr Expr) + ; If the predicate was true, and what the predicate is, and what the input is + (InIf bool Expr Expr) +) + + + +; ================================= +; Leaf nodes +; Constants, argument, and empty tuple +; ================================= + +; Only a single argument is bound- if multiple values are needed, arg will be a tuple. +; e.g. `(Get (Arg tuple_type) 1)` gets the second value in the argument with some tuple_type. +(function Arg (Type Assumption) Expr) + +; Constants +(datatype Constant + (Int i64) + (Bool bool) + (Float f64)) +; All leaf nodes need the type of the argument +; Type is the type of the bound argument in scope +(function Const (Constant Type Assumption) Expr) + +; An empty tuple. +; Type is the type of the bound argument in scope +(function Empty (Type Assumption) Expr) + + +; ================================= +; Operators +; ================================= + +(datatype TernaryOp + ; given a pointer, value, and a state edge + ; writes the value to the pointer and returns + ; the resulting state edge + (Write) + (Select)) +(datatype BinaryOp + ;; integer operators + (Add) + (Sub) + (Div) + (Mul) + (LessThan) + (GreaterThan) + (LessEq) + (GreaterEq) + (Eq) + ;; float operators + (FAdd) + (FSub) + (FDiv) + (FMul) + (FLessThan) + (FGreaterThan) + (FLessEq) + (FGreaterEq) + (FEq) + ;; logical operators + (And) + (Or) + ; given a pointer and a state edge + ; loads the value at the pointer and returns (value, state edge) + (Load) + ; Takes a pointer and an integer, and offsets + ; the pointer by the integer + (PtrAdd) + ; given and value and a state edge, prints the value as a side-effect + ; the value must be a base value, not a tuple + ; returns an empty tuple + (Print) + ; given a pointer and state edge, frees the whole memory region at the pointer + (Free)) +(datatype UnaryOp + (Not)) + +; Operators +(function Top (TernaryOp Expr Expr Expr) Expr) +(function Bop (BinaryOp Expr Expr) Expr) +(function Uop (UnaryOp Expr) Expr) +; gets from a tuple. static index +(function Get (Expr i64) Expr) +; (Alloc id amount state_edge pointer_type) +; allocate an integer amount of memory for a particular type +; returns (pointer to the allocated memory, state edge) +(function Alloc (i64 Expr Expr BaseType) Expr) +; name of func arg +(function Call (String Expr) Expr) + + + +; ================================= +; Tuple operations +; ================================= + +; `Empty`, `Single` and `Concat` create tuples. +; 1. Use `Empty` for an empty tuple. +; 2. Use `Single` for a tuple with one element. +; 3. Use `Concat` to append the elements from two tuples together. +; Nested tuples are not allowed. + + +; A tuple with a single element. +; Necessary because we only use `Concat` to add to tuples. +(function Single (Expr) Expr) +; Concat appends the elemnts from two tuples together +; e.g. (Concat (Concat (Single a) (Single b)) +; (Concat (Single c) (Single d))) = (a, b, c, d) +; expr1 expr2 +(function Concat (Expr Expr) Expr) + + + +; ================================= +; Control flow +; ================================= + +; Switch on a list of lazily-evaluated branches. +; pred must be an integer +; pred inputs branches chosen +(function Switch (Expr Expr ListExpr) Expr) +; If is like switch, but with a boolean predicate +; pred inputs then else +(function If (Expr Expr Expr Expr) Expr) + + +; A do-while loop. +; Evaluates the input, then evaluates the body. +; Keeps looping while the predicate is true. +; input must have the same type as (output1, output2, ..., outputi) +; input must be a tuple +; pred must be a boolean +; pred-and-body must be a flat tuple (pred, out1, out2, ..., outi) +; input must be the same type as (out1, out2, ..., outi) +; input pred-and-body +(function DoWhile (Expr Expr) Expr) + + +; ================================= +; Top-level expressions +; ================================= +(sort ProgramType) +; An entry function and a list of additional functions. +; entry function other functions +(function Program (Expr ListExpr) ProgramType) +; name input ty output ty output +(function Function (String Type Type Expr) Expr) + + + +; Rulesets +(ruleset always-run) +(ruleset error-checking) +(ruleset memory) +(ruleset memory-helpers) +(ruleset smem) + +;; Initliazation +(relation bop->string (BinaryOp String)) +(relation uop->string (UnaryOp String)) +(relation top->string (TernaryOp String)) +(bop->string (Add) "Add") +(bop->string (Sub) "Sub") +(bop->string (Div) "Div") +(bop->string (Mul) "Mul") +(bop->string (LessThan) "LessThan") +(bop->string (GreaterThan) "GreaterThan") +(bop->string (LessEq) "LessEq") +(bop->string (GreaterEq) "GreaterEq") +(bop->string (Eq) "Eq") +(bop->string (FAdd) "FAdd") +(bop->string (FSub) "FSub") +(bop->string (FDiv) "FDiv") +(bop->string (FMul) "FMul") +(bop->string (FLessThan) "FLessThan") +(bop->string (FGreaterThan) "FGreaterThan") +(bop->string (FLessEq) "FLessEq") +(bop->string (FGreaterEq) "FGreaterEq") +(bop->string (FEq) "FEq") +(bop->string (And) "And") +(bop->string (Or) "Or") +(bop->string (Load) "Load") +(bop->string (PtrAdd) "PtrAdd") +(bop->string (Print) "Print") +(bop->string (Free) "Free") +(ruleset type-analysis) +(ruleset type-helpers) ;; these rules need to saturate between every iter of type-analysis rules + +(function TLConcat (TypeList TypeList) TypeList :unextractable) +(rewrite (TLConcat (TNil) r) r :ruleset type-helpers) +(rewrite (TLConcat (TCons hd tl) r) + (TCons hd (TLConcat tl r)) + :ruleset type-helpers) + +(function TypeList-length (TypeList) i64 :unextractable) +(function TypeList-ith (TypeList i64) BaseType :unextractable) +(function TypeList-suffix (TypeList i64) TypeList :unextractable) + +(rule ((TupleT tylist)) ((union (TypeList-suffix tylist 0) tylist)) :ruleset type-helpers) + +(rule ((= (TypeList-suffix top n) (TCons hd tl))) + ((union (TypeList-ith top n) hd) + (union (TypeList-suffix top (+ n 1)) tl)) :ruleset type-helpers) + +(rule ((= (TypeList-suffix list n) (TNil))) + ((set (TypeList-length list) n)) :ruleset type-helpers) + +(rule ((TypeList-ith list i) + (= (TypeList-length list) n) + (>= i n)) + ((panic "TypeList-ith out of bounds")) :ruleset type-helpers) + +(relation HasType (Expr Type)) + + +;; Keep track of type expectations for error messages +(relation ExpectType (Expr Type String)) +(rule ( + (ExpectType e expected msg) + (HasType e actual) + (!= expected actual) ;; OKAY to compare types for equality because we never union types. + ) + ((extract "Expecting expression") + (extract e) + (extract "to have type") + (extract expected) + (extract "but got type") + (extract actual) + (extract "with message") + (extract msg) + (panic "type mismatch")) + :ruleset error-checking) + +(relation HasArgType (Expr Type)) + +(rule ((HasArgType (Arg t1 ctx) t2) + (!= t1 t2)) + ((panic "arg type mismatch")) + :ruleset error-checking) + +(rule ((= lhs (Function name in out body)) + (HasArgType body ty) + (HasArgType body ty2) + (!= ty ty2)) + ((panic "arg type mismatch in function")) + :ruleset error-checking) + +; Propagate arg types up +(rule ((= lhs (Uop _ e)) + (HasArgType e ty)) + ((HasArgType lhs ty)) + :ruleset type-analysis) +(rule ((= lhs (Bop _ a b)) + (HasArgType a ty)) + ((HasArgType lhs ty)) + :ruleset type-analysis) +(rule ((= lhs (Bop _ a b)) + (HasArgType b ty)) + ((HasArgType lhs ty)) + :ruleset type-analysis) +(rule ((= lhs (Get e _)) + (HasArgType e ty)) + ((HasArgType lhs ty)) + :ruleset type-analysis) +(rule ((= lhs (Alloc _id e state _)) + (HasArgType e ty)) + ((HasArgType lhs ty)) + :ruleset type-analysis) +(rule ((= lhs (Call _ e)) + (HasArgType e ty)) + ((HasArgType lhs ty)) + :ruleset type-analysis) +(rule ((= lhs (Single e)) + (HasArgType e ty)) + ((HasArgType lhs ty)) + :ruleset type-analysis) +(rule ((= lhs (Concat e1 e2)) + (HasArgType e1 ty)) + ((HasArgType lhs ty)) + :ruleset type-analysis) +(rule ((= lhs (Concat e1 e2)) + (HasArgType e2 ty)) + ((HasArgType lhs ty)) + :ruleset type-analysis) +(rule ((= lhs (Switch pred inputs (Cons branch rest))) + (HasArgType pred ty)) + ((HasArgType lhs ty)) + :ruleset type-analysis) +(rule ((= lhs (Switch pred inputs (Cons branch rest))) + (HasArgType branch ty) + (HasType inputs ty2) + (!= ty ty2)) + ((panic "switch branches then branch has incorrect input type")) + :ruleset error-checking) +;; demand with one fewer branches +(rule ((= lhs (Switch pred inputs (Cons branch rest)))) + ((Switch pred inputs rest)) + :ruleset type-analysis) +(rule ((= lhs (If c i t e)) + (HasArgType c ty)) + ((HasArgType lhs ty)) + :ruleset type-analysis) +(rule ((= lhs (If c i t e)) + (HasType i ty) + (HasArgType t ty2) + (!= ty ty2)) + ((panic "if branches then branch has incorrect input type")) + :ruleset error-checking) +(rule ((= lhs (If c i t e)) + (HasType i ty) + (HasArgType e ty2) + (!= ty ty2)) + ((panic "if branches else branch has incorrect input type")) + :ruleset error-checking) + + +(rule ((= lhs (DoWhile ins body)) + (HasArgType ins ty)) + ((HasArgType lhs ty)) + :ruleset type-analysis) +; Don't push arg types through Program, Function, DoWhile, Let exprs because +; these create new arg contexts. + +; Primitives +(rule ((= lhs (Const (Int i) ty ctx))) + ((HasType lhs (Base (IntT))) + (HasArgType lhs ty)) + :ruleset type-analysis) + +(rule ((= lhs (Const (Bool b) ty ctx))) + ((HasType lhs (Base (BoolT))) + (HasArgType lhs ty)) + :ruleset type-analysis) + +(rule ((= lhs (Const (Float b) ty ctx))) + ((HasType lhs (Base (FloatT))) + (HasArgType lhs ty)) + :ruleset type-analysis) + +(rule ((= lhs (Empty ty ctx))) + ((HasType lhs (TupleT (TNil))) + (HasArgType lhs ty)) + :ruleset type-analysis) + +; Unary Ops +(rule ( + (= lhs (Uop (Not) e)) + (HasType e (Base (BoolT))) + ) + ((HasType lhs (Base (BoolT)))) + :ruleset type-analysis) +(rule ((= lhs (Uop (Not) e))) + ((ExpectType e (Base (BoolT)) "(Not)")) + :ruleset type-analysis) + + +(rule ( + (= lhs (Bop (Print) e state)) + (HasType e _ty) ; just make sure it has some type. + ) + ((HasType lhs (Base (StateT)))) + :ruleset type-analysis) + +(rule ( + (= lhs (Bop (Print) e state)) + (HasType e (TupleT ty)) + ) + ((panic "Don't print a tuple")) + :ruleset error-checking) + +(rule ((= lhs (Bop (Free) e s)) + (HasType e (Base (PointerT _ty)))) + ((HasType lhs (Base (StateT)))) + :ruleset type-analysis) +(rule ((= lhs (Bop (Free) e s)) + (HasType e (Base (IntT)))) + ((panic "Free expected pointer, received integer")) + :ruleset error-checking) +(rule ((= lhs (Bop (Free) e s)) + (HasType e (TupleT _ty))) + ((panic "Free expected pointer, received tuple")) + :ruleset error-checking) + +(rule ( + (= lhs (Bop (Load) e state)) + (HasType e (Base (PointerT ty))) + ) + ((HasType lhs (TupleT (TCons ty (TCons (StateT) (TNil)))))) + :ruleset type-analysis) +(rule ( + (= lhs (Bop (Load) e state)) + (HasType e ty) + (= ty (Base (IntT))) + ) + ((panic "(Load) expected pointer, received int")) + :ruleset error-checking) +(rule ( + (= lhs (Bop (Load) e state)) + (HasType e ty) + (= ty (TupleT x)) + ) + ((panic "(Load) expected pointer, received tuple")) + :ruleset error-checking) + +; Binary ops + +;; Operators that have type Type -> Type -> Type +;; Note we only do this generic matching for binary +;; operator since there's a lot of them. +;; In the future we can also extend to other constructs. +(relation bop-of-type (BinaryOp Type)) +(bop-of-type (Add) (Base (IntT))) +(bop-of-type (Sub) (Base (IntT))) +(bop-of-type (Div) (Base (IntT))) +(bop-of-type (Mul) (Base (IntT))) +(bop-of-type (FAdd) (Base (FloatT))) +(bop-of-type (FSub) (Base (FloatT))) +(bop-of-type (FDiv) (Base (FloatT))) +(bop-of-type (FMul) (Base (FloatT))) + +(rule ( + (= lhs (Bop op e1 e2)) + (bop-of-type op ty) + (HasType e1 ty) + (HasType e2 ty) + ) + ((HasType lhs ty)) + :ruleset type-analysis) +(rule ((= lhs (Bop op e1 e2)) + (bop-of-type op ty) + (bop->string op op-str)) + ( + (ExpectType e1 ty op-str) + (ExpectType e2 ty op-str) + ) + :ruleset type-analysis) + +;; Operators that have type Float -> Float -> Bool +(relation bpred-of-type (BinaryOp Type)) +(bpred-of-type (FLessThan) (Base (FloatT))) +(bpred-of-type (FLessEq) (Base (FloatT))) +(bpred-of-type (FGreaterThan) (Base (FloatT))) +(bpred-of-type (FGreaterEq) (Base (FloatT))) +(bpred-of-type (FEq) (Base (FloatT))) +(bpred-of-type (LessThan) (Base (IntT))) +(bpred-of-type (LessEq) (Base (IntT))) +(bpred-of-type (GreaterThan) (Base (IntT))) +(bpred-of-type (GreaterEq) (Base (IntT))) +(bpred-of-type (Eq) (Base (IntT))) +(bpred-of-type (And) (Base (BoolT))) +(bpred-of-type (Or) (Base (BoolT))) + +(rule ( + (= lhs (Bop pred e1 e2)) + (bpred-of-type pred ty) + (HasType e1 ty) + (HasType e2 ty) + ) + ((HasType lhs (Base (BoolT)))) + :ruleset type-analysis) +(rule ((= lhs (Bop pred e1 e2)) + (bpred-of-type pred ty) + (bop->string pred pred-str)) + ( + (ExpectType e1 ty pred-str) + (ExpectType e2 ty pred-str) + ) + :ruleset type-analysis) + +(rule ( + (= lhs (Top (Write) ptr val state)) + (HasType ptr (Base (PointerT ty))) + (HasType val (Base t)) ; TODO need to support pointers to pointers + ) + ((HasType lhs (Base (StateT)))) ; Write returns () + :ruleset type-analysis) + +(rule ( + (= lhs (Top (Write) ptr val state)) + (HasType ptr (Base (PointerT ty)))) + ((ExpectType val (Base ty) "(Write)")) + :ruleset type-analysis) + + + +(rule ( + (= lhs (Bop (PtrAdd) ptr n)) + (HasType ptr (Base (PointerT ty))) + (HasType n (Base (IntT))) + ) + ((HasType lhs (Base (PointerT ty)))) + :ruleset type-analysis) + +; Other ops +(rule ((= lhs (Alloc _id amt state ty))) + ((ExpectType amt (Base (IntT)) "(Alloc)")) + :ruleset type-analysis) + +(rule ( + (= lhs (Alloc _id amt state ty)) + (HasType amt (Base (IntT))) + ) + ((HasType lhs (TupleT (TCons ty (TCons (StateT) (TNil)))))) + :ruleset type-analysis) + +(rule ( + (= lhs (Get e i)) + (HasType e (TupleT tylist)) + ) + ; TypeList-ith needs to compute immediately, so we need to saturate type-helpers + ; rules between every iter of type-analysis rules. + ((HasType lhs (Base (TypeList-ith tylist i)))) + :ruleset type-analysis) + +(rule ( + (HasType (Get expr i) (TupleT tl)) + (= (TypeList-length tl) len) + (>= i len)) + ((panic "index out of bounds")) + :ruleset error-checking) +(rule ( + (HasType (Get expr i) (TupleT tl)) + (= (TypeList-length tl) len) + (< i 0) + ) + ((panic "negative index")) + :ruleset error-checking) + +; ================================= +; Tuple operations +; ================================= + +(rule ( + (= lhs (Single e)) + (HasType e (TupleT tylist)) + ) + ((panic "don't nest tuples")) + :ruleset error-checking) + +(rule ( + (= lhs (Single e)) + (HasType e (Base basety)) + ) + ((HasType lhs (TupleT (TCons basety (TNil))))) + :ruleset type-analysis) + +(rule ( + (= lhs (Concat e1 e2)) + (HasType e1 (TupleT tylist1)) + (HasType e2 (TupleT tylist2)) + ) + ; TLConcat needs to compute immediately, so we need to saturate type-helpers + ; rules between every iter of type-analysis rules. + ((HasType lhs (TupleT (TLConcat tylist1 tylist2)))) + :ruleset type-analysis) + +; ================================= +; Control flow +; ================================= +(rule ((= lhs (If pred inputs then else))) + ((ExpectType pred (Base (BoolT)) "If predicate must be boolean")) + :ruleset type-analysis) +(rule ( + (= lhs (If pred inputs then else)) + (HasType pred (Base (BoolT))) + (HasType then ty) + (HasType else ty) + ) + ((HasType lhs ty)) + :ruleset type-analysis) + +(rule ( + (= lhs (If pred inputs then else)) + (HasType pred (Base (BoolT))) + (HasType then tya) + (HasType else tyb) + (!= tya tyb) + ) + ((panic "if branches had different types")) + :ruleset error-checking) + + + +(rule ((= lhs (Switch pred inputs branches))) + ((ExpectType pred (Base (IntT)) "Switch predicate must be integer")) + :ruleset type-analysis) + +; base case: single branch switch has type of branch +(rule ( + (= lhs (Switch pred inputs (Cons branch (Nil)))) + (HasType pred (Base (IntT))) + (HasType branch ty) + ) + ((HasType lhs ty)) + :ruleset type-analysis) + +; recursive case: peel off a layer +(rule ((Switch pred inputs (Cons branch rest))) + ((Switch pred inputs rest)) + :ruleset type-analysis) + +(rule ( + (= lhs (Switch pred inputs (Cons branch rest))) + (HasType pred (Base (IntT))) + (HasType branch ty) + (HasType (Switch pred inputs rest) ty) ; rest of the branches also have type ty + ) + ((HasType lhs ty)) + :ruleset type-analysis) + +(rule ( + (= lhs (Switch pred inputs (Cons branch rest))) + (HasType pred (Base (IntT))) + (HasType branch tya) + (HasType (Switch pred inputs rest) tyb) + (!= tya tyb) + ) + ((panic "switch branches had different types")) + :ruleset error-checking) + +(rule ((Arg ty ctx)) + ( + (HasType (Arg ty ctx) ty) + (HasArgType (Arg ty ctx) ty) + ) + :ruleset type-analysis) + + +(rule ( + (= lhs (DoWhile inp pred-body)) + (HasType inp (Base ty)) + ) + ((panic "loop input must be tuple")) + :ruleset error-checking) +(rule ( + (= lhs (DoWhile inp pred-body)) + (HasType inp (Base (PointerT ty))) + ) + ((panic "loop input must be tuple")) + :ruleset error-checking) +(rule ( + (= lhs (DoWhile inp pred-body)) + (HasType pred-body (Base ty)) + ) + ((panic "loop pred-body must be tuple")) + :ruleset error-checking) +(rule ( + (= lhs (DoWhile inp pred-body)) + (HasType pred-body (Base (PointerT ty))) + ) + ((panic "loop pred-body must be tuple")) + :ruleset error-checking) + +(rule ( + (= lhs (DoWhile inp pred-body)) + (HasType inp (TupleT tylist)) + ) + ((HasArgType pred-body (TupleT tylist))) + :ruleset type-analysis) + +(rule ((= lhs (DoWhile inp pred-body))) + ((ExpectType (Get pred-body 0) (Base (BoolT)) "loop pred must be bool")) + :ruleset type-analysis) + +(rule ( + (= lhs (DoWhile inp pred-body)) + (HasType inp (TupleT tylist)) ; input is a tuple + ; pred-body is a tuple where the first elt is a bool + ; and the rest of the list matches the input type + (HasType pred-body (TupleT (TCons (BoolT) tylist))) + ) + ((HasType lhs (TupleT tylist))) ; whole thing has type of inputs/outputs + :ruleset type-analysis) + +(rule ( + (= lhs (DoWhile inp pred-body)) + (HasType inp (TupleT in-tys)) + (HasType pred-body (TupleT (TCons (BoolT) out-tys))) + (!= in-tys out-tys) + ) + ((panic "input types and output types don't match")) + :ruleset error-checking) + +; ================================= +; Functions +; ================================= + +(rule ((= lhs (Function name in-ty out-ty body))) + ( + ; Arg should have the specified type in the body + (HasArgType body in-ty) + ; Expect the body to have the specified output type + (ExpectType body out-ty "Function body had wrong type") + ) + :ruleset type-analysis) + +(rule ( + (= lhs (Call name arg)) + (Function name in-ty out-ty body) + ) + ; Expect the arg to have the right type for the function + ((ExpectType arg in-ty "function called with wrong arg type")) + :ruleset type-analysis) + +(rule ( + (= lhs (Call name arg)) + (Function name in-ty out-ty body) + (HasType arg in-ty) + ; We don't need to check the type of the function body, it will + ; be checked elsewhere. If we did require (HasType body out-ty), + ; recursive functions would not get assigned a type. + ) + ((HasType lhs out-ty)) + :ruleset type-analysis) + +; find which types are pure +(relation PureBaseType (BaseType)) +(relation PureType (Type)) +(relation PureTypeList (TypeList)) + +(PureBaseType (IntT)) +(PureBaseType (BoolT)) +(rule ((Base ty) + (PureBaseType ty)) + ((PureType (Base ty))) + :ruleset type-analysis) +(rule ((TupleT tylist) + (PureTypeList tylist)) + ((PureType (TupleT tylist))) + :ruleset type-analysis) +(rule ((TNil)) + ((PureTypeList (TNil))) + :ruleset type-analysis) +(rule ((TCons hd tl) + (PureBaseType hd) + (PureTypeList tl)) + ((PureTypeList (TCons hd tl))) + :ruleset type-analysis) + +(function ListExpr-length (ListExpr) i64) +(function ListExpr-ith (ListExpr i64) Expr :unextractable) +(function ListExpr-suffix (ListExpr i64) ListExpr :unextractable) +(function Append (ListExpr Expr) ListExpr :unextractable) + +(rule ((Switch pred inputs branch)) ((union (ListExpr-suffix branch 0) branch)) :ruleset always-run) + +(rule ((= (ListExpr-suffix top n) (Cons hd tl))) + ((union (ListExpr-ith top n) hd) + (union (ListExpr-suffix top (+ n 1)) tl)) :ruleset always-run) + +(rule ((= (ListExpr-suffix list n) (Nil))) + ((set (ListExpr-length list) n)) :ruleset always-run) + +(rewrite (Append (Cons a b) e) + (Cons a (Append b e)) + :ruleset always-run) +(rewrite (Append (Nil) e) + (Cons e (Nil)) + :ruleset always-run) + +(function tuple-length (Expr) i64 :unextractable) + +(rule ((HasType expr (TupleT tl)) + (= len (TypeList-length tl))) + ((set (tuple-length expr) len)) :ruleset always-run) + +;; Create a Get for every index, and rewrite it to see through Concat +(rule ((Single expr)) ((union (Get (Single expr) 0) expr)) :ruleset always-run) +;; initial get +(rule ((> (tuple-length tuple) 0)) + ((Get tuple 0)) + :ruleset always-run) +;; next get +(rule ((= len (tuple-length tuple)) + (= ith (Get tuple i)) + (< (+ i 1) len) + ) + ((Get tuple (+ 1 i))) + :ruleset always-run) + +;; descend left +(rule ((Get (Concat expr1 expr2) i) + (= (tuple-length expr1) len1) + (< i len1)) + ((union (Get (Concat expr1 expr2) i) + (Get expr1 i))) + :ruleset always-run) +;; descend right +(rule ((Get (Concat expr1 expr2) i) + (= (tuple-length expr1) len1) + (>= i len1)) + ((union (Get (Concat expr1 expr2) i) + (Get expr2 (- i len1)))) + :ruleset always-run) + + +;; A temporary context. +;; Be sure to delete at the end of all actions or else!!! +;; This is safer than using a persistant context, since we may miss an important part of the query. +(function TmpCtx () Assumption) + +(rule ((TmpCtx)) + ((panic "TmpCtx should not exist outside rule body")) + :ruleset always-run) + +(relation ExprIsValid (Expr)) +(relation ListExprIsValid (ListExpr)) +(rule ((ExprIsValid (Function _name _tyin _tyout _out))) ((ExprIsValid _out)) :ruleset always-run) +(rule ((ExprIsValid (Top _op _x _y _z))) ((ExprIsValid _x) +(ExprIsValid _y) +(ExprIsValid _z)) :ruleset always-run) +(rule ((ExprIsValid (Bop _op _x _y))) ((ExprIsValid _x) +(ExprIsValid _y)) :ruleset always-run) +(rule ((ExprIsValid (Uop _op _x))) ((ExprIsValid _x)) :ruleset always-run) +(rule ((ExprIsValid (Get _tup _i))) ((ExprIsValid _tup)) :ruleset always-run) +(rule ((ExprIsValid (Concat _x _y))) ((ExprIsValid _x) +(ExprIsValid _y)) :ruleset always-run) +(rule ((ExprIsValid (Single _x))) ((ExprIsValid _x)) :ruleset always-run) +(rule ((ExprIsValid (Switch _pred _inputs _branches))) ((ExprIsValid _pred) +(ExprIsValid _inputs) +(ListExprIsValid _branches)) :ruleset always-run) +(rule ((ExprIsValid (If _pred _input _then _else))) ((ExprIsValid _pred) +(ExprIsValid _input) +(ExprIsValid _then) +(ExprIsValid _else)) :ruleset always-run) +(rule ((ExprIsValid (DoWhile _in _pred-and-output))) ((ExprIsValid _in) +(ExprIsValid _pred-and-output)) :ruleset always-run) +(rule ((ExprIsValid (Call _func _arg))) ((ExprIsValid _arg)) :ruleset always-run) +(rule ((ListExprIsValid (Cons _hd _tl))) ((ExprIsValid _hd) +(ListExprIsValid _tl)) :ruleset always-run) +(rule ((ExprIsValid (Alloc _id _e _state _ty))) ((ExprIsValid _e) +(ExprIsValid _state)) :ruleset always-run) +(relation ExprIsResolved (Expr)) +(relation ListExprIsResolved (ListExpr)) +(rule ((= lhs (Function _name _tyin _tyout _out)) (ExprIsResolved _out)) ((ExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (Const _n _ty _ctx)) ) ((ExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (Top _op _x _y _z)) (ExprIsResolved _x) +(ExprIsResolved _y) +(ExprIsResolved _z)) ((ExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (Bop _op _x _y)) (ExprIsResolved _x) +(ExprIsResolved _y)) ((ExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (Uop _op _x)) (ExprIsResolved _x)) ((ExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (Get _tup _i)) (ExprIsResolved _tup)) ((ExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (Concat _x _y)) (ExprIsResolved _x) +(ExprIsResolved _y)) ((ExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (Single _x)) (ExprIsResolved _x)) ((ExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (Switch _pred _inputs _branches)) (ExprIsResolved _pred) +(ExprIsResolved _inputs) +(ListExprIsResolved _branches)) ((ExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (If _pred _input _then _else)) (ExprIsResolved _pred) +(ExprIsResolved _input) +(ExprIsResolved _then) +(ExprIsResolved _else)) ((ExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (DoWhile _in _pred-and-output)) (ExprIsResolved _in) +(ExprIsResolved _pred-and-output)) ((ExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (Arg _ty _ctx)) ) ((ExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (Call _func _arg)) (ExprIsResolved _arg)) ((ExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (Empty _ty _ctx)) ) ((ExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (Cons _hd _tl)) (ExprIsResolved _hd) +(ListExprIsResolved _tl)) ((ListExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (Nil)) ) ((ListExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (Alloc _id _e _state _ty)) (ExprIsResolved _e) +(ExprIsResolved _state)) ((ExprIsResolved lhs)) :ruleset always-run) +(relation BodyContainsExpr (Expr Expr)) +(relation BodyContainsListExpr (Expr ListExpr)) +(rule ((Function _name _tyin _tyout _out)) ((BodyContainsExpr (Function _name _tyin _tyout _out) _out)) :ruleset always-run) +(rule ((If _pred _input _then _else)) ((BodyContainsExpr (If _pred _input _then _else) _then) (BodyContainsExpr (If _pred _input _then _else) _else)) :ruleset always-run) +(rule ((DoWhile _in _pred-and-output)) ((BodyContainsExpr (DoWhile _in _pred-and-output) _pred-and-output)) :ruleset always-run) +(rule ((BodyContainsExpr body (Top _op _x _y _z))) ((BodyContainsExpr body _x) (BodyContainsExpr body _y) (BodyContainsExpr body _z)) :ruleset always-run) +(rule ((BodyContainsExpr body (Bop _op _x _y))) ((BodyContainsExpr body _x) (BodyContainsExpr body _y)) :ruleset always-run) +(rule ((BodyContainsExpr body (Uop _op _x))) ((BodyContainsExpr body _x)) :ruleset always-run) +(rule ((BodyContainsExpr body (Get _tup _i))) ((BodyContainsExpr body _tup)) :ruleset always-run) +(rule ((BodyContainsExpr body (Concat _x _y))) ((BodyContainsExpr body _x) (BodyContainsExpr body _y)) :ruleset always-run) +(rule ((BodyContainsExpr body (Single _x))) ((BodyContainsExpr body _x)) :ruleset always-run) +(rule ((BodyContainsExpr body (Switch _pred _inputs _branches))) ((BodyContainsExpr body _pred) (BodyContainsExpr body _inputs)) :ruleset always-run) +(rule ((BodyContainsExpr body (If _pred _input _then _else))) ((BodyContainsExpr body _pred) (BodyContainsExpr body _input)) :ruleset always-run) +(rule ((BodyContainsExpr body (DoWhile _in _pred-and-output))) ((BodyContainsExpr body _in)) :ruleset always-run) +(rule ((BodyContainsExpr body (Call _func _arg))) ((BodyContainsExpr body _arg)) :ruleset always-run) +(rule ((BodyContainsListExpr body (Cons _hd _tl))) ((BodyContainsExpr body _hd)) :ruleset always-run) +(rule ((BodyContainsExpr body (Alloc _id _e _state _ty))) ((BodyContainsExpr body _e) (BodyContainsExpr body _state)) :ruleset always-run) + + (relation ExprIsPure (Expr)) + (relation ListExprIsPure (ListExpr)) + (relation BinaryOpIsPure (BinaryOp)) + (relation UnaryOpIsPure (UnaryOp)) + (relation TopIsPure (TernaryOp)) +(TopIsPure (Select)) +(BinaryOpIsPure (Add)) +(BinaryOpIsPure (Sub)) +(BinaryOpIsPure (Mul)) +(BinaryOpIsPure (Div)) +(BinaryOpIsPure (Eq)) +(BinaryOpIsPure (LessThan)) +(BinaryOpIsPure (GreaterThan)) +(BinaryOpIsPure (LessEq)) +(BinaryOpIsPure (GreaterEq)) +(BinaryOpIsPure (FAdd)) +(BinaryOpIsPure (FSub)) +(BinaryOpIsPure (FMul)) +(BinaryOpIsPure (FDiv)) +(BinaryOpIsPure (FEq)) +(BinaryOpIsPure (FLessThan)) +(BinaryOpIsPure (FGreaterThan)) +(BinaryOpIsPure (FLessEq)) +(BinaryOpIsPure (FGreaterEq)) +(BinaryOpIsPure (And)) +(BinaryOpIsPure (Or)) +(BinaryOpIsPure (PtrAdd)) +(UnaryOpIsPure (Not)) + + (rule ((Function _name _tyin _tyout _out) (ExprIsPure _out)) + ((ExprIsPure (Function _name _tyin _tyout _out))) + :ruleset always-run) + + (rule ((Const _n _ty _ctx)) + ((ExprIsPure (Const _n _ty _ctx))) + :ruleset always-run) + + (rule ((Top _op _x _y _z) (ExprIsPure _x) (ExprIsPure _y) (ExprIsPure _z)) + ((ExprIsPure (Top _op _x _y _z))) + :ruleset always-run) + + (rule ((Bop _op _x _y) (BinaryOpIsPure _op) (ExprIsPure _x) (ExprIsPure _y)) + ((ExprIsPure (Bop _op _x _y))) + :ruleset always-run) + + (rule ((Uop _op _x) (UnaryOpIsPure _op) (ExprIsPure _x)) + ((ExprIsPure (Uop _op _x))) + :ruleset always-run) + + (rule ((Get _tup _i) (ExprIsPure _tup)) + ((ExprIsPure (Get _tup _i))) + :ruleset always-run) + + (rule ((Concat _x _y) (ExprIsPure _x) (ExprIsPure _y)) + ((ExprIsPure (Concat _x _y))) + :ruleset always-run) + + (rule ((Single _x) (ExprIsPure _x)) + ((ExprIsPure (Single _x))) + :ruleset always-run) + + (rule ((Switch _pred _inputs _branches) (ExprIsPure _pred) (ExprIsPure _inputs) (ListExprIsPure _branches)) + ((ExprIsPure (Switch _pred _inputs _branches))) + :ruleset always-run) + + (rule ((If _pred _input _then _else) (ExprIsPure _pred) (ExprIsPure _input) (ExprIsPure _then) (ExprIsPure _else)) + ((ExprIsPure (If _pred _input _then _else))) + :ruleset always-run) + + (rule ((DoWhile _in _pred-and-output) (ExprIsPure _in) (ExprIsPure _pred-and-output)) + ((ExprIsPure (DoWhile _in _pred-and-output))) + :ruleset always-run) + + (rule ((Arg _ty _ctx)) + ((ExprIsPure (Arg _ty _ctx))) + :ruleset always-run) + + (rule ((Call _f _arg) (ExprIsPure _arg) (ExprIsPure (Function _f inty outty out))) + ((ExprIsPure (Call _f _arg))) + :ruleset always-run) + + (rule ((Empty _ty _ctx)) + ((ExprIsPure (Empty _ty _ctx))) + :ruleset always-run) + + (rule ((Cons _hd _tl) (ExprIsPure _hd) (ListExprIsPure _tl)) + ((ListExprIsPure (Cons _hd _tl))) + :ruleset always-run) + + (rule ((Nil)) + ((ListExprIsPure (Nil))) + :ruleset always-run) + +; This file provides AddContext, a helpers that copies a sub-egraph into +; a new one with a new context. +; Users of AddContext can specify how deeply to do this copy. + + +(ruleset context) + +(function AddContext (Assumption Expr) Expr :unextractable) +(function AddContextList (Assumption ListExpr) ListExpr :unextractable) + +;; ################################ saturation + +;; Adding context a second time does nothing, so union +(rule + ((= lhs (AddContext ctx inner)) + (= inner (AddContext ctx expr))) + ((union lhs inner)) + :ruleset context) + + +;; ############################## Base cases- leaf nodes + +;; replace existing contexts that are around leaf nodes +;; AddContext assumes the new context is more specific than the old one +(rule ((= lhs (AddContext ctx (Arg ty oldctx)))) + ((union lhs (Arg ty ctx))) + :ruleset context) +(rule ((= lhs (AddContext ctx (Const c ty oldctx)))) + ((union lhs (Const c ty ctx))) + :ruleset context) +(rule ((= lhs (AddContext ctx (Empty ty oldctx)))) + ((union lhs (Empty ty ctx))) + :ruleset context) + + + + +;; ######################################### Operators +(rewrite (AddContext ctx (Bop op c1 c2)) + (Bop op + (AddContext ctx c1) + (AddContext ctx c2)) + :ruleset context) +(rewrite (AddContext ctx (Uop op c1)) + (Uop op (AddContext ctx c1)) + :ruleset context) +(rewrite (AddContext ctx (Get c1 index)) + (Get (AddContext ctx c1) index) + :ruleset context) +(rewrite (AddContext ctx (Alloc id c1 state ty)) + (Alloc id (AddContext ctx c1) (AddContext ctx state) ty) + :ruleset context) +(rewrite (AddContext ctx (Call name c1)) + (Call name (AddContext ctx c1)) + :ruleset context) + +(rewrite (AddContext ctx (Single c1)) + (Single (AddContext ctx c1)) + :ruleset context) +(rewrite (AddContext ctx (Concat c1 c2)) + (Concat + (AddContext ctx c1) + (AddContext ctx c2)) + :ruleset context) + +;; ################################### List operators + +(rewrite (AddContextList ctx (Nil)) + (Nil) + :ruleset context) + +(rewrite (AddContextList ctx (Cons c1 rest)) + (Cons (AddContext ctx c1) + (AddContextList ctx rest)) + :ruleset context) + + +;; ########################################## Control flow +(rewrite (AddContext ctx (Switch pred inputs branches)) + (Switch (AddContext ctx pred) + (AddContext ctx inputs) + branches) + :ruleset context) + +;; For stop at region, still add context to inputs +(rule ((= lhs (AddContext ctx (If pred inputs c1 c2)))) + ((union lhs + (If (AddContext ctx pred) + (AddContext ctx inputs) + c1 + c2))) + :ruleset context) + + +;; For stop at loop, still add context to inputs +(rule ((= lhs (AddContext ctx (DoWhile inputs outputs)))) + ((union lhs + (DoWhile + (AddContext ctx inputs) + outputs))) + :ruleset context) + + +;; Substitution rules allow for substituting some new expression for the argument +;; in some new context. +;; It performs the substitution, copying over the equalities from the original eclass. +;; It only places context on the leaf nodes. + +(ruleset subst) +(ruleset apply-subst-unions) +(ruleset cleanup-subst) + +;; (Subst assumption to in) substitutes `to` for `(Arg ty)` in `in`. +;; It also replaces the leaf context in `to` with `assumption` using `AddContext`. +;; `assumption` *justifies* this substitution, as the context that the result is used in. +;; In other words, it must refine the equivalence relation of `in` with `to` as the argument. +(function Subst (Assumption Expr Expr) Expr :unextractable) + +;; Used to delay unions for the subst ruleset. +;; This is necessary because substitution may not terminate if it can +;; observe its own results- it may create infinitly large terms. +;; Instead, we phase substitution by delaying resulting unions in this table. +;; After applying this table, substitutions and this table are cleared. +(function DelayedSubstUnion (Expr Expr) Expr :unextractable) + +;; add a type rule to get the arg type of a substitution +;; this enables nested substitutions +(rule ((= lhs (Subst assum to in)) + (HasArgType to ty)) + ((HasArgType lhs ty)) + :ruleset subst) + +;; leaf node with context +;; replace this context- subst assumes the context is more specific +(rule ((= lhs (Subst assum to (Arg ty oldctx))) + ) + ;; add the assumption `to` + ((DelayedSubstUnion lhs (AddContext assum to))) + :ruleset subst) +(rule ((= lhs (Subst assum to (Const c ty oldctx))) + (HasArgType to newty)) + ((DelayedSubstUnion lhs (Const c newty assum))) + :ruleset subst) +(rule ((= lhs (Subst assum to (Empty ty oldctx))) + (HasArgType to newty)) + ((DelayedSubstUnion lhs (Empty newty assum))) + :ruleset subst) + +;; Operators +(rule ((= lhs (Subst assum to (Bop op c1 c2))) + (ExprIsResolved (Bop op c1 c2))) + ((DelayedSubstUnion lhs + (Bop op (Subst assum to c1) + (Subst assum to c2)))) + :ruleset subst) +(rule ((= lhs (Subst assum to (Uop op c1))) + (ExprIsResolved (Uop op c1))) + ((DelayedSubstUnion lhs + (Uop op (Subst assum to c1)))) + :ruleset subst) + +(rule ((= lhs (Subst assum to (Get c1 index))) + (ExprIsResolved (Get c1 index))) + ((DelayedSubstUnion lhs + (Get (Subst assum to c1) index))) + :ruleset subst) +(rule ((= lhs (Subst assum to (Alloc id c1 c2 ty))) + (ExprIsResolved (Alloc id c1 c2 ty))) + ((DelayedSubstUnion lhs + (Alloc id (Subst assum to c1) + (Subst assum to c2) + ty))) + :ruleset subst) +(rule ((= lhs (Subst assum to (Call name c1))) + (ExprIsResolved (Call name c1))) + ((DelayedSubstUnion lhs + (Call name (Subst assum to c1)))) + :ruleset subst) + + +;; Tuple operators +(rule ((= lhs (Subst assum to (Single c1))) + (ExprIsResolved (Single c1))) + ((DelayedSubstUnion lhs + (Single (Subst assum to c1)))) + :ruleset subst) +(rule ((= lhs (Subst assum to (Concat c1 c2))) + (ExprIsResolved (Concat c1 c2))) + ((DelayedSubstUnion lhs + (Concat (Subst assum to c1) + (Subst assum to c2)))) + :ruleset subst) + +;; Control flow +(rule ((= lhs (Subst assum to inner)) + (= inner (Switch pred inputs c1)) + (ExprIsResolved inner)) + ((DelayedSubstUnion lhs + (Switch (Subst assum to pred) + (Subst assum to inputs) + c1))) + :ruleset subst) +(rule ((= lhs (Subst assum to inner)) + (= inner (If pred inputs c1 c2)) + (ExprIsResolved inner)) + ((DelayedSubstUnion lhs + (If (Subst assum to pred) + (Subst assum to inputs) + c1 + c2))) + :ruleset subst) +(rule ((= lhs (Subst assum to (DoWhile in out))) + (ExprIsResolved (DoWhile in out))) + ((DelayedSubstUnion lhs + (DoWhile (Subst assum to in) + out))) + :ruleset subst) + +;; substitute into function (convenience for testing) +(rewrite (Subst assum to (Function name inty outty body)) + (Function name inty outty (Subst assum to body)) + :when ((ExprIsResolved body)) + :ruleset subst) + + + +;; ########################### Apply subst unions + +(rule ((DelayedSubstUnion lhs rhs)) + ((union lhs rhs)) + :ruleset apply-subst-unions) + + +;; ########################### Cleanup subst and DelayedSubstUnion + +(rule ((DelayedSubstUnion lhs rhs)) + ((subsume (DelayedSubstUnion lhs rhs))) + :ruleset cleanup-subst) + +; this cleanup is important- if we don't subsume these substitutions, they +; may oberve their own results and create infinitely sized terms. +; ex: get(parallel!(arg(), int(2)), 0) ignores the first element of the tuple +; so it's equivalent to infinite other times with any other value as the first element of the tuple. +; Check ExprIsResolved to confirm that the substitution finished (all sub-substitutions are done). +(rule ((ExprIsResolved (Subst assum to in))) + ((subsume (Subst assum to in))) + :ruleset cleanup-subst) + +; We only have context for Exprs, not ListExprs. +(relation ContextOf (Expr Assumption)) + +(rule ((Arg ty ctx)) + ((ContextOf (Arg ty ctx) ctx)) + :ruleset always-run) +(rule ((Const c ty ctx)) + ((ContextOf (Const c ty ctx) ctx)) + :ruleset always-run) +(rule ((Empty ty ctx)) + ((ContextOf (Empty ty ctx) ctx)) + :ruleset always-run) + +; Error checking - each expr should only have a single context +(rule ((ContextOf x ctx1) + (ContextOf x ctx2) + (!= ctx1 ctx2)) + ( + (panic "Equivalent expressions have nonequivalent context, breaking the single context invariant.") + ) + :ruleset error-checking) + + +(rule ((Top op x y z) (ContextOf x ctx)) + ((ContextOf (Top op x y z) ctx)) :ruleset always-run) + +(rule ((Top op x y z) (ContextOf y ctx)) + ((ContextOf (Top op x y z) ctx)) :ruleset always-run) + +(rule ((Top op x y z) (ContextOf z ctx)) + ((ContextOf (Top op x y z) ctx)) :ruleset always-run) + +(rule ((Bop op x y) (ContextOf x ctx)) + ((ContextOf (Bop op x y) ctx)) :ruleset always-run) + +(rule ((Bop op x y) (ContextOf y ctx)) + ((ContextOf (Bop op x y) ctx)) :ruleset always-run) + +(rule ((Uop op x) (ContextOf x ctx)) + ((ContextOf (Uop op x) ctx)) :ruleset always-run) + +(rule ((Get tup i) (ContextOf tup ctx)) + ((ContextOf (Get tup i) ctx)) :ruleset always-run) + +(rule ((Concat x y) (ContextOf x ctx)) + ((ContextOf (Concat x y) ctx)) :ruleset always-run) + +(rule ((Concat x y) (ContextOf y ctx)) + ((ContextOf (Concat x y) ctx)) :ruleset always-run) + +(rule ((Single x) (ContextOf x ctx)) + ((ContextOf (Single x) ctx)) :ruleset always-run) + +(rule ((Switch pred inputs branches) (ContextOf pred ctx)) + ((ContextOf (Switch pred inputs branches) ctx)) :ruleset always-run) + +(rule ((If pred inputs then else) (ContextOf pred ctx)) + ((ContextOf (If pred inputs then else) ctx)) :ruleset always-run) + +(rule ((If pred inputs then else) (ContextOf inputs ctx)) + ((ContextOf (If pred inputs then else) ctx)) :ruleset always-run) + +(rule ((DoWhile in pred-and-output) (ContextOf in ctx)) + ((ContextOf (DoWhile in pred-and-output) ctx)) :ruleset always-run) + +(rule ((Call func arg) (ContextOf arg ctx)) + ((ContextOf (Call func arg) ctx)) :ruleset always-run) + +(rule ((Alloc amt e state ty) (ContextOf e ctx)) + ((ContextOf (Alloc amt e state ty) ctx)) :ruleset always-run) + +(rule ((Alloc amt e state ty) (ContextOf state ctx)) + ((ContextOf (Alloc amt e state ty) ctx)) :ruleset always-run) + +(ruleset canon) + +; Commutativity +(rewrite (Bop (Add) x y) (Bop (Add) y x) :ruleset canon) +(rewrite (Bop (Mul) x y) (Bop (Mul) y x) :ruleset canon) +(rewrite (Bop (Eq) x y) (Bop (Eq) y x) :ruleset canon) +(rewrite (Bop (And) x y) (Bop (And) y x) :ruleset canon) +(rewrite (Bop (Or) x y) (Bop (Or) y x) :ruleset canon) + +; Canonicalize to < +; x > y ==> y < x +(rewrite (Bop (GreaterThan) x y) (Bop (LessThan) y x) :ruleset canon) + +; x >= y ==> y < x + 1 +; x >= y ==> y - 1 < x +(rule ( + (= lhs (Bop (GreaterEq) x y)) + (HasArgType x ty) + (ContextOf lhs ctx) + ) + ( + (union lhs (Bop (LessThan) y (Bop (Add) x (Const (Int 1) ty ctx)))) + (union lhs (Bop (LessThan) (Bop (Sub) y (Const (Int 1) ty ctx)) x)) + ) + :ruleset canon) + +; x <= y ==> x < y + 1 +; x <= y ==> x - 1 < y +(rule ( + (= lhs (Bop (LessEq) x y)) + (HasArgType y ty) + (ContextOf lhs ctx) + ) + ( + (union lhs (Bop (LessThan) x (Bop (Add) y (Const (Int 1) ty ctx)))) + (union lhs (Bop (LessThan) (Bop (Sub) x (Const (Int 1) ty ctx)) y)) + ) + :ruleset canon) + + +; Make Concats right-deep +(rewrite (Concat (Concat a b) c) + (Concat a (Concat b c)) + :ruleset always-run) +; Simplify Concat's with empty +(rewrite (Concat (Empty ty ctx) x) + x + :ruleset always-run) +(rewrite (Concat x (Empty ty ctx)) + x + :ruleset always-run) + +; Make a tuple that is a sub-range of another tuple +; tuple start len +(function SubTuple (Expr i64 i64) Expr :unextractable) + +(rewrite (SubTuple expr x 0) + (Empty ty ctx) + :when ((HasArgType expr ty) (ContextOf expr ctx)) + :ruleset always-run) + +(rewrite (SubTuple expr x 1) + (Single (Get expr x)) + :ruleset always-run) + +(rewrite (SubTuple expr a b) + (Concat (Single (Get expr a)) (SubTuple expr (+ a 1) (- b 1))) + :when ((> b 1)) + :ruleset always-run) + +; Helper functions to remove one element from a tuple or type list +; tuple idx +(function TupleRemoveAt (Expr i64) Expr :unextractable) +(function TypeListRemoveAt (TypeList i64) TypeList :unextractable) + +(rewrite (TupleRemoveAt tuple idx) + (Concat (SubTuple tuple 0 idx) + (SubTuple tuple (+ idx 1) (- len (+ idx 1)))) + :when ((= len (tuple-length tuple))) + :ruleset always-run) + +(rewrite (TypeListRemoveAt (TNil) _idx) (TNil) :ruleset always-run) +(rewrite (TypeListRemoveAt (TCons x xs) 0 ) xs :ruleset always-run) +(rewrite (TypeListRemoveAt (TCons x xs) idx) + (TCons x (TypeListRemoveAt xs (- idx 1))) + :when ((> idx 0)) + :ruleset always-run) + +;; Compute the tree size of program, not dag size +(function Expr-size (Expr) i64 :unextractable :merge (min old new) ) +(function ListExpr-size (ListExpr) i64 :unextractable :merge (min old new)) + +(rule ((= expr (Function name tyin tyout out)) + (= sum (Expr-size out))) + ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) + +(rule ((= expr (Const n ty assum))) + ((set (Expr-size expr) 1)) :ruleset always-run) + +(rule ((= expr (Bop op x y)) + (= sum (+ (Expr-size y) (Expr-size x)))) + ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) + +(rule ((= expr (Uop op x)) + (= sum (Expr-size x))) + ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) + +(rule ((= expr (Get tup i)) + (= sum (Expr-size tup))) + ((set (Expr-size expr) sum)) :ruleset always-run) + +(rule ((= expr (Concat x y)) + (= sum (+ (Expr-size y) (Expr-size x)))) + ((set (Expr-size expr) sum)) :ruleset always-run) + +(rule ((= expr (Single x)) + (= sum (Expr-size x))) + ((set (Expr-size expr) sum)) :ruleset always-run) + +(rule ((= expr (Switch pred inputs branches)) + (= sum (+ (Expr-size inputs) (+ (ListExpr-size branches) (Expr-size pred))))) + ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) + +(rule ((= expr (If pred inputs then else)) + (= sum (+ (Expr-size inputs) (+ (Expr-size else) (+ (Expr-size then) (Expr-size pred)))))) + ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) + +(rule ((= expr (DoWhile in pred-and-output)) + (= sum (+ (Expr-size pred-and-output) (Expr-size in)))) + ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) + +(rule ((= expr (Arg ty assum))) + ((set (Expr-size expr) 1)) :ruleset always-run) + +(rule ((= expr (Call func arg)) + (= sum (Expr-size arg))) + ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) + +(rule ((Empty ty assum)) ((set (Expr-size (Empty ty assum)) 0)) :ruleset always-run) + +(rule ((= expr (Cons hd tl)) + (= sum (+ (ListExpr-size tl) (Expr-size hd)))) + ((set (ListExpr-size expr) sum)) :ruleset always-run) + +(rule ((Nil)) + ((set (ListExpr-size (Nil)) 0)) :ruleset always-run) + +(rule ((= expr (Alloc id e state ty)) ;; do state edge's expr should be counted? + (= sum (Expr-size e))) + ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) +;; Like Subst but for dropping inputs to a region +;; See subst.egg for more implementation documentation + +(ruleset drop) +(ruleset apply-drop-unions) +(ruleset cleanup-drop) + +;; (DropAt ctx idx in) removes all references to `(Get (Arg ...) idx)` in `in`. +;; It also replaces the leaf contexts with `ctx` and fixes up argument types, +;; as well as updating `(Get (Arg ...) j)` to `(Get (Arg ...) (- j 1))` for j > idx. +(function DropAt (Assumption i64 Expr) Expr :unextractable) +(function DelayedDropUnion (Expr Expr) Expr :unextractable) + +;; Helper that precomputes the arg type that we need +(function DropAtInternal (Type Assumption i64 Expr) Expr :unextractable) +(rule ((= lhs (DropAt ctx idx in)) + (HasArgType in (TupleT oldty))) + + ((let newty (TupleT (TypeListRemoveAt oldty idx))) + (union lhs (DropAtInternal newty ctx idx in))) + :ruleset drop) + +;; Leaves +(rule ((= lhs (DropAtInternal newty newctx idx (Const c oldty oldctx)))) + ((DelayedDropUnion lhs (Const c newty newctx))) + :ruleset drop) +(rule ((= lhs (DropAtInternal newty newctx idx (Empty oldty oldctx)))) + ((DelayedDropUnion lhs (Empty newty newctx))) + :ruleset drop) +; get stuck on purpose if `i = idx` or if we find a bare `Arg` +(rule ((= lhs (DropAtInternal newty newctx idx (Get (Arg oldty oldctx) i))) + (< i idx)) + ((DelayedDropUnion lhs (Get (Arg newty newctx) i))) + :ruleset drop) +(rule ((= lhs (DropAtInternal newty newctx idx (Get (Arg oldty oldctx) i))) + (> i idx)) + ((DelayedDropUnion lhs (Get (Arg newty newctx) (- i 1)))) + :ruleset drop) + +;; Operators +(rule ((= lhs (DropAtInternal newty newctx idx (Bop op c1 c2))) + (ExprIsResolved (Bop op c1 c2))) + ((DelayedDropUnion lhs (Bop op + (DropAtInternal newty newctx idx c1) + (DropAtInternal newty newctx idx c2)))) + :ruleset drop) + +(rule ((= lhs (DropAtInternal newty newctx idx (Uop op c1))) + (ExprIsResolved (Uop op c1))) + ((DelayedDropUnion lhs (Uop op + (DropAtInternal newty newctx idx c1)))) + :ruleset drop) + +;; this is okay because we get stuck at `Arg`s +(rule ((= lhs (DropAtInternal newty newctx idx (Get c1 index))) + (ExprIsResolved (Get c1 index))) + ((DelayedDropUnion lhs (Get + (DropAtInternal newty newctx idx c1) + index))) + :ruleset drop) + +(rule ((= lhs (DropAtInternal newty newctx idx (Alloc id c1 c2 ty))) + (ExprIsResolved (Alloc id c1 c2 ty))) + ((DelayedDropUnion lhs (Alloc id + (DropAtInternal newty newctx idx c1) + (DropAtInternal newty newctx idx c2) + ty))) + :ruleset drop) + +(rule ((= lhs (DropAtInternal newty newctx idx (Call name c1))) + (ExprIsResolved (Call name c1))) + ((DelayedDropUnion lhs (Call name + (DropAtInternal newty newctx idx c1)))) + :ruleset drop) + +;; Tuple operators +(rule ((= lhs (DropAtInternal newty newctx idx (Single c1))) + (ExprIsResolved (Single c1))) + ((DelayedDropUnion lhs (Single + (DropAtInternal newty newctx idx c1)))) + :ruleset drop) + +(rule ((= lhs (DropAtInternal newty newctx idx (Concat c1 c2))) + (ExprIsResolved (Concat c1 c2))) + ((DelayedDropUnion lhs (Concat + (DropAtInternal newty newctx idx c1) + (DropAtInternal newty newctx idx c2)))) + :ruleset drop) + +;; Control flow +(rule ((= lhs (DropAtInternal newty newctx idx (Switch pred inputs c1))) + (ExprIsResolved (Switch pred inputs c1))) + ((DelayedDropUnion lhs (Switch + (DropAtInternal newty newctx idx pred) + (DropAtInternal newty newctx idx inputs) + c1))) + :ruleset drop) + +(rule ((= lhs (DropAtInternal newty newctx idx (If pred inputs c1 c2))) + (ExprIsResolved (If pred inputs c1 c2))) + ((DelayedDropUnion lhs (If + (DropAtInternal newty newctx idx pred) + (DropAtInternal newty newctx idx inputs) + c1 + c2))) + :ruleset drop) + +(rule ((= lhs (DropAtInternal newty newctx idx (DoWhile in out))) + (ExprIsResolved (DoWhile in out))) + ((DelayedDropUnion lhs (DoWhile + (DropAtInternal newty newctx idx in) + out))) + :ruleset drop) + +(rewrite (DropAtInternal newty newctx idx (Function name inty outty body)) + (Function name inty outty (DropAtInternal newty newctx idx body)) + :when ((ExprIsResolved body)) + :ruleset drop) + + + +;; ########################### Apply drop unions + +(rule ((DelayedDropUnion lhs rhs)) + ((union lhs rhs)) + :ruleset apply-drop-unions) + +;; ########################### Cleanup Dropat, DropAtInternal and DelayedDropUnion + +(rule ((ExprIsResolved (DropAt newctx idx in))) + ((subsume (DropAt newctx idx in))) + :ruleset cleanup-drop) + +(rule ((ExprIsResolved (DropAtInternal newty newctx idx in))) + ((subsume (DropAtInternal newty newctx idx in))) + :ruleset cleanup-drop) + +(rule ((DelayedDropUnion lhs rhs)) + ((subsume (DelayedDropUnion lhs rhs))) + :ruleset cleanup-drop) + +(ruleset interval-analysis) + +(datatype Bound + (IntB i64) + (BoolB bool) + (bound-max Bound Bound) + (bound-min Bound Bound)) + +; bound tables +(function lo-bound (Expr) Bound :unextractable :merge (bound-max old new)) +(function hi-bound (Expr) Bound :unextractable :merge (bound-min old new)) + +; if lo > hi, panic +; We can't run these rules because unreachable branches may have impossible intervals +; Consider re-enabling these rules if we implement an is-reachable analysis +; (rule ( +; (= (IntB lo) (lo-bound expr)) +; (= (IntB hi) (hi-bound expr)) +; (> lo hi) +; ) +; ((panic "lo bound greater than hi bound")) +; :ruleset interval-analysis) +; (rule ( +; (= (BoolB true) (lo-bound expr)) +; (= (BoolB false) (hi-bound expr)) +; ) +; ((panic "lo bound greater than hi bound")) +; :ruleset interval-analysis) + +; combinators +(rewrite (bound-max (IntB x) (IntB y)) + (IntB (max x y)) + :ruleset interval-analysis) +(rewrite (bound-min (IntB x) (IntB y)) + (IntB (min x y)) + :ruleset interval-analysis) +(rewrite (bound-max (BoolB x) (BoolB y)) + (BoolB (or x y)) + :ruleset interval-analysis) +(rewrite (bound-min (BoolB x) (BoolB y)) + (BoolB (and x y)) + :ruleset interval-analysis) + +; ================================= +; Constants +; ================================= +(rule ((= lhs (Const (Int x) ty ctx))) + ( + (set (lo-bound lhs) (IntB x)) + (set (hi-bound lhs) (IntB x)) + ) + :ruleset interval-analysis) + +(rule ((= lhs (Const (Bool x) ty ctx))) + ( + (set (lo-bound lhs) (BoolB x)) + (set (hi-bound lhs) (BoolB x)) + ) + :ruleset interval-analysis) + +; ================================= +; Constant Folding +; ================================= +(rule ( + (= (IntB x) (lo-bound expr)) + (= (IntB x) (hi-bound expr)) + (HasArgType expr ty) + (ContextOf expr ctx) + ) + ((union expr (Const (Int x) ty ctx))) + :ruleset interval-analysis) + +(rule ( + (= (BoolB x) (lo-bound expr)) + (= (BoolB x) (hi-bound expr)) + (HasArgType expr ty) + (ContextOf expr ctx) + ) + ((union expr (Const (Bool x) ty ctx))) + :ruleset interval-analysis) + +; lower bound being true means the bool must be true +(rule ( + (= (BoolB true) (lo-bound expr)) + (HasArgType expr ty) + (ContextOf expr ctx) + ) + ((union expr (Const (Bool true) ty ctx))) + :ruleset interval-analysis) + +; upper bound being false means the bool must be false +(rule ( + (= (BoolB false) (hi-bound expr)) + (HasArgType expr ty) + (ContextOf expr ctx) + ) + ((union expr (Const (Bool false) ty ctx))) + :ruleset interval-analysis) + +; ================================= +; Arithmetic +; ================================= +; + a b interval is (+ la lb) (+ ha hb) +(rule ( + (= lhs (Bop (Add) a b)) + (= (IntB la) (lo-bound a)) + (= (IntB lb) (lo-bound b)) + ) + ((set (lo-bound lhs) (IntB (+ la lb)))) + :ruleset interval-analysis) +(rule ( + (= lhs (Bop (Add) a b)) + (= (IntB ha) (hi-bound a)) + (= (IntB hb) (hi-bound b)) + ) + ((set (hi-bound lhs) (IntB (+ ha hb)))) + :ruleset interval-analysis) + +; - a b interval is (- la hb) (- ha lb) +(rule ( + (= lhs (Bop (Sub) a b)) + (= (IntB la) (lo-bound a)) + (= (IntB hb) (hi-bound b)) + ) + ((set (lo-bound lhs) (IntB (- la hb)))) + :ruleset interval-analysis) +(rule ( + (= lhs (Bop (Sub) a b)) + (= (IntB ha) (hi-bound a)) + (= (IntB lb) (lo-bound b)) + ) + ((set (hi-bound lhs) (IntB (- ha lb)))) + :ruleset interval-analysis) + +; Multiplication for two constants +; TODO: Make fancier interval analysis +(rule ( + (= lhs (Bop (Mul) a b)) + (= (IntB x) (lo-bound a)) + (= (IntB x) (hi-bound a)) + (= (IntB y) (lo-bound b)) + (= (IntB y) (hi-bound b)) + ) + ( + (set (lo-bound lhs) (IntB (* x y))) + (set (hi-bound lhs) (IntB (* x y))) + ) + :ruleset interval-analysis) + +; negative * negative is positive +(rule ( + (= lhs (Bop (Mul) x y)) + (= (IntB hi-x) (hi-bound x)) + (= (IntB hi-y) (hi-bound y)) + (<= hi-x 0) + (<= hi-y 0) + ) + ((set (lo-bound lhs) (IntB 0))) + :ruleset interval-analysis) + +; negative * positive is negative +(rule ( + (= lhs (Bop (Mul) x y)) + (= (IntB hi-x) (hi-bound x)) + (= (IntB lo-y) (lo-bound y)) + (<= hi-x 0) ; x <= 0 (x is negative) + (>= lo-y 0) ; y >= 0 (y is positive) + ) + ((set (hi-bound lhs) (IntB 0))) + :ruleset interval-analysis) + +; positive * positive is positive +(rule ( + (= lhs (Bop (Mul) x y)) + (= (IntB lo-x) (lo-bound x)) + (= (IntB lo-y) (lo-bound y)) + (>= lo-x 0) + (>= lo-y 0) + ) + ((set (lo-bound lhs) (IntB 0))) + :ruleset interval-analysis) + +; < a b interval is (< ha lb) (< la hb) +(rule ( + (= lhs (Bop (LessThan) a b)) + (= (IntB ha) (hi-bound a)) + (= (IntB lb) (lo-bound b)) + ) + ( + (set (lo-bound lhs) (BoolB (bool-< ha lb))) + ) + :ruleset interval-analysis) +(rule ( + (= lhs (Bop (LessThan) a b)) + (= (IntB la) (lo-bound a)) + (= (IntB hb) (hi-bound b)) + ) + ((set (hi-bound lhs) (BoolB (bool-< la hb)))) + :ruleset interval-analysis) + +; ================================= +; Conditionals +; ================================= +; if the predicate is true, merge with then branch +(rule ( + (= lhs (If cond inputs thn els)) + (ContextOf lhs if_ctx) + (= (BoolB true) (lo-bound cond)) + ) + ((union lhs (Subst if_ctx inputs thn))) + :ruleset interval-analysis) + +; if the predicate is false, merge with else branch +(rule ( + (= lhs (If cond inputs thn els)) + (ContextOf lhs if_ctx) + (= (BoolB false) (hi-bound cond)) + ) + ((union lhs (Subst if_ctx inputs els))) + :ruleset interval-analysis) + +; lo-bound of If is the min of the lower bounds +; hi-bound of If is the max of the upper bounds +(rule ( + (= lhs (If cond inputs thn els)) + (= lo-thn (lo-bound thn)) + (= lo-els (lo-bound els)) + ) + ((set (lo-bound lhs) (bound-min lo-thn lo-els))) + :ruleset interval-analysis) +(rule ( + (= lhs (If cond inputs thn els)) + (= hi-thn (hi-bound thn)) + (= hi-els (hi-bound els)) + ) + ((set (hi-bound lhs) (bound-max hi-thn hi-els))) + :ruleset interval-analysis) + +; Same rules, but for Ifs that have multiple outputs +(rule ( + (= lhs (Get (If pred inputs thn els) i)) + (= lo-thn (lo-bound (Get thn i))) + (= lo-els (lo-bound (Get els i))) + ) + ((set (lo-bound lhs) (bound-min lo-thn lo-els))) + :ruleset interval-analysis) +(rule ( + (= lhs (Get (If cond inputs thn els) i)) + (= hi-thn (hi-bound (Get thn i))) + (= hi-els (hi-bound (Get els i))) + ) + ((set (hi-bound lhs) (bound-max hi-thn hi-els))) + :ruleset interval-analysis) + +; If the If takes a tuple +(rule ( + ; expr < value + (= pred (Bop (LessThan) expr value)) + (= if_e (If pred inputs then else)) + ; the left operand of the < is an input to the if region + (= expr (Get inputs i)) + ; the right operand of the < has an upper bound + (= (IntB v) (hi-bound value)) + ; context node inside the if region + (= ctx (Arg ty (InIf true pred inputs))) + (HasType inputs ty) + ) + ; expr < value was true, so we know expr is at most (hi-bound value) - 1 + ((set (hi-bound (Get ctx i)) (IntB (- v 1)))) + :ruleset interval-analysis) +(rule ( + ; expr < value + (= pred (Bop (LessThan) expr value)) + (= if_e (If pred inputs then else)) + ; the left operand of the < is an input to the if region + (= expr (Get inputs i)) + ; the right operand of the < has a lower bound + (= (IntB v) (lo-bound value)) + ; context node inside the if region + (= ctx (Arg ty (InIf false pred inputs))) + (HasType inputs ty) + ) + ; expr < value was false, so we know expr is at least (lo-bound value) + ((set (lo-bound (Get ctx i)) (IntB v))) + :ruleset interval-analysis) + +(rule ( + ; value < expr + (= pred (Bop (LessThan) value expr)) + (= if_e (If pred inputs then else)) + ; the right operand of the < is an input to the if region + (= expr (Get inputs i)) + ; the left operand of the < has a lower bound + (= (IntB v) (lo-bound value)) + ; context node inside the if region + (= ctx (Arg ty (InIf true pred inputs))) + (HasType inputs ty) + ) + ; value < expr was true, so we know expr is at least (lo-bound value) + 1 + ((set (lo-bound (Get ctx i)) (IntB (+ v 1)))) + :ruleset interval-analysis) +(rule ( + ; value < expr + (= pred (Bop (LessThan) value expr)) + (= if_e (If pred inputs then else)) + ; the right operand of the < is an input to the if region + (= expr (Get inputs i)) + ; the left operand of the < has an upper bound + (= (IntB v) (hi-bound value)) + ; context node inside the if region + (= ctx (Arg ty (InIf false pred inputs))) + (HasType inputs ty) + ) + ; value < expr was false, so we know expr is at most (hi-bound value) + ((set (hi-bound (Get ctx i)) (IntB v))) + :ruleset interval-analysis) + +;; Push intervals for inputs into if region +(rule ( + (= if (If pred inputs then_ else_)) + (= ctx (Arg ty (InIf b pred inputs))) + (HasType inputs ty) + (= lo (lo-bound (Get inputs i))) + + ) + ((set (lo-bound (Get ctx i)) lo)) + :ruleset interval-analysis) +(rule ( + (= if (If pred inputs then_ else_)) + (= ctx (Arg ty (InIf b pred inputs))) + (HasType inputs ty) + (= hi (hi-bound (Get inputs i))) + + ) + ((set (hi-bound (Get ctx i)) hi)) + :ruleset interval-analysis) + +; (if (a == b) thn els) +; in the thn branch, we know that a has the same bounds as b +(rule ( + (= pred (Bop (Eq) expr val)) + (= if_e (If pred inputs thn els)) + ; the left operand of the == is an input to the if region + (= expr (Get inputs i)) + (= ctx (Arg ty (InIf true pred inputs))) + (HasType inputs ty) + (= (IntB lo) (lo-bound val)) + ) + ((set (lo-bound (Get ctx i)) (IntB lo))) + :ruleset interval-analysis) +(rule ( + (= pred (Bop (Eq) expr val)) + (= if_e (If pred inputs thn els)) + ; the left operand of the == is an input to the if region + (= expr (Get inputs i)) + (= ctx (Arg ty (InIf true pred inputs))) + (HasType inputs ty) + (= (IntB hi) (hi-bound val)) + ) + ((set (hi-bound (Get ctx i)) (IntB hi))) + :ruleset interval-analysis) + + +(rule ( + ;; argument has loop context + (Arg ty (InLoop inputs outputs)) + ;; in the loop, the argument is passed through + ;; note that some_ctx is not the same as (InLoop inputs outputs) + (= (Get (Arg ty some_ctx) ith) (Get outputs (+ 1 ith))) + ;; input has some bound + (= bound (lo-bound (Get inputs ith))) + ) + ( + (set (lo-bound (Get (Arg ty (InLoop inputs outputs)) ith)) bound) + ) + :ruleset interval-analysis) +(rule ( + ;; argument has loop context + (Arg ty (InLoop inputs outputs)) + ;; in the loop, the argument is passed through + (= (Get (Arg ty some_ctx) ith) (Get outputs (+ 1 ith))) + ;; input has some bound + (= bound (hi-bound (Get inputs ith))) + ) + ( + (set (hi-bound (Get (Arg ty (InLoop inputs outputs)) ith)) bound) + ) + :ruleset interval-analysis) + + +(ruleset switch_rewrite) + +; if (a and b) X Y ~~> if a (if b X Y) Y +(rule ((= lhs (If (Bop (And) a b) ins X Y)) + (HasType ins (TupleT ins_ty)) + (= len (tuple-length ins))) + + ((let outer_ins (Concat (Single b) ins)) + (let outer_ins_ty (TupleT (TCons (BoolT) ins_ty))) + + (let inner_pred (Get (Arg outer_ins_ty (InIf true a outer_ins)) 0)) + (let sub_arg_true (SubTuple (Arg outer_ins_ty (InIf true a outer_ins)) 1 len)) + (let sub_arg_false (SubTuple (Arg outer_ins_ty (InIf false a outer_ins)) 1 len)) + + (let inner_X (AddContext (InIf true inner_pred sub_arg_true) X)) + (let inner_Y (AddContext (InIf false inner_pred sub_arg_true) Y)) + (let outer_Y (Subst (InIf false a outer_ins) sub_arg_false Y)) + + (let inner (If inner_pred sub_arg_true inner_X inner_Y)) + (union lhs (If a outer_ins inner outer_Y))) + + :ruleset switch_rewrite) + +; if (a or b) X Y ~~> if a X (if b X Y) +(rule ((= lhs (If (Bop (Or) a b) ins X Y)) + (HasType ins (TupleT ins_ty)) + (= len (tuple-length ins))) + + ((let outer_ins (Concat (Single b) ins)) + (let outer_ins_ty (TupleT (TCons (BoolT) ins_ty))) + + (let inner_pred (Get (Arg outer_ins_ty (InIf false a outer_ins)) 0)) + (let sub_arg_true (SubTuple (Arg outer_ins_ty (InIf true a outer_ins)) 1 len)) + (let sub_arg_false (SubTuple (Arg outer_ins_ty (InIf false a outer_ins)) 1 len)) + + (let outer_X (Subst (InIf true a outer_ins) sub_arg_true X)) + (let inner_X (AddContext (InIf true inner_pred sub_arg_false) X)) + (let inner_Y (AddContext (InIf false inner_pred sub_arg_false) Y)) + + (let inner (If inner_pred sub_arg_false inner_X inner_Y)) + (union lhs (If a outer_ins outer_X inner ))) + + :ruleset switch_rewrite) + +(rewrite (If (Const (Bool true) ty ctx) ins thn els) + (Subst ctx ins thn) + :ruleset always-run) + +(rewrite (If (Const (Bool false) ty ctx) ins thn els) + (Subst ctx ins els) + :ruleset switch_rewrite) + +(rule ((= lhs (If pred ins thn els)) + (= (Get thn i) (Const (Bool true) ty ctx1)) + (= (Get els i) (Const (Bool false) ty ctx2))) + ((union (Get lhs i) pred)) :ruleset switch_rewrite) + +(rule ((= lhs (If pred ins thn els)) + (= (Get thn i) (Const (Bool false) ty ctx1)) + (= (Get els i) (Const (Bool true) ty ctx2))) + ((union (Get lhs i) (Uop (Not) pred))) :ruleset switch_rewrite) + +; Simple rewrites that don't do a ton with control flow. + +(ruleset peepholes) + +(rewrite (Bop (Mul) (Const (Int 0) ty ctx) e) (Const (Int 0) ty ctx) :ruleset peepholes) +(rewrite (Bop (Mul) e (Const (Int 0) ty ctx)) (Const (Int 0) ty ctx) :ruleset peepholes) +(rewrite (Bop (Mul) (Const (Int 1) ty ctx) e) e :ruleset peepholes) +(rewrite (Bop (Mul) e (Const (Int 1) ty ctx)) e :ruleset peepholes) +(rewrite (Bop (Add) (Const (Int 0) ty ctx) e) e :ruleset peepholes) +(rewrite (Bop (Add) e (Const (Int 0) ty ctx) ) e :ruleset peepholes) + +(rewrite (Bop (Mul) (Const (Int j) ty ctx) (Const (Int i) ty ctx)) (Const (Int (* i j)) ty ctx) :ruleset peepholes) +(rewrite (Bop (Add) (Const (Int j) ty ctx) (Const (Int i) ty ctx)) (Const (Int (+ i j)) ty ctx) :ruleset peepholes) + +(rewrite (Bop (And) (Const (Bool true) ty ctx) e) e :ruleset peepholes) +(rewrite (Bop (And) e (Const (Bool true) ty ctx)) e :ruleset peepholes) +(rewrite (Bop (And) (Const (Bool false) ty ctx) e) (Const (Bool false) ty ctx) :ruleset peepholes) +(rewrite (Bop (And) e (Const (Bool false) ty ctx)) (Const (Bool false) ty ctx) :ruleset peepholes) +(rewrite (Bop (Or) (Const (Bool false) ty ctx) e) e :ruleset peepholes) +(rewrite (Bop (Or) e (Const (Bool false) ty ctx)) e :ruleset peepholes) +(rewrite (Bop (Or) (Const (Bool true) ty ctx) e) (Const (Bool true) ty ctx) :ruleset peepholes) +(rewrite (Bop (Or) e (Const (Bool true) ty ctx)) (Const (Bool true) ty ctx) :ruleset peepholes) + + +(datatype IntOrInfinity + (Infinity) + (NegInfinity) + (I i64)) + +(function MaxIntOrInfinity (IntOrInfinity IntOrInfinity) IntOrInfinity) +(rewrite (MaxIntOrInfinity (Infinity) _) (Infinity) :ruleset always-run) +(rewrite (MaxIntOrInfinity _ (Infinity)) (Infinity) :ruleset always-run) +(rewrite (MaxIntOrInfinity (NegInfinity) x) x :ruleset always-run) +(rewrite (MaxIntOrInfinity x (NegInfinity)) x :ruleset always-run) +(rewrite (MaxIntOrInfinity (I x) (I y)) (I (max x y)) :ruleset always-run) + +(function MinIntOrInfinity (IntOrInfinity IntOrInfinity) IntOrInfinity) +(rewrite (MinIntOrInfinity (NegInfinity) _) (NegInfinity) :ruleset always-run) +(rewrite (MinIntOrInfinity _ (NegInfinity)) (NegInfinity) :ruleset always-run) +(rewrite (MinIntOrInfinity (Infinity) x) x :ruleset always-run) +(rewrite (MinIntOrInfinity x (Infinity)) x :ruleset always-run) +(rewrite (MinIntOrInfinity (I x) (I y)) (I (min x y)) :ruleset always-run) + +(function AddIntOrInfinity (IntOrInfinity IntOrInfinity) IntOrInfinity) +(rewrite (AddIntOrInfinity (Infinity) (Infinity)) (Infinity) :ruleset always-run) +(rewrite (AddIntOrInfinity (Infinity) (I _)) (Infinity) :ruleset always-run) +(rewrite (AddIntOrInfinity (I _) (Infinity)) (Infinity) :ruleset always-run) +(rewrite (AddIntOrInfinity (NegInfinity) (NegInfinity)) (NegInfinity) :ruleset always-run) +(rewrite (AddIntOrInfinity (NegInfinity) (I _)) (NegInfinity) :ruleset always-run) +(rewrite (AddIntOrInfinity (I _) (NegInfinity)) (NegInfinity) :ruleset always-run) +(rewrite (AddIntOrInfinity (I x) (I y)) (I (+ x y)) :ruleset always-run) + +(datatype IntInterval (MkIntInterval IntOrInfinity IntOrInfinity)) + +(function UnionIntInterval (IntInterval IntInterval) IntInterval) +(rewrite (UnionIntInterval (MkIntInterval lo1 hi1) (MkIntInterval lo2 hi2)) + (MkIntInterval (MinIntOrInfinity lo1 lo2) (MaxIntOrInfinity hi1 hi2)) + :ruleset always-run) + +(function IntersectIntInterval (IntInterval IntInterval) IntInterval) +(rewrite (IntersectIntInterval (MkIntInterval lo1 hi1) (MkIntInterval lo2 hi2)) + (MkIntInterval (MaxIntOrInfinity lo1 lo2) (MinIntOrInfinity hi1 hi2)) + :ruleset always-run) + +(function AddIntInterval (IntInterval IntInterval) IntInterval) +(rewrite (AddIntInterval (MkIntInterval lo1 hi1) (MkIntInterval lo2 hi2)) + (MkIntInterval (AddIntOrInfinity lo1 lo2) + (AddIntOrInfinity hi1 hi2)) + :ruleset always-run) + + +(datatype List + (Nil-List) + (Cons-List i64 IntInterval List)) + +(function Length-List (List) i64) +(rule ((= x (Nil-List))) + ((set (Length-List x) 0)) + :ruleset always-run) +(rule ((= x (Cons-List hd0 hd1 tl)) + (= l (Length-List tl))) + ((set (Length-List x) (+ l 1))) + :ruleset always-run) +(rule ((= x (Nil-List))) + ((set (Length-List x) 0)) + :ruleset memory-helpers) +(rule ((= x (Cons-List hd0 hd1 tl)) + (= l (Length-List tl))) + ((set (Length-List x) (+ l 1))) + :ruleset memory-helpers) + +(relation IsEmpty-List (List)) +(rule ((= x (Nil-List))) + ((IsEmpty-List x)) + :ruleset always-run) + +(relation IsNonEmpty-List (List)) +(rule ((= x (Cons-List hd0 hd1 tl))) + ((IsNonEmpty-List x)) + :ruleset always-run) + +(function RevConcat-List (List List) List :cost 1000) +(rewrite (RevConcat-List (Nil-List) l) + l + :ruleset always-run) +(rewrite (RevConcat-List (Cons-List hd0 hd1 tl) l) + (RevConcat-List tl (Cons-List hd0 hd1 l)) + :ruleset always-run) + +(function Rev-List (List) List :cost 1000) +(rewrite (Rev-List m) + (RevConcat-List m (Nil-List)) + :ruleset always-run) + +(function Concat-List (List List) List :cost 1000) +(rewrite (Concat-List x y) + (RevConcat-List (Rev-List x) y) + :ruleset always-run) + +; SuffixAt and At must be demanded, otherwise these are O(N^2) +(relation DemandAt-List (List)) +(relation SuffixAt-List (List i64 List)) +(relation At-List (List i64 i64 IntInterval)) +(rule ((DemandAt-List x)) + ((SuffixAt-List x 0 x)) + :ruleset always-run) +(rule ((SuffixAt-List x i (Cons-List hd0 hd1 tl))) + ((SuffixAt-List x (+ i 1) tl) + (At-List x i hd0 hd1)) + :ruleset always-run) + +(function Union-List (List List) List) + ; The third argument of the helper is a WIP result map. + ; Invariant: keys of the result map are not present in the first two and are in descending order + (function UnionHelper-List (List List List) List) + (rewrite (Union-List m1 m2) + (Rev-List (UnionHelper-List m1 m2 (Nil-List))) + :ruleset always-run) + + ; both m1 and m2 empty + (rewrite (UnionHelper-List (Nil-List) (Nil-List) res) + res + :ruleset always-run) + ; take from m1 when m2 empty and vice versa + (rewrite + (UnionHelper-List + (Nil-List) + (Cons-List hd0 hd1 tl) + res) + (UnionHelper-List + (Nil-List) + tl + (Cons-List hd0 hd1 res)) + :ruleset always-run) + (rewrite + (UnionHelper-List + (Cons-List hd0 hd1 tl) + (Nil-List) + res) + (UnionHelper-List + tl + (Nil-List) + (Cons-List hd0 hd1 res)) + :ruleset always-run) + + ; when both nonempty and smallest key different, take smaller key + (rule ((= f (UnionHelper-List l1 l2 res)) + (= l1 (Cons-List k1 a1 tl1)) + (= l2 (Cons-List k2 b1 tl2)) + (< k1 k2)) + ((union f + (UnionHelper-List tl1 l2 (Cons-List k1 a1 res)))) + :ruleset always-run) + (rule ((= f (UnionHelper-List l1 l2 res)) + (= l1 (Cons-List k1 a1 tl1)) + (= l2 (Cons-List k2 b1 tl2)) + (< k2 k1)) + ((union f + (UnionHelper-List l1 tl2 (Cons-List k2 b1 res)))) + :ruleset always-run) + + ; when shared smallest key, union interval + (rule ((= f (UnionHelper-List l1 l2 res)) + (= l1 (Cons-List k a1 tl1)) + (= l2 (Cons-List k b1 tl2))) + ((union f + (UnionHelper-List tl1 tl2 + (Cons-List k (UnionIntInterval a1 b1) res)))) + :ruleset always-run) + +(function Intersect-List (List List) List) + ; The third argument of the helper is a WIP result map. + ; Invariant: keys of the result map are not present in the first two and are in descending order + (function IntersectHelper-List (List List List) List) + (rewrite (Intersect-List m1 m2) + (Rev-List (IntersectHelper-List m1 m2 (Nil-List))) + :ruleset always-run) + + ; m1 or m2 empty + (rewrite (IntersectHelper-List (Nil-List) m2 res) + res + :ruleset always-run) + (rewrite (IntersectHelper-List m1 (Nil-List) res) + res + :ruleset always-run) + + ; when both nonempty and smallest key different, drop smaller key + (rule ((= f (IntersectHelper-List l1 l2 res)) + (= l1 (Cons-List k1 a1 tl1)) + (= l2 (Cons-List k2 b1 tl2)) + (< k1 k2)) + ((union f (IntersectHelper-List tl1 l2 res))) + :ruleset always-run) + (rule ((= f (IntersectHelper-List l1 l2 res)) + (= l1 (Cons-List k1 a1 tl1)) + (= l2 (Cons-List k2 b1 tl2)) + (< k2 k1)) + ((union f (IntersectHelper-List tl1 l2 res))) + :ruleset always-run) + +(datatype MyBool (MyTrue) (MyFalse)) + +(function IntIntervalValid (IntInterval) MyBool) +(rewrite (IntIntervalValid (MkIntInterval (I lo) (I hi))) + (MyTrue) + :when ((<= lo hi)) + :ruleset always-run) +(rewrite (IntIntervalValid (MkIntInterval (I lo) (I hi))) + (MyFalse) + :when ((> lo hi)) + :ruleset always-run) +(rewrite (IntIntervalValid (MkIntInterval (NegInfinity) _)) + (MyTrue) + :ruleset always-run) +(rewrite (IntIntervalValid (MkIntInterval _ (Infinity))) + (MyTrue) + :ruleset always-run) + +(function ConsIfNonEmpty (i64 IntInterval List) + List + :cost 100) +(rule ((ConsIfNonEmpty k v tl)) + ((IntIntervalValid v)) + :ruleset always-run) +(rule ((= f (ConsIfNonEmpty k v tl)) + (= (MyTrue) (IntIntervalValid v))) + ((union f (Cons-List k v tl))) + :ruleset always-run) +(rule ((= f (ConsIfNonEmpty k v tl)) + (= (MyFalse) (IntIntervalValid v))) + ((union f tl)) + :ruleset always-run) + + ; when shared smallest key, intersect interval + (rule ((= f (IntersectHelper-List l1 l2 res)) + (= l1 (Cons-List k a1 tl1)) + (= l2 (Cons-List k b1 tl2))) + ((union f + (IntersectHelper-List tl1 tl2 + (ConsIfNonEmpty k (IntersectIntInterval a1 b1) res)))) + :ruleset always-run) + +(function AddIntIntervalToAll (IntInterval List) + List) +(rewrite (AddIntIntervalToAll _ (Nil-List)) + (Nil-List) + :ruleset always-run) +(rewrite (AddIntIntervalToAll x (Cons-List allocid offset tl)) + (Cons-List allocid (AddIntInterval x offset) + (AddIntIntervalToAll x tl)) + :ruleset always-run) + +(datatype PtrPointees + (PointsTo List) + (PointsAnywhere)) + +(function AddIntIntervalToPtrPointees (IntInterval PtrPointees) PtrPointees) +(rewrite (AddIntIntervalToPtrPointees interval (PointsAnywhere)) + (PointsAnywhere) + :ruleset always-run) +(rewrite (AddIntIntervalToPtrPointees interval (PointsTo l)) + (PointsTo (AddIntIntervalToAll interval l)) + :ruleset always-run) + +(function Union-PtrPointees (PtrPointees PtrPointees) PtrPointees) +(rewrite (Union-PtrPointees (PointsAnywhere) _) + (PointsAnywhere) + :ruleset always-run) +(rewrite (Union-PtrPointees _ (PointsAnywhere)) + (PointsAnywhere) + :ruleset always-run) +(rewrite (Union-PtrPointees (PointsTo x) (PointsTo y)) + (PointsTo (Union-List x y)) + :ruleset always-run) +(function Intersect-PtrPointees (PtrPointees PtrPointees) PtrPointees) +(rewrite (Intersect-PtrPointees (PointsAnywhere) x) + x + :ruleset always-run) +(rewrite (Intersect-PtrPointees x (PointsAnywhere)) + x + :ruleset always-run) +(rewrite (Intersect-PtrPointees (PointsTo x) (PointsTo y)) + (PointsTo (Intersect-List x y)) + :ruleset always-run) + +(relation PointsNowhere-PtrPointees (PtrPointees)) +(rule ((= f (PointsTo x)) + (IsEmpty-List x)) + ((PointsNowhere-PtrPointees f)) + :ruleset always-run) + + +(datatype List + (Nil-List) + (Cons-List PtrPointees List)) + +(function Length-List (List) i64) +(rule ((= x (Nil-List))) + ((set (Length-List x) 0)) + :ruleset always-run) +(rule ((= x (Cons-List hd0 tl)) + (= l (Length-List tl))) + ((set (Length-List x) (+ l 1))) + :ruleset always-run) +(rule ((= x (Nil-List))) + ((set (Length-List x) 0)) + :ruleset memory-helpers) +(rule ((= x (Cons-List hd0 tl)) + (= l (Length-List tl))) + ((set (Length-List x) (+ l 1))) + :ruleset memory-helpers) + +(relation IsEmpty-List (List)) +(rule ((= x (Nil-List))) + ((IsEmpty-List x)) + :ruleset always-run) + +(relation IsNonEmpty-List (List)) +(rule ((= x (Cons-List hd0 tl))) + ((IsNonEmpty-List x)) + :ruleset always-run) + +(function RevConcat-List (List List) List :cost 1000) +(rewrite (RevConcat-List (Nil-List) l) + l + :ruleset always-run) +(rewrite (RevConcat-List (Cons-List hd0 tl) l) + (RevConcat-List tl (Cons-List hd0 l)) + :ruleset always-run) + +(function Rev-List (List) List :cost 1000) +(rewrite (Rev-List m) + (RevConcat-List m (Nil-List)) + :ruleset always-run) + +(function Concat-List (List List) List :cost 1000) +(rewrite (Concat-List x y) + (RevConcat-List (Rev-List x) y) + :ruleset always-run) + +; SuffixAt and At must be demanded, otherwise these are O(N^2) +(relation DemandAt-List (List)) +(relation SuffixAt-List (List i64 List)) +(relation At-List (List i64 PtrPointees)) +(rule ((DemandAt-List x)) + ((SuffixAt-List x 0 x)) + :ruleset always-run) +(rule ((SuffixAt-List x i (Cons-List hd0 tl))) + ((SuffixAt-List x (+ i 1) tl) + (At-List x i hd0)) + :ruleset always-run) + +(relation All (List)) +(rule ((= x (Nil-List))) + ((All x)) + :ruleset always-run) +(rule ((= x (Cons-List hd0 tl)) + (PointsNowhere-PtrPointees hd0) + (All tl)) + ((All x)) + :ruleset always-run) + + + +(function Zip (List List) List :cost 1000) +(rewrite (Zip (Nil-List) (Nil-List)) + (Nil-List) + :ruleset always-run) +(rewrite (Zip + (Cons-List x0 tl1) + (Cons-List y0 tl2)) + (Cons-List + (Union-PtrPointees x0 y0) + (Zip tl1 tl2)) + :when ((= (Length-List tl1) (Length-List tl2))) + :ruleset always-run) + +(function Zip (List List) List :cost 1000) +(rewrite (Zip (Nil-List) (Nil-List)) + (Nil-List) + :ruleset always-run) +(rewrite (Zip + (Cons-List x0 tl1) + (Cons-List y0 tl2)) + (Cons-List + (Intersect-PtrPointees x0 y0) + (Zip tl1 tl2)) + :ruleset always-run) + + +(sort ExprSetPrim (Set Expr)) + +(datatype ExprSet (ES ExprSetPrim)) + +(function ExprSet-intersect (ExprSet ExprSet) ExprSet) +(rewrite (ExprSet-intersect (ES set1) (ES set2)) (ES (set-intersect set1 set2)) + :ruleset memory-helpers) +(function ExprSet-union (ExprSet ExprSet) ExprSet) +(rewrite (ExprSet-union (ES set1) (ES set2)) (ES (set-union set1 set2)) + :ruleset memory-helpers) +(relation ExprSet-contains (ExprSet Expr)) +(rule ((ES set1) (set-contains set1 x)) + ((ExprSet-contains (ES set1) x)) + :ruleset memory-helpers) +(function ExprSet-insert (ExprSet Expr) ExprSet) +(rewrite (ExprSet-insert (ES set1) x) + (ES (set-insert set1 x)) + :ruleset memory-helpers) +(function ExprSet-length (ExprSet) i64) +(rewrite (ExprSet-length (ES set1)) (set-length set1) :ruleset memory-helpers) + +; ============================ +; Pointees +; ============================ + + +; List is used as an association list; the i64 keys +; (corresponding to alloc ids) are always unique and sorted, the IntInterval +; values correspond to offset ranges. +; +; (TuplePointsTo [{0->[4,5], 1->[0,0]}, {0->[0,0]}]) +; indicates a tuple with two components. +; - The first component might point to Alloc 0 at offsets 4 or 5, +; or Alloc 1 at offset 0 +; - The second component points to Alloc 0 at offset 0 +(datatype Pointees + (TuplePointsTo List) + (PtrPointsTo PtrPointees)) + +(function UnwrapPtrPointsTo (Pointees) PtrPointees) +(rewrite (UnwrapPtrPointsTo (PtrPointsTo x)) + x + :ruleset memory-helpers) +(function UnwrapTuplePointsTo (Pointees) List) +(rewrite (UnwrapTuplePointsTo (TuplePointsTo x)) + x + :ruleset memory-helpers) + +(relation PointsNowhere (Pointees)) +(rule ((= f (PtrPointsTo x)) + (PointsNowhere-PtrPointees x)) + ((PointsNowhere f)) + :ruleset memory-helpers) +(rule ((= f (TuplePointsTo l)) + (All l)) + ((PointsNowhere f)) + :ruleset memory-helpers) + +(function UnionPointees (Pointees Pointees) Pointees) +(rewrite (UnionPointees (PtrPointsTo x) (PtrPointsTo y)) + (PtrPointsTo (Union-PtrPointees x y)) + :ruleset memory-helpers) +(rewrite (UnionPointees (TuplePointsTo x) (TuplePointsTo y)) + (TuplePointsTo (Zip x y)) + :when ((= (Length-List x) (Length-List y))) + :ruleset memory-helpers) +(function IntersectPointees (Pointees Pointees) Pointees) +(rewrite (IntersectPointees (PtrPointsTo x) (PtrPointsTo y)) + (PtrPointsTo (Intersect-PtrPointees x y)) + :ruleset memory-helpers) +(rewrite (IntersectPointees (TuplePointsTo x) (TuplePointsTo y)) + (TuplePointsTo (Zip x y)) + :ruleset memory-helpers) + +(function GetPointees (Pointees i64) Pointees) +(rule ((= f (GetPointees (TuplePointsTo l) i)) + (At-List l i x)) + ((union f (PtrPointsTo x))) + :ruleset memory-helpers) + +(function PointeesDropFirst (Pointees) Pointees) +(rewrite (PointeesDropFirst (TuplePointsTo (Cons-List hd tl))) + (TuplePointsTo tl) + :ruleset memory-helpers) + +; ============================ +; Resolved +; ============================ + +; Resolved checks if an e-class contains a term containing only constructors and +; primitives; i.e. whether equality is decideable +(relation Resolved-IntOrInfinity (IntOrInfinity)) +(rule ((= f (I _))) + ((Resolved-IntOrInfinity f)) + :ruleset memory-helpers) +(rule ((= f (Infinity))) + ((Resolved-IntOrInfinity f)) + :ruleset memory-helpers) +(rule ((= f (NegInfinity))) + ((Resolved-IntOrInfinity f)) + :ruleset memory-helpers) + +(relation Resolved-IntInterval (IntInterval)) +(rule ((= f (MkIntInterval lo hi)) + (Resolved-IntOrInfinity lo) + (Resolved-IntOrInfinity hi)) + ((Resolved-IntInterval f)) + :ruleset memory-helpers) + +(relation Resolved-List (List)) +(rule ((= f (Nil-List))) + ((Resolved-List f)) + :ruleset memory-helpers) +(rule ((= f (Cons-List allocid offsets tl)) + (Resolved-List tl) + (Resolved-IntInterval offsets)) + ((Resolved-List f)) + :ruleset memory-helpers) + +(relation Resolved-PtrPointees (PtrPointees)) +(rule ((= f (PointsAnywhere))) + ((Resolved-PtrPointees f)) + :ruleset memory-helpers) +(rule ((= f (PointsTo x)) + (Resolved-List x)) + ((Resolved-PtrPointees f)) + :ruleset memory-helpers) + +(relation Resolved-List (List)) +(rule ((= f (Nil-List))) + ((Resolved-List f)) + :ruleset memory-helpers) +(rule ((= f (Cons-List hd tl)) + (Resolved-List tl) + (Resolved-PtrPointees hd)) + ((Resolved-List f)) + :ruleset memory-helpers) + +(relation Resolved-Pointees (Pointees)) +(rule ((= f (TuplePointsTo x)) + (Resolved-List x)) + ((Resolved-Pointees f)) + :ruleset memory-helpers) +(rule ((= f (PtrPointsTo x)) + (Resolved-PtrPointees x)) + ((Resolved-Pointees f)) + :ruleset memory-helpers) + + +;;;;; + +(function BaseTypeToPtrPointees (BaseType) PtrPointees :cost 100) +(rewrite (BaseTypeToPtrPointees (PointerT _)) + (PointsAnywhere) + :ruleset memory-helpers) +(rewrite (BaseTypeToPtrPointees (IntT)) + (PointsTo (Nil-List)) + :ruleset memory-helpers) +(rewrite (BaseTypeToPtrPointees (StateT)) + (PointsTo (Nil-List)) + :ruleset memory-helpers) +(rewrite (BaseTypeToPtrPointees (BoolT)) + (PointsTo (Nil-List)) + :ruleset memory-helpers) + +(function TypeListToList (TypeList) List :cost 1000) +(rewrite (TypeListToList (TNil)) + (Nil-List) + :ruleset memory-helpers) +(rewrite (TypeListToList (TCons hd tl)) + (Cons-List + (BaseTypeToPtrPointees hd) + (TypeListToList tl)) + :ruleset memory-helpers) + +(function TypeToPointees (Type) Pointees :cost 1000) +(rewrite (TypeToPointees (TupleT tylist)) + (TuplePointsTo (TypeListToList tylist)) + :ruleset memory-helpers) +(rewrite (TypeToPointees (Base basety)) + (PtrPointsTo (BaseTypeToPtrPointees basety)) + :ruleset memory-helpers) + +; ============================ +; Update PointerishType +; ============================ + +(relation PointerishType (Type)) +(relation PointerishTypeList (TypeList)) + +(rule ((= f (Base (PointerT ty)))) + ((PointerishType f)) + :ruleset always-run) + +(rule ((= f (TCons (PointerT ty) tl))) + ((PointerishTypeList f)) + :ruleset always-run) + +(rule ((= f (TCons hd tl)) + (PointerishTypeList tl)) + ((PointerishTypeList f)) + :ruleset always-run) + +(rule ((= f (TupleT l)) + (PointerishTypeList l)) + ((PointerishType f)) + :ruleset always-run) + +; ============================ +; Update PointsToCells +; ============================ + +; arg pointees result pointees +(function PointsToCells (Expr Pointees) Pointees :unextractable) + +; Top-level demand +(rule ((Function name in-ty out-ty body)) + ((PointsToCells body (TypeToPointees in-ty))) + :ruleset memory-helpers) + +; Demand PointsToCells along state edge and pointer-typed values +(rule ((PointsToCells (Bop (Print) e state) ap)) + ((PointsToCells state ap)) + :ruleset memory-helpers) +(rule ((PointsToCells (Bop (Load) e state) ap)) + ((PointsToCells e ap) + (PointsToCells state ap)) + :ruleset memory-helpers) +(rule ((PointsToCells (Top (Write) ptr val state) ap)) + ((PointsToCells ptr ap) + (PointsToCells state ap)) + :ruleset memory-helpers) +(rule ((PointsToCells (Alloc id sz state ty) ap)) + ((PointsToCells state ap)) + :ruleset memory-helpers) +(rule ((PointsToCells (Bop (Free) ptr state) ap)) + ((PointsToCells ptr ap) + (PointsToCells state ap)) + :ruleset memory-helpers) +(rule ((PointsToCells (Get x i) ap)) + ((PointsToCells x ap)) + :ruleset memory-helpers) +(rule ((PointsToCells (Concat x y) ap)) + ((PointsToCells x ap) + (PointsToCells y ap)) + :ruleset memory-helpers) +(rule ((PointsToCells (Single x) ap)) + ((PointsToCells x ap)) + :ruleset memory-helpers) + +; Compute and propagate PointsToCells +(rewrite (PointsToCells (Concat x y) aps) + (TuplePointsTo (Concat-List + (UnwrapTuplePointsTo (PointsToCells x aps)) + (UnwrapTuplePointsTo (PointsToCells y aps)))) + :when ((HasType (Concat x y) ty) (PointerishType ty)) + :ruleset memory-helpers) + +(rewrite (PointsToCells (Get x i) aps) + (GetPointees (PointsToCells x aps) i) + :when ((HasType (Get x i) ty) (PointerishType ty)) + :ruleset memory-helpers) + +(rewrite (PointsToCells (Single x) aps) + (TuplePointsTo + (Cons-List + (UnwrapPtrPointsTo (PointsToCells x aps)) + (Nil-List))) + :when ((HasType (Single x) ty) (PointerishType ty)) + :ruleset memory-helpers) + +(rewrite (PointsToCells (Arg ty_ ctx) aps) + aps + :when ((HasType (Arg ty_ ctx) ty) (PointerishType ty)) + :ruleset memory-helpers) + +; Allow non-pointer types to resolve +(rule ((PointsToCells x aps) + (HasType x ty)) + ((TypeToPointees ty)) + :ruleset memory-helpers) +(rule ((= f (PointsToCells x aps)) + (HasType x ty) + (= pointees (TypeToPointees ty)) + (PointsNowhere pointees)) + ((union f pointees)) + :ruleset memory-helpers) + +(rewrite (PointsToCells (Bop (PtrAdd) x e) aps) + (PtrPointsTo + (AddIntIntervalToPtrPointees + (MkIntInterval (I lo) (I hi)) + (UnwrapPtrPointsTo (PointsToCells x aps)))) + :when ((= (IntB lo) (lo-bound e)) + (= (IntB hi) (hi-bound e))) + :ruleset memory-helpers) + +(rewrite (PointsToCells (If c inputs t e) aps) + (UnionPointees + (PointsToCells t (PointsToCells inputs aps)) + (PointsToCells e (PointsToCells inputs aps))) + :when ((HasType (If c inputs t e) ty) (PointerishType ty)) + :ruleset memory) + +(rewrite (PointsToCells (Alloc id sz state ty) aps) + (TuplePointsTo + (Cons-List + (PointsTo + (Cons-List + id + (MkIntInterval (I 0) (I 0)) + (Nil-List))) + (Cons-List + (PointsTo (Nil-List)) ; state output points to nothing + (Nil-List)))) + :ruleset memory-helpers) + +; arg pointees * loop in * loop out * i64 -> result pointees +(function PointsToCellsAtIter (Pointees Expr Expr i64) Pointees) + +; compute first two +(rule ((= e (DoWhile inputs pred-body)) + (PointsToCells e aps)) + ((set (PointsToCellsAtIter aps inputs pred-body 0) + (PointsToCells inputs aps)) + (set (PointsToCellsAtIter aps inputs pred-body 1) + (UnionPointees + (PointsToCellsAtIter aps inputs pred-body 0) + (PointeesDropFirst + (PointsToCells pred-body (PointsToCellsAtIter aps inputs pred-body 0)))))) + :ruleset memory-helpers) + +; avoid quadratic query +(function succ (i64) i64 :unextractable) +(rule ((PointsToCellsAtIter aps inputs pred-body i)) + ((set (succ i) (+ i 1))) + :ruleset memory-helpers) + +; Note that this rule is bounded by ruleset memory +(rule ((= pointees0 (PointsToCellsAtIter aps inputs pred-body i)) + (= pointees1 (PointsToCellsAtIter aps inputs pred-body (succ i))) + (Resolved-Pointees pointees0) + (Resolved-Pointees pointees1) + (!= pointees0 pointees1)) + ((set (PointsToCellsAtIter aps inputs pred-body (+ i 2)) + (UnionPointees + pointees1 + (PointeesDropFirst + (PointsToCells pred-body pointees1))))) + :ruleset memory) + +(rule ((= pointees (PointsToCellsAtIter aps inputs pred-body i)) + (= pointees (PointsToCellsAtIter aps inputs pred-body (succ i)))) + ((set (PointsToCells (DoWhile inputs pred-body) aps) + pointees)) + :ruleset memory) + +(rule ((PtrPointsTo (PointsTo l))) + ((DemandAt-List l)) + :ruleset memory-helpers) +(rule ((TuplePointsTo l)) + ((DemandAt-List l)) + :ruleset memory-helpers) + +; ============================ +; Update DontAlias +; ============================ + +(relation DemandDontAlias (Expr Expr Pointees)) +; pointer, pointer, arg pointees +(relation DontAlias (Expr Expr Pointees)) + + +(rule ((DemandDontAlias ptr1 ptr2 arg-pointees) + (BodyContainsExpr body ptr1) + (BodyContainsExpr body ptr2) + (HasType ptr1 (Base (PointerT ty))) + (HasType ptr2 (Base (PointerT ty))) + (= pointees1 (PointsToCells ptr1 arg-pointees)) + (= pointees2 (PointsToCells ptr2 arg-pointees))) + ((IntersectPointees pointees1 pointees2)) + :ruleset memory-helpers) + +(rule ((PointsNowhere + (IntersectPointees + (PointsToCells ptr1 arg-pointees) + (PointsToCells ptr2 arg-pointees)))) + ((DontAlias ptr1 ptr2 arg-pointees)) + :ruleset memory-helpers) + +; ============================ +; Update PointsToExpr +; ============================ + +; program point, pointer +(function PointsToExpr (Expr Expr) Expr :unextractable) + +; After a load, the ptr points to the loaded value +(rule ((= f (Bop (Load) ptr state))) + ((set (PointsToExpr (Get f 1) ptr) (Get f 0))) + :ruleset memory-helpers) + +; If we load and we already know what the pointer points to +; TODO this rule breaks the weakly linear invariant +; when a previous load may not be on the path +;(rule ((= e (Bop (Load) addr state)) +; (= v (PointsToExpr state addr))) +; ((union (Get e 0) v) +; (union (Get e 1) state)) +; :ruleset memory-helpers) + +; Loads and prints don't affect what what pointers already point to +(rule ((= f (PointsToExpr state addr)) + (= e (Bop (Load) any-addr state))) + ((let new-state (Get e 1)) + (union (PointsToExpr new-state addr) f)) + :ruleset memory-helpers) +(rule ((= f (PointsToExpr state addr)) + (= e (Bop (Print) any-val state))) + ((let new-state e) + (union (PointsToExpr new-state addr) f)) + :ruleset memory-helpers) + +; Writes don't affect what a pointer points to if it writes to another pointer +; guaranteed to not alias. +(rule ((= e (Top (Write) addr data state)) + (HasArgType addr argty) + (= otherdata (PointsToExpr state otheraddr))) + ((DemandDontAlias addr otheraddr (TypeToPointees argty))) + :ruleset memory-helpers) +(rule ((= e (Top (Write) addr data state)) + (HasArgType addr argty) + (= otherdata (PointsToExpr state otheraddr)) + (DontAlias addr otheraddr (TypeToPointees argty))) + ((set (PointsToExpr e otheraddr) otherdata)) + :ruleset memory-helpers) + +; For a write, mark the given expression as containing `data`. +(rule ((= e (Top (Write) addr data state))) + ((union (PointsToExpr e addr) data)) + :ruleset memory-helpers) + +; ============================ +; Update CellHasValues (currently unused) +; ============================ + +; ; program point, cell +; (function CellHasValues (Expr i64) ExprSet :merge (ExprSet-intersect old new)) + +; ; At the time of an alloc, a cell doesn't contain any values +; (rule ((= f (Alloc id amt state ty))) + ; ((set (CellHasValues (Get f 1) id) (ES (set-empty)))) + ; :ruleset memory-helpers) + +; ; These two rules find (Write ptr val state) where +; ; ptr points to cells given no assumptions about where (Arg) points. +; ; TODO: make sensitive to offsets +; (rule ((= e (Top (Write) ptr val state)) + ; (HasArgType ptr argty)) + ; ((TypeToPointees argty)) + ; :ruleset memory-helpers) +; (rule ((= e (Top (Write) ptr val state)) + ; (HasArgType ptr argty) + ; (= (PtrPointsTo (PointsTo cells)) (PointsToCells ptr (TypeToPointees argty))) + ; (At-List cells any-idx alloc-id offsets) + ; (= vals (CellHasValues state cell))) + ; ((set (CellHasValues e cell) (ExprSet-insert vals val))) + ; :ruleset memory-helpers) + +;; Loop Invariant + +;; bool: whether the term in the Expr is an invariant. +(function is-inv-Expr (Expr Expr) bool :unextractable :merge (or old new)) +(function is-inv-ListExpr (Expr ListExpr) bool :unextractable :merge (or old new)) + +;; in default, when there is a find, set is-inv to false +(rule ((BodyContainsExpr loop term) + (= loop (DoWhile inputs pred_out))) + ((set (is-inv-Expr loop term) false)) :ruleset always-run) +(rule ((BodyContainsListExpr loop term) + (= loop (DoWhile inputs pred_out))) + ((set (is-inv-ListExpr loop term) false)) :ruleset always-run) + +(relation is-inv-ListExpr-helper (Expr ListExpr i64)) +(rule ((BodyContainsListExpr loop list) + (= loop (DoWhile inputs pred_out))) + ((is-inv-ListExpr-helper loop list 0)) :ruleset always-run) + +(rule ((is-inv-ListExpr-helper loop list i) + (= true (is-inv-Expr loop expr)) + (= expr (ListExpr-ith list i))) + ((is-inv-ListExpr-helper loop list (+ i 1))) :ruleset always-run) + +(rule ((is-inv-ListExpr-helper loop list i) + (= i (ListExpr-length list))) + ((set (is-inv-ListExpr loop list) true)) :ruleset always-run) + + +(ruleset boundary-analysis) +;; An Expr is on boundary when it is invariant and its parent is not +; loop invariant-expr +(relation boundary-Expr (Expr Expr)) + +;; boundary for ListExpr's children +(rule ((= true (is-inv-Expr loop expr)) + (= false (is-inv-ListExpr loop list)) + (= expr (ListExpr-ith list i))) + ((boundary-Expr loop expr)) :ruleset boundary-analysis) + +;; if a output branch/pred is invariant, it's also boundary-Expr +(rule ((= true (is-inv-Expr loop expr)) + (= loop (DoWhile in pred_out)) + (= expr (Get pred_out i))) + ((boundary-Expr loop expr)) :ruleset boundary-analysis) + + +(function hoisted-loop (Expr Expr) bool :unextractable :merge (or old new) ) +(rule ((= loop (DoWhile in pred_out))) + ((set (hoisted-loop in pred_out) false)) :ruleset always-run) + +(function InExtendedLoop (Expr Expr Expr) Assumption) + +;; mock function +(ruleset loop-inv-motion) + +(rule ((boundary-Expr loop inv) + (> (Expr-size inv) 1) + ;; TODO: replace Expr-size when cost model is ready + (= loop (DoWhile in pred_out)) + ;; the outter assumption of the loop + (ContextOf loop loop_ctx) + (HasType in in_type) + (HasType inv inv_type) + (= inv_type (Base base_inv_ty)) + (= in_type (TupleT tylist)) + (= false (hoisted-loop in pred_out)) + (= len (tuple-length in))) + ((let new_input (Concat in (Single (Subst loop_ctx in inv)))) + (let new_input_type (TupleT (TLConcat tylist (TCons base_inv_ty (TNil))))) + ;; create an virtual assume node, union it with actuall InLoop later + (let assum (InExtendedLoop in pred_out new_input)) + (let new_out_branch (Get (Arg new_input_type assum) len)) + ;; this two subst only change arg to arg with new type + (let substed_pred_out (Subst assum (Arg new_input_type assum) pred_out)) + (let inv_in_new_loop (Subst assum (Arg new_input_type assum) inv)) + (let new_pred_out (Concat substed_pred_out (Single new_out_branch))) + + (let new_loop (DoWhile new_input new_pred_out)) + (union assum (InLoop new_input new_pred_out)) + (union inv_in_new_loop new_out_branch) + (let wrapper (SubTuple new_loop 0 len)) + (union loop wrapper) + (subsume (DoWhile in pred_out)) + ;; don't hoist same loop again + (set (hoisted-loop in pred_out) true) + ) + :ruleset loop-inv-motion) + + +(rule ((BodyContainsExpr loop expr) + (= loop (DoWhile in out)) + (= expr (Const _n _ty _ctx))) + ((set (is-inv-Expr loop expr) true)) :ruleset always-run) + +(rule ((BodyContainsExpr loop expr) + (= loop (DoWhile in out)) + (= expr (Get (Arg ty ctx) i)) + (= loop (DoWhile in pred_out)) + (= expr (Get pred_out (+ i 1)))) + ((set (is-inv-Expr loop expr) true)) :ruleset always-run) + +(rule ((BodyContainsExpr loop expr) + (= loop (DoWhile in out)) + (= expr (Function _name _tyin _tyout _out)) + + ) + ((set (is-inv-Expr loop expr) true)) :ruleset always-run) + +(rule ((BodyContainsExpr loop expr) + (= loop (DoWhile in out)) + (= expr (Top _op _x _y _z)) + (= true (is-inv-Expr loop _x)) (= true (is-inv-Expr loop _y)) (= true (is-inv-Expr loop _z)) + ) + ((set (is-inv-Expr loop expr) true)) :ruleset always-run) + +(rule ((BodyContainsExpr loop expr) + (= loop (DoWhile in out)) + (= expr (Bop _op _x _y)) (BinaryOpIsPure _op) + (= true (is-inv-Expr loop _x)) (= true (is-inv-Expr loop _y)) + ) + ((set (is-inv-Expr loop expr) true)) :ruleset always-run) + +(rule ((BodyContainsExpr loop expr) + (= loop (DoWhile in out)) + (= expr (Uop _op _x)) (UnaryOpIsPure _op) + (= true (is-inv-Expr loop _x)) + ) + ((set (is-inv-Expr loop expr) true)) :ruleset always-run) + +(rule ((BodyContainsExpr loop expr) + (= loop (DoWhile in out)) + (= expr (Get _tup _i)) + (= true (is-inv-Expr loop _tup)) + ) + ((set (is-inv-Expr loop expr) true)) :ruleset always-run) + +(rule ((BodyContainsExpr loop expr) + (= loop (DoWhile in out)) + (= expr (Concat _x _y)) + (= true (is-inv-Expr loop _x)) (= true (is-inv-Expr loop _y)) + ) + ((set (is-inv-Expr loop expr) true)) :ruleset always-run) + +(rule ((BodyContainsExpr loop expr) + (= loop (DoWhile in out)) + (= expr (Single _x)) + (= true (is-inv-Expr loop _x)) + ) + ((set (is-inv-Expr loop expr) true)) :ruleset always-run) + +(rule ((BodyContainsExpr loop expr) + (= loop (DoWhile in out)) + (= expr (Switch _pred _inputs _branches)) + (= true (is-inv-Expr loop _pred)) (= true (is-inv-Expr loop _inputs)) (= true (is-inv-ListExpr loop _branches)) + ) + ((set (is-inv-Expr loop expr) true)) :ruleset always-run) + +(rule ((BodyContainsExpr loop expr) + (= loop (DoWhile in out)) + (= expr (If _pred _input _then _else)) + (= true (is-inv-Expr loop _pred)) (= true (is-inv-Expr loop _input)) + ) + ((set (is-inv-Expr loop expr) true)) :ruleset always-run) + +(rule ((BodyContainsExpr loop expr) + (= loop (DoWhile in out)) + (= expr (DoWhile _in _pred-and-output)) + (= true (is-inv-Expr loop _in)) + (ExprIsPure expr)) + ((set (is-inv-Expr loop expr) true)) :ruleset always-run) + +(rule ((BodyContainsExpr loop expr) + (= loop (DoWhile in out)) + (= expr (Call _func _arg)) + (= true (is-inv-Expr loop _arg)) + (ExprIsPure expr)) + ((set (is-inv-Expr loop expr) true)) :ruleset always-run) + +(rule ((BodyContainsExpr loop expr) + (= loop (DoWhile in out)) + (= expr (Empty _ty _ctx)) + + ) + ((set (is-inv-Expr loop expr) true)) :ruleset always-run) + + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (Top _op _x _y _z)) + (= expr1 _x)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (Top _op _x _y _z)) + (= expr1 _y)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (Top _op _x _y _z)) + (= expr1 _z)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (Bop _op _x _y)) + (= expr1 _x)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (Bop _op _x _y)) + (= expr1 _y)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (Uop _op _x)) + (= expr1 _x)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (Concat _x _y)) + (= expr1 _x)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (Concat _x _y)) + (= expr1 _y)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (Single _x)) + (= expr1 _x)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (Switch _pred _inputs _branches)) + (= expr1 _pred)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (Switch _pred _inputs _branches)) + (= expr1 _inputs)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (If _pred _input _then _else)) + (= expr1 _pred)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (If _pred _input _then _else)) + (= expr1 _input)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (DoWhile _in _pred-and-output)) + (= expr1 _in)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (Call _func _arg)) + (= expr1 _arg)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (Alloc _id _e _state _ty)) + (= expr1 _e)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (Alloc _id _e _state _ty)) + (= expr1 _state)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) +;; Some simple simplifications of loops +(ruleset loop-simplify) + +(rewrite + (DoWhile (Arg ty ctx) + (Concat (Single (Const (Bool false) ty ctx2)) + (Single (Const constant ty ctx2)))) + (Single (Const constant ty ctx)) + :ruleset loop-simplify) +;; Some simple simplifications of loops +(ruleset loop-unroll) +(ruleset loop-peel) + +;; inputs, outputs -> number of iterations +(function LoopNumItersGuess (Expr Expr) i64 :merge (max 1 (min old new))) + +;; by default, guess that all loops run 1000 times +(rule ((DoWhile inputs outputs)) + ((set (LoopNumItersGuess inputs outputs) 1000)) + :ruleset always-run) + + +;; loop peeling rule +(rule + ((= lhs (DoWhile inputs outputs)) + (ContextOf lhs ctx) + (HasType inputs inputs-ty) + (= outputs-len (tuple-length outputs)) + (= old_cost (LoopNumItersGuess inputs outputs))) + ((let executed-once + (Subst ctx inputs outputs)) + (let executed-once-body + (SubTuple executed-once 1 (- outputs-len 1))) + (let then-ctx + (InIf true (Get executed-once 0) executed-once-body)) + (let else-ctx + (InIf false (Get executed-once 0) executed-once-body)) + (union lhs + ;; check if we need to continue executing the loop + (If (Get executed-once 0) + executed-once-body ;; inputs are the body executed once + (DoWhile (Arg inputs-ty then-ctx) + outputs) ;; right now, loop unrolling shares the same outputs, but we could add more context here + (Arg inputs-ty else-ctx))) + (set (LoopNumItersGuess (Arg inputs-ty then-ctx) outputs) (- old_cost 1)) + ) + :ruleset loop-peel) + +;; unroll a loop with constant bounds and initial value +(rule + ((= lhs (DoWhile inputs outputs)) + (= num-inputs (tuple-length inputs)) + (= pred (Get outputs 0)) + ;; iteration counter starts at start_const + (= (Const (Int start_const) _ty1 _ctx1) (Get inputs counter_i)) + ;; updated counter at counter_i + (= next_counter (Get outputs (+ counter_i 1))) + ;; increments by one each loop + (= next_counter (Bop (Add) (Get (Arg _ty _ctx) counter_i) + (Const (Int 1) _ty2 _ctx2))) + ;; while less than end_constant + (= pred (Bop (LessThan) next_counter + (Const (Int end_constant) _ty3 _ctx3))) + ;; start and end constant is a multiple of 4 and greater than start_const + (> end_constant start_const) + (= (% start_const 4) 0) + (= (% end_constant 4) 0) + (= old_cost (LoopNumItersGuess inputs outputs)) + ) + ( + (let one-iter (SubTuple outputs 1 num-inputs)) + (let unrolled + (Subst (TmpCtx) one-iter + (Subst (TmpCtx) one-iter + (Subst (TmpCtx) one-iter + outputs)))) + (union lhs + (DoWhile inputs + unrolled)) + (let actual-ctx (InLoop inputs unrolled)) + (union (TmpCtx) actual-ctx) + + (set (LoopNumItersGuess inputs unrolled) (/ old_cost 4)) + (delete (TmpCtx)) + ) + :ruleset loop-unroll) + + + +;; Pass through thetas +(rule ((= lhs (Get loop i)) + (= loop (DoWhile inputs pred-outputs)) + (= (Get pred-outputs (+ i 1)) (Get (Arg _ty _ctx) i)) + ;; only pass through pure types, since some loops don't terminate + ;; so the state edge must pass through them + (HasType (Get loop i) lhs_ty) + (PureType lhs_ty) + ) + ((union lhs (Get inputs i))) + :ruleset always-run) + +;; Pass through switch arguments +(rule ((= lhs (Get switch i)) + (= switch (Switch pred inputs branches)) + (= (ListExpr-length branches) 2) + (= branch0 (ListExpr-ith branches 0)) + (= branch1 (ListExpr-ith branches 1)) + (= (Get branch0 i) (Get (Arg _ _ctx0) j)) + (= (Get branch1 i) (Get (Arg _ _ctx1) j)) + (= passed-through (Get inputs j)) + (HasType lhs lhs_ty) + (!= lhs_ty (Base (StateT)))) + ((union lhs passed-through)) + :ruleset always-run) + +;; Pass through switch predicate +(rule ((= lhs (Get switch i)) + (= switch (Switch pred inputs branches)) + (= (ListExpr-length branches) 2) + (= branch0 (ListExpr-ith branches 0)) + (= branch1 (ListExpr-ith branches 1)) + (= (Get branch0 i) (Const (Bool false) _ _ctx0)) + (= (Get branch1 i) (Const (Bool true) _ _ctx1))) + ((union lhs pred)) + :ruleset always-run) + +;; Pass through if arguments +(rule ((= if (If pred inputs then_ else_)) + (= jth-inside (Get (Arg _ _then_ctx) j)) + (= (Get then_ i) jth-inside) + (= (Get else_ i) (Get (Arg _ _else_ctx) j)) + (HasType jth-inside lhs_ty) + (!= lhs_ty (Base (StateT)))) + ((union (Get if i) (Get inputs j))) + :ruleset always-run) + +; Pass through if state edge arguments +; To maintain the invariant, we have to union the other outputs with a pure if statement +(rule ((= lhs (Get outputs i)) + (= outputs (If pred inputs then_ else_)) + + (= (Get then_ i) (Get (Arg (TupleT arg_ty) then_ctx) j)) + (= (Get else_ i) (Get (Arg (TupleT arg_ty) else_ctx) j)) + (= passed-through (Get inputs j)) + + (HasType lhs lhs_ty) + (= lhs_ty (Base (StateT))) + + (= inputs_len (tuple-length inputs)) + (= outputs_len (tuple-length outputs))) + + ((let new_inputs (TupleRemoveAt inputs j)) + + (let new_then_ctx (InIf true pred new_inputs)) + (let new_else_ctx (InIf false pred new_inputs)) + + (let old_then (TupleRemoveAt then_ i)) + (let old_else (TupleRemoveAt else_ i)) + + (let new_then (DropAt new_then_ctx j old_then)) + (let new_else (DropAt new_else_ctx j old_else)) + + (let old_outputs (TupleRemoveAt outputs i)) + (let new_if (If pred new_inputs new_then new_else)) + (union new_if old_outputs) + + (union lhs passed-through) + (subsume (If pred inputs then_ else_))) + :ruleset always-run) + +;; Pass through if predicate +(rule ((= if (If pred inputs then_ else_)) + (= (Get then_ i) (Const (Bool true) _ _thenctx)) + (= (Get else_ i) (Const (Bool false) _ _elsectx))) + + ((let new_then (TupleRemoveAt then_ i)) + (let new_else (TupleRemoveAt else_ i)) + (let new_if (If pred inputs new_then new_else)) + + (union (Get if i) pred) + (union (TupleRemoveAt if i) new_if) + (subsume (If pred inputs then_ else_))) + :ruleset always-run) + +;; ORIGINAL +;; a = 0 +;; c = 3 +;; for i = 0 to n: +;; a = i * c +;; +;; OPTIMIZED +;; a = 0 +;; c = 3 +;; d = 0 +;; for i = 0 to n: +;; a += d +;; d += c +(ruleset loop-strength-reduction) + +; Finds invariants/constants within a body. +; Columns: body; value of invariant in inputs; value of invariant in outputs +;; Get the input and output value of an invariant, or constant int, within the loop +;; loop in out +(relation lsr-inv (Expr Expr Expr)) + +; TODO: there may be a bug with finding the invariant, or it just may not be extracted. +; Can make this work on loop_with_mul_by_inv and a rust test later. +; (rule ( +; (= loop (DoWhile inputs pred-and-body)) +; (= (Get outputs (+ i 1)) (Get (Arg arg-type assm) i))) +; ((inv loop (Get inputs i) (Get (Arg arg-type assm) i))) :ruleset always-run) +(rule ( + (= loop (DoWhile inputs pred-and-body)) + (ContextOf inputs loop-input-ctx) + (ContextOf pred-and-body loop-output-ctx) + (= constant (Const c out-type loop-output-ctx)) + (HasArgType inputs in-type) + ) + ((lsr-inv loop (Const c in-type loop-input-ctx) constant)) :ruleset always-run) + +(rule + ( + ;; Find loop + (= old-loop (DoWhile inputs pred-and-outputs)) + (ContextOf pred-and-outputs loop-ctx) + + ; Find loop variable (argument that gets incremented with an invariant) + (lsr-inv old-loop loop-incr-in loop-incr-out) + ; Since the first el of pred-and-outputs is the pred, we need to offset i + (= (Get pred-and-outputs (+ i 1)) (Bop (Add) (Get (Arg arg-type assm) i) loop-incr-out)) + + ; Find invariant where input is same as output, or constant + (lsr-inv old-loop c-in c-out) + + ; Find multiplication of loop variable and invariant + (= old-mul (Bop (Mul) c-out (Get (Arg arg-type assm) i))) + (ContextOf old-mul loop-ctx) + + (= arg-type (TupleT ty-list)) + ) + ( + ; Each time we need to update d by the product of the multiplied constant and the loop increment + (let addend (Bop (Mul) c-out loop-incr-out)) + + ; n is index of our new, temporary variable d + (let n (tuple-length inputs)) + + ; Initial value of d is i * c + (let d-init (Bop (Mul) c-in (Get inputs i))) + + ; Construct optimized theta + ; new-inputs already has the correct context + (let new-inputs (Concat inputs (Single d-init))) + + ; We need to create a new type, with one more input + (let new-arg-ty (TupleT (TLConcat ty-list (TCons (IntT) (TNil))))) + + ; Value of d in loop. Add context to addend + (let d-out (Bop (Add) (Get (Arg new-arg-ty (TmpCtx)) n) + (Subst (TmpCtx) (Arg new-arg-ty (TmpCtx)) addend))) + + ; build the old body, making sure to set the correct arg type and context + (let new-body + (Concat + (Subst (TmpCtx) (Arg new-arg-ty (TmpCtx)) pred-and-outputs) + (Single d-out))) + + (let new-loop (DoWhile new-inputs new-body)) + + ; Now that we have the new loop, union the temporary context with the actual ctx + (union (TmpCtx) (InLoop new-inputs new-body)) + + ; Substitute d for the *i expression + (let new-mul + (Bop + (Mul) + (Subst (TmpCtx) (Arg new-arg-ty (TmpCtx)) c-out) + (Get (Arg new-arg-ty (TmpCtx)) i))) + (union (Get (Arg new-arg-ty (TmpCtx)) n) new-mul) + + ; Subsume the multiplication in the new loop to prevent + ; from firing loop strength reduction again on the new loop + (subsume + (Bop + (Mul) + (Subst (TmpCtx) (Arg new-arg-ty (TmpCtx)) c-out) + (Get (Arg new-arg-ty (TmpCtx)) i))) + + ; Project all but last + (union old-loop (SubTuple new-loop 0 n)) + (delete (TmpCtx)) + ) + :ruleset loop-strength-reduction +) +(DoWhile (Concat (Single (Const (Int 0) (TupleT (TNil)) (InFunc "dummy"))) (Single (Const (Int 1) (TupleT (TNil)) (InFunc "dummy")))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 0) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 1))) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 0) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 1))))) + +(If (Bop (LessThan) (Const (Int 0) (TupleT (TNil)) (InFunc "dummy")) (Const (Int 1) (TupleT (TNil)) (InFunc "dummy"))) (Concat (Single (Const (Int 1) (TupleT (TNil)) (InFunc "dummy"))) (Single (Const (Int 1) (TupleT (TNil)) (InFunc "dummy")))) (DoWhile (Concat (Single (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 0)) (Single (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 1))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 0) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 1))) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 0) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 1))))) (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy"))) + + (unstable-combined-ruleset saturating + always-run + canon + type-analysis + context + interval-analysis + memory-helpers + ) + + + (unstable-combined-ruleset optimizations + loop-simplify + memory + loop-unroll + peepholes + ) + + (unstable-combined-ruleset expensive-optimizations + optimizations + ;; TODO why is this expensive? On `adler32.bril` it blows up with 3 iterations + switch_rewrite + ;loop-inv-motion + loop-strength-reduction + ) + + (run-schedule + +;; saturate all helpers first +(saturate + (saturate + (saturate type-helpers) ;; resolve type helpers, finding correct types + (saturate error-checking) ;; check for errors, relies on type-helpers saturating + saturating) + + (saturate drop) + apply-drop-unions + cleanup-drop + + (saturate subst) ;; do e-substitution + apply-subst-unions ;; apply the unions from substitution + cleanup-subst ;; clean up substitutions that are done + + (saturate boundary-analysis) ;; find boundaries of invariants +) + + + loop-peel + (repeat 2 + +;; saturate all helpers first +(saturate + (saturate + (saturate type-helpers) ;; resolve type helpers, finding correct types + (saturate error-checking) ;; check for errors, relies on type-helpers saturating + saturating) + + (saturate drop) + apply-drop-unions + cleanup-drop + + (saturate subst) ;; do e-substitution + apply-subst-unions ;; apply the unions from substitution + cleanup-subst ;; clean up substitutions that are done + + (saturate boundary-analysis) ;; find boundaries of invariants +) + + + expensive-optimizations) + (repeat 4 + +;; saturate all helpers first +(saturate + (saturate + (saturate type-helpers) ;; resolve type helpers, finding correct types + (saturate error-checking) ;; check for errors, relies on type-helpers saturating + saturating) + + (saturate drop) + apply-drop-unions + cleanup-drop + + (saturate subst) ;; do e-substitution + apply-subst-unions ;; apply the unions from substitution + cleanup-subst ;; clean up substitutions that are done + + (saturate boundary-analysis) ;; find boundaries of invariants +) + + + optimizations) + +;; saturate all helpers first +(saturate + (saturate + (saturate type-helpers) ;; resolve type helpers, finding correct types + (saturate error-checking) ;; check for errors, relies on type-helpers saturating + saturating) + + (saturate drop) + apply-drop-unions + cleanup-drop + + (saturate subst) ;; do e-substitution + apply-subst-unions ;; apply the unions from substitution + cleanup-subst ;; clean up substitutions that are done + + (saturate boundary-analysis) ;; find boundaries of invariants +) + +) + + + (query-extract :variants 5 (DoWhile (Concat (Single (Const (Int 0) (TupleT (TNil)) (InFunc "dummy"))) (Single (Const (Int 1) (TupleT (TNil)) (InFunc "dummy")))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 0) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 1))) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 0) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 1)))))) + ;(query-extract :variants 5 (If (Bop (LessThan) (Const (Int 0) (TupleT (TNil)) (InFunc "dummy")) (Const (Int 1) (TupleT (TNil)) (InFunc "dummy"))) (Concat (Single (Const (Int 1) (TupleT (TNil)) (InFunc "dummy"))) (Single (Const (Int 1) (TupleT (TNil)) (InFunc "dummy")))) (DoWhile (Concat (Single (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 0)) (Single (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 1))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 0) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 1))) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 0) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 1))))) (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")))) + +;; use these rules to clean up the database, removing helpers +;; this makes the visualization easier to read + + +(rule ((HasType a b)) + ((delete (HasType a b)))) +(rule ((BodyContainsExpr a b)) + ((delete (BodyContainsExpr a b)))) +(rule ((ExprIsPure e)) + ((delete (ExprIsPure e)))) +(rule ((HasArgType e ty)) + ((delete (HasArgType e ty)))) +(rule ((is-inv-Expr e ty)) + ((delete (is-inv-Expr e ty)))) +(rule ((tuple-length e)) + ((delete (tuple-length e)))) +(rule ((BinaryOpIsPure e)) + ((delete (BinaryOpIsPure e)))) +(rule ((TypeList-suffix e a)) + ((delete (TypeList-suffix e a)))) +(rule ((ContextOf e a)) + ((delete (ContextOf e a)))) +(rule ((ExprIsResolved e)) + ((delete (ExprIsResolved e)))) +(run-schedule (saturate (run))) + + Running unittests src/main.rs (target/release/deps/dag_in_context-13fe7a7639e66d94) diff --git a/dag_in_context/src/optimizations/loop_unroll.egg b/dag_in_context/src/optimizations/loop_unroll.egg index 0b3bc16db..e04c642b9 100644 --- a/dag_in_context/src/optimizations/loop_unroll.egg +++ b/dag_in_context/src/optimizations/loop_unroll.egg @@ -3,6 +3,8 @@ (ruleset loop-peel) ;; inputs, outputs -> number of iterations +;; The minimum possible guess is 1 because of do-while loops +;; TODO: dead loop deletion can turn loops with a false condition to a body (function LoopNumItersGuess (Expr Expr) i64 :merge (max 1 (min old new))) ;; by default, guess that all loops run 1000 times @@ -10,15 +12,68 @@ ((set (LoopNumItersGuess inputs outputs) 1000)) :ruleset always-run) +;; Figure out number of iterations for a loop with constant bounds and initial value +;; and i is updated before checking pred +;; TODO: can make this work for increment by any constant +(rule + ((= lhs (DoWhile inputs outputs)) + (= num-inputs (tuple-length inputs)) + (= pred (Get outputs 0)) + ;; iteration counter starts at start_const + (= (Const (Int start_const) _ty1 _ctx1) (Get inputs counter_i)) + ;; updated counter at counter_i + (= next_counter (Get outputs (+ counter_i 1))) + ;; increments by one each loop + (= next_counter (Bop (Add) (Get (Arg _ty _ctx) counter_i) + ;; TODO: put c instead of (Int 1) and mul by c + (Const (Int 1) _ty2 _ctx2))) + ;; while next_counter less than end_constant + (= pred (Bop (LessThan) next_counter + (Const (Int end_constant) _ty3 _ctx3))) + ;; end constant is greater than start constant + (> end_constant start_const) + ) + ( + (set (LoopNumItersGuess inputs outputs) (- end_constant start_const)) + ) + :ruleset always-run) + +;; Figure out number of iterations for a loop with constant bounds and initial value +;; and i is updated after checking pred +(rule + ((= lhs (DoWhile inputs outputs)) + (= num-inputs (tuple-length inputs)) + (= pred (Get outputs 0)) + ;; iteration counter starts at start_const + (= (Const (Int start_const) _ty1 _ctx1) (Get inputs counter_i)) + ;; updated counter at counter_i + (= next_counter (Get outputs (+ counter_i 1))) + ;; increments by one each loop + (= next_counter (Bop (Add) (Get (Arg _ty _ctx) counter_i) + (Const (Int 1) _ty2 _ctx2))) + ;; while this counter less than end_constant + (= pred (Bop (LessThan) (Get (Arg _ty _ctx) counter_i) + (Const (Int end_constant) _ty3 _ctx3))) + ;; end constant is greater than start constant + (> end_constant start_const) + ) + ( + (set (LoopNumItersGuess inputs outputs) (+ (- end_constant start_const) 1)) + ) + :ruleset always-run) ;; loop peeling rule +;; Only peel loops that we know iterate < 5 times (rule ((= lhs (DoWhile inputs outputs)) (ContextOf lhs ctx) (HasType inputs inputs-ty) (= outputs-len (tuple-length outputs)) - (= old_cost (LoopNumItersGuess inputs outputs))) - ((let executed-once + (= old_cost (LoopNumItersGuess inputs outputs)) + ; (< old_cost 5) + ) + ( + (let executed-once (Subst ctx inputs outputs)) (let executed-once-body (SubTuple executed-once 1 (- outputs-len 1))) diff --git a/dag_in_context/src/optimizations/switch_rewrites.egg b/dag_in_context/src/optimizations/switch_rewrites.egg index bc68d1343..748f128d0 100644 --- a/dag_in_context/src/optimizations/switch_rewrites.egg +++ b/dag_in_context/src/optimizations/switch_rewrites.egg @@ -44,7 +44,7 @@ (rewrite (If (Const (Bool true) ty ctx) ins thn els) (Subst ctx ins thn) - :ruleset switch_rewrite) + :ruleset always-run) (rewrite (If (Const (Bool false) ty ctx) ins thn els) (Subst ctx ins els) diff --git a/dag_in_context/src/schedule.rs b/dag_in_context/src/schedule.rs index b838e9753..07f676d92 100644 --- a/dag_in_context/src/schedule.rs +++ b/dag_in_context/src/schedule.rs @@ -52,11 +52,11 @@ pub fn mk_schedule() -> String { switch_rewrite ;loop-inv-motion loop-strength-reduction + loop-peel ) (run-schedule {helpers} - loop-peel (repeat 2 {helpers} expensive-optimizations) diff --git a/out.egg b/out.egg new file mode 100644 index 000000000..f8819658a --- /dev/null +++ b/out.egg @@ -0,0 +1,3854 @@ +; Every term is an `Expr` or a `ListExpr`. +(datatype Expr) +; Used for constructing a list of branches for `Switch`es +; or a list of functions in a `Program`. +(datatype ListExpr (Cons Expr ListExpr) (Nil)) + +; ================================= +; Types +; ================================= + +(sort TypeList) + +(datatype BaseType + (IntT) + (BoolT) + (FloatT) + ; a pointer to a memory region with a particular type + (PointerT BaseType) + (StateT)) + + +(datatype Type + ; a primitive type + (Base BaseType) + ; a typed tuple. Use an empty tuple as a unit type. + ; state edge also has unit type + (TupleT TypeList) +) + +(function TNil () TypeList) +(function TCons (BaseType TypeList) TypeList) ; Head element should never be a tuple + + +; ================================= +; Assumptions +; ================================= + +(datatype Assumption + ; Assume nothing + (InFunc String) + ; The term is in a loop with `input` and `pred_output`. + ; InLoop is a special context because it describes the argument of the loop. It is a *scope context*. + ; input pred_output + (InLoop Expr Expr) + ; Branch of the switch, and what the predicate is, and what the input is + (InSwitch i64 Expr Expr) + ; If the predicate was true, and what the predicate is, and what the input is + (InIf bool Expr Expr) +) + + + +; ================================= +; Leaf nodes +; Constants, argument, and empty tuple +; ================================= + +; Only a single argument is bound- if multiple values are needed, arg will be a tuple. +; e.g. `(Get (Arg tuple_type) 1)` gets the second value in the argument with some tuple_type. +(function Arg (Type Assumption) Expr) + +; Constants +(datatype Constant + (Int i64) + (Bool bool) + (Float f64)) +; All leaf nodes need the type of the argument +; Type is the type of the bound argument in scope +(function Const (Constant Type Assumption) Expr) + +; An empty tuple. +; Type is the type of the bound argument in scope +(function Empty (Type Assumption) Expr) + + +; ================================= +; Operators +; ================================= + +(datatype TernaryOp + ; given a pointer, value, and a state edge + ; writes the value to the pointer and returns + ; the resulting state edge + (Write) + (Select)) +(datatype BinaryOp + ;; integer operators + (Add) + (Sub) + (Div) + (Mul) + (LessThan) + (GreaterThan) + (LessEq) + (GreaterEq) + (Eq) + ;; float operators + (FAdd) + (FSub) + (FDiv) + (FMul) + (FLessThan) + (FGreaterThan) + (FLessEq) + (FGreaterEq) + (FEq) + ;; logical operators + (And) + (Or) + ; given a pointer and a state edge + ; loads the value at the pointer and returns (value, state edge) + (Load) + ; Takes a pointer and an integer, and offsets + ; the pointer by the integer + (PtrAdd) + ; given and value and a state edge, prints the value as a side-effect + ; the value must be a base value, not a tuple + ; returns an empty tuple + (Print) + ; given a pointer and state edge, frees the whole memory region at the pointer + (Free)) +(datatype UnaryOp + (Not)) + +; Operators +(function Top (TernaryOp Expr Expr Expr) Expr) +(function Bop (BinaryOp Expr Expr) Expr) +(function Uop (UnaryOp Expr) Expr) +; gets from a tuple. static index +(function Get (Expr i64) Expr) +; (Alloc id amount state_edge pointer_type) +; allocate an integer amount of memory for a particular type +; returns (pointer to the allocated memory, state edge) +(function Alloc (i64 Expr Expr BaseType) Expr) +; name of func arg +(function Call (String Expr) Expr) + + + +; ================================= +; Tuple operations +; ================================= + +; `Empty`, `Single` and `Concat` create tuples. +; 1. Use `Empty` for an empty tuple. +; 2. Use `Single` for a tuple with one element. +; 3. Use `Concat` to append the elements from two tuples together. +; Nested tuples are not allowed. + + +; A tuple with a single element. +; Necessary because we only use `Concat` to add to tuples. +(function Single (Expr) Expr) +; Concat appends the elemnts from two tuples together +; e.g. (Concat (Concat (Single a) (Single b)) +; (Concat (Single c) (Single d))) = (a, b, c, d) +; expr1 expr2 +(function Concat (Expr Expr) Expr) + + + +; ================================= +; Control flow +; ================================= + +; Switch on a list of lazily-evaluated branches. +; pred must be an integer +; pred inputs branches chosen +(function Switch (Expr Expr ListExpr) Expr) +; If is like switch, but with a boolean predicate +; pred inputs then else +(function If (Expr Expr Expr Expr) Expr) + + +; A do-while loop. +; Evaluates the input, then evaluates the body. +; Keeps looping while the predicate is true. +; input must have the same type as (output1, output2, ..., outputi) +; input must be a tuple +; pred must be a boolean +; pred-and-body must be a flat tuple (pred, out1, out2, ..., outi) +; input must be the same type as (out1, out2, ..., outi) +; input pred-and-body +(function DoWhile (Expr Expr) Expr) + + +; ================================= +; Top-level expressions +; ================================= +(sort ProgramType) +; An entry function and a list of additional functions. +; entry function other functions +(function Program (Expr ListExpr) ProgramType) +; name input ty output ty output +(function Function (String Type Type Expr) Expr) + + + +; Rulesets +(ruleset always-run) +(ruleset error-checking) +(ruleset memory) +(ruleset memory-helpers) +(ruleset smem) + +;; Initliazation +(relation bop->string (BinaryOp String)) +(relation uop->string (UnaryOp String)) +(relation top->string (TernaryOp String)) +(bop->string (Add) "Add") +(bop->string (Sub) "Sub") +(bop->string (Div) "Div") +(bop->string (Mul) "Mul") +(bop->string (LessThan) "LessThan") +(bop->string (GreaterThan) "GreaterThan") +(bop->string (LessEq) "LessEq") +(bop->string (GreaterEq) "GreaterEq") +(bop->string (Eq) "Eq") +(bop->string (FAdd) "FAdd") +(bop->string (FSub) "FSub") +(bop->string (FDiv) "FDiv") +(bop->string (FMul) "FMul") +(bop->string (FLessThan) "FLessThan") +(bop->string (FGreaterThan) "FGreaterThan") +(bop->string (FLessEq) "FLessEq") +(bop->string (FGreaterEq) "FGreaterEq") +(bop->string (FEq) "FEq") +(bop->string (And) "And") +(bop->string (Or) "Or") +(bop->string (Load) "Load") +(bop->string (PtrAdd) "PtrAdd") +(bop->string (Print) "Print") +(bop->string (Free) "Free") +(ruleset type-analysis) +(ruleset type-helpers) ;; these rules need to saturate between every iter of type-analysis rules + +(function TLConcat (TypeList TypeList) TypeList :unextractable) +(rewrite (TLConcat (TNil) r) r :ruleset type-helpers) +(rewrite (TLConcat (TCons hd tl) r) + (TCons hd (TLConcat tl r)) + :ruleset type-helpers) + +(function TypeList-length (TypeList) i64 :unextractable) +(function TypeList-ith (TypeList i64) BaseType :unextractable) +(function TypeList-suffix (TypeList i64) TypeList :unextractable) + +(rule ((TupleT tylist)) ((union (TypeList-suffix tylist 0) tylist)) :ruleset type-helpers) + +(rule ((= (TypeList-suffix top n) (TCons hd tl))) + ((union (TypeList-ith top n) hd) + (union (TypeList-suffix top (+ n 1)) tl)) :ruleset type-helpers) + +(rule ((= (TypeList-suffix list n) (TNil))) + ((set (TypeList-length list) n)) :ruleset type-helpers) + +(rule ((TypeList-ith list i) + (= (TypeList-length list) n) + (>= i n)) + ((panic "TypeList-ith out of bounds")) :ruleset type-helpers) + +(relation HasType (Expr Type)) + + +;; Keep track of type expectations for error messages +(relation ExpectType (Expr Type String)) +(rule ( + (ExpectType e expected msg) + (HasType e actual) + (!= expected actual) ;; OKAY to compare types for equality because we never union types. + ) + ((extract "Expecting expression") + (extract e) + (extract "to have type") + (extract expected) + (extract "but got type") + (extract actual) + (extract "with message") + (extract msg) + (panic "type mismatch")) + :ruleset error-checking) + +(relation HasArgType (Expr Type)) + +(rule ((HasArgType (Arg t1 ctx) t2) + (!= t1 t2)) + ((panic "arg type mismatch")) + :ruleset error-checking) + +(rule ((= lhs (Function name in out body)) + (HasArgType body ty) + (HasArgType body ty2) + (!= ty ty2)) + ((panic "arg type mismatch in function")) + :ruleset error-checking) + +; Propagate arg types up +(rule ((= lhs (Uop _ e)) + (HasArgType e ty)) + ((HasArgType lhs ty)) + :ruleset type-analysis) +(rule ((= lhs (Bop _ a b)) + (HasArgType a ty)) + ((HasArgType lhs ty)) + :ruleset type-analysis) +(rule ((= lhs (Bop _ a b)) + (HasArgType b ty)) + ((HasArgType lhs ty)) + :ruleset type-analysis) +(rule ((= lhs (Get e _)) + (HasArgType e ty)) + ((HasArgType lhs ty)) + :ruleset type-analysis) +(rule ((= lhs (Alloc _id e state _)) + (HasArgType e ty)) + ((HasArgType lhs ty)) + :ruleset type-analysis) +(rule ((= lhs (Call _ e)) + (HasArgType e ty)) + ((HasArgType lhs ty)) + :ruleset type-analysis) +(rule ((= lhs (Single e)) + (HasArgType e ty)) + ((HasArgType lhs ty)) + :ruleset type-analysis) +(rule ((= lhs (Concat e1 e2)) + (HasArgType e1 ty)) + ((HasArgType lhs ty)) + :ruleset type-analysis) +(rule ((= lhs (Concat e1 e2)) + (HasArgType e2 ty)) + ((HasArgType lhs ty)) + :ruleset type-analysis) +(rule ((= lhs (Switch pred inputs (Cons branch rest))) + (HasArgType pred ty)) + ((HasArgType lhs ty)) + :ruleset type-analysis) +(rule ((= lhs (Switch pred inputs (Cons branch rest))) + (HasArgType branch ty) + (HasType inputs ty2) + (!= ty ty2)) + ((panic "switch branches then branch has incorrect input type")) + :ruleset error-checking) +;; demand with one fewer branches +(rule ((= lhs (Switch pred inputs (Cons branch rest)))) + ((Switch pred inputs rest)) + :ruleset type-analysis) +(rule ((= lhs (If c i t e)) + (HasArgType c ty)) + ((HasArgType lhs ty)) + :ruleset type-analysis) +(rule ((= lhs (If c i t e)) + (HasType i ty) + (HasArgType t ty2) + (!= ty ty2)) + ((panic "if branches then branch has incorrect input type")) + :ruleset error-checking) +(rule ((= lhs (If c i t e)) + (HasType i ty) + (HasArgType e ty2) + (!= ty ty2)) + ((panic "if branches else branch has incorrect input type")) + :ruleset error-checking) + + +(rule ((= lhs (DoWhile ins body)) + (HasArgType ins ty)) + ((HasArgType lhs ty)) + :ruleset type-analysis) +; Don't push arg types through Program, Function, DoWhile, Let exprs because +; these create new arg contexts. + +; Primitives +(rule ((= lhs (Const (Int i) ty ctx))) + ((HasType lhs (Base (IntT))) + (HasArgType lhs ty)) + :ruleset type-analysis) + +(rule ((= lhs (Const (Bool b) ty ctx))) + ((HasType lhs (Base (BoolT))) + (HasArgType lhs ty)) + :ruleset type-analysis) + +(rule ((= lhs (Const (Float b) ty ctx))) + ((HasType lhs (Base (FloatT))) + (HasArgType lhs ty)) + :ruleset type-analysis) + +(rule ((= lhs (Empty ty ctx))) + ((HasType lhs (TupleT (TNil))) + (HasArgType lhs ty)) + :ruleset type-analysis) + +; Unary Ops +(rule ( + (= lhs (Uop (Not) e)) + (HasType e (Base (BoolT))) + ) + ((HasType lhs (Base (BoolT)))) + :ruleset type-analysis) +(rule ((= lhs (Uop (Not) e))) + ((ExpectType e (Base (BoolT)) "(Not)")) + :ruleset type-analysis) + + +(rule ( + (= lhs (Bop (Print) e state)) + (HasType e _ty) ; just make sure it has some type. + ) + ((HasType lhs (Base (StateT)))) + :ruleset type-analysis) + +(rule ( + (= lhs (Bop (Print) e state)) + (HasType e (TupleT ty)) + ) + ((panic "Don't print a tuple")) + :ruleset error-checking) + +(rule ((= lhs (Bop (Free) e s)) + (HasType e (Base (PointerT _ty)))) + ((HasType lhs (Base (StateT)))) + :ruleset type-analysis) +(rule ((= lhs (Bop (Free) e s)) + (HasType e (Base (IntT)))) + ((panic "Free expected pointer, received integer")) + :ruleset error-checking) +(rule ((= lhs (Bop (Free) e s)) + (HasType e (TupleT _ty))) + ((panic "Free expected pointer, received tuple")) + :ruleset error-checking) + +(rule ( + (= lhs (Bop (Load) e state)) + (HasType e (Base (PointerT ty))) + ) + ((HasType lhs (TupleT (TCons ty (TCons (StateT) (TNil)))))) + :ruleset type-analysis) +(rule ( + (= lhs (Bop (Load) e state)) + (HasType e ty) + (= ty (Base (IntT))) + ) + ((panic "(Load) expected pointer, received int")) + :ruleset error-checking) +(rule ( + (= lhs (Bop (Load) e state)) + (HasType e ty) + (= ty (TupleT x)) + ) + ((panic "(Load) expected pointer, received tuple")) + :ruleset error-checking) + +; Binary ops + +;; Operators that have type Type -> Type -> Type +;; Note we only do this generic matching for binary +;; operator since there's a lot of them. +;; In the future we can also extend to other constructs. +(relation bop-of-type (BinaryOp Type)) +(bop-of-type (Add) (Base (IntT))) +(bop-of-type (Sub) (Base (IntT))) +(bop-of-type (Div) (Base (IntT))) +(bop-of-type (Mul) (Base (IntT))) +(bop-of-type (FAdd) (Base (FloatT))) +(bop-of-type (FSub) (Base (FloatT))) +(bop-of-type (FDiv) (Base (FloatT))) +(bop-of-type (FMul) (Base (FloatT))) + +(rule ( + (= lhs (Bop op e1 e2)) + (bop-of-type op ty) + (HasType e1 ty) + (HasType e2 ty) + ) + ((HasType lhs ty)) + :ruleset type-analysis) +(rule ((= lhs (Bop op e1 e2)) + (bop-of-type op ty) + (bop->string op op-str)) + ( + (ExpectType e1 ty op-str) + (ExpectType e2 ty op-str) + ) + :ruleset type-analysis) + +;; Operators that have type Float -> Float -> Bool +(relation bpred-of-type (BinaryOp Type)) +(bpred-of-type (FLessThan) (Base (FloatT))) +(bpred-of-type (FLessEq) (Base (FloatT))) +(bpred-of-type (FGreaterThan) (Base (FloatT))) +(bpred-of-type (FGreaterEq) (Base (FloatT))) +(bpred-of-type (FEq) (Base (FloatT))) +(bpred-of-type (LessThan) (Base (IntT))) +(bpred-of-type (LessEq) (Base (IntT))) +(bpred-of-type (GreaterThan) (Base (IntT))) +(bpred-of-type (GreaterEq) (Base (IntT))) +(bpred-of-type (Eq) (Base (IntT))) +(bpred-of-type (And) (Base (BoolT))) +(bpred-of-type (Or) (Base (BoolT))) + +(rule ( + (= lhs (Bop pred e1 e2)) + (bpred-of-type pred ty) + (HasType e1 ty) + (HasType e2 ty) + ) + ((HasType lhs (Base (BoolT)))) + :ruleset type-analysis) +(rule ((= lhs (Bop pred e1 e2)) + (bpred-of-type pred ty) + (bop->string pred pred-str)) + ( + (ExpectType e1 ty pred-str) + (ExpectType e2 ty pred-str) + ) + :ruleset type-analysis) + +(rule ( + (= lhs (Top (Write) ptr val state)) + (HasType ptr (Base (PointerT ty))) + (HasType val (Base t)) ; TODO need to support pointers to pointers + ) + ((HasType lhs (Base (StateT)))) ; Write returns () + :ruleset type-analysis) + +(rule ( + (= lhs (Top (Write) ptr val state)) + (HasType ptr (Base (PointerT ty)))) + ((ExpectType val (Base ty) "(Write)")) + :ruleset type-analysis) + + + +(rule ( + (= lhs (Bop (PtrAdd) ptr n)) + (HasType ptr (Base (PointerT ty))) + (HasType n (Base (IntT))) + ) + ((HasType lhs (Base (PointerT ty)))) + :ruleset type-analysis) + +; Other ops +(rule ((= lhs (Alloc _id amt state ty))) + ((ExpectType amt (Base (IntT)) "(Alloc)")) + :ruleset type-analysis) + +(rule ( + (= lhs (Alloc _id amt state ty)) + (HasType amt (Base (IntT))) + ) + ((HasType lhs (TupleT (TCons ty (TCons (StateT) (TNil)))))) + :ruleset type-analysis) + +(rule ( + (= lhs (Get e i)) + (HasType e (TupleT tylist)) + ) + ; TypeList-ith needs to compute immediately, so we need to saturate type-helpers + ; rules between every iter of type-analysis rules. + ((HasType lhs (Base (TypeList-ith tylist i)))) + :ruleset type-analysis) + +(rule ( + (HasType (Get expr i) (TupleT tl)) + (= (TypeList-length tl) len) + (>= i len)) + ((panic "index out of bounds")) + :ruleset error-checking) +(rule ( + (HasType (Get expr i) (TupleT tl)) + (= (TypeList-length tl) len) + (< i 0) + ) + ((panic "negative index")) + :ruleset error-checking) + +; ================================= +; Tuple operations +; ================================= + +(rule ( + (= lhs (Single e)) + (HasType e (TupleT tylist)) + ) + ((panic "don't nest tuples")) + :ruleset error-checking) + +(rule ( + (= lhs (Single e)) + (HasType e (Base basety)) + ) + ((HasType lhs (TupleT (TCons basety (TNil))))) + :ruleset type-analysis) + +(rule ( + (= lhs (Concat e1 e2)) + (HasType e1 (TupleT tylist1)) + (HasType e2 (TupleT tylist2)) + ) + ; TLConcat needs to compute immediately, so we need to saturate type-helpers + ; rules between every iter of type-analysis rules. + ((HasType lhs (TupleT (TLConcat tylist1 tylist2)))) + :ruleset type-analysis) + +; ================================= +; Control flow +; ================================= +(rule ((= lhs (If pred inputs then else))) + ((ExpectType pred (Base (BoolT)) "If predicate must be boolean")) + :ruleset type-analysis) +(rule ( + (= lhs (If pred inputs then else)) + (HasType pred (Base (BoolT))) + (HasType then ty) + (HasType else ty) + ) + ((HasType lhs ty)) + :ruleset type-analysis) + +(rule ( + (= lhs (If pred inputs then else)) + (HasType pred (Base (BoolT))) + (HasType then tya) + (HasType else tyb) + (!= tya tyb) + ) + ((panic "if branches had different types")) + :ruleset error-checking) + + + +(rule ((= lhs (Switch pred inputs branches))) + ((ExpectType pred (Base (IntT)) "Switch predicate must be integer")) + :ruleset type-analysis) + +; base case: single branch switch has type of branch +(rule ( + (= lhs (Switch pred inputs (Cons branch (Nil)))) + (HasType pred (Base (IntT))) + (HasType branch ty) + ) + ((HasType lhs ty)) + :ruleset type-analysis) + +; recursive case: peel off a layer +(rule ((Switch pred inputs (Cons branch rest))) + ((Switch pred inputs rest)) + :ruleset type-analysis) + +(rule ( + (= lhs (Switch pred inputs (Cons branch rest))) + (HasType pred (Base (IntT))) + (HasType branch ty) + (HasType (Switch pred inputs rest) ty) ; rest of the branches also have type ty + ) + ((HasType lhs ty)) + :ruleset type-analysis) + +(rule ( + (= lhs (Switch pred inputs (Cons branch rest))) + (HasType pred (Base (IntT))) + (HasType branch tya) + (HasType (Switch pred inputs rest) tyb) + (!= tya tyb) + ) + ((panic "switch branches had different types")) + :ruleset error-checking) + +(rule ((Arg ty ctx)) + ( + (HasType (Arg ty ctx) ty) + (HasArgType (Arg ty ctx) ty) + ) + :ruleset type-analysis) + + +(rule ( + (= lhs (DoWhile inp pred-body)) + (HasType inp (Base ty)) + ) + ((panic "loop input must be tuple")) + :ruleset error-checking) +(rule ( + (= lhs (DoWhile inp pred-body)) + (HasType inp (Base (PointerT ty))) + ) + ((panic "loop input must be tuple")) + :ruleset error-checking) +(rule ( + (= lhs (DoWhile inp pred-body)) + (HasType pred-body (Base ty)) + ) + ((panic "loop pred-body must be tuple")) + :ruleset error-checking) +(rule ( + (= lhs (DoWhile inp pred-body)) + (HasType pred-body (Base (PointerT ty))) + ) + ((panic "loop pred-body must be tuple")) + :ruleset error-checking) + +(rule ( + (= lhs (DoWhile inp pred-body)) + (HasType inp (TupleT tylist)) + ) + ((HasArgType pred-body (TupleT tylist))) + :ruleset type-analysis) + +(rule ((= lhs (DoWhile inp pred-body))) + ((ExpectType (Get pred-body 0) (Base (BoolT)) "loop pred must be bool")) + :ruleset type-analysis) + +(rule ( + (= lhs (DoWhile inp pred-body)) + (HasType inp (TupleT tylist)) ; input is a tuple + ; pred-body is a tuple where the first elt is a bool + ; and the rest of the list matches the input type + (HasType pred-body (TupleT (TCons (BoolT) tylist))) + ) + ((HasType lhs (TupleT tylist))) ; whole thing has type of inputs/outputs + :ruleset type-analysis) + +(rule ( + (= lhs (DoWhile inp pred-body)) + (HasType inp (TupleT in-tys)) + (HasType pred-body (TupleT (TCons (BoolT) out-tys))) + (!= in-tys out-tys) + ) + ((panic "input types and output types don't match")) + :ruleset error-checking) + +; ================================= +; Functions +; ================================= + +(rule ((= lhs (Function name in-ty out-ty body))) + ( + ; Arg should have the specified type in the body + (HasArgType body in-ty) + ; Expect the body to have the specified output type + (ExpectType body out-ty "Function body had wrong type") + ) + :ruleset type-analysis) + +(rule ( + (= lhs (Call name arg)) + (Function name in-ty out-ty body) + ) + ; Expect the arg to have the right type for the function + ((ExpectType arg in-ty "function called with wrong arg type")) + :ruleset type-analysis) + +(rule ( + (= lhs (Call name arg)) + (Function name in-ty out-ty body) + (HasType arg in-ty) + ; We don't need to check the type of the function body, it will + ; be checked elsewhere. If we did require (HasType body out-ty), + ; recursive functions would not get assigned a type. + ) + ((HasType lhs out-ty)) + :ruleset type-analysis) + +; find which types are pure +(relation PureBaseType (BaseType)) +(relation PureType (Type)) +(relation PureTypeList (TypeList)) + +(PureBaseType (IntT)) +(PureBaseType (BoolT)) +(rule ((Base ty) + (PureBaseType ty)) + ((PureType (Base ty))) + :ruleset type-analysis) +(rule ((TupleT tylist) + (PureTypeList tylist)) + ((PureType (TupleT tylist))) + :ruleset type-analysis) +(rule ((TNil)) + ((PureTypeList (TNil))) + :ruleset type-analysis) +(rule ((TCons hd tl) + (PureBaseType hd) + (PureTypeList tl)) + ((PureTypeList (TCons hd tl))) + :ruleset type-analysis) + +(function ListExpr-length (ListExpr) i64) +(function ListExpr-ith (ListExpr i64) Expr :unextractable) +(function ListExpr-suffix (ListExpr i64) ListExpr :unextractable) +(function Append (ListExpr Expr) ListExpr :unextractable) + +(rule ((Switch pred inputs branch)) ((union (ListExpr-suffix branch 0) branch)) :ruleset always-run) + +(rule ((= (ListExpr-suffix top n) (Cons hd tl))) + ((union (ListExpr-ith top n) hd) + (union (ListExpr-suffix top (+ n 1)) tl)) :ruleset always-run) + +(rule ((= (ListExpr-suffix list n) (Nil))) + ((set (ListExpr-length list) n)) :ruleset always-run) + +(rewrite (Append (Cons a b) e) + (Cons a (Append b e)) + :ruleset always-run) +(rewrite (Append (Nil) e) + (Cons e (Nil)) + :ruleset always-run) + +(function tuple-length (Expr) i64 :unextractable) + +(rule ((HasType expr (TupleT tl)) + (= len (TypeList-length tl))) + ((set (tuple-length expr) len)) :ruleset always-run) + +;; Create a Get for every index, and rewrite it to see through Concat +(rule ((Single expr)) ((union (Get (Single expr) 0) expr)) :ruleset always-run) +;; initial get +(rule ((> (tuple-length tuple) 0)) + ((Get tuple 0)) + :ruleset always-run) +;; next get +(rule ((= len (tuple-length tuple)) + (= ith (Get tuple i)) + (< (+ i 1) len) + ) + ((Get tuple (+ 1 i))) + :ruleset always-run) + +;; descend left +(rule ((Get (Concat expr1 expr2) i) + (= (tuple-length expr1) len1) + (< i len1)) + ((union (Get (Concat expr1 expr2) i) + (Get expr1 i))) + :ruleset always-run) +;; descend right +(rule ((Get (Concat expr1 expr2) i) + (= (tuple-length expr1) len1) + (>= i len1)) + ((union (Get (Concat expr1 expr2) i) + (Get expr2 (- i len1)))) + :ruleset always-run) + + +;; A temporary context. +;; Be sure to delete at the end of all actions or else!!! +;; This is safer than using a persistant context, since we may miss an important part of the query. +(function TmpCtx () Assumption) + +(rule ((TmpCtx)) + ((panic "TmpCtx should not exist outside rule body")) + :ruleset always-run) + + +(ruleset subsume-after-helpers) +;; After running the `saturating` ruleset, these if statements can be subsumed +(relation ToSubsumeIf (Expr Expr Expr Expr)) +; (rule ((ToSubsumeIf a b c d)) +; ((subsume (If a b c d))) +; :ruleset subsume-after-helpers) + + + +(relation ExprIsValid (Expr)) +(relation ListExprIsValid (ListExpr)) +(rule ((ExprIsValid (Function _name _tyin _tyout _out))) ((ExprIsValid _out)) :ruleset always-run) +(rule ((ExprIsValid (Top _op _x _y _z))) ((ExprIsValid _x) +(ExprIsValid _y) +(ExprIsValid _z)) :ruleset always-run) +(rule ((ExprIsValid (Bop _op _x _y))) ((ExprIsValid _x) +(ExprIsValid _y)) :ruleset always-run) +(rule ((ExprIsValid (Uop _op _x))) ((ExprIsValid _x)) :ruleset always-run) +(rule ((ExprIsValid (Get _tup _i))) ((ExprIsValid _tup)) :ruleset always-run) +(rule ((ExprIsValid (Concat _x _y))) ((ExprIsValid _x) +(ExprIsValid _y)) :ruleset always-run) +(rule ((ExprIsValid (Single _x))) ((ExprIsValid _x)) :ruleset always-run) +(rule ((ExprIsValid (Switch _pred _inputs _branches))) ((ExprIsValid _pred) +(ExprIsValid _inputs) +(ListExprIsValid _branches)) :ruleset always-run) +(rule ((ExprIsValid (If _pred _input _then _else))) ((ExprIsValid _pred) +(ExprIsValid _input) +(ExprIsValid _then) +(ExprIsValid _else)) :ruleset always-run) +(rule ((ExprIsValid (DoWhile _in _pred-and-output))) ((ExprIsValid _in) +(ExprIsValid _pred-and-output)) :ruleset always-run) +(rule ((ExprIsValid (Call _func _arg))) ((ExprIsValid _arg)) :ruleset always-run) +(rule ((ListExprIsValid (Cons _hd _tl))) ((ExprIsValid _hd) +(ListExprIsValid _tl)) :ruleset always-run) +(rule ((ExprIsValid (Alloc _id _e _state _ty))) ((ExprIsValid _e) +(ExprIsValid _state)) :ruleset always-run) +(relation ExprIsResolved (Expr)) +(relation ListExprIsResolved (ListExpr)) +(rule ((= lhs (Function _name _tyin _tyout _out)) (ExprIsResolved _out)) ((ExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (Const _n _ty _ctx)) ) ((ExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (Top _op _x _y _z)) (ExprIsResolved _x) +(ExprIsResolved _y) +(ExprIsResolved _z)) ((ExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (Bop _op _x _y)) (ExprIsResolved _x) +(ExprIsResolved _y)) ((ExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (Uop _op _x)) (ExprIsResolved _x)) ((ExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (Get _tup _i)) (ExprIsResolved _tup)) ((ExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (Concat _x _y)) (ExprIsResolved _x) +(ExprIsResolved _y)) ((ExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (Single _x)) (ExprIsResolved _x)) ((ExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (Switch _pred _inputs _branches)) (ExprIsResolved _pred) +(ExprIsResolved _inputs) +(ListExprIsResolved _branches)) ((ExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (If _pred _input _then _else)) (ExprIsResolved _pred) +(ExprIsResolved _input) +(ExprIsResolved _then) +(ExprIsResolved _else)) ((ExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (DoWhile _in _pred-and-output)) (ExprIsResolved _in) +(ExprIsResolved _pred-and-output)) ((ExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (Arg _ty _ctx)) ) ((ExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (Call _func _arg)) (ExprIsResolved _arg)) ((ExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (Empty _ty _ctx)) ) ((ExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (Cons _hd _tl)) (ExprIsResolved _hd) +(ListExprIsResolved _tl)) ((ListExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (Nil)) ) ((ListExprIsResolved lhs)) :ruleset always-run) +(rule ((= lhs (Alloc _id _e _state _ty)) (ExprIsResolved _e) +(ExprIsResolved _state)) ((ExprIsResolved lhs)) :ruleset always-run) +(relation BodyContainsExpr (Expr Expr)) +(relation BodyContainsListExpr (Expr ListExpr)) +(rule ((Function _name _tyin _tyout _out)) ((BodyContainsExpr (Function _name _tyin _tyout _out) _out)) :ruleset always-run) +(rule ((If _pred _input _then _else)) ((BodyContainsExpr (If _pred _input _then _else) _then) (BodyContainsExpr (If _pred _input _then _else) _else)) :ruleset always-run) +(rule ((DoWhile _in _pred-and-output)) ((BodyContainsExpr (DoWhile _in _pred-and-output) _pred-and-output)) :ruleset always-run) +(rule ((BodyContainsExpr body (Top _op _x _y _z))) ((BodyContainsExpr body _x) (BodyContainsExpr body _y) (BodyContainsExpr body _z)) :ruleset always-run) +(rule ((BodyContainsExpr body (Bop _op _x _y))) ((BodyContainsExpr body _x) (BodyContainsExpr body _y)) :ruleset always-run) +(rule ((BodyContainsExpr body (Uop _op _x))) ((BodyContainsExpr body _x)) :ruleset always-run) +(rule ((BodyContainsExpr body (Get _tup _i))) ((BodyContainsExpr body _tup)) :ruleset always-run) +(rule ((BodyContainsExpr body (Concat _x _y))) ((BodyContainsExpr body _x) (BodyContainsExpr body _y)) :ruleset always-run) +(rule ((BodyContainsExpr body (Single _x))) ((BodyContainsExpr body _x)) :ruleset always-run) +(rule ((BodyContainsExpr body (Switch _pred _inputs _branches))) ((BodyContainsExpr body _pred) (BodyContainsExpr body _inputs)) :ruleset always-run) +(rule ((BodyContainsExpr body (If _pred _input _then _else))) ((BodyContainsExpr body _pred) (BodyContainsExpr body _input)) :ruleset always-run) +(rule ((BodyContainsExpr body (DoWhile _in _pred-and-output))) ((BodyContainsExpr body _in)) :ruleset always-run) +(rule ((BodyContainsExpr body (Call _func _arg))) ((BodyContainsExpr body _arg)) :ruleset always-run) +(rule ((BodyContainsListExpr body (Cons _hd _tl))) ((BodyContainsExpr body _hd)) :ruleset always-run) +(rule ((BodyContainsExpr body (Alloc _id _e _state _ty))) ((BodyContainsExpr body _e) (BodyContainsExpr body _state)) :ruleset always-run) + + (relation ExprIsPure (Expr)) + (relation ListExprIsPure (ListExpr)) + (relation BinaryOpIsPure (BinaryOp)) + (relation UnaryOpIsPure (UnaryOp)) + (relation TopIsPure (TernaryOp)) +(TopIsPure (Select)) +(BinaryOpIsPure (Add)) +(BinaryOpIsPure (Sub)) +(BinaryOpIsPure (Mul)) +(BinaryOpIsPure (Div)) +(BinaryOpIsPure (Eq)) +(BinaryOpIsPure (LessThan)) +(BinaryOpIsPure (GreaterThan)) +(BinaryOpIsPure (LessEq)) +(BinaryOpIsPure (GreaterEq)) +(BinaryOpIsPure (FAdd)) +(BinaryOpIsPure (FSub)) +(BinaryOpIsPure (FMul)) +(BinaryOpIsPure (FDiv)) +(BinaryOpIsPure (FEq)) +(BinaryOpIsPure (FLessThan)) +(BinaryOpIsPure (FGreaterThan)) +(BinaryOpIsPure (FLessEq)) +(BinaryOpIsPure (FGreaterEq)) +(BinaryOpIsPure (And)) +(BinaryOpIsPure (Or)) +(BinaryOpIsPure (PtrAdd)) +(UnaryOpIsPure (Not)) + + (rule ((Function _name _tyin _tyout _out) (ExprIsPure _out)) + ((ExprIsPure (Function _name _tyin _tyout _out))) + :ruleset always-run) + + (rule ((Const _n _ty _ctx)) + ((ExprIsPure (Const _n _ty _ctx))) + :ruleset always-run) + + (rule ((Top _op _x _y _z) (ExprIsPure _x) (ExprIsPure _y) (ExprIsPure _z)) + ((ExprIsPure (Top _op _x _y _z))) + :ruleset always-run) + + (rule ((Bop _op _x _y) (BinaryOpIsPure _op) (ExprIsPure _x) (ExprIsPure _y)) + ((ExprIsPure (Bop _op _x _y))) + :ruleset always-run) + + (rule ((Uop _op _x) (UnaryOpIsPure _op) (ExprIsPure _x)) + ((ExprIsPure (Uop _op _x))) + :ruleset always-run) + + (rule ((Get _tup _i) (ExprIsPure _tup)) + ((ExprIsPure (Get _tup _i))) + :ruleset always-run) + + (rule ((Concat _x _y) (ExprIsPure _x) (ExprIsPure _y)) + ((ExprIsPure (Concat _x _y))) + :ruleset always-run) + + (rule ((Single _x) (ExprIsPure _x)) + ((ExprIsPure (Single _x))) + :ruleset always-run) + + (rule ((Switch _pred _inputs _branches) (ExprIsPure _pred) (ExprIsPure _inputs) (ListExprIsPure _branches)) + ((ExprIsPure (Switch _pred _inputs _branches))) + :ruleset always-run) + + (rule ((If _pred _input _then _else) (ExprIsPure _pred) (ExprIsPure _input) (ExprIsPure _then) (ExprIsPure _else)) + ((ExprIsPure (If _pred _input _then _else))) + :ruleset always-run) + + (rule ((DoWhile _in _pred-and-output) (ExprIsPure _in) (ExprIsPure _pred-and-output)) + ((ExprIsPure (DoWhile _in _pred-and-output))) + :ruleset always-run) + + (rule ((Arg _ty _ctx)) + ((ExprIsPure (Arg _ty _ctx))) + :ruleset always-run) + + (rule ((Call _f _arg) (ExprIsPure _arg) (ExprIsPure (Function _f inty outty out))) + ((ExprIsPure (Call _f _arg))) + :ruleset always-run) + + (rule ((Empty _ty _ctx)) + ((ExprIsPure (Empty _ty _ctx))) + :ruleset always-run) + + (rule ((Cons _hd _tl) (ExprIsPure _hd) (ListExprIsPure _tl)) + ((ListExprIsPure (Cons _hd _tl))) + :ruleset always-run) + + (rule ((Nil)) + ((ListExprIsPure (Nil))) + :ruleset always-run) + +; This file provides AddContext, a helpers that copies a sub-egraph into +; a new one with a new context. +; Users of AddContext can specify how deeply to do this copy. + + +(ruleset context) + +(function AddContext (Assumption Expr) Expr :unextractable) +(function AddContextList (Assumption ListExpr) ListExpr :unextractable) + +;; ################################ saturation + +;; Adding context a second time does nothing, so union +(rule + ((= lhs (AddContext ctx inner)) + (= inner (AddContext ctx expr))) + ((union lhs inner)) + :ruleset context) + + +;; ############################## Base cases- leaf nodes + +;; replace existing contexts that are around leaf nodes +;; AddContext assumes the new context is more specific than the old one +(rule ((= lhs (AddContext ctx (Arg ty oldctx)))) + ((union lhs (Arg ty ctx))) + :ruleset context) +(rule ((= lhs (AddContext ctx (Const c ty oldctx)))) + ((union lhs (Const c ty ctx))) + :ruleset context) +(rule ((= lhs (AddContext ctx (Empty ty oldctx)))) + ((union lhs (Empty ty ctx))) + :ruleset context) + + + + +;; ######################################### Operators +(rewrite (AddContext ctx (Bop op c1 c2)) + (Bop op + (AddContext ctx c1) + (AddContext ctx c2)) + :ruleset context) +(rewrite (AddContext ctx (Uop op c1)) + (Uop op (AddContext ctx c1)) + :ruleset context) +(rewrite (AddContext ctx (Get c1 index)) + (Get (AddContext ctx c1) index) + :ruleset context) +(rewrite (AddContext ctx (Alloc id c1 state ty)) + (Alloc id (AddContext ctx c1) (AddContext ctx state) ty) + :ruleset context) +(rewrite (AddContext ctx (Call name c1)) + (Call name (AddContext ctx c1)) + :ruleset context) + +(rewrite (AddContext ctx (Single c1)) + (Single (AddContext ctx c1)) + :ruleset context) +(rewrite (AddContext ctx (Concat c1 c2)) + (Concat + (AddContext ctx c1) + (AddContext ctx c2)) + :ruleset context) + +;; ################################### List operators + +(rewrite (AddContextList ctx (Nil)) + (Nil) + :ruleset context) + +(rewrite (AddContextList ctx (Cons c1 rest)) + (Cons (AddContext ctx c1) + (AddContextList ctx rest)) + :ruleset context) + + +;; ########################################## Control flow +(rewrite (AddContext ctx (Switch pred inputs branches)) + (Switch (AddContext ctx pred) + (AddContext ctx inputs) + branches) + :ruleset context) + +;; For stop at region, still add context to inputs +(rule ((= lhs (AddContext ctx (If pred inputs c1 c2)))) + ((union lhs + (If (AddContext ctx pred) + (AddContext ctx inputs) + c1 + c2))) + :ruleset context) + + +;; For stop at loop, still add context to inputs +(rule ((= lhs (AddContext ctx (DoWhile inputs outputs)))) + ((union lhs + (DoWhile + (AddContext ctx inputs) + outputs))) + :ruleset context) + + +;; Substitution rules allow for substituting some new expression for the argument +;; in some new context. +;; It performs the substitution, copying over the equalities from the original eclass. +;; It only places context on the leaf nodes. + +(ruleset subst) +(ruleset apply-subst-unions) +(ruleset cleanup-subst) + +;; (Subst assumption to in) substitutes `to` for `(Arg ty)` in `in`. +;; It also replaces the leaf context in `to` with `assumption` using `AddContext`. +;; `assumption` *justifies* this substitution, as the context that the result is used in. +;; In other words, it must refine the equivalence relation of `in` with `to` as the argument. +(function Subst (Assumption Expr Expr) Expr ) + +;; Used to delay unions for the subst ruleset. +;; This is necessary because substitution may not terminate if it can +;; observe its own results- it may create infinitly large terms. +;; Instead, we phase substitution by delaying resulting unions in this table. +;; After applying this table, substitutions and this table are cleared. +(function DelayedSubstUnion (Expr Expr) Expr ) + +;; add a type rule to get the arg type of a substitution +;; this enables nested substitutions +(rule ((= lhs (Subst assum to in)) + (HasArgType to ty)) + ((HasArgType lhs ty)) + :ruleset subst) + +;; leaf node with context +;; replace this context- subst assumes the context is more specific +(rule ((= lhs (Subst assum to (Arg ty oldctx))) + ) + ;; add the assumption `to` + ((DelayedSubstUnion lhs (AddContext assum to))) + :ruleset subst) +(rule ((= lhs (Subst assum to (Const c ty oldctx))) + (HasArgType to newty)) + ((DelayedSubstUnion lhs (Const c newty assum))) + :ruleset subst) +(rule ((= lhs (Subst assum to (Empty ty oldctx))) + (HasArgType to newty)) + ((DelayedSubstUnion lhs (Empty newty assum))) + :ruleset subst) + +;; Operators +(rule ((= lhs (Subst assum to (Bop op c1 c2))) + (ExprIsResolved (Bop op c1 c2))) + ((DelayedSubstUnion lhs + (Bop op (Subst assum to c1) + (Subst assum to c2)))) + :ruleset subst) +(rule ((= lhs (Subst assum to (Uop op c1))) + (ExprIsResolved (Uop op c1))) + ((DelayedSubstUnion lhs + (Uop op (Subst assum to c1)))) + :ruleset subst) + +(rule ((= lhs (Subst assum to (Get c1 index))) + (ExprIsResolved (Get c1 index))) + ((DelayedSubstUnion lhs + (Get (Subst assum to c1) index))) + :ruleset subst) +(rule ((= lhs (Subst assum to (Alloc id c1 c2 ty))) + (ExprIsResolved (Alloc id c1 c2 ty))) + ((DelayedSubstUnion lhs + (Alloc id (Subst assum to c1) + (Subst assum to c2) + ty))) + :ruleset subst) +(rule ((= lhs (Subst assum to (Call name c1))) + (ExprIsResolved (Call name c1))) + ((DelayedSubstUnion lhs + (Call name (Subst assum to c1)))) + :ruleset subst) + + +;; Tuple operators +(rule ((= lhs (Subst assum to (Single c1))) + (ExprIsResolved (Single c1))) + ((DelayedSubstUnion lhs + (Single (Subst assum to c1)))) + :ruleset subst) +(rule ((= lhs (Subst assum to (Concat c1 c2))) + (ExprIsResolved (Concat c1 c2))) + ((DelayedSubstUnion lhs + (Concat (Subst assum to c1) + (Subst assum to c2)))) + :ruleset subst) + +;; Control flow +(rule ((= lhs (Subst assum to inner)) + (= inner (Switch pred inputs c1)) + (ExprIsResolved inner)) + ((DelayedSubstUnion lhs + (Switch (Subst assum to pred) + (Subst assum to inputs) + c1))) + :ruleset subst) +(rule ((= lhs (Subst assum to inner)) + (= inner (If pred inputs c1 c2)) + (ExprIsResolved inner)) + ((DelayedSubstUnion lhs + (If (Subst assum to pred) + (Subst assum to inputs) + c1 + c2))) + :ruleset subst) +(rule ((= lhs (Subst assum to (DoWhile in out))) + (ExprIsResolved (DoWhile in out))) + ((DelayedSubstUnion lhs + (DoWhile (Subst assum to in) + out))) + :ruleset subst) + +;; substitute into function (convenience for testing) +(rewrite (Subst assum to (Function name inty outty body)) + (Function name inty outty (Subst assum to body)) + :when ((ExprIsResolved body)) + :ruleset subst) + + + +;; ########################### Apply subst unions + +(rule ((DelayedSubstUnion lhs rhs)) + ((union lhs rhs)) + :ruleset apply-subst-unions) + + +;; ########################### Cleanup subst and DelayedSubstUnion + +(rule ((DelayedSubstUnion lhs rhs)) + ((subsume (DelayedSubstUnion lhs rhs))) + :ruleset cleanup-subst) + +; this cleanup is important- if we don't subsume these substitutions, they +; may oberve their own results and create infinitely sized terms. +; ex: get(parallel!(arg(), int(2)), 0) ignores the first element of the tuple +; so it's equivalent to infinite other times with any other value as the first element of the tuple. +; Check ExprIsResolved to confirm that the substitution finished (all sub-substitutions are done). +(rule ((ExprIsResolved (Subst assum to in))) + ((subsume (Subst assum to in))) + :ruleset cleanup-subst) + +; We only have context for Exprs, not ListExprs. +(relation ContextOf (Expr Assumption)) + +(rule ((Arg ty ctx)) + ((ContextOf (Arg ty ctx) ctx)) + :ruleset always-run) +(rule ((Const c ty ctx)) + ((ContextOf (Const c ty ctx) ctx)) + :ruleset always-run) +(rule ((Empty ty ctx)) + ((ContextOf (Empty ty ctx) ctx)) + :ruleset always-run) + +; Error checking - each expr should only have a single context +(rule ((ContextOf x ctx1) + (ContextOf x ctx2) + (!= ctx1 ctx2)) + ( + (panic "Equivalent expressions have nonequivalent context, breaking the single context invariant.") + ) + :ruleset error-checking) + + +(rule ((Top op x y z) (ContextOf x ctx)) + ((ContextOf (Top op x y z) ctx)) :ruleset always-run) + +(rule ((Top op x y z) (ContextOf y ctx)) + ((ContextOf (Top op x y z) ctx)) :ruleset always-run) + +(rule ((Top op x y z) (ContextOf z ctx)) + ((ContextOf (Top op x y z) ctx)) :ruleset always-run) + +(rule ((Bop op x y) (ContextOf x ctx)) + ((ContextOf (Bop op x y) ctx)) :ruleset always-run) + +(rule ((Bop op x y) (ContextOf y ctx)) + ((ContextOf (Bop op x y) ctx)) :ruleset always-run) + +(rule ((Uop op x) (ContextOf x ctx)) + ((ContextOf (Uop op x) ctx)) :ruleset always-run) + +(rule ((Get tup i) (ContextOf tup ctx)) + ((ContextOf (Get tup i) ctx)) :ruleset always-run) + +(rule ((Concat x y) (ContextOf x ctx)) + ((ContextOf (Concat x y) ctx)) :ruleset always-run) + +(rule ((Concat x y) (ContextOf y ctx)) + ((ContextOf (Concat x y) ctx)) :ruleset always-run) + +(rule ((Single x) (ContextOf x ctx)) + ((ContextOf (Single x) ctx)) :ruleset always-run) + +(rule ((Switch pred inputs branches) (ContextOf pred ctx)) + ((ContextOf (Switch pred inputs branches) ctx)) :ruleset always-run) + +(rule ((If pred inputs then else) (ContextOf pred ctx)) + ((ContextOf (If pred inputs then else) ctx)) :ruleset always-run) + +(rule ((If pred inputs then else) (ContextOf inputs ctx)) + ((ContextOf (If pred inputs then else) ctx)) :ruleset always-run) + +(rule ((DoWhile in pred-and-output) (ContextOf in ctx)) + ((ContextOf (DoWhile in pred-and-output) ctx)) :ruleset always-run) + +(rule ((Call func arg) (ContextOf arg ctx)) + ((ContextOf (Call func arg) ctx)) :ruleset always-run) + +(rule ((Alloc amt e state ty) (ContextOf e ctx)) + ((ContextOf (Alloc amt e state ty) ctx)) :ruleset always-run) + +(rule ((Alloc amt e state ty) (ContextOf state ctx)) + ((ContextOf (Alloc amt e state ty) ctx)) :ruleset always-run) + +(ruleset canon) + +; Commutativity +(rewrite (Bop (Add) x y) (Bop (Add) y x) :ruleset canon) +(rewrite (Bop (Mul) x y) (Bop (Mul) y x) :ruleset canon) +(rewrite (Bop (Eq) x y) (Bop (Eq) y x) :ruleset canon) +(rewrite (Bop (And) x y) (Bop (And) y x) :ruleset canon) +(rewrite (Bop (Or) x y) (Bop (Or) y x) :ruleset canon) + +; Canonicalize to < +; x > y ==> y < x +(rewrite (Bop (GreaterThan) x y) (Bop (LessThan) y x) :ruleset canon) + +; x >= y ==> y < x + 1 +; x >= y ==> y - 1 < x +(rule ( + (= lhs (Bop (GreaterEq) x y)) + (HasArgType x ty) + (ContextOf lhs ctx) + ) + ( + (union lhs (Bop (LessThan) y (Bop (Add) x (Const (Int 1) ty ctx)))) + (union lhs (Bop (LessThan) (Bop (Sub) y (Const (Int 1) ty ctx)) x)) + ) + :ruleset canon) + +; x <= y ==> x < y + 1 +; x <= y ==> x - 1 < y +(rule ( + (= lhs (Bop (LessEq) x y)) + (HasArgType y ty) + (ContextOf lhs ctx) + ) + ( + (union lhs (Bop (LessThan) x (Bop (Add) y (Const (Int 1) ty ctx)))) + (union lhs (Bop (LessThan) (Bop (Sub) x (Const (Int 1) ty ctx)) y)) + ) + :ruleset canon) + + +; Make Concats right-deep +(rewrite (Concat (Concat a b) c) + (Concat a (Concat b c)) + :ruleset always-run) +; Simplify Concat's with empty +(rewrite (Concat (Empty ty ctx) x) + x + :ruleset always-run) +(rewrite (Concat x (Empty ty ctx)) + x + :ruleset always-run) + +; Make a tuple that is a sub-range of another tuple +; tuple start len +(function SubTuple (Expr i64 i64) Expr :unextractable) + +(rewrite (SubTuple expr x 0) + (Empty ty ctx) + :when ((HasArgType expr ty) (ContextOf expr ctx)) + :ruleset always-run) + +(rewrite (SubTuple expr x 1) + (Single (Get expr x)) + :ruleset always-run) + +(rewrite (SubTuple expr a b) + (Concat (Single (Get expr a)) (SubTuple expr (+ a 1) (- b 1))) + :when ((> b 1)) + :ruleset always-run) + +; Helper functions to remove one element from a tuple or type list +; tuple idx +(function TupleRemoveAt (Expr i64) Expr :unextractable) +(function TypeListRemoveAt (TypeList i64) TypeList :unextractable) + +(rewrite (TupleRemoveAt tuple idx) + (Concat (SubTuple tuple 0 idx) + (SubTuple tuple (+ idx 1) (- len (+ idx 1)))) + :when ((= len (tuple-length tuple))) + :ruleset always-run) + +(rewrite (TypeListRemoveAt (TNil) _idx) (TNil) :ruleset always-run) +(rewrite (TypeListRemoveAt (TCons x xs) 0 ) xs :ruleset always-run) +(rewrite (TypeListRemoveAt (TCons x xs) idx) + (TCons x (TypeListRemoveAt xs (- idx 1))) + :when ((> idx 0)) + :ruleset always-run) + +;; Compute the tree size of program, not dag size +(function Expr-size (Expr) i64 :unextractable :merge (min old new) ) +(function ListExpr-size (ListExpr) i64 :unextractable :merge (min old new)) + +(rule ((= expr (Function name tyin tyout out)) + (= sum (Expr-size out))) + ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) + +(rule ((= expr (Const n ty assum))) + ((set (Expr-size expr) 1)) :ruleset always-run) + +(rule ((= expr (Bop op x y)) + (= sum (+ (Expr-size y) (Expr-size x)))) + ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) + +(rule ((= expr (Uop op x)) + (= sum (Expr-size x))) + ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) + +(rule ((= expr (Get tup i)) + (= sum (Expr-size tup))) + ((set (Expr-size expr) sum)) :ruleset always-run) + +(rule ((= expr (Concat x y)) + (= sum (+ (Expr-size y) (Expr-size x)))) + ((set (Expr-size expr) sum)) :ruleset always-run) + +(rule ((= expr (Single x)) + (= sum (Expr-size x))) + ((set (Expr-size expr) sum)) :ruleset always-run) + +(rule ((= expr (Switch pred inputs branches)) + (= sum (+ (Expr-size inputs) (+ (ListExpr-size branches) (Expr-size pred))))) + ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) + +(rule ((= expr (If pred inputs then else)) + (= sum (+ (Expr-size inputs) (+ (Expr-size else) (+ (Expr-size then) (Expr-size pred)))))) + ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) + +(rule ((= expr (DoWhile in pred-and-output)) + (= sum (+ (Expr-size pred-and-output) (Expr-size in)))) + ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) + +(rule ((= expr (Arg ty assum))) + ((set (Expr-size expr) 1)) :ruleset always-run) + +(rule ((= expr (Call func arg)) + (= sum (Expr-size arg))) + ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) + +(rule ((Empty ty assum)) ((set (Expr-size (Empty ty assum)) 0)) :ruleset always-run) + +(rule ((= expr (Cons hd tl)) + (= sum (+ (ListExpr-size tl) (Expr-size hd)))) + ((set (ListExpr-size expr) sum)) :ruleset always-run) + +(rule ((Nil)) + ((set (ListExpr-size (Nil)) 0)) :ruleset always-run) + +(rule ((= expr (Alloc id e state ty)) ;; do state edge's expr should be counted? + (= sum (Expr-size e))) + ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) +;; Like Subst but for dropping inputs to a region +;; See subst.egg for more implementation documentation + +(ruleset drop) +(ruleset apply-drop-unions) +(ruleset cleanup-drop) + +;; (DropAt ctx idx in) removes all references to `(Get (Arg ...) idx)` in `in`. +;; It also replaces the leaf contexts with `ctx` and fixes up argument types, +;; as well as updating `(Get (Arg ...) j)` to `(Get (Arg ...) (- j 1))` for j > idx. +(function DropAt (Assumption i64 Expr) Expr :unextractable) +(function DelayedDropUnion (Expr Expr) Expr :unextractable) + +;; Helper that precomputes the arg type that we need +(function DropAtInternal (Type Assumption i64 Expr) Expr :unextractable) +(rule ((= lhs (DropAt ctx idx in)) + (HasArgType in (TupleT oldty))) + + ((let newty (TupleT (TypeListRemoveAt oldty idx))) + (union lhs (DropAtInternal newty ctx idx in))) + :ruleset drop) + +;; Leaves +(rule ((= lhs (DropAtInternal newty newctx idx (Const c oldty oldctx)))) + ((DelayedDropUnion lhs (Const c newty newctx))) + :ruleset drop) +(rule ((= lhs (DropAtInternal newty newctx idx (Empty oldty oldctx)))) + ((DelayedDropUnion lhs (Empty newty newctx))) + :ruleset drop) +; get stuck on purpose if `i = idx` or if we find a bare `Arg` +(rule ((= lhs (DropAtInternal newty newctx idx (Get (Arg oldty oldctx) i))) + (< i idx)) + ((DelayedDropUnion lhs (Get (Arg newty newctx) i))) + :ruleset drop) +(rule ((= lhs (DropAtInternal newty newctx idx (Get (Arg oldty oldctx) i))) + (> i idx)) + ((DelayedDropUnion lhs (Get (Arg newty newctx) (- i 1)))) + :ruleset drop) + +;; Operators +(rule ((= lhs (DropAtInternal newty newctx idx (Bop op c1 c2))) + (ExprIsResolved (Bop op c1 c2))) + ((DelayedDropUnion lhs (Bop op + (DropAtInternal newty newctx idx c1) + (DropAtInternal newty newctx idx c2)))) + :ruleset drop) + +(rule ((= lhs (DropAtInternal newty newctx idx (Uop op c1))) + (ExprIsResolved (Uop op c1))) + ((DelayedDropUnion lhs (Uop op + (DropAtInternal newty newctx idx c1)))) + :ruleset drop) + +;; this is okay because we get stuck at `Arg`s +(rule ((= lhs (DropAtInternal newty newctx idx (Get c1 index))) + (ExprIsResolved (Get c1 index))) + ((DelayedDropUnion lhs (Get + (DropAtInternal newty newctx idx c1) + index))) + :ruleset drop) + +(rule ((= lhs (DropAtInternal newty newctx idx (Alloc id c1 c2 ty))) + (ExprIsResolved (Alloc id c1 c2 ty))) + ((DelayedDropUnion lhs (Alloc id + (DropAtInternal newty newctx idx c1) + (DropAtInternal newty newctx idx c2) + ty))) + :ruleset drop) + +(rule ((= lhs (DropAtInternal newty newctx idx (Call name c1))) + (ExprIsResolved (Call name c1))) + ((DelayedDropUnion lhs (Call name + (DropAtInternal newty newctx idx c1)))) + :ruleset drop) + +;; Tuple operators +(rule ((= lhs (DropAtInternal newty newctx idx (Single c1))) + (ExprIsResolved (Single c1))) + ((DelayedDropUnion lhs (Single + (DropAtInternal newty newctx idx c1)))) + :ruleset drop) + +(rule ((= lhs (DropAtInternal newty newctx idx (Concat c1 c2))) + (ExprIsResolved (Concat c1 c2))) + ((DelayedDropUnion lhs (Concat + (DropAtInternal newty newctx idx c1) + (DropAtInternal newty newctx idx c2)))) + :ruleset drop) + +;; Control flow +(rule ((= lhs (DropAtInternal newty newctx idx (Switch pred inputs c1))) + (ExprIsResolved (Switch pred inputs c1))) + ((DelayedDropUnion lhs (Switch + (DropAtInternal newty newctx idx pred) + (DropAtInternal newty newctx idx inputs) + c1))) + :ruleset drop) + +(rule ((= lhs (DropAtInternal newty newctx idx (If pred inputs c1 c2))) + (ExprIsResolved (If pred inputs c1 c2))) + ((DelayedDropUnion lhs (If + (DropAtInternal newty newctx idx pred) + (DropAtInternal newty newctx idx inputs) + c1 + c2))) + :ruleset drop) + +(rule ((= lhs (DropAtInternal newty newctx idx (DoWhile in out))) + (ExprIsResolved (DoWhile in out))) + ((DelayedDropUnion lhs (DoWhile + (DropAtInternal newty newctx idx in) + out))) + :ruleset drop) + +(rewrite (DropAtInternal newty newctx idx (Function name inty outty body)) + (Function name inty outty (DropAtInternal newty newctx idx body)) + :when ((ExprIsResolved body)) + :ruleset drop) + + + +;; ########################### Apply drop unions + +(rule ((DelayedDropUnion lhs rhs)) + ((union lhs rhs)) + :ruleset apply-drop-unions) + +;; ########################### Cleanup Dropat, DropAtInternal and DelayedDropUnion + +(rule ((ExprIsResolved (DropAt newctx idx in))) + ((subsume (DropAt newctx idx in))) + :ruleset cleanup-drop) + +(rule ((ExprIsResolved (DropAtInternal newty newctx idx in))) + ((subsume (DropAtInternal newty newctx idx in))) + :ruleset cleanup-drop) + +(rule ((DelayedDropUnion lhs rhs)) + ((subsume (DelayedDropUnion lhs rhs))) + :ruleset cleanup-drop) + +(ruleset interval-analysis) + +(datatype Bound + (IntB i64) + (BoolB bool) + (bound-max Bound Bound) + (bound-min Bound Bound)) + +; bound tables +(function lo-bound (Expr) Bound :unextractable :merge (bound-max old new)) +(function hi-bound (Expr) Bound :unextractable :merge (bound-min old new)) + +; if lo > hi, panic +; We can't run these rules because unreachable branches may have impossible intervals +; Consider re-enabling these rules if we implement an is-reachable analysis +; (rule ( +; (= (IntB lo) (lo-bound expr)) +; (= (IntB hi) (hi-bound expr)) +; (> lo hi) +; ) +; ((panic "lo bound greater than hi bound")) +; :ruleset interval-analysis) +; (rule ( +; (= (BoolB true) (lo-bound expr)) +; (= (BoolB false) (hi-bound expr)) +; ) +; ((panic "lo bound greater than hi bound")) +; :ruleset interval-analysis) + +; combinators +(rewrite (bound-max (IntB x) (IntB y)) + (IntB (max x y)) + :ruleset interval-analysis) +(rewrite (bound-min (IntB x) (IntB y)) + (IntB (min x y)) + :ruleset interval-analysis) +(rewrite (bound-max (BoolB x) (BoolB y)) + (BoolB (or x y)) + :ruleset interval-analysis) +(rewrite (bound-min (BoolB x) (BoolB y)) + (BoolB (and x y)) + :ruleset interval-analysis) + +; ================================= +; Constants +; ================================= +(rule ((= lhs (Const (Int x) ty ctx))) + ( + (set (lo-bound lhs) (IntB x)) + (set (hi-bound lhs) (IntB x)) + ) + :ruleset interval-analysis) + +(rule ((= lhs (Const (Bool x) ty ctx))) + ( + (set (lo-bound lhs) (BoolB x)) + (set (hi-bound lhs) (BoolB x)) + ) + :ruleset interval-analysis) + +; ================================= +; Constant Folding +; ================================= +(rule ( + (= (IntB x) (lo-bound expr)) + (= (IntB x) (hi-bound expr)) + (HasArgType expr ty) + (ContextOf expr ctx) + ) + ((union expr (Const (Int x) ty ctx))) + :ruleset interval-analysis) + +(rule ( + (= (BoolB x) (lo-bound expr)) + (= (BoolB x) (hi-bound expr)) + (HasArgType expr ty) + (ContextOf expr ctx) + ) + ((union expr (Const (Bool x) ty ctx))) + :ruleset interval-analysis) + +; lower bound being true means the bool must be true +(rule ( + (= (BoolB true) (lo-bound expr)) + (HasArgType expr ty) + (ContextOf expr ctx) + ) + ((union expr (Const (Bool true) ty ctx))) + :ruleset interval-analysis) + +; upper bound being false means the bool must be false +(rule ( + (= (BoolB false) (hi-bound expr)) + (HasArgType expr ty) + (ContextOf expr ctx) + ) + ((union expr (Const (Bool false) ty ctx))) + :ruleset interval-analysis) + +; ================================= +; Arithmetic +; ================================= +; + a b interval is (+ la lb) (+ ha hb) +(rule ( + (= lhs (Bop (Add) a b)) + (= (IntB la) (lo-bound a)) + (= (IntB lb) (lo-bound b)) + ) + ((set (lo-bound lhs) (IntB (+ la lb)))) + :ruleset interval-analysis) +(rule ( + (= lhs (Bop (Add) a b)) + (= (IntB ha) (hi-bound a)) + (= (IntB hb) (hi-bound b)) + ) + ((set (hi-bound lhs) (IntB (+ ha hb)))) + :ruleset interval-analysis) + +; - a b interval is (- la hb) (- ha lb) +(rule ( + (= lhs (Bop (Sub) a b)) + (= (IntB la) (lo-bound a)) + (= (IntB hb) (hi-bound b)) + ) + ((set (lo-bound lhs) (IntB (- la hb)))) + :ruleset interval-analysis) +(rule ( + (= lhs (Bop (Sub) a b)) + (= (IntB ha) (hi-bound a)) + (= (IntB lb) (lo-bound b)) + ) + ((set (hi-bound lhs) (IntB (- ha lb)))) + :ruleset interval-analysis) + +; Multiplication for two constants +; TODO: Make fancier interval analysis +(rule ( + (= lhs (Bop (Mul) a b)) + (= (IntB x) (lo-bound a)) + (= (IntB x) (hi-bound a)) + (= (IntB y) (lo-bound b)) + (= (IntB y) (hi-bound b)) + ) + ( + (set (lo-bound lhs) (IntB (* x y))) + (set (hi-bound lhs) (IntB (* x y))) + ) + :ruleset interval-analysis) + +; negative * negative is positive +(rule ( + (= lhs (Bop (Mul) x y)) + (= (IntB hi-x) (hi-bound x)) + (= (IntB hi-y) (hi-bound y)) + (<= hi-x 0) + (<= hi-y 0) + ) + ((set (lo-bound lhs) (IntB 0))) + :ruleset interval-analysis) + +; negative * positive is negative +(rule ( + (= lhs (Bop (Mul) x y)) + (= (IntB hi-x) (hi-bound x)) + (= (IntB lo-y) (lo-bound y)) + (<= hi-x 0) ; x <= 0 (x is negative) + (>= lo-y 0) ; y >= 0 (y is positive) + ) + ((set (hi-bound lhs) (IntB 0))) + :ruleset interval-analysis) + +; positive * positive is positive +(rule ( + (= lhs (Bop (Mul) x y)) + (= (IntB lo-x) (lo-bound x)) + (= (IntB lo-y) (lo-bound y)) + (>= lo-x 0) + (>= lo-y 0) + ) + ((set (lo-bound lhs) (IntB 0))) + :ruleset interval-analysis) + +; < a b interval is (< ha lb) (< la hb) +(rule ( + (= lhs (Bop (LessThan) a b)) + (= (IntB ha) (hi-bound a)) + (= (IntB lb) (lo-bound b)) + ) + ( + (set (lo-bound lhs) (BoolB (bool-< ha lb))) + ) + :ruleset interval-analysis) +(rule ( + (= lhs (Bop (LessThan) a b)) + (= (IntB la) (lo-bound a)) + (= (IntB hb) (hi-bound b)) + ) + ((set (hi-bound lhs) (BoolB (bool-< la hb)))) + :ruleset interval-analysis) + +; ================================= +; Conditionals +; ================================= +; if the predicate is true, merge with then branch +(rule ( + (= lhs (If cond inputs thn els)) + (ContextOf lhs if_ctx) + (= (BoolB true) (lo-bound cond)) + ) + ((union lhs (Subst if_ctx inputs thn))) + :ruleset interval-analysis) + +; if the predicate is false, merge with else branch +(rule ( + (= lhs (If cond inputs thn els)) + (ContextOf lhs if_ctx) + (= (BoolB false) (hi-bound cond)) + ) + ((union lhs (Subst if_ctx inputs els))) + :ruleset interval-analysis) + +; lo-bound of If is the min of the lower bounds +; hi-bound of If is the max of the upper bounds +(rule ( + (= lhs (If cond inputs thn els)) + (= lo-thn (lo-bound thn)) + (= lo-els (lo-bound els)) + ) + ((set (lo-bound lhs) (bound-min lo-thn lo-els))) + :ruleset interval-analysis) +(rule ( + (= lhs (If cond inputs thn els)) + (= hi-thn (hi-bound thn)) + (= hi-els (hi-bound els)) + ) + ((set (hi-bound lhs) (bound-max hi-thn hi-els))) + :ruleset interval-analysis) + +; Same rules, but for Ifs that have multiple outputs +(rule ( + (= lhs (If pred inputs thn els)) + (= lo-thn (lo-bound (Get thn i))) + (= lo-els (lo-bound (Get els i))) + ) + ((set (lo-bound (Get lhs i)) (bound-min lo-thn lo-els))) + :ruleset interval-analysis) +(rule ( + (= lhs (If cond inputs thn els)) + (= hi-thn (hi-bound (Get thn i))) + (= hi-els (hi-bound (Get els i))) + ) + ((set (hi-bound (Get lhs i)) (bound-max hi-thn hi-els))) + :ruleset interval-analysis) + +; If the If takes a tuple +(rule ( + ; expr < value + (= pred (Bop (LessThan) expr value)) + (= if_e (If pred inputs then else)) + ; the left operand of the < is an input to the if region + (= expr (Get inputs i)) + ; the right operand of the < has an upper bound + (= (IntB v) (hi-bound value)) + ; context node inside the if region + (= ctx (Arg ty (InIf true pred inputs))) + (HasType inputs ty) + ) + ; expr < value was true, so we know expr is at most (hi-bound value) - 1 + ((set (hi-bound (Get ctx i)) (IntB (- v 1)))) + :ruleset interval-analysis) +(rule ( + ; expr < value + (= pred (Bop (LessThan) expr value)) + (= if_e (If pred inputs then else)) + ; the left operand of the < is an input to the if region + (= expr (Get inputs i)) + ; the right operand of the < has a lower bound + (= (IntB v) (lo-bound value)) + ; context node inside the if region + (= ctx (Arg ty (InIf false pred inputs))) + (HasType inputs ty) + ) + ; expr < value was false, so we know expr is at least (lo-bound value) + ((set (lo-bound (Get ctx i)) (IntB v))) + :ruleset interval-analysis) + +(rule ( + ; value < expr + (= pred (Bop (LessThan) value expr)) + (= if_e (If pred inputs then else)) + ; the right operand of the < is an input to the if region + (= expr (Get inputs i)) + ; the left operand of the < has a lower bound + (= (IntB v) (lo-bound value)) + ; context node inside the if region + (= ctx (Arg ty (InIf true pred inputs))) + (HasType inputs ty) + ) + ; value < expr was true, so we know expr is at least (lo-bound value) + 1 + ((set (lo-bound (Get ctx i)) (IntB (+ v 1)))) + :ruleset interval-analysis) +(rule ( + ; value < expr + (= pred (Bop (LessThan) value expr)) + (= if_e (If pred inputs then else)) + ; the right operand of the < is an input to the if region + (= expr (Get inputs i)) + ; the left operand of the < has an upper bound + (= (IntB v) (hi-bound value)) + ; context node inside the if region + (= ctx (Arg ty (InIf false pred inputs))) + (HasType inputs ty) + ) + ; value < expr was false, so we know expr is at most (hi-bound value) + ((set (hi-bound (Get ctx i)) (IntB v))) + :ruleset interval-analysis) + +;; Push intervals for inputs into if region +(rule ( + (= if (If pred inputs then_ else_)) + (= ctx (Arg ty (InIf b pred inputs))) + (HasType inputs ty) + (= lo (lo-bound (Get inputs i))) + + ) + ((set (lo-bound (Get ctx i)) lo)) + :ruleset interval-analysis) +(rule ( + (= if (If pred inputs then_ else_)) + (= ctx (Arg ty (InIf b pred inputs))) + (HasType inputs ty) + (= hi (hi-bound (Get inputs i))) + + ) + ((set (hi-bound (Get ctx i)) hi)) + :ruleset interval-analysis) + +; (if (a == b) thn els) +; in the thn branch, we know that a has the same bounds as b +(rule ( + (= pred (Bop (Eq) expr val)) + (= if_e (If pred inputs thn els)) + ; the left operand of the == is an input to the if region + (= expr (Get inputs i)) + (= ctx (Arg ty (InIf true pred inputs))) + (HasType inputs ty) + (= (IntB lo) (lo-bound val)) + ) + ((set (lo-bound (Get ctx i)) (IntB lo))) + :ruleset interval-analysis) +(rule ( + (= pred (Bop (Eq) expr val)) + (= if_e (If pred inputs thn els)) + ; the left operand of the == is an input to the if region + (= expr (Get inputs i)) + (= ctx (Arg ty (InIf true pred inputs))) + (HasType inputs ty) + (= (IntB hi) (hi-bound val)) + ) + ((set (hi-bound (Get ctx i)) (IntB hi))) + :ruleset interval-analysis) + + +(rule ( + ;; argument has loop context + (Arg ty (InLoop inputs outputs)) + ;; in the loop, the argument is passed through + ;; note that some_ctx is not the same as (InLoop inputs outputs) + (= (Get (Arg ty some_ctx) ith) (Get outputs (+ 1 ith))) + ;; input has some bound + (= bound (lo-bound (Get inputs ith))) + ) + ( + (set (lo-bound (Get (Arg ty (InLoop inputs outputs)) ith)) bound) + ) + :ruleset interval-analysis) +(rule ( + ;; argument has loop context + (Arg ty (InLoop inputs outputs)) + ;; in the loop, the argument is passed through + (= (Get (Arg ty some_ctx) ith) (Get outputs (+ 1 ith))) + ;; input has some bound + (= bound (hi-bound (Get inputs ith))) + ) + ( + (set (hi-bound (Get (Arg ty (InLoop inputs outputs)) ith)) bound) + ) + :ruleset interval-analysis) + + +(ruleset switch_rewrite) + +; if (a and b) X Y ~~> if a (if b X Y) Y +(rule ((= lhs (If (Bop (And) a b) ins X Y)) + (HasType ins (TupleT ins_ty)) + (= len (tuple-length ins))) + + ((let outer_ins (Concat (Single b) ins)) + (let outer_ins_ty (TupleT (TCons (BoolT) ins_ty))) + + (let inner_pred (Get (Arg outer_ins_ty (InIf true a outer_ins)) 0)) + (let sub_arg_true (SubTuple (Arg outer_ins_ty (InIf true a outer_ins)) 1 len)) + (let sub_arg_false (SubTuple (Arg outer_ins_ty (InIf false a outer_ins)) 1 len)) + + (let inner_X (AddContext (InIf true inner_pred sub_arg_true) X)) + (let inner_Y (AddContext (InIf false inner_pred sub_arg_true) Y)) + (let outer_Y (Subst (InIf false a outer_ins) sub_arg_false Y)) + + (let inner (If inner_pred sub_arg_true inner_X inner_Y)) + (union lhs (If a outer_ins inner outer_Y))) + + :ruleset switch_rewrite) + +; if (a or b) X Y ~~> if a X (if b X Y) +(rule ((= lhs (If (Bop (Or) a b) ins X Y)) + (HasType ins (TupleT ins_ty)) + (= len (tuple-length ins))) + + ((let outer_ins (Concat (Single b) ins)) + (let outer_ins_ty (TupleT (TCons (BoolT) ins_ty))) + + (let inner_pred (Get (Arg outer_ins_ty (InIf false a outer_ins)) 0)) + (let sub_arg_true (SubTuple (Arg outer_ins_ty (InIf true a outer_ins)) 1 len)) + (let sub_arg_false (SubTuple (Arg outer_ins_ty (InIf false a outer_ins)) 1 len)) + + (let outer_X (Subst (InIf true a outer_ins) sub_arg_true X)) + (let inner_X (AddContext (InIf true inner_pred sub_arg_false) X)) + (let inner_Y (AddContext (InIf false inner_pred sub_arg_false) Y)) + + (let inner (If inner_pred sub_arg_false inner_X inner_Y)) + (union lhs (If a outer_ins outer_X inner ))) + + :ruleset switch_rewrite) + +(relation Debug (Assumption Expr Expr)) +(rule ((If (Const (Bool true) ty ctx) ins thn els)) +( + (Debug ctx ins thn) +) + :ruleset always-run) + +(rewrite (If (Const (Bool true) ty ctx) ins thn els) + (Subst ctx ins thn) + :ruleset always-run) + +(rewrite (If (Const (Bool false) ty ctx) ins thn els) + (Subst ctx ins els) + :ruleset switch_rewrite) + +(rule ((= lhs (If pred ins thn els)) + (= (Get thn i) (Const (Bool true) ty ctx1)) + (= (Get els i) (Const (Bool false) ty ctx2))) + ((union (Get lhs i) pred)) :ruleset switch_rewrite) + +(rule ((= lhs (If pred ins thn els)) + (= (Get thn i) (Const (Bool false) ty ctx1)) + (= (Get els i) (Const (Bool true) ty ctx2))) + ((union (Get lhs i) (Uop (Not) pred))) :ruleset switch_rewrite) + +; Simple rewrites that don't do a ton with control flow. + +(ruleset peepholes) + +(rewrite (Bop (Mul) (Const (Int 0) ty ctx) e) (Const (Int 0) ty ctx) :ruleset peepholes) +(rewrite (Bop (Mul) e (Const (Int 0) ty ctx)) (Const (Int 0) ty ctx) :ruleset peepholes) +(rewrite (Bop (Mul) (Const (Int 1) ty ctx) e) e :ruleset peepholes) +(rewrite (Bop (Mul) e (Const (Int 1) ty ctx)) e :ruleset peepholes) +(rewrite (Bop (Add) (Const (Int 0) ty ctx) e) e :ruleset peepholes) +(rewrite (Bop (Add) e (Const (Int 0) ty ctx) ) e :ruleset peepholes) + +(rewrite (Bop (Mul) (Const (Int j) ty ctx) (Const (Int i) ty ctx)) (Const (Int (* i j)) ty ctx) :ruleset peepholes) +(rewrite (Bop (Add) (Const (Int j) ty ctx) (Const (Int i) ty ctx)) (Const (Int (+ i j)) ty ctx) :ruleset peepholes) + +(rewrite (Bop (And) (Const (Bool true) ty ctx) e) e :ruleset peepholes) +(rewrite (Bop (And) e (Const (Bool true) ty ctx)) e :ruleset peepholes) +(rewrite (Bop (And) (Const (Bool false) ty ctx) e) (Const (Bool false) ty ctx) :ruleset peepholes) +(rewrite (Bop (And) e (Const (Bool false) ty ctx)) (Const (Bool false) ty ctx) :ruleset peepholes) +(rewrite (Bop (Or) (Const (Bool false) ty ctx) e) e :ruleset peepholes) +(rewrite (Bop (Or) e (Const (Bool false) ty ctx)) e :ruleset peepholes) +(rewrite (Bop (Or) (Const (Bool true) ty ctx) e) (Const (Bool true) ty ctx) :ruleset peepholes) +(rewrite (Bop (Or) e (Const (Bool true) ty ctx)) (Const (Bool true) ty ctx) :ruleset peepholes) + + +(datatype IntOrInfinity + (Infinity) + (NegInfinity) + (I i64)) + +(function MaxIntOrInfinity (IntOrInfinity IntOrInfinity) IntOrInfinity) +(rewrite (MaxIntOrInfinity (Infinity) _) (Infinity) :ruleset always-run) +(rewrite (MaxIntOrInfinity _ (Infinity)) (Infinity) :ruleset always-run) +(rewrite (MaxIntOrInfinity (NegInfinity) x) x :ruleset always-run) +(rewrite (MaxIntOrInfinity x (NegInfinity)) x :ruleset always-run) +(rewrite (MaxIntOrInfinity (I x) (I y)) (I (max x y)) :ruleset always-run) + +(function MinIntOrInfinity (IntOrInfinity IntOrInfinity) IntOrInfinity) +(rewrite (MinIntOrInfinity (NegInfinity) _) (NegInfinity) :ruleset always-run) +(rewrite (MinIntOrInfinity _ (NegInfinity)) (NegInfinity) :ruleset always-run) +(rewrite (MinIntOrInfinity (Infinity) x) x :ruleset always-run) +(rewrite (MinIntOrInfinity x (Infinity)) x :ruleset always-run) +(rewrite (MinIntOrInfinity (I x) (I y)) (I (min x y)) :ruleset always-run) + +(function AddIntOrInfinity (IntOrInfinity IntOrInfinity) IntOrInfinity) +(rewrite (AddIntOrInfinity (Infinity) (Infinity)) (Infinity) :ruleset always-run) +(rewrite (AddIntOrInfinity (Infinity) (I _)) (Infinity) :ruleset always-run) +(rewrite (AddIntOrInfinity (I _) (Infinity)) (Infinity) :ruleset always-run) +(rewrite (AddIntOrInfinity (NegInfinity) (NegInfinity)) (NegInfinity) :ruleset always-run) +(rewrite (AddIntOrInfinity (NegInfinity) (I _)) (NegInfinity) :ruleset always-run) +(rewrite (AddIntOrInfinity (I _) (NegInfinity)) (NegInfinity) :ruleset always-run) +(rewrite (AddIntOrInfinity (I x) (I y)) (I (+ x y)) :ruleset always-run) + +(datatype IntInterval (MkIntInterval IntOrInfinity IntOrInfinity)) + +(function UnionIntInterval (IntInterval IntInterval) IntInterval) +(rewrite (UnionIntInterval (MkIntInterval lo1 hi1) (MkIntInterval lo2 hi2)) + (MkIntInterval (MinIntOrInfinity lo1 lo2) (MaxIntOrInfinity hi1 hi2)) + :ruleset always-run) + +(function IntersectIntInterval (IntInterval IntInterval) IntInterval) +(rewrite (IntersectIntInterval (MkIntInterval lo1 hi1) (MkIntInterval lo2 hi2)) + (MkIntInterval (MaxIntOrInfinity lo1 lo2) (MinIntOrInfinity hi1 hi2)) + :ruleset always-run) + +(function AddIntInterval (IntInterval IntInterval) IntInterval) +(rewrite (AddIntInterval (MkIntInterval lo1 hi1) (MkIntInterval lo2 hi2)) + (MkIntInterval (AddIntOrInfinity lo1 lo2) + (AddIntOrInfinity hi1 hi2)) + :ruleset always-run) + + +(datatype List + (Nil-List) + (Cons-List i64 IntInterval List)) + +(function Length-List (List) i64) +(rule ((= x (Nil-List))) + ((set (Length-List x) 0)) + :ruleset always-run) +(rule ((= x (Cons-List hd0 hd1 tl)) + (= l (Length-List tl))) + ((set (Length-List x) (+ l 1))) + :ruleset always-run) +(rule ((= x (Nil-List))) + ((set (Length-List x) 0)) + :ruleset memory-helpers) +(rule ((= x (Cons-List hd0 hd1 tl)) + (= l (Length-List tl))) + ((set (Length-List x) (+ l 1))) + :ruleset memory-helpers) + +(relation IsEmpty-List (List)) +(rule ((= x (Nil-List))) + ((IsEmpty-List x)) + :ruleset always-run) + +(relation IsNonEmpty-List (List)) +(rule ((= x (Cons-List hd0 hd1 tl))) + ((IsNonEmpty-List x)) + :ruleset always-run) + +(function RevConcat-List (List List) List :cost 1000) +(rewrite (RevConcat-List (Nil-List) l) + l + :ruleset always-run) +(rewrite (RevConcat-List (Cons-List hd0 hd1 tl) l) + (RevConcat-List tl (Cons-List hd0 hd1 l)) + :ruleset always-run) + +(function Rev-List (List) List :cost 1000) +(rewrite (Rev-List m) + (RevConcat-List m (Nil-List)) + :ruleset always-run) + +(function Concat-List (List List) List :cost 1000) +(rewrite (Concat-List x y) + (RevConcat-List (Rev-List x) y) + :ruleset always-run) + +; SuffixAt and At must be demanded, otherwise these are O(N^2) +(relation DemandAt-List (List)) +(relation SuffixAt-List (List i64 List)) +(relation At-List (List i64 i64 IntInterval)) +(rule ((DemandAt-List x)) + ((SuffixAt-List x 0 x)) + :ruleset always-run) +(rule ((SuffixAt-List x i (Cons-List hd0 hd1 tl))) + ((SuffixAt-List x (+ i 1) tl) + (At-List x i hd0 hd1)) + :ruleset always-run) + +(function Union-List (List List) List) + ; The third argument of the helper is a WIP result map. + ; Invariant: keys of the result map are not present in the first two and are in descending order + (function UnionHelper-List (List List List) List) + (rewrite (Union-List m1 m2) + (Rev-List (UnionHelper-List m1 m2 (Nil-List))) + :ruleset always-run) + + ; both m1 and m2 empty + (rewrite (UnionHelper-List (Nil-List) (Nil-List) res) + res + :ruleset always-run) + ; take from m1 when m2 empty and vice versa + (rewrite + (UnionHelper-List + (Nil-List) + (Cons-List hd0 hd1 tl) + res) + (UnionHelper-List + (Nil-List) + tl + (Cons-List hd0 hd1 res)) + :ruleset always-run) + (rewrite + (UnionHelper-List + (Cons-List hd0 hd1 tl) + (Nil-List) + res) + (UnionHelper-List + tl + (Nil-List) + (Cons-List hd0 hd1 res)) + :ruleset always-run) + + ; when both nonempty and smallest key different, take smaller key + (rule ((= f (UnionHelper-List l1 l2 res)) + (= l1 (Cons-List k1 a1 tl1)) + (= l2 (Cons-List k2 b1 tl2)) + (< k1 k2)) + ((union f + (UnionHelper-List tl1 l2 (Cons-List k1 a1 res)))) + :ruleset always-run) + (rule ((= f (UnionHelper-List l1 l2 res)) + (= l1 (Cons-List k1 a1 tl1)) + (= l2 (Cons-List k2 b1 tl2)) + (< k2 k1)) + ((union f + (UnionHelper-List l1 tl2 (Cons-List k2 b1 res)))) + :ruleset always-run) + + ; when shared smallest key, union interval + (rule ((= f (UnionHelper-List l1 l2 res)) + (= l1 (Cons-List k a1 tl1)) + (= l2 (Cons-List k b1 tl2))) + ((union f + (UnionHelper-List tl1 tl2 + (Cons-List k (UnionIntInterval a1 b1) res)))) + :ruleset always-run) + +(function Intersect-List (List List) List) + ; The third argument of the helper is a WIP result map. + ; Invariant: keys of the result map are not present in the first two and are in descending order + (function IntersectHelper-List (List List List) List) + (rewrite (Intersect-List m1 m2) + (Rev-List (IntersectHelper-List m1 m2 (Nil-List))) + :ruleset always-run) + + ; m1 or m2 empty + (rewrite (IntersectHelper-List (Nil-List) m2 res) + res + :ruleset always-run) + (rewrite (IntersectHelper-List m1 (Nil-List) res) + res + :ruleset always-run) + + ; when both nonempty and smallest key different, drop smaller key + (rule ((= f (IntersectHelper-List l1 l2 res)) + (= l1 (Cons-List k1 a1 tl1)) + (= l2 (Cons-List k2 b1 tl2)) + (< k1 k2)) + ((union f (IntersectHelper-List tl1 l2 res))) + :ruleset always-run) + (rule ((= f (IntersectHelper-List l1 l2 res)) + (= l1 (Cons-List k1 a1 tl1)) + (= l2 (Cons-List k2 b1 tl2)) + (< k2 k1)) + ((union f (IntersectHelper-List tl1 l2 res))) + :ruleset always-run) + +(datatype MyBool (MyTrue) (MyFalse)) + +(function IntIntervalValid (IntInterval) MyBool) +(rewrite (IntIntervalValid (MkIntInterval (I lo) (I hi))) + (MyTrue) + :when ((<= lo hi)) + :ruleset always-run) +(rewrite (IntIntervalValid (MkIntInterval (I lo) (I hi))) + (MyFalse) + :when ((> lo hi)) + :ruleset always-run) +(rewrite (IntIntervalValid (MkIntInterval (NegInfinity) _)) + (MyTrue) + :ruleset always-run) +(rewrite (IntIntervalValid (MkIntInterval _ (Infinity))) + (MyTrue) + :ruleset always-run) + +(function ConsIfNonEmpty (i64 IntInterval List) + List + :cost 100) +(rule ((ConsIfNonEmpty k v tl)) + ((IntIntervalValid v)) + :ruleset always-run) +(rule ((= f (ConsIfNonEmpty k v tl)) + (= (MyTrue) (IntIntervalValid v))) + ((union f (Cons-List k v tl))) + :ruleset always-run) +(rule ((= f (ConsIfNonEmpty k v tl)) + (= (MyFalse) (IntIntervalValid v))) + ((union f tl)) + :ruleset always-run) + + ; when shared smallest key, intersect interval + (rule ((= f (IntersectHelper-List l1 l2 res)) + (= l1 (Cons-List k a1 tl1)) + (= l2 (Cons-List k b1 tl2))) + ((union f + (IntersectHelper-List tl1 tl2 + (ConsIfNonEmpty k (IntersectIntInterval a1 b1) res)))) + :ruleset always-run) + +(function AddIntIntervalToAll (IntInterval List) + List) +(rewrite (AddIntIntervalToAll _ (Nil-List)) + (Nil-List) + :ruleset always-run) +(rewrite (AddIntIntervalToAll x (Cons-List allocid offset tl)) + (Cons-List allocid (AddIntInterval x offset) + (AddIntIntervalToAll x tl)) + :ruleset always-run) + +(datatype PtrPointees + (PointsTo List) + (PointsAnywhere)) + +(function AddIntIntervalToPtrPointees (IntInterval PtrPointees) PtrPointees) +(rewrite (AddIntIntervalToPtrPointees interval (PointsAnywhere)) + (PointsAnywhere) + :ruleset always-run) +(rewrite (AddIntIntervalToPtrPointees interval (PointsTo l)) + (PointsTo (AddIntIntervalToAll interval l)) + :ruleset always-run) + +(function Union-PtrPointees (PtrPointees PtrPointees) PtrPointees) +(rewrite (Union-PtrPointees (PointsAnywhere) _) + (PointsAnywhere) + :ruleset always-run) +(rewrite (Union-PtrPointees _ (PointsAnywhere)) + (PointsAnywhere) + :ruleset always-run) +(rewrite (Union-PtrPointees (PointsTo x) (PointsTo y)) + (PointsTo (Union-List x y)) + :ruleset always-run) +(function Intersect-PtrPointees (PtrPointees PtrPointees) PtrPointees) +(rewrite (Intersect-PtrPointees (PointsAnywhere) x) + x + :ruleset always-run) +(rewrite (Intersect-PtrPointees x (PointsAnywhere)) + x + :ruleset always-run) +(rewrite (Intersect-PtrPointees (PointsTo x) (PointsTo y)) + (PointsTo (Intersect-List x y)) + :ruleset always-run) + +(relation PointsNowhere-PtrPointees (PtrPointees)) +(rule ((= f (PointsTo x)) + (IsEmpty-List x)) + ((PointsNowhere-PtrPointees f)) + :ruleset always-run) + + +(datatype List + (Nil-List) + (Cons-List PtrPointees List)) + +(function Length-List (List) i64) +(rule ((= x (Nil-List))) + ((set (Length-List x) 0)) + :ruleset always-run) +(rule ((= x (Cons-List hd0 tl)) + (= l (Length-List tl))) + ((set (Length-List x) (+ l 1))) + :ruleset always-run) +(rule ((= x (Nil-List))) + ((set (Length-List x) 0)) + :ruleset memory-helpers) +(rule ((= x (Cons-List hd0 tl)) + (= l (Length-List tl))) + ((set (Length-List x) (+ l 1))) + :ruleset memory-helpers) + +(relation IsEmpty-List (List)) +(rule ((= x (Nil-List))) + ((IsEmpty-List x)) + :ruleset always-run) + +(relation IsNonEmpty-List (List)) +(rule ((= x (Cons-List hd0 tl))) + ((IsNonEmpty-List x)) + :ruleset always-run) + +(function RevConcat-List (List List) List :cost 1000) +(rewrite (RevConcat-List (Nil-List) l) + l + :ruleset always-run) +(rewrite (RevConcat-List (Cons-List hd0 tl) l) + (RevConcat-List tl (Cons-List hd0 l)) + :ruleset always-run) + +(function Rev-List (List) List :cost 1000) +(rewrite (Rev-List m) + (RevConcat-List m (Nil-List)) + :ruleset always-run) + +(function Concat-List (List List) List :cost 1000) +(rewrite (Concat-List x y) + (RevConcat-List (Rev-List x) y) + :ruleset always-run) + +; SuffixAt and At must be demanded, otherwise these are O(N^2) +(relation DemandAt-List (List)) +(relation SuffixAt-List (List i64 List)) +(relation At-List (List i64 PtrPointees)) +(rule ((DemandAt-List x)) + ((SuffixAt-List x 0 x)) + :ruleset always-run) +(rule ((SuffixAt-List x i (Cons-List hd0 tl))) + ((SuffixAt-List x (+ i 1) tl) + (At-List x i hd0)) + :ruleset always-run) + +(relation All (List)) +(rule ((= x (Nil-List))) + ((All x)) + :ruleset always-run) +(rule ((= x (Cons-List hd0 tl)) + (PointsNowhere-PtrPointees hd0) + (All tl)) + ((All x)) + :ruleset always-run) + + + +(function Zip (List List) List :cost 1000) +(rewrite (Zip (Nil-List) (Nil-List)) + (Nil-List) + :ruleset always-run) +(rewrite (Zip + (Cons-List x0 tl1) + (Cons-List y0 tl2)) + (Cons-List + (Union-PtrPointees x0 y0) + (Zip tl1 tl2)) + :when ((= (Length-List tl1) (Length-List tl2))) + :ruleset always-run) + +(function Zip (List List) List :cost 1000) +(rewrite (Zip (Nil-List) (Nil-List)) + (Nil-List) + :ruleset always-run) +(rewrite (Zip + (Cons-List x0 tl1) + (Cons-List y0 tl2)) + (Cons-List + (Intersect-PtrPointees x0 y0) + (Zip tl1 tl2)) + :ruleset always-run) + + +(sort ExprSetPrim (Set Expr)) + +(datatype ExprSet (ES ExprSetPrim)) + +(function ExprSet-intersect (ExprSet ExprSet) ExprSet) +(rewrite (ExprSet-intersect (ES set1) (ES set2)) (ES (set-intersect set1 set2)) + :ruleset memory-helpers) +(function ExprSet-union (ExprSet ExprSet) ExprSet) +(rewrite (ExprSet-union (ES set1) (ES set2)) (ES (set-union set1 set2)) + :ruleset memory-helpers) +(relation ExprSet-contains (ExprSet Expr)) +(rule ((ES set1) (set-contains set1 x)) + ((ExprSet-contains (ES set1) x)) + :ruleset memory-helpers) +(function ExprSet-insert (ExprSet Expr) ExprSet) +(rewrite (ExprSet-insert (ES set1) x) + (ES (set-insert set1 x)) + :ruleset memory-helpers) +(function ExprSet-length (ExprSet) i64) +(rewrite (ExprSet-length (ES set1)) (set-length set1) :ruleset memory-helpers) + +; ============================ +; Pointees +; ============================ + + +; List is used as an association list; the i64 keys +; (corresponding to alloc ids) are always unique and sorted, the IntInterval +; values correspond to offset ranges. +; +; (TuplePointsTo [{0->[4,5], 1->[0,0]}, {0->[0,0]}]) +; indicates a tuple with two components. +; - The first component might point to Alloc 0 at offsets 4 or 5, +; or Alloc 1 at offset 0 +; - The second component points to Alloc 0 at offset 0 +(datatype Pointees + (TuplePointsTo List) + (PtrPointsTo PtrPointees)) + +(function UnwrapPtrPointsTo (Pointees) PtrPointees) +(rewrite (UnwrapPtrPointsTo (PtrPointsTo x)) + x + :ruleset memory-helpers) +(function UnwrapTuplePointsTo (Pointees) List) +(rewrite (UnwrapTuplePointsTo (TuplePointsTo x)) + x + :ruleset memory-helpers) + +(relation PointsNowhere (Pointees)) +(rule ((= f (PtrPointsTo x)) + (PointsNowhere-PtrPointees x)) + ((PointsNowhere f)) + :ruleset memory-helpers) +(rule ((= f (TuplePointsTo l)) + (All l)) + ((PointsNowhere f)) + :ruleset memory-helpers) + +(function UnionPointees (Pointees Pointees) Pointees) +(rewrite (UnionPointees (PtrPointsTo x) (PtrPointsTo y)) + (PtrPointsTo (Union-PtrPointees x y)) + :ruleset memory-helpers) +(rewrite (UnionPointees (TuplePointsTo x) (TuplePointsTo y)) + (TuplePointsTo (Zip x y)) + :when ((= (Length-List x) (Length-List y))) + :ruleset memory-helpers) +(function IntersectPointees (Pointees Pointees) Pointees) +(rewrite (IntersectPointees (PtrPointsTo x) (PtrPointsTo y)) + (PtrPointsTo (Intersect-PtrPointees x y)) + :ruleset memory-helpers) +(rewrite (IntersectPointees (TuplePointsTo x) (TuplePointsTo y)) + (TuplePointsTo (Zip x y)) + :ruleset memory-helpers) + +(function GetPointees (Pointees i64) Pointees) +(rule ((= f (GetPointees (TuplePointsTo l) i)) + (At-List l i x)) + ((union f (PtrPointsTo x))) + :ruleset memory-helpers) + +(function PointeesDropFirst (Pointees) Pointees) +(rewrite (PointeesDropFirst (TuplePointsTo (Cons-List hd tl))) + (TuplePointsTo tl) + :ruleset memory-helpers) + +; ============================ +; Resolved +; ============================ + +; Resolved checks if an e-class contains a term containing only constructors and +; primitives; i.e. whether equality is decideable +(relation Resolved-IntOrInfinity (IntOrInfinity)) +(rule ((= f (I _))) + ((Resolved-IntOrInfinity f)) + :ruleset memory-helpers) +(rule ((= f (Infinity))) + ((Resolved-IntOrInfinity f)) + :ruleset memory-helpers) +(rule ((= f (NegInfinity))) + ((Resolved-IntOrInfinity f)) + :ruleset memory-helpers) + +(relation Resolved-IntInterval (IntInterval)) +(rule ((= f (MkIntInterval lo hi)) + (Resolved-IntOrInfinity lo) + (Resolved-IntOrInfinity hi)) + ((Resolved-IntInterval f)) + :ruleset memory-helpers) + +(relation Resolved-List (List)) +(rule ((= f (Nil-List))) + ((Resolved-List f)) + :ruleset memory-helpers) +(rule ((= f (Cons-List allocid offsets tl)) + (Resolved-List tl) + (Resolved-IntInterval offsets)) + ((Resolved-List f)) + :ruleset memory-helpers) + +(relation Resolved-PtrPointees (PtrPointees)) +(rule ((= f (PointsAnywhere))) + ((Resolved-PtrPointees f)) + :ruleset memory-helpers) +(rule ((= f (PointsTo x)) + (Resolved-List x)) + ((Resolved-PtrPointees f)) + :ruleset memory-helpers) + +(relation Resolved-List (List)) +(rule ((= f (Nil-List))) + ((Resolved-List f)) + :ruleset memory-helpers) +(rule ((= f (Cons-List hd tl)) + (Resolved-List tl) + (Resolved-PtrPointees hd)) + ((Resolved-List f)) + :ruleset memory-helpers) + +(relation Resolved-Pointees (Pointees)) +(rule ((= f (TuplePointsTo x)) + (Resolved-List x)) + ((Resolved-Pointees f)) + :ruleset memory-helpers) +(rule ((= f (PtrPointsTo x)) + (Resolved-PtrPointees x)) + ((Resolved-Pointees f)) + :ruleset memory-helpers) + + +;;;;; + +(function BaseTypeToPtrPointees (BaseType) PtrPointees :cost 100) +(rewrite (BaseTypeToPtrPointees (PointerT _)) + (PointsAnywhere) + :ruleset memory-helpers) +(rewrite (BaseTypeToPtrPointees (IntT)) + (PointsTo (Nil-List)) + :ruleset memory-helpers) +(rewrite (BaseTypeToPtrPointees (StateT)) + (PointsTo (Nil-List)) + :ruleset memory-helpers) +(rewrite (BaseTypeToPtrPointees (BoolT)) + (PointsTo (Nil-List)) + :ruleset memory-helpers) + +(function TypeListToList (TypeList) List :cost 1000) +(rewrite (TypeListToList (TNil)) + (Nil-List) + :ruleset memory-helpers) +(rewrite (TypeListToList (TCons hd tl)) + (Cons-List + (BaseTypeToPtrPointees hd) + (TypeListToList tl)) + :ruleset memory-helpers) + +(function TypeToPointees (Type) Pointees :cost 1000) +(rewrite (TypeToPointees (TupleT tylist)) + (TuplePointsTo (TypeListToList tylist)) + :ruleset memory-helpers) +(rewrite (TypeToPointees (Base basety)) + (PtrPointsTo (BaseTypeToPtrPointees basety)) + :ruleset memory-helpers) + +; ============================ +; Update PointerishType +; ============================ + +(relation PointerishType (Type)) +(relation PointerishTypeList (TypeList)) + +(rule ((= f (Base (PointerT ty)))) + ((PointerishType f)) + :ruleset always-run) + +(rule ((= f (TCons (PointerT ty) tl))) + ((PointerishTypeList f)) + :ruleset always-run) + +(rule ((= f (TCons hd tl)) + (PointerishTypeList tl)) + ((PointerishTypeList f)) + :ruleset always-run) + +(rule ((= f (TupleT l)) + (PointerishTypeList l)) + ((PointerishType f)) + :ruleset always-run) + +; ============================ +; Update PointsToCells +; ============================ + +; arg pointees result pointees +(function PointsToCells (Expr Pointees) Pointees :unextractable) + +; Top-level demand +(rule ((Function name in-ty out-ty body)) + ((PointsToCells body (TypeToPointees in-ty))) + :ruleset memory-helpers) + +; Demand PointsToCells along state edge and pointer-typed values +(rule ((PointsToCells (Bop (Print) e state) ap)) + ((PointsToCells state ap)) + :ruleset memory-helpers) +(rule ((PointsToCells (Bop (Load) e state) ap)) + ((PointsToCells e ap) + (PointsToCells state ap)) + :ruleset memory-helpers) +(rule ((PointsToCells (Top (Write) ptr val state) ap)) + ((PointsToCells ptr ap) + (PointsToCells state ap)) + :ruleset memory-helpers) +(rule ((PointsToCells (Alloc id sz state ty) ap)) + ((PointsToCells state ap)) + :ruleset memory-helpers) +(rule ((PointsToCells (Bop (Free) ptr state) ap)) + ((PointsToCells ptr ap) + (PointsToCells state ap)) + :ruleset memory-helpers) +(rule ((PointsToCells (Get x i) ap)) + ((PointsToCells x ap)) + :ruleset memory-helpers) +(rule ((PointsToCells (Concat x y) ap)) + ((PointsToCells x ap) + (PointsToCells y ap)) + :ruleset memory-helpers) +(rule ((PointsToCells (Single x) ap)) + ((PointsToCells x ap)) + :ruleset memory-helpers) + +; Compute and propagate PointsToCells +(rewrite (PointsToCells (Concat x y) aps) + (TuplePointsTo (Concat-List + (UnwrapTuplePointsTo (PointsToCells x aps)) + (UnwrapTuplePointsTo (PointsToCells y aps)))) + :when ((HasType (Concat x y) ty) (PointerishType ty)) + :ruleset memory-helpers) + +(rewrite (PointsToCells (Get x i) aps) + (GetPointees (PointsToCells x aps) i) + :when ((HasType (Get x i) ty) (PointerishType ty)) + :ruleset memory-helpers) + +(rewrite (PointsToCells (Single x) aps) + (TuplePointsTo + (Cons-List + (UnwrapPtrPointsTo (PointsToCells x aps)) + (Nil-List))) + :when ((HasType (Single x) ty) (PointerishType ty)) + :ruleset memory-helpers) + +(rewrite (PointsToCells (Arg ty_ ctx) aps) + aps + :when ((HasType (Arg ty_ ctx) ty) (PointerishType ty)) + :ruleset memory-helpers) + +; Allow non-pointer types to resolve +(rule ((PointsToCells x aps) + (HasType x ty)) + ((TypeToPointees ty)) + :ruleset memory-helpers) +(rule ((= f (PointsToCells x aps)) + (HasType x ty) + (= pointees (TypeToPointees ty)) + (PointsNowhere pointees)) + ((union f pointees)) + :ruleset memory-helpers) + +(rewrite (PointsToCells (Bop (PtrAdd) x e) aps) + (PtrPointsTo + (AddIntIntervalToPtrPointees + (MkIntInterval (I lo) (I hi)) + (UnwrapPtrPointsTo (PointsToCells x aps)))) + :when ((= (IntB lo) (lo-bound e)) + (= (IntB hi) (hi-bound e))) + :ruleset memory-helpers) + +(rewrite (PointsToCells (If c inputs t e) aps) + (UnionPointees + (PointsToCells t (PointsToCells inputs aps)) + (PointsToCells e (PointsToCells inputs aps))) + :when ((HasType (If c inputs t e) ty) (PointerishType ty)) + :ruleset memory) + +(rewrite (PointsToCells (Alloc id sz state ty) aps) + (TuplePointsTo + (Cons-List + (PointsTo + (Cons-List + id + (MkIntInterval (I 0) (I 0)) + (Nil-List))) + (Cons-List + (PointsTo (Nil-List)) ; state output points to nothing + (Nil-List)))) + :ruleset memory-helpers) + +; arg pointees * loop in * loop out * i64 -> result pointees +(function PointsToCellsAtIter (Pointees Expr Expr i64) Pointees) + +; compute first two +(rule ((= e (DoWhile inputs pred-body)) + (PointsToCells e aps)) + ((set (PointsToCellsAtIter aps inputs pred-body 0) + (PointsToCells inputs aps)) + (set (PointsToCellsAtIter aps inputs pred-body 1) + (UnionPointees + (PointsToCellsAtIter aps inputs pred-body 0) + (PointeesDropFirst + (PointsToCells pred-body (PointsToCellsAtIter aps inputs pred-body 0)))))) + :ruleset memory-helpers) + +; avoid quadratic query +(function succ (i64) i64 :unextractable) +(rule ((PointsToCellsAtIter aps inputs pred-body i)) + ((set (succ i) (+ i 1))) + :ruleset memory-helpers) + +; Note that this rule is bounded by ruleset memory +(rule ((= pointees0 (PointsToCellsAtIter aps inputs pred-body i)) + (= pointees1 (PointsToCellsAtIter aps inputs pred-body (succ i))) + (Resolved-Pointees pointees0) + (Resolved-Pointees pointees1) + (!= pointees0 pointees1)) + ((set (PointsToCellsAtIter aps inputs pred-body (+ i 2)) + (UnionPointees + pointees1 + (PointeesDropFirst + (PointsToCells pred-body pointees1))))) + :ruleset memory) + +(rule ((= pointees (PointsToCellsAtIter aps inputs pred-body i)) + (= pointees (PointsToCellsAtIter aps inputs pred-body (succ i)))) + ((set (PointsToCells (DoWhile inputs pred-body) aps) + pointees)) + :ruleset memory) + +(rule ((PtrPointsTo (PointsTo l))) + ((DemandAt-List l)) + :ruleset memory-helpers) +(rule ((TuplePointsTo l)) + ((DemandAt-List l)) + :ruleset memory-helpers) + +; ============================ +; Update DontAlias +; ============================ + +(relation DemandDontAlias (Expr Expr Pointees)) +; pointer, pointer, arg pointees +(relation DontAlias (Expr Expr Pointees)) + + +(rule ((DemandDontAlias ptr1 ptr2 arg-pointees) + (BodyContainsExpr body ptr1) + (BodyContainsExpr body ptr2) + (HasType ptr1 (Base (PointerT ty))) + (HasType ptr2 (Base (PointerT ty))) + (= pointees1 (PointsToCells ptr1 arg-pointees)) + (= pointees2 (PointsToCells ptr2 arg-pointees))) + ((IntersectPointees pointees1 pointees2)) + :ruleset memory-helpers) + +(rule ((PointsNowhere + (IntersectPointees + (PointsToCells ptr1 arg-pointees) + (PointsToCells ptr2 arg-pointees)))) + ((DontAlias ptr1 ptr2 arg-pointees)) + :ruleset memory-helpers) + +; ============================ +; Update PointsToExpr +; ============================ + +; program point, pointer +(function PointsToExpr (Expr Expr) Expr :unextractable) + +; After a load, the ptr points to the loaded value +(rule ((= f (Bop (Load) ptr state))) + ((set (PointsToExpr (Get f 1) ptr) (Get f 0))) + :ruleset memory-helpers) + +; If we load and we already know what the pointer points to +; TODO this rule breaks the weakly linear invariant +; when a previous load may not be on the path +;(rule ((= e (Bop (Load) addr state)) +; (= v (PointsToExpr state addr))) +; ((union (Get e 0) v) +; (union (Get e 1) state)) +; :ruleset memory-helpers) + +; Loads and prints don't affect what what pointers already point to +(rule ((= f (PointsToExpr state addr)) + (= e (Bop (Load) any-addr state))) + ((let new-state (Get e 1)) + (union (PointsToExpr new-state addr) f)) + :ruleset memory-helpers) +(rule ((= f (PointsToExpr state addr)) + (= e (Bop (Print) any-val state))) + ((let new-state e) + (union (PointsToExpr new-state addr) f)) + :ruleset memory-helpers) + +; Writes don't affect what a pointer points to if it writes to another pointer +; guaranteed to not alias. +(rule ((= e (Top (Write) addr data state)) + (HasArgType addr argty) + (= otherdata (PointsToExpr state otheraddr))) + ((DemandDontAlias addr otheraddr (TypeToPointees argty))) + :ruleset memory-helpers) +(rule ((= e (Top (Write) addr data state)) + (HasArgType addr argty) + (= otherdata (PointsToExpr state otheraddr)) + (DontAlias addr otheraddr (TypeToPointees argty))) + ((set (PointsToExpr e otheraddr) otherdata)) + :ruleset memory-helpers) + +; For a write, mark the given expression as containing `data`. +(rule ((= e (Top (Write) addr data state))) + ((union (PointsToExpr e addr) data)) + :ruleset memory-helpers) + +; ============================ +; Update CellHasValues (currently unused) +; ============================ + +; ; program point, cell +; (function CellHasValues (Expr i64) ExprSet :merge (ExprSet-intersect old new)) + +; ; At the time of an alloc, a cell doesn't contain any values +; (rule ((= f (Alloc id amt state ty))) + ; ((set (CellHasValues (Get f 1) id) (ES (set-empty)))) + ; :ruleset memory-helpers) + +; ; These two rules find (Write ptr val state) where +; ; ptr points to cells given no assumptions about where (Arg) points. +; ; TODO: make sensitive to offsets +; (rule ((= e (Top (Write) ptr val state)) + ; (HasArgType ptr argty)) + ; ((TypeToPointees argty)) + ; :ruleset memory-helpers) +; (rule ((= e (Top (Write) ptr val state)) + ; (HasArgType ptr argty) + ; (= (PtrPointsTo (PointsTo cells)) (PointsToCells ptr (TypeToPointees argty))) + ; (At-List cells any-idx alloc-id offsets) + ; (= vals (CellHasValues state cell))) + ; ((set (CellHasValues e cell) (ExprSet-insert vals val))) + ; :ruleset memory-helpers) + +;; Loop Invariant + +;; bool: whether the term in the Expr is an invariant. +(function is-inv-Expr (Expr Expr) bool :unextractable :merge (or old new)) +(function is-inv-ListExpr (Expr ListExpr) bool :unextractable :merge (or old new)) + +;; in default, when there is a find, set is-inv to false +(rule ((BodyContainsExpr loop term) + (= loop (DoWhile inputs pred_out))) + ((set (is-inv-Expr loop term) false)) :ruleset always-run) +(rule ((BodyContainsListExpr loop term) + (= loop (DoWhile inputs pred_out))) + ((set (is-inv-ListExpr loop term) false)) :ruleset always-run) + +(relation is-inv-ListExpr-helper (Expr ListExpr i64)) +(rule ((BodyContainsListExpr loop list) + (= loop (DoWhile inputs pred_out))) + ((is-inv-ListExpr-helper loop list 0)) :ruleset always-run) + +(rule ((is-inv-ListExpr-helper loop list i) + (= true (is-inv-Expr loop expr)) + (= expr (ListExpr-ith list i))) + ((is-inv-ListExpr-helper loop list (+ i 1))) :ruleset always-run) + +(rule ((is-inv-ListExpr-helper loop list i) + (= i (ListExpr-length list))) + ((set (is-inv-ListExpr loop list) true)) :ruleset always-run) + + +(ruleset boundary-analysis) +;; An Expr is on boundary when it is invariant and its parent is not +; loop invariant-expr +(relation boundary-Expr (Expr Expr)) + +;; boundary for ListExpr's children +(rule ((= true (is-inv-Expr loop expr)) + (= false (is-inv-ListExpr loop list)) + (= expr (ListExpr-ith list i))) + ((boundary-Expr loop expr)) :ruleset boundary-analysis) + +;; if a output branch/pred is invariant, it's also boundary-Expr +(rule ((= true (is-inv-Expr loop expr)) + (= loop (DoWhile in pred_out)) + (= expr (Get pred_out i))) + ((boundary-Expr loop expr)) :ruleset boundary-analysis) + + +(function hoisted-loop (Expr Expr) bool :unextractable :merge (or old new) ) +(rule ((= loop (DoWhile in pred_out))) + ((set (hoisted-loop in pred_out) false)) :ruleset always-run) + +(function InExtendedLoop (Expr Expr Expr) Assumption) + +;; mock function +(ruleset loop-inv-motion) + +(rule ((boundary-Expr loop inv) + (> (Expr-size inv) 1) + ;; TODO: replace Expr-size when cost model is ready + (= loop (DoWhile in pred_out)) + ;; the outter assumption of the loop + (ContextOf loop loop_ctx) + (HasType in in_type) + (HasType inv inv_type) + (= inv_type (Base base_inv_ty)) + (= in_type (TupleT tylist)) + (= false (hoisted-loop in pred_out)) + (= len (tuple-length in))) + ((let new_input (Concat in (Single (Subst loop_ctx in inv)))) + (let new_input_type (TupleT (TLConcat tylist (TCons base_inv_ty (TNil))))) + ;; create an virtual assume node, union it with actuall InLoop later + (let assum (InExtendedLoop in pred_out new_input)) + (let new_out_branch (Get (Arg new_input_type assum) len)) + ;; this two subst only change arg to arg with new type + (let substed_pred_out (Subst assum (Arg new_input_type assum) pred_out)) + (let inv_in_new_loop (Subst assum (Arg new_input_type assum) inv)) + (let new_pred_out (Concat substed_pred_out (Single new_out_branch))) + + (let new_loop (DoWhile new_input new_pred_out)) + (union assum (InLoop new_input new_pred_out)) + (union inv_in_new_loop new_out_branch) + (let wrapper (SubTuple new_loop 0 len)) + (union loop wrapper) + (subsume (DoWhile in pred_out)) + ;; don't hoist same loop again + (set (hoisted-loop in pred_out) true) + ) + :ruleset loop-inv-motion) + + +(rule ((BodyContainsExpr loop expr) + (= loop (DoWhile in out)) + (= expr (Const _n _ty _ctx))) + ((set (is-inv-Expr loop expr) true)) :ruleset always-run) + +(rule ((BodyContainsExpr loop expr) + (= loop (DoWhile in out)) + (= expr (Get (Arg ty ctx) i)) + (= loop (DoWhile in pred_out)) + (= expr (Get pred_out (+ i 1)))) + ((set (is-inv-Expr loop expr) true)) :ruleset always-run) + +(rule ((BodyContainsExpr loop expr) + (= loop (DoWhile in out)) + (= expr (Function _name _tyin _tyout _out)) + + ) + ((set (is-inv-Expr loop expr) true)) :ruleset always-run) + +(rule ((BodyContainsExpr loop expr) + (= loop (DoWhile in out)) + (= expr (Top _op _x _y _z)) + (= true (is-inv-Expr loop _x)) (= true (is-inv-Expr loop _y)) (= true (is-inv-Expr loop _z)) + ) + ((set (is-inv-Expr loop expr) true)) :ruleset always-run) + +(rule ((BodyContainsExpr loop expr) + (= loop (DoWhile in out)) + (= expr (Bop _op _x _y)) (BinaryOpIsPure _op) + (= true (is-inv-Expr loop _x)) (= true (is-inv-Expr loop _y)) + ) + ((set (is-inv-Expr loop expr) true)) :ruleset always-run) + +(rule ((BodyContainsExpr loop expr) + (= loop (DoWhile in out)) + (= expr (Uop _op _x)) (UnaryOpIsPure _op) + (= true (is-inv-Expr loop _x)) + ) + ((set (is-inv-Expr loop expr) true)) :ruleset always-run) + +(rule ((BodyContainsExpr loop expr) + (= loop (DoWhile in out)) + (= expr (Get _tup _i)) + (= true (is-inv-Expr loop _tup)) + ) + ((set (is-inv-Expr loop expr) true)) :ruleset always-run) + +(rule ((BodyContainsExpr loop expr) + (= loop (DoWhile in out)) + (= expr (Concat _x _y)) + (= true (is-inv-Expr loop _x)) (= true (is-inv-Expr loop _y)) + ) + ((set (is-inv-Expr loop expr) true)) :ruleset always-run) + +(rule ((BodyContainsExpr loop expr) + (= loop (DoWhile in out)) + (= expr (Single _x)) + (= true (is-inv-Expr loop _x)) + ) + ((set (is-inv-Expr loop expr) true)) :ruleset always-run) + +(rule ((BodyContainsExpr loop expr) + (= loop (DoWhile in out)) + (= expr (Switch _pred _inputs _branches)) + (= true (is-inv-Expr loop _pred)) (= true (is-inv-Expr loop _inputs)) (= true (is-inv-ListExpr loop _branches)) + ) + ((set (is-inv-Expr loop expr) true)) :ruleset always-run) + +(rule ((BodyContainsExpr loop expr) + (= loop (DoWhile in out)) + (= expr (If _pred _input _then _else)) + (= true (is-inv-Expr loop _pred)) (= true (is-inv-Expr loop _input)) + ) + ((set (is-inv-Expr loop expr) true)) :ruleset always-run) + +(rule ((BodyContainsExpr loop expr) + (= loop (DoWhile in out)) + (= expr (DoWhile _in _pred-and-output)) + (= true (is-inv-Expr loop _in)) + (ExprIsPure expr)) + ((set (is-inv-Expr loop expr) true)) :ruleset always-run) + +(rule ((BodyContainsExpr loop expr) + (= loop (DoWhile in out)) + (= expr (Call _func _arg)) + (= true (is-inv-Expr loop _arg)) + (ExprIsPure expr)) + ((set (is-inv-Expr loop expr) true)) :ruleset always-run) + +(rule ((BodyContainsExpr loop expr) + (= loop (DoWhile in out)) + (= expr (Empty _ty _ctx)) + + ) + ((set (is-inv-Expr loop expr) true)) :ruleset always-run) + + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (Top _op _x _y _z)) + (= expr1 _x)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (Top _op _x _y _z)) + (= expr1 _y)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (Top _op _x _y _z)) + (= expr1 _z)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (Bop _op _x _y)) + (= expr1 _x)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (Bop _op _x _y)) + (= expr1 _y)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (Uop _op _x)) + (= expr1 _x)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (Concat _x _y)) + (= expr1 _x)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (Concat _x _y)) + (= expr1 _y)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (Single _x)) + (= expr1 _x)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (Switch _pred _inputs _branches)) + (= expr1 _pred)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (Switch _pred _inputs _branches)) + (= expr1 _inputs)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (If _pred _input _then _else)) + (= expr1 _pred)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (If _pred _input _then _else)) + (= expr1 _input)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (DoWhile _in _pred-and-output)) + (= expr1 _in)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (Call _func _arg)) + (= expr1 _arg)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (Alloc _id _e _state _ty)) + (= expr1 _e)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) + +(rule ((= true (is-inv-Expr loop expr1)) + (= false (is-inv-Expr loop expr2)) + (= expr2 (Alloc _id _e _state _ty)) + (= expr1 _state)) + ((boundary-Expr loop expr1)) :ruleset boundary-analysis) +;; Some simple simplifications of loops +(ruleset loop-simplify) + +(rewrite + (DoWhile (Arg ty ctx) + (Concat (Single (Const (Bool false) ty ctx2)) + (Single (Const constant ty ctx2)))) + (Single (Const constant ty ctx)) + :ruleset loop-simplify) +;; Some simple simplifications of loops +(ruleset loop-unroll) +(ruleset loop-peel) + +;; inputs, outputs -> number of iterations +;; The minimum possible guess is 1 because of do-while loops +;; TODO: dead loop deletion can turn loops with a false condition to a body +(function LoopNumItersGuess (Expr Expr) i64 :merge (max 1 (min old new))) + +;; by default, guess that all loops run 1000 times +(rule ((DoWhile inputs outputs)) + ((set (LoopNumItersGuess inputs outputs) 1000)) + :ruleset always-run) + +;; Figure out number of iterations for a loop with constant bounds and initial value +;; and i is updated before checking pred +;; TODO: can make this work for increment by any constant +(rule + ((= lhs (DoWhile inputs outputs)) + (= num-inputs (tuple-length inputs)) + (= pred (Get outputs 0)) + ;; iteration counter starts at start_const + (= (Const (Int start_const) _ty1 _ctx1) (Get inputs counter_i)) + ;; updated counter at counter_i + (= next_counter (Get outputs (+ counter_i 1))) + ;; increments by one each loop + (= next_counter (Bop (Add) (Get (Arg _ty _ctx) counter_i) + ;; TODO: put c instead of (Int 1) and mul by c + (Const (Int 1) _ty2 _ctx2))) + ;; while next_counter less than end_constant + (= pred (Bop (LessThan) next_counter + (Const (Int end_constant) _ty3 _ctx3))) + ;; end constant is greater than start constant + (> end_constant start_const) + ) + ( + (set (LoopNumItersGuess inputs outputs) (- end_constant start_const)) + ) + :ruleset always-run) + +;; Figure out number of iterations for a loop with constant bounds and initial value +;; and i is updated after checking pred +(rule + ((= lhs (DoWhile inputs outputs)) + (= num-inputs (tuple-length inputs)) + (= pred (Get outputs 0)) + ;; iteration counter starts at start_const + (= (Const (Int start_const) _ty1 _ctx1) (Get inputs counter_i)) + ;; updated counter at counter_i + (= next_counter (Get outputs (+ counter_i 1))) + ;; increments by one each loop + (= next_counter (Bop (Add) (Get (Arg _ty _ctx) counter_i) + (Const (Int 1) _ty2 _ctx2))) + ;; while this counter less than end_constant + (= pred (Bop (LessThan) (Get (Arg _ty _ctx) counter_i) + (Const (Int end_constant) _ty3 _ctx3))) + ;; end constant is greater than start constant + (> end_constant start_const) + ) + ( + (set (LoopNumItersGuess inputs outputs) (+ (- end_constant start_const) 1)) + ) + :ruleset always-run) + +;; loop peeling rule +;; Only peel loops that we know iterate < 5 times +(rule + ((= lhs (DoWhile inputs outputs)) + (ContextOf lhs ctx) + (HasType inputs inputs-ty) + (= outputs-len (tuple-length outputs)) + (= old_cost (LoopNumItersGuess inputs outputs)) + (< old_cost 5) + ) + ( + (let executed-once + (Subst ctx inputs outputs)) + (let executed-once-body + (SubTuple executed-once 1 (- outputs-len 1))) + (let then-ctx + (InIf true (Get executed-once 0) executed-once-body)) + (let else-ctx + (InIf false (Get executed-once 0) executed-once-body)) + (union lhs + ;; check if we need to continue executing the loop + (If (Get executed-once 0) + executed-once-body ;; inputs are the body executed once + (DoWhile (Arg inputs-ty then-ctx) + outputs) ;; right now, loop unrolling shares the same outputs, but we could add more context here + (Arg inputs-ty else-ctx))) + (set (LoopNumItersGuess (Arg inputs-ty then-ctx) outputs) (- old_cost 1)) + ) + :ruleset loop-peel) + +;; unroll a loop with constant bounds and initial value +(rule + ((= lhs (DoWhile inputs outputs)) + (= num-inputs (tuple-length inputs)) + (= pred (Get outputs 0)) + ;; iteration counter starts at start_const + (= (Const (Int start_const) _ty1 _ctx1) (Get inputs counter_i)) + ;; updated counter at counter_i + (= next_counter (Get outputs (+ counter_i 1))) + ;; increments by one each loop + (= next_counter (Bop (Add) (Get (Arg _ty _ctx) counter_i) + (Const (Int 1) _ty2 _ctx2))) + ;; while less than end_constant + (= pred (Bop (LessThan) next_counter + (Const (Int end_constant) _ty3 _ctx3))) + ;; start and end constant is a multiple of 4 and greater than start_const + (> end_constant start_const) + (= (% start_const 4) 0) + (= (% end_constant 4) 0) + (= old_cost (LoopNumItersGuess inputs outputs)) + ) + ( + (let one-iter (SubTuple outputs 1 num-inputs)) + (let unrolled + (Subst (TmpCtx) one-iter + (Subst (TmpCtx) one-iter + (Subst (TmpCtx) one-iter + outputs)))) + (union lhs + (DoWhile inputs + unrolled)) + (let actual-ctx (InLoop inputs unrolled)) + (union (TmpCtx) actual-ctx) + + (set (LoopNumItersGuess inputs unrolled) (/ old_cost 4)) + (delete (TmpCtx)) + ) + :ruleset loop-unroll) + + + +(ruleset passthrough) + + +;; Pass through thetas +(rule ((= lhs (Get loop i)) + (= loop (DoWhile inputs pred-outputs)) + (= (Get pred-outputs (+ i 1)) (Get (Arg _ty _ctx) i)) + ;; only pass through pure types, since some loops don't terminate + ;; so the state edge must pass through them + (HasType (Get loop i) lhs_ty) + (PureType lhs_ty) + ) + ((union lhs (Get inputs i))) + :ruleset passthrough) + +;; Pass through switch arguments +(rule ((= lhs (Get switch i)) + (= switch (Switch pred inputs branches)) + (= (ListExpr-length branches) 2) + (= branch0 (ListExpr-ith branches 0)) + (= branch1 (ListExpr-ith branches 1)) + (= (Get branch0 i) (Get (Arg _ _ctx0) j)) + (= (Get branch1 i) (Get (Arg _ _ctx1) j)) + (= passed-through (Get inputs j)) + (HasType lhs lhs_ty) + (!= lhs_ty (Base (StateT)))) + ((union lhs passed-through)) + :ruleset passthrough) + +;; Pass through switch predicate +(rule ((= lhs (Get switch i)) + (= switch (Switch pred inputs branches)) + (= (ListExpr-length branches) 2) + (= branch0 (ListExpr-ith branches 0)) + (= branch1 (ListExpr-ith branches 1)) + (= (Get branch0 i) (Const (Bool false) _ _ctx0)) + (= (Get branch1 i) (Const (Bool true) _ _ctx1))) + ((union lhs pred)) + :ruleset passthrough) + +;; Pass through if arguments +(rule ((= if (If pred inputs then_ else_)) + (= (Get then_ i) (Get (Arg arg_ty _then_ctx) j)) + (= (Get else_ i) (Get (Arg arg_ty _else_ctx) j)) + (HasType (Get then_ i) lhs_ty) + (!= lhs_ty (Base (StateT)))) + ((union (Get if i) (Get inputs j))) + :ruleset passthrough) + +; Pass through if state edge arguments +; To maintain the invariant, we have to union the other outputs with a pure if statement +;; TODO This rule causes blowup in the egraph, unclear why +;; disabled for now +(ruleset pass-through-state-edge-if) +(rule ((= outputs (If pred inputs then_ else_)) + + (= (Get then_ i) (Get (Arg arg_ty then_ctx) j)) + (= (Get else_ i) (Get (Arg arg_ty else_ctx) j)) + + (HasType (Get then_ i) (Base (StateT)))) + + ((let lhs (Get outputs i)) + (let new_inputs (TupleRemoveAt inputs j)) + + (let new_then_ctx (InIf true pred new_inputs)) + (let new_else_ctx (InIf false pred new_inputs)) + + (let old_then (TupleRemoveAt then_ i)) + (let old_else (TupleRemoveAt else_ i)) + + (let new_then (DropAt new_then_ctx j old_then)) + (let new_else (DropAt new_else_ctx j old_else)) + + (let old_outputs (TupleRemoveAt outputs i)) + (let new_if (If pred new_inputs new_then new_else)) + (union new_if old_outputs) + + (union lhs (Get inputs j)) + ;; Be careful not to subsume the original if statement immediately, + ;; since TupleRemoveAt still needs to match on it + (ToSubsumeIf pred inputs then_ else_)) + :ruleset pass-through-state-edge-if) + + +;; Pass through if predicate +(rule ((= if (If pred inputs then_ else_)) + (= (Get then_ i) (Const (Bool true) _ _thenctx)) + (= (Get else_ i) (Const (Bool false) _ _elsectx))) + + ((let new_then (TupleRemoveAt then_ i)) + (let new_else (TupleRemoveAt else_ i)) + (let new_if (If pred inputs new_then new_else)) + + (union (Get if i) pred) + (union (TupleRemoveAt if i) new_if) + (ToSubsumeIf pred inputs then_ else_)) + :ruleset passthrough) + +;; ORIGINAL +;; a = 0 +;; c = 3 +;; for i = 0 to n: +;; a = i * c +;; +;; OPTIMIZED +;; a = 0 +;; c = 3 +;; d = 0 +;; for i = 0 to n: +;; a += d +;; d += c +(ruleset loop-strength-reduction) + +; Finds invariants/constants within a body. +; Columns: body; value of invariant in inputs; value of invariant in outputs +;; Get the input and output value of an invariant, or constant int, within the loop +;; loop in out +(relation lsr-inv (Expr Expr Expr)) + +; TODO: there may be a bug with finding the invariant, or it just may not be extracted. +; Can make this work on loop_with_mul_by_inv and a rust test later. +; (rule ( +; (= loop (DoWhile inputs pred-and-body)) +; (= (Get outputs (+ i 1)) (Get (Arg arg-type assm) i))) +; ((inv loop (Get inputs i) (Get (Arg arg-type assm) i))) :ruleset always-run) +(rule ( + (= loop (DoWhile inputs pred-and-body)) + (ContextOf inputs loop-input-ctx) + (ContextOf pred-and-body loop-output-ctx) + (= constant (Const c out-type loop-output-ctx)) + (HasArgType inputs in-type) + ) + ((lsr-inv loop (Const c in-type loop-input-ctx) constant)) :ruleset always-run) + +(rule + ( + ;; Find loop + (= old-loop (DoWhile inputs pred-and-outputs)) + (ContextOf pred-and-outputs loop-ctx) + + ; Find loop variable (argument that gets incremented with an invariant) + (lsr-inv old-loop loop-incr-in loop-incr-out) + ; Since the first el of pred-and-outputs is the pred, we need to offset i + (= (Get pred-and-outputs (+ i 1)) (Bop (Add) (Get (Arg arg-type assm) i) loop-incr-out)) + + ; Find invariant where input is same as output, or constant + (lsr-inv old-loop c-in c-out) + + ; Find multiplication of loop variable and invariant + (= old-mul (Bop (Mul) c-out (Get (Arg arg-type assm) i))) + (ContextOf old-mul loop-ctx) + + (= arg-type (TupleT ty-list)) + ) + ( + ; Each time we need to update d by the product of the multiplied constant and the loop increment + (let addend (Bop (Mul) c-out loop-incr-out)) + + ; n is index of our new, temporary variable d + (let n (tuple-length inputs)) + + ; Initial value of d is i * c + (let d-init (Bop (Mul) c-in (Get inputs i))) + + ; Construct optimized theta + ; new-inputs already has the correct context + (let new-inputs (Concat inputs (Single d-init))) + + ; We need to create a new type, with one more input + (let new-arg-ty (TupleT (TLConcat ty-list (TCons (IntT) (TNil))))) + + ; Value of d in loop. Add context to addend + (let d-out (Bop (Add) (Get (Arg new-arg-ty (TmpCtx)) n) + (Subst (TmpCtx) (Arg new-arg-ty (TmpCtx)) addend))) + + ; build the old body, making sure to set the correct arg type and context + (let new-body + (Concat + (Subst (TmpCtx) (Arg new-arg-ty (TmpCtx)) pred-and-outputs) + (Single d-out))) + + (let new-loop (DoWhile new-inputs new-body)) + + ; Now that we have the new loop, union the temporary context with the actual ctx + (union (TmpCtx) (InLoop new-inputs new-body)) + + ; Substitute d for the *i expression + (let new-mul + (Bop + (Mul) + (Subst (TmpCtx) (Arg new-arg-ty (TmpCtx)) c-out) + (Get (Arg new-arg-ty (TmpCtx)) i))) + (union (Get (Arg new-arg-ty (TmpCtx)) n) new-mul) + + ; Subsume the multiplication in the new loop to prevent + ; from firing loop strength reduction again on the new loop + (subsume + (Bop + (Mul) + (Subst (TmpCtx) (Arg new-arg-ty (TmpCtx)) c-out) + (Get (Arg new-arg-ty (TmpCtx)) i))) + + ; Project all but last + (union old-loop (SubTuple new-loop 0 n)) + (delete (TmpCtx)) + ) + :ruleset loop-strength-reduction +) +(let __tmp0 (StateT )) +(let __tmp1 (TNil )) +(let __tmp2 (TCons __tmp0 __tmp1)) +(let __tmp3 (TupleT __tmp2)) +(let __tmp4 (Print )) +(let __tmp5 (InFunc "main")) +(let __tmp6 (Arg __tmp3 __tmp5)) +(let __tmp7 (Get __tmp6 0)) +(let __tmp8 (Single __tmp7)) +(let __tmp9 (Int 0)) +(let __tmp10 (Const __tmp9 __tmp3 __tmp5)) +(let __tmp11 (Single __tmp10)) +(let __tmp12 (Int 1)) +(let __tmp13 (Const __tmp12 __tmp3 __tmp5)) +(let __tmp14 (Single __tmp13)) +(let __tmp15 (Concat __tmp11 __tmp14)) +(let __tmp16 (Concat __tmp8 __tmp15)) +(let __tmp17 (LessThan )) +(let __tmp18 (IntT )) +(let __tmp19 (TCons __tmp18 __tmp1)) +(let __tmp20 (TCons __tmp18 __tmp19)) +(let __tmp21 (TCons __tmp0 __tmp20)) +(let __tmp22 (TupleT __tmp21)) +(let __tmp23 (InFunc "dummy")) +(let __tmp24 (Arg __tmp22 __tmp23)) +(let __tmp25 (Get __tmp24 1)) +(let __tmp26 (Get __tmp24 2)) +(let __tmp27 (Bop __tmp17 __tmp25 __tmp26)) +(let __tmp28 (Single __tmp27)) +(let __tmp29 (Get __tmp24 0)) +(let __tmp30 (Single __tmp29)) +(let __tmp31 (Add )) +(let __tmp32 (Bop __tmp31 __tmp26 __tmp25)) +(let __tmp33 (Single __tmp32)) +(let __tmp34 (Single __tmp26)) +(let __tmp35 (Concat __tmp33 __tmp34)) +(let __tmp36 (Concat __tmp30 __tmp35)) +(let __tmp37 (Concat __tmp28 __tmp36)) +(let __tmp38 (InLoop __tmp16 __tmp37)) +(let __tmp39 (Arg __tmp22 __tmp38)) +(let __tmp40 (Get __tmp39 1)) +(let __tmp41 (Get __tmp39 2)) +(let __tmp42 (Bop __tmp17 __tmp40 __tmp41)) +(let __tmp43 (Single __tmp42)) +(let __tmp44 (Get __tmp39 0)) +(let __tmp45 (Single __tmp44)) +(let __tmp46 (Bop __tmp31 __tmp41 __tmp40)) +(let __tmp47 (Single __tmp46)) +(let __tmp48 (Single __tmp41)) +(let __tmp49 (Concat __tmp47 __tmp48)) +(let __tmp50 (Concat __tmp45 __tmp49)) +(let __tmp51 (Concat __tmp43 __tmp50)) +(let __tmp52 (DoWhile __tmp16 __tmp51)) +(let __tmp53 (Get __tmp52 1)) +(let __tmp54 (Get __tmp52 0)) +(let __tmp55 (Bop __tmp4 __tmp53 __tmp54)) +(let __tmp56 (Single __tmp55)) +(let __tmp57 (Function "main" __tmp3 __tmp3 __tmp56)) +(let __tmp58 (Nil )) +(let __tmp59 (Program __tmp57 __tmp58)) + +(let PROG __tmp59) +(relation InlinedCall (String Expr)) + +; (let expected (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 2) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main")))))) + +; (let substituted ( Subst (InFunc "main") (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf true (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))))) 0)) (Concat (Single (Const (Int 2) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf true (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main")))))))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf true (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main")))))))))))) +; (let iftrue +; (If (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf true (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))))) 0)) (Concat (Single (Const (Int 2) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf true (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main")))))))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf true (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main")))))))))) (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf false (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))))))) +; (Debug (If (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf true (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))))) 0)) (Concat (Single (Const (Int 2) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf true (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main")))))))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf true (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main")))))))))) (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf false (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))))))) + (unstable-combined-ruleset saturating + always-run + passthrough + canon + type-analysis + context + interval-analysis + memory-helpers + ) + + + (unstable-combined-ruleset optimizations + loop-simplify + memory + loop-unroll + peepholes + loop-peel + ) + + (unstable-combined-ruleset expensive-optimizations + optimizations + switch_rewrite + ;loop-inv-motion + loop-strength-reduction + ) + + (run-schedule + +;; saturate all helpers first +(saturate + (saturate + (saturate type-helpers) ;; resolve type helpers, finding correct types + (saturate error-checking) ;; check for errors, relies on type-helpers saturating + saturating) + + (saturate drop) + apply-drop-unions + cleanup-drop + + subsume-after-helpers + + (saturate subst) ;; do e-substitution + apply-subst-unions ;; apply the unions from substitution + cleanup-subst ;; clean up substitutions that are done + + + (saturate boundary-analysis) ;; find boundaries of invariants +) + + + (repeat 2 + +;; saturate all helpers first +(saturate + (saturate + (saturate type-helpers) ;; resolve type helpers, finding correct types + (saturate error-checking) ;; check for errors, relies on type-helpers saturating + saturating) + + (saturate drop) + apply-drop-unions + cleanup-drop + + subsume-after-helpers + + (saturate subst) ;; do e-substitution + apply-subst-unions ;; apply the unions from substitution + cleanup-subst ;; clean up substitutions that are done + + + (saturate boundary-analysis) ;; find boundaries of invariants +) + + + expensive-optimizations) + (repeat 4 + +;; saturate all helpers first +(saturate + (saturate + (saturate type-helpers) ;; resolve type helpers, finding correct types + (saturate error-checking) ;; check for errors, relies on type-helpers saturating + saturating) + + (saturate drop) + apply-drop-unions + cleanup-drop + + subsume-after-helpers + + (saturate subst) ;; do e-substitution + apply-subst-unions ;; apply the unions from substitution + cleanup-subst ;; clean up substitutions that are done + + + (saturate boundary-analysis) ;; find boundaries of invariants +) + + + optimizations) + +;; saturate all helpers first +(saturate + (saturate + (saturate type-helpers) ;; resolve type helpers, finding correct types + (saturate error-checking) ;; check for errors, relies on type-helpers saturating + saturating) + + (saturate drop) + apply-drop-unions + cleanup-drop + + subsume-after-helpers + + (saturate subst) ;; do e-substitution + apply-subst-unions ;; apply the unions from substitution + cleanup-subst ;; clean up substitutions that are done + + + (saturate boundary-analysis) ;; find boundaries of invariants +) +(saturate + (saturate + (saturate type-helpers) ;; resolve type helpers, finding correct types + (saturate error-checking) ;; check for errors, relies on type-helpers saturating + saturating) + + (saturate drop) + apply-drop-unions + cleanup-drop + + subsume-after-helpers + + (saturate subst) ;; do e-substitution + apply-subst-unions ;; apply the unions from substitution + cleanup-subst ;; clean up substitutions that are done + + + (saturate boundary-analysis) ;; find boundaries of invariants +) + + +) + + +; (print-function Subst 100) +; (let substituted ( Subst (InFunc "main") (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf true (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))))) 0)) (Concat (Single (Const (Int 2) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf true (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main")))))))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf true (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main")))))))))))) +; (let thn (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf true (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))))) 0)) (Concat (Single (Const (Int 2) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf true (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main")))))))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf true (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))))))))) +; (let els (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf false (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main")))))))) +; (query-extract :variants 5 thn) +; (query-extract :variants 5 els) +; (query-extract :variants 5 substituted) +(query-extract :variants 5 __tmp52) +; (check (= __tmp52 expected)) + +; (print-function Debug 10) +; (DoWhile (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 0) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InLoop (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 0) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 0)) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))))))) 1) (Const (Int 1) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InLoop (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 0) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 0)) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))))))))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InLoop (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 0) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 0)) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))))))) 0)) (Concat (Single (Bop (Add) (Const (Int 1) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InLoop (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 0) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 0)) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))))))) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InLoop (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 0) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 0)) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))))))) 1))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InLoop (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 0) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 0)) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2)))))))))))) +; (DoWhile (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InLoop (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 0) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 0)) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))))))) 1) (Const (Int 1) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InLoop (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 0) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 0)) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))))))))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InLoop (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 0) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 0)) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))))))) 0)) (Concat (Single (Bop (Add) (Const (Int 1) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InLoop (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 0) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 0)) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))))))) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InLoop (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 0) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 0)) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))))))) 1))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InLoop (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 0) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 0)) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2)))))))))))) + +; (If ) \ No newline at end of file diff --git a/tests/passing/small/peel_twice.bril b/tests/passing/small/peel_twice.bril new file mode 100644 index 000000000..c471ea218 --- /dev/null +++ b/tests/passing/small/peel_twice.bril @@ -0,0 +1,13 @@ +@main { + i: int = const 0; + one: int = const 1; + two: int = const 2; + +.loop: + i: int = add one i; + cond: bool = lt i two; + br cond .loop .loop_end; + +.loop_end: + print i; +} diff --git a/tests/passing/small/peel_twice_precalc_pred.bril b/tests/passing/small/peel_twice_precalc_pred.bril new file mode 100644 index 000000000..c42ae87bd --- /dev/null +++ b/tests/passing/small/peel_twice_precalc_pred.bril @@ -0,0 +1,12 @@ +@main { + i: int = const 0; + one: int = const 1; + +.loop: + cond: bool = lt i one; + i: int = add one i; + br cond .loop .loop_end; + +.loop_end: + print i; +} \ No newline at end of file From 94a3b4cb6661f42000cec188ad4fb3cc471d2461 Mon Sep 17 00:00:00 2001 From: Kirsten <32720576+kirstenmg@users.noreply.github.com> Date: Wed, 22 May 2024 15:17:48 -0700 Subject: [PATCH 04/47] Setting iters to 1 working; peeling iter 1 not working --- .../src/optimizations/loop_unroll.egg | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/dag_in_context/src/optimizations/loop_unroll.egg b/dag_in_context/src/optimizations/loop_unroll.egg index e04c642b9..1f630f0e9 100644 --- a/dag_in_context/src/optimizations/loop_unroll.egg +++ b/dag_in_context/src/optimizations/loop_unroll.egg @@ -12,6 +12,21 @@ ((set (LoopNumItersGuess inputs outputs) 1000)) :ruleset always-run) +;; For a loop that is false, its num iters is 1 +(rule + ((= loop (DoWhile inputs outputs)) + (= (Const (Bool false) ty ctx) (Get outputs 0))) + ((set (LoopNumItersGuess inputs outputs) 1)) +:ruleset always-run) + +;; For a loop that has only one iteration, union it with its body +(rule + ((= loop (DoWhile inputs outputs)) + (= 1 (LoopNumItersGuess inputs outputs)) + (ContextOf inputs ctx)) + ((union loop (Subst ctx inputs outputs))) +:ruleset always-run) + ;; Figure out number of iterations for a loop with constant bounds and initial value ;; and i is updated before checking pred ;; TODO: can make this work for increment by any constant @@ -70,7 +85,7 @@ (HasType inputs inputs-ty) (= outputs-len (tuple-length outputs)) (= old_cost (LoopNumItersGuess inputs outputs)) - ; (< old_cost 5) + (< old_cost 5) ) ( (let executed-once From 4245c624e7869ae393382c63118cc593d024326c Mon Sep 17 00:00:00 2001 From: Anjali Pal Date: Wed, 22 May 2024 15:30:49 -0700 Subject: [PATCH 05/47] store llvm separately --- infra/nightly-resources/data.js | 15 +++++++++++---- infra/nightly-resources/handlers.js | 11 ++--------- infra/nightly.sh | 2 +- infra/profile.py | 18 ++++++++---------- 4 files changed, 22 insertions(+), 24 deletions(-) diff --git a/infra/nightly-resources/data.js b/infra/nightly-resources/data.js index 6120ec873..2c09855d6 100644 --- a/infra/nightly-resources/data.js +++ b/infra/nightly-resources/data.js @@ -29,6 +29,16 @@ function getBaselineHyperfine(benchmark, runMethod) { } } +function shouldHaveLlvm(runMethod) { + return [ + "rvsdg-round-trip-to-executable", + "llvm-O0", + "llvm-O0-eggcc", + "llvm-O3", + "llvm-O3-eggcc", + ].includes(runMethod) +} + function getDataForBenchmark(benchmark) { const executions = GLOBAL_DATA.currentRun ?.filter((o) => o.benchmark === benchmark) @@ -47,10 +57,7 @@ function getDataForBenchmark(benchmark) { medianVsBaseline: diffAttribute(hyperfine, baselineHyperfine, "median"), stddev: { class: "", value: tryRound(hyperfine.stddev) }, }; - if (o.hasOwnProperty("llvm_ir")) { - if (o.llvm_ir === "") { - addWarning(`missing LLVM IR for ${o.benchmark} ${o.runMethod}`); - } + if (shouldHaveLlvm(o.runMethod)) { rowData.runMethod = `${o.runMethod}`; } return rowData; diff --git a/infra/nightly-resources/handlers.js b/infra/nightly-resources/handlers.js index 9c6f7afd4..65667762c 100644 --- a/infra/nightly-resources/handlers.js +++ b/infra/nightly-resources/handlers.js @@ -31,15 +31,8 @@ async function load_llvm() { if (!benchmark || !runMode) { console.error("missing query params, this probably shouldn't happen"); } - const entry = GLOBAL_DATA.currentRun.filter( - (entry) => entry.benchmark === benchmark && entry.runMethod === runMode, - ); - if (entry.length !== 1) { - console.error( - `missing or duplicate entries for ${benchmark} and ${runMode}, this probably shouldn't happen`, - ); - } - document.getElementById("llvm").innerText = entry[0].llvm_ir; + const llvm = await fetchText(`./data/llvm/${benchmark}-${runMode}.ll`); + document.getElementById("llvm").innerText = llvm; } async function load_table() { diff --git a/infra/nightly.sh b/infra/nightly.sh index 03948f67f..e9eb8ac26 100755 --- a/infra/nightly.sh +++ b/infra/nightly.sh @@ -40,7 +40,7 @@ echo "Switching to nighly script directory: $MYDIR" rm -rf $NIGHTLY_DIR # Prepare output directories -mkdir -p "$NIGHTLY_DIR/data" "$NIGHTLY_DIR/output" +mkdir -p "$NIGHTLY_DIR/data" "$NIGHTLY_DIR/data/llvm" "$NIGHTLY_DIR/output" pushd $TOP_DIR diff --git a/infra/profile.py b/infra/profile.py index 5766d914b..45936e3b2 100755 --- a/infra/profile.py +++ b/infra/profile.py @@ -100,18 +100,16 @@ def should_have_llvm_ir(runMethod): "llvm-O3-eggcc", ] -def get_llvm_ir(runMethod, benchmark): - path = f'./tmp/bench/{benchmark}/llvm-{runMethod}/{benchmark}-{runMethod}.ll' +def dump_llvm_ir(runMethod, benchmark, output_directory): + from_path = f'./tmp/bench/{benchmark}/llvm-{runMethod}/{benchmark}-{runMethod}.ll' - try: - with open(path) as f: - return f.read() - except OSError: - return "" + to_path = f'{output_directory}/data/llvm/{benchmark}-{runMethod}.ll' + + os.system(f'cp {from_path} {to_path}') # aggregate all profile info into a single json array. -def aggregate(compile_times, bench_times): +def aggregate(compile_times, bench_times, output_directory): res = [] for path in sorted(compile_times.keys()): @@ -119,7 +117,7 @@ def aggregate(compile_times, bench_times): runMethod = path.split("/")[-1] result = {"runMethod": runMethod, "benchmark": name, "hyperfine": bench_times[path], "compileTime": compile_times[path]} if should_have_llvm_ir(runMethod): - result["llvm_ir"] = get_llvm_ir(runMethod, name) + dump_llvm_ir(runMethod, name, output_directory) res.append(result) return res @@ -183,6 +181,6 @@ def aggregate(compile_times, bench_times): (path, _bench_data) = res bench_data[path] = _bench_data - nightly_data = aggregate(compile_times, bench_data) + nightly_data = aggregate(compile_times, bench_data, output_path) with open(f"{output_path}/data/profile.json", "w") as profile: json.dump(nightly_data, profile, indent=2) From d625e1f3f75a2765fe6ceaab218ee64bd92f7c65 Mon Sep 17 00:00:00 2001 From: Anjali Pal Date: Wed, 22 May 2024 15:31:36 -0700 Subject: [PATCH 06/47] prettier --- infra/nightly-resources/data.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infra/nightly-resources/data.js b/infra/nightly-resources/data.js index 2c09855d6..e814ff772 100644 --- a/infra/nightly-resources/data.js +++ b/infra/nightly-resources/data.js @@ -36,7 +36,7 @@ function shouldHaveLlvm(runMethod) { "llvm-O0-eggcc", "llvm-O3", "llvm-O3-eggcc", - ].includes(runMethod) + ].includes(runMethod); } function getDataForBenchmark(benchmark) { From 1cf2e13094dfea8f796dc1da525d45bd5943e1f8 Mon Sep 17 00:00:00 2001 From: oflatt Date: Wed, 22 May 2024 15:37:47 -0700 Subject: [PATCH 07/47] update comment --- src/rvsdg/optimize_direct_jumps.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rvsdg/optimize_direct_jumps.rs b/src/rvsdg/optimize_direct_jumps.rs index 7809dfd77..dab0c1a28 100644 --- a/src/rvsdg/optimize_direct_jumps.rs +++ b/src/rvsdg/optimize_direct_jumps.rs @@ -34,9 +34,9 @@ impl SimpleCfgFunction { // it points to the new, fused node let mut node_mapping: HashMap = HashMap::new(); - // we use a bfs so that previous nodes are mapped to new nodes - // before their children. - // This ensures that `node_mapping[&previous]` succeeds. + // we use a dfs post order + // so dependencies are visited before parents + // This ensures that `node_mapping[&next]` succeeds. let mut dfs = DfsPostOrder::new(&self.graph, self.entry); let mut edges_to_add = vec![]; From 0a6c1e482347837ec568e60b88b65b54077a4473 Mon Sep 17 00:00:00 2001 From: Anjali Pal Date: Wed, 22 May 2024 16:16:04 -0700 Subject: [PATCH 08/47] fix underscore escaping --- infra/generate_line_counts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infra/generate_line_counts.py b/infra/generate_line_counts.py index d432c5bef..4a5a94647 100755 --- a/infra/generate_line_counts.py +++ b/infra/generate_line_counts.py @@ -82,7 +82,7 @@ def get_rows_for_benchmark(bench, profile_data): data_for_bench = [x for x in profile_data if x["benchmark"] == bench] rows = [] for (idx, entry) in enumerate(data_for_bench): - fst_col = r'\multirow{' + str(len(data_for_bench)) + r'}{*}{' + bench + r'}' if idx == 0 else '' + fst_col = r'\multirow{' + str(len(data_for_bench)) + r'}{*}{' + bench.replace("_", r'\_') + r'}' if idx == 0 else '' res = entry["hyperfine"]["results"][0] row = " ".join([ r'\multicolumn{1}{|l|}{' + fst_col + r'} &', From ab846895685ca1414c0d59079c190decd8826b6d Mon Sep 17 00:00:00 2001 From: Eli Rosenthal Date: Thu, 23 May 2024 16:12:11 +0100 Subject: [PATCH 09/47] Replace jumps to the exit block with rets. --- src/cfg/to_bril.rs | 43 ++++++- ...state_mem_to_cfg_more_blocks_snapshot.snap | 3 +- tests/files.rs | 1 - ...files__branch_duplicate_work-optimize.snap | 11 +- tests/snapshots/files__diamond-optimize.snap | 8 +- .../files__fib_recursive-optimize.snap | 5 +- .../files__impossible_if-optimize.snap | 3 +- ...s__mem_simple_redundant_load-optimize.snap | 18 +-- .../files__range_check-optimize.snap | 3 +- .../files__range_splitting-optimize.snap | 3 +- tests/snapshots/files__sqrt-optimize.snap | 110 +++++++++--------- 11 files changed, 129 insertions(+), 79 deletions(-) diff --git a/src/cfg/to_bril.rs b/src/cfg/to_bril.rs index 5ab9379ab..101e3fbf8 100644 --- a/src/cfg/to_bril.rs +++ b/src/cfg/to_bril.rs @@ -113,7 +113,48 @@ impl SimpleCfgFunction { match self.get_branch(node) { SimpleBranch::NoBranch => {} SimpleBranch::Jmp(to) => { - if Some(&to) != next_node { + if Some(&to) == next_node { + // We will implicitly jump to the next block + return; + } + // NB: BlockName::Exit isn't always populated; e.g. it isn't + // populated in the RVSDG=>CFG code. + let target = self.graph.neighbors(node).next().unwrap(); + if target == self.exit { + // Jumping to the exit block. We want to replace these, + // where possible, with direct returns. + + // Get the exit block. + let block = &self.graph[self.exit]; + match block.instrs.last() { + Some(instr) => { + // There are instructions in the exit block. Copy them over. + self.node_to_bril(self.exit, func, node_order); + if matches!(instr, Instruction::Effect { op, .. } if op != &EffectOps::Return) + { + // We don't end with a return statement. Add one. + func.instrs.push(Code::Instruction(Instruction::Effect { + op: EffectOps::Return, + args: vec![], + funcs: vec![], + labels: vec![], + pos: None, + })); + } + } + None => { + // empty block! Just return + func.instrs.push(Code::Instruction(Instruction::Effect { + op: EffectOps::Return, + args: vec![], + funcs: vec![], + labels: vec![], + pos: None, + })); + } + } + } else { + // Standard base-case func.instrs.push(Code::Instruction(Instruction::Effect { op: EffectOps::Jump, args: vec![], diff --git a/src/rvsdg/snapshots/eggcc__rvsdg__tests__rvsdg_state_mem_to_cfg_more_blocks_snapshot.snap b/src/rvsdg/snapshots/eggcc__rvsdg__tests__rvsdg_state_mem_to_cfg_more_blocks_snapshot.snap index db37e57b9..5311a1e51 100644 --- a/src/rvsdg/snapshots/eggcc__rvsdg__tests__rvsdg_state_mem_to_cfg_more_blocks_snapshot.snap +++ b/src/rvsdg/snapshots/eggcc__rvsdg__tests__rvsdg_state_mem_to_cfg_more_blocks_snapshot.snap @@ -15,7 +15,8 @@ expression: prog.to_string() print v11; free v4; v31: int = id v7; - jmp .__42__; + print v31; + ret; .__32__: v24: int = add v11 v1; free v4; diff --git a/tests/files.rs b/tests/files.rs index f1840e51a..a4aba9c0b 100644 --- a/tests/files.rs +++ b/tests/files.rs @@ -21,7 +21,6 @@ fn generate_tests(glob: &str, benchmark_mode: bool) -> Vec { } Ok(res) => res, }; - if run.interp.should_interp() && result.original_interpreted.as_ref().unwrap() != result.result_interpreted.as_ref().unwrap() diff --git a/tests/snapshots/files__branch_duplicate_work-optimize.snap b/tests/snapshots/files__branch_duplicate_work-optimize.snap index cf1bd8c2c..16aa11209 100644 --- a/tests/snapshots/files__branch_duplicate_work-optimize.snap +++ b/tests/snapshots/files__branch_duplicate_work-optimize.snap @@ -10,11 +10,12 @@ expression: visualization.result .v4_: v6_: int = add v0 v0; v7_: int = id v6_; - jmp .v8_; + print v7_; + ret; .v5_: - v9_: int = add v0 v0; - v10_: int = mul v2_ v9_; - v7_: int = id v10_; -.v8_: + v8_: int = add v0 v0; + v9_: int = mul v2_ v8_; + v7_: int = id v9_; +.v10_: print v7_; } diff --git a/tests/snapshots/files__diamond-optimize.snap b/tests/snapshots/files__diamond-optimize.snap index b12ebafca..815ec7797 100644 --- a/tests/snapshots/files__diamond-optimize.snap +++ b/tests/snapshots/files__diamond-optimize.snap @@ -9,9 +9,9 @@ expression: visualization.result .v3_: v5_: int = const 1; print v5_; - jmp .v6_; + ret; .v4_: - v7_: int = const 2; - print v7_; -.v6_: + v6_: int = const 2; + print v6_; +.v7_: } diff --git a/tests/snapshots/files__fib_recursive-optimize.snap b/tests/snapshots/files__fib_recursive-optimize.snap index 014a41f7c..9a02639c2 100644 --- a/tests/snapshots/files__fib_recursive-optimize.snap +++ b/tests/snapshots/files__fib_recursive-optimize.snap @@ -39,7 +39,7 @@ expression: visualization.result v30_: int = id v4_; .v31_: v5_: int = id v30_; - jmp .v6_; + ret v5_; .v24_: v32_: int = const -1; v33_: int = sub v32_ v4_; @@ -284,7 +284,8 @@ expression: visualization.result v21_: int = id v4_; .v22_: v5_: int = id v21_; - jmp .v6_; + print v5_; + ret; .v17_: v23_: int = const -1; v24_: int = sub v23_ v4_; diff --git a/tests/snapshots/files__impossible_if-optimize.snap b/tests/snapshots/files__impossible_if-optimize.snap index 52410e924..fd72f3598 100644 --- a/tests/snapshots/files__impossible_if-optimize.snap +++ b/tests/snapshots/files__impossible_if-optimize.snap @@ -11,7 +11,8 @@ expression: visualization.result .v5_: print v2_; v7_: int = id v2_; - jmp .v8_; + print v2_; + ret; .v6_: print v2_; v7_: int = id v2_; diff --git a/tests/snapshots/files__mem_simple_redundant_load-optimize.snap b/tests/snapshots/files__mem_simple_redundant_load-optimize.snap index 59f68fc7c..07f982a9f 100644 --- a/tests/snapshots/files__mem_simple_redundant_load-optimize.snap +++ b/tests/snapshots/files__mem_simple_redundant_load-optimize.snap @@ -11,14 +11,18 @@ expression: visualization.result v6_: int = const 2; store v3_ v6_; v7_: ptr = id v3_; - jmp .v8_; + v8_: int = load v3_; + v9_: int = load v3_; + print v8_; + free v3_; + ret; .v5_: - v9_: int = const 3; - store v3_ v9_; + v10_: int = const 3; + store v3_ v10_; v7_: ptr = id v3_; -.v8_: - v10_: int = load v3_; - v11_: int = load v3_; - print v10_; +.v11_: + v8_: int = load v3_; + v9_: int = load v3_; + print v8_; free v3_; } diff --git a/tests/snapshots/files__range_check-optimize.snap b/tests/snapshots/files__range_check-optimize.snap index ec7cd1e03..9276ab108 100644 --- a/tests/snapshots/files__range_check-optimize.snap +++ b/tests/snapshots/files__range_check-optimize.snap @@ -33,7 +33,8 @@ expression: visualization.result br v9_ .v7_ .v22_; .v22_: v3_: int = id v6_; - jmp .v5_; + print v3_; + ret; .v13_: v23_: int = const 2; print v23_; diff --git a/tests/snapshots/files__range_splitting-optimize.snap b/tests/snapshots/files__range_splitting-optimize.snap index 197c74a10..631ad2c0c 100644 --- a/tests/snapshots/files__range_splitting-optimize.snap +++ b/tests/snapshots/files__range_splitting-optimize.snap @@ -32,7 +32,8 @@ expression: visualization.result br v11_ .v7_ .v21_; .v21_: v3_: int = id v6_; - jmp .v5_; + print v3_; + ret; .v14_: v22_: int = const 2; print v22_; diff --git a/tests/snapshots/files__sqrt-optimize.snap b/tests/snapshots/files__sqrt-optimize.snap index fb7981af8..ad9335e24 100644 --- a/tests/snapshots/files__sqrt-optimize.snap +++ b/tests/snapshots/files__sqrt-optimize.snap @@ -9,74 +9,74 @@ expression: visualization.result br v3_ .v4_ .v5_; .v4_: print v2_; - jmp .v6_; + ret; .v5_: - v7_: bool = feq v0 v0; - v8_: bool = const true; - v9_: float = id v2_; - v10_: bool = id v8_; - br v7_ .v11_ .v12_; -.v11_: - v13_: bool = flt v0 v2_; - v14_: float = id v2_; - br v13_ .v15_ .v16_; -.v16_: - v17_: float = const 1; - v18_: float = const 1.0000000001; - v19_: float = const 0.9999999999; - v20_: float = const 2; - v21_: float = id v2_; + v6_: bool = feq v0 v0; + v7_: bool = const true; + v8_: float = id v2_; + v9_: bool = id v7_; + br v6_ .v10_ .v11_; +.v10_: + v12_: bool = flt v0 v2_; + v13_: float = id v2_; + br v12_ .v14_ .v15_; +.v15_: + v16_: float = const 1; + v17_: float = const 1.0000000001; + v18_: float = const 0.9999999999; + v19_: float = const 2; + v20_: float = id v2_; + v21_: float = id v16_; v22_: float = id v17_; v23_: float = id v18_; v24_: float = id v19_; - v25_: float = id v20_; - v26_: float = id v0; -.v27_: - v28_: float = fdiv v26_ v22_; - v29_: float = fadd v22_ v28_; - v30_: float = fdiv v29_ v25_; - v31_: float = fdiv v30_ v22_; - v32_: bool = fle v31_ v23_; - v33_: bool = fge v31_ v24_; - v34_: bool = and v32_ v33_; - v35_: bool = const true; - v36_: float = id v21_; - v37_: float = id v30_; - v38_: bool = id v35_; + v25_: float = id v0; +.v26_: + v27_: float = fdiv v25_ v21_; + v28_: float = fadd v21_ v27_; + v29_: float = fdiv v28_ v24_; + v30_: float = fdiv v29_ v21_; + v31_: bool = fle v30_ v22_; + v32_: bool = fge v30_ v23_; + v33_: bool = and v31_ v32_; + v34_: bool = const true; + v35_: float = id v20_; + v36_: float = id v29_; + v37_: bool = id v34_; + v38_: float = id v22_; v39_: float = id v23_; v40_: float = id v24_; v41_: float = id v25_; - v42_: float = id v26_; - br v34_ .v43_ .v44_; -.v43_: - v45_: bool = const false; - v36_: float = id v21_; - v37_: float = id v30_; - v38_: bool = id v45_; + br v33_ .v42_ .v43_; +.v42_: + v44_: bool = const false; + v35_: float = id v20_; + v36_: float = id v29_; + v37_: bool = id v44_; + v38_: float = id v22_; v39_: float = id v23_; v40_: float = id v24_; v41_: float = id v25_; - v42_: float = id v26_; -.v44_: - v46_: bool = not v34_; - v21_: float = id v21_; - v22_: float = id v30_; +.v43_: + v45_: bool = not v33_; + v20_: float = id v20_; + v21_: float = id v29_; + v22_: float = id v22_; v23_: float = id v23_; v24_: float = id v24_; v25_: float = id v25_; - v26_: float = id v26_; - br v46_ .v27_ .v47_; + br v45_ .v26_ .v46_; +.v46_: + print v21_; + v13_: float = id v20_; +.v14_: + v8_: float = id v13_; + v9_: bool = id v12_; +.v11_: + br v9_ .v47_ .v48_; .v47_: - print v22_; - v14_: float = id v21_; -.v15_: - v9_: float = id v14_; - v10_: bool = id v13_; -.v12_: - br v10_ .v48_ .v49_; + v49_: float = fdiv v8_ v8_; + print v49_; .v48_: - v50_: float = fdiv v9_ v9_; - print v50_; -.v49_: -.v6_: +.v50_: } From f31384c4f85281da7ee094dda48168b67edd2ab1 Mon Sep 17 00:00:00 2001 From: Kirsten <32720576+kirstenmg@users.noreply.github.com> Date: Thu, 23 May 2024 11:56:07 -0700 Subject: [PATCH 10/47] Generalize loop peeling for any constant increment loop --- .../src/optimizations/loop_unroll.egg | 33 ++++----- dag_in_context/src/schedule.rs | 2 +- tests/passing/small/jumping_loop.bril | 12 ++++ .../files__gamma_condition_and-optimize.snap | 2 +- .../files__implicit-return-optimize.snap | 71 ++++++++----------- .../files__jumping_loop-optimize.snap | 7 ++ .../snapshots/files__peel_twice-optimize.snap | 9 +++ ...les__peel_twice_precalc_pred-optimize.snap | 9 +++ .../files__range_check-optimize.snap | 62 +++++++--------- .../files__range_splitting-optimize.snap | 60 +++++++--------- .../files__simplest_loop-optimize.snap | 23 +++--- tests/snapshots/files__sqrt-optimize.snap | 4 +- .../files__unroll_multiple_4-optimize.snap | 10 +-- 13 files changed, 153 insertions(+), 151 deletions(-) create mode 100644 tests/passing/small/jumping_loop.bril create mode 100644 tests/snapshots/files__jumping_loop-optimize.snap create mode 100644 tests/snapshots/files__peel_twice-optimize.snap create mode 100644 tests/snapshots/files__peel_twice_precalc_pred-optimize.snap diff --git a/dag_in_context/src/optimizations/loop_unroll.egg b/dag_in_context/src/optimizations/loop_unroll.egg index 1f630f0e9..e02b53ef5 100644 --- a/dag_in_context/src/optimizations/loop_unroll.egg +++ b/dag_in_context/src/optimizations/loop_unroll.egg @@ -19,17 +19,9 @@ ((set (LoopNumItersGuess inputs outputs) 1)) :ruleset always-run) -;; For a loop that has only one iteration, union it with its body -(rule - ((= loop (DoWhile inputs outputs)) - (= 1 (LoopNumItersGuess inputs outputs)) - (ContextOf inputs ctx)) - ((union loop (Subst ctx inputs outputs))) -:ruleset always-run) - ;; Figure out number of iterations for a loop with constant bounds and initial value ;; and i is updated before checking pred -;; TODO: can make this work for increment by any constant +;; TODO: we could make it work for decrementing loops (rule ((= lhs (DoWhile inputs outputs)) (= num-inputs (tuple-length inputs)) @@ -38,18 +30,18 @@ (= (Const (Int start_const) _ty1 _ctx1) (Get inputs counter_i)) ;; updated counter at counter_i (= next_counter (Get outputs (+ counter_i 1))) - ;; increments by one each loop + ;; increments by some constant each loop (= next_counter (Bop (Add) (Get (Arg _ty _ctx) counter_i) - ;; TODO: put c instead of (Int 1) and mul by c - (Const (Int 1) _ty2 _ctx2))) + (Const (Int increment) _ty2 _ctx2))) + (> increment 0) ;; while next_counter less than end_constant (= pred (Bop (LessThan) next_counter (Const (Int end_constant) _ty3 _ctx3))) - ;; end constant is greater than start constant - (> end_constant start_const) + ;; end constant is at least start constant + (>= end_constant start_const) ) ( - (set (LoopNumItersGuess inputs outputs) (- end_constant start_const)) + (set (LoopNumItersGuess inputs outputs) (/ (- end_constant start_const) increment)) ) :ruleset always-run) @@ -63,17 +55,18 @@ (= (Const (Int start_const) _ty1 _ctx1) (Get inputs counter_i)) ;; updated counter at counter_i (= next_counter (Get outputs (+ counter_i 1))) - ;; increments by one each loop + ;; increments by a constant each loop (= next_counter (Bop (Add) (Get (Arg _ty _ctx) counter_i) - (Const (Int 1) _ty2 _ctx2))) + (Const (Int increment) _ty2 _ctx2))) + (> increment 0) ;; while this counter less than end_constant (= pred (Bop (LessThan) (Get (Arg _ty _ctx) counter_i) (Const (Int end_constant) _ty3 _ctx3))) - ;; end constant is greater than start constant - (> end_constant start_const) + ;; end constant is at least start constant + (>= end_constant start_const) ) ( - (set (LoopNumItersGuess inputs outputs) (+ (- end_constant start_const) 1)) + (set (LoopNumItersGuess inputs outputs) (+ (/ (- end_constant start_const) increment) 1)) ) :ruleset always-run) diff --git a/dag_in_context/src/schedule.rs b/dag_in_context/src/schedule.rs index 07f676d92..40ec492b5 100644 --- a/dag_in_context/src/schedule.rs +++ b/dag_in_context/src/schedule.rs @@ -45,6 +45,7 @@ pub fn mk_schedule() -> String { memory loop-unroll peepholes + loop-peel ) (unstable-combined-ruleset expensive-optimizations @@ -52,7 +53,6 @@ pub fn mk_schedule() -> String { switch_rewrite ;loop-inv-motion loop-strength-reduction - loop-peel ) (run-schedule diff --git a/tests/passing/small/jumping_loop.bril b/tests/passing/small/jumping_loop.bril new file mode 100644 index 000000000..f85253eb4 --- /dev/null +++ b/tests/passing/small/jumping_loop.bril @@ -0,0 +1,12 @@ +@main { + jump: int = const 4; + i: int = const 0; + n: int = const 18; + +.loop: + i: int = add jump i; + pred: bool = lt i n; + br pred .loop .end; + +.end: +} \ No newline at end of file diff --git a/tests/snapshots/files__gamma_condition_and-optimize.snap b/tests/snapshots/files__gamma_condition_and-optimize.snap index d2fb01cff..5b6fe2370 100644 --- a/tests/snapshots/files__gamma_condition_and-optimize.snap +++ b/tests/snapshots/files__gamma_condition_and-optimize.snap @@ -5,7 +5,7 @@ expression: visualization.result @main(v0: int) { .v1_: v2_: int = const 0; - v3_: bool = lt v2_ v0; + v3_: bool = gt v0 v2_; v4_: bool = lt v0 v2_; v5_: int = const 1; v6_: int = const 3; diff --git a/tests/snapshots/files__implicit-return-optimize.snap b/tests/snapshots/files__implicit-return-optimize.snap index 05f54ca89..53ad6fedf 100644 --- a/tests/snapshots/files__implicit-return-optimize.snap +++ b/tests/snapshots/files__implicit-return-optimize.snap @@ -37,48 +37,35 @@ expression: visualization.result } @main { .v0_: - v1_: bool = const true; - v2_: int = const 16; - v3_: int = const 1; - v4_: int = const 4; - v5_: int = const 15; - v6_: int = id v2_; + v1_: int = const 4; + v2_: int = const 0; + v3_: int = const 15; + v4_: int = id v1_; + v5_: int = id v2_; + v6_: int = id v1_; v7_: int = id v3_; - v8_: int = id v4_; - v9_: int = id v5_; - br v1_ .v10_ .v11_; -.v10_: - v12_: int = id v2_; - v13_: int = id v3_; - v14_: int = id v4_; - v15_: int = id v5_; -.v16_: - v17_: int = const 14; - v18_: bool = lt v13_ v17_; - v19_: int = id v12_; - v20_: int = id v13_; - v21_: int = id v14_; - v22_: int = id v15_; - br v18_ .v23_ .v24_; -.v23_: - v25_: int = mul v12_ v14_; - v26_: int = const 1; - v27_: int = add v13_ v26_; - v19_: int = id v25_; - v20_: int = id v27_; - v21_: int = id v14_; - v22_: int = id v15_; -.v24_: +.v8_: + v9_: int = const 14; + v10_: bool = lt v5_ v9_; + v11_: int = id v4_; + v12_: int = id v5_; + v13_: int = id v6_; + v14_: int = id v7_; + br v10_ .v15_ .v16_; +.v15_: + v17_: int = mul v4_ v6_; + v18_: int = const 1; + v19_: int = add v18_ v5_; + v11_: int = id v17_; v12_: int = id v19_; - v13_: int = id v20_; - v14_: int = id v21_; - v15_: int = id v22_; - br v18_ .v16_ .v28_; -.v28_: - v6_: int = id v12_; - v7_: int = id v13_; - v8_: int = id v14_; - v9_: int = id v15_; -.v11_: - print v6_; + v13_: int = id v6_; + v14_: int = id v7_; +.v16_: + v4_: int = id v11_; + v5_: int = id v12_; + v6_: int = id v13_; + v7_: int = id v14_; + br v10_ .v8_ .v20_; +.v20_: + print v4_; } diff --git a/tests/snapshots/files__jumping_loop-optimize.snap b/tests/snapshots/files__jumping_loop-optimize.snap new file mode 100644 index 000000000..a1c1c23ac --- /dev/null +++ b/tests/snapshots/files__jumping_loop-optimize.snap @@ -0,0 +1,7 @@ +--- +source: tests/files.rs +expression: visualization.result +--- +@main { +.v0_: +} diff --git a/tests/snapshots/files__peel_twice-optimize.snap b/tests/snapshots/files__peel_twice-optimize.snap new file mode 100644 index 000000000..f2691ba96 --- /dev/null +++ b/tests/snapshots/files__peel_twice-optimize.snap @@ -0,0 +1,9 @@ +--- +source: tests/files.rs +expression: visualization.result +--- +@main { +.v0_: + v1_: int = const 2; + print v1_; +} diff --git a/tests/snapshots/files__peel_twice_precalc_pred-optimize.snap b/tests/snapshots/files__peel_twice_precalc_pred-optimize.snap new file mode 100644 index 000000000..f2691ba96 --- /dev/null +++ b/tests/snapshots/files__peel_twice_precalc_pred-optimize.snap @@ -0,0 +1,9 @@ +--- +source: tests/files.rs +expression: visualization.result +--- +@main { +.v0_: + v1_: int = const 2; + print v1_; +} diff --git a/tests/snapshots/files__range_check-optimize.snap b/tests/snapshots/files__range_check-optimize.snap index ec7cd1e03..59f868ab0 100644 --- a/tests/snapshots/files__range_check-optimize.snap +++ b/tests/snapshots/files__range_check-optimize.snap @@ -4,41 +4,33 @@ expression: visualization.result --- @main { .v0_: - v1_: bool = const true; - v2_: int = const 1; - print v2_; - v3_: int = id v2_; - br v1_ .v4_ .v5_; -.v4_: - v6_: int = id v2_; -.v7_: - v8_: int = const 6; - v9_: bool = lt v6_ v8_; - v10_: int = const 5; - v11_: bool = lt v6_ v10_; - br v11_ .v12_ .v13_; + v1_: int = const 0; + v2_: int = id v1_; +.v3_: + v4_: int = const 6; + v5_: bool = lt v2_ v4_; + v6_: int = const 5; + v7_: bool = lt v2_ v6_; + br v7_ .v8_ .v9_; +.v8_: + v10_: int = const 1; + print v10_; + v11_: int = id v2_; .v12_: - v14_: int = const 1; - print v14_; - v15_: int = id v6_; + v13_: int = const 1; + v14_: int = add v13_ v2_; + v15_: int = id v14_; + br v5_ .v16_ .v17_; .v16_: - v17_: int = const 1; - v18_: int = add v17_ v6_; - v19_: int = id v18_; - br v9_ .v20_ .v21_; -.v20_: - v19_: int = id v18_; -.v21_: - v6_: int = id v19_; - br v9_ .v7_ .v22_; -.v22_: - v3_: int = id v6_; - jmp .v5_; -.v13_: - v23_: int = const 2; - print v23_; - v15_: int = id v6_; - jmp .v16_; -.v5_: - print v3_; + v15_: int = id v14_; +.v17_: + v2_: int = id v15_; + br v5_ .v3_ .v18_; +.v9_: + v19_: int = const 2; + print v19_; + v11_: int = id v2_; + jmp .v12_; +.v18_: + print v2_; } diff --git a/tests/snapshots/files__range_splitting-optimize.snap b/tests/snapshots/files__range_splitting-optimize.snap index 197c74a10..1e64a449e 100644 --- a/tests/snapshots/files__range_splitting-optimize.snap +++ b/tests/snapshots/files__range_splitting-optimize.snap @@ -4,40 +4,32 @@ expression: visualization.result --- @main { .v0_: - v1_: bool = const true; - v2_: int = const 1; - print v2_; - v3_: int = id v2_; - br v1_ .v4_ .v5_; -.v4_: - v6_: int = id v2_; -.v7_: - v8_: int = const 1; - v9_: int = add v6_ v8_; - v10_: int = const 5; - v11_: bool = lt v9_ v10_; - v12_: bool = lt v6_ v10_; - br v12_ .v13_ .v14_; + v1_: int = const 0; + v2_: int = id v1_; +.v3_: + v4_: int = const 1; + v5_: int = add v2_ v4_; + v6_: int = const 5; + v7_: bool = lt v5_ v6_; + v8_: bool = lt v2_ v6_; + br v8_ .v9_ .v10_; +.v9_: + v11_: int = const 1; + print v11_; + v12_: int = id v2_; .v13_: - v15_: int = const 1; - print v15_; - v16_: int = id v6_; + v14_: int = id v5_; + br v7_ .v15_ .v16_; +.v15_: + v14_: int = id v5_; +.v16_: + v2_: int = id v14_; + br v7_ .v3_ .v17_; +.v10_: + v18_: int = const 2; + print v18_; + v12_: int = id v2_; + jmp .v13_; .v17_: - v18_: int = id v9_; - br v11_ .v19_ .v20_; -.v19_: - v18_: int = id v9_; -.v20_: - v6_: int = id v18_; - br v11_ .v7_ .v21_; -.v21_: - v3_: int = id v6_; - jmp .v5_; -.v14_: - v22_: int = const 2; - print v22_; - v16_: int = id v6_; - jmp .v17_; -.v5_: - print v3_; + print v2_; } diff --git a/tests/snapshots/files__simplest_loop-optimize.snap b/tests/snapshots/files__simplest_loop-optimize.snap index f0b6a9bea..b1a6cd2c5 100644 --- a/tests/snapshots/files__simplest_loop-optimize.snap +++ b/tests/snapshots/files__simplest_loop-optimize.snap @@ -4,17 +4,18 @@ expression: visualization.result --- @main { .v0_: - v1_: int = const 1; + v1_: int = const 0; v2_: int = const 5; - v3_: int = id v1_; - v4_: int = id v2_; - v5_: int = id v1_; -.v6_: - v7_: int = add v3_ v5_; - v8_: bool = lt v7_ v4_; - v3_: int = id v7_; - v4_: int = id v4_; + v3_: int = const 1; + v4_: int = id v1_; + v5_: int = id v2_; + v6_: int = id v3_; +.v7_: + v8_: int = add v4_ v6_; + v9_: bool = lt v8_ v5_; + v4_: int = id v8_; v5_: int = id v5_; - br v8_ .v6_ .v9_; -.v9_: + v6_: int = id v6_; + br v9_ .v7_ .v10_; +.v10_: } diff --git a/tests/snapshots/files__sqrt-optimize.snap b/tests/snapshots/files__sqrt-optimize.snap index fb7981af8..35f236503 100644 --- a/tests/snapshots/files__sqrt-optimize.snap +++ b/tests/snapshots/files__sqrt-optimize.snap @@ -36,8 +36,8 @@ expression: visualization.result v29_: float = fadd v22_ v28_; v30_: float = fdiv v29_ v25_; v31_: float = fdiv v30_ v22_; - v32_: bool = fle v31_ v23_; - v33_: bool = fge v31_ v24_; + v32_: bool = fge v31_ v24_; + v33_: bool = fle v31_ v23_; v34_: bool = and v32_ v33_; v35_: bool = const true; v36_: float = id v21_; diff --git a/tests/snapshots/files__unroll_multiple_4-optimize.snap b/tests/snapshots/files__unroll_multiple_4-optimize.snap index e338c81fa..093bd6745 100644 --- a/tests/snapshots/files__unroll_multiple_4-optimize.snap +++ b/tests/snapshots/files__unroll_multiple_4-optimize.snap @@ -4,11 +4,11 @@ expression: visualization.result --- @main { .v0_: - v1_: int = const 0; - v2_: int = const 16; + v1_: int = const 16; + v2_: int = const 0; v3_: int = const 1; - v4_: int = id v1_; - v5_: int = id v2_; + v4_: int = id v2_; + v5_: int = id v1_; v6_: int = id v3_; .v7_: v8_: int = add v4_ v6_; @@ -21,5 +21,5 @@ expression: visualization.result v6_: int = id v6_; br v12_ .v7_ .v13_; .v13_: - print v4_; + print v1_; } From 8fa6bf17b5edfa593de760461a94502255326c5d Mon Sep 17 00:00:00 2001 From: Kirsten <32720576+kirstenmg@users.noreply.github.com> Date: Thu, 23 May 2024 11:57:50 -0700 Subject: [PATCH 11/47] Remove debugging files' --- dag_in_context/out.egg | 3725 -------------------------------------- out.egg | 3854 ---------------------------------------- 2 files changed, 7579 deletions(-) delete mode 100644 dag_in_context/out.egg delete mode 100644 out.egg diff --git a/dag_in_context/out.egg b/dag_in_context/out.egg deleted file mode 100644 index dcc5f9426..000000000 --- a/dag_in_context/out.egg +++ /dev/null @@ -1,3725 +0,0 @@ - Compiling dag_in_context v0.1.0 (/Users/kirsten/GitHub/eggcc/dag_in_context) -warning: unused import: `crate::egglog_test` - --> src/optimizations/loop_unroll.rs:34:9 - | -34 | use crate::egglog_test; - | ^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(unused_imports)]` on by default - -warning: unused import: `crate::egglog_test_and_print_program` - --> src/optimizations/loop_unroll.rs:1:5 - | -1 | use crate::egglog_test_and_print_program; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(unused_imports)]` on by default - -warning: unused variable: `expected` - --> src/optimizations/loop_unroll.rs:61:9 - | -61 | let expected = parallel!(int(2), int(1)).with_arg_types(emptyt(), tuplet!(intt(), intt())); - | ^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_expected` - | - = note: `#[warn(unused_variables)]` on by default - -warning: `dag_in_context` (lib) generated 1 warning (run `cargo fix --lib -p dag_in_context` to apply 1 suggestion) -warning: `dag_in_context` (lib test) generated 2 warnings (run `cargo fix --lib -p dag_in_context --tests` to apply 2 suggestions) - Finished release [optimized] target(s) in 5.98s - Running unittests src/lib.rs (target/release/deps/dag_in_context-90c12cb0a35ca697) -; Every term is an `Expr` or a `ListExpr`. -(datatype Expr) -; Used for constructing a list of branches for `Switch`es -; or a list of functions in a `Program`. -(datatype ListExpr (Cons Expr ListExpr) (Nil)) - -; ================================= -; Types -; ================================= - -(sort TypeList) - -(datatype BaseType - (IntT) - (BoolT) - (FloatT) - ; a pointer to a memory region with a particular type - (PointerT BaseType) - (StateT)) - - -(datatype Type - ; a primitive type - (Base BaseType) - ; a typed tuple. Use an empty tuple as a unit type. - ; state edge also has unit type - (TupleT TypeList) -) - -(function TNil () TypeList) -(function TCons (BaseType TypeList) TypeList) ; Head element should never be a tuple - - -; ================================= -; Assumptions -; ================================= - -(datatype Assumption - ; Assume nothing - (InFunc String) - ; The term is in a loop with `input` and `pred_output`. - ; InLoop is a special context because it describes the argument of the loop. It is a *scope context*. - ; input pred_output - (InLoop Expr Expr) - ; Branch of the switch, and what the predicate is, and what the input is - (InSwitch i64 Expr Expr) - ; If the predicate was true, and what the predicate is, and what the input is - (InIf bool Expr Expr) -) - - - -; ================================= -; Leaf nodes -; Constants, argument, and empty tuple -; ================================= - -; Only a single argument is bound- if multiple values are needed, arg will be a tuple. -; e.g. `(Get (Arg tuple_type) 1)` gets the second value in the argument with some tuple_type. -(function Arg (Type Assumption) Expr) - -; Constants -(datatype Constant - (Int i64) - (Bool bool) - (Float f64)) -; All leaf nodes need the type of the argument -; Type is the type of the bound argument in scope -(function Const (Constant Type Assumption) Expr) - -; An empty tuple. -; Type is the type of the bound argument in scope -(function Empty (Type Assumption) Expr) - - -; ================================= -; Operators -; ================================= - -(datatype TernaryOp - ; given a pointer, value, and a state edge - ; writes the value to the pointer and returns - ; the resulting state edge - (Write) - (Select)) -(datatype BinaryOp - ;; integer operators - (Add) - (Sub) - (Div) - (Mul) - (LessThan) - (GreaterThan) - (LessEq) - (GreaterEq) - (Eq) - ;; float operators - (FAdd) - (FSub) - (FDiv) - (FMul) - (FLessThan) - (FGreaterThan) - (FLessEq) - (FGreaterEq) - (FEq) - ;; logical operators - (And) - (Or) - ; given a pointer and a state edge - ; loads the value at the pointer and returns (value, state edge) - (Load) - ; Takes a pointer and an integer, and offsets - ; the pointer by the integer - (PtrAdd) - ; given and value and a state edge, prints the value as a side-effect - ; the value must be a base value, not a tuple - ; returns an empty tuple - (Print) - ; given a pointer and state edge, frees the whole memory region at the pointer - (Free)) -(datatype UnaryOp - (Not)) - -; Operators -(function Top (TernaryOp Expr Expr Expr) Expr) -(function Bop (BinaryOp Expr Expr) Expr) -(function Uop (UnaryOp Expr) Expr) -; gets from a tuple. static index -(function Get (Expr i64) Expr) -; (Alloc id amount state_edge pointer_type) -; allocate an integer amount of memory for a particular type -; returns (pointer to the allocated memory, state edge) -(function Alloc (i64 Expr Expr BaseType) Expr) -; name of func arg -(function Call (String Expr) Expr) - - - -; ================================= -; Tuple operations -; ================================= - -; `Empty`, `Single` and `Concat` create tuples. -; 1. Use `Empty` for an empty tuple. -; 2. Use `Single` for a tuple with one element. -; 3. Use `Concat` to append the elements from two tuples together. -; Nested tuples are not allowed. - - -; A tuple with a single element. -; Necessary because we only use `Concat` to add to tuples. -(function Single (Expr) Expr) -; Concat appends the elemnts from two tuples together -; e.g. (Concat (Concat (Single a) (Single b)) -; (Concat (Single c) (Single d))) = (a, b, c, d) -; expr1 expr2 -(function Concat (Expr Expr) Expr) - - - -; ================================= -; Control flow -; ================================= - -; Switch on a list of lazily-evaluated branches. -; pred must be an integer -; pred inputs branches chosen -(function Switch (Expr Expr ListExpr) Expr) -; If is like switch, but with a boolean predicate -; pred inputs then else -(function If (Expr Expr Expr Expr) Expr) - - -; A do-while loop. -; Evaluates the input, then evaluates the body. -; Keeps looping while the predicate is true. -; input must have the same type as (output1, output2, ..., outputi) -; input must be a tuple -; pred must be a boolean -; pred-and-body must be a flat tuple (pred, out1, out2, ..., outi) -; input must be the same type as (out1, out2, ..., outi) -; input pred-and-body -(function DoWhile (Expr Expr) Expr) - - -; ================================= -; Top-level expressions -; ================================= -(sort ProgramType) -; An entry function and a list of additional functions. -; entry function other functions -(function Program (Expr ListExpr) ProgramType) -; name input ty output ty output -(function Function (String Type Type Expr) Expr) - - - -; Rulesets -(ruleset always-run) -(ruleset error-checking) -(ruleset memory) -(ruleset memory-helpers) -(ruleset smem) - -;; Initliazation -(relation bop->string (BinaryOp String)) -(relation uop->string (UnaryOp String)) -(relation top->string (TernaryOp String)) -(bop->string (Add) "Add") -(bop->string (Sub) "Sub") -(bop->string (Div) "Div") -(bop->string (Mul) "Mul") -(bop->string (LessThan) "LessThan") -(bop->string (GreaterThan) "GreaterThan") -(bop->string (LessEq) "LessEq") -(bop->string (GreaterEq) "GreaterEq") -(bop->string (Eq) "Eq") -(bop->string (FAdd) "FAdd") -(bop->string (FSub) "FSub") -(bop->string (FDiv) "FDiv") -(bop->string (FMul) "FMul") -(bop->string (FLessThan) "FLessThan") -(bop->string (FGreaterThan) "FGreaterThan") -(bop->string (FLessEq) "FLessEq") -(bop->string (FGreaterEq) "FGreaterEq") -(bop->string (FEq) "FEq") -(bop->string (And) "And") -(bop->string (Or) "Or") -(bop->string (Load) "Load") -(bop->string (PtrAdd) "PtrAdd") -(bop->string (Print) "Print") -(bop->string (Free) "Free") -(ruleset type-analysis) -(ruleset type-helpers) ;; these rules need to saturate between every iter of type-analysis rules - -(function TLConcat (TypeList TypeList) TypeList :unextractable) -(rewrite (TLConcat (TNil) r) r :ruleset type-helpers) -(rewrite (TLConcat (TCons hd tl) r) - (TCons hd (TLConcat tl r)) - :ruleset type-helpers) - -(function TypeList-length (TypeList) i64 :unextractable) -(function TypeList-ith (TypeList i64) BaseType :unextractable) -(function TypeList-suffix (TypeList i64) TypeList :unextractable) - -(rule ((TupleT tylist)) ((union (TypeList-suffix tylist 0) tylist)) :ruleset type-helpers) - -(rule ((= (TypeList-suffix top n) (TCons hd tl))) - ((union (TypeList-ith top n) hd) - (union (TypeList-suffix top (+ n 1)) tl)) :ruleset type-helpers) - -(rule ((= (TypeList-suffix list n) (TNil))) - ((set (TypeList-length list) n)) :ruleset type-helpers) - -(rule ((TypeList-ith list i) - (= (TypeList-length list) n) - (>= i n)) - ((panic "TypeList-ith out of bounds")) :ruleset type-helpers) - -(relation HasType (Expr Type)) - - -;; Keep track of type expectations for error messages -(relation ExpectType (Expr Type String)) -(rule ( - (ExpectType e expected msg) - (HasType e actual) - (!= expected actual) ;; OKAY to compare types for equality because we never union types. - ) - ((extract "Expecting expression") - (extract e) - (extract "to have type") - (extract expected) - (extract "but got type") - (extract actual) - (extract "with message") - (extract msg) - (panic "type mismatch")) - :ruleset error-checking) - -(relation HasArgType (Expr Type)) - -(rule ((HasArgType (Arg t1 ctx) t2) - (!= t1 t2)) - ((panic "arg type mismatch")) - :ruleset error-checking) - -(rule ((= lhs (Function name in out body)) - (HasArgType body ty) - (HasArgType body ty2) - (!= ty ty2)) - ((panic "arg type mismatch in function")) - :ruleset error-checking) - -; Propagate arg types up -(rule ((= lhs (Uop _ e)) - (HasArgType e ty)) - ((HasArgType lhs ty)) - :ruleset type-analysis) -(rule ((= lhs (Bop _ a b)) - (HasArgType a ty)) - ((HasArgType lhs ty)) - :ruleset type-analysis) -(rule ((= lhs (Bop _ a b)) - (HasArgType b ty)) - ((HasArgType lhs ty)) - :ruleset type-analysis) -(rule ((= lhs (Get e _)) - (HasArgType e ty)) - ((HasArgType lhs ty)) - :ruleset type-analysis) -(rule ((= lhs (Alloc _id e state _)) - (HasArgType e ty)) - ((HasArgType lhs ty)) - :ruleset type-analysis) -(rule ((= lhs (Call _ e)) - (HasArgType e ty)) - ((HasArgType lhs ty)) - :ruleset type-analysis) -(rule ((= lhs (Single e)) - (HasArgType e ty)) - ((HasArgType lhs ty)) - :ruleset type-analysis) -(rule ((= lhs (Concat e1 e2)) - (HasArgType e1 ty)) - ((HasArgType lhs ty)) - :ruleset type-analysis) -(rule ((= lhs (Concat e1 e2)) - (HasArgType e2 ty)) - ((HasArgType lhs ty)) - :ruleset type-analysis) -(rule ((= lhs (Switch pred inputs (Cons branch rest))) - (HasArgType pred ty)) - ((HasArgType lhs ty)) - :ruleset type-analysis) -(rule ((= lhs (Switch pred inputs (Cons branch rest))) - (HasArgType branch ty) - (HasType inputs ty2) - (!= ty ty2)) - ((panic "switch branches then branch has incorrect input type")) - :ruleset error-checking) -;; demand with one fewer branches -(rule ((= lhs (Switch pred inputs (Cons branch rest)))) - ((Switch pred inputs rest)) - :ruleset type-analysis) -(rule ((= lhs (If c i t e)) - (HasArgType c ty)) - ((HasArgType lhs ty)) - :ruleset type-analysis) -(rule ((= lhs (If c i t e)) - (HasType i ty) - (HasArgType t ty2) - (!= ty ty2)) - ((panic "if branches then branch has incorrect input type")) - :ruleset error-checking) -(rule ((= lhs (If c i t e)) - (HasType i ty) - (HasArgType e ty2) - (!= ty ty2)) - ((panic "if branches else branch has incorrect input type")) - :ruleset error-checking) - - -(rule ((= lhs (DoWhile ins body)) - (HasArgType ins ty)) - ((HasArgType lhs ty)) - :ruleset type-analysis) -; Don't push arg types through Program, Function, DoWhile, Let exprs because -; these create new arg contexts. - -; Primitives -(rule ((= lhs (Const (Int i) ty ctx))) - ((HasType lhs (Base (IntT))) - (HasArgType lhs ty)) - :ruleset type-analysis) - -(rule ((= lhs (Const (Bool b) ty ctx))) - ((HasType lhs (Base (BoolT))) - (HasArgType lhs ty)) - :ruleset type-analysis) - -(rule ((= lhs (Const (Float b) ty ctx))) - ((HasType lhs (Base (FloatT))) - (HasArgType lhs ty)) - :ruleset type-analysis) - -(rule ((= lhs (Empty ty ctx))) - ((HasType lhs (TupleT (TNil))) - (HasArgType lhs ty)) - :ruleset type-analysis) - -; Unary Ops -(rule ( - (= lhs (Uop (Not) e)) - (HasType e (Base (BoolT))) - ) - ((HasType lhs (Base (BoolT)))) - :ruleset type-analysis) -(rule ((= lhs (Uop (Not) e))) - ((ExpectType e (Base (BoolT)) "(Not)")) - :ruleset type-analysis) - - -(rule ( - (= lhs (Bop (Print) e state)) - (HasType e _ty) ; just make sure it has some type. - ) - ((HasType lhs (Base (StateT)))) - :ruleset type-analysis) - -(rule ( - (= lhs (Bop (Print) e state)) - (HasType e (TupleT ty)) - ) - ((panic "Don't print a tuple")) - :ruleset error-checking) - -(rule ((= lhs (Bop (Free) e s)) - (HasType e (Base (PointerT _ty)))) - ((HasType lhs (Base (StateT)))) - :ruleset type-analysis) -(rule ((= lhs (Bop (Free) e s)) - (HasType e (Base (IntT)))) - ((panic "Free expected pointer, received integer")) - :ruleset error-checking) -(rule ((= lhs (Bop (Free) e s)) - (HasType e (TupleT _ty))) - ((panic "Free expected pointer, received tuple")) - :ruleset error-checking) - -(rule ( - (= lhs (Bop (Load) e state)) - (HasType e (Base (PointerT ty))) - ) - ((HasType lhs (TupleT (TCons ty (TCons (StateT) (TNil)))))) - :ruleset type-analysis) -(rule ( - (= lhs (Bop (Load) e state)) - (HasType e ty) - (= ty (Base (IntT))) - ) - ((panic "(Load) expected pointer, received int")) - :ruleset error-checking) -(rule ( - (= lhs (Bop (Load) e state)) - (HasType e ty) - (= ty (TupleT x)) - ) - ((panic "(Load) expected pointer, received tuple")) - :ruleset error-checking) - -; Binary ops - -;; Operators that have type Type -> Type -> Type -;; Note we only do this generic matching for binary -;; operator since there's a lot of them. -;; In the future we can also extend to other constructs. -(relation bop-of-type (BinaryOp Type)) -(bop-of-type (Add) (Base (IntT))) -(bop-of-type (Sub) (Base (IntT))) -(bop-of-type (Div) (Base (IntT))) -(bop-of-type (Mul) (Base (IntT))) -(bop-of-type (FAdd) (Base (FloatT))) -(bop-of-type (FSub) (Base (FloatT))) -(bop-of-type (FDiv) (Base (FloatT))) -(bop-of-type (FMul) (Base (FloatT))) - -(rule ( - (= lhs (Bop op e1 e2)) - (bop-of-type op ty) - (HasType e1 ty) - (HasType e2 ty) - ) - ((HasType lhs ty)) - :ruleset type-analysis) -(rule ((= lhs (Bop op e1 e2)) - (bop-of-type op ty) - (bop->string op op-str)) - ( - (ExpectType e1 ty op-str) - (ExpectType e2 ty op-str) - ) - :ruleset type-analysis) - -;; Operators that have type Float -> Float -> Bool -(relation bpred-of-type (BinaryOp Type)) -(bpred-of-type (FLessThan) (Base (FloatT))) -(bpred-of-type (FLessEq) (Base (FloatT))) -(bpred-of-type (FGreaterThan) (Base (FloatT))) -(bpred-of-type (FGreaterEq) (Base (FloatT))) -(bpred-of-type (FEq) (Base (FloatT))) -(bpred-of-type (LessThan) (Base (IntT))) -(bpred-of-type (LessEq) (Base (IntT))) -(bpred-of-type (GreaterThan) (Base (IntT))) -(bpred-of-type (GreaterEq) (Base (IntT))) -(bpred-of-type (Eq) (Base (IntT))) -(bpred-of-type (And) (Base (BoolT))) -(bpred-of-type (Or) (Base (BoolT))) - -(rule ( - (= lhs (Bop pred e1 e2)) - (bpred-of-type pred ty) - (HasType e1 ty) - (HasType e2 ty) - ) - ((HasType lhs (Base (BoolT)))) - :ruleset type-analysis) -(rule ((= lhs (Bop pred e1 e2)) - (bpred-of-type pred ty) - (bop->string pred pred-str)) - ( - (ExpectType e1 ty pred-str) - (ExpectType e2 ty pred-str) - ) - :ruleset type-analysis) - -(rule ( - (= lhs (Top (Write) ptr val state)) - (HasType ptr (Base (PointerT ty))) - (HasType val (Base t)) ; TODO need to support pointers to pointers - ) - ((HasType lhs (Base (StateT)))) ; Write returns () - :ruleset type-analysis) - -(rule ( - (= lhs (Top (Write) ptr val state)) - (HasType ptr (Base (PointerT ty)))) - ((ExpectType val (Base ty) "(Write)")) - :ruleset type-analysis) - - - -(rule ( - (= lhs (Bop (PtrAdd) ptr n)) - (HasType ptr (Base (PointerT ty))) - (HasType n (Base (IntT))) - ) - ((HasType lhs (Base (PointerT ty)))) - :ruleset type-analysis) - -; Other ops -(rule ((= lhs (Alloc _id amt state ty))) - ((ExpectType amt (Base (IntT)) "(Alloc)")) - :ruleset type-analysis) - -(rule ( - (= lhs (Alloc _id amt state ty)) - (HasType amt (Base (IntT))) - ) - ((HasType lhs (TupleT (TCons ty (TCons (StateT) (TNil)))))) - :ruleset type-analysis) - -(rule ( - (= lhs (Get e i)) - (HasType e (TupleT tylist)) - ) - ; TypeList-ith needs to compute immediately, so we need to saturate type-helpers - ; rules between every iter of type-analysis rules. - ((HasType lhs (Base (TypeList-ith tylist i)))) - :ruleset type-analysis) - -(rule ( - (HasType (Get expr i) (TupleT tl)) - (= (TypeList-length tl) len) - (>= i len)) - ((panic "index out of bounds")) - :ruleset error-checking) -(rule ( - (HasType (Get expr i) (TupleT tl)) - (= (TypeList-length tl) len) - (< i 0) - ) - ((panic "negative index")) - :ruleset error-checking) - -; ================================= -; Tuple operations -; ================================= - -(rule ( - (= lhs (Single e)) - (HasType e (TupleT tylist)) - ) - ((panic "don't nest tuples")) - :ruleset error-checking) - -(rule ( - (= lhs (Single e)) - (HasType e (Base basety)) - ) - ((HasType lhs (TupleT (TCons basety (TNil))))) - :ruleset type-analysis) - -(rule ( - (= lhs (Concat e1 e2)) - (HasType e1 (TupleT tylist1)) - (HasType e2 (TupleT tylist2)) - ) - ; TLConcat needs to compute immediately, so we need to saturate type-helpers - ; rules between every iter of type-analysis rules. - ((HasType lhs (TupleT (TLConcat tylist1 tylist2)))) - :ruleset type-analysis) - -; ================================= -; Control flow -; ================================= -(rule ((= lhs (If pred inputs then else))) - ((ExpectType pred (Base (BoolT)) "If predicate must be boolean")) - :ruleset type-analysis) -(rule ( - (= lhs (If pred inputs then else)) - (HasType pred (Base (BoolT))) - (HasType then ty) - (HasType else ty) - ) - ((HasType lhs ty)) - :ruleset type-analysis) - -(rule ( - (= lhs (If pred inputs then else)) - (HasType pred (Base (BoolT))) - (HasType then tya) - (HasType else tyb) - (!= tya tyb) - ) - ((panic "if branches had different types")) - :ruleset error-checking) - - - -(rule ((= lhs (Switch pred inputs branches))) - ((ExpectType pred (Base (IntT)) "Switch predicate must be integer")) - :ruleset type-analysis) - -; base case: single branch switch has type of branch -(rule ( - (= lhs (Switch pred inputs (Cons branch (Nil)))) - (HasType pred (Base (IntT))) - (HasType branch ty) - ) - ((HasType lhs ty)) - :ruleset type-analysis) - -; recursive case: peel off a layer -(rule ((Switch pred inputs (Cons branch rest))) - ((Switch pred inputs rest)) - :ruleset type-analysis) - -(rule ( - (= lhs (Switch pred inputs (Cons branch rest))) - (HasType pred (Base (IntT))) - (HasType branch ty) - (HasType (Switch pred inputs rest) ty) ; rest of the branches also have type ty - ) - ((HasType lhs ty)) - :ruleset type-analysis) - -(rule ( - (= lhs (Switch pred inputs (Cons branch rest))) - (HasType pred (Base (IntT))) - (HasType branch tya) - (HasType (Switch pred inputs rest) tyb) - (!= tya tyb) - ) - ((panic "switch branches had different types")) - :ruleset error-checking) - -(rule ((Arg ty ctx)) - ( - (HasType (Arg ty ctx) ty) - (HasArgType (Arg ty ctx) ty) - ) - :ruleset type-analysis) - - -(rule ( - (= lhs (DoWhile inp pred-body)) - (HasType inp (Base ty)) - ) - ((panic "loop input must be tuple")) - :ruleset error-checking) -(rule ( - (= lhs (DoWhile inp pred-body)) - (HasType inp (Base (PointerT ty))) - ) - ((panic "loop input must be tuple")) - :ruleset error-checking) -(rule ( - (= lhs (DoWhile inp pred-body)) - (HasType pred-body (Base ty)) - ) - ((panic "loop pred-body must be tuple")) - :ruleset error-checking) -(rule ( - (= lhs (DoWhile inp pred-body)) - (HasType pred-body (Base (PointerT ty))) - ) - ((panic "loop pred-body must be tuple")) - :ruleset error-checking) - -(rule ( - (= lhs (DoWhile inp pred-body)) - (HasType inp (TupleT tylist)) - ) - ((HasArgType pred-body (TupleT tylist))) - :ruleset type-analysis) - -(rule ((= lhs (DoWhile inp pred-body))) - ((ExpectType (Get pred-body 0) (Base (BoolT)) "loop pred must be bool")) - :ruleset type-analysis) - -(rule ( - (= lhs (DoWhile inp pred-body)) - (HasType inp (TupleT tylist)) ; input is a tuple - ; pred-body is a tuple where the first elt is a bool - ; and the rest of the list matches the input type - (HasType pred-body (TupleT (TCons (BoolT) tylist))) - ) - ((HasType lhs (TupleT tylist))) ; whole thing has type of inputs/outputs - :ruleset type-analysis) - -(rule ( - (= lhs (DoWhile inp pred-body)) - (HasType inp (TupleT in-tys)) - (HasType pred-body (TupleT (TCons (BoolT) out-tys))) - (!= in-tys out-tys) - ) - ((panic "input types and output types don't match")) - :ruleset error-checking) - -; ================================= -; Functions -; ================================= - -(rule ((= lhs (Function name in-ty out-ty body))) - ( - ; Arg should have the specified type in the body - (HasArgType body in-ty) - ; Expect the body to have the specified output type - (ExpectType body out-ty "Function body had wrong type") - ) - :ruleset type-analysis) - -(rule ( - (= lhs (Call name arg)) - (Function name in-ty out-ty body) - ) - ; Expect the arg to have the right type for the function - ((ExpectType arg in-ty "function called with wrong arg type")) - :ruleset type-analysis) - -(rule ( - (= lhs (Call name arg)) - (Function name in-ty out-ty body) - (HasType arg in-ty) - ; We don't need to check the type of the function body, it will - ; be checked elsewhere. If we did require (HasType body out-ty), - ; recursive functions would not get assigned a type. - ) - ((HasType lhs out-ty)) - :ruleset type-analysis) - -; find which types are pure -(relation PureBaseType (BaseType)) -(relation PureType (Type)) -(relation PureTypeList (TypeList)) - -(PureBaseType (IntT)) -(PureBaseType (BoolT)) -(rule ((Base ty) - (PureBaseType ty)) - ((PureType (Base ty))) - :ruleset type-analysis) -(rule ((TupleT tylist) - (PureTypeList tylist)) - ((PureType (TupleT tylist))) - :ruleset type-analysis) -(rule ((TNil)) - ((PureTypeList (TNil))) - :ruleset type-analysis) -(rule ((TCons hd tl) - (PureBaseType hd) - (PureTypeList tl)) - ((PureTypeList (TCons hd tl))) - :ruleset type-analysis) - -(function ListExpr-length (ListExpr) i64) -(function ListExpr-ith (ListExpr i64) Expr :unextractable) -(function ListExpr-suffix (ListExpr i64) ListExpr :unextractable) -(function Append (ListExpr Expr) ListExpr :unextractable) - -(rule ((Switch pred inputs branch)) ((union (ListExpr-suffix branch 0) branch)) :ruleset always-run) - -(rule ((= (ListExpr-suffix top n) (Cons hd tl))) - ((union (ListExpr-ith top n) hd) - (union (ListExpr-suffix top (+ n 1)) tl)) :ruleset always-run) - -(rule ((= (ListExpr-suffix list n) (Nil))) - ((set (ListExpr-length list) n)) :ruleset always-run) - -(rewrite (Append (Cons a b) e) - (Cons a (Append b e)) - :ruleset always-run) -(rewrite (Append (Nil) e) - (Cons e (Nil)) - :ruleset always-run) - -(function tuple-length (Expr) i64 :unextractable) - -(rule ((HasType expr (TupleT tl)) - (= len (TypeList-length tl))) - ((set (tuple-length expr) len)) :ruleset always-run) - -;; Create a Get for every index, and rewrite it to see through Concat -(rule ((Single expr)) ((union (Get (Single expr) 0) expr)) :ruleset always-run) -;; initial get -(rule ((> (tuple-length tuple) 0)) - ((Get tuple 0)) - :ruleset always-run) -;; next get -(rule ((= len (tuple-length tuple)) - (= ith (Get tuple i)) - (< (+ i 1) len) - ) - ((Get tuple (+ 1 i))) - :ruleset always-run) - -;; descend left -(rule ((Get (Concat expr1 expr2) i) - (= (tuple-length expr1) len1) - (< i len1)) - ((union (Get (Concat expr1 expr2) i) - (Get expr1 i))) - :ruleset always-run) -;; descend right -(rule ((Get (Concat expr1 expr2) i) - (= (tuple-length expr1) len1) - (>= i len1)) - ((union (Get (Concat expr1 expr2) i) - (Get expr2 (- i len1)))) - :ruleset always-run) - - -;; A temporary context. -;; Be sure to delete at the end of all actions or else!!! -;; This is safer than using a persistant context, since we may miss an important part of the query. -(function TmpCtx () Assumption) - -(rule ((TmpCtx)) - ((panic "TmpCtx should not exist outside rule body")) - :ruleset always-run) - -(relation ExprIsValid (Expr)) -(relation ListExprIsValid (ListExpr)) -(rule ((ExprIsValid (Function _name _tyin _tyout _out))) ((ExprIsValid _out)) :ruleset always-run) -(rule ((ExprIsValid (Top _op _x _y _z))) ((ExprIsValid _x) -(ExprIsValid _y) -(ExprIsValid _z)) :ruleset always-run) -(rule ((ExprIsValid (Bop _op _x _y))) ((ExprIsValid _x) -(ExprIsValid _y)) :ruleset always-run) -(rule ((ExprIsValid (Uop _op _x))) ((ExprIsValid _x)) :ruleset always-run) -(rule ((ExprIsValid (Get _tup _i))) ((ExprIsValid _tup)) :ruleset always-run) -(rule ((ExprIsValid (Concat _x _y))) ((ExprIsValid _x) -(ExprIsValid _y)) :ruleset always-run) -(rule ((ExprIsValid (Single _x))) ((ExprIsValid _x)) :ruleset always-run) -(rule ((ExprIsValid (Switch _pred _inputs _branches))) ((ExprIsValid _pred) -(ExprIsValid _inputs) -(ListExprIsValid _branches)) :ruleset always-run) -(rule ((ExprIsValid (If _pred _input _then _else))) ((ExprIsValid _pred) -(ExprIsValid _input) -(ExprIsValid _then) -(ExprIsValid _else)) :ruleset always-run) -(rule ((ExprIsValid (DoWhile _in _pred-and-output))) ((ExprIsValid _in) -(ExprIsValid _pred-and-output)) :ruleset always-run) -(rule ((ExprIsValid (Call _func _arg))) ((ExprIsValid _arg)) :ruleset always-run) -(rule ((ListExprIsValid (Cons _hd _tl))) ((ExprIsValid _hd) -(ListExprIsValid _tl)) :ruleset always-run) -(rule ((ExprIsValid (Alloc _id _e _state _ty))) ((ExprIsValid _e) -(ExprIsValid _state)) :ruleset always-run) -(relation ExprIsResolved (Expr)) -(relation ListExprIsResolved (ListExpr)) -(rule ((= lhs (Function _name _tyin _tyout _out)) (ExprIsResolved _out)) ((ExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (Const _n _ty _ctx)) ) ((ExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (Top _op _x _y _z)) (ExprIsResolved _x) -(ExprIsResolved _y) -(ExprIsResolved _z)) ((ExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (Bop _op _x _y)) (ExprIsResolved _x) -(ExprIsResolved _y)) ((ExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (Uop _op _x)) (ExprIsResolved _x)) ((ExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (Get _tup _i)) (ExprIsResolved _tup)) ((ExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (Concat _x _y)) (ExprIsResolved _x) -(ExprIsResolved _y)) ((ExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (Single _x)) (ExprIsResolved _x)) ((ExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (Switch _pred _inputs _branches)) (ExprIsResolved _pred) -(ExprIsResolved _inputs) -(ListExprIsResolved _branches)) ((ExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (If _pred _input _then _else)) (ExprIsResolved _pred) -(ExprIsResolved _input) -(ExprIsResolved _then) -(ExprIsResolved _else)) ((ExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (DoWhile _in _pred-and-output)) (ExprIsResolved _in) -(ExprIsResolved _pred-and-output)) ((ExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (Arg _ty _ctx)) ) ((ExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (Call _func _arg)) (ExprIsResolved _arg)) ((ExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (Empty _ty _ctx)) ) ((ExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (Cons _hd _tl)) (ExprIsResolved _hd) -(ListExprIsResolved _tl)) ((ListExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (Nil)) ) ((ListExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (Alloc _id _e _state _ty)) (ExprIsResolved _e) -(ExprIsResolved _state)) ((ExprIsResolved lhs)) :ruleset always-run) -(relation BodyContainsExpr (Expr Expr)) -(relation BodyContainsListExpr (Expr ListExpr)) -(rule ((Function _name _tyin _tyout _out)) ((BodyContainsExpr (Function _name _tyin _tyout _out) _out)) :ruleset always-run) -(rule ((If _pred _input _then _else)) ((BodyContainsExpr (If _pred _input _then _else) _then) (BodyContainsExpr (If _pred _input _then _else) _else)) :ruleset always-run) -(rule ((DoWhile _in _pred-and-output)) ((BodyContainsExpr (DoWhile _in _pred-and-output) _pred-and-output)) :ruleset always-run) -(rule ((BodyContainsExpr body (Top _op _x _y _z))) ((BodyContainsExpr body _x) (BodyContainsExpr body _y) (BodyContainsExpr body _z)) :ruleset always-run) -(rule ((BodyContainsExpr body (Bop _op _x _y))) ((BodyContainsExpr body _x) (BodyContainsExpr body _y)) :ruleset always-run) -(rule ((BodyContainsExpr body (Uop _op _x))) ((BodyContainsExpr body _x)) :ruleset always-run) -(rule ((BodyContainsExpr body (Get _tup _i))) ((BodyContainsExpr body _tup)) :ruleset always-run) -(rule ((BodyContainsExpr body (Concat _x _y))) ((BodyContainsExpr body _x) (BodyContainsExpr body _y)) :ruleset always-run) -(rule ((BodyContainsExpr body (Single _x))) ((BodyContainsExpr body _x)) :ruleset always-run) -(rule ((BodyContainsExpr body (Switch _pred _inputs _branches))) ((BodyContainsExpr body _pred) (BodyContainsExpr body _inputs)) :ruleset always-run) -(rule ((BodyContainsExpr body (If _pred _input _then _else))) ((BodyContainsExpr body _pred) (BodyContainsExpr body _input)) :ruleset always-run) -(rule ((BodyContainsExpr body (DoWhile _in _pred-and-output))) ((BodyContainsExpr body _in)) :ruleset always-run) -(rule ((BodyContainsExpr body (Call _func _arg))) ((BodyContainsExpr body _arg)) :ruleset always-run) -(rule ((BodyContainsListExpr body (Cons _hd _tl))) ((BodyContainsExpr body _hd)) :ruleset always-run) -(rule ((BodyContainsExpr body (Alloc _id _e _state _ty))) ((BodyContainsExpr body _e) (BodyContainsExpr body _state)) :ruleset always-run) - - (relation ExprIsPure (Expr)) - (relation ListExprIsPure (ListExpr)) - (relation BinaryOpIsPure (BinaryOp)) - (relation UnaryOpIsPure (UnaryOp)) - (relation TopIsPure (TernaryOp)) -(TopIsPure (Select)) -(BinaryOpIsPure (Add)) -(BinaryOpIsPure (Sub)) -(BinaryOpIsPure (Mul)) -(BinaryOpIsPure (Div)) -(BinaryOpIsPure (Eq)) -(BinaryOpIsPure (LessThan)) -(BinaryOpIsPure (GreaterThan)) -(BinaryOpIsPure (LessEq)) -(BinaryOpIsPure (GreaterEq)) -(BinaryOpIsPure (FAdd)) -(BinaryOpIsPure (FSub)) -(BinaryOpIsPure (FMul)) -(BinaryOpIsPure (FDiv)) -(BinaryOpIsPure (FEq)) -(BinaryOpIsPure (FLessThan)) -(BinaryOpIsPure (FGreaterThan)) -(BinaryOpIsPure (FLessEq)) -(BinaryOpIsPure (FGreaterEq)) -(BinaryOpIsPure (And)) -(BinaryOpIsPure (Or)) -(BinaryOpIsPure (PtrAdd)) -(UnaryOpIsPure (Not)) - - (rule ((Function _name _tyin _tyout _out) (ExprIsPure _out)) - ((ExprIsPure (Function _name _tyin _tyout _out))) - :ruleset always-run) - - (rule ((Const _n _ty _ctx)) - ((ExprIsPure (Const _n _ty _ctx))) - :ruleset always-run) - - (rule ((Top _op _x _y _z) (ExprIsPure _x) (ExprIsPure _y) (ExprIsPure _z)) - ((ExprIsPure (Top _op _x _y _z))) - :ruleset always-run) - - (rule ((Bop _op _x _y) (BinaryOpIsPure _op) (ExprIsPure _x) (ExprIsPure _y)) - ((ExprIsPure (Bop _op _x _y))) - :ruleset always-run) - - (rule ((Uop _op _x) (UnaryOpIsPure _op) (ExprIsPure _x)) - ((ExprIsPure (Uop _op _x))) - :ruleset always-run) - - (rule ((Get _tup _i) (ExprIsPure _tup)) - ((ExprIsPure (Get _tup _i))) - :ruleset always-run) - - (rule ((Concat _x _y) (ExprIsPure _x) (ExprIsPure _y)) - ((ExprIsPure (Concat _x _y))) - :ruleset always-run) - - (rule ((Single _x) (ExprIsPure _x)) - ((ExprIsPure (Single _x))) - :ruleset always-run) - - (rule ((Switch _pred _inputs _branches) (ExprIsPure _pred) (ExprIsPure _inputs) (ListExprIsPure _branches)) - ((ExprIsPure (Switch _pred _inputs _branches))) - :ruleset always-run) - - (rule ((If _pred _input _then _else) (ExprIsPure _pred) (ExprIsPure _input) (ExprIsPure _then) (ExprIsPure _else)) - ((ExprIsPure (If _pred _input _then _else))) - :ruleset always-run) - - (rule ((DoWhile _in _pred-and-output) (ExprIsPure _in) (ExprIsPure _pred-and-output)) - ((ExprIsPure (DoWhile _in _pred-and-output))) - :ruleset always-run) - - (rule ((Arg _ty _ctx)) - ((ExprIsPure (Arg _ty _ctx))) - :ruleset always-run) - - (rule ((Call _f _arg) (ExprIsPure _arg) (ExprIsPure (Function _f inty outty out))) - ((ExprIsPure (Call _f _arg))) - :ruleset always-run) - - (rule ((Empty _ty _ctx)) - ((ExprIsPure (Empty _ty _ctx))) - :ruleset always-run) - - (rule ((Cons _hd _tl) (ExprIsPure _hd) (ListExprIsPure _tl)) - ((ListExprIsPure (Cons _hd _tl))) - :ruleset always-run) - - (rule ((Nil)) - ((ListExprIsPure (Nil))) - :ruleset always-run) - -; This file provides AddContext, a helpers that copies a sub-egraph into -; a new one with a new context. -; Users of AddContext can specify how deeply to do this copy. - - -(ruleset context) - -(function AddContext (Assumption Expr) Expr :unextractable) -(function AddContextList (Assumption ListExpr) ListExpr :unextractable) - -;; ################################ saturation - -;; Adding context a second time does nothing, so union -(rule - ((= lhs (AddContext ctx inner)) - (= inner (AddContext ctx expr))) - ((union lhs inner)) - :ruleset context) - - -;; ############################## Base cases- leaf nodes - -;; replace existing contexts that are around leaf nodes -;; AddContext assumes the new context is more specific than the old one -(rule ((= lhs (AddContext ctx (Arg ty oldctx)))) - ((union lhs (Arg ty ctx))) - :ruleset context) -(rule ((= lhs (AddContext ctx (Const c ty oldctx)))) - ((union lhs (Const c ty ctx))) - :ruleset context) -(rule ((= lhs (AddContext ctx (Empty ty oldctx)))) - ((union lhs (Empty ty ctx))) - :ruleset context) - - - - -;; ######################################### Operators -(rewrite (AddContext ctx (Bop op c1 c2)) - (Bop op - (AddContext ctx c1) - (AddContext ctx c2)) - :ruleset context) -(rewrite (AddContext ctx (Uop op c1)) - (Uop op (AddContext ctx c1)) - :ruleset context) -(rewrite (AddContext ctx (Get c1 index)) - (Get (AddContext ctx c1) index) - :ruleset context) -(rewrite (AddContext ctx (Alloc id c1 state ty)) - (Alloc id (AddContext ctx c1) (AddContext ctx state) ty) - :ruleset context) -(rewrite (AddContext ctx (Call name c1)) - (Call name (AddContext ctx c1)) - :ruleset context) - -(rewrite (AddContext ctx (Single c1)) - (Single (AddContext ctx c1)) - :ruleset context) -(rewrite (AddContext ctx (Concat c1 c2)) - (Concat - (AddContext ctx c1) - (AddContext ctx c2)) - :ruleset context) - -;; ################################### List operators - -(rewrite (AddContextList ctx (Nil)) - (Nil) - :ruleset context) - -(rewrite (AddContextList ctx (Cons c1 rest)) - (Cons (AddContext ctx c1) - (AddContextList ctx rest)) - :ruleset context) - - -;; ########################################## Control flow -(rewrite (AddContext ctx (Switch pred inputs branches)) - (Switch (AddContext ctx pred) - (AddContext ctx inputs) - branches) - :ruleset context) - -;; For stop at region, still add context to inputs -(rule ((= lhs (AddContext ctx (If pred inputs c1 c2)))) - ((union lhs - (If (AddContext ctx pred) - (AddContext ctx inputs) - c1 - c2))) - :ruleset context) - - -;; For stop at loop, still add context to inputs -(rule ((= lhs (AddContext ctx (DoWhile inputs outputs)))) - ((union lhs - (DoWhile - (AddContext ctx inputs) - outputs))) - :ruleset context) - - -;; Substitution rules allow for substituting some new expression for the argument -;; in some new context. -;; It performs the substitution, copying over the equalities from the original eclass. -;; It only places context on the leaf nodes. - -(ruleset subst) -(ruleset apply-subst-unions) -(ruleset cleanup-subst) - -;; (Subst assumption to in) substitutes `to` for `(Arg ty)` in `in`. -;; It also replaces the leaf context in `to` with `assumption` using `AddContext`. -;; `assumption` *justifies* this substitution, as the context that the result is used in. -;; In other words, it must refine the equivalence relation of `in` with `to` as the argument. -(function Subst (Assumption Expr Expr) Expr :unextractable) - -;; Used to delay unions for the subst ruleset. -;; This is necessary because substitution may not terminate if it can -;; observe its own results- it may create infinitly large terms. -;; Instead, we phase substitution by delaying resulting unions in this table. -;; After applying this table, substitutions and this table are cleared. -(function DelayedSubstUnion (Expr Expr) Expr :unextractable) - -;; add a type rule to get the arg type of a substitution -;; this enables nested substitutions -(rule ((= lhs (Subst assum to in)) - (HasArgType to ty)) - ((HasArgType lhs ty)) - :ruleset subst) - -;; leaf node with context -;; replace this context- subst assumes the context is more specific -(rule ((= lhs (Subst assum to (Arg ty oldctx))) - ) - ;; add the assumption `to` - ((DelayedSubstUnion lhs (AddContext assum to))) - :ruleset subst) -(rule ((= lhs (Subst assum to (Const c ty oldctx))) - (HasArgType to newty)) - ((DelayedSubstUnion lhs (Const c newty assum))) - :ruleset subst) -(rule ((= lhs (Subst assum to (Empty ty oldctx))) - (HasArgType to newty)) - ((DelayedSubstUnion lhs (Empty newty assum))) - :ruleset subst) - -;; Operators -(rule ((= lhs (Subst assum to (Bop op c1 c2))) - (ExprIsResolved (Bop op c1 c2))) - ((DelayedSubstUnion lhs - (Bop op (Subst assum to c1) - (Subst assum to c2)))) - :ruleset subst) -(rule ((= lhs (Subst assum to (Uop op c1))) - (ExprIsResolved (Uop op c1))) - ((DelayedSubstUnion lhs - (Uop op (Subst assum to c1)))) - :ruleset subst) - -(rule ((= lhs (Subst assum to (Get c1 index))) - (ExprIsResolved (Get c1 index))) - ((DelayedSubstUnion lhs - (Get (Subst assum to c1) index))) - :ruleset subst) -(rule ((= lhs (Subst assum to (Alloc id c1 c2 ty))) - (ExprIsResolved (Alloc id c1 c2 ty))) - ((DelayedSubstUnion lhs - (Alloc id (Subst assum to c1) - (Subst assum to c2) - ty))) - :ruleset subst) -(rule ((= lhs (Subst assum to (Call name c1))) - (ExprIsResolved (Call name c1))) - ((DelayedSubstUnion lhs - (Call name (Subst assum to c1)))) - :ruleset subst) - - -;; Tuple operators -(rule ((= lhs (Subst assum to (Single c1))) - (ExprIsResolved (Single c1))) - ((DelayedSubstUnion lhs - (Single (Subst assum to c1)))) - :ruleset subst) -(rule ((= lhs (Subst assum to (Concat c1 c2))) - (ExprIsResolved (Concat c1 c2))) - ((DelayedSubstUnion lhs - (Concat (Subst assum to c1) - (Subst assum to c2)))) - :ruleset subst) - -;; Control flow -(rule ((= lhs (Subst assum to inner)) - (= inner (Switch pred inputs c1)) - (ExprIsResolved inner)) - ((DelayedSubstUnion lhs - (Switch (Subst assum to pred) - (Subst assum to inputs) - c1))) - :ruleset subst) -(rule ((= lhs (Subst assum to inner)) - (= inner (If pred inputs c1 c2)) - (ExprIsResolved inner)) - ((DelayedSubstUnion lhs - (If (Subst assum to pred) - (Subst assum to inputs) - c1 - c2))) - :ruleset subst) -(rule ((= lhs (Subst assum to (DoWhile in out))) - (ExprIsResolved (DoWhile in out))) - ((DelayedSubstUnion lhs - (DoWhile (Subst assum to in) - out))) - :ruleset subst) - -;; substitute into function (convenience for testing) -(rewrite (Subst assum to (Function name inty outty body)) - (Function name inty outty (Subst assum to body)) - :when ((ExprIsResolved body)) - :ruleset subst) - - - -;; ########################### Apply subst unions - -(rule ((DelayedSubstUnion lhs rhs)) - ((union lhs rhs)) - :ruleset apply-subst-unions) - - -;; ########################### Cleanup subst and DelayedSubstUnion - -(rule ((DelayedSubstUnion lhs rhs)) - ((subsume (DelayedSubstUnion lhs rhs))) - :ruleset cleanup-subst) - -; this cleanup is important- if we don't subsume these substitutions, they -; may oberve their own results and create infinitely sized terms. -; ex: get(parallel!(arg(), int(2)), 0) ignores the first element of the tuple -; so it's equivalent to infinite other times with any other value as the first element of the tuple. -; Check ExprIsResolved to confirm that the substitution finished (all sub-substitutions are done). -(rule ((ExprIsResolved (Subst assum to in))) - ((subsume (Subst assum to in))) - :ruleset cleanup-subst) - -; We only have context for Exprs, not ListExprs. -(relation ContextOf (Expr Assumption)) - -(rule ((Arg ty ctx)) - ((ContextOf (Arg ty ctx) ctx)) - :ruleset always-run) -(rule ((Const c ty ctx)) - ((ContextOf (Const c ty ctx) ctx)) - :ruleset always-run) -(rule ((Empty ty ctx)) - ((ContextOf (Empty ty ctx) ctx)) - :ruleset always-run) - -; Error checking - each expr should only have a single context -(rule ((ContextOf x ctx1) - (ContextOf x ctx2) - (!= ctx1 ctx2)) - ( - (panic "Equivalent expressions have nonequivalent context, breaking the single context invariant.") - ) - :ruleset error-checking) - - -(rule ((Top op x y z) (ContextOf x ctx)) - ((ContextOf (Top op x y z) ctx)) :ruleset always-run) - -(rule ((Top op x y z) (ContextOf y ctx)) - ((ContextOf (Top op x y z) ctx)) :ruleset always-run) - -(rule ((Top op x y z) (ContextOf z ctx)) - ((ContextOf (Top op x y z) ctx)) :ruleset always-run) - -(rule ((Bop op x y) (ContextOf x ctx)) - ((ContextOf (Bop op x y) ctx)) :ruleset always-run) - -(rule ((Bop op x y) (ContextOf y ctx)) - ((ContextOf (Bop op x y) ctx)) :ruleset always-run) - -(rule ((Uop op x) (ContextOf x ctx)) - ((ContextOf (Uop op x) ctx)) :ruleset always-run) - -(rule ((Get tup i) (ContextOf tup ctx)) - ((ContextOf (Get tup i) ctx)) :ruleset always-run) - -(rule ((Concat x y) (ContextOf x ctx)) - ((ContextOf (Concat x y) ctx)) :ruleset always-run) - -(rule ((Concat x y) (ContextOf y ctx)) - ((ContextOf (Concat x y) ctx)) :ruleset always-run) - -(rule ((Single x) (ContextOf x ctx)) - ((ContextOf (Single x) ctx)) :ruleset always-run) - -(rule ((Switch pred inputs branches) (ContextOf pred ctx)) - ((ContextOf (Switch pred inputs branches) ctx)) :ruleset always-run) - -(rule ((If pred inputs then else) (ContextOf pred ctx)) - ((ContextOf (If pred inputs then else) ctx)) :ruleset always-run) - -(rule ((If pred inputs then else) (ContextOf inputs ctx)) - ((ContextOf (If pred inputs then else) ctx)) :ruleset always-run) - -(rule ((DoWhile in pred-and-output) (ContextOf in ctx)) - ((ContextOf (DoWhile in pred-and-output) ctx)) :ruleset always-run) - -(rule ((Call func arg) (ContextOf arg ctx)) - ((ContextOf (Call func arg) ctx)) :ruleset always-run) - -(rule ((Alloc amt e state ty) (ContextOf e ctx)) - ((ContextOf (Alloc amt e state ty) ctx)) :ruleset always-run) - -(rule ((Alloc amt e state ty) (ContextOf state ctx)) - ((ContextOf (Alloc amt e state ty) ctx)) :ruleset always-run) - -(ruleset canon) - -; Commutativity -(rewrite (Bop (Add) x y) (Bop (Add) y x) :ruleset canon) -(rewrite (Bop (Mul) x y) (Bop (Mul) y x) :ruleset canon) -(rewrite (Bop (Eq) x y) (Bop (Eq) y x) :ruleset canon) -(rewrite (Bop (And) x y) (Bop (And) y x) :ruleset canon) -(rewrite (Bop (Or) x y) (Bop (Or) y x) :ruleset canon) - -; Canonicalize to < -; x > y ==> y < x -(rewrite (Bop (GreaterThan) x y) (Bop (LessThan) y x) :ruleset canon) - -; x >= y ==> y < x + 1 -; x >= y ==> y - 1 < x -(rule ( - (= lhs (Bop (GreaterEq) x y)) - (HasArgType x ty) - (ContextOf lhs ctx) - ) - ( - (union lhs (Bop (LessThan) y (Bop (Add) x (Const (Int 1) ty ctx)))) - (union lhs (Bop (LessThan) (Bop (Sub) y (Const (Int 1) ty ctx)) x)) - ) - :ruleset canon) - -; x <= y ==> x < y + 1 -; x <= y ==> x - 1 < y -(rule ( - (= lhs (Bop (LessEq) x y)) - (HasArgType y ty) - (ContextOf lhs ctx) - ) - ( - (union lhs (Bop (LessThan) x (Bop (Add) y (Const (Int 1) ty ctx)))) - (union lhs (Bop (LessThan) (Bop (Sub) x (Const (Int 1) ty ctx)) y)) - ) - :ruleset canon) - - -; Make Concats right-deep -(rewrite (Concat (Concat a b) c) - (Concat a (Concat b c)) - :ruleset always-run) -; Simplify Concat's with empty -(rewrite (Concat (Empty ty ctx) x) - x - :ruleset always-run) -(rewrite (Concat x (Empty ty ctx)) - x - :ruleset always-run) - -; Make a tuple that is a sub-range of another tuple -; tuple start len -(function SubTuple (Expr i64 i64) Expr :unextractable) - -(rewrite (SubTuple expr x 0) - (Empty ty ctx) - :when ((HasArgType expr ty) (ContextOf expr ctx)) - :ruleset always-run) - -(rewrite (SubTuple expr x 1) - (Single (Get expr x)) - :ruleset always-run) - -(rewrite (SubTuple expr a b) - (Concat (Single (Get expr a)) (SubTuple expr (+ a 1) (- b 1))) - :when ((> b 1)) - :ruleset always-run) - -; Helper functions to remove one element from a tuple or type list -; tuple idx -(function TupleRemoveAt (Expr i64) Expr :unextractable) -(function TypeListRemoveAt (TypeList i64) TypeList :unextractable) - -(rewrite (TupleRemoveAt tuple idx) - (Concat (SubTuple tuple 0 idx) - (SubTuple tuple (+ idx 1) (- len (+ idx 1)))) - :when ((= len (tuple-length tuple))) - :ruleset always-run) - -(rewrite (TypeListRemoveAt (TNil) _idx) (TNil) :ruleset always-run) -(rewrite (TypeListRemoveAt (TCons x xs) 0 ) xs :ruleset always-run) -(rewrite (TypeListRemoveAt (TCons x xs) idx) - (TCons x (TypeListRemoveAt xs (- idx 1))) - :when ((> idx 0)) - :ruleset always-run) - -;; Compute the tree size of program, not dag size -(function Expr-size (Expr) i64 :unextractable :merge (min old new) ) -(function ListExpr-size (ListExpr) i64 :unextractable :merge (min old new)) - -(rule ((= expr (Function name tyin tyout out)) - (= sum (Expr-size out))) - ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) - -(rule ((= expr (Const n ty assum))) - ((set (Expr-size expr) 1)) :ruleset always-run) - -(rule ((= expr (Bop op x y)) - (= sum (+ (Expr-size y) (Expr-size x)))) - ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) - -(rule ((= expr (Uop op x)) - (= sum (Expr-size x))) - ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) - -(rule ((= expr (Get tup i)) - (= sum (Expr-size tup))) - ((set (Expr-size expr) sum)) :ruleset always-run) - -(rule ((= expr (Concat x y)) - (= sum (+ (Expr-size y) (Expr-size x)))) - ((set (Expr-size expr) sum)) :ruleset always-run) - -(rule ((= expr (Single x)) - (= sum (Expr-size x))) - ((set (Expr-size expr) sum)) :ruleset always-run) - -(rule ((= expr (Switch pred inputs branches)) - (= sum (+ (Expr-size inputs) (+ (ListExpr-size branches) (Expr-size pred))))) - ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) - -(rule ((= expr (If pred inputs then else)) - (= sum (+ (Expr-size inputs) (+ (Expr-size else) (+ (Expr-size then) (Expr-size pred)))))) - ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) - -(rule ((= expr (DoWhile in pred-and-output)) - (= sum (+ (Expr-size pred-and-output) (Expr-size in)))) - ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) - -(rule ((= expr (Arg ty assum))) - ((set (Expr-size expr) 1)) :ruleset always-run) - -(rule ((= expr (Call func arg)) - (= sum (Expr-size arg))) - ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) - -(rule ((Empty ty assum)) ((set (Expr-size (Empty ty assum)) 0)) :ruleset always-run) - -(rule ((= expr (Cons hd tl)) - (= sum (+ (ListExpr-size tl) (Expr-size hd)))) - ((set (ListExpr-size expr) sum)) :ruleset always-run) - -(rule ((Nil)) - ((set (ListExpr-size (Nil)) 0)) :ruleset always-run) - -(rule ((= expr (Alloc id e state ty)) ;; do state edge's expr should be counted? - (= sum (Expr-size e))) - ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) -;; Like Subst but for dropping inputs to a region -;; See subst.egg for more implementation documentation - -(ruleset drop) -(ruleset apply-drop-unions) -(ruleset cleanup-drop) - -;; (DropAt ctx idx in) removes all references to `(Get (Arg ...) idx)` in `in`. -;; It also replaces the leaf contexts with `ctx` and fixes up argument types, -;; as well as updating `(Get (Arg ...) j)` to `(Get (Arg ...) (- j 1))` for j > idx. -(function DropAt (Assumption i64 Expr) Expr :unextractable) -(function DelayedDropUnion (Expr Expr) Expr :unextractable) - -;; Helper that precomputes the arg type that we need -(function DropAtInternal (Type Assumption i64 Expr) Expr :unextractable) -(rule ((= lhs (DropAt ctx idx in)) - (HasArgType in (TupleT oldty))) - - ((let newty (TupleT (TypeListRemoveAt oldty idx))) - (union lhs (DropAtInternal newty ctx idx in))) - :ruleset drop) - -;; Leaves -(rule ((= lhs (DropAtInternal newty newctx idx (Const c oldty oldctx)))) - ((DelayedDropUnion lhs (Const c newty newctx))) - :ruleset drop) -(rule ((= lhs (DropAtInternal newty newctx idx (Empty oldty oldctx)))) - ((DelayedDropUnion lhs (Empty newty newctx))) - :ruleset drop) -; get stuck on purpose if `i = idx` or if we find a bare `Arg` -(rule ((= lhs (DropAtInternal newty newctx idx (Get (Arg oldty oldctx) i))) - (< i idx)) - ((DelayedDropUnion lhs (Get (Arg newty newctx) i))) - :ruleset drop) -(rule ((= lhs (DropAtInternal newty newctx idx (Get (Arg oldty oldctx) i))) - (> i idx)) - ((DelayedDropUnion lhs (Get (Arg newty newctx) (- i 1)))) - :ruleset drop) - -;; Operators -(rule ((= lhs (DropAtInternal newty newctx idx (Bop op c1 c2))) - (ExprIsResolved (Bop op c1 c2))) - ((DelayedDropUnion lhs (Bop op - (DropAtInternal newty newctx idx c1) - (DropAtInternal newty newctx idx c2)))) - :ruleset drop) - -(rule ((= lhs (DropAtInternal newty newctx idx (Uop op c1))) - (ExprIsResolved (Uop op c1))) - ((DelayedDropUnion lhs (Uop op - (DropAtInternal newty newctx idx c1)))) - :ruleset drop) - -;; this is okay because we get stuck at `Arg`s -(rule ((= lhs (DropAtInternal newty newctx idx (Get c1 index))) - (ExprIsResolved (Get c1 index))) - ((DelayedDropUnion lhs (Get - (DropAtInternal newty newctx idx c1) - index))) - :ruleset drop) - -(rule ((= lhs (DropAtInternal newty newctx idx (Alloc id c1 c2 ty))) - (ExprIsResolved (Alloc id c1 c2 ty))) - ((DelayedDropUnion lhs (Alloc id - (DropAtInternal newty newctx idx c1) - (DropAtInternal newty newctx idx c2) - ty))) - :ruleset drop) - -(rule ((= lhs (DropAtInternal newty newctx idx (Call name c1))) - (ExprIsResolved (Call name c1))) - ((DelayedDropUnion lhs (Call name - (DropAtInternal newty newctx idx c1)))) - :ruleset drop) - -;; Tuple operators -(rule ((= lhs (DropAtInternal newty newctx idx (Single c1))) - (ExprIsResolved (Single c1))) - ((DelayedDropUnion lhs (Single - (DropAtInternal newty newctx idx c1)))) - :ruleset drop) - -(rule ((= lhs (DropAtInternal newty newctx idx (Concat c1 c2))) - (ExprIsResolved (Concat c1 c2))) - ((DelayedDropUnion lhs (Concat - (DropAtInternal newty newctx idx c1) - (DropAtInternal newty newctx idx c2)))) - :ruleset drop) - -;; Control flow -(rule ((= lhs (DropAtInternal newty newctx idx (Switch pred inputs c1))) - (ExprIsResolved (Switch pred inputs c1))) - ((DelayedDropUnion lhs (Switch - (DropAtInternal newty newctx idx pred) - (DropAtInternal newty newctx idx inputs) - c1))) - :ruleset drop) - -(rule ((= lhs (DropAtInternal newty newctx idx (If pred inputs c1 c2))) - (ExprIsResolved (If pred inputs c1 c2))) - ((DelayedDropUnion lhs (If - (DropAtInternal newty newctx idx pred) - (DropAtInternal newty newctx idx inputs) - c1 - c2))) - :ruleset drop) - -(rule ((= lhs (DropAtInternal newty newctx idx (DoWhile in out))) - (ExprIsResolved (DoWhile in out))) - ((DelayedDropUnion lhs (DoWhile - (DropAtInternal newty newctx idx in) - out))) - :ruleset drop) - -(rewrite (DropAtInternal newty newctx idx (Function name inty outty body)) - (Function name inty outty (DropAtInternal newty newctx idx body)) - :when ((ExprIsResolved body)) - :ruleset drop) - - - -;; ########################### Apply drop unions - -(rule ((DelayedDropUnion lhs rhs)) - ((union lhs rhs)) - :ruleset apply-drop-unions) - -;; ########################### Cleanup Dropat, DropAtInternal and DelayedDropUnion - -(rule ((ExprIsResolved (DropAt newctx idx in))) - ((subsume (DropAt newctx idx in))) - :ruleset cleanup-drop) - -(rule ((ExprIsResolved (DropAtInternal newty newctx idx in))) - ((subsume (DropAtInternal newty newctx idx in))) - :ruleset cleanup-drop) - -(rule ((DelayedDropUnion lhs rhs)) - ((subsume (DelayedDropUnion lhs rhs))) - :ruleset cleanup-drop) - -(ruleset interval-analysis) - -(datatype Bound - (IntB i64) - (BoolB bool) - (bound-max Bound Bound) - (bound-min Bound Bound)) - -; bound tables -(function lo-bound (Expr) Bound :unextractable :merge (bound-max old new)) -(function hi-bound (Expr) Bound :unextractable :merge (bound-min old new)) - -; if lo > hi, panic -; We can't run these rules because unreachable branches may have impossible intervals -; Consider re-enabling these rules if we implement an is-reachable analysis -; (rule ( -; (= (IntB lo) (lo-bound expr)) -; (= (IntB hi) (hi-bound expr)) -; (> lo hi) -; ) -; ((panic "lo bound greater than hi bound")) -; :ruleset interval-analysis) -; (rule ( -; (= (BoolB true) (lo-bound expr)) -; (= (BoolB false) (hi-bound expr)) -; ) -; ((panic "lo bound greater than hi bound")) -; :ruleset interval-analysis) - -; combinators -(rewrite (bound-max (IntB x) (IntB y)) - (IntB (max x y)) - :ruleset interval-analysis) -(rewrite (bound-min (IntB x) (IntB y)) - (IntB (min x y)) - :ruleset interval-analysis) -(rewrite (bound-max (BoolB x) (BoolB y)) - (BoolB (or x y)) - :ruleset interval-analysis) -(rewrite (bound-min (BoolB x) (BoolB y)) - (BoolB (and x y)) - :ruleset interval-analysis) - -; ================================= -; Constants -; ================================= -(rule ((= lhs (Const (Int x) ty ctx))) - ( - (set (lo-bound lhs) (IntB x)) - (set (hi-bound lhs) (IntB x)) - ) - :ruleset interval-analysis) - -(rule ((= lhs (Const (Bool x) ty ctx))) - ( - (set (lo-bound lhs) (BoolB x)) - (set (hi-bound lhs) (BoolB x)) - ) - :ruleset interval-analysis) - -; ================================= -; Constant Folding -; ================================= -(rule ( - (= (IntB x) (lo-bound expr)) - (= (IntB x) (hi-bound expr)) - (HasArgType expr ty) - (ContextOf expr ctx) - ) - ((union expr (Const (Int x) ty ctx))) - :ruleset interval-analysis) - -(rule ( - (= (BoolB x) (lo-bound expr)) - (= (BoolB x) (hi-bound expr)) - (HasArgType expr ty) - (ContextOf expr ctx) - ) - ((union expr (Const (Bool x) ty ctx))) - :ruleset interval-analysis) - -; lower bound being true means the bool must be true -(rule ( - (= (BoolB true) (lo-bound expr)) - (HasArgType expr ty) - (ContextOf expr ctx) - ) - ((union expr (Const (Bool true) ty ctx))) - :ruleset interval-analysis) - -; upper bound being false means the bool must be false -(rule ( - (= (BoolB false) (hi-bound expr)) - (HasArgType expr ty) - (ContextOf expr ctx) - ) - ((union expr (Const (Bool false) ty ctx))) - :ruleset interval-analysis) - -; ================================= -; Arithmetic -; ================================= -; + a b interval is (+ la lb) (+ ha hb) -(rule ( - (= lhs (Bop (Add) a b)) - (= (IntB la) (lo-bound a)) - (= (IntB lb) (lo-bound b)) - ) - ((set (lo-bound lhs) (IntB (+ la lb)))) - :ruleset interval-analysis) -(rule ( - (= lhs (Bop (Add) a b)) - (= (IntB ha) (hi-bound a)) - (= (IntB hb) (hi-bound b)) - ) - ((set (hi-bound lhs) (IntB (+ ha hb)))) - :ruleset interval-analysis) - -; - a b interval is (- la hb) (- ha lb) -(rule ( - (= lhs (Bop (Sub) a b)) - (= (IntB la) (lo-bound a)) - (= (IntB hb) (hi-bound b)) - ) - ((set (lo-bound lhs) (IntB (- la hb)))) - :ruleset interval-analysis) -(rule ( - (= lhs (Bop (Sub) a b)) - (= (IntB ha) (hi-bound a)) - (= (IntB lb) (lo-bound b)) - ) - ((set (hi-bound lhs) (IntB (- ha lb)))) - :ruleset interval-analysis) - -; Multiplication for two constants -; TODO: Make fancier interval analysis -(rule ( - (= lhs (Bop (Mul) a b)) - (= (IntB x) (lo-bound a)) - (= (IntB x) (hi-bound a)) - (= (IntB y) (lo-bound b)) - (= (IntB y) (hi-bound b)) - ) - ( - (set (lo-bound lhs) (IntB (* x y))) - (set (hi-bound lhs) (IntB (* x y))) - ) - :ruleset interval-analysis) - -; negative * negative is positive -(rule ( - (= lhs (Bop (Mul) x y)) - (= (IntB hi-x) (hi-bound x)) - (= (IntB hi-y) (hi-bound y)) - (<= hi-x 0) - (<= hi-y 0) - ) - ((set (lo-bound lhs) (IntB 0))) - :ruleset interval-analysis) - -; negative * positive is negative -(rule ( - (= lhs (Bop (Mul) x y)) - (= (IntB hi-x) (hi-bound x)) - (= (IntB lo-y) (lo-bound y)) - (<= hi-x 0) ; x <= 0 (x is negative) - (>= lo-y 0) ; y >= 0 (y is positive) - ) - ((set (hi-bound lhs) (IntB 0))) - :ruleset interval-analysis) - -; positive * positive is positive -(rule ( - (= lhs (Bop (Mul) x y)) - (= (IntB lo-x) (lo-bound x)) - (= (IntB lo-y) (lo-bound y)) - (>= lo-x 0) - (>= lo-y 0) - ) - ((set (lo-bound lhs) (IntB 0))) - :ruleset interval-analysis) - -; < a b interval is (< ha lb) (< la hb) -(rule ( - (= lhs (Bop (LessThan) a b)) - (= (IntB ha) (hi-bound a)) - (= (IntB lb) (lo-bound b)) - ) - ( - (set (lo-bound lhs) (BoolB (bool-< ha lb))) - ) - :ruleset interval-analysis) -(rule ( - (= lhs (Bop (LessThan) a b)) - (= (IntB la) (lo-bound a)) - (= (IntB hb) (hi-bound b)) - ) - ((set (hi-bound lhs) (BoolB (bool-< la hb)))) - :ruleset interval-analysis) - -; ================================= -; Conditionals -; ================================= -; if the predicate is true, merge with then branch -(rule ( - (= lhs (If cond inputs thn els)) - (ContextOf lhs if_ctx) - (= (BoolB true) (lo-bound cond)) - ) - ((union lhs (Subst if_ctx inputs thn))) - :ruleset interval-analysis) - -; if the predicate is false, merge with else branch -(rule ( - (= lhs (If cond inputs thn els)) - (ContextOf lhs if_ctx) - (= (BoolB false) (hi-bound cond)) - ) - ((union lhs (Subst if_ctx inputs els))) - :ruleset interval-analysis) - -; lo-bound of If is the min of the lower bounds -; hi-bound of If is the max of the upper bounds -(rule ( - (= lhs (If cond inputs thn els)) - (= lo-thn (lo-bound thn)) - (= lo-els (lo-bound els)) - ) - ((set (lo-bound lhs) (bound-min lo-thn lo-els))) - :ruleset interval-analysis) -(rule ( - (= lhs (If cond inputs thn els)) - (= hi-thn (hi-bound thn)) - (= hi-els (hi-bound els)) - ) - ((set (hi-bound lhs) (bound-max hi-thn hi-els))) - :ruleset interval-analysis) - -; Same rules, but for Ifs that have multiple outputs -(rule ( - (= lhs (Get (If pred inputs thn els) i)) - (= lo-thn (lo-bound (Get thn i))) - (= lo-els (lo-bound (Get els i))) - ) - ((set (lo-bound lhs) (bound-min lo-thn lo-els))) - :ruleset interval-analysis) -(rule ( - (= lhs (Get (If cond inputs thn els) i)) - (= hi-thn (hi-bound (Get thn i))) - (= hi-els (hi-bound (Get els i))) - ) - ((set (hi-bound lhs) (bound-max hi-thn hi-els))) - :ruleset interval-analysis) - -; If the If takes a tuple -(rule ( - ; expr < value - (= pred (Bop (LessThan) expr value)) - (= if_e (If pred inputs then else)) - ; the left operand of the < is an input to the if region - (= expr (Get inputs i)) - ; the right operand of the < has an upper bound - (= (IntB v) (hi-bound value)) - ; context node inside the if region - (= ctx (Arg ty (InIf true pred inputs))) - (HasType inputs ty) - ) - ; expr < value was true, so we know expr is at most (hi-bound value) - 1 - ((set (hi-bound (Get ctx i)) (IntB (- v 1)))) - :ruleset interval-analysis) -(rule ( - ; expr < value - (= pred (Bop (LessThan) expr value)) - (= if_e (If pred inputs then else)) - ; the left operand of the < is an input to the if region - (= expr (Get inputs i)) - ; the right operand of the < has a lower bound - (= (IntB v) (lo-bound value)) - ; context node inside the if region - (= ctx (Arg ty (InIf false pred inputs))) - (HasType inputs ty) - ) - ; expr < value was false, so we know expr is at least (lo-bound value) - ((set (lo-bound (Get ctx i)) (IntB v))) - :ruleset interval-analysis) - -(rule ( - ; value < expr - (= pred (Bop (LessThan) value expr)) - (= if_e (If pred inputs then else)) - ; the right operand of the < is an input to the if region - (= expr (Get inputs i)) - ; the left operand of the < has a lower bound - (= (IntB v) (lo-bound value)) - ; context node inside the if region - (= ctx (Arg ty (InIf true pred inputs))) - (HasType inputs ty) - ) - ; value < expr was true, so we know expr is at least (lo-bound value) + 1 - ((set (lo-bound (Get ctx i)) (IntB (+ v 1)))) - :ruleset interval-analysis) -(rule ( - ; value < expr - (= pred (Bop (LessThan) value expr)) - (= if_e (If pred inputs then else)) - ; the right operand of the < is an input to the if region - (= expr (Get inputs i)) - ; the left operand of the < has an upper bound - (= (IntB v) (hi-bound value)) - ; context node inside the if region - (= ctx (Arg ty (InIf false pred inputs))) - (HasType inputs ty) - ) - ; value < expr was false, so we know expr is at most (hi-bound value) - ((set (hi-bound (Get ctx i)) (IntB v))) - :ruleset interval-analysis) - -;; Push intervals for inputs into if region -(rule ( - (= if (If pred inputs then_ else_)) - (= ctx (Arg ty (InIf b pred inputs))) - (HasType inputs ty) - (= lo (lo-bound (Get inputs i))) - - ) - ((set (lo-bound (Get ctx i)) lo)) - :ruleset interval-analysis) -(rule ( - (= if (If pred inputs then_ else_)) - (= ctx (Arg ty (InIf b pred inputs))) - (HasType inputs ty) - (= hi (hi-bound (Get inputs i))) - - ) - ((set (hi-bound (Get ctx i)) hi)) - :ruleset interval-analysis) - -; (if (a == b) thn els) -; in the thn branch, we know that a has the same bounds as b -(rule ( - (= pred (Bop (Eq) expr val)) - (= if_e (If pred inputs thn els)) - ; the left operand of the == is an input to the if region - (= expr (Get inputs i)) - (= ctx (Arg ty (InIf true pred inputs))) - (HasType inputs ty) - (= (IntB lo) (lo-bound val)) - ) - ((set (lo-bound (Get ctx i)) (IntB lo))) - :ruleset interval-analysis) -(rule ( - (= pred (Bop (Eq) expr val)) - (= if_e (If pred inputs thn els)) - ; the left operand of the == is an input to the if region - (= expr (Get inputs i)) - (= ctx (Arg ty (InIf true pred inputs))) - (HasType inputs ty) - (= (IntB hi) (hi-bound val)) - ) - ((set (hi-bound (Get ctx i)) (IntB hi))) - :ruleset interval-analysis) - - -(rule ( - ;; argument has loop context - (Arg ty (InLoop inputs outputs)) - ;; in the loop, the argument is passed through - ;; note that some_ctx is not the same as (InLoop inputs outputs) - (= (Get (Arg ty some_ctx) ith) (Get outputs (+ 1 ith))) - ;; input has some bound - (= bound (lo-bound (Get inputs ith))) - ) - ( - (set (lo-bound (Get (Arg ty (InLoop inputs outputs)) ith)) bound) - ) - :ruleset interval-analysis) -(rule ( - ;; argument has loop context - (Arg ty (InLoop inputs outputs)) - ;; in the loop, the argument is passed through - (= (Get (Arg ty some_ctx) ith) (Get outputs (+ 1 ith))) - ;; input has some bound - (= bound (hi-bound (Get inputs ith))) - ) - ( - (set (hi-bound (Get (Arg ty (InLoop inputs outputs)) ith)) bound) - ) - :ruleset interval-analysis) - - -(ruleset switch_rewrite) - -; if (a and b) X Y ~~> if a (if b X Y) Y -(rule ((= lhs (If (Bop (And) a b) ins X Y)) - (HasType ins (TupleT ins_ty)) - (= len (tuple-length ins))) - - ((let outer_ins (Concat (Single b) ins)) - (let outer_ins_ty (TupleT (TCons (BoolT) ins_ty))) - - (let inner_pred (Get (Arg outer_ins_ty (InIf true a outer_ins)) 0)) - (let sub_arg_true (SubTuple (Arg outer_ins_ty (InIf true a outer_ins)) 1 len)) - (let sub_arg_false (SubTuple (Arg outer_ins_ty (InIf false a outer_ins)) 1 len)) - - (let inner_X (AddContext (InIf true inner_pred sub_arg_true) X)) - (let inner_Y (AddContext (InIf false inner_pred sub_arg_true) Y)) - (let outer_Y (Subst (InIf false a outer_ins) sub_arg_false Y)) - - (let inner (If inner_pred sub_arg_true inner_X inner_Y)) - (union lhs (If a outer_ins inner outer_Y))) - - :ruleset switch_rewrite) - -; if (a or b) X Y ~~> if a X (if b X Y) -(rule ((= lhs (If (Bop (Or) a b) ins X Y)) - (HasType ins (TupleT ins_ty)) - (= len (tuple-length ins))) - - ((let outer_ins (Concat (Single b) ins)) - (let outer_ins_ty (TupleT (TCons (BoolT) ins_ty))) - - (let inner_pred (Get (Arg outer_ins_ty (InIf false a outer_ins)) 0)) - (let sub_arg_true (SubTuple (Arg outer_ins_ty (InIf true a outer_ins)) 1 len)) - (let sub_arg_false (SubTuple (Arg outer_ins_ty (InIf false a outer_ins)) 1 len)) - - (let outer_X (Subst (InIf true a outer_ins) sub_arg_true X)) - (let inner_X (AddContext (InIf true inner_pred sub_arg_false) X)) - (let inner_Y (AddContext (InIf false inner_pred sub_arg_false) Y)) - - (let inner (If inner_pred sub_arg_false inner_X inner_Y)) - (union lhs (If a outer_ins outer_X inner ))) - - :ruleset switch_rewrite) - -(rewrite (If (Const (Bool true) ty ctx) ins thn els) - (Subst ctx ins thn) - :ruleset always-run) - -(rewrite (If (Const (Bool false) ty ctx) ins thn els) - (Subst ctx ins els) - :ruleset switch_rewrite) - -(rule ((= lhs (If pred ins thn els)) - (= (Get thn i) (Const (Bool true) ty ctx1)) - (= (Get els i) (Const (Bool false) ty ctx2))) - ((union (Get lhs i) pred)) :ruleset switch_rewrite) - -(rule ((= lhs (If pred ins thn els)) - (= (Get thn i) (Const (Bool false) ty ctx1)) - (= (Get els i) (Const (Bool true) ty ctx2))) - ((union (Get lhs i) (Uop (Not) pred))) :ruleset switch_rewrite) - -; Simple rewrites that don't do a ton with control flow. - -(ruleset peepholes) - -(rewrite (Bop (Mul) (Const (Int 0) ty ctx) e) (Const (Int 0) ty ctx) :ruleset peepholes) -(rewrite (Bop (Mul) e (Const (Int 0) ty ctx)) (Const (Int 0) ty ctx) :ruleset peepholes) -(rewrite (Bop (Mul) (Const (Int 1) ty ctx) e) e :ruleset peepholes) -(rewrite (Bop (Mul) e (Const (Int 1) ty ctx)) e :ruleset peepholes) -(rewrite (Bop (Add) (Const (Int 0) ty ctx) e) e :ruleset peepholes) -(rewrite (Bop (Add) e (Const (Int 0) ty ctx) ) e :ruleset peepholes) - -(rewrite (Bop (Mul) (Const (Int j) ty ctx) (Const (Int i) ty ctx)) (Const (Int (* i j)) ty ctx) :ruleset peepholes) -(rewrite (Bop (Add) (Const (Int j) ty ctx) (Const (Int i) ty ctx)) (Const (Int (+ i j)) ty ctx) :ruleset peepholes) - -(rewrite (Bop (And) (Const (Bool true) ty ctx) e) e :ruleset peepholes) -(rewrite (Bop (And) e (Const (Bool true) ty ctx)) e :ruleset peepholes) -(rewrite (Bop (And) (Const (Bool false) ty ctx) e) (Const (Bool false) ty ctx) :ruleset peepholes) -(rewrite (Bop (And) e (Const (Bool false) ty ctx)) (Const (Bool false) ty ctx) :ruleset peepholes) -(rewrite (Bop (Or) (Const (Bool false) ty ctx) e) e :ruleset peepholes) -(rewrite (Bop (Or) e (Const (Bool false) ty ctx)) e :ruleset peepholes) -(rewrite (Bop (Or) (Const (Bool true) ty ctx) e) (Const (Bool true) ty ctx) :ruleset peepholes) -(rewrite (Bop (Or) e (Const (Bool true) ty ctx)) (Const (Bool true) ty ctx) :ruleset peepholes) - - -(datatype IntOrInfinity - (Infinity) - (NegInfinity) - (I i64)) - -(function MaxIntOrInfinity (IntOrInfinity IntOrInfinity) IntOrInfinity) -(rewrite (MaxIntOrInfinity (Infinity) _) (Infinity) :ruleset always-run) -(rewrite (MaxIntOrInfinity _ (Infinity)) (Infinity) :ruleset always-run) -(rewrite (MaxIntOrInfinity (NegInfinity) x) x :ruleset always-run) -(rewrite (MaxIntOrInfinity x (NegInfinity)) x :ruleset always-run) -(rewrite (MaxIntOrInfinity (I x) (I y)) (I (max x y)) :ruleset always-run) - -(function MinIntOrInfinity (IntOrInfinity IntOrInfinity) IntOrInfinity) -(rewrite (MinIntOrInfinity (NegInfinity) _) (NegInfinity) :ruleset always-run) -(rewrite (MinIntOrInfinity _ (NegInfinity)) (NegInfinity) :ruleset always-run) -(rewrite (MinIntOrInfinity (Infinity) x) x :ruleset always-run) -(rewrite (MinIntOrInfinity x (Infinity)) x :ruleset always-run) -(rewrite (MinIntOrInfinity (I x) (I y)) (I (min x y)) :ruleset always-run) - -(function AddIntOrInfinity (IntOrInfinity IntOrInfinity) IntOrInfinity) -(rewrite (AddIntOrInfinity (Infinity) (Infinity)) (Infinity) :ruleset always-run) -(rewrite (AddIntOrInfinity (Infinity) (I _)) (Infinity) :ruleset always-run) -(rewrite (AddIntOrInfinity (I _) (Infinity)) (Infinity) :ruleset always-run) -(rewrite (AddIntOrInfinity (NegInfinity) (NegInfinity)) (NegInfinity) :ruleset always-run) -(rewrite (AddIntOrInfinity (NegInfinity) (I _)) (NegInfinity) :ruleset always-run) -(rewrite (AddIntOrInfinity (I _) (NegInfinity)) (NegInfinity) :ruleset always-run) -(rewrite (AddIntOrInfinity (I x) (I y)) (I (+ x y)) :ruleset always-run) - -(datatype IntInterval (MkIntInterval IntOrInfinity IntOrInfinity)) - -(function UnionIntInterval (IntInterval IntInterval) IntInterval) -(rewrite (UnionIntInterval (MkIntInterval lo1 hi1) (MkIntInterval lo2 hi2)) - (MkIntInterval (MinIntOrInfinity lo1 lo2) (MaxIntOrInfinity hi1 hi2)) - :ruleset always-run) - -(function IntersectIntInterval (IntInterval IntInterval) IntInterval) -(rewrite (IntersectIntInterval (MkIntInterval lo1 hi1) (MkIntInterval lo2 hi2)) - (MkIntInterval (MaxIntOrInfinity lo1 lo2) (MinIntOrInfinity hi1 hi2)) - :ruleset always-run) - -(function AddIntInterval (IntInterval IntInterval) IntInterval) -(rewrite (AddIntInterval (MkIntInterval lo1 hi1) (MkIntInterval lo2 hi2)) - (MkIntInterval (AddIntOrInfinity lo1 lo2) - (AddIntOrInfinity hi1 hi2)) - :ruleset always-run) - - -(datatype List - (Nil-List) - (Cons-List i64 IntInterval List)) - -(function Length-List (List) i64) -(rule ((= x (Nil-List))) - ((set (Length-List x) 0)) - :ruleset always-run) -(rule ((= x (Cons-List hd0 hd1 tl)) - (= l (Length-List tl))) - ((set (Length-List x) (+ l 1))) - :ruleset always-run) -(rule ((= x (Nil-List))) - ((set (Length-List x) 0)) - :ruleset memory-helpers) -(rule ((= x (Cons-List hd0 hd1 tl)) - (= l (Length-List tl))) - ((set (Length-List x) (+ l 1))) - :ruleset memory-helpers) - -(relation IsEmpty-List (List)) -(rule ((= x (Nil-List))) - ((IsEmpty-List x)) - :ruleset always-run) - -(relation IsNonEmpty-List (List)) -(rule ((= x (Cons-List hd0 hd1 tl))) - ((IsNonEmpty-List x)) - :ruleset always-run) - -(function RevConcat-List (List List) List :cost 1000) -(rewrite (RevConcat-List (Nil-List) l) - l - :ruleset always-run) -(rewrite (RevConcat-List (Cons-List hd0 hd1 tl) l) - (RevConcat-List tl (Cons-List hd0 hd1 l)) - :ruleset always-run) - -(function Rev-List (List) List :cost 1000) -(rewrite (Rev-List m) - (RevConcat-List m (Nil-List)) - :ruleset always-run) - -(function Concat-List (List List) List :cost 1000) -(rewrite (Concat-List x y) - (RevConcat-List (Rev-List x) y) - :ruleset always-run) - -; SuffixAt and At must be demanded, otherwise these are O(N^2) -(relation DemandAt-List (List)) -(relation SuffixAt-List (List i64 List)) -(relation At-List (List i64 i64 IntInterval)) -(rule ((DemandAt-List x)) - ((SuffixAt-List x 0 x)) - :ruleset always-run) -(rule ((SuffixAt-List x i (Cons-List hd0 hd1 tl))) - ((SuffixAt-List x (+ i 1) tl) - (At-List x i hd0 hd1)) - :ruleset always-run) - -(function Union-List (List List) List) - ; The third argument of the helper is a WIP result map. - ; Invariant: keys of the result map are not present in the first two and are in descending order - (function UnionHelper-List (List List List) List) - (rewrite (Union-List m1 m2) - (Rev-List (UnionHelper-List m1 m2 (Nil-List))) - :ruleset always-run) - - ; both m1 and m2 empty - (rewrite (UnionHelper-List (Nil-List) (Nil-List) res) - res - :ruleset always-run) - ; take from m1 when m2 empty and vice versa - (rewrite - (UnionHelper-List - (Nil-List) - (Cons-List hd0 hd1 tl) - res) - (UnionHelper-List - (Nil-List) - tl - (Cons-List hd0 hd1 res)) - :ruleset always-run) - (rewrite - (UnionHelper-List - (Cons-List hd0 hd1 tl) - (Nil-List) - res) - (UnionHelper-List - tl - (Nil-List) - (Cons-List hd0 hd1 res)) - :ruleset always-run) - - ; when both nonempty and smallest key different, take smaller key - (rule ((= f (UnionHelper-List l1 l2 res)) - (= l1 (Cons-List k1 a1 tl1)) - (= l2 (Cons-List k2 b1 tl2)) - (< k1 k2)) - ((union f - (UnionHelper-List tl1 l2 (Cons-List k1 a1 res)))) - :ruleset always-run) - (rule ((= f (UnionHelper-List l1 l2 res)) - (= l1 (Cons-List k1 a1 tl1)) - (= l2 (Cons-List k2 b1 tl2)) - (< k2 k1)) - ((union f - (UnionHelper-List l1 tl2 (Cons-List k2 b1 res)))) - :ruleset always-run) - - ; when shared smallest key, union interval - (rule ((= f (UnionHelper-List l1 l2 res)) - (= l1 (Cons-List k a1 tl1)) - (= l2 (Cons-List k b1 tl2))) - ((union f - (UnionHelper-List tl1 tl2 - (Cons-List k (UnionIntInterval a1 b1) res)))) - :ruleset always-run) - -(function Intersect-List (List List) List) - ; The third argument of the helper is a WIP result map. - ; Invariant: keys of the result map are not present in the first two and are in descending order - (function IntersectHelper-List (List List List) List) - (rewrite (Intersect-List m1 m2) - (Rev-List (IntersectHelper-List m1 m2 (Nil-List))) - :ruleset always-run) - - ; m1 or m2 empty - (rewrite (IntersectHelper-List (Nil-List) m2 res) - res - :ruleset always-run) - (rewrite (IntersectHelper-List m1 (Nil-List) res) - res - :ruleset always-run) - - ; when both nonempty and smallest key different, drop smaller key - (rule ((= f (IntersectHelper-List l1 l2 res)) - (= l1 (Cons-List k1 a1 tl1)) - (= l2 (Cons-List k2 b1 tl2)) - (< k1 k2)) - ((union f (IntersectHelper-List tl1 l2 res))) - :ruleset always-run) - (rule ((= f (IntersectHelper-List l1 l2 res)) - (= l1 (Cons-List k1 a1 tl1)) - (= l2 (Cons-List k2 b1 tl2)) - (< k2 k1)) - ((union f (IntersectHelper-List tl1 l2 res))) - :ruleset always-run) - -(datatype MyBool (MyTrue) (MyFalse)) - -(function IntIntervalValid (IntInterval) MyBool) -(rewrite (IntIntervalValid (MkIntInterval (I lo) (I hi))) - (MyTrue) - :when ((<= lo hi)) - :ruleset always-run) -(rewrite (IntIntervalValid (MkIntInterval (I lo) (I hi))) - (MyFalse) - :when ((> lo hi)) - :ruleset always-run) -(rewrite (IntIntervalValid (MkIntInterval (NegInfinity) _)) - (MyTrue) - :ruleset always-run) -(rewrite (IntIntervalValid (MkIntInterval _ (Infinity))) - (MyTrue) - :ruleset always-run) - -(function ConsIfNonEmpty (i64 IntInterval List) - List - :cost 100) -(rule ((ConsIfNonEmpty k v tl)) - ((IntIntervalValid v)) - :ruleset always-run) -(rule ((= f (ConsIfNonEmpty k v tl)) - (= (MyTrue) (IntIntervalValid v))) - ((union f (Cons-List k v tl))) - :ruleset always-run) -(rule ((= f (ConsIfNonEmpty k v tl)) - (= (MyFalse) (IntIntervalValid v))) - ((union f tl)) - :ruleset always-run) - - ; when shared smallest key, intersect interval - (rule ((= f (IntersectHelper-List l1 l2 res)) - (= l1 (Cons-List k a1 tl1)) - (= l2 (Cons-List k b1 tl2))) - ((union f - (IntersectHelper-List tl1 tl2 - (ConsIfNonEmpty k (IntersectIntInterval a1 b1) res)))) - :ruleset always-run) - -(function AddIntIntervalToAll (IntInterval List) - List) -(rewrite (AddIntIntervalToAll _ (Nil-List)) - (Nil-List) - :ruleset always-run) -(rewrite (AddIntIntervalToAll x (Cons-List allocid offset tl)) - (Cons-List allocid (AddIntInterval x offset) - (AddIntIntervalToAll x tl)) - :ruleset always-run) - -(datatype PtrPointees - (PointsTo List) - (PointsAnywhere)) - -(function AddIntIntervalToPtrPointees (IntInterval PtrPointees) PtrPointees) -(rewrite (AddIntIntervalToPtrPointees interval (PointsAnywhere)) - (PointsAnywhere) - :ruleset always-run) -(rewrite (AddIntIntervalToPtrPointees interval (PointsTo l)) - (PointsTo (AddIntIntervalToAll interval l)) - :ruleset always-run) - -(function Union-PtrPointees (PtrPointees PtrPointees) PtrPointees) -(rewrite (Union-PtrPointees (PointsAnywhere) _) - (PointsAnywhere) - :ruleset always-run) -(rewrite (Union-PtrPointees _ (PointsAnywhere)) - (PointsAnywhere) - :ruleset always-run) -(rewrite (Union-PtrPointees (PointsTo x) (PointsTo y)) - (PointsTo (Union-List x y)) - :ruleset always-run) -(function Intersect-PtrPointees (PtrPointees PtrPointees) PtrPointees) -(rewrite (Intersect-PtrPointees (PointsAnywhere) x) - x - :ruleset always-run) -(rewrite (Intersect-PtrPointees x (PointsAnywhere)) - x - :ruleset always-run) -(rewrite (Intersect-PtrPointees (PointsTo x) (PointsTo y)) - (PointsTo (Intersect-List x y)) - :ruleset always-run) - -(relation PointsNowhere-PtrPointees (PtrPointees)) -(rule ((= f (PointsTo x)) - (IsEmpty-List x)) - ((PointsNowhere-PtrPointees f)) - :ruleset always-run) - - -(datatype List - (Nil-List) - (Cons-List PtrPointees List)) - -(function Length-List (List) i64) -(rule ((= x (Nil-List))) - ((set (Length-List x) 0)) - :ruleset always-run) -(rule ((= x (Cons-List hd0 tl)) - (= l (Length-List tl))) - ((set (Length-List x) (+ l 1))) - :ruleset always-run) -(rule ((= x (Nil-List))) - ((set (Length-List x) 0)) - :ruleset memory-helpers) -(rule ((= x (Cons-List hd0 tl)) - (= l (Length-List tl))) - ((set (Length-List x) (+ l 1))) - :ruleset memory-helpers) - -(relation IsEmpty-List (List)) -(rule ((= x (Nil-List))) - ((IsEmpty-List x)) - :ruleset always-run) - -(relation IsNonEmpty-List (List)) -(rule ((= x (Cons-List hd0 tl))) - ((IsNonEmpty-List x)) - :ruleset always-run) - -(function RevConcat-List (List List) List :cost 1000) -(rewrite (RevConcat-List (Nil-List) l) - l - :ruleset always-run) -(rewrite (RevConcat-List (Cons-List hd0 tl) l) - (RevConcat-List tl (Cons-List hd0 l)) - :ruleset always-run) - -(function Rev-List (List) List :cost 1000) -(rewrite (Rev-List m) - (RevConcat-List m (Nil-List)) - :ruleset always-run) - -(function Concat-List (List List) List :cost 1000) -(rewrite (Concat-List x y) - (RevConcat-List (Rev-List x) y) - :ruleset always-run) - -; SuffixAt and At must be demanded, otherwise these are O(N^2) -(relation DemandAt-List (List)) -(relation SuffixAt-List (List i64 List)) -(relation At-List (List i64 PtrPointees)) -(rule ((DemandAt-List x)) - ((SuffixAt-List x 0 x)) - :ruleset always-run) -(rule ((SuffixAt-List x i (Cons-List hd0 tl))) - ((SuffixAt-List x (+ i 1) tl) - (At-List x i hd0)) - :ruleset always-run) - -(relation All (List)) -(rule ((= x (Nil-List))) - ((All x)) - :ruleset always-run) -(rule ((= x (Cons-List hd0 tl)) - (PointsNowhere-PtrPointees hd0) - (All tl)) - ((All x)) - :ruleset always-run) - - - -(function Zip (List List) List :cost 1000) -(rewrite (Zip (Nil-List) (Nil-List)) - (Nil-List) - :ruleset always-run) -(rewrite (Zip - (Cons-List x0 tl1) - (Cons-List y0 tl2)) - (Cons-List - (Union-PtrPointees x0 y0) - (Zip tl1 tl2)) - :when ((= (Length-List tl1) (Length-List tl2))) - :ruleset always-run) - -(function Zip (List List) List :cost 1000) -(rewrite (Zip (Nil-List) (Nil-List)) - (Nil-List) - :ruleset always-run) -(rewrite (Zip - (Cons-List x0 tl1) - (Cons-List y0 tl2)) - (Cons-List - (Intersect-PtrPointees x0 y0) - (Zip tl1 tl2)) - :ruleset always-run) - - -(sort ExprSetPrim (Set Expr)) - -(datatype ExprSet (ES ExprSetPrim)) - -(function ExprSet-intersect (ExprSet ExprSet) ExprSet) -(rewrite (ExprSet-intersect (ES set1) (ES set2)) (ES (set-intersect set1 set2)) - :ruleset memory-helpers) -(function ExprSet-union (ExprSet ExprSet) ExprSet) -(rewrite (ExprSet-union (ES set1) (ES set2)) (ES (set-union set1 set2)) - :ruleset memory-helpers) -(relation ExprSet-contains (ExprSet Expr)) -(rule ((ES set1) (set-contains set1 x)) - ((ExprSet-contains (ES set1) x)) - :ruleset memory-helpers) -(function ExprSet-insert (ExprSet Expr) ExprSet) -(rewrite (ExprSet-insert (ES set1) x) - (ES (set-insert set1 x)) - :ruleset memory-helpers) -(function ExprSet-length (ExprSet) i64) -(rewrite (ExprSet-length (ES set1)) (set-length set1) :ruleset memory-helpers) - -; ============================ -; Pointees -; ============================ - - -; List is used as an association list; the i64 keys -; (corresponding to alloc ids) are always unique and sorted, the IntInterval -; values correspond to offset ranges. -; -; (TuplePointsTo [{0->[4,5], 1->[0,0]}, {0->[0,0]}]) -; indicates a tuple with two components. -; - The first component might point to Alloc 0 at offsets 4 or 5, -; or Alloc 1 at offset 0 -; - The second component points to Alloc 0 at offset 0 -(datatype Pointees - (TuplePointsTo List) - (PtrPointsTo PtrPointees)) - -(function UnwrapPtrPointsTo (Pointees) PtrPointees) -(rewrite (UnwrapPtrPointsTo (PtrPointsTo x)) - x - :ruleset memory-helpers) -(function UnwrapTuplePointsTo (Pointees) List) -(rewrite (UnwrapTuplePointsTo (TuplePointsTo x)) - x - :ruleset memory-helpers) - -(relation PointsNowhere (Pointees)) -(rule ((= f (PtrPointsTo x)) - (PointsNowhere-PtrPointees x)) - ((PointsNowhere f)) - :ruleset memory-helpers) -(rule ((= f (TuplePointsTo l)) - (All l)) - ((PointsNowhere f)) - :ruleset memory-helpers) - -(function UnionPointees (Pointees Pointees) Pointees) -(rewrite (UnionPointees (PtrPointsTo x) (PtrPointsTo y)) - (PtrPointsTo (Union-PtrPointees x y)) - :ruleset memory-helpers) -(rewrite (UnionPointees (TuplePointsTo x) (TuplePointsTo y)) - (TuplePointsTo (Zip x y)) - :when ((= (Length-List x) (Length-List y))) - :ruleset memory-helpers) -(function IntersectPointees (Pointees Pointees) Pointees) -(rewrite (IntersectPointees (PtrPointsTo x) (PtrPointsTo y)) - (PtrPointsTo (Intersect-PtrPointees x y)) - :ruleset memory-helpers) -(rewrite (IntersectPointees (TuplePointsTo x) (TuplePointsTo y)) - (TuplePointsTo (Zip x y)) - :ruleset memory-helpers) - -(function GetPointees (Pointees i64) Pointees) -(rule ((= f (GetPointees (TuplePointsTo l) i)) - (At-List l i x)) - ((union f (PtrPointsTo x))) - :ruleset memory-helpers) - -(function PointeesDropFirst (Pointees) Pointees) -(rewrite (PointeesDropFirst (TuplePointsTo (Cons-List hd tl))) - (TuplePointsTo tl) - :ruleset memory-helpers) - -; ============================ -; Resolved -; ============================ - -; Resolved checks if an e-class contains a term containing only constructors and -; primitives; i.e. whether equality is decideable -(relation Resolved-IntOrInfinity (IntOrInfinity)) -(rule ((= f (I _))) - ((Resolved-IntOrInfinity f)) - :ruleset memory-helpers) -(rule ((= f (Infinity))) - ((Resolved-IntOrInfinity f)) - :ruleset memory-helpers) -(rule ((= f (NegInfinity))) - ((Resolved-IntOrInfinity f)) - :ruleset memory-helpers) - -(relation Resolved-IntInterval (IntInterval)) -(rule ((= f (MkIntInterval lo hi)) - (Resolved-IntOrInfinity lo) - (Resolved-IntOrInfinity hi)) - ((Resolved-IntInterval f)) - :ruleset memory-helpers) - -(relation Resolved-List (List)) -(rule ((= f (Nil-List))) - ((Resolved-List f)) - :ruleset memory-helpers) -(rule ((= f (Cons-List allocid offsets tl)) - (Resolved-List tl) - (Resolved-IntInterval offsets)) - ((Resolved-List f)) - :ruleset memory-helpers) - -(relation Resolved-PtrPointees (PtrPointees)) -(rule ((= f (PointsAnywhere))) - ((Resolved-PtrPointees f)) - :ruleset memory-helpers) -(rule ((= f (PointsTo x)) - (Resolved-List x)) - ((Resolved-PtrPointees f)) - :ruleset memory-helpers) - -(relation Resolved-List (List)) -(rule ((= f (Nil-List))) - ((Resolved-List f)) - :ruleset memory-helpers) -(rule ((= f (Cons-List hd tl)) - (Resolved-List tl) - (Resolved-PtrPointees hd)) - ((Resolved-List f)) - :ruleset memory-helpers) - -(relation Resolved-Pointees (Pointees)) -(rule ((= f (TuplePointsTo x)) - (Resolved-List x)) - ((Resolved-Pointees f)) - :ruleset memory-helpers) -(rule ((= f (PtrPointsTo x)) - (Resolved-PtrPointees x)) - ((Resolved-Pointees f)) - :ruleset memory-helpers) - - -;;;;; - -(function BaseTypeToPtrPointees (BaseType) PtrPointees :cost 100) -(rewrite (BaseTypeToPtrPointees (PointerT _)) - (PointsAnywhere) - :ruleset memory-helpers) -(rewrite (BaseTypeToPtrPointees (IntT)) - (PointsTo (Nil-List)) - :ruleset memory-helpers) -(rewrite (BaseTypeToPtrPointees (StateT)) - (PointsTo (Nil-List)) - :ruleset memory-helpers) -(rewrite (BaseTypeToPtrPointees (BoolT)) - (PointsTo (Nil-List)) - :ruleset memory-helpers) - -(function TypeListToList (TypeList) List :cost 1000) -(rewrite (TypeListToList (TNil)) - (Nil-List) - :ruleset memory-helpers) -(rewrite (TypeListToList (TCons hd tl)) - (Cons-List - (BaseTypeToPtrPointees hd) - (TypeListToList tl)) - :ruleset memory-helpers) - -(function TypeToPointees (Type) Pointees :cost 1000) -(rewrite (TypeToPointees (TupleT tylist)) - (TuplePointsTo (TypeListToList tylist)) - :ruleset memory-helpers) -(rewrite (TypeToPointees (Base basety)) - (PtrPointsTo (BaseTypeToPtrPointees basety)) - :ruleset memory-helpers) - -; ============================ -; Update PointerishType -; ============================ - -(relation PointerishType (Type)) -(relation PointerishTypeList (TypeList)) - -(rule ((= f (Base (PointerT ty)))) - ((PointerishType f)) - :ruleset always-run) - -(rule ((= f (TCons (PointerT ty) tl))) - ((PointerishTypeList f)) - :ruleset always-run) - -(rule ((= f (TCons hd tl)) - (PointerishTypeList tl)) - ((PointerishTypeList f)) - :ruleset always-run) - -(rule ((= f (TupleT l)) - (PointerishTypeList l)) - ((PointerishType f)) - :ruleset always-run) - -; ============================ -; Update PointsToCells -; ============================ - -; arg pointees result pointees -(function PointsToCells (Expr Pointees) Pointees :unextractable) - -; Top-level demand -(rule ((Function name in-ty out-ty body)) - ((PointsToCells body (TypeToPointees in-ty))) - :ruleset memory-helpers) - -; Demand PointsToCells along state edge and pointer-typed values -(rule ((PointsToCells (Bop (Print) e state) ap)) - ((PointsToCells state ap)) - :ruleset memory-helpers) -(rule ((PointsToCells (Bop (Load) e state) ap)) - ((PointsToCells e ap) - (PointsToCells state ap)) - :ruleset memory-helpers) -(rule ((PointsToCells (Top (Write) ptr val state) ap)) - ((PointsToCells ptr ap) - (PointsToCells state ap)) - :ruleset memory-helpers) -(rule ((PointsToCells (Alloc id sz state ty) ap)) - ((PointsToCells state ap)) - :ruleset memory-helpers) -(rule ((PointsToCells (Bop (Free) ptr state) ap)) - ((PointsToCells ptr ap) - (PointsToCells state ap)) - :ruleset memory-helpers) -(rule ((PointsToCells (Get x i) ap)) - ((PointsToCells x ap)) - :ruleset memory-helpers) -(rule ((PointsToCells (Concat x y) ap)) - ((PointsToCells x ap) - (PointsToCells y ap)) - :ruleset memory-helpers) -(rule ((PointsToCells (Single x) ap)) - ((PointsToCells x ap)) - :ruleset memory-helpers) - -; Compute and propagate PointsToCells -(rewrite (PointsToCells (Concat x y) aps) - (TuplePointsTo (Concat-List - (UnwrapTuplePointsTo (PointsToCells x aps)) - (UnwrapTuplePointsTo (PointsToCells y aps)))) - :when ((HasType (Concat x y) ty) (PointerishType ty)) - :ruleset memory-helpers) - -(rewrite (PointsToCells (Get x i) aps) - (GetPointees (PointsToCells x aps) i) - :when ((HasType (Get x i) ty) (PointerishType ty)) - :ruleset memory-helpers) - -(rewrite (PointsToCells (Single x) aps) - (TuplePointsTo - (Cons-List - (UnwrapPtrPointsTo (PointsToCells x aps)) - (Nil-List))) - :when ((HasType (Single x) ty) (PointerishType ty)) - :ruleset memory-helpers) - -(rewrite (PointsToCells (Arg ty_ ctx) aps) - aps - :when ((HasType (Arg ty_ ctx) ty) (PointerishType ty)) - :ruleset memory-helpers) - -; Allow non-pointer types to resolve -(rule ((PointsToCells x aps) - (HasType x ty)) - ((TypeToPointees ty)) - :ruleset memory-helpers) -(rule ((= f (PointsToCells x aps)) - (HasType x ty) - (= pointees (TypeToPointees ty)) - (PointsNowhere pointees)) - ((union f pointees)) - :ruleset memory-helpers) - -(rewrite (PointsToCells (Bop (PtrAdd) x e) aps) - (PtrPointsTo - (AddIntIntervalToPtrPointees - (MkIntInterval (I lo) (I hi)) - (UnwrapPtrPointsTo (PointsToCells x aps)))) - :when ((= (IntB lo) (lo-bound e)) - (= (IntB hi) (hi-bound e))) - :ruleset memory-helpers) - -(rewrite (PointsToCells (If c inputs t e) aps) - (UnionPointees - (PointsToCells t (PointsToCells inputs aps)) - (PointsToCells e (PointsToCells inputs aps))) - :when ((HasType (If c inputs t e) ty) (PointerishType ty)) - :ruleset memory) - -(rewrite (PointsToCells (Alloc id sz state ty) aps) - (TuplePointsTo - (Cons-List - (PointsTo - (Cons-List - id - (MkIntInterval (I 0) (I 0)) - (Nil-List))) - (Cons-List - (PointsTo (Nil-List)) ; state output points to nothing - (Nil-List)))) - :ruleset memory-helpers) - -; arg pointees * loop in * loop out * i64 -> result pointees -(function PointsToCellsAtIter (Pointees Expr Expr i64) Pointees) - -; compute first two -(rule ((= e (DoWhile inputs pred-body)) - (PointsToCells e aps)) - ((set (PointsToCellsAtIter aps inputs pred-body 0) - (PointsToCells inputs aps)) - (set (PointsToCellsAtIter aps inputs pred-body 1) - (UnionPointees - (PointsToCellsAtIter aps inputs pred-body 0) - (PointeesDropFirst - (PointsToCells pred-body (PointsToCellsAtIter aps inputs pred-body 0)))))) - :ruleset memory-helpers) - -; avoid quadratic query -(function succ (i64) i64 :unextractable) -(rule ((PointsToCellsAtIter aps inputs pred-body i)) - ((set (succ i) (+ i 1))) - :ruleset memory-helpers) - -; Note that this rule is bounded by ruleset memory -(rule ((= pointees0 (PointsToCellsAtIter aps inputs pred-body i)) - (= pointees1 (PointsToCellsAtIter aps inputs pred-body (succ i))) - (Resolved-Pointees pointees0) - (Resolved-Pointees pointees1) - (!= pointees0 pointees1)) - ((set (PointsToCellsAtIter aps inputs pred-body (+ i 2)) - (UnionPointees - pointees1 - (PointeesDropFirst - (PointsToCells pred-body pointees1))))) - :ruleset memory) - -(rule ((= pointees (PointsToCellsAtIter aps inputs pred-body i)) - (= pointees (PointsToCellsAtIter aps inputs pred-body (succ i)))) - ((set (PointsToCells (DoWhile inputs pred-body) aps) - pointees)) - :ruleset memory) - -(rule ((PtrPointsTo (PointsTo l))) - ((DemandAt-List l)) - :ruleset memory-helpers) -(rule ((TuplePointsTo l)) - ((DemandAt-List l)) - :ruleset memory-helpers) - -; ============================ -; Update DontAlias -; ============================ - -(relation DemandDontAlias (Expr Expr Pointees)) -; pointer, pointer, arg pointees -(relation DontAlias (Expr Expr Pointees)) - - -(rule ((DemandDontAlias ptr1 ptr2 arg-pointees) - (BodyContainsExpr body ptr1) - (BodyContainsExpr body ptr2) - (HasType ptr1 (Base (PointerT ty))) - (HasType ptr2 (Base (PointerT ty))) - (= pointees1 (PointsToCells ptr1 arg-pointees)) - (= pointees2 (PointsToCells ptr2 arg-pointees))) - ((IntersectPointees pointees1 pointees2)) - :ruleset memory-helpers) - -(rule ((PointsNowhere - (IntersectPointees - (PointsToCells ptr1 arg-pointees) - (PointsToCells ptr2 arg-pointees)))) - ((DontAlias ptr1 ptr2 arg-pointees)) - :ruleset memory-helpers) - -; ============================ -; Update PointsToExpr -; ============================ - -; program point, pointer -(function PointsToExpr (Expr Expr) Expr :unextractable) - -; After a load, the ptr points to the loaded value -(rule ((= f (Bop (Load) ptr state))) - ((set (PointsToExpr (Get f 1) ptr) (Get f 0))) - :ruleset memory-helpers) - -; If we load and we already know what the pointer points to -; TODO this rule breaks the weakly linear invariant -; when a previous load may not be on the path -;(rule ((= e (Bop (Load) addr state)) -; (= v (PointsToExpr state addr))) -; ((union (Get e 0) v) -; (union (Get e 1) state)) -; :ruleset memory-helpers) - -; Loads and prints don't affect what what pointers already point to -(rule ((= f (PointsToExpr state addr)) - (= e (Bop (Load) any-addr state))) - ((let new-state (Get e 1)) - (union (PointsToExpr new-state addr) f)) - :ruleset memory-helpers) -(rule ((= f (PointsToExpr state addr)) - (= e (Bop (Print) any-val state))) - ((let new-state e) - (union (PointsToExpr new-state addr) f)) - :ruleset memory-helpers) - -; Writes don't affect what a pointer points to if it writes to another pointer -; guaranteed to not alias. -(rule ((= e (Top (Write) addr data state)) - (HasArgType addr argty) - (= otherdata (PointsToExpr state otheraddr))) - ((DemandDontAlias addr otheraddr (TypeToPointees argty))) - :ruleset memory-helpers) -(rule ((= e (Top (Write) addr data state)) - (HasArgType addr argty) - (= otherdata (PointsToExpr state otheraddr)) - (DontAlias addr otheraddr (TypeToPointees argty))) - ((set (PointsToExpr e otheraddr) otherdata)) - :ruleset memory-helpers) - -; For a write, mark the given expression as containing `data`. -(rule ((= e (Top (Write) addr data state))) - ((union (PointsToExpr e addr) data)) - :ruleset memory-helpers) - -; ============================ -; Update CellHasValues (currently unused) -; ============================ - -; ; program point, cell -; (function CellHasValues (Expr i64) ExprSet :merge (ExprSet-intersect old new)) - -; ; At the time of an alloc, a cell doesn't contain any values -; (rule ((= f (Alloc id amt state ty))) - ; ((set (CellHasValues (Get f 1) id) (ES (set-empty)))) - ; :ruleset memory-helpers) - -; ; These two rules find (Write ptr val state) where -; ; ptr points to cells given no assumptions about where (Arg) points. -; ; TODO: make sensitive to offsets -; (rule ((= e (Top (Write) ptr val state)) - ; (HasArgType ptr argty)) - ; ((TypeToPointees argty)) - ; :ruleset memory-helpers) -; (rule ((= e (Top (Write) ptr val state)) - ; (HasArgType ptr argty) - ; (= (PtrPointsTo (PointsTo cells)) (PointsToCells ptr (TypeToPointees argty))) - ; (At-List cells any-idx alloc-id offsets) - ; (= vals (CellHasValues state cell))) - ; ((set (CellHasValues e cell) (ExprSet-insert vals val))) - ; :ruleset memory-helpers) - -;; Loop Invariant - -;; bool: whether the term in the Expr is an invariant. -(function is-inv-Expr (Expr Expr) bool :unextractable :merge (or old new)) -(function is-inv-ListExpr (Expr ListExpr) bool :unextractable :merge (or old new)) - -;; in default, when there is a find, set is-inv to false -(rule ((BodyContainsExpr loop term) - (= loop (DoWhile inputs pred_out))) - ((set (is-inv-Expr loop term) false)) :ruleset always-run) -(rule ((BodyContainsListExpr loop term) - (= loop (DoWhile inputs pred_out))) - ((set (is-inv-ListExpr loop term) false)) :ruleset always-run) - -(relation is-inv-ListExpr-helper (Expr ListExpr i64)) -(rule ((BodyContainsListExpr loop list) - (= loop (DoWhile inputs pred_out))) - ((is-inv-ListExpr-helper loop list 0)) :ruleset always-run) - -(rule ((is-inv-ListExpr-helper loop list i) - (= true (is-inv-Expr loop expr)) - (= expr (ListExpr-ith list i))) - ((is-inv-ListExpr-helper loop list (+ i 1))) :ruleset always-run) - -(rule ((is-inv-ListExpr-helper loop list i) - (= i (ListExpr-length list))) - ((set (is-inv-ListExpr loop list) true)) :ruleset always-run) - - -(ruleset boundary-analysis) -;; An Expr is on boundary when it is invariant and its parent is not -; loop invariant-expr -(relation boundary-Expr (Expr Expr)) - -;; boundary for ListExpr's children -(rule ((= true (is-inv-Expr loop expr)) - (= false (is-inv-ListExpr loop list)) - (= expr (ListExpr-ith list i))) - ((boundary-Expr loop expr)) :ruleset boundary-analysis) - -;; if a output branch/pred is invariant, it's also boundary-Expr -(rule ((= true (is-inv-Expr loop expr)) - (= loop (DoWhile in pred_out)) - (= expr (Get pred_out i))) - ((boundary-Expr loop expr)) :ruleset boundary-analysis) - - -(function hoisted-loop (Expr Expr) bool :unextractable :merge (or old new) ) -(rule ((= loop (DoWhile in pred_out))) - ((set (hoisted-loop in pred_out) false)) :ruleset always-run) - -(function InExtendedLoop (Expr Expr Expr) Assumption) - -;; mock function -(ruleset loop-inv-motion) - -(rule ((boundary-Expr loop inv) - (> (Expr-size inv) 1) - ;; TODO: replace Expr-size when cost model is ready - (= loop (DoWhile in pred_out)) - ;; the outter assumption of the loop - (ContextOf loop loop_ctx) - (HasType in in_type) - (HasType inv inv_type) - (= inv_type (Base base_inv_ty)) - (= in_type (TupleT tylist)) - (= false (hoisted-loop in pred_out)) - (= len (tuple-length in))) - ((let new_input (Concat in (Single (Subst loop_ctx in inv)))) - (let new_input_type (TupleT (TLConcat tylist (TCons base_inv_ty (TNil))))) - ;; create an virtual assume node, union it with actuall InLoop later - (let assum (InExtendedLoop in pred_out new_input)) - (let new_out_branch (Get (Arg new_input_type assum) len)) - ;; this two subst only change arg to arg with new type - (let substed_pred_out (Subst assum (Arg new_input_type assum) pred_out)) - (let inv_in_new_loop (Subst assum (Arg new_input_type assum) inv)) - (let new_pred_out (Concat substed_pred_out (Single new_out_branch))) - - (let new_loop (DoWhile new_input new_pred_out)) - (union assum (InLoop new_input new_pred_out)) - (union inv_in_new_loop new_out_branch) - (let wrapper (SubTuple new_loop 0 len)) - (union loop wrapper) - (subsume (DoWhile in pred_out)) - ;; don't hoist same loop again - (set (hoisted-loop in pred_out) true) - ) - :ruleset loop-inv-motion) - - -(rule ((BodyContainsExpr loop expr) - (= loop (DoWhile in out)) - (= expr (Const _n _ty _ctx))) - ((set (is-inv-Expr loop expr) true)) :ruleset always-run) - -(rule ((BodyContainsExpr loop expr) - (= loop (DoWhile in out)) - (= expr (Get (Arg ty ctx) i)) - (= loop (DoWhile in pred_out)) - (= expr (Get pred_out (+ i 1)))) - ((set (is-inv-Expr loop expr) true)) :ruleset always-run) - -(rule ((BodyContainsExpr loop expr) - (= loop (DoWhile in out)) - (= expr (Function _name _tyin _tyout _out)) - - ) - ((set (is-inv-Expr loop expr) true)) :ruleset always-run) - -(rule ((BodyContainsExpr loop expr) - (= loop (DoWhile in out)) - (= expr (Top _op _x _y _z)) - (= true (is-inv-Expr loop _x)) (= true (is-inv-Expr loop _y)) (= true (is-inv-Expr loop _z)) - ) - ((set (is-inv-Expr loop expr) true)) :ruleset always-run) - -(rule ((BodyContainsExpr loop expr) - (= loop (DoWhile in out)) - (= expr (Bop _op _x _y)) (BinaryOpIsPure _op) - (= true (is-inv-Expr loop _x)) (= true (is-inv-Expr loop _y)) - ) - ((set (is-inv-Expr loop expr) true)) :ruleset always-run) - -(rule ((BodyContainsExpr loop expr) - (= loop (DoWhile in out)) - (= expr (Uop _op _x)) (UnaryOpIsPure _op) - (= true (is-inv-Expr loop _x)) - ) - ((set (is-inv-Expr loop expr) true)) :ruleset always-run) - -(rule ((BodyContainsExpr loop expr) - (= loop (DoWhile in out)) - (= expr (Get _tup _i)) - (= true (is-inv-Expr loop _tup)) - ) - ((set (is-inv-Expr loop expr) true)) :ruleset always-run) - -(rule ((BodyContainsExpr loop expr) - (= loop (DoWhile in out)) - (= expr (Concat _x _y)) - (= true (is-inv-Expr loop _x)) (= true (is-inv-Expr loop _y)) - ) - ((set (is-inv-Expr loop expr) true)) :ruleset always-run) - -(rule ((BodyContainsExpr loop expr) - (= loop (DoWhile in out)) - (= expr (Single _x)) - (= true (is-inv-Expr loop _x)) - ) - ((set (is-inv-Expr loop expr) true)) :ruleset always-run) - -(rule ((BodyContainsExpr loop expr) - (= loop (DoWhile in out)) - (= expr (Switch _pred _inputs _branches)) - (= true (is-inv-Expr loop _pred)) (= true (is-inv-Expr loop _inputs)) (= true (is-inv-ListExpr loop _branches)) - ) - ((set (is-inv-Expr loop expr) true)) :ruleset always-run) - -(rule ((BodyContainsExpr loop expr) - (= loop (DoWhile in out)) - (= expr (If _pred _input _then _else)) - (= true (is-inv-Expr loop _pred)) (= true (is-inv-Expr loop _input)) - ) - ((set (is-inv-Expr loop expr) true)) :ruleset always-run) - -(rule ((BodyContainsExpr loop expr) - (= loop (DoWhile in out)) - (= expr (DoWhile _in _pred-and-output)) - (= true (is-inv-Expr loop _in)) - (ExprIsPure expr)) - ((set (is-inv-Expr loop expr) true)) :ruleset always-run) - -(rule ((BodyContainsExpr loop expr) - (= loop (DoWhile in out)) - (= expr (Call _func _arg)) - (= true (is-inv-Expr loop _arg)) - (ExprIsPure expr)) - ((set (is-inv-Expr loop expr) true)) :ruleset always-run) - -(rule ((BodyContainsExpr loop expr) - (= loop (DoWhile in out)) - (= expr (Empty _ty _ctx)) - - ) - ((set (is-inv-Expr loop expr) true)) :ruleset always-run) - - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (Top _op _x _y _z)) - (= expr1 _x)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (Top _op _x _y _z)) - (= expr1 _y)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (Top _op _x _y _z)) - (= expr1 _z)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (Bop _op _x _y)) - (= expr1 _x)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (Bop _op _x _y)) - (= expr1 _y)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (Uop _op _x)) - (= expr1 _x)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (Concat _x _y)) - (= expr1 _x)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (Concat _x _y)) - (= expr1 _y)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (Single _x)) - (= expr1 _x)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (Switch _pred _inputs _branches)) - (= expr1 _pred)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (Switch _pred _inputs _branches)) - (= expr1 _inputs)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (If _pred _input _then _else)) - (= expr1 _pred)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (If _pred _input _then _else)) - (= expr1 _input)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (DoWhile _in _pred-and-output)) - (= expr1 _in)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (Call _func _arg)) - (= expr1 _arg)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (Alloc _id _e _state _ty)) - (= expr1 _e)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (Alloc _id _e _state _ty)) - (= expr1 _state)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) -;; Some simple simplifications of loops -(ruleset loop-simplify) - -(rewrite - (DoWhile (Arg ty ctx) - (Concat (Single (Const (Bool false) ty ctx2)) - (Single (Const constant ty ctx2)))) - (Single (Const constant ty ctx)) - :ruleset loop-simplify) -;; Some simple simplifications of loops -(ruleset loop-unroll) -(ruleset loop-peel) - -;; inputs, outputs -> number of iterations -(function LoopNumItersGuess (Expr Expr) i64 :merge (max 1 (min old new))) - -;; by default, guess that all loops run 1000 times -(rule ((DoWhile inputs outputs)) - ((set (LoopNumItersGuess inputs outputs) 1000)) - :ruleset always-run) - - -;; loop peeling rule -(rule - ((= lhs (DoWhile inputs outputs)) - (ContextOf lhs ctx) - (HasType inputs inputs-ty) - (= outputs-len (tuple-length outputs)) - (= old_cost (LoopNumItersGuess inputs outputs))) - ((let executed-once - (Subst ctx inputs outputs)) - (let executed-once-body - (SubTuple executed-once 1 (- outputs-len 1))) - (let then-ctx - (InIf true (Get executed-once 0) executed-once-body)) - (let else-ctx - (InIf false (Get executed-once 0) executed-once-body)) - (union lhs - ;; check if we need to continue executing the loop - (If (Get executed-once 0) - executed-once-body ;; inputs are the body executed once - (DoWhile (Arg inputs-ty then-ctx) - outputs) ;; right now, loop unrolling shares the same outputs, but we could add more context here - (Arg inputs-ty else-ctx))) - (set (LoopNumItersGuess (Arg inputs-ty then-ctx) outputs) (- old_cost 1)) - ) - :ruleset loop-peel) - -;; unroll a loop with constant bounds and initial value -(rule - ((= lhs (DoWhile inputs outputs)) - (= num-inputs (tuple-length inputs)) - (= pred (Get outputs 0)) - ;; iteration counter starts at start_const - (= (Const (Int start_const) _ty1 _ctx1) (Get inputs counter_i)) - ;; updated counter at counter_i - (= next_counter (Get outputs (+ counter_i 1))) - ;; increments by one each loop - (= next_counter (Bop (Add) (Get (Arg _ty _ctx) counter_i) - (Const (Int 1) _ty2 _ctx2))) - ;; while less than end_constant - (= pred (Bop (LessThan) next_counter - (Const (Int end_constant) _ty3 _ctx3))) - ;; start and end constant is a multiple of 4 and greater than start_const - (> end_constant start_const) - (= (% start_const 4) 0) - (= (% end_constant 4) 0) - (= old_cost (LoopNumItersGuess inputs outputs)) - ) - ( - (let one-iter (SubTuple outputs 1 num-inputs)) - (let unrolled - (Subst (TmpCtx) one-iter - (Subst (TmpCtx) one-iter - (Subst (TmpCtx) one-iter - outputs)))) - (union lhs - (DoWhile inputs - unrolled)) - (let actual-ctx (InLoop inputs unrolled)) - (union (TmpCtx) actual-ctx) - - (set (LoopNumItersGuess inputs unrolled) (/ old_cost 4)) - (delete (TmpCtx)) - ) - :ruleset loop-unroll) - - - -;; Pass through thetas -(rule ((= lhs (Get loop i)) - (= loop (DoWhile inputs pred-outputs)) - (= (Get pred-outputs (+ i 1)) (Get (Arg _ty _ctx) i)) - ;; only pass through pure types, since some loops don't terminate - ;; so the state edge must pass through them - (HasType (Get loop i) lhs_ty) - (PureType lhs_ty) - ) - ((union lhs (Get inputs i))) - :ruleset always-run) - -;; Pass through switch arguments -(rule ((= lhs (Get switch i)) - (= switch (Switch pred inputs branches)) - (= (ListExpr-length branches) 2) - (= branch0 (ListExpr-ith branches 0)) - (= branch1 (ListExpr-ith branches 1)) - (= (Get branch0 i) (Get (Arg _ _ctx0) j)) - (= (Get branch1 i) (Get (Arg _ _ctx1) j)) - (= passed-through (Get inputs j)) - (HasType lhs lhs_ty) - (!= lhs_ty (Base (StateT)))) - ((union lhs passed-through)) - :ruleset always-run) - -;; Pass through switch predicate -(rule ((= lhs (Get switch i)) - (= switch (Switch pred inputs branches)) - (= (ListExpr-length branches) 2) - (= branch0 (ListExpr-ith branches 0)) - (= branch1 (ListExpr-ith branches 1)) - (= (Get branch0 i) (Const (Bool false) _ _ctx0)) - (= (Get branch1 i) (Const (Bool true) _ _ctx1))) - ((union lhs pred)) - :ruleset always-run) - -;; Pass through if arguments -(rule ((= if (If pred inputs then_ else_)) - (= jth-inside (Get (Arg _ _then_ctx) j)) - (= (Get then_ i) jth-inside) - (= (Get else_ i) (Get (Arg _ _else_ctx) j)) - (HasType jth-inside lhs_ty) - (!= lhs_ty (Base (StateT)))) - ((union (Get if i) (Get inputs j))) - :ruleset always-run) - -; Pass through if state edge arguments -; To maintain the invariant, we have to union the other outputs with a pure if statement -(rule ((= lhs (Get outputs i)) - (= outputs (If pred inputs then_ else_)) - - (= (Get then_ i) (Get (Arg (TupleT arg_ty) then_ctx) j)) - (= (Get else_ i) (Get (Arg (TupleT arg_ty) else_ctx) j)) - (= passed-through (Get inputs j)) - - (HasType lhs lhs_ty) - (= lhs_ty (Base (StateT))) - - (= inputs_len (tuple-length inputs)) - (= outputs_len (tuple-length outputs))) - - ((let new_inputs (TupleRemoveAt inputs j)) - - (let new_then_ctx (InIf true pred new_inputs)) - (let new_else_ctx (InIf false pred new_inputs)) - - (let old_then (TupleRemoveAt then_ i)) - (let old_else (TupleRemoveAt else_ i)) - - (let new_then (DropAt new_then_ctx j old_then)) - (let new_else (DropAt new_else_ctx j old_else)) - - (let old_outputs (TupleRemoveAt outputs i)) - (let new_if (If pred new_inputs new_then new_else)) - (union new_if old_outputs) - - (union lhs passed-through) - (subsume (If pred inputs then_ else_))) - :ruleset always-run) - -;; Pass through if predicate -(rule ((= if (If pred inputs then_ else_)) - (= (Get then_ i) (Const (Bool true) _ _thenctx)) - (= (Get else_ i) (Const (Bool false) _ _elsectx))) - - ((let new_then (TupleRemoveAt then_ i)) - (let new_else (TupleRemoveAt else_ i)) - (let new_if (If pred inputs new_then new_else)) - - (union (Get if i) pred) - (union (TupleRemoveAt if i) new_if) - (subsume (If pred inputs then_ else_))) - :ruleset always-run) - -;; ORIGINAL -;; a = 0 -;; c = 3 -;; for i = 0 to n: -;; a = i * c -;; -;; OPTIMIZED -;; a = 0 -;; c = 3 -;; d = 0 -;; for i = 0 to n: -;; a += d -;; d += c -(ruleset loop-strength-reduction) - -; Finds invariants/constants within a body. -; Columns: body; value of invariant in inputs; value of invariant in outputs -;; Get the input and output value of an invariant, or constant int, within the loop -;; loop in out -(relation lsr-inv (Expr Expr Expr)) - -; TODO: there may be a bug with finding the invariant, or it just may not be extracted. -; Can make this work on loop_with_mul_by_inv and a rust test later. -; (rule ( -; (= loop (DoWhile inputs pred-and-body)) -; (= (Get outputs (+ i 1)) (Get (Arg arg-type assm) i))) -; ((inv loop (Get inputs i) (Get (Arg arg-type assm) i))) :ruleset always-run) -(rule ( - (= loop (DoWhile inputs pred-and-body)) - (ContextOf inputs loop-input-ctx) - (ContextOf pred-and-body loop-output-ctx) - (= constant (Const c out-type loop-output-ctx)) - (HasArgType inputs in-type) - ) - ((lsr-inv loop (Const c in-type loop-input-ctx) constant)) :ruleset always-run) - -(rule - ( - ;; Find loop - (= old-loop (DoWhile inputs pred-and-outputs)) - (ContextOf pred-and-outputs loop-ctx) - - ; Find loop variable (argument that gets incremented with an invariant) - (lsr-inv old-loop loop-incr-in loop-incr-out) - ; Since the first el of pred-and-outputs is the pred, we need to offset i - (= (Get pred-and-outputs (+ i 1)) (Bop (Add) (Get (Arg arg-type assm) i) loop-incr-out)) - - ; Find invariant where input is same as output, or constant - (lsr-inv old-loop c-in c-out) - - ; Find multiplication of loop variable and invariant - (= old-mul (Bop (Mul) c-out (Get (Arg arg-type assm) i))) - (ContextOf old-mul loop-ctx) - - (= arg-type (TupleT ty-list)) - ) - ( - ; Each time we need to update d by the product of the multiplied constant and the loop increment - (let addend (Bop (Mul) c-out loop-incr-out)) - - ; n is index of our new, temporary variable d - (let n (tuple-length inputs)) - - ; Initial value of d is i * c - (let d-init (Bop (Mul) c-in (Get inputs i))) - - ; Construct optimized theta - ; new-inputs already has the correct context - (let new-inputs (Concat inputs (Single d-init))) - - ; We need to create a new type, with one more input - (let new-arg-ty (TupleT (TLConcat ty-list (TCons (IntT) (TNil))))) - - ; Value of d in loop. Add context to addend - (let d-out (Bop (Add) (Get (Arg new-arg-ty (TmpCtx)) n) - (Subst (TmpCtx) (Arg new-arg-ty (TmpCtx)) addend))) - - ; build the old body, making sure to set the correct arg type and context - (let new-body - (Concat - (Subst (TmpCtx) (Arg new-arg-ty (TmpCtx)) pred-and-outputs) - (Single d-out))) - - (let new-loop (DoWhile new-inputs new-body)) - - ; Now that we have the new loop, union the temporary context with the actual ctx - (union (TmpCtx) (InLoop new-inputs new-body)) - - ; Substitute d for the *i expression - (let new-mul - (Bop - (Mul) - (Subst (TmpCtx) (Arg new-arg-ty (TmpCtx)) c-out) - (Get (Arg new-arg-ty (TmpCtx)) i))) - (union (Get (Arg new-arg-ty (TmpCtx)) n) new-mul) - - ; Subsume the multiplication in the new loop to prevent - ; from firing loop strength reduction again on the new loop - (subsume - (Bop - (Mul) - (Subst (TmpCtx) (Arg new-arg-ty (TmpCtx)) c-out) - (Get (Arg new-arg-ty (TmpCtx)) i))) - - ; Project all but last - (union old-loop (SubTuple new-loop 0 n)) - (delete (TmpCtx)) - ) - :ruleset loop-strength-reduction -) -(DoWhile (Concat (Single (Const (Int 0) (TupleT (TNil)) (InFunc "dummy"))) (Single (Const (Int 1) (TupleT (TNil)) (InFunc "dummy")))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 0) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 1))) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 0) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 1))))) - -(If (Bop (LessThan) (Const (Int 0) (TupleT (TNil)) (InFunc "dummy")) (Const (Int 1) (TupleT (TNil)) (InFunc "dummy"))) (Concat (Single (Const (Int 1) (TupleT (TNil)) (InFunc "dummy"))) (Single (Const (Int 1) (TupleT (TNil)) (InFunc "dummy")))) (DoWhile (Concat (Single (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 0)) (Single (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 1))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 0) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 1))) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 0) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 1))))) (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy"))) - - (unstable-combined-ruleset saturating - always-run - canon - type-analysis - context - interval-analysis - memory-helpers - ) - - - (unstable-combined-ruleset optimizations - loop-simplify - memory - loop-unroll - peepholes - ) - - (unstable-combined-ruleset expensive-optimizations - optimizations - ;; TODO why is this expensive? On `adler32.bril` it blows up with 3 iterations - switch_rewrite - ;loop-inv-motion - loop-strength-reduction - ) - - (run-schedule - -;; saturate all helpers first -(saturate - (saturate - (saturate type-helpers) ;; resolve type helpers, finding correct types - (saturate error-checking) ;; check for errors, relies on type-helpers saturating - saturating) - - (saturate drop) - apply-drop-unions - cleanup-drop - - (saturate subst) ;; do e-substitution - apply-subst-unions ;; apply the unions from substitution - cleanup-subst ;; clean up substitutions that are done - - (saturate boundary-analysis) ;; find boundaries of invariants -) - - - loop-peel - (repeat 2 - -;; saturate all helpers first -(saturate - (saturate - (saturate type-helpers) ;; resolve type helpers, finding correct types - (saturate error-checking) ;; check for errors, relies on type-helpers saturating - saturating) - - (saturate drop) - apply-drop-unions - cleanup-drop - - (saturate subst) ;; do e-substitution - apply-subst-unions ;; apply the unions from substitution - cleanup-subst ;; clean up substitutions that are done - - (saturate boundary-analysis) ;; find boundaries of invariants -) - - - expensive-optimizations) - (repeat 4 - -;; saturate all helpers first -(saturate - (saturate - (saturate type-helpers) ;; resolve type helpers, finding correct types - (saturate error-checking) ;; check for errors, relies on type-helpers saturating - saturating) - - (saturate drop) - apply-drop-unions - cleanup-drop - - (saturate subst) ;; do e-substitution - apply-subst-unions ;; apply the unions from substitution - cleanup-subst ;; clean up substitutions that are done - - (saturate boundary-analysis) ;; find boundaries of invariants -) - - - optimizations) - -;; saturate all helpers first -(saturate - (saturate - (saturate type-helpers) ;; resolve type helpers, finding correct types - (saturate error-checking) ;; check for errors, relies on type-helpers saturating - saturating) - - (saturate drop) - apply-drop-unions - cleanup-drop - - (saturate subst) ;; do e-substitution - apply-subst-unions ;; apply the unions from substitution - cleanup-subst ;; clean up substitutions that are done - - (saturate boundary-analysis) ;; find boundaries of invariants -) - -) - - - (query-extract :variants 5 (DoWhile (Concat (Single (Const (Int 0) (TupleT (TNil)) (InFunc "dummy"))) (Single (Const (Int 1) (TupleT (TNil)) (InFunc "dummy")))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 0) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 1))) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 0) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 1)))))) - ;(query-extract :variants 5 (If (Bop (LessThan) (Const (Int 0) (TupleT (TNil)) (InFunc "dummy")) (Const (Int 1) (TupleT (TNil)) (InFunc "dummy"))) (Concat (Single (Const (Int 1) (TupleT (TNil)) (InFunc "dummy"))) (Single (Const (Int 1) (TupleT (TNil)) (InFunc "dummy")))) (DoWhile (Concat (Single (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 0)) (Single (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 1))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 0) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 1))) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 0) (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")) 1))))) (Arg (TupleT (TCons (IntT) (TCons (IntT) (TNil)))) (InFunc "dummy")))) - -;; use these rules to clean up the database, removing helpers -;; this makes the visualization easier to read - - -(rule ((HasType a b)) - ((delete (HasType a b)))) -(rule ((BodyContainsExpr a b)) - ((delete (BodyContainsExpr a b)))) -(rule ((ExprIsPure e)) - ((delete (ExprIsPure e)))) -(rule ((HasArgType e ty)) - ((delete (HasArgType e ty)))) -(rule ((is-inv-Expr e ty)) - ((delete (is-inv-Expr e ty)))) -(rule ((tuple-length e)) - ((delete (tuple-length e)))) -(rule ((BinaryOpIsPure e)) - ((delete (BinaryOpIsPure e)))) -(rule ((TypeList-suffix e a)) - ((delete (TypeList-suffix e a)))) -(rule ((ContextOf e a)) - ((delete (ContextOf e a)))) -(rule ((ExprIsResolved e)) - ((delete (ExprIsResolved e)))) -(run-schedule (saturate (run))) - - Running unittests src/main.rs (target/release/deps/dag_in_context-13fe7a7639e66d94) diff --git a/out.egg b/out.egg deleted file mode 100644 index f8819658a..000000000 --- a/out.egg +++ /dev/null @@ -1,3854 +0,0 @@ -; Every term is an `Expr` or a `ListExpr`. -(datatype Expr) -; Used for constructing a list of branches for `Switch`es -; or a list of functions in a `Program`. -(datatype ListExpr (Cons Expr ListExpr) (Nil)) - -; ================================= -; Types -; ================================= - -(sort TypeList) - -(datatype BaseType - (IntT) - (BoolT) - (FloatT) - ; a pointer to a memory region with a particular type - (PointerT BaseType) - (StateT)) - - -(datatype Type - ; a primitive type - (Base BaseType) - ; a typed tuple. Use an empty tuple as a unit type. - ; state edge also has unit type - (TupleT TypeList) -) - -(function TNil () TypeList) -(function TCons (BaseType TypeList) TypeList) ; Head element should never be a tuple - - -; ================================= -; Assumptions -; ================================= - -(datatype Assumption - ; Assume nothing - (InFunc String) - ; The term is in a loop with `input` and `pred_output`. - ; InLoop is a special context because it describes the argument of the loop. It is a *scope context*. - ; input pred_output - (InLoop Expr Expr) - ; Branch of the switch, and what the predicate is, and what the input is - (InSwitch i64 Expr Expr) - ; If the predicate was true, and what the predicate is, and what the input is - (InIf bool Expr Expr) -) - - - -; ================================= -; Leaf nodes -; Constants, argument, and empty tuple -; ================================= - -; Only a single argument is bound- if multiple values are needed, arg will be a tuple. -; e.g. `(Get (Arg tuple_type) 1)` gets the second value in the argument with some tuple_type. -(function Arg (Type Assumption) Expr) - -; Constants -(datatype Constant - (Int i64) - (Bool bool) - (Float f64)) -; All leaf nodes need the type of the argument -; Type is the type of the bound argument in scope -(function Const (Constant Type Assumption) Expr) - -; An empty tuple. -; Type is the type of the bound argument in scope -(function Empty (Type Assumption) Expr) - - -; ================================= -; Operators -; ================================= - -(datatype TernaryOp - ; given a pointer, value, and a state edge - ; writes the value to the pointer and returns - ; the resulting state edge - (Write) - (Select)) -(datatype BinaryOp - ;; integer operators - (Add) - (Sub) - (Div) - (Mul) - (LessThan) - (GreaterThan) - (LessEq) - (GreaterEq) - (Eq) - ;; float operators - (FAdd) - (FSub) - (FDiv) - (FMul) - (FLessThan) - (FGreaterThan) - (FLessEq) - (FGreaterEq) - (FEq) - ;; logical operators - (And) - (Or) - ; given a pointer and a state edge - ; loads the value at the pointer and returns (value, state edge) - (Load) - ; Takes a pointer and an integer, and offsets - ; the pointer by the integer - (PtrAdd) - ; given and value and a state edge, prints the value as a side-effect - ; the value must be a base value, not a tuple - ; returns an empty tuple - (Print) - ; given a pointer and state edge, frees the whole memory region at the pointer - (Free)) -(datatype UnaryOp - (Not)) - -; Operators -(function Top (TernaryOp Expr Expr Expr) Expr) -(function Bop (BinaryOp Expr Expr) Expr) -(function Uop (UnaryOp Expr) Expr) -; gets from a tuple. static index -(function Get (Expr i64) Expr) -; (Alloc id amount state_edge pointer_type) -; allocate an integer amount of memory for a particular type -; returns (pointer to the allocated memory, state edge) -(function Alloc (i64 Expr Expr BaseType) Expr) -; name of func arg -(function Call (String Expr) Expr) - - - -; ================================= -; Tuple operations -; ================================= - -; `Empty`, `Single` and `Concat` create tuples. -; 1. Use `Empty` for an empty tuple. -; 2. Use `Single` for a tuple with one element. -; 3. Use `Concat` to append the elements from two tuples together. -; Nested tuples are not allowed. - - -; A tuple with a single element. -; Necessary because we only use `Concat` to add to tuples. -(function Single (Expr) Expr) -; Concat appends the elemnts from two tuples together -; e.g. (Concat (Concat (Single a) (Single b)) -; (Concat (Single c) (Single d))) = (a, b, c, d) -; expr1 expr2 -(function Concat (Expr Expr) Expr) - - - -; ================================= -; Control flow -; ================================= - -; Switch on a list of lazily-evaluated branches. -; pred must be an integer -; pred inputs branches chosen -(function Switch (Expr Expr ListExpr) Expr) -; If is like switch, but with a boolean predicate -; pred inputs then else -(function If (Expr Expr Expr Expr) Expr) - - -; A do-while loop. -; Evaluates the input, then evaluates the body. -; Keeps looping while the predicate is true. -; input must have the same type as (output1, output2, ..., outputi) -; input must be a tuple -; pred must be a boolean -; pred-and-body must be a flat tuple (pred, out1, out2, ..., outi) -; input must be the same type as (out1, out2, ..., outi) -; input pred-and-body -(function DoWhile (Expr Expr) Expr) - - -; ================================= -; Top-level expressions -; ================================= -(sort ProgramType) -; An entry function and a list of additional functions. -; entry function other functions -(function Program (Expr ListExpr) ProgramType) -; name input ty output ty output -(function Function (String Type Type Expr) Expr) - - - -; Rulesets -(ruleset always-run) -(ruleset error-checking) -(ruleset memory) -(ruleset memory-helpers) -(ruleset smem) - -;; Initliazation -(relation bop->string (BinaryOp String)) -(relation uop->string (UnaryOp String)) -(relation top->string (TernaryOp String)) -(bop->string (Add) "Add") -(bop->string (Sub) "Sub") -(bop->string (Div) "Div") -(bop->string (Mul) "Mul") -(bop->string (LessThan) "LessThan") -(bop->string (GreaterThan) "GreaterThan") -(bop->string (LessEq) "LessEq") -(bop->string (GreaterEq) "GreaterEq") -(bop->string (Eq) "Eq") -(bop->string (FAdd) "FAdd") -(bop->string (FSub) "FSub") -(bop->string (FDiv) "FDiv") -(bop->string (FMul) "FMul") -(bop->string (FLessThan) "FLessThan") -(bop->string (FGreaterThan) "FGreaterThan") -(bop->string (FLessEq) "FLessEq") -(bop->string (FGreaterEq) "FGreaterEq") -(bop->string (FEq) "FEq") -(bop->string (And) "And") -(bop->string (Or) "Or") -(bop->string (Load) "Load") -(bop->string (PtrAdd) "PtrAdd") -(bop->string (Print) "Print") -(bop->string (Free) "Free") -(ruleset type-analysis) -(ruleset type-helpers) ;; these rules need to saturate between every iter of type-analysis rules - -(function TLConcat (TypeList TypeList) TypeList :unextractable) -(rewrite (TLConcat (TNil) r) r :ruleset type-helpers) -(rewrite (TLConcat (TCons hd tl) r) - (TCons hd (TLConcat tl r)) - :ruleset type-helpers) - -(function TypeList-length (TypeList) i64 :unextractable) -(function TypeList-ith (TypeList i64) BaseType :unextractable) -(function TypeList-suffix (TypeList i64) TypeList :unextractable) - -(rule ((TupleT tylist)) ((union (TypeList-suffix tylist 0) tylist)) :ruleset type-helpers) - -(rule ((= (TypeList-suffix top n) (TCons hd tl))) - ((union (TypeList-ith top n) hd) - (union (TypeList-suffix top (+ n 1)) tl)) :ruleset type-helpers) - -(rule ((= (TypeList-suffix list n) (TNil))) - ((set (TypeList-length list) n)) :ruleset type-helpers) - -(rule ((TypeList-ith list i) - (= (TypeList-length list) n) - (>= i n)) - ((panic "TypeList-ith out of bounds")) :ruleset type-helpers) - -(relation HasType (Expr Type)) - - -;; Keep track of type expectations for error messages -(relation ExpectType (Expr Type String)) -(rule ( - (ExpectType e expected msg) - (HasType e actual) - (!= expected actual) ;; OKAY to compare types for equality because we never union types. - ) - ((extract "Expecting expression") - (extract e) - (extract "to have type") - (extract expected) - (extract "but got type") - (extract actual) - (extract "with message") - (extract msg) - (panic "type mismatch")) - :ruleset error-checking) - -(relation HasArgType (Expr Type)) - -(rule ((HasArgType (Arg t1 ctx) t2) - (!= t1 t2)) - ((panic "arg type mismatch")) - :ruleset error-checking) - -(rule ((= lhs (Function name in out body)) - (HasArgType body ty) - (HasArgType body ty2) - (!= ty ty2)) - ((panic "arg type mismatch in function")) - :ruleset error-checking) - -; Propagate arg types up -(rule ((= lhs (Uop _ e)) - (HasArgType e ty)) - ((HasArgType lhs ty)) - :ruleset type-analysis) -(rule ((= lhs (Bop _ a b)) - (HasArgType a ty)) - ((HasArgType lhs ty)) - :ruleset type-analysis) -(rule ((= lhs (Bop _ a b)) - (HasArgType b ty)) - ((HasArgType lhs ty)) - :ruleset type-analysis) -(rule ((= lhs (Get e _)) - (HasArgType e ty)) - ((HasArgType lhs ty)) - :ruleset type-analysis) -(rule ((= lhs (Alloc _id e state _)) - (HasArgType e ty)) - ((HasArgType lhs ty)) - :ruleset type-analysis) -(rule ((= lhs (Call _ e)) - (HasArgType e ty)) - ((HasArgType lhs ty)) - :ruleset type-analysis) -(rule ((= lhs (Single e)) - (HasArgType e ty)) - ((HasArgType lhs ty)) - :ruleset type-analysis) -(rule ((= lhs (Concat e1 e2)) - (HasArgType e1 ty)) - ((HasArgType lhs ty)) - :ruleset type-analysis) -(rule ((= lhs (Concat e1 e2)) - (HasArgType e2 ty)) - ((HasArgType lhs ty)) - :ruleset type-analysis) -(rule ((= lhs (Switch pred inputs (Cons branch rest))) - (HasArgType pred ty)) - ((HasArgType lhs ty)) - :ruleset type-analysis) -(rule ((= lhs (Switch pred inputs (Cons branch rest))) - (HasArgType branch ty) - (HasType inputs ty2) - (!= ty ty2)) - ((panic "switch branches then branch has incorrect input type")) - :ruleset error-checking) -;; demand with one fewer branches -(rule ((= lhs (Switch pred inputs (Cons branch rest)))) - ((Switch pred inputs rest)) - :ruleset type-analysis) -(rule ((= lhs (If c i t e)) - (HasArgType c ty)) - ((HasArgType lhs ty)) - :ruleset type-analysis) -(rule ((= lhs (If c i t e)) - (HasType i ty) - (HasArgType t ty2) - (!= ty ty2)) - ((panic "if branches then branch has incorrect input type")) - :ruleset error-checking) -(rule ((= lhs (If c i t e)) - (HasType i ty) - (HasArgType e ty2) - (!= ty ty2)) - ((panic "if branches else branch has incorrect input type")) - :ruleset error-checking) - - -(rule ((= lhs (DoWhile ins body)) - (HasArgType ins ty)) - ((HasArgType lhs ty)) - :ruleset type-analysis) -; Don't push arg types through Program, Function, DoWhile, Let exprs because -; these create new arg contexts. - -; Primitives -(rule ((= lhs (Const (Int i) ty ctx))) - ((HasType lhs (Base (IntT))) - (HasArgType lhs ty)) - :ruleset type-analysis) - -(rule ((= lhs (Const (Bool b) ty ctx))) - ((HasType lhs (Base (BoolT))) - (HasArgType lhs ty)) - :ruleset type-analysis) - -(rule ((= lhs (Const (Float b) ty ctx))) - ((HasType lhs (Base (FloatT))) - (HasArgType lhs ty)) - :ruleset type-analysis) - -(rule ((= lhs (Empty ty ctx))) - ((HasType lhs (TupleT (TNil))) - (HasArgType lhs ty)) - :ruleset type-analysis) - -; Unary Ops -(rule ( - (= lhs (Uop (Not) e)) - (HasType e (Base (BoolT))) - ) - ((HasType lhs (Base (BoolT)))) - :ruleset type-analysis) -(rule ((= lhs (Uop (Not) e))) - ((ExpectType e (Base (BoolT)) "(Not)")) - :ruleset type-analysis) - - -(rule ( - (= lhs (Bop (Print) e state)) - (HasType e _ty) ; just make sure it has some type. - ) - ((HasType lhs (Base (StateT)))) - :ruleset type-analysis) - -(rule ( - (= lhs (Bop (Print) e state)) - (HasType e (TupleT ty)) - ) - ((panic "Don't print a tuple")) - :ruleset error-checking) - -(rule ((= lhs (Bop (Free) e s)) - (HasType e (Base (PointerT _ty)))) - ((HasType lhs (Base (StateT)))) - :ruleset type-analysis) -(rule ((= lhs (Bop (Free) e s)) - (HasType e (Base (IntT)))) - ((panic "Free expected pointer, received integer")) - :ruleset error-checking) -(rule ((= lhs (Bop (Free) e s)) - (HasType e (TupleT _ty))) - ((panic "Free expected pointer, received tuple")) - :ruleset error-checking) - -(rule ( - (= lhs (Bop (Load) e state)) - (HasType e (Base (PointerT ty))) - ) - ((HasType lhs (TupleT (TCons ty (TCons (StateT) (TNil)))))) - :ruleset type-analysis) -(rule ( - (= lhs (Bop (Load) e state)) - (HasType e ty) - (= ty (Base (IntT))) - ) - ((panic "(Load) expected pointer, received int")) - :ruleset error-checking) -(rule ( - (= lhs (Bop (Load) e state)) - (HasType e ty) - (= ty (TupleT x)) - ) - ((panic "(Load) expected pointer, received tuple")) - :ruleset error-checking) - -; Binary ops - -;; Operators that have type Type -> Type -> Type -;; Note we only do this generic matching for binary -;; operator since there's a lot of them. -;; In the future we can also extend to other constructs. -(relation bop-of-type (BinaryOp Type)) -(bop-of-type (Add) (Base (IntT))) -(bop-of-type (Sub) (Base (IntT))) -(bop-of-type (Div) (Base (IntT))) -(bop-of-type (Mul) (Base (IntT))) -(bop-of-type (FAdd) (Base (FloatT))) -(bop-of-type (FSub) (Base (FloatT))) -(bop-of-type (FDiv) (Base (FloatT))) -(bop-of-type (FMul) (Base (FloatT))) - -(rule ( - (= lhs (Bop op e1 e2)) - (bop-of-type op ty) - (HasType e1 ty) - (HasType e2 ty) - ) - ((HasType lhs ty)) - :ruleset type-analysis) -(rule ((= lhs (Bop op e1 e2)) - (bop-of-type op ty) - (bop->string op op-str)) - ( - (ExpectType e1 ty op-str) - (ExpectType e2 ty op-str) - ) - :ruleset type-analysis) - -;; Operators that have type Float -> Float -> Bool -(relation bpred-of-type (BinaryOp Type)) -(bpred-of-type (FLessThan) (Base (FloatT))) -(bpred-of-type (FLessEq) (Base (FloatT))) -(bpred-of-type (FGreaterThan) (Base (FloatT))) -(bpred-of-type (FGreaterEq) (Base (FloatT))) -(bpred-of-type (FEq) (Base (FloatT))) -(bpred-of-type (LessThan) (Base (IntT))) -(bpred-of-type (LessEq) (Base (IntT))) -(bpred-of-type (GreaterThan) (Base (IntT))) -(bpred-of-type (GreaterEq) (Base (IntT))) -(bpred-of-type (Eq) (Base (IntT))) -(bpred-of-type (And) (Base (BoolT))) -(bpred-of-type (Or) (Base (BoolT))) - -(rule ( - (= lhs (Bop pred e1 e2)) - (bpred-of-type pred ty) - (HasType e1 ty) - (HasType e2 ty) - ) - ((HasType lhs (Base (BoolT)))) - :ruleset type-analysis) -(rule ((= lhs (Bop pred e1 e2)) - (bpred-of-type pred ty) - (bop->string pred pred-str)) - ( - (ExpectType e1 ty pred-str) - (ExpectType e2 ty pred-str) - ) - :ruleset type-analysis) - -(rule ( - (= lhs (Top (Write) ptr val state)) - (HasType ptr (Base (PointerT ty))) - (HasType val (Base t)) ; TODO need to support pointers to pointers - ) - ((HasType lhs (Base (StateT)))) ; Write returns () - :ruleset type-analysis) - -(rule ( - (= lhs (Top (Write) ptr val state)) - (HasType ptr (Base (PointerT ty)))) - ((ExpectType val (Base ty) "(Write)")) - :ruleset type-analysis) - - - -(rule ( - (= lhs (Bop (PtrAdd) ptr n)) - (HasType ptr (Base (PointerT ty))) - (HasType n (Base (IntT))) - ) - ((HasType lhs (Base (PointerT ty)))) - :ruleset type-analysis) - -; Other ops -(rule ((= lhs (Alloc _id amt state ty))) - ((ExpectType amt (Base (IntT)) "(Alloc)")) - :ruleset type-analysis) - -(rule ( - (= lhs (Alloc _id amt state ty)) - (HasType amt (Base (IntT))) - ) - ((HasType lhs (TupleT (TCons ty (TCons (StateT) (TNil)))))) - :ruleset type-analysis) - -(rule ( - (= lhs (Get e i)) - (HasType e (TupleT tylist)) - ) - ; TypeList-ith needs to compute immediately, so we need to saturate type-helpers - ; rules between every iter of type-analysis rules. - ((HasType lhs (Base (TypeList-ith tylist i)))) - :ruleset type-analysis) - -(rule ( - (HasType (Get expr i) (TupleT tl)) - (= (TypeList-length tl) len) - (>= i len)) - ((panic "index out of bounds")) - :ruleset error-checking) -(rule ( - (HasType (Get expr i) (TupleT tl)) - (= (TypeList-length tl) len) - (< i 0) - ) - ((panic "negative index")) - :ruleset error-checking) - -; ================================= -; Tuple operations -; ================================= - -(rule ( - (= lhs (Single e)) - (HasType e (TupleT tylist)) - ) - ((panic "don't nest tuples")) - :ruleset error-checking) - -(rule ( - (= lhs (Single e)) - (HasType e (Base basety)) - ) - ((HasType lhs (TupleT (TCons basety (TNil))))) - :ruleset type-analysis) - -(rule ( - (= lhs (Concat e1 e2)) - (HasType e1 (TupleT tylist1)) - (HasType e2 (TupleT tylist2)) - ) - ; TLConcat needs to compute immediately, so we need to saturate type-helpers - ; rules between every iter of type-analysis rules. - ((HasType lhs (TupleT (TLConcat tylist1 tylist2)))) - :ruleset type-analysis) - -; ================================= -; Control flow -; ================================= -(rule ((= lhs (If pred inputs then else))) - ((ExpectType pred (Base (BoolT)) "If predicate must be boolean")) - :ruleset type-analysis) -(rule ( - (= lhs (If pred inputs then else)) - (HasType pred (Base (BoolT))) - (HasType then ty) - (HasType else ty) - ) - ((HasType lhs ty)) - :ruleset type-analysis) - -(rule ( - (= lhs (If pred inputs then else)) - (HasType pred (Base (BoolT))) - (HasType then tya) - (HasType else tyb) - (!= tya tyb) - ) - ((panic "if branches had different types")) - :ruleset error-checking) - - - -(rule ((= lhs (Switch pred inputs branches))) - ((ExpectType pred (Base (IntT)) "Switch predicate must be integer")) - :ruleset type-analysis) - -; base case: single branch switch has type of branch -(rule ( - (= lhs (Switch pred inputs (Cons branch (Nil)))) - (HasType pred (Base (IntT))) - (HasType branch ty) - ) - ((HasType lhs ty)) - :ruleset type-analysis) - -; recursive case: peel off a layer -(rule ((Switch pred inputs (Cons branch rest))) - ((Switch pred inputs rest)) - :ruleset type-analysis) - -(rule ( - (= lhs (Switch pred inputs (Cons branch rest))) - (HasType pred (Base (IntT))) - (HasType branch ty) - (HasType (Switch pred inputs rest) ty) ; rest of the branches also have type ty - ) - ((HasType lhs ty)) - :ruleset type-analysis) - -(rule ( - (= lhs (Switch pred inputs (Cons branch rest))) - (HasType pred (Base (IntT))) - (HasType branch tya) - (HasType (Switch pred inputs rest) tyb) - (!= tya tyb) - ) - ((panic "switch branches had different types")) - :ruleset error-checking) - -(rule ((Arg ty ctx)) - ( - (HasType (Arg ty ctx) ty) - (HasArgType (Arg ty ctx) ty) - ) - :ruleset type-analysis) - - -(rule ( - (= lhs (DoWhile inp pred-body)) - (HasType inp (Base ty)) - ) - ((panic "loop input must be tuple")) - :ruleset error-checking) -(rule ( - (= lhs (DoWhile inp pred-body)) - (HasType inp (Base (PointerT ty))) - ) - ((panic "loop input must be tuple")) - :ruleset error-checking) -(rule ( - (= lhs (DoWhile inp pred-body)) - (HasType pred-body (Base ty)) - ) - ((panic "loop pred-body must be tuple")) - :ruleset error-checking) -(rule ( - (= lhs (DoWhile inp pred-body)) - (HasType pred-body (Base (PointerT ty))) - ) - ((panic "loop pred-body must be tuple")) - :ruleset error-checking) - -(rule ( - (= lhs (DoWhile inp pred-body)) - (HasType inp (TupleT tylist)) - ) - ((HasArgType pred-body (TupleT tylist))) - :ruleset type-analysis) - -(rule ((= lhs (DoWhile inp pred-body))) - ((ExpectType (Get pred-body 0) (Base (BoolT)) "loop pred must be bool")) - :ruleset type-analysis) - -(rule ( - (= lhs (DoWhile inp pred-body)) - (HasType inp (TupleT tylist)) ; input is a tuple - ; pred-body is a tuple where the first elt is a bool - ; and the rest of the list matches the input type - (HasType pred-body (TupleT (TCons (BoolT) tylist))) - ) - ((HasType lhs (TupleT tylist))) ; whole thing has type of inputs/outputs - :ruleset type-analysis) - -(rule ( - (= lhs (DoWhile inp pred-body)) - (HasType inp (TupleT in-tys)) - (HasType pred-body (TupleT (TCons (BoolT) out-tys))) - (!= in-tys out-tys) - ) - ((panic "input types and output types don't match")) - :ruleset error-checking) - -; ================================= -; Functions -; ================================= - -(rule ((= lhs (Function name in-ty out-ty body))) - ( - ; Arg should have the specified type in the body - (HasArgType body in-ty) - ; Expect the body to have the specified output type - (ExpectType body out-ty "Function body had wrong type") - ) - :ruleset type-analysis) - -(rule ( - (= lhs (Call name arg)) - (Function name in-ty out-ty body) - ) - ; Expect the arg to have the right type for the function - ((ExpectType arg in-ty "function called with wrong arg type")) - :ruleset type-analysis) - -(rule ( - (= lhs (Call name arg)) - (Function name in-ty out-ty body) - (HasType arg in-ty) - ; We don't need to check the type of the function body, it will - ; be checked elsewhere. If we did require (HasType body out-ty), - ; recursive functions would not get assigned a type. - ) - ((HasType lhs out-ty)) - :ruleset type-analysis) - -; find which types are pure -(relation PureBaseType (BaseType)) -(relation PureType (Type)) -(relation PureTypeList (TypeList)) - -(PureBaseType (IntT)) -(PureBaseType (BoolT)) -(rule ((Base ty) - (PureBaseType ty)) - ((PureType (Base ty))) - :ruleset type-analysis) -(rule ((TupleT tylist) - (PureTypeList tylist)) - ((PureType (TupleT tylist))) - :ruleset type-analysis) -(rule ((TNil)) - ((PureTypeList (TNil))) - :ruleset type-analysis) -(rule ((TCons hd tl) - (PureBaseType hd) - (PureTypeList tl)) - ((PureTypeList (TCons hd tl))) - :ruleset type-analysis) - -(function ListExpr-length (ListExpr) i64) -(function ListExpr-ith (ListExpr i64) Expr :unextractable) -(function ListExpr-suffix (ListExpr i64) ListExpr :unextractable) -(function Append (ListExpr Expr) ListExpr :unextractable) - -(rule ((Switch pred inputs branch)) ((union (ListExpr-suffix branch 0) branch)) :ruleset always-run) - -(rule ((= (ListExpr-suffix top n) (Cons hd tl))) - ((union (ListExpr-ith top n) hd) - (union (ListExpr-suffix top (+ n 1)) tl)) :ruleset always-run) - -(rule ((= (ListExpr-suffix list n) (Nil))) - ((set (ListExpr-length list) n)) :ruleset always-run) - -(rewrite (Append (Cons a b) e) - (Cons a (Append b e)) - :ruleset always-run) -(rewrite (Append (Nil) e) - (Cons e (Nil)) - :ruleset always-run) - -(function tuple-length (Expr) i64 :unextractable) - -(rule ((HasType expr (TupleT tl)) - (= len (TypeList-length tl))) - ((set (tuple-length expr) len)) :ruleset always-run) - -;; Create a Get for every index, and rewrite it to see through Concat -(rule ((Single expr)) ((union (Get (Single expr) 0) expr)) :ruleset always-run) -;; initial get -(rule ((> (tuple-length tuple) 0)) - ((Get tuple 0)) - :ruleset always-run) -;; next get -(rule ((= len (tuple-length tuple)) - (= ith (Get tuple i)) - (< (+ i 1) len) - ) - ((Get tuple (+ 1 i))) - :ruleset always-run) - -;; descend left -(rule ((Get (Concat expr1 expr2) i) - (= (tuple-length expr1) len1) - (< i len1)) - ((union (Get (Concat expr1 expr2) i) - (Get expr1 i))) - :ruleset always-run) -;; descend right -(rule ((Get (Concat expr1 expr2) i) - (= (tuple-length expr1) len1) - (>= i len1)) - ((union (Get (Concat expr1 expr2) i) - (Get expr2 (- i len1)))) - :ruleset always-run) - - -;; A temporary context. -;; Be sure to delete at the end of all actions or else!!! -;; This is safer than using a persistant context, since we may miss an important part of the query. -(function TmpCtx () Assumption) - -(rule ((TmpCtx)) - ((panic "TmpCtx should not exist outside rule body")) - :ruleset always-run) - - -(ruleset subsume-after-helpers) -;; After running the `saturating` ruleset, these if statements can be subsumed -(relation ToSubsumeIf (Expr Expr Expr Expr)) -; (rule ((ToSubsumeIf a b c d)) -; ((subsume (If a b c d))) -; :ruleset subsume-after-helpers) - - - -(relation ExprIsValid (Expr)) -(relation ListExprIsValid (ListExpr)) -(rule ((ExprIsValid (Function _name _tyin _tyout _out))) ((ExprIsValid _out)) :ruleset always-run) -(rule ((ExprIsValid (Top _op _x _y _z))) ((ExprIsValid _x) -(ExprIsValid _y) -(ExprIsValid _z)) :ruleset always-run) -(rule ((ExprIsValid (Bop _op _x _y))) ((ExprIsValid _x) -(ExprIsValid _y)) :ruleset always-run) -(rule ((ExprIsValid (Uop _op _x))) ((ExprIsValid _x)) :ruleset always-run) -(rule ((ExprIsValid (Get _tup _i))) ((ExprIsValid _tup)) :ruleset always-run) -(rule ((ExprIsValid (Concat _x _y))) ((ExprIsValid _x) -(ExprIsValid _y)) :ruleset always-run) -(rule ((ExprIsValid (Single _x))) ((ExprIsValid _x)) :ruleset always-run) -(rule ((ExprIsValid (Switch _pred _inputs _branches))) ((ExprIsValid _pred) -(ExprIsValid _inputs) -(ListExprIsValid _branches)) :ruleset always-run) -(rule ((ExprIsValid (If _pred _input _then _else))) ((ExprIsValid _pred) -(ExprIsValid _input) -(ExprIsValid _then) -(ExprIsValid _else)) :ruleset always-run) -(rule ((ExprIsValid (DoWhile _in _pred-and-output))) ((ExprIsValid _in) -(ExprIsValid _pred-and-output)) :ruleset always-run) -(rule ((ExprIsValid (Call _func _arg))) ((ExprIsValid _arg)) :ruleset always-run) -(rule ((ListExprIsValid (Cons _hd _tl))) ((ExprIsValid _hd) -(ListExprIsValid _tl)) :ruleset always-run) -(rule ((ExprIsValid (Alloc _id _e _state _ty))) ((ExprIsValid _e) -(ExprIsValid _state)) :ruleset always-run) -(relation ExprIsResolved (Expr)) -(relation ListExprIsResolved (ListExpr)) -(rule ((= lhs (Function _name _tyin _tyout _out)) (ExprIsResolved _out)) ((ExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (Const _n _ty _ctx)) ) ((ExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (Top _op _x _y _z)) (ExprIsResolved _x) -(ExprIsResolved _y) -(ExprIsResolved _z)) ((ExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (Bop _op _x _y)) (ExprIsResolved _x) -(ExprIsResolved _y)) ((ExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (Uop _op _x)) (ExprIsResolved _x)) ((ExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (Get _tup _i)) (ExprIsResolved _tup)) ((ExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (Concat _x _y)) (ExprIsResolved _x) -(ExprIsResolved _y)) ((ExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (Single _x)) (ExprIsResolved _x)) ((ExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (Switch _pred _inputs _branches)) (ExprIsResolved _pred) -(ExprIsResolved _inputs) -(ListExprIsResolved _branches)) ((ExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (If _pred _input _then _else)) (ExprIsResolved _pred) -(ExprIsResolved _input) -(ExprIsResolved _then) -(ExprIsResolved _else)) ((ExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (DoWhile _in _pred-and-output)) (ExprIsResolved _in) -(ExprIsResolved _pred-and-output)) ((ExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (Arg _ty _ctx)) ) ((ExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (Call _func _arg)) (ExprIsResolved _arg)) ((ExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (Empty _ty _ctx)) ) ((ExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (Cons _hd _tl)) (ExprIsResolved _hd) -(ListExprIsResolved _tl)) ((ListExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (Nil)) ) ((ListExprIsResolved lhs)) :ruleset always-run) -(rule ((= lhs (Alloc _id _e _state _ty)) (ExprIsResolved _e) -(ExprIsResolved _state)) ((ExprIsResolved lhs)) :ruleset always-run) -(relation BodyContainsExpr (Expr Expr)) -(relation BodyContainsListExpr (Expr ListExpr)) -(rule ((Function _name _tyin _tyout _out)) ((BodyContainsExpr (Function _name _tyin _tyout _out) _out)) :ruleset always-run) -(rule ((If _pred _input _then _else)) ((BodyContainsExpr (If _pred _input _then _else) _then) (BodyContainsExpr (If _pred _input _then _else) _else)) :ruleset always-run) -(rule ((DoWhile _in _pred-and-output)) ((BodyContainsExpr (DoWhile _in _pred-and-output) _pred-and-output)) :ruleset always-run) -(rule ((BodyContainsExpr body (Top _op _x _y _z))) ((BodyContainsExpr body _x) (BodyContainsExpr body _y) (BodyContainsExpr body _z)) :ruleset always-run) -(rule ((BodyContainsExpr body (Bop _op _x _y))) ((BodyContainsExpr body _x) (BodyContainsExpr body _y)) :ruleset always-run) -(rule ((BodyContainsExpr body (Uop _op _x))) ((BodyContainsExpr body _x)) :ruleset always-run) -(rule ((BodyContainsExpr body (Get _tup _i))) ((BodyContainsExpr body _tup)) :ruleset always-run) -(rule ((BodyContainsExpr body (Concat _x _y))) ((BodyContainsExpr body _x) (BodyContainsExpr body _y)) :ruleset always-run) -(rule ((BodyContainsExpr body (Single _x))) ((BodyContainsExpr body _x)) :ruleset always-run) -(rule ((BodyContainsExpr body (Switch _pred _inputs _branches))) ((BodyContainsExpr body _pred) (BodyContainsExpr body _inputs)) :ruleset always-run) -(rule ((BodyContainsExpr body (If _pred _input _then _else))) ((BodyContainsExpr body _pred) (BodyContainsExpr body _input)) :ruleset always-run) -(rule ((BodyContainsExpr body (DoWhile _in _pred-and-output))) ((BodyContainsExpr body _in)) :ruleset always-run) -(rule ((BodyContainsExpr body (Call _func _arg))) ((BodyContainsExpr body _arg)) :ruleset always-run) -(rule ((BodyContainsListExpr body (Cons _hd _tl))) ((BodyContainsExpr body _hd)) :ruleset always-run) -(rule ((BodyContainsExpr body (Alloc _id _e _state _ty))) ((BodyContainsExpr body _e) (BodyContainsExpr body _state)) :ruleset always-run) - - (relation ExprIsPure (Expr)) - (relation ListExprIsPure (ListExpr)) - (relation BinaryOpIsPure (BinaryOp)) - (relation UnaryOpIsPure (UnaryOp)) - (relation TopIsPure (TernaryOp)) -(TopIsPure (Select)) -(BinaryOpIsPure (Add)) -(BinaryOpIsPure (Sub)) -(BinaryOpIsPure (Mul)) -(BinaryOpIsPure (Div)) -(BinaryOpIsPure (Eq)) -(BinaryOpIsPure (LessThan)) -(BinaryOpIsPure (GreaterThan)) -(BinaryOpIsPure (LessEq)) -(BinaryOpIsPure (GreaterEq)) -(BinaryOpIsPure (FAdd)) -(BinaryOpIsPure (FSub)) -(BinaryOpIsPure (FMul)) -(BinaryOpIsPure (FDiv)) -(BinaryOpIsPure (FEq)) -(BinaryOpIsPure (FLessThan)) -(BinaryOpIsPure (FGreaterThan)) -(BinaryOpIsPure (FLessEq)) -(BinaryOpIsPure (FGreaterEq)) -(BinaryOpIsPure (And)) -(BinaryOpIsPure (Or)) -(BinaryOpIsPure (PtrAdd)) -(UnaryOpIsPure (Not)) - - (rule ((Function _name _tyin _tyout _out) (ExprIsPure _out)) - ((ExprIsPure (Function _name _tyin _tyout _out))) - :ruleset always-run) - - (rule ((Const _n _ty _ctx)) - ((ExprIsPure (Const _n _ty _ctx))) - :ruleset always-run) - - (rule ((Top _op _x _y _z) (ExprIsPure _x) (ExprIsPure _y) (ExprIsPure _z)) - ((ExprIsPure (Top _op _x _y _z))) - :ruleset always-run) - - (rule ((Bop _op _x _y) (BinaryOpIsPure _op) (ExprIsPure _x) (ExprIsPure _y)) - ((ExprIsPure (Bop _op _x _y))) - :ruleset always-run) - - (rule ((Uop _op _x) (UnaryOpIsPure _op) (ExprIsPure _x)) - ((ExprIsPure (Uop _op _x))) - :ruleset always-run) - - (rule ((Get _tup _i) (ExprIsPure _tup)) - ((ExprIsPure (Get _tup _i))) - :ruleset always-run) - - (rule ((Concat _x _y) (ExprIsPure _x) (ExprIsPure _y)) - ((ExprIsPure (Concat _x _y))) - :ruleset always-run) - - (rule ((Single _x) (ExprIsPure _x)) - ((ExprIsPure (Single _x))) - :ruleset always-run) - - (rule ((Switch _pred _inputs _branches) (ExprIsPure _pred) (ExprIsPure _inputs) (ListExprIsPure _branches)) - ((ExprIsPure (Switch _pred _inputs _branches))) - :ruleset always-run) - - (rule ((If _pred _input _then _else) (ExprIsPure _pred) (ExprIsPure _input) (ExprIsPure _then) (ExprIsPure _else)) - ((ExprIsPure (If _pred _input _then _else))) - :ruleset always-run) - - (rule ((DoWhile _in _pred-and-output) (ExprIsPure _in) (ExprIsPure _pred-and-output)) - ((ExprIsPure (DoWhile _in _pred-and-output))) - :ruleset always-run) - - (rule ((Arg _ty _ctx)) - ((ExprIsPure (Arg _ty _ctx))) - :ruleset always-run) - - (rule ((Call _f _arg) (ExprIsPure _arg) (ExprIsPure (Function _f inty outty out))) - ((ExprIsPure (Call _f _arg))) - :ruleset always-run) - - (rule ((Empty _ty _ctx)) - ((ExprIsPure (Empty _ty _ctx))) - :ruleset always-run) - - (rule ((Cons _hd _tl) (ExprIsPure _hd) (ListExprIsPure _tl)) - ((ListExprIsPure (Cons _hd _tl))) - :ruleset always-run) - - (rule ((Nil)) - ((ListExprIsPure (Nil))) - :ruleset always-run) - -; This file provides AddContext, a helpers that copies a sub-egraph into -; a new one with a new context. -; Users of AddContext can specify how deeply to do this copy. - - -(ruleset context) - -(function AddContext (Assumption Expr) Expr :unextractable) -(function AddContextList (Assumption ListExpr) ListExpr :unextractable) - -;; ################################ saturation - -;; Adding context a second time does nothing, so union -(rule - ((= lhs (AddContext ctx inner)) - (= inner (AddContext ctx expr))) - ((union lhs inner)) - :ruleset context) - - -;; ############################## Base cases- leaf nodes - -;; replace existing contexts that are around leaf nodes -;; AddContext assumes the new context is more specific than the old one -(rule ((= lhs (AddContext ctx (Arg ty oldctx)))) - ((union lhs (Arg ty ctx))) - :ruleset context) -(rule ((= lhs (AddContext ctx (Const c ty oldctx)))) - ((union lhs (Const c ty ctx))) - :ruleset context) -(rule ((= lhs (AddContext ctx (Empty ty oldctx)))) - ((union lhs (Empty ty ctx))) - :ruleset context) - - - - -;; ######################################### Operators -(rewrite (AddContext ctx (Bop op c1 c2)) - (Bop op - (AddContext ctx c1) - (AddContext ctx c2)) - :ruleset context) -(rewrite (AddContext ctx (Uop op c1)) - (Uop op (AddContext ctx c1)) - :ruleset context) -(rewrite (AddContext ctx (Get c1 index)) - (Get (AddContext ctx c1) index) - :ruleset context) -(rewrite (AddContext ctx (Alloc id c1 state ty)) - (Alloc id (AddContext ctx c1) (AddContext ctx state) ty) - :ruleset context) -(rewrite (AddContext ctx (Call name c1)) - (Call name (AddContext ctx c1)) - :ruleset context) - -(rewrite (AddContext ctx (Single c1)) - (Single (AddContext ctx c1)) - :ruleset context) -(rewrite (AddContext ctx (Concat c1 c2)) - (Concat - (AddContext ctx c1) - (AddContext ctx c2)) - :ruleset context) - -;; ################################### List operators - -(rewrite (AddContextList ctx (Nil)) - (Nil) - :ruleset context) - -(rewrite (AddContextList ctx (Cons c1 rest)) - (Cons (AddContext ctx c1) - (AddContextList ctx rest)) - :ruleset context) - - -;; ########################################## Control flow -(rewrite (AddContext ctx (Switch pred inputs branches)) - (Switch (AddContext ctx pred) - (AddContext ctx inputs) - branches) - :ruleset context) - -;; For stop at region, still add context to inputs -(rule ((= lhs (AddContext ctx (If pred inputs c1 c2)))) - ((union lhs - (If (AddContext ctx pred) - (AddContext ctx inputs) - c1 - c2))) - :ruleset context) - - -;; For stop at loop, still add context to inputs -(rule ((= lhs (AddContext ctx (DoWhile inputs outputs)))) - ((union lhs - (DoWhile - (AddContext ctx inputs) - outputs))) - :ruleset context) - - -;; Substitution rules allow for substituting some new expression for the argument -;; in some new context. -;; It performs the substitution, copying over the equalities from the original eclass. -;; It only places context on the leaf nodes. - -(ruleset subst) -(ruleset apply-subst-unions) -(ruleset cleanup-subst) - -;; (Subst assumption to in) substitutes `to` for `(Arg ty)` in `in`. -;; It also replaces the leaf context in `to` with `assumption` using `AddContext`. -;; `assumption` *justifies* this substitution, as the context that the result is used in. -;; In other words, it must refine the equivalence relation of `in` with `to` as the argument. -(function Subst (Assumption Expr Expr) Expr ) - -;; Used to delay unions for the subst ruleset. -;; This is necessary because substitution may not terminate if it can -;; observe its own results- it may create infinitly large terms. -;; Instead, we phase substitution by delaying resulting unions in this table. -;; After applying this table, substitutions and this table are cleared. -(function DelayedSubstUnion (Expr Expr) Expr ) - -;; add a type rule to get the arg type of a substitution -;; this enables nested substitutions -(rule ((= lhs (Subst assum to in)) - (HasArgType to ty)) - ((HasArgType lhs ty)) - :ruleset subst) - -;; leaf node with context -;; replace this context- subst assumes the context is more specific -(rule ((= lhs (Subst assum to (Arg ty oldctx))) - ) - ;; add the assumption `to` - ((DelayedSubstUnion lhs (AddContext assum to))) - :ruleset subst) -(rule ((= lhs (Subst assum to (Const c ty oldctx))) - (HasArgType to newty)) - ((DelayedSubstUnion lhs (Const c newty assum))) - :ruleset subst) -(rule ((= lhs (Subst assum to (Empty ty oldctx))) - (HasArgType to newty)) - ((DelayedSubstUnion lhs (Empty newty assum))) - :ruleset subst) - -;; Operators -(rule ((= lhs (Subst assum to (Bop op c1 c2))) - (ExprIsResolved (Bop op c1 c2))) - ((DelayedSubstUnion lhs - (Bop op (Subst assum to c1) - (Subst assum to c2)))) - :ruleset subst) -(rule ((= lhs (Subst assum to (Uop op c1))) - (ExprIsResolved (Uop op c1))) - ((DelayedSubstUnion lhs - (Uop op (Subst assum to c1)))) - :ruleset subst) - -(rule ((= lhs (Subst assum to (Get c1 index))) - (ExprIsResolved (Get c1 index))) - ((DelayedSubstUnion lhs - (Get (Subst assum to c1) index))) - :ruleset subst) -(rule ((= lhs (Subst assum to (Alloc id c1 c2 ty))) - (ExprIsResolved (Alloc id c1 c2 ty))) - ((DelayedSubstUnion lhs - (Alloc id (Subst assum to c1) - (Subst assum to c2) - ty))) - :ruleset subst) -(rule ((= lhs (Subst assum to (Call name c1))) - (ExprIsResolved (Call name c1))) - ((DelayedSubstUnion lhs - (Call name (Subst assum to c1)))) - :ruleset subst) - - -;; Tuple operators -(rule ((= lhs (Subst assum to (Single c1))) - (ExprIsResolved (Single c1))) - ((DelayedSubstUnion lhs - (Single (Subst assum to c1)))) - :ruleset subst) -(rule ((= lhs (Subst assum to (Concat c1 c2))) - (ExprIsResolved (Concat c1 c2))) - ((DelayedSubstUnion lhs - (Concat (Subst assum to c1) - (Subst assum to c2)))) - :ruleset subst) - -;; Control flow -(rule ((= lhs (Subst assum to inner)) - (= inner (Switch pred inputs c1)) - (ExprIsResolved inner)) - ((DelayedSubstUnion lhs - (Switch (Subst assum to pred) - (Subst assum to inputs) - c1))) - :ruleset subst) -(rule ((= lhs (Subst assum to inner)) - (= inner (If pred inputs c1 c2)) - (ExprIsResolved inner)) - ((DelayedSubstUnion lhs - (If (Subst assum to pred) - (Subst assum to inputs) - c1 - c2))) - :ruleset subst) -(rule ((= lhs (Subst assum to (DoWhile in out))) - (ExprIsResolved (DoWhile in out))) - ((DelayedSubstUnion lhs - (DoWhile (Subst assum to in) - out))) - :ruleset subst) - -;; substitute into function (convenience for testing) -(rewrite (Subst assum to (Function name inty outty body)) - (Function name inty outty (Subst assum to body)) - :when ((ExprIsResolved body)) - :ruleset subst) - - - -;; ########################### Apply subst unions - -(rule ((DelayedSubstUnion lhs rhs)) - ((union lhs rhs)) - :ruleset apply-subst-unions) - - -;; ########################### Cleanup subst and DelayedSubstUnion - -(rule ((DelayedSubstUnion lhs rhs)) - ((subsume (DelayedSubstUnion lhs rhs))) - :ruleset cleanup-subst) - -; this cleanup is important- if we don't subsume these substitutions, they -; may oberve their own results and create infinitely sized terms. -; ex: get(parallel!(arg(), int(2)), 0) ignores the first element of the tuple -; so it's equivalent to infinite other times with any other value as the first element of the tuple. -; Check ExprIsResolved to confirm that the substitution finished (all sub-substitutions are done). -(rule ((ExprIsResolved (Subst assum to in))) - ((subsume (Subst assum to in))) - :ruleset cleanup-subst) - -; We only have context for Exprs, not ListExprs. -(relation ContextOf (Expr Assumption)) - -(rule ((Arg ty ctx)) - ((ContextOf (Arg ty ctx) ctx)) - :ruleset always-run) -(rule ((Const c ty ctx)) - ((ContextOf (Const c ty ctx) ctx)) - :ruleset always-run) -(rule ((Empty ty ctx)) - ((ContextOf (Empty ty ctx) ctx)) - :ruleset always-run) - -; Error checking - each expr should only have a single context -(rule ((ContextOf x ctx1) - (ContextOf x ctx2) - (!= ctx1 ctx2)) - ( - (panic "Equivalent expressions have nonequivalent context, breaking the single context invariant.") - ) - :ruleset error-checking) - - -(rule ((Top op x y z) (ContextOf x ctx)) - ((ContextOf (Top op x y z) ctx)) :ruleset always-run) - -(rule ((Top op x y z) (ContextOf y ctx)) - ((ContextOf (Top op x y z) ctx)) :ruleset always-run) - -(rule ((Top op x y z) (ContextOf z ctx)) - ((ContextOf (Top op x y z) ctx)) :ruleset always-run) - -(rule ((Bop op x y) (ContextOf x ctx)) - ((ContextOf (Bop op x y) ctx)) :ruleset always-run) - -(rule ((Bop op x y) (ContextOf y ctx)) - ((ContextOf (Bop op x y) ctx)) :ruleset always-run) - -(rule ((Uop op x) (ContextOf x ctx)) - ((ContextOf (Uop op x) ctx)) :ruleset always-run) - -(rule ((Get tup i) (ContextOf tup ctx)) - ((ContextOf (Get tup i) ctx)) :ruleset always-run) - -(rule ((Concat x y) (ContextOf x ctx)) - ((ContextOf (Concat x y) ctx)) :ruleset always-run) - -(rule ((Concat x y) (ContextOf y ctx)) - ((ContextOf (Concat x y) ctx)) :ruleset always-run) - -(rule ((Single x) (ContextOf x ctx)) - ((ContextOf (Single x) ctx)) :ruleset always-run) - -(rule ((Switch pred inputs branches) (ContextOf pred ctx)) - ((ContextOf (Switch pred inputs branches) ctx)) :ruleset always-run) - -(rule ((If pred inputs then else) (ContextOf pred ctx)) - ((ContextOf (If pred inputs then else) ctx)) :ruleset always-run) - -(rule ((If pred inputs then else) (ContextOf inputs ctx)) - ((ContextOf (If pred inputs then else) ctx)) :ruleset always-run) - -(rule ((DoWhile in pred-and-output) (ContextOf in ctx)) - ((ContextOf (DoWhile in pred-and-output) ctx)) :ruleset always-run) - -(rule ((Call func arg) (ContextOf arg ctx)) - ((ContextOf (Call func arg) ctx)) :ruleset always-run) - -(rule ((Alloc amt e state ty) (ContextOf e ctx)) - ((ContextOf (Alloc amt e state ty) ctx)) :ruleset always-run) - -(rule ((Alloc amt e state ty) (ContextOf state ctx)) - ((ContextOf (Alloc amt e state ty) ctx)) :ruleset always-run) - -(ruleset canon) - -; Commutativity -(rewrite (Bop (Add) x y) (Bop (Add) y x) :ruleset canon) -(rewrite (Bop (Mul) x y) (Bop (Mul) y x) :ruleset canon) -(rewrite (Bop (Eq) x y) (Bop (Eq) y x) :ruleset canon) -(rewrite (Bop (And) x y) (Bop (And) y x) :ruleset canon) -(rewrite (Bop (Or) x y) (Bop (Or) y x) :ruleset canon) - -; Canonicalize to < -; x > y ==> y < x -(rewrite (Bop (GreaterThan) x y) (Bop (LessThan) y x) :ruleset canon) - -; x >= y ==> y < x + 1 -; x >= y ==> y - 1 < x -(rule ( - (= lhs (Bop (GreaterEq) x y)) - (HasArgType x ty) - (ContextOf lhs ctx) - ) - ( - (union lhs (Bop (LessThan) y (Bop (Add) x (Const (Int 1) ty ctx)))) - (union lhs (Bop (LessThan) (Bop (Sub) y (Const (Int 1) ty ctx)) x)) - ) - :ruleset canon) - -; x <= y ==> x < y + 1 -; x <= y ==> x - 1 < y -(rule ( - (= lhs (Bop (LessEq) x y)) - (HasArgType y ty) - (ContextOf lhs ctx) - ) - ( - (union lhs (Bop (LessThan) x (Bop (Add) y (Const (Int 1) ty ctx)))) - (union lhs (Bop (LessThan) (Bop (Sub) x (Const (Int 1) ty ctx)) y)) - ) - :ruleset canon) - - -; Make Concats right-deep -(rewrite (Concat (Concat a b) c) - (Concat a (Concat b c)) - :ruleset always-run) -; Simplify Concat's with empty -(rewrite (Concat (Empty ty ctx) x) - x - :ruleset always-run) -(rewrite (Concat x (Empty ty ctx)) - x - :ruleset always-run) - -; Make a tuple that is a sub-range of another tuple -; tuple start len -(function SubTuple (Expr i64 i64) Expr :unextractable) - -(rewrite (SubTuple expr x 0) - (Empty ty ctx) - :when ((HasArgType expr ty) (ContextOf expr ctx)) - :ruleset always-run) - -(rewrite (SubTuple expr x 1) - (Single (Get expr x)) - :ruleset always-run) - -(rewrite (SubTuple expr a b) - (Concat (Single (Get expr a)) (SubTuple expr (+ a 1) (- b 1))) - :when ((> b 1)) - :ruleset always-run) - -; Helper functions to remove one element from a tuple or type list -; tuple idx -(function TupleRemoveAt (Expr i64) Expr :unextractable) -(function TypeListRemoveAt (TypeList i64) TypeList :unextractable) - -(rewrite (TupleRemoveAt tuple idx) - (Concat (SubTuple tuple 0 idx) - (SubTuple tuple (+ idx 1) (- len (+ idx 1)))) - :when ((= len (tuple-length tuple))) - :ruleset always-run) - -(rewrite (TypeListRemoveAt (TNil) _idx) (TNil) :ruleset always-run) -(rewrite (TypeListRemoveAt (TCons x xs) 0 ) xs :ruleset always-run) -(rewrite (TypeListRemoveAt (TCons x xs) idx) - (TCons x (TypeListRemoveAt xs (- idx 1))) - :when ((> idx 0)) - :ruleset always-run) - -;; Compute the tree size of program, not dag size -(function Expr-size (Expr) i64 :unextractable :merge (min old new) ) -(function ListExpr-size (ListExpr) i64 :unextractable :merge (min old new)) - -(rule ((= expr (Function name tyin tyout out)) - (= sum (Expr-size out))) - ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) - -(rule ((= expr (Const n ty assum))) - ((set (Expr-size expr) 1)) :ruleset always-run) - -(rule ((= expr (Bop op x y)) - (= sum (+ (Expr-size y) (Expr-size x)))) - ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) - -(rule ((= expr (Uop op x)) - (= sum (Expr-size x))) - ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) - -(rule ((= expr (Get tup i)) - (= sum (Expr-size tup))) - ((set (Expr-size expr) sum)) :ruleset always-run) - -(rule ((= expr (Concat x y)) - (= sum (+ (Expr-size y) (Expr-size x)))) - ((set (Expr-size expr) sum)) :ruleset always-run) - -(rule ((= expr (Single x)) - (= sum (Expr-size x))) - ((set (Expr-size expr) sum)) :ruleset always-run) - -(rule ((= expr (Switch pred inputs branches)) - (= sum (+ (Expr-size inputs) (+ (ListExpr-size branches) (Expr-size pred))))) - ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) - -(rule ((= expr (If pred inputs then else)) - (= sum (+ (Expr-size inputs) (+ (Expr-size else) (+ (Expr-size then) (Expr-size pred)))))) - ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) - -(rule ((= expr (DoWhile in pred-and-output)) - (= sum (+ (Expr-size pred-and-output) (Expr-size in)))) - ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) - -(rule ((= expr (Arg ty assum))) - ((set (Expr-size expr) 1)) :ruleset always-run) - -(rule ((= expr (Call func arg)) - (= sum (Expr-size arg))) - ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) - -(rule ((Empty ty assum)) ((set (Expr-size (Empty ty assum)) 0)) :ruleset always-run) - -(rule ((= expr (Cons hd tl)) - (= sum (+ (ListExpr-size tl) (Expr-size hd)))) - ((set (ListExpr-size expr) sum)) :ruleset always-run) - -(rule ((Nil)) - ((set (ListExpr-size (Nil)) 0)) :ruleset always-run) - -(rule ((= expr (Alloc id e state ty)) ;; do state edge's expr should be counted? - (= sum (Expr-size e))) - ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) -;; Like Subst but for dropping inputs to a region -;; See subst.egg for more implementation documentation - -(ruleset drop) -(ruleset apply-drop-unions) -(ruleset cleanup-drop) - -;; (DropAt ctx idx in) removes all references to `(Get (Arg ...) idx)` in `in`. -;; It also replaces the leaf contexts with `ctx` and fixes up argument types, -;; as well as updating `(Get (Arg ...) j)` to `(Get (Arg ...) (- j 1))` for j > idx. -(function DropAt (Assumption i64 Expr) Expr :unextractable) -(function DelayedDropUnion (Expr Expr) Expr :unextractable) - -;; Helper that precomputes the arg type that we need -(function DropAtInternal (Type Assumption i64 Expr) Expr :unextractable) -(rule ((= lhs (DropAt ctx idx in)) - (HasArgType in (TupleT oldty))) - - ((let newty (TupleT (TypeListRemoveAt oldty idx))) - (union lhs (DropAtInternal newty ctx idx in))) - :ruleset drop) - -;; Leaves -(rule ((= lhs (DropAtInternal newty newctx idx (Const c oldty oldctx)))) - ((DelayedDropUnion lhs (Const c newty newctx))) - :ruleset drop) -(rule ((= lhs (DropAtInternal newty newctx idx (Empty oldty oldctx)))) - ((DelayedDropUnion lhs (Empty newty newctx))) - :ruleset drop) -; get stuck on purpose if `i = idx` or if we find a bare `Arg` -(rule ((= lhs (DropAtInternal newty newctx idx (Get (Arg oldty oldctx) i))) - (< i idx)) - ((DelayedDropUnion lhs (Get (Arg newty newctx) i))) - :ruleset drop) -(rule ((= lhs (DropAtInternal newty newctx idx (Get (Arg oldty oldctx) i))) - (> i idx)) - ((DelayedDropUnion lhs (Get (Arg newty newctx) (- i 1)))) - :ruleset drop) - -;; Operators -(rule ((= lhs (DropAtInternal newty newctx idx (Bop op c1 c2))) - (ExprIsResolved (Bop op c1 c2))) - ((DelayedDropUnion lhs (Bop op - (DropAtInternal newty newctx idx c1) - (DropAtInternal newty newctx idx c2)))) - :ruleset drop) - -(rule ((= lhs (DropAtInternal newty newctx idx (Uop op c1))) - (ExprIsResolved (Uop op c1))) - ((DelayedDropUnion lhs (Uop op - (DropAtInternal newty newctx idx c1)))) - :ruleset drop) - -;; this is okay because we get stuck at `Arg`s -(rule ((= lhs (DropAtInternal newty newctx idx (Get c1 index))) - (ExprIsResolved (Get c1 index))) - ((DelayedDropUnion lhs (Get - (DropAtInternal newty newctx idx c1) - index))) - :ruleset drop) - -(rule ((= lhs (DropAtInternal newty newctx idx (Alloc id c1 c2 ty))) - (ExprIsResolved (Alloc id c1 c2 ty))) - ((DelayedDropUnion lhs (Alloc id - (DropAtInternal newty newctx idx c1) - (DropAtInternal newty newctx idx c2) - ty))) - :ruleset drop) - -(rule ((= lhs (DropAtInternal newty newctx idx (Call name c1))) - (ExprIsResolved (Call name c1))) - ((DelayedDropUnion lhs (Call name - (DropAtInternal newty newctx idx c1)))) - :ruleset drop) - -;; Tuple operators -(rule ((= lhs (DropAtInternal newty newctx idx (Single c1))) - (ExprIsResolved (Single c1))) - ((DelayedDropUnion lhs (Single - (DropAtInternal newty newctx idx c1)))) - :ruleset drop) - -(rule ((= lhs (DropAtInternal newty newctx idx (Concat c1 c2))) - (ExprIsResolved (Concat c1 c2))) - ((DelayedDropUnion lhs (Concat - (DropAtInternal newty newctx idx c1) - (DropAtInternal newty newctx idx c2)))) - :ruleset drop) - -;; Control flow -(rule ((= lhs (DropAtInternal newty newctx idx (Switch pred inputs c1))) - (ExprIsResolved (Switch pred inputs c1))) - ((DelayedDropUnion lhs (Switch - (DropAtInternal newty newctx idx pred) - (DropAtInternal newty newctx idx inputs) - c1))) - :ruleset drop) - -(rule ((= lhs (DropAtInternal newty newctx idx (If pred inputs c1 c2))) - (ExprIsResolved (If pred inputs c1 c2))) - ((DelayedDropUnion lhs (If - (DropAtInternal newty newctx idx pred) - (DropAtInternal newty newctx idx inputs) - c1 - c2))) - :ruleset drop) - -(rule ((= lhs (DropAtInternal newty newctx idx (DoWhile in out))) - (ExprIsResolved (DoWhile in out))) - ((DelayedDropUnion lhs (DoWhile - (DropAtInternal newty newctx idx in) - out))) - :ruleset drop) - -(rewrite (DropAtInternal newty newctx idx (Function name inty outty body)) - (Function name inty outty (DropAtInternal newty newctx idx body)) - :when ((ExprIsResolved body)) - :ruleset drop) - - - -;; ########################### Apply drop unions - -(rule ((DelayedDropUnion lhs rhs)) - ((union lhs rhs)) - :ruleset apply-drop-unions) - -;; ########################### Cleanup Dropat, DropAtInternal and DelayedDropUnion - -(rule ((ExprIsResolved (DropAt newctx idx in))) - ((subsume (DropAt newctx idx in))) - :ruleset cleanup-drop) - -(rule ((ExprIsResolved (DropAtInternal newty newctx idx in))) - ((subsume (DropAtInternal newty newctx idx in))) - :ruleset cleanup-drop) - -(rule ((DelayedDropUnion lhs rhs)) - ((subsume (DelayedDropUnion lhs rhs))) - :ruleset cleanup-drop) - -(ruleset interval-analysis) - -(datatype Bound - (IntB i64) - (BoolB bool) - (bound-max Bound Bound) - (bound-min Bound Bound)) - -; bound tables -(function lo-bound (Expr) Bound :unextractable :merge (bound-max old new)) -(function hi-bound (Expr) Bound :unextractable :merge (bound-min old new)) - -; if lo > hi, panic -; We can't run these rules because unreachable branches may have impossible intervals -; Consider re-enabling these rules if we implement an is-reachable analysis -; (rule ( -; (= (IntB lo) (lo-bound expr)) -; (= (IntB hi) (hi-bound expr)) -; (> lo hi) -; ) -; ((panic "lo bound greater than hi bound")) -; :ruleset interval-analysis) -; (rule ( -; (= (BoolB true) (lo-bound expr)) -; (= (BoolB false) (hi-bound expr)) -; ) -; ((panic "lo bound greater than hi bound")) -; :ruleset interval-analysis) - -; combinators -(rewrite (bound-max (IntB x) (IntB y)) - (IntB (max x y)) - :ruleset interval-analysis) -(rewrite (bound-min (IntB x) (IntB y)) - (IntB (min x y)) - :ruleset interval-analysis) -(rewrite (bound-max (BoolB x) (BoolB y)) - (BoolB (or x y)) - :ruleset interval-analysis) -(rewrite (bound-min (BoolB x) (BoolB y)) - (BoolB (and x y)) - :ruleset interval-analysis) - -; ================================= -; Constants -; ================================= -(rule ((= lhs (Const (Int x) ty ctx))) - ( - (set (lo-bound lhs) (IntB x)) - (set (hi-bound lhs) (IntB x)) - ) - :ruleset interval-analysis) - -(rule ((= lhs (Const (Bool x) ty ctx))) - ( - (set (lo-bound lhs) (BoolB x)) - (set (hi-bound lhs) (BoolB x)) - ) - :ruleset interval-analysis) - -; ================================= -; Constant Folding -; ================================= -(rule ( - (= (IntB x) (lo-bound expr)) - (= (IntB x) (hi-bound expr)) - (HasArgType expr ty) - (ContextOf expr ctx) - ) - ((union expr (Const (Int x) ty ctx))) - :ruleset interval-analysis) - -(rule ( - (= (BoolB x) (lo-bound expr)) - (= (BoolB x) (hi-bound expr)) - (HasArgType expr ty) - (ContextOf expr ctx) - ) - ((union expr (Const (Bool x) ty ctx))) - :ruleset interval-analysis) - -; lower bound being true means the bool must be true -(rule ( - (= (BoolB true) (lo-bound expr)) - (HasArgType expr ty) - (ContextOf expr ctx) - ) - ((union expr (Const (Bool true) ty ctx))) - :ruleset interval-analysis) - -; upper bound being false means the bool must be false -(rule ( - (= (BoolB false) (hi-bound expr)) - (HasArgType expr ty) - (ContextOf expr ctx) - ) - ((union expr (Const (Bool false) ty ctx))) - :ruleset interval-analysis) - -; ================================= -; Arithmetic -; ================================= -; + a b interval is (+ la lb) (+ ha hb) -(rule ( - (= lhs (Bop (Add) a b)) - (= (IntB la) (lo-bound a)) - (= (IntB lb) (lo-bound b)) - ) - ((set (lo-bound lhs) (IntB (+ la lb)))) - :ruleset interval-analysis) -(rule ( - (= lhs (Bop (Add) a b)) - (= (IntB ha) (hi-bound a)) - (= (IntB hb) (hi-bound b)) - ) - ((set (hi-bound lhs) (IntB (+ ha hb)))) - :ruleset interval-analysis) - -; - a b interval is (- la hb) (- ha lb) -(rule ( - (= lhs (Bop (Sub) a b)) - (= (IntB la) (lo-bound a)) - (= (IntB hb) (hi-bound b)) - ) - ((set (lo-bound lhs) (IntB (- la hb)))) - :ruleset interval-analysis) -(rule ( - (= lhs (Bop (Sub) a b)) - (= (IntB ha) (hi-bound a)) - (= (IntB lb) (lo-bound b)) - ) - ((set (hi-bound lhs) (IntB (- ha lb)))) - :ruleset interval-analysis) - -; Multiplication for two constants -; TODO: Make fancier interval analysis -(rule ( - (= lhs (Bop (Mul) a b)) - (= (IntB x) (lo-bound a)) - (= (IntB x) (hi-bound a)) - (= (IntB y) (lo-bound b)) - (= (IntB y) (hi-bound b)) - ) - ( - (set (lo-bound lhs) (IntB (* x y))) - (set (hi-bound lhs) (IntB (* x y))) - ) - :ruleset interval-analysis) - -; negative * negative is positive -(rule ( - (= lhs (Bop (Mul) x y)) - (= (IntB hi-x) (hi-bound x)) - (= (IntB hi-y) (hi-bound y)) - (<= hi-x 0) - (<= hi-y 0) - ) - ((set (lo-bound lhs) (IntB 0))) - :ruleset interval-analysis) - -; negative * positive is negative -(rule ( - (= lhs (Bop (Mul) x y)) - (= (IntB hi-x) (hi-bound x)) - (= (IntB lo-y) (lo-bound y)) - (<= hi-x 0) ; x <= 0 (x is negative) - (>= lo-y 0) ; y >= 0 (y is positive) - ) - ((set (hi-bound lhs) (IntB 0))) - :ruleset interval-analysis) - -; positive * positive is positive -(rule ( - (= lhs (Bop (Mul) x y)) - (= (IntB lo-x) (lo-bound x)) - (= (IntB lo-y) (lo-bound y)) - (>= lo-x 0) - (>= lo-y 0) - ) - ((set (lo-bound lhs) (IntB 0))) - :ruleset interval-analysis) - -; < a b interval is (< ha lb) (< la hb) -(rule ( - (= lhs (Bop (LessThan) a b)) - (= (IntB ha) (hi-bound a)) - (= (IntB lb) (lo-bound b)) - ) - ( - (set (lo-bound lhs) (BoolB (bool-< ha lb))) - ) - :ruleset interval-analysis) -(rule ( - (= lhs (Bop (LessThan) a b)) - (= (IntB la) (lo-bound a)) - (= (IntB hb) (hi-bound b)) - ) - ((set (hi-bound lhs) (BoolB (bool-< la hb)))) - :ruleset interval-analysis) - -; ================================= -; Conditionals -; ================================= -; if the predicate is true, merge with then branch -(rule ( - (= lhs (If cond inputs thn els)) - (ContextOf lhs if_ctx) - (= (BoolB true) (lo-bound cond)) - ) - ((union lhs (Subst if_ctx inputs thn))) - :ruleset interval-analysis) - -; if the predicate is false, merge with else branch -(rule ( - (= lhs (If cond inputs thn els)) - (ContextOf lhs if_ctx) - (= (BoolB false) (hi-bound cond)) - ) - ((union lhs (Subst if_ctx inputs els))) - :ruleset interval-analysis) - -; lo-bound of If is the min of the lower bounds -; hi-bound of If is the max of the upper bounds -(rule ( - (= lhs (If cond inputs thn els)) - (= lo-thn (lo-bound thn)) - (= lo-els (lo-bound els)) - ) - ((set (lo-bound lhs) (bound-min lo-thn lo-els))) - :ruleset interval-analysis) -(rule ( - (= lhs (If cond inputs thn els)) - (= hi-thn (hi-bound thn)) - (= hi-els (hi-bound els)) - ) - ((set (hi-bound lhs) (bound-max hi-thn hi-els))) - :ruleset interval-analysis) - -; Same rules, but for Ifs that have multiple outputs -(rule ( - (= lhs (If pred inputs thn els)) - (= lo-thn (lo-bound (Get thn i))) - (= lo-els (lo-bound (Get els i))) - ) - ((set (lo-bound (Get lhs i)) (bound-min lo-thn lo-els))) - :ruleset interval-analysis) -(rule ( - (= lhs (If cond inputs thn els)) - (= hi-thn (hi-bound (Get thn i))) - (= hi-els (hi-bound (Get els i))) - ) - ((set (hi-bound (Get lhs i)) (bound-max hi-thn hi-els))) - :ruleset interval-analysis) - -; If the If takes a tuple -(rule ( - ; expr < value - (= pred (Bop (LessThan) expr value)) - (= if_e (If pred inputs then else)) - ; the left operand of the < is an input to the if region - (= expr (Get inputs i)) - ; the right operand of the < has an upper bound - (= (IntB v) (hi-bound value)) - ; context node inside the if region - (= ctx (Arg ty (InIf true pred inputs))) - (HasType inputs ty) - ) - ; expr < value was true, so we know expr is at most (hi-bound value) - 1 - ((set (hi-bound (Get ctx i)) (IntB (- v 1)))) - :ruleset interval-analysis) -(rule ( - ; expr < value - (= pred (Bop (LessThan) expr value)) - (= if_e (If pred inputs then else)) - ; the left operand of the < is an input to the if region - (= expr (Get inputs i)) - ; the right operand of the < has a lower bound - (= (IntB v) (lo-bound value)) - ; context node inside the if region - (= ctx (Arg ty (InIf false pred inputs))) - (HasType inputs ty) - ) - ; expr < value was false, so we know expr is at least (lo-bound value) - ((set (lo-bound (Get ctx i)) (IntB v))) - :ruleset interval-analysis) - -(rule ( - ; value < expr - (= pred (Bop (LessThan) value expr)) - (= if_e (If pred inputs then else)) - ; the right operand of the < is an input to the if region - (= expr (Get inputs i)) - ; the left operand of the < has a lower bound - (= (IntB v) (lo-bound value)) - ; context node inside the if region - (= ctx (Arg ty (InIf true pred inputs))) - (HasType inputs ty) - ) - ; value < expr was true, so we know expr is at least (lo-bound value) + 1 - ((set (lo-bound (Get ctx i)) (IntB (+ v 1)))) - :ruleset interval-analysis) -(rule ( - ; value < expr - (= pred (Bop (LessThan) value expr)) - (= if_e (If pred inputs then else)) - ; the right operand of the < is an input to the if region - (= expr (Get inputs i)) - ; the left operand of the < has an upper bound - (= (IntB v) (hi-bound value)) - ; context node inside the if region - (= ctx (Arg ty (InIf false pred inputs))) - (HasType inputs ty) - ) - ; value < expr was false, so we know expr is at most (hi-bound value) - ((set (hi-bound (Get ctx i)) (IntB v))) - :ruleset interval-analysis) - -;; Push intervals for inputs into if region -(rule ( - (= if (If pred inputs then_ else_)) - (= ctx (Arg ty (InIf b pred inputs))) - (HasType inputs ty) - (= lo (lo-bound (Get inputs i))) - - ) - ((set (lo-bound (Get ctx i)) lo)) - :ruleset interval-analysis) -(rule ( - (= if (If pred inputs then_ else_)) - (= ctx (Arg ty (InIf b pred inputs))) - (HasType inputs ty) - (= hi (hi-bound (Get inputs i))) - - ) - ((set (hi-bound (Get ctx i)) hi)) - :ruleset interval-analysis) - -; (if (a == b) thn els) -; in the thn branch, we know that a has the same bounds as b -(rule ( - (= pred (Bop (Eq) expr val)) - (= if_e (If pred inputs thn els)) - ; the left operand of the == is an input to the if region - (= expr (Get inputs i)) - (= ctx (Arg ty (InIf true pred inputs))) - (HasType inputs ty) - (= (IntB lo) (lo-bound val)) - ) - ((set (lo-bound (Get ctx i)) (IntB lo))) - :ruleset interval-analysis) -(rule ( - (= pred (Bop (Eq) expr val)) - (= if_e (If pred inputs thn els)) - ; the left operand of the == is an input to the if region - (= expr (Get inputs i)) - (= ctx (Arg ty (InIf true pred inputs))) - (HasType inputs ty) - (= (IntB hi) (hi-bound val)) - ) - ((set (hi-bound (Get ctx i)) (IntB hi))) - :ruleset interval-analysis) - - -(rule ( - ;; argument has loop context - (Arg ty (InLoop inputs outputs)) - ;; in the loop, the argument is passed through - ;; note that some_ctx is not the same as (InLoop inputs outputs) - (= (Get (Arg ty some_ctx) ith) (Get outputs (+ 1 ith))) - ;; input has some bound - (= bound (lo-bound (Get inputs ith))) - ) - ( - (set (lo-bound (Get (Arg ty (InLoop inputs outputs)) ith)) bound) - ) - :ruleset interval-analysis) -(rule ( - ;; argument has loop context - (Arg ty (InLoop inputs outputs)) - ;; in the loop, the argument is passed through - (= (Get (Arg ty some_ctx) ith) (Get outputs (+ 1 ith))) - ;; input has some bound - (= bound (hi-bound (Get inputs ith))) - ) - ( - (set (hi-bound (Get (Arg ty (InLoop inputs outputs)) ith)) bound) - ) - :ruleset interval-analysis) - - -(ruleset switch_rewrite) - -; if (a and b) X Y ~~> if a (if b X Y) Y -(rule ((= lhs (If (Bop (And) a b) ins X Y)) - (HasType ins (TupleT ins_ty)) - (= len (tuple-length ins))) - - ((let outer_ins (Concat (Single b) ins)) - (let outer_ins_ty (TupleT (TCons (BoolT) ins_ty))) - - (let inner_pred (Get (Arg outer_ins_ty (InIf true a outer_ins)) 0)) - (let sub_arg_true (SubTuple (Arg outer_ins_ty (InIf true a outer_ins)) 1 len)) - (let sub_arg_false (SubTuple (Arg outer_ins_ty (InIf false a outer_ins)) 1 len)) - - (let inner_X (AddContext (InIf true inner_pred sub_arg_true) X)) - (let inner_Y (AddContext (InIf false inner_pred sub_arg_true) Y)) - (let outer_Y (Subst (InIf false a outer_ins) sub_arg_false Y)) - - (let inner (If inner_pred sub_arg_true inner_X inner_Y)) - (union lhs (If a outer_ins inner outer_Y))) - - :ruleset switch_rewrite) - -; if (a or b) X Y ~~> if a X (if b X Y) -(rule ((= lhs (If (Bop (Or) a b) ins X Y)) - (HasType ins (TupleT ins_ty)) - (= len (tuple-length ins))) - - ((let outer_ins (Concat (Single b) ins)) - (let outer_ins_ty (TupleT (TCons (BoolT) ins_ty))) - - (let inner_pred (Get (Arg outer_ins_ty (InIf false a outer_ins)) 0)) - (let sub_arg_true (SubTuple (Arg outer_ins_ty (InIf true a outer_ins)) 1 len)) - (let sub_arg_false (SubTuple (Arg outer_ins_ty (InIf false a outer_ins)) 1 len)) - - (let outer_X (Subst (InIf true a outer_ins) sub_arg_true X)) - (let inner_X (AddContext (InIf true inner_pred sub_arg_false) X)) - (let inner_Y (AddContext (InIf false inner_pred sub_arg_false) Y)) - - (let inner (If inner_pred sub_arg_false inner_X inner_Y)) - (union lhs (If a outer_ins outer_X inner ))) - - :ruleset switch_rewrite) - -(relation Debug (Assumption Expr Expr)) -(rule ((If (Const (Bool true) ty ctx) ins thn els)) -( - (Debug ctx ins thn) -) - :ruleset always-run) - -(rewrite (If (Const (Bool true) ty ctx) ins thn els) - (Subst ctx ins thn) - :ruleset always-run) - -(rewrite (If (Const (Bool false) ty ctx) ins thn els) - (Subst ctx ins els) - :ruleset switch_rewrite) - -(rule ((= lhs (If pred ins thn els)) - (= (Get thn i) (Const (Bool true) ty ctx1)) - (= (Get els i) (Const (Bool false) ty ctx2))) - ((union (Get lhs i) pred)) :ruleset switch_rewrite) - -(rule ((= lhs (If pred ins thn els)) - (= (Get thn i) (Const (Bool false) ty ctx1)) - (= (Get els i) (Const (Bool true) ty ctx2))) - ((union (Get lhs i) (Uop (Not) pred))) :ruleset switch_rewrite) - -; Simple rewrites that don't do a ton with control flow. - -(ruleset peepholes) - -(rewrite (Bop (Mul) (Const (Int 0) ty ctx) e) (Const (Int 0) ty ctx) :ruleset peepholes) -(rewrite (Bop (Mul) e (Const (Int 0) ty ctx)) (Const (Int 0) ty ctx) :ruleset peepholes) -(rewrite (Bop (Mul) (Const (Int 1) ty ctx) e) e :ruleset peepholes) -(rewrite (Bop (Mul) e (Const (Int 1) ty ctx)) e :ruleset peepholes) -(rewrite (Bop (Add) (Const (Int 0) ty ctx) e) e :ruleset peepholes) -(rewrite (Bop (Add) e (Const (Int 0) ty ctx) ) e :ruleset peepholes) - -(rewrite (Bop (Mul) (Const (Int j) ty ctx) (Const (Int i) ty ctx)) (Const (Int (* i j)) ty ctx) :ruleset peepholes) -(rewrite (Bop (Add) (Const (Int j) ty ctx) (Const (Int i) ty ctx)) (Const (Int (+ i j)) ty ctx) :ruleset peepholes) - -(rewrite (Bop (And) (Const (Bool true) ty ctx) e) e :ruleset peepholes) -(rewrite (Bop (And) e (Const (Bool true) ty ctx)) e :ruleset peepholes) -(rewrite (Bop (And) (Const (Bool false) ty ctx) e) (Const (Bool false) ty ctx) :ruleset peepholes) -(rewrite (Bop (And) e (Const (Bool false) ty ctx)) (Const (Bool false) ty ctx) :ruleset peepholes) -(rewrite (Bop (Or) (Const (Bool false) ty ctx) e) e :ruleset peepholes) -(rewrite (Bop (Or) e (Const (Bool false) ty ctx)) e :ruleset peepholes) -(rewrite (Bop (Or) (Const (Bool true) ty ctx) e) (Const (Bool true) ty ctx) :ruleset peepholes) -(rewrite (Bop (Or) e (Const (Bool true) ty ctx)) (Const (Bool true) ty ctx) :ruleset peepholes) - - -(datatype IntOrInfinity - (Infinity) - (NegInfinity) - (I i64)) - -(function MaxIntOrInfinity (IntOrInfinity IntOrInfinity) IntOrInfinity) -(rewrite (MaxIntOrInfinity (Infinity) _) (Infinity) :ruleset always-run) -(rewrite (MaxIntOrInfinity _ (Infinity)) (Infinity) :ruleset always-run) -(rewrite (MaxIntOrInfinity (NegInfinity) x) x :ruleset always-run) -(rewrite (MaxIntOrInfinity x (NegInfinity)) x :ruleset always-run) -(rewrite (MaxIntOrInfinity (I x) (I y)) (I (max x y)) :ruleset always-run) - -(function MinIntOrInfinity (IntOrInfinity IntOrInfinity) IntOrInfinity) -(rewrite (MinIntOrInfinity (NegInfinity) _) (NegInfinity) :ruleset always-run) -(rewrite (MinIntOrInfinity _ (NegInfinity)) (NegInfinity) :ruleset always-run) -(rewrite (MinIntOrInfinity (Infinity) x) x :ruleset always-run) -(rewrite (MinIntOrInfinity x (Infinity)) x :ruleset always-run) -(rewrite (MinIntOrInfinity (I x) (I y)) (I (min x y)) :ruleset always-run) - -(function AddIntOrInfinity (IntOrInfinity IntOrInfinity) IntOrInfinity) -(rewrite (AddIntOrInfinity (Infinity) (Infinity)) (Infinity) :ruleset always-run) -(rewrite (AddIntOrInfinity (Infinity) (I _)) (Infinity) :ruleset always-run) -(rewrite (AddIntOrInfinity (I _) (Infinity)) (Infinity) :ruleset always-run) -(rewrite (AddIntOrInfinity (NegInfinity) (NegInfinity)) (NegInfinity) :ruleset always-run) -(rewrite (AddIntOrInfinity (NegInfinity) (I _)) (NegInfinity) :ruleset always-run) -(rewrite (AddIntOrInfinity (I _) (NegInfinity)) (NegInfinity) :ruleset always-run) -(rewrite (AddIntOrInfinity (I x) (I y)) (I (+ x y)) :ruleset always-run) - -(datatype IntInterval (MkIntInterval IntOrInfinity IntOrInfinity)) - -(function UnionIntInterval (IntInterval IntInterval) IntInterval) -(rewrite (UnionIntInterval (MkIntInterval lo1 hi1) (MkIntInterval lo2 hi2)) - (MkIntInterval (MinIntOrInfinity lo1 lo2) (MaxIntOrInfinity hi1 hi2)) - :ruleset always-run) - -(function IntersectIntInterval (IntInterval IntInterval) IntInterval) -(rewrite (IntersectIntInterval (MkIntInterval lo1 hi1) (MkIntInterval lo2 hi2)) - (MkIntInterval (MaxIntOrInfinity lo1 lo2) (MinIntOrInfinity hi1 hi2)) - :ruleset always-run) - -(function AddIntInterval (IntInterval IntInterval) IntInterval) -(rewrite (AddIntInterval (MkIntInterval lo1 hi1) (MkIntInterval lo2 hi2)) - (MkIntInterval (AddIntOrInfinity lo1 lo2) - (AddIntOrInfinity hi1 hi2)) - :ruleset always-run) - - -(datatype List - (Nil-List) - (Cons-List i64 IntInterval List)) - -(function Length-List (List) i64) -(rule ((= x (Nil-List))) - ((set (Length-List x) 0)) - :ruleset always-run) -(rule ((= x (Cons-List hd0 hd1 tl)) - (= l (Length-List tl))) - ((set (Length-List x) (+ l 1))) - :ruleset always-run) -(rule ((= x (Nil-List))) - ((set (Length-List x) 0)) - :ruleset memory-helpers) -(rule ((= x (Cons-List hd0 hd1 tl)) - (= l (Length-List tl))) - ((set (Length-List x) (+ l 1))) - :ruleset memory-helpers) - -(relation IsEmpty-List (List)) -(rule ((= x (Nil-List))) - ((IsEmpty-List x)) - :ruleset always-run) - -(relation IsNonEmpty-List (List)) -(rule ((= x (Cons-List hd0 hd1 tl))) - ((IsNonEmpty-List x)) - :ruleset always-run) - -(function RevConcat-List (List List) List :cost 1000) -(rewrite (RevConcat-List (Nil-List) l) - l - :ruleset always-run) -(rewrite (RevConcat-List (Cons-List hd0 hd1 tl) l) - (RevConcat-List tl (Cons-List hd0 hd1 l)) - :ruleset always-run) - -(function Rev-List (List) List :cost 1000) -(rewrite (Rev-List m) - (RevConcat-List m (Nil-List)) - :ruleset always-run) - -(function Concat-List (List List) List :cost 1000) -(rewrite (Concat-List x y) - (RevConcat-List (Rev-List x) y) - :ruleset always-run) - -; SuffixAt and At must be demanded, otherwise these are O(N^2) -(relation DemandAt-List (List)) -(relation SuffixAt-List (List i64 List)) -(relation At-List (List i64 i64 IntInterval)) -(rule ((DemandAt-List x)) - ((SuffixAt-List x 0 x)) - :ruleset always-run) -(rule ((SuffixAt-List x i (Cons-List hd0 hd1 tl))) - ((SuffixAt-List x (+ i 1) tl) - (At-List x i hd0 hd1)) - :ruleset always-run) - -(function Union-List (List List) List) - ; The third argument of the helper is a WIP result map. - ; Invariant: keys of the result map are not present in the first two and are in descending order - (function UnionHelper-List (List List List) List) - (rewrite (Union-List m1 m2) - (Rev-List (UnionHelper-List m1 m2 (Nil-List))) - :ruleset always-run) - - ; both m1 and m2 empty - (rewrite (UnionHelper-List (Nil-List) (Nil-List) res) - res - :ruleset always-run) - ; take from m1 when m2 empty and vice versa - (rewrite - (UnionHelper-List - (Nil-List) - (Cons-List hd0 hd1 tl) - res) - (UnionHelper-List - (Nil-List) - tl - (Cons-List hd0 hd1 res)) - :ruleset always-run) - (rewrite - (UnionHelper-List - (Cons-List hd0 hd1 tl) - (Nil-List) - res) - (UnionHelper-List - tl - (Nil-List) - (Cons-List hd0 hd1 res)) - :ruleset always-run) - - ; when both nonempty and smallest key different, take smaller key - (rule ((= f (UnionHelper-List l1 l2 res)) - (= l1 (Cons-List k1 a1 tl1)) - (= l2 (Cons-List k2 b1 tl2)) - (< k1 k2)) - ((union f - (UnionHelper-List tl1 l2 (Cons-List k1 a1 res)))) - :ruleset always-run) - (rule ((= f (UnionHelper-List l1 l2 res)) - (= l1 (Cons-List k1 a1 tl1)) - (= l2 (Cons-List k2 b1 tl2)) - (< k2 k1)) - ((union f - (UnionHelper-List l1 tl2 (Cons-List k2 b1 res)))) - :ruleset always-run) - - ; when shared smallest key, union interval - (rule ((= f (UnionHelper-List l1 l2 res)) - (= l1 (Cons-List k a1 tl1)) - (= l2 (Cons-List k b1 tl2))) - ((union f - (UnionHelper-List tl1 tl2 - (Cons-List k (UnionIntInterval a1 b1) res)))) - :ruleset always-run) - -(function Intersect-List (List List) List) - ; The third argument of the helper is a WIP result map. - ; Invariant: keys of the result map are not present in the first two and are in descending order - (function IntersectHelper-List (List List List) List) - (rewrite (Intersect-List m1 m2) - (Rev-List (IntersectHelper-List m1 m2 (Nil-List))) - :ruleset always-run) - - ; m1 or m2 empty - (rewrite (IntersectHelper-List (Nil-List) m2 res) - res - :ruleset always-run) - (rewrite (IntersectHelper-List m1 (Nil-List) res) - res - :ruleset always-run) - - ; when both nonempty and smallest key different, drop smaller key - (rule ((= f (IntersectHelper-List l1 l2 res)) - (= l1 (Cons-List k1 a1 tl1)) - (= l2 (Cons-List k2 b1 tl2)) - (< k1 k2)) - ((union f (IntersectHelper-List tl1 l2 res))) - :ruleset always-run) - (rule ((= f (IntersectHelper-List l1 l2 res)) - (= l1 (Cons-List k1 a1 tl1)) - (= l2 (Cons-List k2 b1 tl2)) - (< k2 k1)) - ((union f (IntersectHelper-List tl1 l2 res))) - :ruleset always-run) - -(datatype MyBool (MyTrue) (MyFalse)) - -(function IntIntervalValid (IntInterval) MyBool) -(rewrite (IntIntervalValid (MkIntInterval (I lo) (I hi))) - (MyTrue) - :when ((<= lo hi)) - :ruleset always-run) -(rewrite (IntIntervalValid (MkIntInterval (I lo) (I hi))) - (MyFalse) - :when ((> lo hi)) - :ruleset always-run) -(rewrite (IntIntervalValid (MkIntInterval (NegInfinity) _)) - (MyTrue) - :ruleset always-run) -(rewrite (IntIntervalValid (MkIntInterval _ (Infinity))) - (MyTrue) - :ruleset always-run) - -(function ConsIfNonEmpty (i64 IntInterval List) - List - :cost 100) -(rule ((ConsIfNonEmpty k v tl)) - ((IntIntervalValid v)) - :ruleset always-run) -(rule ((= f (ConsIfNonEmpty k v tl)) - (= (MyTrue) (IntIntervalValid v))) - ((union f (Cons-List k v tl))) - :ruleset always-run) -(rule ((= f (ConsIfNonEmpty k v tl)) - (= (MyFalse) (IntIntervalValid v))) - ((union f tl)) - :ruleset always-run) - - ; when shared smallest key, intersect interval - (rule ((= f (IntersectHelper-List l1 l2 res)) - (= l1 (Cons-List k a1 tl1)) - (= l2 (Cons-List k b1 tl2))) - ((union f - (IntersectHelper-List tl1 tl2 - (ConsIfNonEmpty k (IntersectIntInterval a1 b1) res)))) - :ruleset always-run) - -(function AddIntIntervalToAll (IntInterval List) - List) -(rewrite (AddIntIntervalToAll _ (Nil-List)) - (Nil-List) - :ruleset always-run) -(rewrite (AddIntIntervalToAll x (Cons-List allocid offset tl)) - (Cons-List allocid (AddIntInterval x offset) - (AddIntIntervalToAll x tl)) - :ruleset always-run) - -(datatype PtrPointees - (PointsTo List) - (PointsAnywhere)) - -(function AddIntIntervalToPtrPointees (IntInterval PtrPointees) PtrPointees) -(rewrite (AddIntIntervalToPtrPointees interval (PointsAnywhere)) - (PointsAnywhere) - :ruleset always-run) -(rewrite (AddIntIntervalToPtrPointees interval (PointsTo l)) - (PointsTo (AddIntIntervalToAll interval l)) - :ruleset always-run) - -(function Union-PtrPointees (PtrPointees PtrPointees) PtrPointees) -(rewrite (Union-PtrPointees (PointsAnywhere) _) - (PointsAnywhere) - :ruleset always-run) -(rewrite (Union-PtrPointees _ (PointsAnywhere)) - (PointsAnywhere) - :ruleset always-run) -(rewrite (Union-PtrPointees (PointsTo x) (PointsTo y)) - (PointsTo (Union-List x y)) - :ruleset always-run) -(function Intersect-PtrPointees (PtrPointees PtrPointees) PtrPointees) -(rewrite (Intersect-PtrPointees (PointsAnywhere) x) - x - :ruleset always-run) -(rewrite (Intersect-PtrPointees x (PointsAnywhere)) - x - :ruleset always-run) -(rewrite (Intersect-PtrPointees (PointsTo x) (PointsTo y)) - (PointsTo (Intersect-List x y)) - :ruleset always-run) - -(relation PointsNowhere-PtrPointees (PtrPointees)) -(rule ((= f (PointsTo x)) - (IsEmpty-List x)) - ((PointsNowhere-PtrPointees f)) - :ruleset always-run) - - -(datatype List - (Nil-List) - (Cons-List PtrPointees List)) - -(function Length-List (List) i64) -(rule ((= x (Nil-List))) - ((set (Length-List x) 0)) - :ruleset always-run) -(rule ((= x (Cons-List hd0 tl)) - (= l (Length-List tl))) - ((set (Length-List x) (+ l 1))) - :ruleset always-run) -(rule ((= x (Nil-List))) - ((set (Length-List x) 0)) - :ruleset memory-helpers) -(rule ((= x (Cons-List hd0 tl)) - (= l (Length-List tl))) - ((set (Length-List x) (+ l 1))) - :ruleset memory-helpers) - -(relation IsEmpty-List (List)) -(rule ((= x (Nil-List))) - ((IsEmpty-List x)) - :ruleset always-run) - -(relation IsNonEmpty-List (List)) -(rule ((= x (Cons-List hd0 tl))) - ((IsNonEmpty-List x)) - :ruleset always-run) - -(function RevConcat-List (List List) List :cost 1000) -(rewrite (RevConcat-List (Nil-List) l) - l - :ruleset always-run) -(rewrite (RevConcat-List (Cons-List hd0 tl) l) - (RevConcat-List tl (Cons-List hd0 l)) - :ruleset always-run) - -(function Rev-List (List) List :cost 1000) -(rewrite (Rev-List m) - (RevConcat-List m (Nil-List)) - :ruleset always-run) - -(function Concat-List (List List) List :cost 1000) -(rewrite (Concat-List x y) - (RevConcat-List (Rev-List x) y) - :ruleset always-run) - -; SuffixAt and At must be demanded, otherwise these are O(N^2) -(relation DemandAt-List (List)) -(relation SuffixAt-List (List i64 List)) -(relation At-List (List i64 PtrPointees)) -(rule ((DemandAt-List x)) - ((SuffixAt-List x 0 x)) - :ruleset always-run) -(rule ((SuffixAt-List x i (Cons-List hd0 tl))) - ((SuffixAt-List x (+ i 1) tl) - (At-List x i hd0)) - :ruleset always-run) - -(relation All (List)) -(rule ((= x (Nil-List))) - ((All x)) - :ruleset always-run) -(rule ((= x (Cons-List hd0 tl)) - (PointsNowhere-PtrPointees hd0) - (All tl)) - ((All x)) - :ruleset always-run) - - - -(function Zip (List List) List :cost 1000) -(rewrite (Zip (Nil-List) (Nil-List)) - (Nil-List) - :ruleset always-run) -(rewrite (Zip - (Cons-List x0 tl1) - (Cons-List y0 tl2)) - (Cons-List - (Union-PtrPointees x0 y0) - (Zip tl1 tl2)) - :when ((= (Length-List tl1) (Length-List tl2))) - :ruleset always-run) - -(function Zip (List List) List :cost 1000) -(rewrite (Zip (Nil-List) (Nil-List)) - (Nil-List) - :ruleset always-run) -(rewrite (Zip - (Cons-List x0 tl1) - (Cons-List y0 tl2)) - (Cons-List - (Intersect-PtrPointees x0 y0) - (Zip tl1 tl2)) - :ruleset always-run) - - -(sort ExprSetPrim (Set Expr)) - -(datatype ExprSet (ES ExprSetPrim)) - -(function ExprSet-intersect (ExprSet ExprSet) ExprSet) -(rewrite (ExprSet-intersect (ES set1) (ES set2)) (ES (set-intersect set1 set2)) - :ruleset memory-helpers) -(function ExprSet-union (ExprSet ExprSet) ExprSet) -(rewrite (ExprSet-union (ES set1) (ES set2)) (ES (set-union set1 set2)) - :ruleset memory-helpers) -(relation ExprSet-contains (ExprSet Expr)) -(rule ((ES set1) (set-contains set1 x)) - ((ExprSet-contains (ES set1) x)) - :ruleset memory-helpers) -(function ExprSet-insert (ExprSet Expr) ExprSet) -(rewrite (ExprSet-insert (ES set1) x) - (ES (set-insert set1 x)) - :ruleset memory-helpers) -(function ExprSet-length (ExprSet) i64) -(rewrite (ExprSet-length (ES set1)) (set-length set1) :ruleset memory-helpers) - -; ============================ -; Pointees -; ============================ - - -; List is used as an association list; the i64 keys -; (corresponding to alloc ids) are always unique and sorted, the IntInterval -; values correspond to offset ranges. -; -; (TuplePointsTo [{0->[4,5], 1->[0,0]}, {0->[0,0]}]) -; indicates a tuple with two components. -; - The first component might point to Alloc 0 at offsets 4 or 5, -; or Alloc 1 at offset 0 -; - The second component points to Alloc 0 at offset 0 -(datatype Pointees - (TuplePointsTo List) - (PtrPointsTo PtrPointees)) - -(function UnwrapPtrPointsTo (Pointees) PtrPointees) -(rewrite (UnwrapPtrPointsTo (PtrPointsTo x)) - x - :ruleset memory-helpers) -(function UnwrapTuplePointsTo (Pointees) List) -(rewrite (UnwrapTuplePointsTo (TuplePointsTo x)) - x - :ruleset memory-helpers) - -(relation PointsNowhere (Pointees)) -(rule ((= f (PtrPointsTo x)) - (PointsNowhere-PtrPointees x)) - ((PointsNowhere f)) - :ruleset memory-helpers) -(rule ((= f (TuplePointsTo l)) - (All l)) - ((PointsNowhere f)) - :ruleset memory-helpers) - -(function UnionPointees (Pointees Pointees) Pointees) -(rewrite (UnionPointees (PtrPointsTo x) (PtrPointsTo y)) - (PtrPointsTo (Union-PtrPointees x y)) - :ruleset memory-helpers) -(rewrite (UnionPointees (TuplePointsTo x) (TuplePointsTo y)) - (TuplePointsTo (Zip x y)) - :when ((= (Length-List x) (Length-List y))) - :ruleset memory-helpers) -(function IntersectPointees (Pointees Pointees) Pointees) -(rewrite (IntersectPointees (PtrPointsTo x) (PtrPointsTo y)) - (PtrPointsTo (Intersect-PtrPointees x y)) - :ruleset memory-helpers) -(rewrite (IntersectPointees (TuplePointsTo x) (TuplePointsTo y)) - (TuplePointsTo (Zip x y)) - :ruleset memory-helpers) - -(function GetPointees (Pointees i64) Pointees) -(rule ((= f (GetPointees (TuplePointsTo l) i)) - (At-List l i x)) - ((union f (PtrPointsTo x))) - :ruleset memory-helpers) - -(function PointeesDropFirst (Pointees) Pointees) -(rewrite (PointeesDropFirst (TuplePointsTo (Cons-List hd tl))) - (TuplePointsTo tl) - :ruleset memory-helpers) - -; ============================ -; Resolved -; ============================ - -; Resolved checks if an e-class contains a term containing only constructors and -; primitives; i.e. whether equality is decideable -(relation Resolved-IntOrInfinity (IntOrInfinity)) -(rule ((= f (I _))) - ((Resolved-IntOrInfinity f)) - :ruleset memory-helpers) -(rule ((= f (Infinity))) - ((Resolved-IntOrInfinity f)) - :ruleset memory-helpers) -(rule ((= f (NegInfinity))) - ((Resolved-IntOrInfinity f)) - :ruleset memory-helpers) - -(relation Resolved-IntInterval (IntInterval)) -(rule ((= f (MkIntInterval lo hi)) - (Resolved-IntOrInfinity lo) - (Resolved-IntOrInfinity hi)) - ((Resolved-IntInterval f)) - :ruleset memory-helpers) - -(relation Resolved-List (List)) -(rule ((= f (Nil-List))) - ((Resolved-List f)) - :ruleset memory-helpers) -(rule ((= f (Cons-List allocid offsets tl)) - (Resolved-List tl) - (Resolved-IntInterval offsets)) - ((Resolved-List f)) - :ruleset memory-helpers) - -(relation Resolved-PtrPointees (PtrPointees)) -(rule ((= f (PointsAnywhere))) - ((Resolved-PtrPointees f)) - :ruleset memory-helpers) -(rule ((= f (PointsTo x)) - (Resolved-List x)) - ((Resolved-PtrPointees f)) - :ruleset memory-helpers) - -(relation Resolved-List (List)) -(rule ((= f (Nil-List))) - ((Resolved-List f)) - :ruleset memory-helpers) -(rule ((= f (Cons-List hd tl)) - (Resolved-List tl) - (Resolved-PtrPointees hd)) - ((Resolved-List f)) - :ruleset memory-helpers) - -(relation Resolved-Pointees (Pointees)) -(rule ((= f (TuplePointsTo x)) - (Resolved-List x)) - ((Resolved-Pointees f)) - :ruleset memory-helpers) -(rule ((= f (PtrPointsTo x)) - (Resolved-PtrPointees x)) - ((Resolved-Pointees f)) - :ruleset memory-helpers) - - -;;;;; - -(function BaseTypeToPtrPointees (BaseType) PtrPointees :cost 100) -(rewrite (BaseTypeToPtrPointees (PointerT _)) - (PointsAnywhere) - :ruleset memory-helpers) -(rewrite (BaseTypeToPtrPointees (IntT)) - (PointsTo (Nil-List)) - :ruleset memory-helpers) -(rewrite (BaseTypeToPtrPointees (StateT)) - (PointsTo (Nil-List)) - :ruleset memory-helpers) -(rewrite (BaseTypeToPtrPointees (BoolT)) - (PointsTo (Nil-List)) - :ruleset memory-helpers) - -(function TypeListToList (TypeList) List :cost 1000) -(rewrite (TypeListToList (TNil)) - (Nil-List) - :ruleset memory-helpers) -(rewrite (TypeListToList (TCons hd tl)) - (Cons-List - (BaseTypeToPtrPointees hd) - (TypeListToList tl)) - :ruleset memory-helpers) - -(function TypeToPointees (Type) Pointees :cost 1000) -(rewrite (TypeToPointees (TupleT tylist)) - (TuplePointsTo (TypeListToList tylist)) - :ruleset memory-helpers) -(rewrite (TypeToPointees (Base basety)) - (PtrPointsTo (BaseTypeToPtrPointees basety)) - :ruleset memory-helpers) - -; ============================ -; Update PointerishType -; ============================ - -(relation PointerishType (Type)) -(relation PointerishTypeList (TypeList)) - -(rule ((= f (Base (PointerT ty)))) - ((PointerishType f)) - :ruleset always-run) - -(rule ((= f (TCons (PointerT ty) tl))) - ((PointerishTypeList f)) - :ruleset always-run) - -(rule ((= f (TCons hd tl)) - (PointerishTypeList tl)) - ((PointerishTypeList f)) - :ruleset always-run) - -(rule ((= f (TupleT l)) - (PointerishTypeList l)) - ((PointerishType f)) - :ruleset always-run) - -; ============================ -; Update PointsToCells -; ============================ - -; arg pointees result pointees -(function PointsToCells (Expr Pointees) Pointees :unextractable) - -; Top-level demand -(rule ((Function name in-ty out-ty body)) - ((PointsToCells body (TypeToPointees in-ty))) - :ruleset memory-helpers) - -; Demand PointsToCells along state edge and pointer-typed values -(rule ((PointsToCells (Bop (Print) e state) ap)) - ((PointsToCells state ap)) - :ruleset memory-helpers) -(rule ((PointsToCells (Bop (Load) e state) ap)) - ((PointsToCells e ap) - (PointsToCells state ap)) - :ruleset memory-helpers) -(rule ((PointsToCells (Top (Write) ptr val state) ap)) - ((PointsToCells ptr ap) - (PointsToCells state ap)) - :ruleset memory-helpers) -(rule ((PointsToCells (Alloc id sz state ty) ap)) - ((PointsToCells state ap)) - :ruleset memory-helpers) -(rule ((PointsToCells (Bop (Free) ptr state) ap)) - ((PointsToCells ptr ap) - (PointsToCells state ap)) - :ruleset memory-helpers) -(rule ((PointsToCells (Get x i) ap)) - ((PointsToCells x ap)) - :ruleset memory-helpers) -(rule ((PointsToCells (Concat x y) ap)) - ((PointsToCells x ap) - (PointsToCells y ap)) - :ruleset memory-helpers) -(rule ((PointsToCells (Single x) ap)) - ((PointsToCells x ap)) - :ruleset memory-helpers) - -; Compute and propagate PointsToCells -(rewrite (PointsToCells (Concat x y) aps) - (TuplePointsTo (Concat-List - (UnwrapTuplePointsTo (PointsToCells x aps)) - (UnwrapTuplePointsTo (PointsToCells y aps)))) - :when ((HasType (Concat x y) ty) (PointerishType ty)) - :ruleset memory-helpers) - -(rewrite (PointsToCells (Get x i) aps) - (GetPointees (PointsToCells x aps) i) - :when ((HasType (Get x i) ty) (PointerishType ty)) - :ruleset memory-helpers) - -(rewrite (PointsToCells (Single x) aps) - (TuplePointsTo - (Cons-List - (UnwrapPtrPointsTo (PointsToCells x aps)) - (Nil-List))) - :when ((HasType (Single x) ty) (PointerishType ty)) - :ruleset memory-helpers) - -(rewrite (PointsToCells (Arg ty_ ctx) aps) - aps - :when ((HasType (Arg ty_ ctx) ty) (PointerishType ty)) - :ruleset memory-helpers) - -; Allow non-pointer types to resolve -(rule ((PointsToCells x aps) - (HasType x ty)) - ((TypeToPointees ty)) - :ruleset memory-helpers) -(rule ((= f (PointsToCells x aps)) - (HasType x ty) - (= pointees (TypeToPointees ty)) - (PointsNowhere pointees)) - ((union f pointees)) - :ruleset memory-helpers) - -(rewrite (PointsToCells (Bop (PtrAdd) x e) aps) - (PtrPointsTo - (AddIntIntervalToPtrPointees - (MkIntInterval (I lo) (I hi)) - (UnwrapPtrPointsTo (PointsToCells x aps)))) - :when ((= (IntB lo) (lo-bound e)) - (= (IntB hi) (hi-bound e))) - :ruleset memory-helpers) - -(rewrite (PointsToCells (If c inputs t e) aps) - (UnionPointees - (PointsToCells t (PointsToCells inputs aps)) - (PointsToCells e (PointsToCells inputs aps))) - :when ((HasType (If c inputs t e) ty) (PointerishType ty)) - :ruleset memory) - -(rewrite (PointsToCells (Alloc id sz state ty) aps) - (TuplePointsTo - (Cons-List - (PointsTo - (Cons-List - id - (MkIntInterval (I 0) (I 0)) - (Nil-List))) - (Cons-List - (PointsTo (Nil-List)) ; state output points to nothing - (Nil-List)))) - :ruleset memory-helpers) - -; arg pointees * loop in * loop out * i64 -> result pointees -(function PointsToCellsAtIter (Pointees Expr Expr i64) Pointees) - -; compute first two -(rule ((= e (DoWhile inputs pred-body)) - (PointsToCells e aps)) - ((set (PointsToCellsAtIter aps inputs pred-body 0) - (PointsToCells inputs aps)) - (set (PointsToCellsAtIter aps inputs pred-body 1) - (UnionPointees - (PointsToCellsAtIter aps inputs pred-body 0) - (PointeesDropFirst - (PointsToCells pred-body (PointsToCellsAtIter aps inputs pred-body 0)))))) - :ruleset memory-helpers) - -; avoid quadratic query -(function succ (i64) i64 :unextractable) -(rule ((PointsToCellsAtIter aps inputs pred-body i)) - ((set (succ i) (+ i 1))) - :ruleset memory-helpers) - -; Note that this rule is bounded by ruleset memory -(rule ((= pointees0 (PointsToCellsAtIter aps inputs pred-body i)) - (= pointees1 (PointsToCellsAtIter aps inputs pred-body (succ i))) - (Resolved-Pointees pointees0) - (Resolved-Pointees pointees1) - (!= pointees0 pointees1)) - ((set (PointsToCellsAtIter aps inputs pred-body (+ i 2)) - (UnionPointees - pointees1 - (PointeesDropFirst - (PointsToCells pred-body pointees1))))) - :ruleset memory) - -(rule ((= pointees (PointsToCellsAtIter aps inputs pred-body i)) - (= pointees (PointsToCellsAtIter aps inputs pred-body (succ i)))) - ((set (PointsToCells (DoWhile inputs pred-body) aps) - pointees)) - :ruleset memory) - -(rule ((PtrPointsTo (PointsTo l))) - ((DemandAt-List l)) - :ruleset memory-helpers) -(rule ((TuplePointsTo l)) - ((DemandAt-List l)) - :ruleset memory-helpers) - -; ============================ -; Update DontAlias -; ============================ - -(relation DemandDontAlias (Expr Expr Pointees)) -; pointer, pointer, arg pointees -(relation DontAlias (Expr Expr Pointees)) - - -(rule ((DemandDontAlias ptr1 ptr2 arg-pointees) - (BodyContainsExpr body ptr1) - (BodyContainsExpr body ptr2) - (HasType ptr1 (Base (PointerT ty))) - (HasType ptr2 (Base (PointerT ty))) - (= pointees1 (PointsToCells ptr1 arg-pointees)) - (= pointees2 (PointsToCells ptr2 arg-pointees))) - ((IntersectPointees pointees1 pointees2)) - :ruleset memory-helpers) - -(rule ((PointsNowhere - (IntersectPointees - (PointsToCells ptr1 arg-pointees) - (PointsToCells ptr2 arg-pointees)))) - ((DontAlias ptr1 ptr2 arg-pointees)) - :ruleset memory-helpers) - -; ============================ -; Update PointsToExpr -; ============================ - -; program point, pointer -(function PointsToExpr (Expr Expr) Expr :unextractable) - -; After a load, the ptr points to the loaded value -(rule ((= f (Bop (Load) ptr state))) - ((set (PointsToExpr (Get f 1) ptr) (Get f 0))) - :ruleset memory-helpers) - -; If we load and we already know what the pointer points to -; TODO this rule breaks the weakly linear invariant -; when a previous load may not be on the path -;(rule ((= e (Bop (Load) addr state)) -; (= v (PointsToExpr state addr))) -; ((union (Get e 0) v) -; (union (Get e 1) state)) -; :ruleset memory-helpers) - -; Loads and prints don't affect what what pointers already point to -(rule ((= f (PointsToExpr state addr)) - (= e (Bop (Load) any-addr state))) - ((let new-state (Get e 1)) - (union (PointsToExpr new-state addr) f)) - :ruleset memory-helpers) -(rule ((= f (PointsToExpr state addr)) - (= e (Bop (Print) any-val state))) - ((let new-state e) - (union (PointsToExpr new-state addr) f)) - :ruleset memory-helpers) - -; Writes don't affect what a pointer points to if it writes to another pointer -; guaranteed to not alias. -(rule ((= e (Top (Write) addr data state)) - (HasArgType addr argty) - (= otherdata (PointsToExpr state otheraddr))) - ((DemandDontAlias addr otheraddr (TypeToPointees argty))) - :ruleset memory-helpers) -(rule ((= e (Top (Write) addr data state)) - (HasArgType addr argty) - (= otherdata (PointsToExpr state otheraddr)) - (DontAlias addr otheraddr (TypeToPointees argty))) - ((set (PointsToExpr e otheraddr) otherdata)) - :ruleset memory-helpers) - -; For a write, mark the given expression as containing `data`. -(rule ((= e (Top (Write) addr data state))) - ((union (PointsToExpr e addr) data)) - :ruleset memory-helpers) - -; ============================ -; Update CellHasValues (currently unused) -; ============================ - -; ; program point, cell -; (function CellHasValues (Expr i64) ExprSet :merge (ExprSet-intersect old new)) - -; ; At the time of an alloc, a cell doesn't contain any values -; (rule ((= f (Alloc id amt state ty))) - ; ((set (CellHasValues (Get f 1) id) (ES (set-empty)))) - ; :ruleset memory-helpers) - -; ; These two rules find (Write ptr val state) where -; ; ptr points to cells given no assumptions about where (Arg) points. -; ; TODO: make sensitive to offsets -; (rule ((= e (Top (Write) ptr val state)) - ; (HasArgType ptr argty)) - ; ((TypeToPointees argty)) - ; :ruleset memory-helpers) -; (rule ((= e (Top (Write) ptr val state)) - ; (HasArgType ptr argty) - ; (= (PtrPointsTo (PointsTo cells)) (PointsToCells ptr (TypeToPointees argty))) - ; (At-List cells any-idx alloc-id offsets) - ; (= vals (CellHasValues state cell))) - ; ((set (CellHasValues e cell) (ExprSet-insert vals val))) - ; :ruleset memory-helpers) - -;; Loop Invariant - -;; bool: whether the term in the Expr is an invariant. -(function is-inv-Expr (Expr Expr) bool :unextractable :merge (or old new)) -(function is-inv-ListExpr (Expr ListExpr) bool :unextractable :merge (or old new)) - -;; in default, when there is a find, set is-inv to false -(rule ((BodyContainsExpr loop term) - (= loop (DoWhile inputs pred_out))) - ((set (is-inv-Expr loop term) false)) :ruleset always-run) -(rule ((BodyContainsListExpr loop term) - (= loop (DoWhile inputs pred_out))) - ((set (is-inv-ListExpr loop term) false)) :ruleset always-run) - -(relation is-inv-ListExpr-helper (Expr ListExpr i64)) -(rule ((BodyContainsListExpr loop list) - (= loop (DoWhile inputs pred_out))) - ((is-inv-ListExpr-helper loop list 0)) :ruleset always-run) - -(rule ((is-inv-ListExpr-helper loop list i) - (= true (is-inv-Expr loop expr)) - (= expr (ListExpr-ith list i))) - ((is-inv-ListExpr-helper loop list (+ i 1))) :ruleset always-run) - -(rule ((is-inv-ListExpr-helper loop list i) - (= i (ListExpr-length list))) - ((set (is-inv-ListExpr loop list) true)) :ruleset always-run) - - -(ruleset boundary-analysis) -;; An Expr is on boundary when it is invariant and its parent is not -; loop invariant-expr -(relation boundary-Expr (Expr Expr)) - -;; boundary for ListExpr's children -(rule ((= true (is-inv-Expr loop expr)) - (= false (is-inv-ListExpr loop list)) - (= expr (ListExpr-ith list i))) - ((boundary-Expr loop expr)) :ruleset boundary-analysis) - -;; if a output branch/pred is invariant, it's also boundary-Expr -(rule ((= true (is-inv-Expr loop expr)) - (= loop (DoWhile in pred_out)) - (= expr (Get pred_out i))) - ((boundary-Expr loop expr)) :ruleset boundary-analysis) - - -(function hoisted-loop (Expr Expr) bool :unextractable :merge (or old new) ) -(rule ((= loop (DoWhile in pred_out))) - ((set (hoisted-loop in pred_out) false)) :ruleset always-run) - -(function InExtendedLoop (Expr Expr Expr) Assumption) - -;; mock function -(ruleset loop-inv-motion) - -(rule ((boundary-Expr loop inv) - (> (Expr-size inv) 1) - ;; TODO: replace Expr-size when cost model is ready - (= loop (DoWhile in pred_out)) - ;; the outter assumption of the loop - (ContextOf loop loop_ctx) - (HasType in in_type) - (HasType inv inv_type) - (= inv_type (Base base_inv_ty)) - (= in_type (TupleT tylist)) - (= false (hoisted-loop in pred_out)) - (= len (tuple-length in))) - ((let new_input (Concat in (Single (Subst loop_ctx in inv)))) - (let new_input_type (TupleT (TLConcat tylist (TCons base_inv_ty (TNil))))) - ;; create an virtual assume node, union it with actuall InLoop later - (let assum (InExtendedLoop in pred_out new_input)) - (let new_out_branch (Get (Arg new_input_type assum) len)) - ;; this two subst only change arg to arg with new type - (let substed_pred_out (Subst assum (Arg new_input_type assum) pred_out)) - (let inv_in_new_loop (Subst assum (Arg new_input_type assum) inv)) - (let new_pred_out (Concat substed_pred_out (Single new_out_branch))) - - (let new_loop (DoWhile new_input new_pred_out)) - (union assum (InLoop new_input new_pred_out)) - (union inv_in_new_loop new_out_branch) - (let wrapper (SubTuple new_loop 0 len)) - (union loop wrapper) - (subsume (DoWhile in pred_out)) - ;; don't hoist same loop again - (set (hoisted-loop in pred_out) true) - ) - :ruleset loop-inv-motion) - - -(rule ((BodyContainsExpr loop expr) - (= loop (DoWhile in out)) - (= expr (Const _n _ty _ctx))) - ((set (is-inv-Expr loop expr) true)) :ruleset always-run) - -(rule ((BodyContainsExpr loop expr) - (= loop (DoWhile in out)) - (= expr (Get (Arg ty ctx) i)) - (= loop (DoWhile in pred_out)) - (= expr (Get pred_out (+ i 1)))) - ((set (is-inv-Expr loop expr) true)) :ruleset always-run) - -(rule ((BodyContainsExpr loop expr) - (= loop (DoWhile in out)) - (= expr (Function _name _tyin _tyout _out)) - - ) - ((set (is-inv-Expr loop expr) true)) :ruleset always-run) - -(rule ((BodyContainsExpr loop expr) - (= loop (DoWhile in out)) - (= expr (Top _op _x _y _z)) - (= true (is-inv-Expr loop _x)) (= true (is-inv-Expr loop _y)) (= true (is-inv-Expr loop _z)) - ) - ((set (is-inv-Expr loop expr) true)) :ruleset always-run) - -(rule ((BodyContainsExpr loop expr) - (= loop (DoWhile in out)) - (= expr (Bop _op _x _y)) (BinaryOpIsPure _op) - (= true (is-inv-Expr loop _x)) (= true (is-inv-Expr loop _y)) - ) - ((set (is-inv-Expr loop expr) true)) :ruleset always-run) - -(rule ((BodyContainsExpr loop expr) - (= loop (DoWhile in out)) - (= expr (Uop _op _x)) (UnaryOpIsPure _op) - (= true (is-inv-Expr loop _x)) - ) - ((set (is-inv-Expr loop expr) true)) :ruleset always-run) - -(rule ((BodyContainsExpr loop expr) - (= loop (DoWhile in out)) - (= expr (Get _tup _i)) - (= true (is-inv-Expr loop _tup)) - ) - ((set (is-inv-Expr loop expr) true)) :ruleset always-run) - -(rule ((BodyContainsExpr loop expr) - (= loop (DoWhile in out)) - (= expr (Concat _x _y)) - (= true (is-inv-Expr loop _x)) (= true (is-inv-Expr loop _y)) - ) - ((set (is-inv-Expr loop expr) true)) :ruleset always-run) - -(rule ((BodyContainsExpr loop expr) - (= loop (DoWhile in out)) - (= expr (Single _x)) - (= true (is-inv-Expr loop _x)) - ) - ((set (is-inv-Expr loop expr) true)) :ruleset always-run) - -(rule ((BodyContainsExpr loop expr) - (= loop (DoWhile in out)) - (= expr (Switch _pred _inputs _branches)) - (= true (is-inv-Expr loop _pred)) (= true (is-inv-Expr loop _inputs)) (= true (is-inv-ListExpr loop _branches)) - ) - ((set (is-inv-Expr loop expr) true)) :ruleset always-run) - -(rule ((BodyContainsExpr loop expr) - (= loop (DoWhile in out)) - (= expr (If _pred _input _then _else)) - (= true (is-inv-Expr loop _pred)) (= true (is-inv-Expr loop _input)) - ) - ((set (is-inv-Expr loop expr) true)) :ruleset always-run) - -(rule ((BodyContainsExpr loop expr) - (= loop (DoWhile in out)) - (= expr (DoWhile _in _pred-and-output)) - (= true (is-inv-Expr loop _in)) - (ExprIsPure expr)) - ((set (is-inv-Expr loop expr) true)) :ruleset always-run) - -(rule ((BodyContainsExpr loop expr) - (= loop (DoWhile in out)) - (= expr (Call _func _arg)) - (= true (is-inv-Expr loop _arg)) - (ExprIsPure expr)) - ((set (is-inv-Expr loop expr) true)) :ruleset always-run) - -(rule ((BodyContainsExpr loop expr) - (= loop (DoWhile in out)) - (= expr (Empty _ty _ctx)) - - ) - ((set (is-inv-Expr loop expr) true)) :ruleset always-run) - - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (Top _op _x _y _z)) - (= expr1 _x)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (Top _op _x _y _z)) - (= expr1 _y)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (Top _op _x _y _z)) - (= expr1 _z)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (Bop _op _x _y)) - (= expr1 _x)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (Bop _op _x _y)) - (= expr1 _y)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (Uop _op _x)) - (= expr1 _x)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (Concat _x _y)) - (= expr1 _x)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (Concat _x _y)) - (= expr1 _y)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (Single _x)) - (= expr1 _x)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (Switch _pred _inputs _branches)) - (= expr1 _pred)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (Switch _pred _inputs _branches)) - (= expr1 _inputs)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (If _pred _input _then _else)) - (= expr1 _pred)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (If _pred _input _then _else)) - (= expr1 _input)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (DoWhile _in _pred-and-output)) - (= expr1 _in)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (Call _func _arg)) - (= expr1 _arg)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (Alloc _id _e _state _ty)) - (= expr1 _e)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) - -(rule ((= true (is-inv-Expr loop expr1)) - (= false (is-inv-Expr loop expr2)) - (= expr2 (Alloc _id _e _state _ty)) - (= expr1 _state)) - ((boundary-Expr loop expr1)) :ruleset boundary-analysis) -;; Some simple simplifications of loops -(ruleset loop-simplify) - -(rewrite - (DoWhile (Arg ty ctx) - (Concat (Single (Const (Bool false) ty ctx2)) - (Single (Const constant ty ctx2)))) - (Single (Const constant ty ctx)) - :ruleset loop-simplify) -;; Some simple simplifications of loops -(ruleset loop-unroll) -(ruleset loop-peel) - -;; inputs, outputs -> number of iterations -;; The minimum possible guess is 1 because of do-while loops -;; TODO: dead loop deletion can turn loops with a false condition to a body -(function LoopNumItersGuess (Expr Expr) i64 :merge (max 1 (min old new))) - -;; by default, guess that all loops run 1000 times -(rule ((DoWhile inputs outputs)) - ((set (LoopNumItersGuess inputs outputs) 1000)) - :ruleset always-run) - -;; Figure out number of iterations for a loop with constant bounds and initial value -;; and i is updated before checking pred -;; TODO: can make this work for increment by any constant -(rule - ((= lhs (DoWhile inputs outputs)) - (= num-inputs (tuple-length inputs)) - (= pred (Get outputs 0)) - ;; iteration counter starts at start_const - (= (Const (Int start_const) _ty1 _ctx1) (Get inputs counter_i)) - ;; updated counter at counter_i - (= next_counter (Get outputs (+ counter_i 1))) - ;; increments by one each loop - (= next_counter (Bop (Add) (Get (Arg _ty _ctx) counter_i) - ;; TODO: put c instead of (Int 1) and mul by c - (Const (Int 1) _ty2 _ctx2))) - ;; while next_counter less than end_constant - (= pred (Bop (LessThan) next_counter - (Const (Int end_constant) _ty3 _ctx3))) - ;; end constant is greater than start constant - (> end_constant start_const) - ) - ( - (set (LoopNumItersGuess inputs outputs) (- end_constant start_const)) - ) - :ruleset always-run) - -;; Figure out number of iterations for a loop with constant bounds and initial value -;; and i is updated after checking pred -(rule - ((= lhs (DoWhile inputs outputs)) - (= num-inputs (tuple-length inputs)) - (= pred (Get outputs 0)) - ;; iteration counter starts at start_const - (= (Const (Int start_const) _ty1 _ctx1) (Get inputs counter_i)) - ;; updated counter at counter_i - (= next_counter (Get outputs (+ counter_i 1))) - ;; increments by one each loop - (= next_counter (Bop (Add) (Get (Arg _ty _ctx) counter_i) - (Const (Int 1) _ty2 _ctx2))) - ;; while this counter less than end_constant - (= pred (Bop (LessThan) (Get (Arg _ty _ctx) counter_i) - (Const (Int end_constant) _ty3 _ctx3))) - ;; end constant is greater than start constant - (> end_constant start_const) - ) - ( - (set (LoopNumItersGuess inputs outputs) (+ (- end_constant start_const) 1)) - ) - :ruleset always-run) - -;; loop peeling rule -;; Only peel loops that we know iterate < 5 times -(rule - ((= lhs (DoWhile inputs outputs)) - (ContextOf lhs ctx) - (HasType inputs inputs-ty) - (= outputs-len (tuple-length outputs)) - (= old_cost (LoopNumItersGuess inputs outputs)) - (< old_cost 5) - ) - ( - (let executed-once - (Subst ctx inputs outputs)) - (let executed-once-body - (SubTuple executed-once 1 (- outputs-len 1))) - (let then-ctx - (InIf true (Get executed-once 0) executed-once-body)) - (let else-ctx - (InIf false (Get executed-once 0) executed-once-body)) - (union lhs - ;; check if we need to continue executing the loop - (If (Get executed-once 0) - executed-once-body ;; inputs are the body executed once - (DoWhile (Arg inputs-ty then-ctx) - outputs) ;; right now, loop unrolling shares the same outputs, but we could add more context here - (Arg inputs-ty else-ctx))) - (set (LoopNumItersGuess (Arg inputs-ty then-ctx) outputs) (- old_cost 1)) - ) - :ruleset loop-peel) - -;; unroll a loop with constant bounds and initial value -(rule - ((= lhs (DoWhile inputs outputs)) - (= num-inputs (tuple-length inputs)) - (= pred (Get outputs 0)) - ;; iteration counter starts at start_const - (= (Const (Int start_const) _ty1 _ctx1) (Get inputs counter_i)) - ;; updated counter at counter_i - (= next_counter (Get outputs (+ counter_i 1))) - ;; increments by one each loop - (= next_counter (Bop (Add) (Get (Arg _ty _ctx) counter_i) - (Const (Int 1) _ty2 _ctx2))) - ;; while less than end_constant - (= pred (Bop (LessThan) next_counter - (Const (Int end_constant) _ty3 _ctx3))) - ;; start and end constant is a multiple of 4 and greater than start_const - (> end_constant start_const) - (= (% start_const 4) 0) - (= (% end_constant 4) 0) - (= old_cost (LoopNumItersGuess inputs outputs)) - ) - ( - (let one-iter (SubTuple outputs 1 num-inputs)) - (let unrolled - (Subst (TmpCtx) one-iter - (Subst (TmpCtx) one-iter - (Subst (TmpCtx) one-iter - outputs)))) - (union lhs - (DoWhile inputs - unrolled)) - (let actual-ctx (InLoop inputs unrolled)) - (union (TmpCtx) actual-ctx) - - (set (LoopNumItersGuess inputs unrolled) (/ old_cost 4)) - (delete (TmpCtx)) - ) - :ruleset loop-unroll) - - - -(ruleset passthrough) - - -;; Pass through thetas -(rule ((= lhs (Get loop i)) - (= loop (DoWhile inputs pred-outputs)) - (= (Get pred-outputs (+ i 1)) (Get (Arg _ty _ctx) i)) - ;; only pass through pure types, since some loops don't terminate - ;; so the state edge must pass through them - (HasType (Get loop i) lhs_ty) - (PureType lhs_ty) - ) - ((union lhs (Get inputs i))) - :ruleset passthrough) - -;; Pass through switch arguments -(rule ((= lhs (Get switch i)) - (= switch (Switch pred inputs branches)) - (= (ListExpr-length branches) 2) - (= branch0 (ListExpr-ith branches 0)) - (= branch1 (ListExpr-ith branches 1)) - (= (Get branch0 i) (Get (Arg _ _ctx0) j)) - (= (Get branch1 i) (Get (Arg _ _ctx1) j)) - (= passed-through (Get inputs j)) - (HasType lhs lhs_ty) - (!= lhs_ty (Base (StateT)))) - ((union lhs passed-through)) - :ruleset passthrough) - -;; Pass through switch predicate -(rule ((= lhs (Get switch i)) - (= switch (Switch pred inputs branches)) - (= (ListExpr-length branches) 2) - (= branch0 (ListExpr-ith branches 0)) - (= branch1 (ListExpr-ith branches 1)) - (= (Get branch0 i) (Const (Bool false) _ _ctx0)) - (= (Get branch1 i) (Const (Bool true) _ _ctx1))) - ((union lhs pred)) - :ruleset passthrough) - -;; Pass through if arguments -(rule ((= if (If pred inputs then_ else_)) - (= (Get then_ i) (Get (Arg arg_ty _then_ctx) j)) - (= (Get else_ i) (Get (Arg arg_ty _else_ctx) j)) - (HasType (Get then_ i) lhs_ty) - (!= lhs_ty (Base (StateT)))) - ((union (Get if i) (Get inputs j))) - :ruleset passthrough) - -; Pass through if state edge arguments -; To maintain the invariant, we have to union the other outputs with a pure if statement -;; TODO This rule causes blowup in the egraph, unclear why -;; disabled for now -(ruleset pass-through-state-edge-if) -(rule ((= outputs (If pred inputs then_ else_)) - - (= (Get then_ i) (Get (Arg arg_ty then_ctx) j)) - (= (Get else_ i) (Get (Arg arg_ty else_ctx) j)) - - (HasType (Get then_ i) (Base (StateT)))) - - ((let lhs (Get outputs i)) - (let new_inputs (TupleRemoveAt inputs j)) - - (let new_then_ctx (InIf true pred new_inputs)) - (let new_else_ctx (InIf false pred new_inputs)) - - (let old_then (TupleRemoveAt then_ i)) - (let old_else (TupleRemoveAt else_ i)) - - (let new_then (DropAt new_then_ctx j old_then)) - (let new_else (DropAt new_else_ctx j old_else)) - - (let old_outputs (TupleRemoveAt outputs i)) - (let new_if (If pred new_inputs new_then new_else)) - (union new_if old_outputs) - - (union lhs (Get inputs j)) - ;; Be careful not to subsume the original if statement immediately, - ;; since TupleRemoveAt still needs to match on it - (ToSubsumeIf pred inputs then_ else_)) - :ruleset pass-through-state-edge-if) - - -;; Pass through if predicate -(rule ((= if (If pred inputs then_ else_)) - (= (Get then_ i) (Const (Bool true) _ _thenctx)) - (= (Get else_ i) (Const (Bool false) _ _elsectx))) - - ((let new_then (TupleRemoveAt then_ i)) - (let new_else (TupleRemoveAt else_ i)) - (let new_if (If pred inputs new_then new_else)) - - (union (Get if i) pred) - (union (TupleRemoveAt if i) new_if) - (ToSubsumeIf pred inputs then_ else_)) - :ruleset passthrough) - -;; ORIGINAL -;; a = 0 -;; c = 3 -;; for i = 0 to n: -;; a = i * c -;; -;; OPTIMIZED -;; a = 0 -;; c = 3 -;; d = 0 -;; for i = 0 to n: -;; a += d -;; d += c -(ruleset loop-strength-reduction) - -; Finds invariants/constants within a body. -; Columns: body; value of invariant in inputs; value of invariant in outputs -;; Get the input and output value of an invariant, or constant int, within the loop -;; loop in out -(relation lsr-inv (Expr Expr Expr)) - -; TODO: there may be a bug with finding the invariant, or it just may not be extracted. -; Can make this work on loop_with_mul_by_inv and a rust test later. -; (rule ( -; (= loop (DoWhile inputs pred-and-body)) -; (= (Get outputs (+ i 1)) (Get (Arg arg-type assm) i))) -; ((inv loop (Get inputs i) (Get (Arg arg-type assm) i))) :ruleset always-run) -(rule ( - (= loop (DoWhile inputs pred-and-body)) - (ContextOf inputs loop-input-ctx) - (ContextOf pred-and-body loop-output-ctx) - (= constant (Const c out-type loop-output-ctx)) - (HasArgType inputs in-type) - ) - ((lsr-inv loop (Const c in-type loop-input-ctx) constant)) :ruleset always-run) - -(rule - ( - ;; Find loop - (= old-loop (DoWhile inputs pred-and-outputs)) - (ContextOf pred-and-outputs loop-ctx) - - ; Find loop variable (argument that gets incremented with an invariant) - (lsr-inv old-loop loop-incr-in loop-incr-out) - ; Since the first el of pred-and-outputs is the pred, we need to offset i - (= (Get pred-and-outputs (+ i 1)) (Bop (Add) (Get (Arg arg-type assm) i) loop-incr-out)) - - ; Find invariant where input is same as output, or constant - (lsr-inv old-loop c-in c-out) - - ; Find multiplication of loop variable and invariant - (= old-mul (Bop (Mul) c-out (Get (Arg arg-type assm) i))) - (ContextOf old-mul loop-ctx) - - (= arg-type (TupleT ty-list)) - ) - ( - ; Each time we need to update d by the product of the multiplied constant and the loop increment - (let addend (Bop (Mul) c-out loop-incr-out)) - - ; n is index of our new, temporary variable d - (let n (tuple-length inputs)) - - ; Initial value of d is i * c - (let d-init (Bop (Mul) c-in (Get inputs i))) - - ; Construct optimized theta - ; new-inputs already has the correct context - (let new-inputs (Concat inputs (Single d-init))) - - ; We need to create a new type, with one more input - (let new-arg-ty (TupleT (TLConcat ty-list (TCons (IntT) (TNil))))) - - ; Value of d in loop. Add context to addend - (let d-out (Bop (Add) (Get (Arg new-arg-ty (TmpCtx)) n) - (Subst (TmpCtx) (Arg new-arg-ty (TmpCtx)) addend))) - - ; build the old body, making sure to set the correct arg type and context - (let new-body - (Concat - (Subst (TmpCtx) (Arg new-arg-ty (TmpCtx)) pred-and-outputs) - (Single d-out))) - - (let new-loop (DoWhile new-inputs new-body)) - - ; Now that we have the new loop, union the temporary context with the actual ctx - (union (TmpCtx) (InLoop new-inputs new-body)) - - ; Substitute d for the *i expression - (let new-mul - (Bop - (Mul) - (Subst (TmpCtx) (Arg new-arg-ty (TmpCtx)) c-out) - (Get (Arg new-arg-ty (TmpCtx)) i))) - (union (Get (Arg new-arg-ty (TmpCtx)) n) new-mul) - - ; Subsume the multiplication in the new loop to prevent - ; from firing loop strength reduction again on the new loop - (subsume - (Bop - (Mul) - (Subst (TmpCtx) (Arg new-arg-ty (TmpCtx)) c-out) - (Get (Arg new-arg-ty (TmpCtx)) i))) - - ; Project all but last - (union old-loop (SubTuple new-loop 0 n)) - (delete (TmpCtx)) - ) - :ruleset loop-strength-reduction -) -(let __tmp0 (StateT )) -(let __tmp1 (TNil )) -(let __tmp2 (TCons __tmp0 __tmp1)) -(let __tmp3 (TupleT __tmp2)) -(let __tmp4 (Print )) -(let __tmp5 (InFunc "main")) -(let __tmp6 (Arg __tmp3 __tmp5)) -(let __tmp7 (Get __tmp6 0)) -(let __tmp8 (Single __tmp7)) -(let __tmp9 (Int 0)) -(let __tmp10 (Const __tmp9 __tmp3 __tmp5)) -(let __tmp11 (Single __tmp10)) -(let __tmp12 (Int 1)) -(let __tmp13 (Const __tmp12 __tmp3 __tmp5)) -(let __tmp14 (Single __tmp13)) -(let __tmp15 (Concat __tmp11 __tmp14)) -(let __tmp16 (Concat __tmp8 __tmp15)) -(let __tmp17 (LessThan )) -(let __tmp18 (IntT )) -(let __tmp19 (TCons __tmp18 __tmp1)) -(let __tmp20 (TCons __tmp18 __tmp19)) -(let __tmp21 (TCons __tmp0 __tmp20)) -(let __tmp22 (TupleT __tmp21)) -(let __tmp23 (InFunc "dummy")) -(let __tmp24 (Arg __tmp22 __tmp23)) -(let __tmp25 (Get __tmp24 1)) -(let __tmp26 (Get __tmp24 2)) -(let __tmp27 (Bop __tmp17 __tmp25 __tmp26)) -(let __tmp28 (Single __tmp27)) -(let __tmp29 (Get __tmp24 0)) -(let __tmp30 (Single __tmp29)) -(let __tmp31 (Add )) -(let __tmp32 (Bop __tmp31 __tmp26 __tmp25)) -(let __tmp33 (Single __tmp32)) -(let __tmp34 (Single __tmp26)) -(let __tmp35 (Concat __tmp33 __tmp34)) -(let __tmp36 (Concat __tmp30 __tmp35)) -(let __tmp37 (Concat __tmp28 __tmp36)) -(let __tmp38 (InLoop __tmp16 __tmp37)) -(let __tmp39 (Arg __tmp22 __tmp38)) -(let __tmp40 (Get __tmp39 1)) -(let __tmp41 (Get __tmp39 2)) -(let __tmp42 (Bop __tmp17 __tmp40 __tmp41)) -(let __tmp43 (Single __tmp42)) -(let __tmp44 (Get __tmp39 0)) -(let __tmp45 (Single __tmp44)) -(let __tmp46 (Bop __tmp31 __tmp41 __tmp40)) -(let __tmp47 (Single __tmp46)) -(let __tmp48 (Single __tmp41)) -(let __tmp49 (Concat __tmp47 __tmp48)) -(let __tmp50 (Concat __tmp45 __tmp49)) -(let __tmp51 (Concat __tmp43 __tmp50)) -(let __tmp52 (DoWhile __tmp16 __tmp51)) -(let __tmp53 (Get __tmp52 1)) -(let __tmp54 (Get __tmp52 0)) -(let __tmp55 (Bop __tmp4 __tmp53 __tmp54)) -(let __tmp56 (Single __tmp55)) -(let __tmp57 (Function "main" __tmp3 __tmp3 __tmp56)) -(let __tmp58 (Nil )) -(let __tmp59 (Program __tmp57 __tmp58)) - -(let PROG __tmp59) -(relation InlinedCall (String Expr)) - -; (let expected (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 2) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main")))))) - -; (let substituted ( Subst (InFunc "main") (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf true (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))))) 0)) (Concat (Single (Const (Int 2) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf true (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main")))))))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf true (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main")))))))))))) -; (let iftrue -; (If (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf true (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))))) 0)) (Concat (Single (Const (Int 2) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf true (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main")))))))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf true (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main")))))))))) (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf false (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))))))) -; (Debug (If (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf true (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))))) 0)) (Concat (Single (Const (Int 2) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf true (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main")))))))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf true (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main")))))))))) (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf false (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))))))) - (unstable-combined-ruleset saturating - always-run - passthrough - canon - type-analysis - context - interval-analysis - memory-helpers - ) - - - (unstable-combined-ruleset optimizations - loop-simplify - memory - loop-unroll - peepholes - loop-peel - ) - - (unstable-combined-ruleset expensive-optimizations - optimizations - switch_rewrite - ;loop-inv-motion - loop-strength-reduction - ) - - (run-schedule - -;; saturate all helpers first -(saturate - (saturate - (saturate type-helpers) ;; resolve type helpers, finding correct types - (saturate error-checking) ;; check for errors, relies on type-helpers saturating - saturating) - - (saturate drop) - apply-drop-unions - cleanup-drop - - subsume-after-helpers - - (saturate subst) ;; do e-substitution - apply-subst-unions ;; apply the unions from substitution - cleanup-subst ;; clean up substitutions that are done - - - (saturate boundary-analysis) ;; find boundaries of invariants -) - - - (repeat 2 - -;; saturate all helpers first -(saturate - (saturate - (saturate type-helpers) ;; resolve type helpers, finding correct types - (saturate error-checking) ;; check for errors, relies on type-helpers saturating - saturating) - - (saturate drop) - apply-drop-unions - cleanup-drop - - subsume-after-helpers - - (saturate subst) ;; do e-substitution - apply-subst-unions ;; apply the unions from substitution - cleanup-subst ;; clean up substitutions that are done - - - (saturate boundary-analysis) ;; find boundaries of invariants -) - - - expensive-optimizations) - (repeat 4 - -;; saturate all helpers first -(saturate - (saturate - (saturate type-helpers) ;; resolve type helpers, finding correct types - (saturate error-checking) ;; check for errors, relies on type-helpers saturating - saturating) - - (saturate drop) - apply-drop-unions - cleanup-drop - - subsume-after-helpers - - (saturate subst) ;; do e-substitution - apply-subst-unions ;; apply the unions from substitution - cleanup-subst ;; clean up substitutions that are done - - - (saturate boundary-analysis) ;; find boundaries of invariants -) - - - optimizations) - -;; saturate all helpers first -(saturate - (saturate - (saturate type-helpers) ;; resolve type helpers, finding correct types - (saturate error-checking) ;; check for errors, relies on type-helpers saturating - saturating) - - (saturate drop) - apply-drop-unions - cleanup-drop - - subsume-after-helpers - - (saturate subst) ;; do e-substitution - apply-subst-unions ;; apply the unions from substitution - cleanup-subst ;; clean up substitutions that are done - - - (saturate boundary-analysis) ;; find boundaries of invariants -) -(saturate - (saturate - (saturate type-helpers) ;; resolve type helpers, finding correct types - (saturate error-checking) ;; check for errors, relies on type-helpers saturating - saturating) - - (saturate drop) - apply-drop-unions - cleanup-drop - - subsume-after-helpers - - (saturate subst) ;; do e-substitution - apply-subst-unions ;; apply the unions from substitution - cleanup-subst ;; clean up substitutions that are done - - - (saturate boundary-analysis) ;; find boundaries of invariants -) - - -) - - -; (print-function Subst 100) -; (let substituted ( Subst (InFunc "main") (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf true (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))))) 0)) (Concat (Single (Const (Int 2) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf true (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main")))))))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf true (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main")))))))))))) -; (let thn (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf true (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))))) 0)) (Concat (Single (Const (Int 2) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf true (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main")))))))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf true (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))))))))) -; (let els (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InIf false (Const (Bool true) (TupleT (TCons (StateT) (TNil))) (InFunc "main")) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main")))))))) -; (query-extract :variants 5 thn) -; (query-extract :variants 5 els) -; (query-extract :variants 5 substituted) -(query-extract :variants 5 __tmp52) -; (check (= __tmp52 expected)) - -; (print-function Debug 10) -; (DoWhile (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 0) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InLoop (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 0) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 0)) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))))))) 1) (Const (Int 1) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InLoop (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 0) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 0)) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))))))))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InLoop (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 0) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 0)) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))))))) 0)) (Concat (Single (Bop (Add) (Const (Int 1) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InLoop (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 0) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 0)) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))))))) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InLoop (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 0) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 0)) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))))))) 1))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InLoop (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 0) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 0)) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2)))))))))))) -; (DoWhile (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InLoop (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 0) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 0)) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))))))) 1) (Const (Int 1) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InLoop (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 0) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 0)) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))))))))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InLoop (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 0) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 0)) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))))))) 0)) (Concat (Single (Bop (Add) (Const (Int 1) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InLoop (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 0) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 0)) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))))))) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InLoop (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 0) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 0)) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))))))) 1))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InLoop (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TNil))) (InFunc "main")) 0)) (Concat (Single (Const (Int 0) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))) (Single (Const (Int 1) (TupleT (TCons (StateT) (TNil))) (InFunc "main"))))) (Concat (Single (Bop (LessThan) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2))) (Concat (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 0)) (Concat (Single (Bop (Add) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2) (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 1))) (Single (Get (Arg (TupleT (TCons (StateT) (TCons (IntT) (TCons (IntT) (TNil))))) (InFunc "dummy")) 2)))))))))))) - -; (If ) \ No newline at end of file From 539cbd8514f00f1418f0f7cd54a7d4fd0ebf938e Mon Sep 17 00:00:00 2001 From: Kirsten <32720576+kirstenmg@users.noreply.github.com> Date: Thu, 23 May 2024 12:14:17 -0700 Subject: [PATCH 12/47] Update rulesets --- dag_in_context/src/optimizations/loop_unroll.egg | 9 +++++---- dag_in_context/src/optimizations/switch_rewrites.egg | 5 +++-- dag_in_context/src/schedule.rs | 2 ++ tests/snapshots/files__gamma_condition_and-optimize.snap | 2 +- tests/snapshots/files__sqrt-optimize.snap | 4 ++-- 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/dag_in_context/src/optimizations/loop_unroll.egg b/dag_in_context/src/optimizations/loop_unroll.egg index e02b53ef5..55135d7e5 100644 --- a/dag_in_context/src/optimizations/loop_unroll.egg +++ b/dag_in_context/src/optimizations/loop_unroll.egg @@ -1,6 +1,7 @@ ;; Some simple simplifications of loops (ruleset loop-unroll) (ruleset loop-peel) +(ruleset loop-iters-analysis) ;; inputs, outputs -> number of iterations ;; The minimum possible guess is 1 because of do-while loops @@ -10,14 +11,14 @@ ;; by default, guess that all loops run 1000 times (rule ((DoWhile inputs outputs)) ((set (LoopNumItersGuess inputs outputs) 1000)) - :ruleset always-run) + :ruleset loop-iters-analysis) ;; For a loop that is false, its num iters is 1 (rule ((= loop (DoWhile inputs outputs)) (= (Const (Bool false) ty ctx) (Get outputs 0))) ((set (LoopNumItersGuess inputs outputs) 1)) -:ruleset always-run) +:ruleset loop-iters-analysis) ;; Figure out number of iterations for a loop with constant bounds and initial value ;; and i is updated before checking pred @@ -43,7 +44,7 @@ ( (set (LoopNumItersGuess inputs outputs) (/ (- end_constant start_const) increment)) ) - :ruleset always-run) + :ruleset loop-iters-analysis) ;; Figure out number of iterations for a loop with constant bounds and initial value ;; and i is updated after checking pred @@ -68,7 +69,7 @@ ( (set (LoopNumItersGuess inputs outputs) (+ (/ (- end_constant start_const) increment) 1)) ) - :ruleset always-run) + :ruleset loop-iters-analysis) ;; loop peeling rule ;; Only peel loops that we know iterate < 5 times diff --git a/dag_in_context/src/optimizations/switch_rewrites.egg b/dag_in_context/src/optimizations/switch_rewrites.egg index 748f128d0..778c6eb95 100644 --- a/dag_in_context/src/optimizations/switch_rewrites.egg +++ b/dag_in_context/src/optimizations/switch_rewrites.egg @@ -1,4 +1,5 @@ (ruleset switch_rewrite) +(ruleset always-switch-rewrite) ; if (a and b) X Y ~~> if a (if b X Y) Y (rule ((= lhs (If (Bop (And) a b) ins X Y)) @@ -44,11 +45,11 @@ (rewrite (If (Const (Bool true) ty ctx) ins thn els) (Subst ctx ins thn) - :ruleset always-run) + :ruleset always-switch-rewrite) (rewrite (If (Const (Bool false) ty ctx) ins thn els) (Subst ctx ins els) - :ruleset switch_rewrite) + :ruleset always-switch-rewrite) (rule ((= lhs (If pred ins thn els)) (= (Get thn i) (Const (Bool true) ty ctx1)) diff --git a/dag_in_context/src/schedule.rs b/dag_in_context/src/schedule.rs index 40ec492b5..5ecada4d3 100644 --- a/dag_in_context/src/schedule.rs +++ b/dag_in_context/src/schedule.rs @@ -37,6 +37,8 @@ pub fn mk_schedule() -> String { context interval-analysis memory-helpers + always-switch-rewrite + loop-iters-analysis ) diff --git a/tests/snapshots/files__gamma_condition_and-optimize.snap b/tests/snapshots/files__gamma_condition_and-optimize.snap index 5b6fe2370..d2fb01cff 100644 --- a/tests/snapshots/files__gamma_condition_and-optimize.snap +++ b/tests/snapshots/files__gamma_condition_and-optimize.snap @@ -5,7 +5,7 @@ expression: visualization.result @main(v0: int) { .v1_: v2_: int = const 0; - v3_: bool = gt v0 v2_; + v3_: bool = lt v2_ v0; v4_: bool = lt v0 v2_; v5_: int = const 1; v6_: int = const 3; diff --git a/tests/snapshots/files__sqrt-optimize.snap b/tests/snapshots/files__sqrt-optimize.snap index 35f236503..fb7981af8 100644 --- a/tests/snapshots/files__sqrt-optimize.snap +++ b/tests/snapshots/files__sqrt-optimize.snap @@ -36,8 +36,8 @@ expression: visualization.result v29_: float = fadd v22_ v28_; v30_: float = fdiv v29_ v25_; v31_: float = fdiv v30_ v22_; - v32_: bool = fge v31_ v24_; - v33_: bool = fle v31_ v23_; + v32_: bool = fle v31_ v23_; + v33_: bool = fge v31_ v24_; v34_: bool = and v32_ v33_; v35_: bool = const true; v36_: float = id v21_; From 9b22a7762bdf53b1f62920e3297ab06d1e84954d Mon Sep 17 00:00:00 2001 From: Anjali Pal Date: Thu, 23 May 2024 13:05:00 -0700 Subject: [PATCH 13/47] backend --- infra/generate_cfgs.py | 48 ++++++++++++++++++++++++++++++++++++++++++ infra/nightly.sh | 3 +++ infra/profile.py | 3 ++- 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100755 infra/generate_cfgs.py diff --git a/infra/generate_cfgs.py b/infra/generate_cfgs.py new file mode 100755 index 000000000..747efaf7c --- /dev/null +++ b/infra/generate_cfgs.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +import glob +import os + +def make_cfgs(bench, data_dir): + print(bench) + cwd = os.getcwd() + path = f"{data_dir}/{bench}" + runmodes = os.listdir(path) + print(runmodes) + for mode in runmodes: + os.chdir(f"{path}/{mode}") + + # https://llvm.org/docs/Passes.html#dot-cfg-print-cfg-of-function-to-dot-file + cmd = "opt -disable-output -passes=dot-cfg llvm.ll > /dev/null 2>&1" + os.system(cmd) + + # Find all the dot files (can't use glob because it doesn't match hidden files) + # There are also a bunch of files that start with ._Z that I don't think we care about? + dots = [f for f in os.listdir(".") if f.endswith(".dot") and not f.startswith("._Z")] + for dot in dots: + name = dot.split(".")[1] + + # Convert to png + cmd = f"dot -Tpng -o {name}.png {dot}" + os.system(cmd) + + pngs = glob.glob("*.png") + with open("png_names.txt", "w") as f: + f.write("\n".join(pngs)) + + # Clean up dot files + os.system("rm .*.dot") + + # Reset dir + os.chdir(cwd) + + +if __name__ == '__main__': + # expect a single argument + if len(os.sys.argv) != 2: + print("Usage: generate_line_counts.py ") + exit(1) + data_dir = os.sys.argv[1] + print(data_dir) + benchmarks = os.listdir(data_dir) + for bench in benchmarks: + make_cfgs(bench, data_dir) diff --git a/infra/nightly.sh b/infra/nightly.sh index e9eb8ac26..2a5809440 100755 --- a/infra/nightly.sh +++ b/infra/nightly.sh @@ -62,6 +62,9 @@ fi # Generate latex after running the profiler (depends on profile.json) ./infra/generate_line_counts.py "$NIGHTLY_DIR" +# Generate CFGs for LLVM after running the profiler +./infra/generate_cfgs.py "$NIGHTLY_DIR/data/llvm" + rm -r ./tmp/ popd diff --git a/infra/profile.py b/infra/profile.py index 45936e3b2..6d4db55d1 100755 --- a/infra/profile.py +++ b/infra/profile.py @@ -103,8 +103,9 @@ def should_have_llvm_ir(runMethod): def dump_llvm_ir(runMethod, benchmark, output_directory): from_path = f'./tmp/bench/{benchmark}/llvm-{runMethod}/{benchmark}-{runMethod}.ll' - to_path = f'{output_directory}/data/llvm/{benchmark}-{runMethod}.ll' + to_path = f'{output_directory}/data/llvm/{benchmark}/{runMethod}/llvm.ll' + os.system(f'mkdir -p {output_directory}/data/llvm/{benchmark}/{runMethod}') os.system(f'cp {from_path} {to_path}') From 0e92f0c7b54888495e485fd00a08d7d109e6448c Mon Sep 17 00:00:00 2001 From: Anjali Pal Date: Thu, 23 May 2024 13:29:51 -0700 Subject: [PATCH 14/47] frontend --- infra/generate_cfgs.py | 2 +- infra/nightly-resources/handlers.js | 35 ++++++++++++++++++++++++-- infra/nightly-resources/llvm.html | 3 ++- infra/nightly-resources/stylesheet.css | 5 ++++ 4 files changed, 41 insertions(+), 4 deletions(-) diff --git a/infra/generate_cfgs.py b/infra/generate_cfgs.py index 747efaf7c..b812261f9 100755 --- a/infra/generate_cfgs.py +++ b/infra/generate_cfgs.py @@ -17,7 +17,7 @@ def make_cfgs(bench, data_dir): # Find all the dot files (can't use glob because it doesn't match hidden files) # There are also a bunch of files that start with ._Z that I don't think we care about? - dots = [f for f in os.listdir(".") if f.endswith(".dot") and not f.startswith("._Z")] + dots = [f for f in os.listdir(".") if f.endswith(".dot") and not f.startswith("._Z") and not f.startswith("._bril")] for dot in dots: name = dot.split(".")[1] diff --git a/infra/nightly-resources/handlers.js b/infra/nightly-resources/handlers.js index 65667762c..0d24822bf 100644 --- a/infra/nightly-resources/handlers.js +++ b/infra/nightly-resources/handlers.js @@ -31,8 +31,39 @@ async function load_llvm() { if (!benchmark || !runMode) { console.error("missing query params, this probably shouldn't happen"); } - const llvm = await fetchText(`./data/llvm/${benchmark}-${runMode}.ll`); - document.getElementById("llvm").innerText = llvm; + const llvm = await fetchText(`./data/llvm/${benchmark}/${runMode}/llvm.ll`); + document.getElementById("llvm-ir").innerText = llvm; + let pngs = ( + await fetchText(`./data/llvm/${benchmark}/${runMode}/png_names.txt`) + ).split("\n"); + + // Move main.png and _main.png to top + const _main = "_main.png"; + if (pngs.includes(_main)) { + pngs = pngs.filter((x) => x !== _main); + pngs.unshift(_main); + } + const main = "main.png"; + if (pngs.includes(main)) { + pngs = pngs.filter((x) => x !== main); + pngs.unshift(main); + } + + const pngContainer = document.getElementById("llvm-cfg"); + pngs.forEach((png) => { + const elt = document.createElement("div"); + + const img = document.createElement("img"); + img.className = "cfg"; + img.src = `data/llvm/${benchmark}/${runMode}/${png}`; + elt.appendChild(img); + + const p = document.createElement("p"); + p.innerText = png; + elt.appendChild(p); + + pngContainer.appendChild(elt); + }); } async function load_table() { diff --git a/infra/nightly-resources/llvm.html b/infra/nightly-resources/llvm.html index e11c17576..c9c1fd081 100644 --- a/infra/nightly-resources/llvm.html +++ b/infra/nightly-resources/llvm.html @@ -19,7 +19,8 @@

LLVM

-
+
+
diff --git a/infra/nightly-resources/stylesheet.css b/infra/nightly-resources/stylesheet.css index 43a11098a..f857c779c 100644 --- a/infra/nightly-resources/stylesheet.css +++ b/infra/nightly-resources/stylesheet.css @@ -58,4 +58,9 @@ body { #speedup-formula { visibility: hidden; +} + +.cfg { + height: 200px; + display: block; } \ No newline at end of file From f36cef019332ddada7785276e1ea042201ad383c Mon Sep 17 00:00:00 2001 From: Kirsten <32720576+kirstenmg@users.noreply.github.com> Date: Thu, 23 May 2024 13:59:22 -0700 Subject: [PATCH 15/47] Update snapshot --- dag_in_context/src/optimizations/loop_unroll.egg | 4 ++-- dag_in_context/src/schedule.rs | 2 +- tests/snapshots/files__jumping_loop-optimize.snap | 14 ++++++++++++++ .../files__unroll_multiple_4-optimize.snap | 10 +++++----- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/dag_in_context/src/optimizations/loop_unroll.egg b/dag_in_context/src/optimizations/loop_unroll.egg index 55135d7e5..022756849 100644 --- a/dag_in_context/src/optimizations/loop_unroll.egg +++ b/dag_in_context/src/optimizations/loop_unroll.egg @@ -72,14 +72,14 @@ :ruleset loop-iters-analysis) ;; loop peeling rule -;; Only peel loops that we know iterate < 5 times +;; Only peel loops that we know iterate < 3 times (rule ((= lhs (DoWhile inputs outputs)) (ContextOf lhs ctx) (HasType inputs inputs-ty) (= outputs-len (tuple-length outputs)) (= old_cost (LoopNumItersGuess inputs outputs)) - (< old_cost 5) + (< old_cost 3) ) ( (let executed-once diff --git a/dag_in_context/src/schedule.rs b/dag_in_context/src/schedule.rs index 5ecada4d3..e77e5b72d 100644 --- a/dag_in_context/src/schedule.rs +++ b/dag_in_context/src/schedule.rs @@ -47,7 +47,6 @@ pub fn mk_schedule() -> String { memory loop-unroll peepholes - loop-peel ) (unstable-combined-ruleset expensive-optimizations @@ -55,6 +54,7 @@ pub fn mk_schedule() -> String { switch_rewrite ;loop-inv-motion loop-strength-reduction + loop-peel ) (run-schedule diff --git a/tests/snapshots/files__jumping_loop-optimize.snap b/tests/snapshots/files__jumping_loop-optimize.snap index a1c1c23ac..03867db9c 100644 --- a/tests/snapshots/files__jumping_loop-optimize.snap +++ b/tests/snapshots/files__jumping_loop-optimize.snap @@ -4,4 +4,18 @@ expression: visualization.result --- @main { .v0_: + v1_: int = const 0; + v2_: int = const 18; + v3_: int = const 4; + v4_: int = id v1_; + v5_: int = id v2_; + v6_: int = id v3_; +.v7_: + v8_: int = add v4_ v6_; + v9_: bool = lt v8_ v5_; + v4_: int = id v8_; + v5_: int = id v5_; + v6_: int = id v6_; + br v9_ .v7_ .v10_; +.v10_: } diff --git a/tests/snapshots/files__unroll_multiple_4-optimize.snap b/tests/snapshots/files__unroll_multiple_4-optimize.snap index 093bd6745..e338c81fa 100644 --- a/tests/snapshots/files__unroll_multiple_4-optimize.snap +++ b/tests/snapshots/files__unroll_multiple_4-optimize.snap @@ -4,11 +4,11 @@ expression: visualization.result --- @main { .v0_: - v1_: int = const 16; - v2_: int = const 0; + v1_: int = const 0; + v2_: int = const 16; v3_: int = const 1; - v4_: int = id v2_; - v5_: int = id v1_; + v4_: int = id v1_; + v5_: int = id v2_; v6_: int = id v3_; .v7_: v8_: int = add v4_ v6_; @@ -21,5 +21,5 @@ expression: visualization.result v6_: int = id v6_; br v12_ .v7_ .v13_; .v13_: - print v1_; + print v4_; } From 7d2f43ff904e895af8bc4913df4011b68b5af8d3 Mon Sep 17 00:00:00 2001 From: Anjali Pal Date: Thu, 23 May 2024 15:10:11 -0700 Subject: [PATCH 16/47] Make the cfgs actually look nice --- infra/nightly-resources/handlers.js | 75 ++++++-------------------- infra/nightly-resources/index.html | 26 +++++---- infra/nightly-resources/index.js | 2 +- infra/nightly-resources/llvm.html | 13 ++--- infra/nightly-resources/llvm.js | 43 +++++++++++++++ infra/nightly-resources/stylesheet.css | 12 ++--- infra/nightly-resources/table.html | 6 --- 7 files changed, 84 insertions(+), 93 deletions(-) create mode 100644 infra/nightly-resources/llvm.js diff --git a/infra/nightly-resources/handlers.js b/infra/nightly-resources/handlers.js index 0d24822bf..1e1a12c21 100644 --- a/infra/nightly-resources/handlers.js +++ b/infra/nightly-resources/handlers.js @@ -24,46 +24,16 @@ async function load_index() { // Top-level load function for the llvm page async function load_llvm() { - await loadCommonData(); const params = new URLSearchParams(window.location.search); const benchmark = params.get("benchmark"); const runMode = params.get("runmode"); + if (!benchmark || !runMode) { console.error("missing query params, this probably shouldn't happen"); + return; } - const llvm = await fetchText(`./data/llvm/${benchmark}/${runMode}/llvm.ll`); - document.getElementById("llvm-ir").innerText = llvm; - let pngs = ( - await fetchText(`./data/llvm/${benchmark}/${runMode}/png_names.txt`) - ).split("\n"); - - // Move main.png and _main.png to top - const _main = "_main.png"; - if (pngs.includes(_main)) { - pngs = pngs.filter((x) => x !== _main); - pngs.unshift(_main); - } - const main = "main.png"; - if (pngs.includes(main)) { - pngs = pngs.filter((x) => x !== main); - pngs.unshift(main); - } - - const pngContainer = document.getElementById("llvm-cfg"); - pngs.forEach((png) => { - const elt = document.createElement("div"); - - const img = document.createElement("img"); - img.className = "cfg"; - img.src = `data/llvm/${benchmark}/${runMode}/${png}`; - elt.appendChild(img); - - const p = document.createElement("p"); - p.innerText = png; - elt.appendChild(p); - - pngContainer.appendChild(elt); - }); + showIR(benchmark, runMode); + showCFGs(benchmark, runMode); } async function load_table() { @@ -130,32 +100,6 @@ async function loadBaseline(url) { refreshView(); } -function toggleWarnings() { - const elt = document.getElementById("warnings-toggle"); - elt.classList.toggle("active"); - const content = elt.nextElementSibling; - if (content.style.display === "block") { - elt.innerText = `Show ${GLOBAL_DATA.warnings.size} Warnings`; - content.style.display = "none"; - } else { - elt.innerText = `Hide ${GLOBAL_DATA.warnings.size} Warnings`; - content.style.display = "block"; - } -} - -function toggleChart() { - const elt = document.getElementById("chart-toggle"); - elt.classList.toggle("active"); - const content = elt.nextElementSibling; - if (content.style.display === "block") { - elt.innerText = "Show Chart"; - content.style.display = "none"; - } else { - elt.innerText = "Hide Chart"; - content.style.display = "block"; - } -} - function onRadioClick(elt) { GLOBAL_DATA.chart.mode = elt.value; document.getElementById("speedup-formula").style.visibility = @@ -166,3 +110,14 @@ function onRadioClick(elt) { function copyToClipboard(eltId) { navigator.clipboard.writeText(document.getElementById(eltId).innerText); } + +function toggle(elt, showText, hideText) { + const content = elt.nextElementSibling; + if (content.style.display === "block") { + elt.innerText = showText; + content.style.display = "none"; + } else { + elt.innerText = hideText; + content.style.display = "block"; + } +} diff --git a/infra/nightly-resources/index.html b/infra/nightly-resources/index.html index 41ddc6de0..3d6791ffa 100644 --- a/infra/nightly-resources/index.html +++ b/infra/nightly-resources/index.html @@ -7,12 +7,11 @@ - + - Nightlies @@ -22,13 +21,15 @@

Nightlies

Profile

- - - - -
-

Speedup = (LLVM-O0 TIME / RUN MODE TIME)

- + +
+ + + +
+

Speedup = (LLVM-O0 TIME / RUN MODE TIME)

+ +
@@ -36,7 +37,12 @@

Profile

- +
diff --git a/infra/nightly-resources/index.js b/infra/nightly-resources/index.js index 96784780b..09068d8d5 100644 --- a/infra/nightly-resources/index.js +++ b/infra/nightly-resources/index.js @@ -52,7 +52,7 @@ function refreshView() { function renderWarnings() { const toggle = document.getElementById("warnings-toggle"); - toggle.innerText = `Show ${GLOBAL_DATA.warnings.size} Warnings`; + toggle.innerText = `â–¶ Show ${GLOBAL_DATA.warnings.size} Warnings`; const warningContainer = document.getElementById("warnings"); warningContainer.innerHTML = ""; diff --git a/infra/nightly-resources/llvm.html b/infra/nightly-resources/llvm.html index c9c1fd081..0c1dfc24a 100644 --- a/infra/nightly-resources/llvm.html +++ b/infra/nightly-resources/llvm.html @@ -3,16 +3,10 @@ - - - - - - - - + + LLVM @@ -20,7 +14,8 @@

LLVM

-
+ +
diff --git a/infra/nightly-resources/llvm.js b/infra/nightly-resources/llvm.js new file mode 100644 index 000000000..7f1ac31dc --- /dev/null +++ b/infra/nightly-resources/llvm.js @@ -0,0 +1,43 @@ +async function showIR(benchmark, runMode) { + const llvm = await fetchText(`./data/llvm/${benchmark}/${runMode}/llvm.ll`); + document.getElementById("llvm-ir").innerText = llvm; +} + +async function showCFGs(benchmark, runMode) { + let pngs = ( + await fetchText(`./data/llvm/${benchmark}/${runMode}/png_names.txt`) + ).split("\n"); + + // Move main.png and _main.png to top + const _main = "_main.png"; + if (pngs.includes(_main)) { + pngs = pngs.filter((x) => x !== _main); + pngs.unshift(_main); + } + const main = "main.png"; + if (pngs.includes(main)) { + pngs = pngs.filter((x) => x !== main); + pngs.unshift(main); + } + + const pngContainer = document.getElementById("llvm-cfg"); + pngs.forEach((png) => { + const elt = document.createElement("div"); + + const btn = document.createElement("button"); + btn.innerText = `â–¶ Show ${png}`; + btn.classList.add("collapsible"); + btn.onclick = (elt) => + toggle(elt.target, `â–¶ Show ${png}`, `â–¼ Hide ${png}`); + + elt.appendChild(btn); + + const img = document.createElement("img"); + img.className = "cfg"; + img.src = `data/llvm/${benchmark}/${runMode}/${png}`; + img.style.display = "none"; + elt.appendChild(img); + + pngContainer.appendChild(elt); + }); +} diff --git a/infra/nightly-resources/stylesheet.css b/infra/nightly-resources/stylesheet.css index f857c779c..169177cd1 100644 --- a/infra/nightly-resources/stylesheet.css +++ b/infra/nightly-resources/stylesheet.css @@ -19,20 +19,18 @@ body { } .collapsible { - background-color: #777; - color: white; + background-color: white; cursor: pointer; - padding: 18px; - width: 100%; + padding: 10px 0px; border: none; text-align: left; outline: none; font-size: 15px; - margin: 10px 0px; + font-weight: normal; } .active, .collapsible:hover { - background-color: #555; + font-weight: bold; } .content { @@ -61,6 +59,6 @@ body { } .cfg { - height: 200px; + max-width: 100%; display: block; } \ No newline at end of file diff --git a/infra/nightly-resources/table.html b/infra/nightly-resources/table.html index a9b4ef8b9..5a6fda98b 100644 --- a/infra/nightly-resources/table.html +++ b/infra/nightly-resources/table.html @@ -3,16 +3,10 @@ - - - - - - TABLE From 34a51e0602d2aa4fa77497005f786266560f6d05 Mon Sep 17 00:00:00 2001 From: Anjali Pal Date: Thu, 23 May 2024 15:23:11 -0700 Subject: [PATCH 17/47] add expand/collapse all --- infra/nightly-resources/handlers.js | 21 +++++++++++++++++++++ infra/nightly-resources/llvm.html | 1 + 2 files changed, 22 insertions(+) diff --git a/infra/nightly-resources/handlers.js b/infra/nightly-resources/handlers.js index 1e1a12c21..0be4ab603 100644 --- a/infra/nightly-resources/handlers.js +++ b/infra/nightly-resources/handlers.js @@ -121,3 +121,24 @@ function toggle(elt, showText, hideText) { content.style.display = "block"; } } + +function toggleAllPngs(elt) { + const btns = Array.from(document.getElementsByTagName("button")); + btns.shift(); // Skip the first button (this element) + + if (elt.innerText == "Expand All") { + elt.innerText = "Collapse All"; + btns.forEach((btn) => { + btn.innerText = btn.innerText.replace("â–¶ Show", "â–¼ Hide"); + const content = btn.nextElementSibling; + content.style.display = "block"; + }); + } else { + elt.innerText = "Expand All"; + btns.forEach((btn) => { + btn.innerText = btn.innerText.replace("â–¼ Hide", "â–¶ Show"); + const content = btn.nextElementSibling; + content.style.display = "none"; + }); + } +} diff --git a/infra/nightly-resources/llvm.html b/infra/nightly-resources/llvm.html index 0c1dfc24a..b9af3dbbe 100644 --- a/infra/nightly-resources/llvm.html +++ b/infra/nightly-resources/llvm.html @@ -13,6 +13,7 @@

LLVM

+
From 2a7e633c7bb789487d63dabe8e81e8e71c663a3c Mon Sep 17 00:00:00 2001 From: Anjali Pal Date: Thu, 23 May 2024 15:24:24 -0700 Subject: [PATCH 18/47] make pngs slightly more manageable --- infra/nightly-resources/stylesheet.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infra/nightly-resources/stylesheet.css b/infra/nightly-resources/stylesheet.css index 169177cd1..93a365252 100644 --- a/infra/nightly-resources/stylesheet.css +++ b/infra/nightly-resources/stylesheet.css @@ -59,6 +59,6 @@ body { } .cfg { - max-width: 100%; + max-height: 600px; display: block; } \ No newline at end of file From 4bd3278c6b042f68e0a865fe9cb84be5173d8e0c Mon Sep 17 00:00:00 2001 From: Anjali Pal Date: Thu, 23 May 2024 15:33:27 -0700 Subject: [PATCH 19/47] better logging --- infra/generate_cfgs.py | 4 +--- infra/generate_line_counts.py | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/infra/generate_cfgs.py b/infra/generate_cfgs.py index b812261f9..97c88eee5 100755 --- a/infra/generate_cfgs.py +++ b/infra/generate_cfgs.py @@ -3,11 +3,9 @@ import os def make_cfgs(bench, data_dir): - print(bench) cwd = os.getcwd() path = f"{data_dir}/{bench}" runmodes = os.listdir(path) - print(runmodes) for mode in runmodes: os.chdir(f"{path}/{mode}") @@ -26,6 +24,7 @@ def make_cfgs(bench, data_dir): os.system(cmd) pngs = glob.glob("*.png") + print(f"Generated {len(pngs)} CFGs for {bench} {mode}") with open("png_names.txt", "w") as f: f.write("\n".join(pngs)) @@ -42,7 +41,6 @@ def make_cfgs(bench, data_dir): print("Usage: generate_line_counts.py ") exit(1) data_dir = os.sys.argv[1] - print(data_dir) benchmarks = os.listdir(data_dir) for bench in benchmarks: make_cfgs(bench, data_dir) diff --git a/infra/generate_line_counts.py b/infra/generate_line_counts.py index 4a5a94647..383bdf2c5 100755 --- a/infra/generate_line_counts.py +++ b/infra/generate_line_counts.py @@ -129,7 +129,7 @@ def generate_latex(output_path): f.write(benchmarks_table()) tex_files = glob.glob(f"{output_path}/data/*.tex") for tex in tex_files: - cmd = " ".join(["pdflatex", f"-output-directory {output_path}/data/", tex]) + cmd = " ".join(["pdflatex", f"-output-directory {output_path}/data/", tex, "> /dev/null 2>&1"]) os.system(cmd) From 5c285df14506890dcd321b357f0951ed52400431 Mon Sep 17 00:00:00 2001 From: Anjali Pal Date: Fri, 24 May 2024 12:02:03 -0700 Subject: [PATCH 20/47] checkpoint --- infra/generate_cfgs.py | 11 ++++++++++- infra/nightly-resources/handlers.js | 7 +++---- infra/nightly-resources/index.html | 6 +++--- infra/nightly-resources/index.js | 2 +- infra/nightly-resources/llvm.html | 2 +- infra/nightly-resources/llvm.js | 8 ++++++-- infra/nightly.sh | 8 ++++---- 7 files changed, 28 insertions(+), 16 deletions(-) diff --git a/infra/generate_cfgs.py b/infra/generate_cfgs.py index 97c88eee5..2c5d6e67a 100755 --- a/infra/generate_cfgs.py +++ b/infra/generate_cfgs.py @@ -9,8 +9,17 @@ def make_cfgs(bench, data_dir): for mode in runmodes: os.chdir(f"{path}/{mode}") + # HACK: check if opt-18 exists + # otherwise use opt + # On Linux, sometimes it's called opt-18, while on mac it seems to be just opt + # Also, on some machines, just running `opt-18` hangs, so we pass the version flag + if os.system("opt-18 --version") == 0: + opt = "opt-18" + else: + opt = "opt" + # https://llvm.org/docs/Passes.html#dot-cfg-print-cfg-of-function-to-dot-file - cmd = "opt -disable-output -passes=dot-cfg llvm.ll > /dev/null 2>&1" + cmd = f"{opt} -disable-output -passes=dot-cfg llvm.ll" os.system(cmd) # Find all the dot files (can't use glob because it doesn't match hidden files) diff --git a/infra/nightly-resources/handlers.js b/infra/nightly-resources/handlers.js index 0be4ab603..cd2d6be56 100644 --- a/infra/nightly-resources/handlers.js +++ b/infra/nightly-resources/handlers.js @@ -123,20 +123,19 @@ function toggle(elt, showText, hideText) { } function toggleAllPngs(elt) { - const btns = Array.from(document.getElementsByTagName("button")); - btns.shift(); // Skip the first button (this element) + const btns = Array.from(document.getElementsByClassName("pngToggle")); if (elt.innerText == "Expand All") { elt.innerText = "Collapse All"; btns.forEach((btn) => { - btn.innerText = btn.innerText.replace("â–¶ Show", "â–¼ Hide"); + btn.innerText = btn.innerText.replace("\u25B6 Show", "\u25BC Hide"); const content = btn.nextElementSibling; content.style.display = "block"; }); } else { elt.innerText = "Expand All"; btns.forEach((btn) => { - btn.innerText = btn.innerText.replace("â–¼ Hide", "â–¶ Show"); + btn.innerText = btn.innerText.replace("\u25BC Hide", "\u25B6 Show"); const content = btn.nextElementSibling; content.style.display = "none"; }); diff --git a/infra/nightly-resources/index.html b/infra/nightly-resources/index.html index 3d6791ffa..3aabbfcf3 100644 --- a/infra/nightly-resources/index.html +++ b/infra/nightly-resources/index.html @@ -21,7 +21,7 @@

Nightlies

Profile

- +
@@ -41,7 +41,7 @@

Profile

type="button" class="collapsible" id="warnings-toggle" - onclick="toggle(this, `â–¶ Show ${GLOBAL_DATA.warnings.size} Warnings`, `â–¼ Hide ${GLOBAL_DATA.warnings.size} Warnings`)"> + onclick="toggle(this, `\u25B6 Show ${GLOBAL_DATA.warnings.size} Warnings`, `\u25BC Hide ${GLOBAL_DATA.warnings.size} Warnings`)">
@@ -79,7 +79,7 @@

Raw

Nightly Table

- Log + Log

diff --git a/infra/nightly-resources/index.js b/infra/nightly-resources/index.js index 09068d8d5..06af0a1ac 100644 --- a/infra/nightly-resources/index.js +++ b/infra/nightly-resources/index.js @@ -52,7 +52,7 @@ function refreshView() { function renderWarnings() { const toggle = document.getElementById("warnings-toggle"); - toggle.innerText = `â–¶ Show ${GLOBAL_DATA.warnings.size} Warnings`; + toggle.innerText = `\u25B6 Show ${GLOBAL_DATA.warnings.size} Warnings`; const warningContainer = document.getElementById("warnings"); warningContainer.innerHTML = ""; diff --git a/infra/nightly-resources/llvm.html b/infra/nightly-resources/llvm.html index b9af3dbbe..ccc30d74a 100644 --- a/infra/nightly-resources/llvm.html +++ b/infra/nightly-resources/llvm.html @@ -15,7 +15,7 @@

LLVM

- +
diff --git a/infra/nightly-resources/llvm.js b/infra/nightly-resources/llvm.js index 7f1ac31dc..33197c30d 100644 --- a/infra/nightly-resources/llvm.js +++ b/infra/nightly-resources/llvm.js @@ -8,6 +8,9 @@ async function showCFGs(benchmark, runMode) { await fetchText(`./data/llvm/${benchmark}/${runMode}/png_names.txt`) ).split("\n"); + let d = await fetchJson(`./data/llvm/${benchmark}/${runMode}/`); + debugger; + // Move main.png and _main.png to top const _main = "_main.png"; if (pngs.includes(_main)) { @@ -25,10 +28,11 @@ async function showCFGs(benchmark, runMode) { const elt = document.createElement("div"); const btn = document.createElement("button"); - btn.innerText = `â–¶ Show ${png}`; + btn.innerText = `\u25B6 Show ${png}`; btn.classList.add("collapsible"); + btn.classList.add("pngToggle"); btn.onclick = (elt) => - toggle(elt.target, `â–¶ Show ${png}`, `â–¼ Hide ${png}`); + toggle(elt.target, `\u25B6 Show ${png}`, `\u25BC Hide ${png}`); elt.appendChild(btn); diff --git a/infra/nightly.sh b/infra/nightly.sh index 2a5809440..bb190a9f1 100755 --- a/infra/nightly.sh +++ b/infra/nightly.sh @@ -51,19 +51,19 @@ mkdir -p ./tmp/bench # locally, run on argument if [ "$LOCAL" != "" ]; then - ./infra/profile.py "$@" "$NIGHTLY_DIR" + ./infra/profile.py "$@" "$NIGHTLY_DIR" >> $NIGHTLY_DIR/log.txt 2>&1 else export LLVM_SYS_180_PREFIX="/usr/lib/llvm-18/" make runtime # run on all benchmarks in nightly - ./infra/profile.py benchmarks/passing "$NIGHTLY_DIR" + ./infra/profile.py benchmarks/passing "$NIGHTLY_DIR" >> $NIGHTLY_DIR/log.txt 2>&1 fi # Generate latex after running the profiler (depends on profile.json) -./infra/generate_line_counts.py "$NIGHTLY_DIR" +./infra/generate_line_counts.py "$NIGHTLY_DIR" >> $NIGHTLY_DIR/log.txt 2>&1 # Generate CFGs for LLVM after running the profiler -./infra/generate_cfgs.py "$NIGHTLY_DIR/data/llvm" +./infra/generate_cfgs.py "$NIGHTLY_DIR/data/llvm" >> $NIGHTLY_DIR/log.txt 2>&1 rm -r ./tmp/ From 367cffcad286464707916011da1657139916102c Mon Sep 17 00:00:00 2001 From: Anjali Pal Date: Fri, 24 May 2024 14:23:02 -0700 Subject: [PATCH 21/47] less file copying --- infra/generate_cfgs.py | 6 ++- infra/generate_line_counts.py | 12 ++--- infra/nightly.sh | 11 ++--- infra/profile.py | 85 ++++++++++++++++++----------------- 4 files changed, 58 insertions(+), 56 deletions(-) diff --git a/infra/generate_cfgs.py b/infra/generate_cfgs.py index 2c5d6e67a..c1cfdee61 100755 --- a/infra/generate_cfgs.py +++ b/infra/generate_cfgs.py @@ -19,9 +19,13 @@ def make_cfgs(bench, data_dir): opt = "opt" # https://llvm.org/docs/Passes.html#dot-cfg-print-cfg-of-function-to-dot-file - cmd = f"{opt} -disable-output -passes=dot-cfg llvm.ll" + cmd = f"{opt} -disable-output -passes=dot-cfg {bench}-{mode}.ll" os.system(cmd) + # Delete the -init.ll file (We don't need it for nightly, + # so just reduce the amount of clutter we copy to the nightly machine) + os.system(f"rm {bench}-{mode}-init.ll") + # Find all the dot files (can't use glob because it doesn't match hidden files) # There are also a bunch of files that start with ._Z that I don't think we care about? dots = [f for f in os.listdir(".") if f.endswith(".dot") and not f.startswith("._Z") and not f.startswith("._bril")] diff --git a/infra/generate_line_counts.py b/infra/generate_line_counts.py index 383bdf2c5..c804b293e 100755 --- a/infra/generate_line_counts.py +++ b/infra/generate_line_counts.py @@ -98,7 +98,7 @@ def get_rows_for_benchmark(bench, profile_data): def benchmarks_table(): - profile_data = json.load(open(f'{output_path}/data/profile.json')) + profile_data = json.load(open(f'{output_path}/profile.json')) benchmarks = set([x["benchmark"] for x in profile_data]) rows = header() rows += [ @@ -121,15 +121,15 @@ def benchmarks_table(): return "\n".join(rows) def generate_latex(output_path): - with open(f'{output_path}/data/linecount.tex', "w") as f: + with open(f'{output_path}/linecount.tex', "w") as f: f.write(linecount_table()) - with open(f'{output_path}/data/detailed-linecount.tex', "w") as f: + with open(f'{output_path}/detailed-linecount.tex', "w") as f: f.write(detailed_linecount_table()) - with open(f'{output_path}/data/benchmarks.tex', "w") as f: + with open(f'{output_path}/benchmarks.tex', "w") as f: f.write(benchmarks_table()) - tex_files = glob.glob(f"{output_path}/data/*.tex") + tex_files = glob.glob(f"{output_path}/*.tex") for tex in tex_files: - cmd = " ".join(["pdflatex", f"-output-directory {output_path}/data/", tex, "> /dev/null 2>&1"]) + cmd = " ".join(["pdflatex", f"-output-directory {output_path}/", tex, "> /dev/null 2>&1"]) os.system(cmd) diff --git a/infra/nightly.sh b/infra/nightly.sh index bb190a9f1..a567d3e49 100755 --- a/infra/nightly.sh +++ b/infra/nightly.sh @@ -30,6 +30,7 @@ MYDIR="$(cd -P "$(dirname "$src")" && pwd)" TOP_DIR="$MYDIR/.." RESOURCE_DIR="$MYDIR/nightly-resources" NIGHTLY_DIR="$TOP_DIR/nightly" +DATA_DIR="$TOP_DIR/nightly/data" # Make sure we're in the right place cd $MYDIR @@ -46,8 +47,6 @@ mkdir -p "$NIGHTLY_DIR/data" "$NIGHTLY_DIR/data/llvm" "$NIGHTLY_DIR/output" pushd $TOP_DIR # Run profiler. -# create temporary directory structure necessary for bench runs -mkdir -p ./tmp/bench # locally, run on argument if [ "$LOCAL" != "" ]; then @@ -56,16 +55,14 @@ else export LLVM_SYS_180_PREFIX="/usr/lib/llvm-18/" make runtime # run on all benchmarks in nightly - ./infra/profile.py benchmarks/passing "$NIGHTLY_DIR" >> $NIGHTLY_DIR/log.txt 2>&1 + ./infra/profile.py benchmarks/passing "$DATA_DIR" >> $NIGHTLY_DIR/log.txt 2>&1 fi # Generate latex after running the profiler (depends on profile.json) -./infra/generate_line_counts.py "$NIGHTLY_DIR" >> $NIGHTLY_DIR/log.txt 2>&1 +./infra/generate_line_counts.py "$DATA_DIR" >> $NIGHTLY_DIR/log.txt 2>&1 # Generate CFGs for LLVM after running the profiler -./infra/generate_cfgs.py "$NIGHTLY_DIR/data/llvm" >> $NIGHTLY_DIR/log.txt 2>&1 - -rm -r ./tmp/ +./infra/generate_cfgs.py "$DATA_DIR/llvm" >> $NIGHTLY_DIR/log.txt 2>&1 popd diff --git a/infra/profile.py b/infra/profile.py index 6d4db55d1..71ff4a385 100755 --- a/infra/profile.py +++ b/infra/profile.py @@ -18,51 +18,55 @@ "llvm-O3-eggcc", ] -def get_eggcc_options(name, profile_dir): - match name: +# Where to output files that are needed for nightly report +DATA_DIR = None + +# Where to write intermediate files that should be cleaned up at the end of this script +TMP_DIR = "tmp" + +def get_eggcc_options(run_mode, benchmark): + llvm_out_dir = f"{DATA_DIR}/llvm/{benchmark}/{run_mode}" + match run_mode: case "rvsdg-round-trip-to-executable": - return f'--run-mode rvsdg-round-trip-to-executable --llvm-output-dir {profile_dir}/llvm-{name}' + return f'--run-mode rvsdg-round-trip-to-executable --llvm-output-dir {llvm_out_dir}' case "cranelift-O3": return f'--run-mode cranelift --optimize-egglog false --optimize-brilift true' case "llvm-O0": - return f'--run-mode llvm --optimize-egglog false --optimize-bril-llvm false --llvm-output-dir {profile_dir}/llvm-{name}' + return f'--run-mode llvm --optimize-egglog false --optimize-bril-llvm false --llvm-output-dir {llvm_out_dir}' case "llvm-O3": - return f'--run-mode llvm --optimize-egglog false --optimize-bril-llvm true --llvm-output-dir {profile_dir}/llvm-{name}' + return f'--run-mode llvm --optimize-egglog false --optimize-bril-llvm true --llvm-output-dir {llvm_out_dir}' case "llvm-O0-eggcc": - return f'--run-mode llvm --optimize-egglog true --optimize-bril-llvm false --llvm-output-dir {profile_dir}/llvm-{name}' + return f'--run-mode llvm --optimize-egglog true --optimize-bril-llvm false --llvm-output-dir {llvm_out_dir}' case "llvm-O3-eggcc": - return f'--run-mode llvm --optimize-egglog true --optimize-bril-llvm true --llvm-output-dir {profile_dir}/llvm-{name}' + return f'--run-mode llvm --optimize-egglog true --optimize-bril-llvm true --llvm-output-dir {llvm_out_dir}' case _: - raise Exception("Unexpected run mode: " + name) + raise Exception("Unexpected run mode: " + run_mode) class Benchmark: def __init__(self, path, treatment, index, total): self.path = path + self.name = path.split("/")[-1][:-len(".bril")] self.treatment = treatment # index of this benchmark (for printing) self.index = index # total number of benchmarks being run self.total = total -def benchmark_name(benchmark_path): - return benchmark_path.split("/")[-1][:-len(".bril")] - -def benchmark_profile_dir(benchmark_path): - return f'./tmp/bench/{benchmark_name(benchmark_path)}' +def benchmark_profile_dir(name): + return f'{TMP_DIR}/{name}' -def setup_benchmark(benchmark_path): - # strip off the .bril to get just the profile name - profile_dir = benchmark_profile_dir(benchmark_path) +def setup_benchmark(name): + profile_dir = benchmark_profile_dir(name) try: os.mkdir(profile_dir) except FileExistsError: print(f'{profile_dir} exists, overwriting contents') def optimize(benchmark): - print(f'[{benchmark.index}/{benchmark.total}] Optimizing {benchmark.path} with {benchmark.treatment}') - profile_dir = benchmark_profile_dir(benchmark.path) - cmd = f'cargo run --release {benchmark.path} {get_eggcc_options(benchmark.treatment, profile_dir)} -o {profile_dir}/{benchmark.treatment}' + print(f'[{benchmark.index}/{benchmark.total}] Optimizing {benchmark.name} with {benchmark.treatment}') + profile_dir = benchmark_profile_dir(benchmark.name) + cmd = f'cargo run --release {benchmark.path} {get_eggcc_options(benchmark.treatment, benchmark.name)} -o {profile_dir}/{benchmark.treatment}' print(f'Running: {cmd}') start = time.time() subprocess.call(cmd, shell=True) @@ -72,8 +76,8 @@ def optimize(benchmark): def bench(benchmark): - print(f'[{benchmark.index}/{benchmark.total}] Benchmarking {benchmark.path} with {benchmark.treatment}') - profile_dir = benchmark_profile_dir(benchmark.path) + print(f'[{benchmark.index}/{benchmark.total}] Benchmarking {benchmark.name} with {benchmark.treatment}') + profile_dir = benchmark_profile_dir(benchmark.name) with open(f'{profile_dir}/{benchmark.treatment}-args') as f: args = f.read().rstrip() @@ -100,25 +104,14 @@ def should_have_llvm_ir(runMethod): "llvm-O3-eggcc", ] -def dump_llvm_ir(runMethod, benchmark, output_directory): - from_path = f'./tmp/bench/{benchmark}/llvm-{runMethod}/{benchmark}-{runMethod}.ll' - - to_path = f'{output_directory}/data/llvm/{benchmark}/{runMethod}/llvm.ll' - - os.system(f'mkdir -p {output_directory}/data/llvm/{benchmark}/{runMethod}') - os.system(f'cp {from_path} {to_path}') - - # aggregate all profile info into a single json array. -def aggregate(compile_times, bench_times, output_directory): +def aggregate(compile_times, bench_times): res = [] for path in sorted(compile_times.keys()): name = path.split("/")[-2] runMethod = path.split("/")[-1] result = {"runMethod": runMethod, "benchmark": name, "hyperfine": bench_times[path], "compileTime": compile_times[path]} - if should_have_llvm_ir(runMethod): - dump_llvm_ir(runMethod, name, output_directory) res.append(result) return res @@ -130,17 +123,19 @@ def aggregate(compile_times, bench_times, output_directory): print("Usage: profile.py ") exit(1) - profile_path, output_path = os.sys.argv[1:] + # Create tmp directory for intermediate files + os.mkdir(TMP_DIR) + + bril_dir, DATA_DIR = os.sys.argv[1:] profiles = [] # if it is a directory get all files - if os.path.isdir(profile_path): - print(f'Running all bril files in {profile_path}') - profiles = glob(f'{profile_path}/**/*.bril', recursive=True) + if os.path.isdir(bril_dir): + print(f'Running all bril files in {bril_dir}') + profiles = glob(f'{bril_dir}/**/*.bril', recursive=True) else: - profiles = [profile_path] + profiles = [bril_dir] - for benchmark_path in profiles: - setup_benchmark(benchmark_path) + profiles = profiles[0:1] to_run = [] index = 0 @@ -149,6 +144,9 @@ def aggregate(compile_times, bench_times, output_directory): for treatment in treatments: to_run.append(Benchmark(benchmark_path, treatment, index, total)) index += 1 + + for benchmark in to_run: + setup_benchmark(benchmark.name) compile_times = {} @@ -182,6 +180,9 @@ def aggregate(compile_times, bench_times, output_directory): (path, _bench_data) = res bench_data[path] = _bench_data - nightly_data = aggregate(compile_times, bench_data, output_path) - with open(f"{output_path}/data/profile.json", "w") as profile: + nightly_data = aggregate(compile_times, bench_data) + with open(f"{DATA_DIR}/profile.json", "w") as profile: json.dump(nightly_data, profile, indent=2) + + # Clean up intermediate files + os.system(f"rm -rf {TMP_DIR}") From 24a846111edde2a91db5a50b5a656b802ad2ec00 Mon Sep 17 00:00:00 2001 From: Anjali Pal Date: Fri, 24 May 2024 14:26:41 -0700 Subject: [PATCH 22/47] oops --- infra/nightly-resources/llvm.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/infra/nightly-resources/llvm.js b/infra/nightly-resources/llvm.js index 33197c30d..626e1b299 100644 --- a/infra/nightly-resources/llvm.js +++ b/infra/nightly-resources/llvm.js @@ -1,5 +1,5 @@ async function showIR(benchmark, runMode) { - const llvm = await fetchText(`./data/llvm/${benchmark}/${runMode}/llvm.ll`); + const llvm = await fetchText(`./data/llvm/${benchmark}/${runMode}/${benchmark}-${runMode}.ll`); document.getElementById("llvm-ir").innerText = llvm; } @@ -8,9 +8,6 @@ async function showCFGs(benchmark, runMode) { await fetchText(`./data/llvm/${benchmark}/${runMode}/png_names.txt`) ).split("\n"); - let d = await fetchJson(`./data/llvm/${benchmark}/${runMode}/`); - debugger; - // Move main.png and _main.png to top const _main = "_main.png"; if (pngs.includes(_main)) { From 31f24688fa1f334b15c7cc50101d16b26bb1a4b5 Mon Sep 17 00:00:00 2001 From: Anjali Pal Date: Fri, 24 May 2024 14:27:11 -0700 Subject: [PATCH 23/47] prettier --- infra/nightly-resources/llvm.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/infra/nightly-resources/llvm.js b/infra/nightly-resources/llvm.js index 626e1b299..d6d542ac6 100644 --- a/infra/nightly-resources/llvm.js +++ b/infra/nightly-resources/llvm.js @@ -1,5 +1,7 @@ async function showIR(benchmark, runMode) { - const llvm = await fetchText(`./data/llvm/${benchmark}/${runMode}/${benchmark}-${runMode}.ll`); + const llvm = await fetchText( + `./data/llvm/${benchmark}/${runMode}/${benchmark}-${runMode}.ll`, + ); document.getElementById("llvm-ir").innerText = llvm; } From 491b81109b4d48abc20f1999ab64f7505e01ef60 Mon Sep 17 00:00:00 2001 From: Kirsten <32720576+kirstenmg@users.noreply.github.com> Date: Fri, 24 May 2024 14:34:30 -0700 Subject: [PATCH 24/47] Update README with nightly instructions --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index f32ae730b..224289177 100644 --- a/README.md +++ b/README.md @@ -28,3 +28,10 @@ ## How to add a test - Add a bril file under `tests/`. - Run `cargo insta review` to confirm the output for the new file. + + +## How to run local nightly +- Make sure you have the command `hyperfine` (install if not). +- Run `bash infra/localnightly.sh ` + +To run the nightly server for an existing nightly, run `cd nightly/output && python3 -m http.server`. \ No newline at end of file From 985b1823d8a250ede7bdf9101e499478632a7065 Mon Sep 17 00:00:00 2001 From: Anjali Pal Date: Fri, 24 May 2024 14:44:46 -0700 Subject: [PATCH 25/47] de-dupe toggling logic --- infra/nightly-resources/handlers.js | 28 +++++++++++++++++--------- infra/nightly-resources/index.html | 6 +++--- infra/nightly-resources/llvm.js | 4 ++-- infra/nightly-resources/stylesheet.css | 8 ++++++++ 4 files changed, 32 insertions(+), 14 deletions(-) diff --git a/infra/nightly-resources/handlers.js b/infra/nightly-resources/handlers.js index cd2d6be56..fe607a199 100644 --- a/infra/nightly-resources/handlers.js +++ b/infra/nightly-resources/handlers.js @@ -111,14 +111,24 @@ function copyToClipboard(eltId) { navigator.clipboard.writeText(document.getElementById(eltId).innerText); } +function expand(elt, labelElt, text) { + elt.classList.add("expanded"); + elt.classList.remove("collapsed"); + labelElt.innerText = text; +} + +function collapse(elt, labelElt, text) { + elt.classList.add("collapsed"); + elt.classList.remove("expanded"); + labelElt.innerText = text; +} + function toggle(elt, showText, hideText) { const content = elt.nextElementSibling; - if (content.style.display === "block") { - elt.innerText = showText; - content.style.display = "none"; + if (content.classList.contains("expanded")) { + collapse(content, elt, showText); } else { - elt.innerText = hideText; - content.style.display = "block"; + expand(content, elt, hideText); } } @@ -128,16 +138,16 @@ function toggleAllPngs(elt) { if (elt.innerText == "Expand All") { elt.innerText = "Collapse All"; btns.forEach((btn) => { - btn.innerText = btn.innerText.replace("\u25B6 Show", "\u25BC Hide"); + const txt = btn.innerText.replace("\u25B6 Show", "\u25BC Hide"); const content = btn.nextElementSibling; - content.style.display = "block"; + expand(content, btn, txt); }); } else { elt.innerText = "Expand All"; btns.forEach((btn) => { - btn.innerText = btn.innerText.replace("\u25BC Hide", "\u25B6 Show"); + const txt = btn.innerText.replace("\u25BC Hide", "\u25B6 Show"); const content = btn.nextElementSibling; - content.style.display = "none"; + collapse(content, btn, txt); }); } } diff --git a/infra/nightly-resources/index.html b/infra/nightly-resources/index.html index 3aabbfcf3..b8d29099a 100644 --- a/infra/nightly-resources/index.html +++ b/infra/nightly-resources/index.html @@ -21,8 +21,8 @@

Nightlies

Profile

- -
+ +
@@ -43,7 +43,7 @@

Profile

id="warnings-toggle" onclick="toggle(this, `\u25B6 Show ${GLOBAL_DATA.warnings.size} Warnings`, `\u25BC Hide ${GLOBAL_DATA.warnings.size} Warnings`)"> -
+
diff --git a/infra/nightly-resources/llvm.js b/infra/nightly-resources/llvm.js index d6d542ac6..1022491e2 100644 --- a/infra/nightly-resources/llvm.js +++ b/infra/nightly-resources/llvm.js @@ -36,9 +36,9 @@ async function showCFGs(benchmark, runMode) { elt.appendChild(btn); const img = document.createElement("img"); - img.className = "cfg"; + img.classList.add("cfg"); + img.classList.add("collapsed"); img.src = `data/llvm/${benchmark}/${runMode}/${png}`; - img.style.display = "none"; elt.appendChild(img); pngContainer.appendChild(elt); diff --git a/infra/nightly-resources/stylesheet.css b/infra/nightly-resources/stylesheet.css index 93a365252..5fb8f1028 100644 --- a/infra/nightly-resources/stylesheet.css +++ b/infra/nightly-resources/stylesheet.css @@ -61,4 +61,12 @@ body { .cfg { max-height: 600px; display: block; +} + +.expanded { + display: block; +} + +.collapsed { + display: none; } \ No newline at end of file From 0e441ab6106a6ee4a2717999d3738064541cb638 Mon Sep 17 00:00:00 2001 From: Anjali Pal Date: Fri, 24 May 2024 14:49:57 -0700 Subject: [PATCH 26/47] copy log --- infra/nightly.sh | 5 ++++- infra/profile.py | 2 -- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/infra/nightly.sh b/infra/nightly.sh index a567d3e49..dca4362e1 100755 --- a/infra/nightly.sh +++ b/infra/nightly.sh @@ -69,9 +69,12 @@ popd # Update HTML index page. cp "$RESOURCE_DIR"/* "$NIGHTLY_DIR/output" -# Copy json directory to the artifact +# Copy data directory to the artifact cp -r "$NIGHTLY_DIR/data" "$NIGHTLY_DIR/output/data" +# Copy log +cp "$NIGHTLY_DIR/log.txt" "$NIGHTLY_DIR/output" + # gzip all JSON in the nightly dir if [ "$LOCAL" == "" ]; then gzip "$NIGHTLY_DIR/output/data/profile.json" diff --git a/infra/profile.py b/infra/profile.py index 71ff4a385..efc5f9f42 100755 --- a/infra/profile.py +++ b/infra/profile.py @@ -135,8 +135,6 @@ def aggregate(compile_times, bench_times): else: profiles = [bril_dir] - profiles = profiles[0:1] - to_run = [] index = 0 total = len(profiles) * len(treatments) From a25e62e97c7427dcd210c5b4e8d8cba2359cd639 Mon Sep 17 00:00:00 2001 From: Anjali Pal Date: Fri, 24 May 2024 15:09:44 -0700 Subject: [PATCH 27/47] handle file exists, update log path --- infra/nightly-resources/index.html | 2 +- infra/profile.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/infra/nightly-resources/index.html b/infra/nightly-resources/index.html index b8d29099a..2ebbc0379 100644 --- a/infra/nightly-resources/index.html +++ b/infra/nightly-resources/index.html @@ -79,7 +79,7 @@

Raw

Nightly Table

- Log + Log

diff --git a/infra/profile.py b/infra/profile.py index efc5f9f42..d49584edc 100755 --- a/infra/profile.py +++ b/infra/profile.py @@ -124,7 +124,10 @@ def aggregate(compile_times, bench_times): exit(1) # Create tmp directory for intermediate files - os.mkdir(TMP_DIR) + try: + os.mkdir(TMP_DIR) + except FileExistsError: + print(f"{TMP_DIR} exits, overwriting contents") bril_dir, DATA_DIR = os.sys.argv[1:] profiles = [] From 73bd6719d7d4f0666ba3768b6dfc7156a3d4dcc9 Mon Sep 17 00:00:00 2001 From: Kirsten <32720576+kirstenmg@users.noreply.github.com> Date: Fri, 24 May 2024 15:10:36 -0700 Subject: [PATCH 28/47] Snapshots --- .../files__range_check-optimize.snap | 23 ------------------- .../files__range_splitting-optimize.snap | 21 ----------------- 2 files changed, 44 deletions(-) diff --git a/tests/snapshots/files__range_check-optimize.snap b/tests/snapshots/files__range_check-optimize.snap index cc6d1879f..59f868ab0 100644 --- a/tests/snapshots/files__range_check-optimize.snap +++ b/tests/snapshots/files__range_check-optimize.snap @@ -22,7 +22,6 @@ expression: visualization.result v15_: int = id v14_; br v5_ .v16_ .v17_; .v16_: -<<<<<<< HEAD v15_: int = id v14_; .v17_: v2_: int = id v15_; @@ -34,26 +33,4 @@ expression: visualization.result jmp .v12_; .v18_: print v2_; -======= - v17_: int = const 1; - v18_: int = add v17_ v6_; - v19_: int = id v18_; - br v9_ .v20_ .v21_; -.v20_: - v19_: int = id v18_; -.v21_: - v6_: int = id v19_; - br v9_ .v7_ .v22_; -.v22_: - v3_: int = id v6_; - print v3_; - ret; -.v13_: - v23_: int = const 2; - print v23_; - v15_: int = id v6_; - jmp .v16_; -.v5_: - print v3_; ->>>>>>> main } diff --git a/tests/snapshots/files__range_splitting-optimize.snap b/tests/snapshots/files__range_splitting-optimize.snap index 925a9af76..1e64a449e 100644 --- a/tests/snapshots/files__range_splitting-optimize.snap +++ b/tests/snapshots/files__range_splitting-optimize.snap @@ -31,26 +31,5 @@ expression: visualization.result v12_: int = id v2_; jmp .v13_; .v17_: -<<<<<<< HEAD print v2_; -======= - v18_: int = id v9_; - br v11_ .v19_ .v20_; -.v19_: - v18_: int = id v9_; -.v20_: - v6_: int = id v18_; - br v11_ .v7_ .v21_; -.v21_: - v3_: int = id v6_; - print v3_; - ret; -.v14_: - v22_: int = const 2; - print v22_; - v16_: int = id v6_; - jmp .v17_; -.v5_: - print v3_; ->>>>>>> main } From 21620ab9d2e4e514ac0f875ec006d6d20cd9353e Mon Sep 17 00:00:00 2001 From: Anjali Pal Date: Mon, 27 May 2024 15:29:46 -0700 Subject: [PATCH 29/47] add ops to bril --- Cargo.lock | 34 ++++++++++++------- Cargo.toml | 12 +++---- dag_in_context/src/ast.rs | 24 +++++++++++++ dag_in_context/src/from_egglog.rs | 6 ++++ dag_in_context/src/greedy_dag_extractor.rs | 6 ++-- dag_in_context/src/interpreter.rs | 29 +++++++++++++++- .../src/optimizations/purity_analysis.rs | 4 +-- dag_in_context/src/schema.egg | 6 ++++ dag_in_context/src/schema.rs | 6 ++++ dag_in_context/src/schema_helpers.rs | 10 ++++-- src/rvsdg/from_dag.rs | 6 ++++ src/rvsdg/to_dag.rs | 7 ++++ 12 files changed, 124 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 831906c2d..bbec07825 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -193,6 +193,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bril-rs" +version = "0.1.0" +source = "git+https://github.com/uwplse/bril?rev=40ec0e5803c69bc2cde794785ba6b13a4fc401fe#40ec0e5803c69bc2cde794785ba6b13a4fc401fe" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "bril-rs" version = "0.1.0" @@ -206,7 +216,7 @@ dependencies = [ [[package]] name = "bril-rs" version = "0.1.0" -source = "git+https://github.com/uwplse/bril#5652d6ac53d727c0901a53a0484e8241db887d04" +source = "git+https://github.com/uwplse/bril?rev=8fd97903e7f46decb89398cf57a6dabd55e4fecf#8fd97903e7f46decb89398cf57a6dabd55e4fecf" dependencies = [ "serde", "serde_json", @@ -216,9 +226,9 @@ dependencies = [ [[package]] name = "bril2json" version = "0.1.0" -source = "git+https://github.com/uwplse/bril?rev=78881c45aa53231915f333d1d6dcc26cedc63b57#78881c45aa53231915f333d1d6dcc26cedc63b57" +source = "git+https://github.com/uwplse/bril?rev=8fd97903e7f46decb89398cf57a6dabd55e4fecf#8fd97903e7f46decb89398cf57a6dabd55e4fecf" dependencies = [ - "bril-rs 0.1.0 (git+https://github.com/uwplse/bril?rev=78881c45aa53231915f333d1d6dcc26cedc63b57)", + "bril-rs 0.1.0 (git+https://github.com/uwplse/bril?rev=8fd97903e7f46decb89398cf57a6dabd55e4fecf)", "clap", "lalrpop", "lalrpop-util", @@ -228,10 +238,10 @@ dependencies = [ [[package]] name = "brilift" version = "0.1.0" -source = "git+https://github.com/uwplse/bril?rev=78881c45aa53231915f333d1d6dcc26cedc63b57#78881c45aa53231915f333d1d6dcc26cedc63b57" +source = "git+https://github.com/uwplse/bril?rev=8fd97903e7f46decb89398cf57a6dabd55e4fecf#8fd97903e7f46decb89398cf57a6dabd55e4fecf" dependencies = [ "argh", - "bril-rs 0.1.0 (git+https://github.com/uwplse/bril?rev=78881c45aa53231915f333d1d6dcc26cedc63b57)", + "bril-rs 0.1.0 (git+https://github.com/uwplse/bril?rev=8fd97903e7f46decb89398cf57a6dabd55e4fecf)", "cranelift-codegen", "cranelift-frontend", "cranelift-jit", @@ -245,9 +255,9 @@ dependencies = [ [[package]] name = "brilirs" version = "0.1.0" -source = "git+https://github.com/uwplse/bril?rev=78881c45aa53231915f333d1d6dcc26cedc63b57#78881c45aa53231915f333d1d6dcc26cedc63b57" +source = "git+https://github.com/uwplse/bril?rev=8fd97903e7f46decb89398cf57a6dabd55e4fecf#8fd97903e7f46decb89398cf57a6dabd55e4fecf" dependencies = [ - "bril-rs 0.1.0 (git+https://github.com/uwplse/bril?rev=78881c45aa53231915f333d1d6dcc26cedc63b57)", + "bril-rs 0.1.0 (git+https://github.com/uwplse/bril?rev=8fd97903e7f46decb89398cf57a6dabd55e4fecf)", "bril2json", "clap", "fxhash", @@ -259,9 +269,9 @@ dependencies = [ [[package]] name = "brillvm" version = "0.1.0" -source = "git+https://github.com/uwplse/bril?rev=78881c45aa53231915f333d1d6dcc26cedc63b57#78881c45aa53231915f333d1d6dcc26cedc63b57" +source = "git+https://github.com/uwplse/bril?rev=8fd97903e7f46decb89398cf57a6dabd55e4fecf#8fd97903e7f46decb89398cf57a6dabd55e4fecf" dependencies = [ - "bril-rs 0.1.0 (git+https://github.com/uwplse/bril)", + "bril-rs 0.1.0 (git+https://github.com/uwplse/bril?rev=40ec0e5803c69bc2cde794785ba6b13a4fc401fe)", "clap", "inkwell", ] @@ -598,7 +608,7 @@ checksum = "675e35c02a51bb4d4618cb4885b3839ce6d1787c97b664474d9208d074742e20" name = "eggcc" version = "0.1.0" dependencies = [ - "bril-rs 0.1.0 (git+https://github.com/uwplse/bril?rev=78881c45aa53231915f333d1d6dcc26cedc63b57)", + "bril-rs 0.1.0 (git+https://github.com/uwplse/bril?rev=8fd97903e7f46decb89398cf57a6dabd55e4fecf)", "bril2json", "brilift", "brilirs", @@ -1525,9 +1535,9 @@ dependencies = [ [[package]] name = "rs2bril" version = "0.1.0" -source = "git+https://github.com/uwplse/bril?rev=78881c45aa53231915f333d1d6dcc26cedc63b57#78881c45aa53231915f333d1d6dcc26cedc63b57" +source = "git+https://github.com/uwplse/bril?rev=8fd97903e7f46decb89398cf57a6dabd55e4fecf#8fd97903e7f46decb89398cf57a6dabd55e4fecf" dependencies = [ - "bril-rs 0.1.0 (git+https://github.com/uwplse/bril?rev=78881c45aa53231915f333d1d6dcc26cedc63b57)", + "bril-rs 0.1.0 (git+https://github.com/uwplse/bril?rev=8fd97903e7f46decb89398cf57a6dabd55e4fecf)", "clap", "proc-macro2", "syn 2.0.64", diff --git a/Cargo.toml b/Cargo.toml index 7f7e536a3..222d8478e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,14 +22,14 @@ smallvec = "1.11.1" syn = { version = "2.0", features = ["full", "extra-traits"] } # currently using the uwplse/bril fork of bril, on eggcc-main -bril2json = { git = "https://github.com/uwplse/bril", rev = "78881c45aa53231915f333d1d6dcc26cedc63b57" } -brilirs = { git = "https://github.com/uwplse/bril", rev = "78881c45aa53231915f333d1d6dcc26cedc63b57" } -bril-rs = { git = "https://github.com/uwplse/bril", rev = "78881c45aa53231915f333d1d6dcc26cedc63b57" } -brilift = { git = "https://github.com/uwplse/bril", rev = "78881c45aa53231915f333d1d6dcc26cedc63b57" } -rs2bril = { git = "https://github.com/uwplse/bril", rev = "78881c45aa53231915f333d1d6dcc26cedc63b57" ,features = [ +bril2json = { git = "https://github.com/uwplse/bril", rev = "8fd97903e7f46decb89398cf57a6dabd55e4fecf" } +brilirs = { git = "https://github.com/uwplse/bril", rev = "8fd97903e7f46decb89398cf57a6dabd55e4fecf" } +bril-rs = { git = "https://github.com/uwplse/bril", rev = "8fd97903e7f46decb89398cf57a6dabd55e4fecf" } +brilift = { git = "https://github.com/uwplse/bril", rev = "8fd97903e7f46decb89398cf57a6dabd55e4fecf" } +rs2bril = { git = "https://github.com/uwplse/bril", rev = "8fd97903e7f46decb89398cf57a6dabd55e4fecf" ,features = [ "import", ] } -brillvm = { git = "https://github.com/uwplse/bril", rev = "78881c45aa53231915f333d1d6dcc26cedc63b57" } +brillvm = { git = "https://github.com/uwplse/bril", rev = "8fd97903e7f46decb89398cf57a6dabd55e4fecf" } ordered-float = { version = "3.7" } diff --git a/dag_in_context/src/ast.rs b/dag_in_context/src/ast.rs index ebd65f547..386a74270 100644 --- a/dag_in_context/src/ast.rs +++ b/dag_in_context/src/ast.rs @@ -102,6 +102,22 @@ pub fn div(l: RcExpr, r: RcExpr) -> RcExpr { RcExpr::new(Expr::Bop(BinaryOp::Div, l, r)) } +pub fn smax(l: RcExpr, r: RcExpr) -> RcExpr { + RcExpr::new(Expr::Bop(BinaryOp::Smax, l, r)) +} + +pub fn smin(l: RcExpr, r: RcExpr) -> RcExpr { + RcExpr::new(Expr::Bop(BinaryOp::Smin, l, r)) +} + +pub fn shl(l: RcExpr, r: RcExpr) -> RcExpr { + RcExpr::new(Expr::Bop(BinaryOp::Shl, l, r)) +} + +pub fn shr(l: RcExpr, r: RcExpr) -> RcExpr { + RcExpr::new(Expr::Bop(BinaryOp::Shr, l, r)) +} + pub fn fadd(l: RcExpr, r: RcExpr) -> RcExpr { RcExpr::new(Expr::Bop(BinaryOp::FAdd, l, r)) } @@ -118,6 +134,14 @@ pub fn fdiv(l: RcExpr, r: RcExpr) -> RcExpr { RcExpr::new(Expr::Bop(BinaryOp::FDiv, l, r)) } +pub fn fmax(l: RcExpr, r: RcExpr) -> RcExpr { + RcExpr::new(Expr::Bop(BinaryOp::Fmax, l, r)) +} + +pub fn fmin(l: RcExpr, r: RcExpr) -> RcExpr { + RcExpr::new(Expr::Bop(BinaryOp::Fmin, l, r)) +} + pub fn less_than(l: RcExpr, r: RcExpr) -> RcExpr { RcExpr::new(Expr::Bop(BinaryOp::LessThan, l, r)) } diff --git a/dag_in_context/src/from_egglog.rs b/dag_in_context/src/from_egglog.rs index 728481ea9..6c1c863c6 100644 --- a/dag_in_context/src/from_egglog.rs +++ b/dag_in_context/src/from_egglog.rs @@ -168,6 +168,10 @@ impl<'a> FromEgglog<'a> { ("GreaterThan", []) => BinaryOp::GreaterThan, ("LessEq", []) => BinaryOp::LessEq, ("GreaterEq", []) => BinaryOp::GreaterEq, + ("Smax", []) => BinaryOp::Smax, + ("Smin", []) => BinaryOp::Smin, + ("Shl", []) => BinaryOp::Shl, + ("Shr", []) => BinaryOp::Shr, ("FAdd", []) => BinaryOp::FAdd, ("FSub", []) => BinaryOp::FSub, ("FMul", []) => BinaryOp::FMul, @@ -177,6 +181,8 @@ impl<'a> FromEgglog<'a> { ("FGreaterThan", []) => BinaryOp::FGreaterThan, ("FLessEq", []) => BinaryOp::FLessEq, ("FGreaterEq", []) => BinaryOp::FGreaterEq, + ("Fmax", []) => BinaryOp::Fmax, + ("Fmin", []) => BinaryOp::Fmin, ("And", []) => BinaryOp::And, ("Or", []) => BinaryOp::Or, ("PtrAdd", []) => BinaryOp::PtrAdd, diff --git a/dag_in_context/src/greedy_dag_extractor.rs b/dag_in_context/src/greedy_dag_extractor.rs index 154968bd7..c33d66810 100644 --- a/dag_in_context/src/greedy_dag_extractor.rs +++ b/dag_in_context/src/greedy_dag_extractor.rs @@ -857,15 +857,15 @@ impl CostModel for DefaultCostModel { "Base" | "TupleT" | "TNil" | "TCons" => 0., "Int" | "Bool" | "Float" => 0., // Algebra - "Add" | "PtrAdd" | "Sub" | "And" | "Or" | "Not" => 10., - "FAdd" | "FSub" => 50., + "Add" | "PtrAdd" | "Sub" | "And" | "Or" | "Not" | "Shl" | "Shr" => 10., + "FAdd" | "FSub" | "Fmax" | "Fmin" => 50., "Mul" => 30., "FMul" => 150., "Div" => 50., "FDiv" => 250., // Comparisons "Eq" | "LessThan" | "GreaterThan" | "LessEq" | "GreaterEq" => 10., - "Select" => 10., + "Select" | "Smax" | "Smin" => 10., "FEq" => 10., "FLessThan" | "FGreaterThan" | "FLessEq" | "FGreaterEq" => 100., // Effects diff --git a/dag_in_context/src/interpreter.rs b/dag_in_context/src/interpreter.rs index ebebfddcb..a29f2b967 100644 --- a/dag_in_context/src/interpreter.rs +++ b/dag_in_context/src/interpreter.rs @@ -4,7 +4,7 @@ //! shared as the same Rc pointer. Otherwise, effects may be executed multiple times. //! The invariant is maintained by translation from RVSDG, type checking, and translation from egglog. -use std::{collections::HashMap, fmt::Display, rc::Rc}; +use std::{collections::HashMap, fmt::Display, ops::{Shl, Shr}, rc::Rc}; use crate::{ schema::{BinaryOp, Constant, Expr, RcExpr, TernaryOp, TreeProgram, UnaryOp}, @@ -242,6 +242,22 @@ impl<'a> VirtualMachine<'a> { BinaryOp::Div => Const(Constant::Int( get_int(e1, self).wrapping_div(get_int(e2, self)), )), + BinaryOp::Smax => { + let a = get_int(e1, self); + let b = get_int(e2, self); + Const(Constant::Int(if a > b { a } else { b })) + }, + BinaryOp::Smin => { + let a = get_int(e1, self); + let b = get_int(e2, self); + Const(Constant::Int(if a < b { a } else { b })) + }, + BinaryOp::Shl => Const(Constant::Int( + get_int(e1, self).shl(get_int(e2, self)) + )), + BinaryOp::Shr => Const(Constant::Int( + get_int(e1, self).shr(get_int(e2, self)) + )), BinaryOp::Eq => Const(Constant::Bool(get_int(e1, self) == get_int(e2, self))), BinaryOp::LessThan => Const(Constant::Bool(get_int(e1, self) < get_int(e2, self))), BinaryOp::GreaterThan => Const(Constant::Bool(get_int(e1, self) > get_int(e2, self))), @@ -303,6 +319,17 @@ impl<'a> VirtualMachine<'a> { BinaryOp::FGreaterEq => { Const(Constant::Bool(get_float(e1, self) >= get_float(e2, self))) } + BinaryOp::Fmax => { + let a = get_float(e1, self); + let b = get_float(e2, self); + Const(Constant::Float(if a > b { a } else { b })) + }, + BinaryOp::Fmin => { + let a = get_float(e1, self); + let b = get_float(e2, self); + Const(Constant::Float(if a < b { a } else { b })) + }, + } } diff --git a/dag_in_context/src/optimizations/purity_analysis.rs b/dag_in_context/src/optimizations/purity_analysis.rs index 9ca8ec9d4..0e82ced7b 100644 --- a/dag_in_context/src/optimizations/purity_analysis.rs +++ b/dag_in_context/src/optimizations/purity_analysis.rs @@ -13,8 +13,8 @@ fn top_is_pure(top: &TernaryOp) -> bool { fn bop_is_pure(bop: &BinaryOp) -> bool { use BinaryOp::*; match bop { - Add | Sub | Mul | LessThan | Div | Eq | GreaterThan | LessEq | GreaterEq => true, - FAdd | FSub | FMul | FLessThan | FDiv | FEq | FGreaterThan | FLessEq | FGreaterEq => true, + Add | Sub | Mul | LessThan | Div | Eq | GreaterThan | LessEq | GreaterEq | Smax | Smin | Shl | Shr => true, + FAdd | FSub | FMul | FLessThan | FDiv | FEq | FGreaterThan | FLessEq | FGreaterEq | Fmax | Fmin => true, PtrAdd => true, And | Or => true, Load | Print | Free => false, diff --git a/dag_in_context/src/schema.egg b/dag_in_context/src/schema.egg index 8dd9f093e..5f4db287d 100644 --- a/dag_in_context/src/schema.egg +++ b/dag_in_context/src/schema.egg @@ -94,6 +94,10 @@ (LessEq) (GreaterEq) (Eq) + (Smin) + (Smax) + (Shl) + (Shr) ;; float operators (FAdd) (FSub) @@ -104,6 +108,8 @@ (FLessEq) (FGreaterEq) (FEq) + (Fmin) + (Fmax) ;; logical operators (And) (Or) diff --git a/dag_in_context/src/schema.rs b/dag_in_context/src/schema.rs index b1f8080d9..7b2dff7fa 100644 --- a/dag_in_context/src/schema.rs +++ b/dag_in_context/src/schema.rs @@ -47,6 +47,10 @@ pub enum BinaryOp { GreaterThan, LessEq, GreaterEq, + Smax, + Smin, + Shl, + Shr, FAdd, FSub, FMul, @@ -56,6 +60,8 @@ pub enum BinaryOp { FGreaterThan, FLessEq, FGreaterEq, + Fmax, + Fmin, And, Or, PtrAdd, diff --git a/dag_in_context/src/schema_helpers.rs b/dag_in_context/src/schema_helpers.rs index 29e758499..2ef51cb3e 100644 --- a/dag_in_context/src/schema_helpers.rs +++ b/dag_in_context/src/schema_helpers.rs @@ -68,6 +68,10 @@ impl BinaryOp { LessThan => "LessThan", GreaterEq => "GreaterEq", LessEq => "LessEq", + Smax => "Smax", + Smin => "Smin", + Shl => "Shl", + Shr => "Shr", FAdd => "FAdd", FSub => "FSub", FMul => "FMul", @@ -77,6 +81,8 @@ impl BinaryOp { FLessThan => "FLessThan", FGreaterEq => "FGreaterEq", FLessEq => "FLessEq", + Fmax => "Fmax", + Fmin => "Fmin", And => "And", Or => "Or", Load => "Load", @@ -690,10 +696,10 @@ impl BinaryOp { /// When a binary op has concrete input sorts, return them. pub fn types(&self) -> Option<(Type, Type, Type)> { match self { - BinaryOp::Add | BinaryOp::Sub | BinaryOp::Mul | BinaryOp::Div => { + BinaryOp::Add | BinaryOp::Sub | BinaryOp::Mul | BinaryOp::Div | BinaryOp::Smax | BinaryOp::Smin | BinaryOp::Shl | BinaryOp::Shr => { Some((base(intt()), base(intt()), base(intt()))) } - BinaryOp::FAdd | BinaryOp::FSub | BinaryOp::FMul | BinaryOp::FDiv => { + BinaryOp::FAdd | BinaryOp::FSub | BinaryOp::FMul | BinaryOp::FDiv | BinaryOp::Fmax | BinaryOp::Fmin => { Some((base(floatt()), base(floatt()), base(floatt()))) } BinaryOp::And | BinaryOp::Or => Some((base(boolt()), base(boolt()), base(boolt()))), diff --git a/src/rvsdg/from_dag.rs b/src/rvsdg/from_dag.rs index b3c121b6c..0bf3abfd3 100644 --- a/src/rvsdg/from_dag.rs +++ b/src/rvsdg/from_dag.rs @@ -153,6 +153,10 @@ fn value_op_from_binary_op(bop: BinaryOp) -> Option { BinaryOp::GreaterThan => Some(ValueOps::Gt), BinaryOp::LessEq => Some(ValueOps::Le), BinaryOp::GreaterEq => Some(ValueOps::Ge), + BinaryOp::Smax => Some(ValueOps::Smax), + BinaryOp::Smin => Some(ValueOps::Smin), + BinaryOp::Shl => Some(ValueOps::Shl), + BinaryOp::Shr => Some(ValueOps::Shr), // float operators BinaryOp::FAdd => Some(ValueOps::Fadd), BinaryOp::FSub => Some(ValueOps::Fsub), @@ -163,6 +167,8 @@ fn value_op_from_binary_op(bop: BinaryOp) -> Option { BinaryOp::FGreaterThan => Some(ValueOps::Fgt), BinaryOp::FLessEq => Some(ValueOps::Fle), BinaryOp::FGreaterEq => Some(ValueOps::Fge), + BinaryOp::Fmax => Some(ValueOps::Fmax), + BinaryOp::Fmin => Some(ValueOps::Fmin), // logical op BinaryOp::And => Some(ValueOps::And), BinaryOp::Or => Some(ValueOps::Or), diff --git a/src/rvsdg/to_dag.rs b/src/rvsdg/to_dag.rs index 99ed9dbfa..a6b410435 100644 --- a/src/rvsdg/to_dag.rs +++ b/src/rvsdg/to_dag.rs @@ -240,6 +240,11 @@ impl<'a> DagTranslator<'a> { (ValueOps::Sub, [a, b]) => sub(a.clone(), b.clone()), (ValueOps::Div, [a, b]) => div(a.clone(), b.clone()), + (ValueOps::Smax, [a, b]) => smax(a.clone(), b.clone()), + (ValueOps::Smin, [a, b]) => smin(a.clone(), b.clone()), + (ValueOps::Shl, [a, b]) => shl(a.clone(), b.clone()), + (ValueOps::Shr, [a, b]) => shr(a.clone(), b.clone()), + (ValueOps::Fadd, [a, b]) => fadd(a.clone(), b.clone()), (ValueOps::Fmul, [a, b]) => fmul(a.clone(), b.clone()), (ValueOps::Fsub, [a, b]) => fsub(a.clone(), b.clone()), @@ -256,6 +261,8 @@ impl<'a> DagTranslator<'a> { (ValueOps::Flt, [a, b]) => fless_than(a.clone(), b.clone()), (ValueOps::Fge, [a, b]) => fgreater_eq(a.clone(), b.clone()), (ValueOps::Fle, [a, b]) => fless_eq(a.clone(), b.clone()), + (ValueOps::Fmax, [a, b]) => fmax(a.clone(), b.clone()), + (ValueOps::Fmin, [a, b]) => fmin(a.clone(), b.clone()), (ValueOps::And, [a, b]) => and(a.clone(), b.clone()), (ValueOps::Or, [a, b]) => or(a.clone(), b.clone()), From eb03bdf6cf623c0da1fc5d80cb3920fa25f75f09 Mon Sep 17 00:00:00 2001 From: Anjali Pal Date: Mon, 27 May 2024 15:34:46 -0700 Subject: [PATCH 30/47] snapshots --- ...ollatz_redundant_computation-optimize.snap | 4 +- .../files__fib_recursive-optimize.snap | 46 +++++++++---------- .../files__gamma_condition_and-optimize.snap | 4 +- .../snapshots/files__if_context-optimize.snap | 21 +++++---- .../files__if_interval-optimize.snap | 15 +++--- .../files__loop_pass_through-optimize.snap | 2 +- tests/snapshots/files__reassoc-optimize.snap | 8 ++-- 7 files changed, 51 insertions(+), 49 deletions(-) diff --git a/tests/snapshots/files__collatz_redundant_computation-optimize.snap b/tests/snapshots/files__collatz_redundant_computation-optimize.snap index 187e40bd8..1914461d7 100644 --- a/tests/snapshots/files__collatz_redundant_computation-optimize.snap +++ b/tests/snapshots/files__collatz_redundant_computation-optimize.snap @@ -19,8 +19,8 @@ expression: visualization.result v14_: bool = const false; v15_: int = id v6_; v16_: bool = id v14_; - v17_: int = id v7_; - v18_: int = id v7_; + v17_: int = id v8_; + v18_: int = id v8_; v19_: int = id v9_; v20_: int = id v10_; v21_: int = id v11_; diff --git a/tests/snapshots/files__fib_recursive-optimize.snap b/tests/snapshots/files__fib_recursive-optimize.snap index 9a02639c2..be78d3e83 100644 --- a/tests/snapshots/files__fib_recursive-optimize.snap +++ b/tests/snapshots/files__fib_recursive-optimize.snap @@ -14,35 +14,35 @@ expression: visualization.result br v8_ .v9_ .v10_; .v9_: v11_: bool = eq v2_ v2_; - v12_: int = id v4_; + v12_: int = id v0; br v11_ .v13_ .v14_; .v14_: - v15_: bool = eq v2_ v4_; + v15_: bool = eq v0 v2_; br v15_ .v16_ .v17_; .v16_: v18_: bool = eq v2_ v2_; - v19_: int = id v4_; + v19_: int = id v2_; br v18_ .v20_ .v21_; .v21_: - v22_: bool = eq v2_ v4_; + v22_: bool = eq v2_ v2_; br v22_ .v23_ .v24_; .v23_: v25_: int = call @fac v2_; - v26_: int = id v4_; + v26_: int = id v2_; .v27_: v19_: int = id v26_; .v20_: - v28_: int = id v4_; + v28_: int = id v2_; .v29_: v12_: int = id v28_; .v13_: - v30_: int = id v4_; + v30_: int = id v0; .v31_: v5_: int = id v30_; ret v5_; .v24_: v32_: int = const -1; - v33_: int = sub v32_ v4_; + v33_: int = sub v32_ v2_; v34_: int = call @fac v32_; v35_: int = call @fac v33_; v36_: int = add v34_ v35_; @@ -53,25 +53,25 @@ expression: visualization.result v38_: bool = eq v2_ v37_; v39_: int = const -1; v40_: bool = eq v2_ v39_; - v41_: int = id v4_; + v41_: int = id v0; br v40_ .v42_ .v43_; .v43_: - v44_: bool = eq v39_ v4_; + v44_: bool = eq v0 v39_; br v44_ .v45_ .v46_; .v45_: v47_: int = call @fac v2_; - v48_: int = id v4_; + v48_: int = id v39_; .v49_: v41_: int = id v48_; .v42_: - v50_: int = id v4_; + v50_: int = id v0; br v38_ .v51_ .v52_; .v52_: - v53_: bool = eq v37_ v4_; + v53_: bool = eq v0 v37_; br v53_ .v54_ .v55_; .v54_: v56_: int = call @fac v2_; - v57_: int = id v4_; + v57_: int = id v0; .v58_: v50_: int = id v57_; .v51_: @@ -135,7 +135,7 @@ expression: visualization.result br v102_ .v103_ .v104_; .v103_: v105_: int = call @fac v2_; - v106_: int = id v71_; + v106_: int = id v2_; .v107_: v99_: int = id v106_; .v100_: @@ -166,7 +166,7 @@ expression: visualization.result br v123_ .v124_ .v125_; .v124_: v126_: int = call @fac v2_; - v127_: int = id v116_; + v127_: int = id v4_; .v128_: v120_: int = id v127_; .v121_: @@ -220,7 +220,7 @@ expression: visualization.result br v161_ .v162_ .v163_; .v162_: v164_: int = call @fac v2_; - v165_: int = id v4_; + v165_: int = id v154_; .v166_: v158_: int = id v165_; .v159_: @@ -270,25 +270,25 @@ expression: visualization.result br v8_ .v9_ .v10_; .v9_: v11_: bool = eq v2_ v2_; - v12_: int = id v4_; + v12_: int = id v1_; br v11_ .v13_ .v14_; .v14_: - v15_: bool = eq v2_ v4_; + v15_: bool = eq v1_ v2_; br v15_ .v16_ .v17_; .v16_: v18_: int = call @fac v2_; - v19_: int = id v4_; + v19_: int = id v1_; .v20_: v12_: int = id v19_; .v13_: - v21_: int = id v4_; + v21_: int = id v1_; .v22_: v5_: int = id v21_; print v5_; ret; .v17_: v23_: int = const -1; - v24_: int = sub v23_ v4_; + v24_: int = sub v23_ v1_; v25_: int = call @fac v23_; v26_: int = call @fac v24_; v27_: int = add v25_ v26_; @@ -315,7 +315,7 @@ expression: visualization.result br v42_ .v43_ .v44_; .v43_: v45_: int = call @fac v2_; - v46_: int = id v4_; + v46_: int = id v2_; .v47_: v39_: int = id v46_; .v40_: diff --git a/tests/snapshots/files__gamma_condition_and-optimize.snap b/tests/snapshots/files__gamma_condition_and-optimize.snap index d2fb01cff..43798cb45 100644 --- a/tests/snapshots/files__gamma_condition_and-optimize.snap +++ b/tests/snapshots/files__gamma_condition_and-optimize.snap @@ -5,8 +5,8 @@ expression: visualization.result @main(v0: int) { .v1_: v2_: int = const 0; - v3_: bool = lt v2_ v0; - v4_: bool = lt v0 v2_; + v3_: bool = lt v0 v2_; + v4_: bool = lt v2_ v0; v5_: int = const 1; v6_: int = const 3; v7_: int = id v6_; diff --git a/tests/snapshots/files__if_context-optimize.snap b/tests/snapshots/files__if_context-optimize.snap index 9cbf293e5..949c353d2 100644 --- a/tests/snapshots/files__if_context-optimize.snap +++ b/tests/snapshots/files__if_context-optimize.snap @@ -5,16 +5,17 @@ expression: visualization.result @main(v0: int) { .v1_: v2_: bool = const true; - v3_: int = const 0; - v4_: bool = le v0 v3_; - v5_: int = id v0; - v6_: int = id v3_; - br v4_ .v7_ .v8_; + v3_: int = const 1; + v4_: bool = lt v0 v3_; + v5_: int = const 0; + v6_: int = id v0; + v7_: int = id v5_; + br v4_ .v8_ .v9_; +.v9_: + v10_: int = const -1; + v11_: int = mul v0 v10_; + v6_: int = id v11_; + v7_: int = id v5_; .v8_: - v9_: int = const -1; - v10_: int = mul v0 v9_; - v5_: int = id v10_; - v6_: int = id v3_; -.v7_: print v2_; } diff --git a/tests/snapshots/files__if_interval-optimize.snap b/tests/snapshots/files__if_interval-optimize.snap index 29150d300..fabad26eb 100644 --- a/tests/snapshots/files__if_interval-optimize.snap +++ b/tests/snapshots/files__if_interval-optimize.snap @@ -5,13 +5,14 @@ expression: visualization.result @main(v0: int) { .v1_: v2_: bool = const true; - v3_: int = const 0; - v4_: bool = le v0 v3_; - v5_: int = const 3; - v6_: int = id v5_; - br v4_ .v7_ .v8_; -.v7_: - v6_: int = id v3_; + v3_: int = const 1; + v4_: bool = lt v0 v3_; + v5_: int = const 0; + v6_: int = const 3; + v7_: int = id v6_; + br v4_ .v8_ .v9_; .v8_: + v7_: int = id v5_; +.v9_: print v2_; } diff --git a/tests/snapshots/files__loop_pass_through-optimize.snap b/tests/snapshots/files__loop_pass_through-optimize.snap index 8df973601..f6b78d6e5 100644 --- a/tests/snapshots/files__loop_pass_through-optimize.snap +++ b/tests/snapshots/files__loop_pass_through-optimize.snap @@ -4,7 +4,7 @@ expression: visualization.result --- @main(v0: int) { .v1_: - v2_: int = const 1; + v2_: int = const 2; v3_: int = id v2_; v4_: int = id v0; .v5_: diff --git a/tests/snapshots/files__reassoc-optimize.snap b/tests/snapshots/files__reassoc-optimize.snap index e0ef8fc33..d35ad99ae 100644 --- a/tests/snapshots/files__reassoc-optimize.snap +++ b/tests/snapshots/files__reassoc-optimize.snap @@ -5,10 +5,10 @@ expression: visualization.result @main(v0: int, v1: int) { .v2_: v3_: int = const 1; - v4_: int = const 4; - v5_: int = add v1 v4_; - v6_: int = const 3; - v7_: int = add v0 v6_; + v4_: int = const 3; + v5_: int = add v0 v4_; + v6_: int = const 4; + v7_: int = add v1 v6_; v8_: int = add v5_ v7_; v9_: int = add v3_ v8_; print v9_; From c39f93b7c40876ac62c5e3ebc7440160769c5d48 Mon Sep 17 00:00:00 2001 From: Anjali Pal Date: Mon, 27 May 2024 15:49:49 -0700 Subject: [PATCH 31/47] fmt --- dag_in_context/src/interpreter.rs | 24 +++++++++---------- .../src/optimizations/purity_analysis.rs | 6 +++-- dag_in_context/src/schema_helpers.rs | 20 +++++++++++----- 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/dag_in_context/src/interpreter.rs b/dag_in_context/src/interpreter.rs index a29f2b967..27bf5f8ff 100644 --- a/dag_in_context/src/interpreter.rs +++ b/dag_in_context/src/interpreter.rs @@ -4,7 +4,12 @@ //! shared as the same Rc pointer. Otherwise, effects may be executed multiple times. //! The invariant is maintained by translation from RVSDG, type checking, and translation from egglog. -use std::{collections::HashMap, fmt::Display, ops::{Shl, Shr}, rc::Rc}; +use std::{ + collections::HashMap, + fmt::Display, + ops::{Shl, Shr}, + rc::Rc, +}; use crate::{ schema::{BinaryOp, Constant, Expr, RcExpr, TernaryOp, TreeProgram, UnaryOp}, @@ -246,18 +251,14 @@ impl<'a> VirtualMachine<'a> { let a = get_int(e1, self); let b = get_int(e2, self); Const(Constant::Int(if a > b { a } else { b })) - }, + } BinaryOp::Smin => { let a = get_int(e1, self); let b = get_int(e2, self); Const(Constant::Int(if a < b { a } else { b })) - }, - BinaryOp::Shl => Const(Constant::Int( - get_int(e1, self).shl(get_int(e2, self)) - )), - BinaryOp::Shr => Const(Constant::Int( - get_int(e1, self).shr(get_int(e2, self)) - )), + } + BinaryOp::Shl => Const(Constant::Int(get_int(e1, self).shl(get_int(e2, self)))), + BinaryOp::Shr => Const(Constant::Int(get_int(e1, self).shr(get_int(e2, self)))), BinaryOp::Eq => Const(Constant::Bool(get_int(e1, self) == get_int(e2, self))), BinaryOp::LessThan => Const(Constant::Bool(get_int(e1, self) < get_int(e2, self))), BinaryOp::GreaterThan => Const(Constant::Bool(get_int(e1, self) > get_int(e2, self))), @@ -323,13 +324,12 @@ impl<'a> VirtualMachine<'a> { let a = get_float(e1, self); let b = get_float(e2, self); Const(Constant::Float(if a > b { a } else { b })) - }, + } BinaryOp::Fmin => { let a = get_float(e1, self); let b = get_float(e2, self); Const(Constant::Float(if a < b { a } else { b })) - }, - + } } } diff --git a/dag_in_context/src/optimizations/purity_analysis.rs b/dag_in_context/src/optimizations/purity_analysis.rs index 0e82ced7b..dae713f32 100644 --- a/dag_in_context/src/optimizations/purity_analysis.rs +++ b/dag_in_context/src/optimizations/purity_analysis.rs @@ -13,8 +13,10 @@ fn top_is_pure(top: &TernaryOp) -> bool { fn bop_is_pure(bop: &BinaryOp) -> bool { use BinaryOp::*; match bop { - Add | Sub | Mul | LessThan | Div | Eq | GreaterThan | LessEq | GreaterEq | Smax | Smin | Shl | Shr => true, - FAdd | FSub | FMul | FLessThan | FDiv | FEq | FGreaterThan | FLessEq | FGreaterEq | Fmax | Fmin => true, + Add | Sub | Mul | LessThan | Div | Eq | GreaterThan | LessEq | GreaterEq | Smax | Smin + | Shl | Shr => true, + FAdd | FSub | FMul | FLessThan | FDiv | FEq | FGreaterThan | FLessEq | FGreaterEq + | Fmax | Fmin => true, PtrAdd => true, And | Or => true, Load | Print | Free => false, diff --git a/dag_in_context/src/schema_helpers.rs b/dag_in_context/src/schema_helpers.rs index 2ef51cb3e..30c3fb226 100644 --- a/dag_in_context/src/schema_helpers.rs +++ b/dag_in_context/src/schema_helpers.rs @@ -696,12 +696,20 @@ impl BinaryOp { /// When a binary op has concrete input sorts, return them. pub fn types(&self) -> Option<(Type, Type, Type)> { match self { - BinaryOp::Add | BinaryOp::Sub | BinaryOp::Mul | BinaryOp::Div | BinaryOp::Smax | BinaryOp::Smin | BinaryOp::Shl | BinaryOp::Shr => { - Some((base(intt()), base(intt()), base(intt()))) - } - BinaryOp::FAdd | BinaryOp::FSub | BinaryOp::FMul | BinaryOp::FDiv | BinaryOp::Fmax | BinaryOp::Fmin => { - Some((base(floatt()), base(floatt()), base(floatt()))) - } + BinaryOp::Add + | BinaryOp::Sub + | BinaryOp::Mul + | BinaryOp::Div + | BinaryOp::Smax + | BinaryOp::Smin + | BinaryOp::Shl + | BinaryOp::Shr => Some((base(intt()), base(intt()), base(intt()))), + BinaryOp::FAdd + | BinaryOp::FSub + | BinaryOp::FMul + | BinaryOp::FDiv + | BinaryOp::Fmax + | BinaryOp::Fmin => Some((base(floatt()), base(floatt()), base(floatt()))), BinaryOp::And | BinaryOp::Or => Some((base(boolt()), base(boolt()), base(boolt()))), BinaryOp::LessThan | BinaryOp::GreaterThan From d70b3b49e2c13b950e86769419a81c255d2ac6c1 Mon Sep 17 00:00:00 2001 From: Anjali Pal Date: Tue, 28 May 2024 11:07:27 -0700 Subject: [PATCH 32/47] snapshots --- tests/snapshots/files__gamma_condition_and-optimize.snap | 2 +- tests/snapshots/files__loop_pass_through-optimize.snap | 2 +- tests/snapshots/files__sqrt-optimize.snap | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/snapshots/files__gamma_condition_and-optimize.snap b/tests/snapshots/files__gamma_condition_and-optimize.snap index 43798cb45..2155e35e7 100644 --- a/tests/snapshots/files__gamma_condition_and-optimize.snap +++ b/tests/snapshots/files__gamma_condition_and-optimize.snap @@ -6,7 +6,7 @@ expression: visualization.result .v1_: v2_: int = const 0; v3_: bool = lt v0 v2_; - v4_: bool = lt v2_ v0; + v4_: bool = gt v0 v2_; v5_: int = const 1; v6_: int = const 3; v7_: int = id v6_; diff --git a/tests/snapshots/files__loop_pass_through-optimize.snap b/tests/snapshots/files__loop_pass_through-optimize.snap index f6b78d6e5..8df973601 100644 --- a/tests/snapshots/files__loop_pass_through-optimize.snap +++ b/tests/snapshots/files__loop_pass_through-optimize.snap @@ -4,7 +4,7 @@ expression: visualization.result --- @main(v0: int) { .v1_: - v2_: int = const 2; + v2_: int = const 1; v3_: int = id v2_; v4_: int = id v0; .v5_: diff --git a/tests/snapshots/files__sqrt-optimize.snap b/tests/snapshots/files__sqrt-optimize.snap index ad9335e24..92bfe28f8 100644 --- a/tests/snapshots/files__sqrt-optimize.snap +++ b/tests/snapshots/files__sqrt-optimize.snap @@ -36,8 +36,8 @@ expression: visualization.result v28_: float = fadd v21_ v27_; v29_: float = fdiv v28_ v24_; v30_: float = fdiv v29_ v21_; - v31_: bool = fle v30_ v22_; - v32_: bool = fge v30_ v23_; + v31_: bool = fge v30_ v23_; + v32_: bool = fle v30_ v22_; v33_: bool = and v31_ v32_; v34_: bool = const true; v35_: float = id v20_; From af7bc489e2919443be0eb331680b6ded4890ee9b Mon Sep 17 00:00:00 2001 From: Anjali Pal Date: Tue, 28 May 2024 13:56:41 -0700 Subject: [PATCH 33/47] filter benchmarks by looped --- infra/nightly-resources/handlers.js | 23 ++++++++++++++--------- infra/nightly-resources/index.html | 7 +++++-- infra/profile.py | 15 ++++++++++++--- 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/infra/nightly-resources/handlers.js b/infra/nightly-resources/handlers.js index fe607a199..932a0f98d 100644 --- a/infra/nightly-resources/handlers.js +++ b/infra/nightly-resources/handlers.js @@ -59,16 +59,21 @@ function selectAllModes(enabled) { refreshView(); } -function selectAllBenchmarks(enabled) { +function selectAllBenchmarks(enabled, category) { const checkboxContainer = document.getElementById("benchmarkCheckboxes"); - Array.from(checkboxContainer.getElementsByTagName("input")).forEach( - (checkbox) => { - checkbox.checked = enabled; - enabled - ? GLOBAL_DATA.enabledBenchmarks.add(checkbox.id) - : GLOBAL_DATA.enabledBenchmarks.delete(checkbox.id); - }, - ); + let checkboxes = Array.from(checkboxContainer.getElementsByTagName("input")); + if (category === "looped") { + const loopedBenchmarks = new Set( + GLOBAL_DATA.currentRun.filter((x) => x.looped).map((x) => x.benchmark), + ); + checkboxes = checkboxes.filter((x) => loopedBenchmarks.has(x.id)); + } + checkboxes.forEach((checkbox) => { + checkbox.checked = enabled; + enabled + ? GLOBAL_DATA.enabledBenchmarks.add(checkbox.id) + : GLOBAL_DATA.enabledBenchmarks.delete(checkbox.id); + }); refreshView(); } diff --git a/infra/nightly-resources/index.html b/infra/nightly-resources/index.html index 2ebbc0379..1974ebcb0 100644 --- a/infra/nightly-resources/index.html +++ b/infra/nightly-resources/index.html @@ -57,8 +57,11 @@

Profile

Benchmarks

- - + + +
+ +
diff --git a/infra/profile.py b/infra/profile.py index d49584edc..d227df87c 100755 --- a/infra/profile.py +++ b/infra/profile.py @@ -105,17 +105,21 @@ def should_have_llvm_ir(runMethod): ] # aggregate all profile info into a single json array. -def aggregate(compile_times, bench_times): +def aggregate(compile_times, bench_times, looped): res = [] for path in sorted(compile_times.keys()): name = path.split("/")[-2] runMethod = path.split("/")[-1] - result = {"runMethod": runMethod, "benchmark": name, "hyperfine": bench_times[path], "compileTime": compile_times[path]} + result = {"runMethod": runMethod, "benchmark": name, "hyperfine": bench_times[path], "compileTime": compile_times[path], "looped": looped[name]} res.append(result) return res +def is_looped(bril_file): + with open(bril_file) as f: + txt = f.read() + return "orig_main" in txt if __name__ == '__main__': # expect two arguments @@ -138,6 +142,11 @@ def aggregate(compile_times, bench_times): else: profiles = [bril_dir] + looped = {} + for profile in profiles: + name = profile.split("/")[-1][:-len(".bril")] + looped[name] = is_looped(profile) + to_run = [] index = 0 total = len(profiles) * len(treatments) @@ -181,7 +190,7 @@ def aggregate(compile_times, bench_times): (path, _bench_data) = res bench_data[path] = _bench_data - nightly_data = aggregate(compile_times, bench_data) + nightly_data = aggregate(compile_times, bench_data, looped) with open(f"{DATA_DIR}/profile.json", "w") as profile: json.dump(nightly_data, profile, indent=2) From 25511456d8cf365ee82c22f5fcdb0d416b0d5807 Mon Sep 17 00:00:00 2001 From: Anjali Pal Date: Tue, 28 May 2024 14:05:21 -0700 Subject: [PATCH 34/47] make header + tab title more clear --- infra/nightly-resources/handlers.js | 3 +++ infra/nightly-resources/llvm.html | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/infra/nightly-resources/handlers.js b/infra/nightly-resources/handlers.js index 932a0f98d..b40bb4379 100644 --- a/infra/nightly-resources/handlers.js +++ b/infra/nightly-resources/handlers.js @@ -28,6 +28,9 @@ async function load_llvm() { const benchmark = params.get("benchmark"); const runMode = params.get("runmode"); + document.title = `${benchmark} | ${runMode}`; + document.getElementById("llvm-header").innerText = `Benchmark: ${benchmark} | Run Mode: ${runMode}`; + if (!benchmark || !runMode) { console.error("missing query params, this probably shouldn't happen"); return; diff --git a/infra/nightly-resources/llvm.html b/infra/nightly-resources/llvm.html index ccc30d74a..9edb9d41b 100644 --- a/infra/nightly-resources/llvm.html +++ b/infra/nightly-resources/llvm.html @@ -12,7 +12,7 @@ LLVM -

LLVM

+

LLVM

From 70f1d1bc8643bea361596329d0270dea964afd28 Mon Sep 17 00:00:00 2001 From: Anjali Pal Date: Tue, 28 May 2024 14:05:40 -0700 Subject: [PATCH 35/47] prettier --- infra/nightly-resources/handlers.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/infra/nightly-resources/handlers.js b/infra/nightly-resources/handlers.js index b40bb4379..dd156e893 100644 --- a/infra/nightly-resources/handlers.js +++ b/infra/nightly-resources/handlers.js @@ -29,7 +29,8 @@ async function load_llvm() { const runMode = params.get("runmode"); document.title = `${benchmark} | ${runMode}`; - document.getElementById("llvm-header").innerText = `Benchmark: ${benchmark} | Run Mode: ${runMode}`; + document.getElementById("llvm-header").innerText = + `Benchmark: ${benchmark} | Run Mode: ${runMode}`; if (!benchmark || !runMode) { console.error("missing query params, this probably shouldn't happen"); From 413d4892f25cc2bf7b364789ef98562e28dc28a6 Mon Sep 17 00:00:00 2001 From: Anjali Pal Date: Wed, 29 May 2024 09:15:44 -0700 Subject: [PATCH 36/47] bump bril --- Cargo.lock | 28 ++++++++++++++-------------- Cargo.toml | 12 ++++++------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bbec07825..68ff4942f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -196,7 +196,7 @@ dependencies = [ [[package]] name = "bril-rs" version = "0.1.0" -source = "git+https://github.com/uwplse/bril?rev=40ec0e5803c69bc2cde794785ba6b13a4fc401fe#40ec0e5803c69bc2cde794785ba6b13a4fc401fe" +source = "git+https://github.com/uwplse/bril?rev=78881c45aa53231915f333d1d6dcc26cedc63b57#78881c45aa53231915f333d1d6dcc26cedc63b57" dependencies = [ "serde", "serde_json", @@ -206,7 +206,7 @@ dependencies = [ [[package]] name = "bril-rs" version = "0.1.0" -source = "git+https://github.com/uwplse/bril?rev=78881c45aa53231915f333d1d6dcc26cedc63b57#78881c45aa53231915f333d1d6dcc26cedc63b57" +source = "git+https://github.com/uwplse/bril?rev=e2be3f5d7e160f02b7aed0ef2bcc3e13ae722d2b#e2be3f5d7e160f02b7aed0ef2bcc3e13ae722d2b" dependencies = [ "serde", "serde_json", @@ -216,7 +216,7 @@ dependencies = [ [[package]] name = "bril-rs" version = "0.1.0" -source = "git+https://github.com/uwplse/bril?rev=8fd97903e7f46decb89398cf57a6dabd55e4fecf#8fd97903e7f46decb89398cf57a6dabd55e4fecf" +source = "git+https://github.com/uwplse/bril#e2be3f5d7e160f02b7aed0ef2bcc3e13ae722d2b" dependencies = [ "serde", "serde_json", @@ -226,9 +226,9 @@ dependencies = [ [[package]] name = "bril2json" version = "0.1.0" -source = "git+https://github.com/uwplse/bril?rev=8fd97903e7f46decb89398cf57a6dabd55e4fecf#8fd97903e7f46decb89398cf57a6dabd55e4fecf" +source = "git+https://github.com/uwplse/bril?rev=e2be3f5d7e160f02b7aed0ef2bcc3e13ae722d2b#e2be3f5d7e160f02b7aed0ef2bcc3e13ae722d2b" dependencies = [ - "bril-rs 0.1.0 (git+https://github.com/uwplse/bril?rev=8fd97903e7f46decb89398cf57a6dabd55e4fecf)", + "bril-rs 0.1.0 (git+https://github.com/uwplse/bril?rev=e2be3f5d7e160f02b7aed0ef2bcc3e13ae722d2b)", "clap", "lalrpop", "lalrpop-util", @@ -238,10 +238,10 @@ dependencies = [ [[package]] name = "brilift" version = "0.1.0" -source = "git+https://github.com/uwplse/bril?rev=8fd97903e7f46decb89398cf57a6dabd55e4fecf#8fd97903e7f46decb89398cf57a6dabd55e4fecf" +source = "git+https://github.com/uwplse/bril?rev=e2be3f5d7e160f02b7aed0ef2bcc3e13ae722d2b#e2be3f5d7e160f02b7aed0ef2bcc3e13ae722d2b" dependencies = [ "argh", - "bril-rs 0.1.0 (git+https://github.com/uwplse/bril?rev=8fd97903e7f46decb89398cf57a6dabd55e4fecf)", + "bril-rs 0.1.0 (git+https://github.com/uwplse/bril?rev=e2be3f5d7e160f02b7aed0ef2bcc3e13ae722d2b)", "cranelift-codegen", "cranelift-frontend", "cranelift-jit", @@ -255,9 +255,9 @@ dependencies = [ [[package]] name = "brilirs" version = "0.1.0" -source = "git+https://github.com/uwplse/bril?rev=8fd97903e7f46decb89398cf57a6dabd55e4fecf#8fd97903e7f46decb89398cf57a6dabd55e4fecf" +source = "git+https://github.com/uwplse/bril?rev=e2be3f5d7e160f02b7aed0ef2bcc3e13ae722d2b#e2be3f5d7e160f02b7aed0ef2bcc3e13ae722d2b" dependencies = [ - "bril-rs 0.1.0 (git+https://github.com/uwplse/bril?rev=8fd97903e7f46decb89398cf57a6dabd55e4fecf)", + "bril-rs 0.1.0 (git+https://github.com/uwplse/bril?rev=e2be3f5d7e160f02b7aed0ef2bcc3e13ae722d2b)", "bril2json", "clap", "fxhash", @@ -269,9 +269,9 @@ dependencies = [ [[package]] name = "brillvm" version = "0.1.0" -source = "git+https://github.com/uwplse/bril?rev=8fd97903e7f46decb89398cf57a6dabd55e4fecf#8fd97903e7f46decb89398cf57a6dabd55e4fecf" +source = "git+https://github.com/uwplse/bril?rev=e2be3f5d7e160f02b7aed0ef2bcc3e13ae722d2b#e2be3f5d7e160f02b7aed0ef2bcc3e13ae722d2b" dependencies = [ - "bril-rs 0.1.0 (git+https://github.com/uwplse/bril?rev=40ec0e5803c69bc2cde794785ba6b13a4fc401fe)", + "bril-rs 0.1.0 (git+https://github.com/uwplse/bril)", "clap", "inkwell", ] @@ -608,7 +608,7 @@ checksum = "675e35c02a51bb4d4618cb4885b3839ce6d1787c97b664474d9208d074742e20" name = "eggcc" version = "0.1.0" dependencies = [ - "bril-rs 0.1.0 (git+https://github.com/uwplse/bril?rev=8fd97903e7f46decb89398cf57a6dabd55e4fecf)", + "bril-rs 0.1.0 (git+https://github.com/uwplse/bril?rev=e2be3f5d7e160f02b7aed0ef2bcc3e13ae722d2b)", "bril2json", "brilift", "brilirs", @@ -1535,9 +1535,9 @@ dependencies = [ [[package]] name = "rs2bril" version = "0.1.0" -source = "git+https://github.com/uwplse/bril?rev=8fd97903e7f46decb89398cf57a6dabd55e4fecf#8fd97903e7f46decb89398cf57a6dabd55e4fecf" +source = "git+https://github.com/uwplse/bril?rev=e2be3f5d7e160f02b7aed0ef2bcc3e13ae722d2b#e2be3f5d7e160f02b7aed0ef2bcc3e13ae722d2b" dependencies = [ - "bril-rs 0.1.0 (git+https://github.com/uwplse/bril?rev=8fd97903e7f46decb89398cf57a6dabd55e4fecf)", + "bril-rs 0.1.0 (git+https://github.com/uwplse/bril?rev=e2be3f5d7e160f02b7aed0ef2bcc3e13ae722d2b)", "clap", "proc-macro2", "syn 2.0.64", diff --git a/Cargo.toml b/Cargo.toml index 222d8478e..fa915af68 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,14 +22,14 @@ smallvec = "1.11.1" syn = { version = "2.0", features = ["full", "extra-traits"] } # currently using the uwplse/bril fork of bril, on eggcc-main -bril2json = { git = "https://github.com/uwplse/bril", rev = "8fd97903e7f46decb89398cf57a6dabd55e4fecf" } -brilirs = { git = "https://github.com/uwplse/bril", rev = "8fd97903e7f46decb89398cf57a6dabd55e4fecf" } -bril-rs = { git = "https://github.com/uwplse/bril", rev = "8fd97903e7f46decb89398cf57a6dabd55e4fecf" } -brilift = { git = "https://github.com/uwplse/bril", rev = "8fd97903e7f46decb89398cf57a6dabd55e4fecf" } -rs2bril = { git = "https://github.com/uwplse/bril", rev = "8fd97903e7f46decb89398cf57a6dabd55e4fecf" ,features = [ +bril2json = { git = "https://github.com/uwplse/bril", rev = "e2be3f5d7e160f02b7aed0ef2bcc3e13ae722d2b" } +brilirs = { git = "https://github.com/uwplse/bril", rev = "e2be3f5d7e160f02b7aed0ef2bcc3e13ae722d2b" } +bril-rs = { git = "https://github.com/uwplse/bril", rev = "e2be3f5d7e160f02b7aed0ef2bcc3e13ae722d2b" } +brilift = { git = "https://github.com/uwplse/bril", rev = "e2be3f5d7e160f02b7aed0ef2bcc3e13ae722d2b" } +rs2bril = { git = "https://github.com/uwplse/bril", rev = "e2be3f5d7e160f02b7aed0ef2bcc3e13ae722d2b" ,features = [ "import", ] } -brillvm = { git = "https://github.com/uwplse/bril", rev = "8fd97903e7f46decb89398cf57a6dabd55e4fecf" } +brillvm = { git = "https://github.com/uwplse/bril", rev = "e2be3f5d7e160f02b7aed0ef2bcc3e13ae722d2b" } ordered-float = { version = "3.7" } From 11249a6575fc87b873362b0e810f9ceeba5089b9 Mon Sep 17 00:00:00 2001 From: oflatt Date: Wed, 29 May 2024 11:16:27 -0700 Subject: [PATCH 37/47] fix up nightly to still show output --- infra/nightly.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/infra/nightly.sh b/infra/nightly.sh index dca4362e1..f1c27f492 100755 --- a/infra/nightly.sh +++ b/infra/nightly.sh @@ -50,19 +50,19 @@ pushd $TOP_DIR # locally, run on argument if [ "$LOCAL" != "" ]; then - ./infra/profile.py "$@" "$NIGHTLY_DIR" >> $NIGHTLY_DIR/log.txt 2>&1 + ./infra/profile.py "$@" "$DATA_DIR" 2>&1 | tee $NIGHTLY_DIR/log.txt else export LLVM_SYS_180_PREFIX="/usr/lib/llvm-18/" make runtime # run on all benchmarks in nightly - ./infra/profile.py benchmarks/passing "$DATA_DIR" >> $NIGHTLY_DIR/log.txt 2>&1 + ./infra/profile.py benchmarks/passing "$DATA_DIR" 2>&1 | tee $NIGHTLY_DIR/log.txt fi # Generate latex after running the profiler (depends on profile.json) -./infra/generate_line_counts.py "$DATA_DIR" >> $NIGHTLY_DIR/log.txt 2>&1 +./infra/generate_line_counts.py "$DATA_DIR" 2>&1 | tee $NIGHTLY_DIR/log.txt # Generate CFGs for LLVM after running the profiler -./infra/generate_cfgs.py "$DATA_DIR/llvm" >> $NIGHTLY_DIR/log.txt 2>&1 +./infra/generate_cfgs.py "$DATA_DIR/llvm" 2>&1 | tee $NIGHTLY_DIR/log.txt popd From cfa288b152ee5d615decdaac3888397439650a19 Mon Sep 17 00:00:00 2001 From: oflatt Date: Wed, 29 May 2024 11:19:59 -0700 Subject: [PATCH 38/47] better names --- src/canonicalize_names.rs | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/canonicalize_names.rs b/src/canonicalize_names.rs index 5fd7fae78..38b3bc853 100644 --- a/src/canonicalize_names.rs +++ b/src/canonicalize_names.rs @@ -35,11 +35,13 @@ fn canonicalize_func_names(func: &Function) -> Function { } impl Renamer { - fn get_name(&mut self, name: &str) -> String { + /// Get a new name for a variable. If the variable has already been renamed, + /// return the new name. Otherwise, generate a new name and return it. + fn get_name(&mut self, name: &str, prefix: String) -> String { if let Some(new_name) = self.name_map.get(name) { new_name.clone() } else { - let new_name = format!("v{}_", self.name_map.len()); + let new_name = format!("{}{}_", prefix, self.name_map.len()); self.name_map.insert(name.to_string(), new_name.clone()); new_name } @@ -58,7 +60,7 @@ impl Renamer { Code::Instruction(self.canonicalize_instruction_names(instr)) } Code::Label { label, pos } => Code::Label { - label: self.get_name(label), + label: self.get_name(label, "b".to_string()), pos: pos.clone(), }, } @@ -73,7 +75,7 @@ impl Renamer { const_type, value, } => Instruction::Constant { - dest: self.get_name(dest), + dest: self.get_name(dest, "c".to_string()), op: *op, pos: pos.clone(), const_type: const_type.clone(), @@ -89,16 +91,22 @@ impl Renamer { op_type, } => Instruction::Value { args: { - let mut args: Vec<_> = args.iter().map(|arg| self.get_name(arg)).collect(); + let mut args: Vec<_> = args + .iter() + .map(|arg| self.get_name(arg, "v".to_string())) + .collect(); use bril_rs::ValueOps::*; if matches!(op, Add | Mul | Eq | And | Or) { args.sort(); } args }, - dest: self.get_name(dest), + dest: self.get_name(dest, "v".to_string()), funcs: funcs.clone(), - labels: labels.iter().map(|label| self.get_name(label)).collect(), + labels: labels + .iter() + .map(|label| self.get_name(label, "b".to_string())) + .collect(), op: *op, pos: pos.clone(), op_type: op_type.clone(), @@ -110,9 +118,15 @@ impl Renamer { op, pos, } => Instruction::Effect { - args: args.iter().map(|arg| self.get_name(arg)).collect(), + args: args + .iter() + .map(|arg| self.get_name(arg, "v".to_string())) + .collect(), funcs: funcs.clone(), - labels: labels.iter().map(|label| self.get_name(label)).collect(), + labels: labels + .iter() + .map(|label| self.get_name(label, "b".to_string())) + .collect(), op: *op, pos: pos.clone(), }, From 915481ed97de1bd341974978ddd831fae5a5f3b6 Mon Sep 17 00:00:00 2001 From: oflatt Date: Wed, 29 May 2024 11:23:17 -0700 Subject: [PATCH 39/47] cargo lock --- dag_in_context/.gitignore | 1 - dag_in_context/Cargo.lock | 1429 +++++++++++++++++++++++++++++++++++++ 2 files changed, 1429 insertions(+), 1 deletion(-) delete mode 100644 dag_in_context/.gitignore create mode 100644 dag_in_context/Cargo.lock diff --git a/dag_in_context/.gitignore b/dag_in_context/.gitignore deleted file mode 100644 index ffa3bbd20..000000000 --- a/dag_in_context/.gitignore +++ /dev/null @@ -1 +0,0 @@ -Cargo.lock \ No newline at end of file diff --git a/dag_in_context/Cargo.lock b/dag_in_context/Cargo.lock new file mode 100644 index 000000000..f30d7261b --- /dev/null +++ b/dag_in_context/Cargo.lock @@ -0,0 +1,1429 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + +[[package]] +name = "anstream" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "archery" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8967cd1cc9e9e1954f644e14fbd6042fe9a37da96c52a67e44a2ac18261f8561" +dependencies = [ + "static_assertions", + "triomphe", +] + +[[package]] +name = "ascii-canvas" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +dependencies = [ + "term", +] + +[[package]] +name = "autocfg" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bril-rs" +version = "0.1.0" +source = "git+https://github.com/uwplse/bril?rev=78881c45aa53231915f333d1d6dcc26cedc63b57#78881c45aa53231915f333d1d6dcc26cedc63b57" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.57", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "dag_in_context" +version = "0.1.0" +dependencies = [ + "bril-rs", + "dot-structures", + "egglog", + "egraph-serialize", + "env_logger 0.11.3", + "graphviz-rust 0.8.0", + "indexmap", + "log", + "main_error", + "ordered-float", + "rpds", + "rustc-hash", + "strum", + "strum_macros", + "symbol_table", + "thiserror", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dot-generator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aaac7ada45f71873ebce336491d1c1bc4a7c8042c7cea978168ad59e805b871" +dependencies = [ + "dot-structures", +] + +[[package]] +name = "dot-structures" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "675e35c02a51bb4d4618cb4885b3839ce6d1787c97b664474d9208d074742e20" + +[[package]] +name = "egglog" +version = "0.1.0" +source = "git+https://github.com/egraphs-good/egglog?rev=325814fd90767b5e43c72bc2eb65e14ff0b8746c#325814fd90767b5e43c72bc2eb65e14ff0b8746c" +dependencies = [ + "clap", + "egraph-serialize", + "env_logger 0.10.2", + "generic_symbolic_expressions", + "hashbrown 0.14.3", + "indexmap", + "instant", + "lalrpop", + "lalrpop-util", + "lazy_static", + "log", + "num-integer", + "num-rational", + "num-traits", + "ordered-float", + "regex", + "rustc-hash", + "serde_json", + "smallvec", + "symbol_table", + "thiserror", +] + +[[package]] +name = "egraph-serialize" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a41150f383849cfc16ae6230f592112b3c0a2c0e3ec43eb0b09db037bfcce703" +dependencies = [ + "graphviz-rust 0.6.6", + "indexmap", + "once_cell", + "ordered-float", + "serde", + "serde_json", +] + +[[package]] +name = "either" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" + +[[package]] +name = "ena" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" +dependencies = [ + "log", +] + +[[package]] +name = "env_filter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "env_logger" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "generic_symbolic_expressions" +version = "5.0.3" +source = "git+https://github.com/oflatt/symbolic-expressions?rev=655b6a4c06b4b3d3b2300e17779860b4abe440f0#655b6a4c06b4b3d3b2300e17779860b4abe440f0" + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "graphviz-rust" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27dafd1ac303e0dfb347a3861d9ac440859bab26ec2f534bbceb262ea492a1e0" +dependencies = [ + "dot-generator", + "dot-structures", + "into-attr", + "into-attr-derive", + "pest", + "pest_derive", + "rand", + "tempfile", +] + +[[package]] +name = "graphviz-rust" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d3adbad2800805b14170067aee88336e12838823086b6a4f70ca8dfb5d971f3" +dependencies = [ + "dot-generator", + "dot-structures", + "into-attr", + "into-attr-derive", + "pest", + "pest_derive", + "rand", + "tempfile", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.8", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +dependencies = [ + "ahash 0.8.11", + "allocator-api2", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", + "serde", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "into-attr" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18b48c537e49a709e678caec3753a7dba6854661a1eaa27675024283b3f8b376" +dependencies = [ + "dot-structures", +] + +[[package]] +name = "into-attr-derive" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecac7c1ae6cd2c6a3a64d1061a8bdc7f52ff62c26a831a2301e54c1b5d70d5b1" +dependencies = [ + "dot-generator", + "dot-structures", + "into-attr", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "is-terminal" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys", +] + +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "lalrpop" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cb077ad656299f160924eb2912aa147d7339ea7d69e1b5517326fdcec3c1ca" +dependencies = [ + "ascii-canvas", + "bit-set", + "ena", + "itertools", + "lalrpop-util", + "petgraph", + "pico-args", + "regex", + "regex-syntax", + "string_cache", + "term", + "tiny-keccak", + "unicode-xid", + "walkdir", +] + +[[package]] +name = "lalrpop-util" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.5.0", + "libc", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "main_error" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "155db5e86c6e45ee456bf32fad5a290ee1f7151c2faca27ea27097568da67d1a" + +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "ordered-float" +version = "3.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1e1c390732d15f1d48471625cd92d154e66db2c56645e29a9cd26f4699f72dc" +dependencies = [ + "num-traits", + "rand", + "serde", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.48.5", +] + +[[package]] +name = "pest" +version = "2.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "311fb059dee1a7b802f036316d790138c613a4e8b180c822e3925a662e9f0c95" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f73541b156d32197eecda1a4014d7f868fd2bcb3c550d5386087cfba442bf69c" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c35eeed0a3fab112f75165fdc026b3913f4183133f19b49be773ac9ea966e8bd" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.57", +] + +[[package]] +name = "pest_meta" +version = "2.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2adbf29bb9776f28caece835398781ab24435585fe0d4dc1374a61db5accedca" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + +[[package]] +name = "petgraph" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pico-args" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", + "serde", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", + "serde", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_users" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" + +[[package]] +name = "rpds" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0e15515d3ce3313324d842629ea4905c25a13f81953eadb88f85516f59290a4" +dependencies = [ + "archery", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustix" +version = "0.38.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" +dependencies = [ + "bitflags 2.5.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "ryu" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.57", +] + +[[package]] +name = "serde_json" +version = "1.0.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "string_cache" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +dependencies = [ + "new_debug_unreachable", + "once_cell", + "parking_lot", + "phf_shared", + "precomputed-hash", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" + +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.57", +] + +[[package]] +name = "symbol_table" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "828f672b631c220bf6ea8a1d3b82c7d0fc998e5ba8373383d8604bc1e2a6245a" +dependencies = [ + "ahash 0.7.8", + "hashbrown 0.12.3", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11a6ae1e52eb25aab8f3fb9fca13be982a373b8f1157ca14b897a825ba4a2d35" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if", + "fastrand", + "rustix", + "windows-sys", +] + +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.57", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "triomphe" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.4", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.57", +] From 3fa9cb514e08f07c0841acf0aa0b8e00ca3ca4fe Mon Sep 17 00:00:00 2001 From: oflatt Date: Wed, 29 May 2024 11:23:17 -0700 Subject: [PATCH 40/47] cargo lock --- dag_in_context/.gitignore | 1 - dag_in_context/Cargo.lock | 1429 +++++++++++++++++++++++++++++++++++++ 2 files changed, 1429 insertions(+), 1 deletion(-) delete mode 100644 dag_in_context/.gitignore create mode 100644 dag_in_context/Cargo.lock diff --git a/dag_in_context/.gitignore b/dag_in_context/.gitignore deleted file mode 100644 index ffa3bbd20..000000000 --- a/dag_in_context/.gitignore +++ /dev/null @@ -1 +0,0 @@ -Cargo.lock \ No newline at end of file diff --git a/dag_in_context/Cargo.lock b/dag_in_context/Cargo.lock new file mode 100644 index 000000000..f30d7261b --- /dev/null +++ b/dag_in_context/Cargo.lock @@ -0,0 +1,1429 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + +[[package]] +name = "anstream" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "archery" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8967cd1cc9e9e1954f644e14fbd6042fe9a37da96c52a67e44a2ac18261f8561" +dependencies = [ + "static_assertions", + "triomphe", +] + +[[package]] +name = "ascii-canvas" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +dependencies = [ + "term", +] + +[[package]] +name = "autocfg" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bril-rs" +version = "0.1.0" +source = "git+https://github.com/uwplse/bril?rev=78881c45aa53231915f333d1d6dcc26cedc63b57#78881c45aa53231915f333d1d6dcc26cedc63b57" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.57", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "dag_in_context" +version = "0.1.0" +dependencies = [ + "bril-rs", + "dot-structures", + "egglog", + "egraph-serialize", + "env_logger 0.11.3", + "graphviz-rust 0.8.0", + "indexmap", + "log", + "main_error", + "ordered-float", + "rpds", + "rustc-hash", + "strum", + "strum_macros", + "symbol_table", + "thiserror", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dot-generator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aaac7ada45f71873ebce336491d1c1bc4a7c8042c7cea978168ad59e805b871" +dependencies = [ + "dot-structures", +] + +[[package]] +name = "dot-structures" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "675e35c02a51bb4d4618cb4885b3839ce6d1787c97b664474d9208d074742e20" + +[[package]] +name = "egglog" +version = "0.1.0" +source = "git+https://github.com/egraphs-good/egglog?rev=325814fd90767b5e43c72bc2eb65e14ff0b8746c#325814fd90767b5e43c72bc2eb65e14ff0b8746c" +dependencies = [ + "clap", + "egraph-serialize", + "env_logger 0.10.2", + "generic_symbolic_expressions", + "hashbrown 0.14.3", + "indexmap", + "instant", + "lalrpop", + "lalrpop-util", + "lazy_static", + "log", + "num-integer", + "num-rational", + "num-traits", + "ordered-float", + "regex", + "rustc-hash", + "serde_json", + "smallvec", + "symbol_table", + "thiserror", +] + +[[package]] +name = "egraph-serialize" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a41150f383849cfc16ae6230f592112b3c0a2c0e3ec43eb0b09db037bfcce703" +dependencies = [ + "graphviz-rust 0.6.6", + "indexmap", + "once_cell", + "ordered-float", + "serde", + "serde_json", +] + +[[package]] +name = "either" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" + +[[package]] +name = "ena" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" +dependencies = [ + "log", +] + +[[package]] +name = "env_filter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "env_logger" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "generic_symbolic_expressions" +version = "5.0.3" +source = "git+https://github.com/oflatt/symbolic-expressions?rev=655b6a4c06b4b3d3b2300e17779860b4abe440f0#655b6a4c06b4b3d3b2300e17779860b4abe440f0" + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "graphviz-rust" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27dafd1ac303e0dfb347a3861d9ac440859bab26ec2f534bbceb262ea492a1e0" +dependencies = [ + "dot-generator", + "dot-structures", + "into-attr", + "into-attr-derive", + "pest", + "pest_derive", + "rand", + "tempfile", +] + +[[package]] +name = "graphviz-rust" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d3adbad2800805b14170067aee88336e12838823086b6a4f70ca8dfb5d971f3" +dependencies = [ + "dot-generator", + "dot-structures", + "into-attr", + "into-attr-derive", + "pest", + "pest_derive", + "rand", + "tempfile", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.8", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +dependencies = [ + "ahash 0.8.11", + "allocator-api2", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", + "serde", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "into-attr" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18b48c537e49a709e678caec3753a7dba6854661a1eaa27675024283b3f8b376" +dependencies = [ + "dot-structures", +] + +[[package]] +name = "into-attr-derive" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecac7c1ae6cd2c6a3a64d1061a8bdc7f52ff62c26a831a2301e54c1b5d70d5b1" +dependencies = [ + "dot-generator", + "dot-structures", + "into-attr", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "is-terminal" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys", +] + +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "lalrpop" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cb077ad656299f160924eb2912aa147d7339ea7d69e1b5517326fdcec3c1ca" +dependencies = [ + "ascii-canvas", + "bit-set", + "ena", + "itertools", + "lalrpop-util", + "petgraph", + "pico-args", + "regex", + "regex-syntax", + "string_cache", + "term", + "tiny-keccak", + "unicode-xid", + "walkdir", +] + +[[package]] +name = "lalrpop-util" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.5.0", + "libc", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "main_error" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "155db5e86c6e45ee456bf32fad5a290ee1f7151c2faca27ea27097568da67d1a" + +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "ordered-float" +version = "3.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1e1c390732d15f1d48471625cd92d154e66db2c56645e29a9cd26f4699f72dc" +dependencies = [ + "num-traits", + "rand", + "serde", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.48.5", +] + +[[package]] +name = "pest" +version = "2.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "311fb059dee1a7b802f036316d790138c613a4e8b180c822e3925a662e9f0c95" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f73541b156d32197eecda1a4014d7f868fd2bcb3c550d5386087cfba442bf69c" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c35eeed0a3fab112f75165fdc026b3913f4183133f19b49be773ac9ea966e8bd" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.57", +] + +[[package]] +name = "pest_meta" +version = "2.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2adbf29bb9776f28caece835398781ab24435585fe0d4dc1374a61db5accedca" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + +[[package]] +name = "petgraph" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pico-args" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", + "serde", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", + "serde", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_users" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" + +[[package]] +name = "rpds" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0e15515d3ce3313324d842629ea4905c25a13f81953eadb88f85516f59290a4" +dependencies = [ + "archery", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustix" +version = "0.38.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" +dependencies = [ + "bitflags 2.5.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "ryu" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.57", +] + +[[package]] +name = "serde_json" +version = "1.0.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "string_cache" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +dependencies = [ + "new_debug_unreachable", + "once_cell", + "parking_lot", + "phf_shared", + "precomputed-hash", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" + +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.57", +] + +[[package]] +name = "symbol_table" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "828f672b631c220bf6ea8a1d3b82c7d0fc998e5ba8373383d8604bc1e2a6245a" +dependencies = [ + "ahash 0.7.8", + "hashbrown 0.12.3", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11a6ae1e52eb25aab8f3fb9fca13be982a373b8f1157ca14b897a825ba4a2d35" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if", + "fastrand", + "rustix", + "windows-sys", +] + +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.57", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "triomphe" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.4", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.57", +] From bb4b9907217906e85c416c9ddd6491e141c1cc25 Mon Sep 17 00:00:00 2001 From: oflatt Date: Wed, 29 May 2024 11:38:38 -0700 Subject: [PATCH 41/47] snapshots --- tests/snapshots/files__add-optimize.snap | 6 +- ...files__add_block_indirection-optimize.snap | 6 +- .../files__block-diamond-optimize.snap | 54 +- tests/snapshots/files__bool-optimize.snap | 6 +- ...files__branch_duplicate_work-optimize.snap | 16 +- ...ollatz_redundant_computation-optimize.snap | 52 +- .../files__constant_fold_simple-optimize.snap | 8 +- tests/snapshots/files__diamond-optimize.snap | 18 +- .../files__duplicate_branch-optimize.snap | 18 +- .../files__eliminate_gamma-optimize.snap | 6 +- ...es__eliminate_gamma_interval-optimize.snap | 30 +- .../files__eliminate_loop-optimize.snap | 6 +- .../files__fib_recursive-optimize.snap | 524 +++++++++--------- .../snapshots/files__fib_shape-optimize.snap | 22 +- .../files__five_call_nestings-optimize.snap | 22 +- .../files__flatten_loop-optimize.snap | 38 +- .../files__four_call_nestings-optimize.snap | 20 +- .../files__gamma_condition_and-optimize.snap | 32 +- .../files__gamma_pull_in-optimize.snap | 20 +- .../files__if_constant_fold-optimize.snap | 10 +- .../files__if_constant_fold2-optimize.snap | 34 +- .../snapshots/files__if_context-optimize.snap | 24 +- .../files__if_dead_code-optimize.snap | 20 +- .../files__if_interval-optimize.snap | 22 +- .../files__implicit-return-optimize.snap | 62 +-- .../files__impossible_if-optimize.snap | 28 +- .../files__jumping_loop-optimize.snap | 20 +- .../snapshots/files__loop_hoist-optimize.snap | 30 +- tests/snapshots/files__loop_if-optimize.snap | 40 +- .../files__loop_pass_through-optimize.snap | 16 +- .../files__loop_with_mul_by_inv-optimize.snap | 24 +- ...s__mem_loop_store_forwarding-optimize.snap | 30 +- ...s__mem_simple_redundant_load-optimize.snap | 22 +- ..._mem_simple_store_forwarding-optimize.snap | 20 +- .../files__nested_call-optimize.snap | 24 +- .../snapshots/files__peel_twice-optimize.snap | 6 +- ...les__peel_twice_precalc_pred-optimize.snap | 6 +- .../files__range_check-optimize.snap | 48 +- .../files__range_splitting-optimize.snap | 46 +- tests/snapshots/files__reassoc-optimize.snap | 14 +- .../files__recurse_once-optimize.snap | 50 +- .../files__simple-call-optimize.snap | 12 +- .../files__simple_branch-optimize.snap | 20 +- .../files__simple_call-optimize.snap | 12 +- .../files__simple_loop-optimize.snap | 6 +- .../files__simple_loop_swap-optimize.snap | 20 +- .../files__simple_recursive-optimize.snap | 56 +- .../files__simplest_loop-optimize.snap | 20 +- .../files__small-collatz-optimize.snap | 58 +- .../snapshots/files__small-fib-optimize.snap | 38 +- tests/snapshots/files__sqrt-optimize.snap | 82 +-- .../files__strong_loop-optimize.snap | 30 +- tests/snapshots/files__two_fns-optimize.snap | 12 +- ...es__unroll_and_constant_fold-optimize.snap | 6 +- .../files__unroll_multiple_4-optimize.snap | 20 +- 55 files changed, 946 insertions(+), 946 deletions(-) diff --git a/tests/snapshots/files__add-optimize.snap b/tests/snapshots/files__add-optimize.snap index d95e208b7..0fa2f9633 100644 --- a/tests/snapshots/files__add-optimize.snap +++ b/tests/snapshots/files__add-optimize.snap @@ -3,7 +3,7 @@ source: tests/files.rs expression: visualization.result --- @main { -.v0_: - v1_: int = const 3; - print v1_; +.b0_: + c1_: int = const 3; + print c1_; } diff --git a/tests/snapshots/files__add_block_indirection-optimize.snap b/tests/snapshots/files__add_block_indirection-optimize.snap index d95e208b7..0fa2f9633 100644 --- a/tests/snapshots/files__add_block_indirection-optimize.snap +++ b/tests/snapshots/files__add_block_indirection-optimize.snap @@ -3,7 +3,7 @@ source: tests/files.rs expression: visualization.result --- @main { -.v0_: - v1_: int = const 3; - print v1_; +.b0_: + c1_: int = const 3; + print c1_; } diff --git a/tests/snapshots/files__block-diamond-optimize.snap b/tests/snapshots/files__block-diamond-optimize.snap index 300d2c0ca..047b5bcce 100644 --- a/tests/snapshots/files__block-diamond-optimize.snap +++ b/tests/snapshots/files__block-diamond-optimize.snap @@ -3,35 +3,35 @@ source: tests/files.rs expression: visualization.result --- @main(v0: int) { -.v1_: - v2_: int = const 2; - v3_: bool = lt v0 v2_; +.b1_: + c2_: int = const 2; + v3_: bool = lt v0 c2_; v4_: bool = not v3_; - v5_: int = const 0; - v6_: int = const 1; - v7_: int = const 5; - v8_: bool = const true; - v9_: int = id v6_; - v10_: int = id v6_; - v11_: int = id v2_; - v12_: bool = id v8_; - br v3_ .v13_ .v14_; -.v13_: - v15_: int = const 4; - v16_: bool = const false; - v9_: int = id v15_; - v10_: int = id v6_; - v11_: int = id v2_; - v12_: bool = id v16_; -.v14_: + c5_: int = const 0; + c6_: int = const 1; + c7_: int = const 5; + c8_: bool = const true; + v9_: int = id c6_; + v10_: int = id c6_; + v11_: int = id c2_; + v12_: bool = id c8_; + br v3_ .b13_ .b14_; +.b13_: + c15_: int = const 4; + c16_: bool = const false; + v9_: int = id c15_; + v10_: int = id c6_; + v11_: int = id c2_; + v12_: bool = id c16_; +.b14_: v17_: int = id v9_; - v18_: int = id v6_; - br v4_ .v19_ .v20_; -.v19_: - v21_: int = add v2_ v9_; + v18_: int = id c6_; + br v4_ .b19_ .b20_; +.b19_: + v21_: int = add c2_ v9_; v17_: int = id v21_; - v18_: int = id v6_; -.v20_: - v22_: int = add v17_ v6_; + v18_: int = id c6_; +.b20_: + v22_: int = add c6_ v17_; print v22_; } diff --git a/tests/snapshots/files__bool-optimize.snap b/tests/snapshots/files__bool-optimize.snap index 6eecd39bc..be6719990 100644 --- a/tests/snapshots/files__bool-optimize.snap +++ b/tests/snapshots/files__bool-optimize.snap @@ -3,7 +3,7 @@ source: tests/files.rs expression: visualization.result --- @main { -.v0_: - v1_: bool = const true; - print v1_; +.b0_: + c1_: bool = const true; + print c1_; } diff --git a/tests/snapshots/files__branch_duplicate_work-optimize.snap b/tests/snapshots/files__branch_duplicate_work-optimize.snap index 16aa11209..87248bd9c 100644 --- a/tests/snapshots/files__branch_duplicate_work-optimize.snap +++ b/tests/snapshots/files__branch_duplicate_work-optimize.snap @@ -3,19 +3,19 @@ source: tests/files.rs expression: visualization.result --- @main(v0: int) { -.v1_: - v2_: int = const 2; - v3_: bool = lt v0 v2_; - br v3_ .v4_ .v5_; -.v4_: +.b1_: + c2_: int = const 2; + v3_: bool = lt v0 c2_; + br v3_ .b4_ .b5_; +.b4_: v6_: int = add v0 v0; v7_: int = id v6_; print v7_; ret; -.v5_: +.b5_: v8_: int = add v0 v0; - v9_: int = mul v2_ v8_; + v9_: int = mul c2_ v8_; v7_: int = id v9_; -.v10_: +.b10_: print v7_; } diff --git a/tests/snapshots/files__collatz_redundant_computation-optimize.snap b/tests/snapshots/files__collatz_redundant_computation-optimize.snap index 187e40bd8..80ca1983d 100644 --- a/tests/snapshots/files__collatz_redundant_computation-optimize.snap +++ b/tests/snapshots/files__collatz_redundant_computation-optimize.snap @@ -3,29 +3,29 @@ source: tests/files.rs expression: visualization.result --- @main(v0: int) { -.v1_: - v2_: int = const 1; - v3_: int = const 3; - v4_: int = const 2; - v5_: int = const 0; +.b1_: + c2_: int = const 1; + c3_: int = const 3; + c4_: int = const 2; + c5_: int = const 0; v6_: int = id v0; v7_: int = id v0; - v8_: int = id v2_; - v9_: int = id v3_; - v10_: int = id v4_; - v11_: int = id v5_; -.v12_: + v8_: int = id c2_; + v9_: int = id c3_; + v10_: int = id c4_; + v11_: int = id c5_; +.b12_: v13_: bool = eq v7_ v8_; - v14_: bool = const false; + c14_: bool = const false; v15_: int = id v6_; - v16_: bool = id v14_; + v16_: bool = id c14_; v17_: int = id v7_; v18_: int = id v7_; v19_: int = id v9_; v20_: int = id v10_; v21_: int = id v11_; - br v13_ .v22_ .v23_; -.v23_: + br v13_ .b22_ .b23_; +.b23_: v24_: int = div v7_ v10_; v25_: int = mul v10_ v24_; v26_: int = sub v7_ v25_; @@ -33,34 +33,34 @@ expression: visualization.result print v7_; v28_: int = mul v7_ v9_; v29_: int = add v28_ v8_; - v30_: bool = const true; + c30_: bool = const true; v31_: int = id v6_; - v32_: bool = id v30_; + v32_: bool = id c30_; v33_: int = id v29_; v34_: int = id v8_; v35_: int = id v9_; v36_: int = id v10_; v37_: int = id v11_; - br v27_ .v38_ .v39_; -.v38_: - v40_: bool = const true; + br v27_ .b38_ .b39_; +.b38_: + c40_: bool = const true; v31_: int = id v6_; - v32_: bool = id v40_; + v32_: bool = id c40_; v33_: int = id v24_; v34_: int = id v8_; v35_: int = id v9_; v36_: int = id v10_; v37_: int = id v11_; -.v39_: - v41_: bool = const true; +.b39_: + c41_: bool = const true; v15_: int = id v6_; - v16_: bool = id v41_; + v16_: bool = id c41_; v17_: int = id v33_; v18_: int = id v8_; v19_: int = id v9_; v20_: int = id v10_; v21_: int = id v11_; -.v22_: +.b22_: v42_: bool = not v13_; v6_: int = id v6_; v7_: int = id v17_; @@ -68,7 +68,7 @@ expression: visualization.result v9_: int = id v9_; v10_: int = id v10_; v11_: int = id v11_; - br v42_ .v12_ .v43_; -.v43_: + br v42_ .b12_ .b43_; +.b43_: print v0; } diff --git a/tests/snapshots/files__constant_fold_simple-optimize.snap b/tests/snapshots/files__constant_fold_simple-optimize.snap index c32019f7e..e7558db1f 100644 --- a/tests/snapshots/files__constant_fold_simple-optimize.snap +++ b/tests/snapshots/files__constant_fold_simple-optimize.snap @@ -3,9 +3,9 @@ source: tests/files.rs expression: visualization.result --- @main { -.v0_: - v1_: int = const 3; - v2_: int = const 2; - v3_: int = div v1_ v2_; +.b0_: + c1_: int = const 3; + c2_: int = const 2; + v3_: int = div c1_ c2_; print v3_; } diff --git a/tests/snapshots/files__diamond-optimize.snap b/tests/snapshots/files__diamond-optimize.snap index 815ec7797..8ee1eecf7 100644 --- a/tests/snapshots/files__diamond-optimize.snap +++ b/tests/snapshots/files__diamond-optimize.snap @@ -3,15 +3,15 @@ source: tests/files.rs expression: visualization.result --- @main(v0: int) { -.v1_: +.b1_: v2_: bool = lt v0 v0; - br v2_ .v3_ .v4_; -.v3_: - v5_: int = const 1; - print v5_; + br v2_ .b3_ .b4_; +.b3_: + c5_: int = const 1; + print c5_; ret; -.v4_: - v6_: int = const 2; - print v6_; -.v7_: +.b4_: + c6_: int = const 2; + print c6_; +.b7_: } diff --git a/tests/snapshots/files__duplicate_branch-optimize.snap b/tests/snapshots/files__duplicate_branch-optimize.snap index cb9f9dd84..7f02efff8 100644 --- a/tests/snapshots/files__duplicate_branch-optimize.snap +++ b/tests/snapshots/files__duplicate_branch-optimize.snap @@ -3,13 +3,13 @@ source: tests/files.rs expression: visualization.result --- @main(v0: int) { -.v1_: - v2_: int = const 4; - v3_: bool = lt v2_ v0; - v4_: int = id v2_; - br v3_ .v5_ .v6_; -.v5_: - v4_: int = id v2_; -.v6_: - print v2_; +.b1_: + c2_: int = const 4; + v3_: bool = lt c2_ v0; + v4_: int = id c2_; + br v3_ .b5_ .b6_; +.b5_: + v4_: int = id c2_; +.b6_: + print c2_; } diff --git a/tests/snapshots/files__eliminate_gamma-optimize.snap b/tests/snapshots/files__eliminate_gamma-optimize.snap index 8449ee79a..0020317f3 100644 --- a/tests/snapshots/files__eliminate_gamma-optimize.snap +++ b/tests/snapshots/files__eliminate_gamma-optimize.snap @@ -3,7 +3,7 @@ source: tests/files.rs expression: visualization.result --- @main { -.v0_: - v1_: int = const 1; - print v1_; +.b0_: + c1_: int = const 1; + print c1_; } diff --git a/tests/snapshots/files__eliminate_gamma_interval-optimize.snap b/tests/snapshots/files__eliminate_gamma_interval-optimize.snap index fc1dfb7ef..d1d687cc3 100644 --- a/tests/snapshots/files__eliminate_gamma_interval-optimize.snap +++ b/tests/snapshots/files__eliminate_gamma_interval-optimize.snap @@ -3,19 +3,19 @@ source: tests/files.rs expression: visualization.result --- @main(v0: int) { -.v1_: - v2_: bool = const false; - v3_: int = const 10; - v4_: bool = lt v0 v3_; - v5_: int = const 5; - v6_: int = const 3; - v7_: int = id v3_; - v8_: int = id v6_; - br v4_ .v9_ .v10_; -.v9_: - v11_: int = const 7; - v7_: int = id v3_; - v8_: int = id v11_; -.v10_: - print v2_; +.b1_: + c2_: bool = const false; + c3_: int = const 10; + v4_: bool = lt v0 c3_; + c5_: int = const 5; + c6_: int = const 3; + v7_: int = id c3_; + v8_: int = id c6_; + br v4_ .b9_ .b10_; +.b9_: + c11_: int = const 7; + v7_: int = id c3_; + v8_: int = id c11_; +.b10_: + print c2_; } diff --git a/tests/snapshots/files__eliminate_loop-optimize.snap b/tests/snapshots/files__eliminate_loop-optimize.snap index 8449ee79a..0020317f3 100644 --- a/tests/snapshots/files__eliminate_loop-optimize.snap +++ b/tests/snapshots/files__eliminate_loop-optimize.snap @@ -3,7 +3,7 @@ source: tests/files.rs expression: visualization.result --- @main { -.v0_: - v1_: int = const 1; - print v1_; +.b0_: + c1_: int = const 1; + print c1_; } diff --git a/tests/snapshots/files__fib_recursive-optimize.snap b/tests/snapshots/files__fib_recursive-optimize.snap index 9a02639c2..248e01f79 100644 --- a/tests/snapshots/files__fib_recursive-optimize.snap +++ b/tests/snapshots/files__fib_recursive-optimize.snap @@ -3,340 +3,340 @@ source: tests/files.rs expression: visualization.result --- @fac(v0: int): int { -.v1_: - v2_: int = const 0; - v3_: bool = eq v0 v2_; - v4_: int = const 1; - v5_: int = id v4_; - br v3_ .v6_ .v7_; -.v7_: - v8_: bool = eq v0 v4_; - br v8_ .v9_ .v10_; -.v9_: - v11_: bool = eq v2_ v2_; - v12_: int = id v4_; - br v11_ .v13_ .v14_; -.v14_: - v15_: bool = eq v2_ v4_; - br v15_ .v16_ .v17_; -.v16_: - v18_: bool = eq v2_ v2_; - v19_: int = id v4_; - br v18_ .v20_ .v21_; -.v21_: - v22_: bool = eq v2_ v4_; - br v22_ .v23_ .v24_; -.v23_: - v25_: int = call @fac v2_; - v26_: int = id v4_; -.v27_: +.b1_: + c2_: int = const 0; + v3_: bool = eq c2_ v0; + c4_: int = const 1; + v5_: int = id c4_; + br v3_ .b6_ .b7_; +.b7_: + v8_: bool = eq c4_ v0; + br v8_ .b9_ .b10_; +.b9_: + v11_: bool = eq c2_ c2_; + v12_: int = id c4_; + br v11_ .b13_ .b14_; +.b14_: + v15_: bool = eq c2_ c4_; + br v15_ .b16_ .b17_; +.b16_: + v18_: bool = eq c2_ c2_; + v19_: int = id c4_; + br v18_ .b20_ .b21_; +.b21_: + v22_: bool = eq c2_ c4_; + br v22_ .b23_ .b24_; +.b23_: + v25_: int = call @fac c2_; + v26_: int = id c4_; +.b27_: v19_: int = id v26_; -.v20_: - v28_: int = id v4_; -.v29_: +.b20_: + v28_: int = id c4_; +.b29_: v12_: int = id v28_; -.v13_: - v30_: int = id v4_; -.v31_: +.b13_: + v30_: int = id c4_; +.b31_: v5_: int = id v30_; ret v5_; -.v24_: - v32_: int = const -1; - v33_: int = sub v32_ v4_; - v34_: int = call @fac v32_; +.b24_: + c32_: int = const -1; + v33_: int = sub c32_ c4_; + v34_: int = call @fac c32_; v35_: int = call @fac v33_; v36_: int = add v34_ v35_; v26_: int = id v36_; - jmp .v27_; -.v17_: - v37_: int = const -2; - v38_: bool = eq v2_ v37_; - v39_: int = const -1; - v40_: bool = eq v2_ v39_; - v41_: int = id v4_; - br v40_ .v42_ .v43_; -.v43_: - v44_: bool = eq v39_ v4_; - br v44_ .v45_ .v46_; -.v45_: - v47_: int = call @fac v2_; - v48_: int = id v4_; -.v49_: + jmp .b27_; +.b17_: + c37_: int = const -2; + v38_: bool = eq c2_ c37_; + c39_: int = const -1; + v40_: bool = eq c2_ c39_; + v41_: int = id c4_; + br v40_ .b42_ .b43_; +.b43_: + v44_: bool = eq c39_ c4_; + br v44_ .b45_ .b46_; +.b45_: + v47_: int = call @fac c2_; + v48_: int = id c4_; +.b49_: v41_: int = id v48_; -.v42_: - v50_: int = id v4_; - br v38_ .v51_ .v52_; -.v52_: - v53_: bool = eq v37_ v4_; - br v53_ .v54_ .v55_; -.v54_: - v56_: int = call @fac v2_; - v57_: int = id v4_; -.v58_: +.b42_: + v50_: int = id c4_; + br v38_ .b51_ .b52_; +.b52_: + v53_: bool = eq c37_ c4_; + br v53_ .b54_ .b55_; +.b54_: + v56_: int = call @fac c2_; + v57_: int = id c4_; +.b58_: v50_: int = id v57_; -.v51_: +.b51_: v59_: int = add v41_ v50_; v28_: int = id v59_; - jmp .v29_; -.v55_: - v60_: int = const -4; - v61_: int = const -3; - v62_: int = call @fac v61_; - v63_: int = call @fac v60_; + jmp .b29_; +.b55_: + c60_: int = const -4; + c61_: int = const -3; + v62_: int = call @fac c61_; + v63_: int = call @fac c60_; v64_: int = add v62_ v63_; v57_: int = id v64_; - jmp .v58_; -.v46_: - v65_: int = const -3; - v66_: int = const -2; - v67_: int = call @fac v66_; - v68_: int = call @fac v65_; + jmp .b58_; +.b46_: + c65_: int = const -3; + c66_: int = const -2; + v67_: int = call @fac c66_; + v68_: int = call @fac c65_; v69_: int = add v67_ v68_; v48_: int = id v69_; - jmp .v49_; -.v10_: - v70_: int = sub v0 v4_; - v71_: int = sub v70_ v4_; - v72_: bool = eq v2_ v71_; - v73_: bool = eq v2_ v70_; - v74_: int = id v4_; - br v73_ .v75_ .v76_; -.v76_: - v77_: bool = eq v4_ v70_; - br v77_ .v78_ .v79_; -.v78_: - v80_: bool = eq v2_ v2_; + jmp .b49_; +.b10_: + v70_: int = sub v0 c4_; + v71_: int = sub v70_ c4_; + v72_: bool = eq c2_ v71_; + v73_: bool = eq c2_ v70_; + v74_: int = id c4_; + br v73_ .b75_ .b76_; +.b76_: + v77_: bool = eq c4_ v70_; + br v77_ .b78_ .b79_; +.b78_: + v80_: bool = eq c2_ c2_; v81_: int = id v70_; - br v80_ .v82_ .v83_; -.v83_: - v84_: bool = eq v2_ v70_; - br v84_ .v85_ .v86_; -.v85_: - v87_: int = call @fac v2_; - v88_: int = id v2_; -.v89_: + br v80_ .b82_ .b83_; +.b83_: + v84_: bool = eq c2_ v70_; + br v84_ .b85_ .b86_; +.b85_: + v87_: int = call @fac c2_; + v88_: int = id c2_; +.b89_: v81_: int = id v88_; -.v82_: +.b82_: v90_: int = id v70_; -.v91_: +.b91_: v74_: int = id v90_; -.v75_: - v92_: int = id v4_; - br v72_ .v93_ .v94_; -.v94_: - v95_: bool = eq v4_ v71_; - br v95_ .v96_ .v97_; -.v96_: - v98_: bool = eq v2_ v2_; +.b75_: + v92_: int = id c4_; + br v72_ .b93_ .b94_; +.b94_: + v95_: bool = eq c4_ v71_; + br v95_ .b96_ .b97_; +.b96_: + v98_: bool = eq c2_ c2_; v99_: int = id v71_; - br v98_ .v100_ .v101_; -.v101_: - v102_: bool = eq v2_ v71_; - br v102_ .v103_ .v104_; -.v103_: - v105_: int = call @fac v2_; + br v98_ .b100_ .b101_; +.b101_: + v102_: bool = eq c2_ v71_; + br v102_ .b103_ .b104_; +.b103_: + v105_: int = call @fac c2_; v106_: int = id v71_; -.v107_: +.b107_: v99_: int = id v106_; -.v100_: +.b100_: v108_: int = id v71_; -.v109_: +.b109_: v92_: int = id v108_; -.v93_: +.b93_: v110_: int = add v74_ v92_; v30_: int = id v110_; - jmp .v31_; -.v104_: - v111_: int = const -2; - v112_: int = const -1; - v113_: int = call @fac v112_; - v114_: int = call @fac v111_; + jmp .b31_; +.b104_: + c111_: int = const -2; + c112_: int = const -1; + v113_: int = call @fac c112_; + v114_: int = call @fac c111_; v115_: int = add v113_ v114_; v106_: int = id v115_; - jmp .v107_; -.v97_: - v116_: int = sub v71_ v4_; - v117_: int = sub v116_ v4_; - v118_: bool = eq v117_ v2_; - v119_: bool = eq v116_ v2_; - v120_: int = id v4_; - br v119_ .v121_ .v122_; -.v122_: - v123_: bool = eq v116_ v4_; - br v123_ .v124_ .v125_; -.v124_: - v126_: int = call @fac v2_; + jmp .b107_; +.b97_: + v116_: int = sub v71_ c4_; + v117_: int = sub v116_ c4_; + v118_: bool = eq c2_ v117_; + v119_: bool = eq c2_ v116_; + v120_: int = id c4_; + br v119_ .b121_ .b122_; +.b122_: + v123_: bool = eq c4_ v116_; + br v123_ .b124_ .b125_; +.b124_: + v126_: int = call @fac c2_; v127_: int = id v116_; -.v128_: +.b128_: v120_: int = id v127_; -.v121_: - v129_: int = id v4_; - br v118_ .v130_ .v131_; -.v131_: - v132_: bool = eq v117_ v4_; - br v132_ .v133_ .v134_; -.v133_: - v135_: int = call @fac v2_; - v136_: int = id v4_; -.v137_: +.b121_: + v129_: int = id c4_; + br v118_ .b130_ .b131_; +.b131_: + v132_: bool = eq c4_ v117_; + br v132_ .b133_ .b134_; +.b133_: + v135_: int = call @fac c2_; + v136_: int = id c4_; +.b137_: v129_: int = id v136_; -.v130_: +.b130_: v138_: int = add v120_ v129_; v108_: int = id v138_; - jmp .v109_; -.v134_: - v139_: int = sub v117_ v4_; - v140_: int = sub v139_ v4_; + jmp .b109_; +.b134_: + v139_: int = sub v117_ c4_; + v140_: int = sub v139_ c4_; v141_: int = call @fac v139_; v142_: int = call @fac v140_; v143_: int = add v141_ v142_; v136_: int = id v143_; - jmp .v137_; -.v125_: - v144_: int = sub v116_ v4_; - v145_: int = sub v144_ v4_; + jmp .b137_; +.b125_: + v144_: int = sub v116_ c4_; + v145_: int = sub v144_ c4_; v146_: int = call @fac v144_; v147_: int = call @fac v145_; v148_: int = add v146_ v147_; v127_: int = id v148_; - jmp .v128_; -.v86_: - v149_: int = const -2; - v150_: int = const -1; - v151_: int = call @fac v150_; - v152_: int = call @fac v149_; + jmp .b128_; +.b86_: + c149_: int = const -2; + c150_: int = const -1; + v151_: int = call @fac c150_; + v152_: int = call @fac c149_; v153_: int = add v151_ v152_; v88_: int = id v153_; - jmp .v89_; -.v79_: - v154_: int = sub v70_ v4_; - v155_: int = sub v154_ v4_; - v156_: bool = eq v155_ v2_; - v157_: bool = eq v154_ v2_; - v158_: int = id v4_; - br v157_ .v159_ .v160_; -.v160_: - v161_: bool = eq v154_ v4_; - br v161_ .v162_ .v163_; -.v162_: - v164_: int = call @fac v2_; - v165_: int = id v4_; -.v166_: + jmp .b89_; +.b79_: + v154_: int = sub v70_ c4_; + v155_: int = sub v154_ c4_; + v156_: bool = eq c2_ v155_; + v157_: bool = eq c2_ v154_; + v158_: int = id c4_; + br v157_ .b159_ .b160_; +.b160_: + v161_: bool = eq c4_ v154_; + br v161_ .b162_ .b163_; +.b162_: + v164_: int = call @fac c2_; + v165_: int = id c4_; +.b166_: v158_: int = id v165_; -.v159_: - v167_: int = id v4_; - br v156_ .v168_ .v169_; -.v169_: - v170_: bool = eq v155_ v4_; - br v170_ .v171_ .v172_; -.v171_: - v173_: int = call @fac v2_; - v174_: int = id v4_; -.v175_: +.b159_: + v167_: int = id c4_; + br v156_ .b168_ .b169_; +.b169_: + v170_: bool = eq c4_ v155_; + br v170_ .b171_ .b172_; +.b171_: + v173_: int = call @fac c2_; + v174_: int = id c4_; +.b175_: v167_: int = id v174_; -.v168_: +.b168_: v176_: int = add v158_ v167_; v90_: int = id v176_; - jmp .v91_; -.v172_: - v177_: int = sub v155_ v4_; - v178_: int = sub v177_ v4_; + jmp .b91_; +.b172_: + v177_: int = sub v155_ c4_; + v178_: int = sub v177_ c4_; v179_: int = call @fac v177_; v180_: int = call @fac v178_; v181_: int = add v179_ v180_; v174_: int = id v181_; - jmp .v175_; -.v163_: - v182_: int = sub v154_ v4_; - v183_: int = sub v182_ v4_; + jmp .b175_; +.b163_: + v182_: int = sub v154_ c4_; + v183_: int = sub v182_ c4_; v184_: int = call @fac v182_; v185_: int = call @fac v183_; v186_: int = add v184_ v185_; v165_: int = id v186_; - jmp .v166_; -.v6_: + jmp .b166_; +.b6_: ret v5_; } @main { -.v0_: - v1_: int = const 2; - v2_: int = const 0; - v3_: bool = eq v1_ v2_; - v4_: int = const 1; - v5_: int = id v4_; - br v3_ .v6_ .v7_; -.v7_: - v8_: bool = eq v1_ v4_; - br v8_ .v9_ .v10_; -.v9_: - v11_: bool = eq v2_ v2_; - v12_: int = id v4_; - br v11_ .v13_ .v14_; -.v14_: - v15_: bool = eq v2_ v4_; - br v15_ .v16_ .v17_; -.v16_: - v18_: int = call @fac v2_; - v19_: int = id v4_; -.v20_: +.b0_: + c1_: int = const 2; + c2_: int = const 0; + v3_: bool = eq c1_ c2_; + c4_: int = const 1; + v5_: int = id c4_; + br v3_ .b6_ .b7_; +.b7_: + v8_: bool = eq c1_ c4_; + br v8_ .b9_ .b10_; +.b9_: + v11_: bool = eq c2_ c2_; + v12_: int = id c4_; + br v11_ .b13_ .b14_; +.b14_: + v15_: bool = eq c2_ c4_; + br v15_ .b16_ .b17_; +.b16_: + v18_: int = call @fac c2_; + v19_: int = id c4_; +.b20_: v12_: int = id v19_; -.v13_: - v21_: int = id v4_; -.v22_: +.b13_: + v21_: int = id c4_; +.b22_: v5_: int = id v21_; print v5_; ret; -.v17_: - v23_: int = const -1; - v24_: int = sub v23_ v4_; - v25_: int = call @fac v23_; +.b17_: + c23_: int = const -1; + v24_: int = sub c23_ c4_; + v25_: int = call @fac c23_; v26_: int = call @fac v24_; v27_: int = add v25_ v26_; v19_: int = id v27_; - jmp .v20_; -.v10_: - v28_: bool = eq v2_ v2_; - v29_: bool = eq v2_ v4_; - v30_: int = id v4_; - br v29_ .v31_ .v32_; -.v32_: - v33_: bool = eq v4_ v4_; - br v33_ .v34_ .v35_; -.v34_: - v36_: int = call @fac v2_; - v37_: int = id v4_; -.v38_: + jmp .b20_; +.b10_: + v28_: bool = eq c2_ c2_; + v29_: bool = eq c2_ c4_; + v30_: int = id c4_; + br v29_ .b31_ .b32_; +.b32_: + v33_: bool = eq c4_ c4_; + br v33_ .b34_ .b35_; +.b34_: + v36_: int = call @fac c2_; + v37_: int = id c4_; +.b38_: v30_: int = id v37_; -.v31_: - v39_: int = id v4_; - br v28_ .v40_ .v41_; -.v41_: - v42_: bool = eq v2_ v4_; - br v42_ .v43_ .v44_; -.v43_: - v45_: int = call @fac v2_; - v46_: int = id v4_; -.v47_: +.b31_: + v39_: int = id c4_; + br v28_ .b40_ .b41_; +.b41_: + v42_: bool = eq c2_ c4_; + br v42_ .b43_ .b44_; +.b43_: + v45_: int = call @fac c2_; + v46_: int = id c4_; +.b47_: v39_: int = id v46_; -.v40_: +.b40_: v48_: int = add v30_ v39_; v21_: int = id v48_; - jmp .v22_; -.v44_: - v49_: int = const -2; - v50_: int = const -1; - v51_: int = call @fac v50_; - v52_: int = call @fac v49_; + jmp .b22_; +.b44_: + c49_: int = const -2; + c50_: int = const -1; + v51_: int = call @fac c50_; + v52_: int = call @fac c49_; v53_: int = add v51_ v52_; v46_: int = id v53_; - jmp .v47_; -.v35_: - v54_: int = const -1; - v55_: int = call @fac v2_; - v56_: int = call @fac v54_; + jmp .b47_; +.b35_: + c54_: int = const -1; + v55_: int = call @fac c2_; + v56_: int = call @fac c54_; v57_: int = add v55_ v56_; v37_: int = id v57_; - jmp .v38_; -.v6_: + jmp .b38_; +.b6_: print v5_; } diff --git a/tests/snapshots/files__fib_shape-optimize.snap b/tests/snapshots/files__fib_shape-optimize.snap index c6fdc858b..28e318faf 100644 --- a/tests/snapshots/files__fib_shape-optimize.snap +++ b/tests/snapshots/files__fib_shape-optimize.snap @@ -3,28 +3,28 @@ source: tests/files.rs expression: visualization.result --- @main(v0: int) { -.v1_: - v2_: int = const 0; - v3_: int = const 1; - v4_: int = id v2_; - v5_: int = id v3_; +.b1_: + c2_: int = const 0; + c3_: int = const 1; + v4_: int = id c2_; + v5_: int = id c3_; v6_: int = id v0; -.v7_: +.b7_: v8_: bool = lt v4_ v6_; v9_: int = id v4_; v10_: int = id v5_; v11_: int = id v6_; - br v8_ .v12_ .v13_; -.v12_: + br v8_ .b12_ .b13_; +.b12_: v14_: int = add v4_ v5_; v9_: int = id v14_; v10_: int = id v5_; v11_: int = id v6_; -.v13_: +.b13_: v4_: int = id v9_; v5_: int = id v10_; v6_: int = id v11_; - br v8_ .v7_ .v15_; -.v15_: + br v8_ .b7_ .b15_; +.b15_: print v4_; } diff --git a/tests/snapshots/files__five_call_nestings-optimize.snap b/tests/snapshots/files__five_call_nestings-optimize.snap index 099ef3d53..addf5f8d8 100644 --- a/tests/snapshots/files__five_call_nestings-optimize.snap +++ b/tests/snapshots/files__five_call_nestings-optimize.snap @@ -3,25 +3,25 @@ source: tests/files.rs expression: visualization.result --- @one { -.v0_: +.b0_: call @four; } @two { -.v0_: - v1_: int = const 4; - print v1_; +.b0_: + c1_: int = const 4; + print c1_; } @three { -.v0_: - v1_: int = const 4; - print v1_; +.b0_: + c1_: int = const 4; + print c1_; } @four { -.v0_: - v1_: int = const 4; - print v1_; +.b0_: + c1_: int = const 4; + print c1_; } @main { -.v0_: +.b0_: call @three; } diff --git a/tests/snapshots/files__flatten_loop-optimize.snap b/tests/snapshots/files__flatten_loop-optimize.snap index 8bb02d229..f6eccb4d9 100644 --- a/tests/snapshots/files__flatten_loop-optimize.snap +++ b/tests/snapshots/files__flatten_loop-optimize.snap @@ -3,36 +3,36 @@ source: tests/files.rs expression: visualization.result --- @main(v0: int, v1: int) { -.v2_: - v3_: int = const 0; - v4_: int = const 1; - v5_: int = id v3_; - v6_: int = id v4_; +.b2_: + c3_: int = const 0; + c4_: int = const 1; + v5_: int = id c3_; + v6_: int = id c4_; v7_: int = id v1; v8_: int = id v0; -.v9_: +.b9_: v10_: bool = lt v5_ v8_; v11_: int = id v5_; v12_: int = id v6_; v13_: int = id v7_; v14_: int = id v8_; - br v10_ .v15_ .v16_; -.v15_: - v17_: int = const 0; + br v10_ .b15_ .b16_; +.b15_: + c17_: int = const 0; v18_: int = id v5_; v19_: int = id v6_; - v20_: int = id v17_; + v20_: int = id c17_; v21_: int = id v7_; v22_: int = id v8_; -.v23_: +.b23_: v24_: bool = lt v20_ v21_; v25_: int = id v18_; v26_: int = id v19_; v27_: int = id v20_; v28_: int = id v21_; v29_: int = id v22_; - br v24_ .v30_ .v31_; -.v30_: + br v24_ .b30_ .b31_; +.b30_: v32_: int = mul v18_ v21_; v33_: int = add v20_ v32_; print v33_; @@ -42,25 +42,25 @@ expression: visualization.result v27_: int = id v34_; v28_: int = id v21_; v29_: int = id v22_; -.v31_: +.b31_: v18_: int = id v25_; v19_: int = id v26_; v20_: int = id v27_; v21_: int = id v28_; v22_: int = id v29_; - br v24_ .v23_ .v35_; -.v35_: + br v24_ .b23_ .b35_; +.b35_: v36_: int = add v5_ v6_; v11_: int = id v36_; v12_: int = id v6_; v13_: int = id v7_; v14_: int = id v8_; -.v16_: +.b16_: v5_: int = id v11_; v6_: int = id v12_; v7_: int = id v13_; v8_: int = id v14_; - br v10_ .v9_ .v37_; -.v37_: + br v10_ .b9_ .b37_; +.b37_: print v5_; } diff --git a/tests/snapshots/files__four_call_nestings-optimize.snap b/tests/snapshots/files__four_call_nestings-optimize.snap index 3c3b0a5bc..467fe4938 100644 --- a/tests/snapshots/files__four_call_nestings-optimize.snap +++ b/tests/snapshots/files__four_call_nestings-optimize.snap @@ -3,21 +3,21 @@ source: tests/files.rs expression: visualization.result --- @one { -.v0_: - v1_: int = const 3; - print v1_; +.b0_: + c1_: int = const 3; + print c1_; } @two { -.v0_: - v1_: int = const 3; - print v1_; +.b0_: + c1_: int = const 3; + print c1_; } @three { -.v0_: - v1_: int = const 3; - print v1_; +.b0_: + c1_: int = const 3; + print c1_; } @main { -.v0_: +.b0_: call @three; } diff --git a/tests/snapshots/files__gamma_condition_and-optimize.snap b/tests/snapshots/files__gamma_condition_and-optimize.snap index d2fb01cff..587bd7e9e 100644 --- a/tests/snapshots/files__gamma_condition_and-optimize.snap +++ b/tests/snapshots/files__gamma_condition_and-optimize.snap @@ -3,22 +3,22 @@ source: tests/files.rs expression: visualization.result --- @main(v0: int) { -.v1_: - v2_: int = const 0; - v3_: bool = lt v2_ v0; - v4_: bool = lt v0 v2_; - v5_: int = const 1; - v6_: int = const 3; - v7_: int = id v6_; - br v3_ .v8_ .v9_; -.v8_: - v10_: int = const 3; - v11_: int = id v10_; - br v4_ .v12_ .v13_; -.v12_: - v11_: int = id v5_; -.v13_: +.b1_: + c2_: int = const 0; + v3_: bool = lt c2_ v0; + v4_: bool = lt v0 c2_; + c5_: int = const 1; + c6_: int = const 3; + v7_: int = id c6_; + br v3_ .b8_ .b9_; +.b8_: + c10_: int = const 3; + v11_: int = id c10_; + br v4_ .b12_ .b13_; +.b12_: + v11_: int = id c5_; +.b13_: v7_: int = id v11_; -.v9_: +.b9_: print v7_; } diff --git a/tests/snapshots/files__gamma_pull_in-optimize.snap b/tests/snapshots/files__gamma_pull_in-optimize.snap index dc6692046..568e0a3b9 100644 --- a/tests/snapshots/files__gamma_pull_in-optimize.snap +++ b/tests/snapshots/files__gamma_pull_in-optimize.snap @@ -3,16 +3,16 @@ source: tests/files.rs expression: visualization.result --- @main(v0: int) { -.v1_: - v2_: int = const 10; - v3_: bool = lt v0 v2_; - v4_: int = const 3; - v5_: int = id v4_; - br v3_ .v6_ .v7_; -.v6_: - v8_: int = const 2; - v5_: int = id v8_; -.v7_: +.b1_: + c2_: int = const 10; + v3_: bool = lt v0 c2_; + c4_: int = const 3; + v5_: int = id c4_; + br v3_ .b6_ .b7_; +.b6_: + c8_: int = const 2; + v5_: int = id c8_; +.b7_: v9_: int = add v5_ v5_; print v9_; } diff --git a/tests/snapshots/files__if_constant_fold-optimize.snap b/tests/snapshots/files__if_constant_fold-optimize.snap index bbcb07cbd..257db196f 100644 --- a/tests/snapshots/files__if_constant_fold-optimize.snap +++ b/tests/snapshots/files__if_constant_fold-optimize.snap @@ -3,9 +3,9 @@ source: tests/files.rs expression: visualization.result --- @main(v0: int) { -.v1_: - v2_: int = const 6; - v3_: int = const 3; - print v3_; - print v2_; +.b1_: + c2_: int = const 6; + c3_: int = const 3; + print c3_; + print c2_; } diff --git a/tests/snapshots/files__if_constant_fold2-optimize.snap b/tests/snapshots/files__if_constant_fold2-optimize.snap index 5e90f0242..0ccf05a4e 100644 --- a/tests/snapshots/files__if_constant_fold2-optimize.snap +++ b/tests/snapshots/files__if_constant_fold2-optimize.snap @@ -3,21 +3,21 @@ source: tests/files.rs expression: visualization.result --- @main(v0: int) { -.v1_: - v2_: int = const 20; - v3_: int = const 5; - v4_: bool = eq v0 v3_; - v5_: int = const 4; - v6_: int = id v2_; - br v4_ .v7_ .v8_; -.v8_: - v9_: bool = eq v0 v5_; - v10_: int = id v2_; - br v9_ .v11_ .v12_; -.v11_: - v10_: int = id v2_; -.v12_: - v6_: int = id v2_; -.v7_: - print v2_; +.b1_: + c2_: int = const 20; + c3_: int = const 5; + v4_: bool = eq c3_ v0; + c5_: int = const 4; + v6_: int = id c2_; + br v4_ .b7_ .b8_; +.b8_: + v9_: bool = eq c5_ v0; + v10_: int = id c2_; + br v9_ .b11_ .b12_; +.b11_: + v10_: int = id c2_; +.b12_: + v6_: int = id c2_; +.b7_: + print c2_; } diff --git a/tests/snapshots/files__if_context-optimize.snap b/tests/snapshots/files__if_context-optimize.snap index 9cbf293e5..1ec15577f 100644 --- a/tests/snapshots/files__if_context-optimize.snap +++ b/tests/snapshots/files__if_context-optimize.snap @@ -3,18 +3,18 @@ source: tests/files.rs expression: visualization.result --- @main(v0: int) { -.v1_: - v2_: bool = const true; - v3_: int = const 0; - v4_: bool = le v0 v3_; +.b1_: + c2_: bool = const true; + c3_: int = const 0; + v4_: bool = le v0 c3_; v5_: int = id v0; - v6_: int = id v3_; - br v4_ .v7_ .v8_; -.v8_: - v9_: int = const -1; - v10_: int = mul v0 v9_; + v6_: int = id c3_; + br v4_ .b7_ .b8_; +.b8_: + c9_: int = const -1; + v10_: int = mul c9_ v0; v5_: int = id v10_; - v6_: int = id v3_; -.v7_: - print v2_; + v6_: int = id c3_; +.b7_: + print c2_; } diff --git a/tests/snapshots/files__if_dead_code-optimize.snap b/tests/snapshots/files__if_dead_code-optimize.snap index fed962d86..9e9a5a294 100644 --- a/tests/snapshots/files__if_dead_code-optimize.snap +++ b/tests/snapshots/files__if_dead_code-optimize.snap @@ -3,16 +3,16 @@ source: tests/files.rs expression: visualization.result --- @main(v0: int) { -.v1_: - v2_: int = const 0; - v3_: bool = lt v0 v2_; - v4_: int = const 0; - v5_: int = id v4_; - br v3_ .v6_ .v7_; -.v6_: - v8_: int = const 1; - v5_: int = id v8_; -.v7_: +.b1_: + c2_: int = const 0; + v3_: bool = lt v0 c2_; + c4_: int = const 0; + v5_: int = id c4_; + br v3_ .b6_ .b7_; +.b6_: + c8_: int = const 1; + v5_: int = id c8_; +.b7_: print v5_; print v3_; } diff --git a/tests/snapshots/files__if_interval-optimize.snap b/tests/snapshots/files__if_interval-optimize.snap index 29150d300..4fd11f29d 100644 --- a/tests/snapshots/files__if_interval-optimize.snap +++ b/tests/snapshots/files__if_interval-optimize.snap @@ -3,15 +3,15 @@ source: tests/files.rs expression: visualization.result --- @main(v0: int) { -.v1_: - v2_: bool = const true; - v3_: int = const 0; - v4_: bool = le v0 v3_; - v5_: int = const 3; - v6_: int = id v5_; - br v4_ .v7_ .v8_; -.v7_: - v6_: int = id v3_; -.v8_: - print v2_; +.b1_: + c2_: bool = const true; + c3_: int = const 0; + v4_: bool = le v0 c3_; + c5_: int = const 3; + v6_: int = id c5_; + br v4_ .b7_ .b8_; +.b7_: + v6_: int = id c3_; +.b8_: + print c2_; } diff --git a/tests/snapshots/files__implicit-return-optimize.snap b/tests/snapshots/files__implicit-return-optimize.snap index 53ad6fedf..13def91e7 100644 --- a/tests/snapshots/files__implicit-return-optimize.snap +++ b/tests/snapshots/files__implicit-return-optimize.snap @@ -3,69 +3,69 @@ source: tests/files.rs expression: visualization.result --- @pow(v0: int, v1: int) { -.v2_: - v3_: int = const 0; +.b2_: + c3_: int = const 0; v4_: int = id v0; - v5_: int = id v3_; + v5_: int = id c3_; v6_: int = id v0; v7_: int = id v1; -.v8_: - v9_: int = const 1; - v10_: int = sub v7_ v9_; +.b8_: + c9_: int = const 1; + v10_: int = sub v7_ c9_; v11_: bool = lt v5_ v10_; v12_: int = id v4_; v13_: int = id v5_; v14_: int = id v6_; v15_: int = id v7_; - br v11_ .v16_ .v17_; -.v16_: + br v11_ .b16_ .b17_; +.b16_: v18_: int = mul v4_ v6_; - v19_: int = const 1; - v20_: int = add v19_ v5_; + c19_: int = const 1; + v20_: int = add c19_ v5_; v12_: int = id v18_; v13_: int = id v20_; v14_: int = id v6_; v15_: int = id v7_; -.v17_: +.b17_: v4_: int = id v12_; v5_: int = id v13_; v6_: int = id v14_; v7_: int = id v15_; - br v11_ .v8_ .v21_; -.v21_: + br v11_ .b8_ .b21_; +.b21_: print v4_; } @main { -.v0_: - v1_: int = const 4; - v2_: int = const 0; - v3_: int = const 15; - v4_: int = id v1_; - v5_: int = id v2_; - v6_: int = id v1_; - v7_: int = id v3_; -.v8_: - v9_: int = const 14; - v10_: bool = lt v5_ v9_; +.b0_: + c1_: int = const 4; + c2_: int = const 0; + c3_: int = const 15; + v4_: int = id c1_; + v5_: int = id c2_; + v6_: int = id c1_; + v7_: int = id c3_; +.b8_: + c9_: int = const 14; + v10_: bool = lt v5_ c9_; v11_: int = id v4_; v12_: int = id v5_; v13_: int = id v6_; v14_: int = id v7_; - br v10_ .v15_ .v16_; -.v15_: + br v10_ .b15_ .b16_; +.b15_: v17_: int = mul v4_ v6_; - v18_: int = const 1; - v19_: int = add v18_ v5_; + c18_: int = const 1; + v19_: int = add c18_ v5_; v11_: int = id v17_; v12_: int = id v19_; v13_: int = id v6_; v14_: int = id v7_; -.v16_: +.b16_: v4_: int = id v11_; v5_: int = id v12_; v6_: int = id v13_; v7_: int = id v14_; - br v10_ .v8_ .v20_; -.v20_: + br v10_ .b8_ .b20_; +.b20_: print v4_; } diff --git a/tests/snapshots/files__impossible_if-optimize.snap b/tests/snapshots/files__impossible_if-optimize.snap index fd72f3598..f3ebafea2 100644 --- a/tests/snapshots/files__impossible_if-optimize.snap +++ b/tests/snapshots/files__impossible_if-optimize.snap @@ -3,19 +3,19 @@ source: tests/files.rs expression: visualization.result --- @main(v0: int) { -.v1_: - v2_: int = const 1; - v3_: int = const 2; - v4_: bool = lt v0 v3_; - br v4_ .v5_ .v6_; -.v5_: - print v2_; - v7_: int = id v2_; - print v2_; +.b1_: + c2_: int = const 1; + c3_: int = const 2; + v4_: bool = lt v0 c3_; + br v4_ .b5_ .b6_; +.b5_: + print c2_; + v7_: int = id c2_; + print c2_; ret; -.v6_: - print v2_; - v7_: int = id v2_; -.v8_: - print v2_; +.b6_: + print c2_; + v7_: int = id c2_; +.b8_: + print c2_; } diff --git a/tests/snapshots/files__jumping_loop-optimize.snap b/tests/snapshots/files__jumping_loop-optimize.snap index 03867db9c..ef3829b34 100644 --- a/tests/snapshots/files__jumping_loop-optimize.snap +++ b/tests/snapshots/files__jumping_loop-optimize.snap @@ -3,19 +3,19 @@ source: tests/files.rs expression: visualization.result --- @main { -.v0_: - v1_: int = const 0; - v2_: int = const 18; - v3_: int = const 4; - v4_: int = id v1_; - v5_: int = id v2_; - v6_: int = id v3_; -.v7_: +.b0_: + c1_: int = const 0; + c2_: int = const 18; + c3_: int = const 4; + v4_: int = id c1_; + v5_: int = id c2_; + v6_: int = id c3_; +.b7_: v8_: int = add v4_ v6_; v9_: bool = lt v8_ v5_; v4_: int = id v8_; v5_: int = id v5_; v6_: int = id v6_; - br v9_ .v7_ .v10_; -.v10_: + br v9_ .b7_ .b10_; +.b10_: } diff --git a/tests/snapshots/files__loop_hoist-optimize.snap b/tests/snapshots/files__loop_hoist-optimize.snap index a1b35cc94..9096261c8 100644 --- a/tests/snapshots/files__loop_hoist-optimize.snap +++ b/tests/snapshots/files__loop_hoist-optimize.snap @@ -3,26 +3,26 @@ source: tests/files.rs expression: visualization.result --- @main { -.v0_: - v1_: int = const 1; - v2_: int = const 4; - v3_: int = const 3; - v4_: int = const 2; - v5_: int = id v1_; - v6_: int = id v2_; - v7_: int = id v3_; - v8_: int = id v4_; -.v9_: - v10_: int = const 1; - print v10_; - v11_: int = add v10_ v5_; +.b0_: + c1_: int = const 1; + c2_: int = const 4; + c3_: int = const 3; + c4_: int = const 2; + v5_: int = id c1_; + v6_: int = id c2_; + v7_: int = id c3_; + v8_: int = id c4_; +.b9_: + c10_: int = const 1; + print c10_; + v11_: int = add c10_ v5_; v12_: bool = lt v11_ v6_; v13_: bool = not v12_; v5_: int = id v11_; v6_: int = id v6_; v7_: int = id v7_; v8_: int = id v8_; - br v13_ .v9_ .v14_; -.v14_: + br v13_ .b9_ .b14_; +.b14_: print v5_; } diff --git a/tests/snapshots/files__loop_if-optimize.snap b/tests/snapshots/files__loop_if-optimize.snap index 49d6c7952..bbf8b9417 100644 --- a/tests/snapshots/files__loop_if-optimize.snap +++ b/tests/snapshots/files__loop_if-optimize.snap @@ -3,39 +3,39 @@ source: tests/files.rs expression: visualization.result --- @main { -.v0_: - v1_: int = const 0; - v2_: int = id v1_; - v3_: int = id v1_; -.v4_: +.b0_: + c1_: int = const 0; + v2_: int = id c1_; + v3_: int = id c1_; +.b4_: v5_: bool = eq v2_ v3_; v6_: int = id v2_; v7_: bool = id v5_; v8_: int = id v3_; - br v5_ .v9_ .v10_; -.v10_: - v11_: int = const 1; - v12_: int = add v11_ v2_; - v13_: int = add v11_ v3_; + br v5_ .b9_ .b10_; +.b10_: + c11_: int = const 1; + v12_: int = add c11_ v2_; + v13_: int = add c11_ v3_; v6_: int = id v12_; v7_: bool = id v5_; v8_: int = id v13_; -.v9_: - v14_: bool = const true; +.b9_: + c14_: bool = const true; v15_: int = id v6_; - v16_: bool = id v14_; + v16_: bool = id c14_; v17_: int = id v8_; - br v5_ .v18_ .v19_; -.v18_: - v20_: bool = const false; + br v5_ .b18_ .b19_; +.b18_: + c20_: bool = const false; v15_: int = id v6_; - v16_: bool = id v20_; + v16_: bool = id c20_; v17_: int = id v8_; -.v19_: +.b19_: v21_: bool = not v5_; v2_: int = id v6_; v3_: int = id v8_; - br v21_ .v4_ .v22_; -.v22_: + br v21_ .b4_ .b22_; +.b22_: print v2_; } diff --git a/tests/snapshots/files__loop_pass_through-optimize.snap b/tests/snapshots/files__loop_pass_through-optimize.snap index 8df973601..efd0a0164 100644 --- a/tests/snapshots/files__loop_pass_through-optimize.snap +++ b/tests/snapshots/files__loop_pass_through-optimize.snap @@ -3,18 +3,18 @@ source: tests/files.rs expression: visualization.result --- @main(v0: int) { -.v1_: - v2_: int = const 1; - v3_: int = id v2_; +.b1_: + c2_: int = const 1; + v3_: int = id c2_; v4_: int = id v0; -.v5_: +.b5_: v6_: int = add v3_ v3_; - v7_: int = const 10; - v8_: bool = lt v3_ v7_; + c7_: int = const 10; + v8_: bool = lt v3_ c7_; v3_: int = id v6_; v4_: int = id v4_; - br v8_ .v5_ .v9_; -.v9_: + br v8_ .b5_ .b9_; +.b9_: v10_: int = add v0 v3_; print v10_; } diff --git a/tests/snapshots/files__loop_with_mul_by_inv-optimize.snap b/tests/snapshots/files__loop_with_mul_by_inv-optimize.snap index 21dfa2fe9..cf4d4300c 100644 --- a/tests/snapshots/files__loop_with_mul_by_inv-optimize.snap +++ b/tests/snapshots/files__loop_with_mul_by_inv-optimize.snap @@ -3,18 +3,18 @@ source: tests/files.rs expression: visualization.result --- @main(v0: int) { -.v1_: - v2_: int = const 0; - v3_: int = const 5; - v4_: int = id v2_; - v5_: int = id v2_; - v6_: int = id v3_; +.b1_: + c2_: int = const 0; + c3_: int = const 5; + v4_: int = id c2_; + v5_: int = id c2_; + v6_: int = id c3_; v7_: int = id v0; - v8_: int = id v2_; -.v9_: + v8_: int = id c2_; +.b9_: v10_: int = add v4_ v8_; - v11_: int = const 1; - v12_: int = add v11_ v5_; + c11_: int = const 1; + v12_: int = add c11_ v5_; v13_: int = add v6_ v8_; v14_: bool = lt v5_ v7_; v4_: int = id v10_; @@ -22,7 +22,7 @@ expression: visualization.result v6_: int = id v6_; v7_: int = id v7_; v8_: int = id v13_; - br v14_ .v9_ .v15_; -.v15_: + br v14_ .b9_ .b15_; +.b15_: print v4_; } diff --git a/tests/snapshots/files__mem_loop_store_forwarding-optimize.snap b/tests/snapshots/files__mem_loop_store_forwarding-optimize.snap index 4424ca2b5..3607aca2b 100644 --- a/tests/snapshots/files__mem_loop_store_forwarding-optimize.snap +++ b/tests/snapshots/files__mem_loop_store_forwarding-optimize.snap @@ -3,29 +3,29 @@ source: tests/files.rs expression: visualization.result --- @main(v0: bool) { -.v1_: - v2_: int = const 3; - v3_: ptr = alloc v2_; - v4_: int = const 1; - v5_: ptr = ptradd v3_ v4_; - v6_: int = const 2; - v7_: ptr = ptradd v3_ v6_; +.b1_: + c2_: int = const 3; + v3_: ptr = alloc c2_; + c4_: int = const 1; + v5_: ptr = ptradd v3_ c4_; + c6_: int = const 2; + v7_: ptr = ptradd v3_ c6_; v8_: ptr = id v5_; v9_: ptr = id v3_; v10_: ptr = id v7_; v11_: bool = id v0; -.v12_: +.b12_: v8_: ptr = id v9_; v9_: ptr = id v8_; v10_: ptr = id v10_; v11_: bool = id v11_; - br v11_ .v12_ .v13_; -.v13_: - v14_: int = const 10; - v15_: int = const 20; - store v9_ v14_; - store v10_ v15_; + br v11_ .b12_ .b13_; +.b13_: + c14_: int = const 10; + c15_: int = const 20; + store v9_ c14_; + store v10_ c15_; v16_: int = load v9_; - print v14_; + print c14_; free v8_; } diff --git a/tests/snapshots/files__mem_simple_redundant_load-optimize.snap b/tests/snapshots/files__mem_simple_redundant_load-optimize.snap index 07f982a9f..bef49176a 100644 --- a/tests/snapshots/files__mem_simple_redundant_load-optimize.snap +++ b/tests/snapshots/files__mem_simple_redundant_load-optimize.snap @@ -3,24 +3,24 @@ source: tests/files.rs expression: visualization.result --- @main(v0: bool) { -.v1_: - v2_: int = const 1; - v3_: ptr = alloc v2_; - br v0 .v4_ .v5_; -.v4_: - v6_: int = const 2; - store v3_ v6_; +.b1_: + c2_: int = const 1; + v3_: ptr = alloc c2_; + br v0 .b4_ .b5_; +.b4_: + c6_: int = const 2; + store v3_ c6_; v7_: ptr = id v3_; v8_: int = load v3_; v9_: int = load v3_; print v8_; free v3_; ret; -.v5_: - v10_: int = const 3; - store v3_ v10_; +.b5_: + c10_: int = const 3; + store v3_ c10_; v7_: ptr = id v3_; -.v11_: +.b11_: v8_: int = load v3_; v9_: int = load v3_; print v8_; diff --git a/tests/snapshots/files__mem_simple_store_forwarding-optimize.snap b/tests/snapshots/files__mem_simple_store_forwarding-optimize.snap index 6ed994670..56e06754f 100644 --- a/tests/snapshots/files__mem_simple_store_forwarding-optimize.snap +++ b/tests/snapshots/files__mem_simple_store_forwarding-optimize.snap @@ -3,16 +3,16 @@ source: tests/files.rs expression: visualization.result --- @main { -.v0_: - v1_: int = const 2; - v2_: ptr = alloc v1_; - v3_: int = const 10; - v4_: int = const 1; - v5_: ptr = ptradd v2_ v4_; - v6_: int = const 20; - store v2_ v3_; - store v5_ v6_; +.b0_: + c1_: int = const 2; + v2_: ptr = alloc c1_; + c3_: int = const 10; + c4_: int = const 1; + v5_: ptr = ptradd v2_ c4_; + c6_: int = const 20; + store v2_ c3_; + store v5_ c6_; v7_: int = load v2_; - print v3_; + print c3_; free v2_; } diff --git a/tests/snapshots/files__nested_call-optimize.snap b/tests/snapshots/files__nested_call-optimize.snap index d777b1e3b..f45a1c0f5 100644 --- a/tests/snapshots/files__nested_call-optimize.snap +++ b/tests/snapshots/files__nested_call-optimize.snap @@ -3,22 +3,22 @@ source: tests/files.rs expression: visualization.result --- @inc(v0: int): int { -.v1_: - v2_: int = const 1; - v3_: int = add v0 v2_; - v4_: int = const 2; - v5_: int = mul v3_ v4_; +.b1_: + c2_: int = const 1; + v3_: int = add c2_ v0; + c4_: int = const 2; + v5_: int = mul c4_ v3_; ret v5_; } @double(v0: int): int { -.v1_: - v2_: int = const 2; - v3_: int = mul v0 v2_; +.b1_: + c2_: int = const 2; + v3_: int = mul c2_ v0; ret v3_; } @main { -.v0_: - v1_: int = const 2; - print v1_; - print v1_; +.b0_: + c1_: int = const 2; + print c1_; + print c1_; } diff --git a/tests/snapshots/files__peel_twice-optimize.snap b/tests/snapshots/files__peel_twice-optimize.snap index f2691ba96..bf02b33e4 100644 --- a/tests/snapshots/files__peel_twice-optimize.snap +++ b/tests/snapshots/files__peel_twice-optimize.snap @@ -3,7 +3,7 @@ source: tests/files.rs expression: visualization.result --- @main { -.v0_: - v1_: int = const 2; - print v1_; +.b0_: + c1_: int = const 2; + print c1_; } diff --git a/tests/snapshots/files__peel_twice_precalc_pred-optimize.snap b/tests/snapshots/files__peel_twice_precalc_pred-optimize.snap index f2691ba96..bf02b33e4 100644 --- a/tests/snapshots/files__peel_twice_precalc_pred-optimize.snap +++ b/tests/snapshots/files__peel_twice_precalc_pred-optimize.snap @@ -3,7 +3,7 @@ source: tests/files.rs expression: visualization.result --- @main { -.v0_: - v1_: int = const 2; - print v1_; +.b0_: + c1_: int = const 2; + print c1_; } diff --git a/tests/snapshots/files__range_check-optimize.snap b/tests/snapshots/files__range_check-optimize.snap index 59f868ab0..cfecc22af 100644 --- a/tests/snapshots/files__range_check-optimize.snap +++ b/tests/snapshots/files__range_check-optimize.snap @@ -3,34 +3,34 @@ source: tests/files.rs expression: visualization.result --- @main { -.v0_: - v1_: int = const 0; - v2_: int = id v1_; -.v3_: - v4_: int = const 6; - v5_: bool = lt v2_ v4_; - v6_: int = const 5; - v7_: bool = lt v2_ v6_; - br v7_ .v8_ .v9_; -.v8_: - v10_: int = const 1; - print v10_; +.b0_: + c1_: int = const 0; + v2_: int = id c1_; +.b3_: + c4_: int = const 6; + v5_: bool = lt v2_ c4_; + c6_: int = const 5; + v7_: bool = lt v2_ c6_; + br v7_ .b8_ .b9_; +.b8_: + c10_: int = const 1; + print c10_; v11_: int = id v2_; -.v12_: - v13_: int = const 1; - v14_: int = add v13_ v2_; +.b12_: + c13_: int = const 1; + v14_: int = add c13_ v2_; v15_: int = id v14_; - br v5_ .v16_ .v17_; -.v16_: + br v5_ .b16_ .b17_; +.b16_: v15_: int = id v14_; -.v17_: +.b17_: v2_: int = id v15_; - br v5_ .v3_ .v18_; -.v9_: - v19_: int = const 2; - print v19_; + br v5_ .b3_ .b18_; +.b9_: + c19_: int = const 2; + print c19_; v11_: int = id v2_; - jmp .v12_; -.v18_: + jmp .b12_; +.b18_: print v2_; } diff --git a/tests/snapshots/files__range_splitting-optimize.snap b/tests/snapshots/files__range_splitting-optimize.snap index 1e64a449e..156f153b9 100644 --- a/tests/snapshots/files__range_splitting-optimize.snap +++ b/tests/snapshots/files__range_splitting-optimize.snap @@ -3,33 +3,33 @@ source: tests/files.rs expression: visualization.result --- @main { -.v0_: - v1_: int = const 0; - v2_: int = id v1_; -.v3_: - v4_: int = const 1; - v5_: int = add v2_ v4_; - v6_: int = const 5; - v7_: bool = lt v5_ v6_; - v8_: bool = lt v2_ v6_; - br v8_ .v9_ .v10_; -.v9_: - v11_: int = const 1; - print v11_; +.b0_: + c1_: int = const 0; + v2_: int = id c1_; +.b3_: + c4_: int = const 1; + v5_: int = add c4_ v2_; + c6_: int = const 5; + v7_: bool = lt v5_ c6_; + v8_: bool = lt v2_ c6_; + br v8_ .b9_ .b10_; +.b9_: + c11_: int = const 1; + print c11_; v12_: int = id v2_; -.v13_: +.b13_: v14_: int = id v5_; - br v7_ .v15_ .v16_; -.v15_: + br v7_ .b15_ .b16_; +.b15_: v14_: int = id v5_; -.v16_: +.b16_: v2_: int = id v14_; - br v7_ .v3_ .v17_; -.v10_: - v18_: int = const 2; - print v18_; + br v7_ .b3_ .b17_; +.b10_: + c18_: int = const 2; + print c18_; v12_: int = id v2_; - jmp .v13_; -.v17_: + jmp .b13_; +.b17_: print v2_; } diff --git a/tests/snapshots/files__reassoc-optimize.snap b/tests/snapshots/files__reassoc-optimize.snap index e0ef8fc33..505472839 100644 --- a/tests/snapshots/files__reassoc-optimize.snap +++ b/tests/snapshots/files__reassoc-optimize.snap @@ -3,13 +3,13 @@ source: tests/files.rs expression: visualization.result --- @main(v0: int, v1: int) { -.v2_: - v3_: int = const 1; - v4_: int = const 4; - v5_: int = add v1 v4_; - v6_: int = const 3; - v7_: int = add v0 v6_; +.b2_: + c3_: int = const 1; + c4_: int = const 4; + v5_: int = add c4_ v1; + c6_: int = const 3; + v7_: int = add c6_ v0; v8_: int = add v5_ v7_; - v9_: int = add v3_ v8_; + v9_: int = add c3_ v8_; print v9_; } diff --git a/tests/snapshots/files__recurse_once-optimize.snap b/tests/snapshots/files__recurse_once-optimize.snap index 5f46c84d7..095b6cb89 100644 --- a/tests/snapshots/files__recurse_once-optimize.snap +++ b/tests/snapshots/files__recurse_once-optimize.snap @@ -3,39 +3,39 @@ source: tests/files.rs expression: visualization.result --- @to_zero(v0: int): int { -.v1_: - v2_: int = const 0; - v3_: bool = lt v2_ v0; +.b1_: + c2_: int = const 0; + v3_: bool = lt c2_ v0; v4_: int = id v0; - br v3_ .v5_ .v6_; -.v5_: - v7_: int = const 0; - v8_: int = const 1; - v9_: int = sub v0 v8_; - v10_: bool = lt v7_ v9_; + br v3_ .b5_ .b6_; +.b5_: + c7_: int = const 0; + c8_: int = const 1; + v9_: int = sub v0 c8_; + v10_: bool = lt c7_ v9_; v11_: int = id v9_; - br v10_ .v12_ .v13_; -.v12_: - v14_: int = const 0; - v15_: int = const 1; - v16_: int = sub v9_ v15_; - v17_: bool = lt v14_ v16_; + br v10_ .b12_ .b13_; +.b12_: + c14_: int = const 0; + c15_: int = const 1; + v16_: int = sub v9_ c15_; + v17_: bool = lt c14_ v16_; v18_: int = id v16_; - br v17_ .v19_ .v20_; -.v19_: - v21_: int = const 1; - v22_: int = sub v16_ v21_; + br v17_ .b19_ .b20_; +.b19_: + c21_: int = const 1; + v22_: int = sub v16_ c21_; v23_: int = call @to_zero v22_; v18_: int = id v23_; -.v20_: +.b20_: v11_: int = id v18_; -.v13_: +.b13_: v4_: int = id v11_; -.v6_: +.b6_: ret v4_; } @main { -.v0_: - v1_: int = const 0; - print v1_; +.b0_: + c1_: int = const 0; + print c1_; } diff --git a/tests/snapshots/files__simple-call-optimize.snap b/tests/snapshots/files__simple-call-optimize.snap index a8eb698f7..52bd492cf 100644 --- a/tests/snapshots/files__simple-call-optimize.snap +++ b/tests/snapshots/files__simple-call-optimize.snap @@ -3,13 +3,13 @@ source: tests/files.rs expression: visualization.result --- @inc(v0: int): int { -.v1_: - v2_: int = const 1; - v3_: int = add v0 v2_; +.b1_: + c2_: int = const 1; + v3_: int = add c2_ v0; ret v3_; } @main { -.v0_: - v1_: int = const 1; - print v1_; +.b0_: + c1_: int = const 1; + print c1_; } diff --git a/tests/snapshots/files__simple_branch-optimize.snap b/tests/snapshots/files__simple_branch-optimize.snap index d08d85a7d..f282440eb 100644 --- a/tests/snapshots/files__simple_branch-optimize.snap +++ b/tests/snapshots/files__simple_branch-optimize.snap @@ -3,15 +3,15 @@ source: tests/files.rs expression: visualization.result --- @main(v0: int) { -.v1_: - v2_: int = const 0; - v3_: bool = lt v0 v2_; - v4_: int = const 0; - v5_: int = id v4_; - br v3_ .v6_ .v7_; -.v6_: - v8_: int = const 1; - v5_: int = id v8_; -.v7_: +.b1_: + c2_: int = const 0; + v3_: bool = lt v0 c2_; + c4_: int = const 0; + v5_: int = id c4_; + br v3_ .b6_ .b7_; +.b6_: + c8_: int = const 1; + v5_: int = id c8_; +.b7_: print v5_; } diff --git a/tests/snapshots/files__simple_call-optimize.snap b/tests/snapshots/files__simple_call-optimize.snap index 0da2d197d..f390f720b 100644 --- a/tests/snapshots/files__simple_call-optimize.snap +++ b/tests/snapshots/files__simple_call-optimize.snap @@ -3,13 +3,13 @@ source: tests/files.rs expression: visualization.result --- @inc(v0: int) { -.v1_: - v2_: int = const 1; - v3_: int = add v0 v2_; +.b1_: + c2_: int = const 1; + v3_: int = add c2_ v0; print v3_; } @main { -.v0_: - v1_: int = const 1; - print v1_; +.b0_: + c1_: int = const 1; + print c1_; } diff --git a/tests/snapshots/files__simple_loop-optimize.snap b/tests/snapshots/files__simple_loop-optimize.snap index 08f616927..97630776e 100644 --- a/tests/snapshots/files__simple_loop-optimize.snap +++ b/tests/snapshots/files__simple_loop-optimize.snap @@ -3,7 +3,7 @@ source: tests/files.rs expression: visualization.result --- @main { -.v0_: - v1_: int = const 0; - print v1_; +.b0_: + c1_: int = const 0; + print c1_; } diff --git a/tests/snapshots/files__simple_loop_swap-optimize.snap b/tests/snapshots/files__simple_loop_swap-optimize.snap index 6ed994670..56e06754f 100644 --- a/tests/snapshots/files__simple_loop_swap-optimize.snap +++ b/tests/snapshots/files__simple_loop_swap-optimize.snap @@ -3,16 +3,16 @@ source: tests/files.rs expression: visualization.result --- @main { -.v0_: - v1_: int = const 2; - v2_: ptr = alloc v1_; - v3_: int = const 10; - v4_: int = const 1; - v5_: ptr = ptradd v2_ v4_; - v6_: int = const 20; - store v2_ v3_; - store v5_ v6_; +.b0_: + c1_: int = const 2; + v2_: ptr = alloc c1_; + c3_: int = const 10; + c4_: int = const 1; + v5_: ptr = ptradd v2_ c4_; + c6_: int = const 20; + store v2_ c3_; + store v5_ c6_; v7_: int = load v2_; - print v3_; + print c3_; free v2_; } diff --git a/tests/snapshots/files__simple_recursive-optimize.snap b/tests/snapshots/files__simple_recursive-optimize.snap index cc846abe5..7a0b2aba6 100644 --- a/tests/snapshots/files__simple_recursive-optimize.snap +++ b/tests/snapshots/files__simple_recursive-optimize.snap @@ -3,46 +3,46 @@ source: tests/files.rs expression: visualization.result --- @inc(v0: int): int { -.v1_: - v2_: int = const 2; - v3_: bool = lt v0 v2_; +.b1_: + c2_: int = const 2; + v3_: bool = lt v0 c2_; v4_: int = id v0; - br v3_ .v5_ .v6_; -.v5_: - v7_: int = const 1; - v8_: int = add v0 v7_; - v9_: int = const 2; - v10_: bool = lt v8_ v9_; + br v3_ .b5_ .b6_; +.b5_: + c7_: int = const 1; + v8_: int = add c7_ v0; + c9_: int = const 2; + v10_: bool = lt v8_ c9_; print v8_; v11_: int = id v8_; - br v10_ .v12_ .v13_; -.v12_: - v14_: int = const 1; - v15_: int = add v14_ v8_; - v16_: int = const 2; - v17_: bool = lt v15_ v16_; + br v10_ .b12_ .b13_; +.b12_: + c14_: int = const 1; + v15_: int = add c14_ v8_; + c16_: int = const 2; + v17_: bool = lt v15_ c16_; print v15_; v18_: int = id v15_; - br v17_ .v19_ .v20_; -.v19_: - v21_: int = const 1; - v22_: int = add v15_ v21_; + br v17_ .b19_ .b20_; +.b19_: + c21_: int = const 1; + v22_: int = add c21_ v15_; print v22_; v23_: int = call @inc v22_; v18_: int = id v23_; -.v20_: +.b20_: v11_: int = id v18_; -.v13_: +.b13_: v4_: int = id v11_; -.v6_: +.b6_: ret v4_; } @main { -.v0_: - v1_: int = const 2; - v2_: int = const 1; - print v2_; - print v1_; - v3_: int = call @inc v1_; +.b0_: + c1_: int = const 2; + c2_: int = const 1; + print c2_; + print c1_; + v3_: int = call @inc c1_; print v3_; } diff --git a/tests/snapshots/files__simplest_loop-optimize.snap b/tests/snapshots/files__simplest_loop-optimize.snap index b1a6cd2c5..a539c7461 100644 --- a/tests/snapshots/files__simplest_loop-optimize.snap +++ b/tests/snapshots/files__simplest_loop-optimize.snap @@ -3,19 +3,19 @@ source: tests/files.rs expression: visualization.result --- @main { -.v0_: - v1_: int = const 0; - v2_: int = const 5; - v3_: int = const 1; - v4_: int = id v1_; - v5_: int = id v2_; - v6_: int = id v3_; -.v7_: +.b0_: + c1_: int = const 0; + c2_: int = const 5; + c3_: int = const 1; + v4_: int = id c1_; + v5_: int = id c2_; + v6_: int = id c3_; +.b7_: v8_: int = add v4_ v6_; v9_: bool = lt v8_ v5_; v4_: int = id v8_; v5_: int = id v5_; v6_: int = id v6_; - br v9_ .v7_ .v10_; -.v10_: + br v9_ .b7_ .b10_; +.b10_: } diff --git a/tests/snapshots/files__small-collatz-optimize.snap b/tests/snapshots/files__small-collatz-optimize.snap index 53118761e..eafb1f0c9 100644 --- a/tests/snapshots/files__small-collatz-optimize.snap +++ b/tests/snapshots/files__small-collatz-optimize.snap @@ -3,55 +3,55 @@ source: tests/files.rs expression: visualization.result --- @main(v0: int) { -.v1_: - v2_: int = const 0; - v3_: int = const 2; - v4_: int = const 1; - v5_: int = const 3; - v6_: int = id v2_; +.b1_: + c2_: int = const 0; + c3_: int = const 2; + c4_: int = const 1; + c5_: int = const 3; + v6_: int = id c2_; v7_: int = id v0; - v8_: int = id v3_; - v9_: int = id v4_; - v10_: int = id v5_; - v11_: int = id v2_; -.v12_: + v8_: int = id c3_; + v9_: int = id c4_; + v10_: int = id c5_; + v11_: int = id c2_; +.b12_: v13_: bool = eq v7_ v9_; - v14_: bool = const false; + c14_: bool = const false; v15_: int = id v6_; - v16_: bool = id v14_; + v16_: bool = id c14_; v17_: int = id v9_; v18_: int = id v8_; v19_: int = id v9_; v20_: int = id v10_; v21_: int = id v11_; - br v13_ .v22_ .v23_; -.v23_: + br v13_ .b22_ .b23_; +.b23_: v24_: int = div v7_ v8_; v25_: int = mul v24_ v8_; v26_: int = sub v7_ v25_; v27_: bool = eq v11_ v26_; v28_: int = add v6_ v9_; - br v27_ .v29_ .v30_; -.v29_: - v31_: bool = const true; + br v27_ .b29_ .b30_; +.b29_: + c31_: bool = const true; v32_: int = div v7_ v8_; v33_: int = id v28_; - v34_: bool = id v31_; + v34_: bool = id c31_; v35_: int = id v32_; v36_: int = id v8_; v37_: int = id v9_; v38_: int = id v10_; v39_: int = id v11_; -.v40_: - v41_: bool = const true; +.b40_: + c41_: bool = const true; v15_: int = id v28_; - v16_: bool = id v41_; + v16_: bool = id c41_; v17_: int = id v35_; v18_: int = id v8_; v19_: int = id v9_; v20_: int = id v10_; v21_: int = id v11_; -.v22_: +.b22_: v42_: bool = not v13_; v6_: int = id v15_; v7_: int = id v17_; @@ -59,19 +59,19 @@ expression: visualization.result v9_: int = id v9_; v10_: int = id v10_; v11_: int = id v11_; - br v42_ .v12_ .v43_; -.v30_: - v44_: bool = const true; + br v42_ .b12_ .b43_; +.b30_: + c44_: bool = const true; v45_: int = mul v10_ v7_; v46_: int = add v45_ v9_; v33_: int = id v28_; - v34_: bool = id v44_; + v34_: bool = id c44_; v35_: int = id v46_; v36_: int = id v8_; v37_: int = id v9_; v38_: int = id v10_; v39_: int = id v11_; - jmp .v40_; -.v43_: + jmp .b40_; +.b43_: print v6_; } diff --git a/tests/snapshots/files__small-fib-optimize.snap b/tests/snapshots/files__small-fib-optimize.snap index b350d3e56..6899c481e 100644 --- a/tests/snapshots/files__small-fib-optimize.snap +++ b/tests/snapshots/files__small-fib-optimize.snap @@ -3,39 +3,39 @@ source: tests/files.rs expression: visualization.result --- @main(v0: int) { -.v1_: - v2_: int = const 0; - v3_: bool = eq v0 v2_; - v4_: int = const 1; - print v4_; - br v3_ .v5_ .v6_; -.v6_: - print v4_; - v7_: int = id v4_; - v8_: int = id v4_; - v9_: int = id v4_; +.b1_: + c2_: int = const 0; + v3_: bool = eq c2_ v0; + c4_: int = const 1; + print c4_; + br v3_ .b5_ .b6_; +.b6_: + print c4_; + v7_: int = id c4_; + v8_: int = id c4_; + v9_: int = id c4_; v10_: int = id v0; -.v11_: +.b11_: v12_: bool = lt v7_ v10_; v13_: int = id v7_; v14_: int = id v8_; v15_: int = id v9_; v16_: int = id v10_; - br v12_ .v17_ .v18_; -.v17_: + br v12_ .b17_ .b18_; +.b17_: v19_: int = add v8_ v9_; print v19_; - v20_: int = const 1; - v21_: int = add v20_ v7_; + c20_: int = const 1; + v21_: int = add c20_ v7_; v13_: int = id v21_; v14_: int = id v19_; v15_: int = id v8_; v16_: int = id v10_; -.v18_: +.b18_: v7_: int = id v13_; v8_: int = id v14_; v9_: int = id v15_; v10_: int = id v16_; - br v12_ .v11_ .v5_; -.v5_: + br v12_ .b11_ .b5_; +.b5_: } diff --git a/tests/snapshots/files__sqrt-optimize.snap b/tests/snapshots/files__sqrt-optimize.snap index ad9335e24..e43913c9a 100644 --- a/tests/snapshots/files__sqrt-optimize.snap +++ b/tests/snapshots/files__sqrt-optimize.snap @@ -3,35 +3,35 @@ source: tests/files.rs expression: visualization.result --- @main(v0: float) { -.v1_: - v2_: float = const 0; - v3_: bool = feq v0 v2_; - br v3_ .v4_ .v5_; -.v4_: - print v2_; +.b1_: + c2_: float = const 0; + v3_: bool = feq v0 c2_; + br v3_ .b4_ .b5_; +.b4_: + print c2_; ret; -.v5_: +.b5_: v6_: bool = feq v0 v0; - v7_: bool = const true; - v8_: float = id v2_; - v9_: bool = id v7_; - br v6_ .v10_ .v11_; -.v10_: - v12_: bool = flt v0 v2_; - v13_: float = id v2_; - br v12_ .v14_ .v15_; -.v15_: - v16_: float = const 1; - v17_: float = const 1.0000000001; - v18_: float = const 0.9999999999; - v19_: float = const 2; - v20_: float = id v2_; - v21_: float = id v16_; - v22_: float = id v17_; - v23_: float = id v18_; - v24_: float = id v19_; + c7_: bool = const true; + v8_: float = id c2_; + v9_: bool = id c7_; + br v6_ .b10_ .b11_; +.b10_: + v12_: bool = flt v0 c2_; + v13_: float = id c2_; + br v12_ .b14_ .b15_; +.b15_: + c16_: float = const 1; + c17_: float = const 1.0000000001; + c18_: float = const 0.9999999999; + c19_: float = const 2; + v20_: float = id c2_; + v21_: float = id c16_; + v22_: float = id c17_; + v23_: float = id c18_; + v24_: float = id c19_; v25_: float = id v0; -.v26_: +.b26_: v27_: float = fdiv v25_ v21_; v28_: float = fadd v21_ v27_; v29_: float = fdiv v28_ v24_; @@ -39,25 +39,25 @@ expression: visualization.result v31_: bool = fle v30_ v22_; v32_: bool = fge v30_ v23_; v33_: bool = and v31_ v32_; - v34_: bool = const true; + c34_: bool = const true; v35_: float = id v20_; v36_: float = id v29_; - v37_: bool = id v34_; + v37_: bool = id c34_; v38_: float = id v22_; v39_: float = id v23_; v40_: float = id v24_; v41_: float = id v25_; - br v33_ .v42_ .v43_; -.v42_: - v44_: bool = const false; + br v33_ .b42_ .b43_; +.b42_: + c44_: bool = const false; v35_: float = id v20_; v36_: float = id v29_; - v37_: bool = id v44_; + v37_: bool = id c44_; v38_: float = id v22_; v39_: float = id v23_; v40_: float = id v24_; v41_: float = id v25_; -.v43_: +.b43_: v45_: bool = not v33_; v20_: float = id v20_; v21_: float = id v29_; @@ -65,18 +65,18 @@ expression: visualization.result v23_: float = id v23_; v24_: float = id v24_; v25_: float = id v25_; - br v45_ .v26_ .v46_; -.v46_: + br v45_ .b26_ .b46_; +.b46_: print v21_; v13_: float = id v20_; -.v14_: +.b14_: v8_: float = id v13_; v9_: bool = id v12_; -.v11_: - br v9_ .v47_ .v48_; -.v47_: +.b11_: + br v9_ .b47_ .b48_; +.b47_: v49_: float = fdiv v8_ v8_; print v49_; -.v48_: -.v50_: +.b48_: +.b50_: } diff --git a/tests/snapshots/files__strong_loop-optimize.snap b/tests/snapshots/files__strong_loop-optimize.snap index afe95a437..f51f71ccf 100644 --- a/tests/snapshots/files__strong_loop-optimize.snap +++ b/tests/snapshots/files__strong_loop-optimize.snap @@ -3,31 +3,31 @@ source: tests/files.rs expression: visualization.result --- @main(v0: int) { -.v1_: - v2_: int = const 3; - v3_: int = add v0 v2_; - v4_: int = const 0; - v5_: int = const 21; - v6_: int = id v2_; +.b1_: + c2_: int = const 3; + v3_: int = add c2_ v0; + c4_: int = const 0; + c5_: int = const 21; + v6_: int = id c2_; v7_: int = id v3_; - v8_: int = id v4_; + v8_: int = id c4_; v9_: int = id v0; - v10_: int = id v5_; -.v11_: + v10_: int = id c5_; +.b11_: print v10_; - v12_: int = const 1; - v13_: int = add v12_ v6_; + c12_: int = const 1; + v13_: int = add c12_ v6_; v14_: int = add v10_ v8_; - v15_: int = const 7; - v16_: int = add v10_ v15_; + c15_: int = const 7; + v16_: int = add c15_ v10_; v17_: bool = lt v6_ v9_; v6_: int = id v13_; v7_: int = id v7_; v8_: int = id v14_; v9_: int = id v9_; v10_: int = id v16_; - br v17_ .v11_ .v18_; -.v18_: + br v17_ .b11_ .b18_; +.b18_: print v8_; print v3_; print v6_; diff --git a/tests/snapshots/files__two_fns-optimize.snap b/tests/snapshots/files__two_fns-optimize.snap index d2d20fb74..32fee4b71 100644 --- a/tests/snapshots/files__two_fns-optimize.snap +++ b/tests/snapshots/files__two_fns-optimize.snap @@ -3,12 +3,12 @@ source: tests/files.rs expression: visualization.result --- @sub: int { -.v0_: - v1_: int = const -1; - ret v1_; +.b0_: + c1_: int = const -1; + ret c1_; } @main { -.v0_: - v1_: int = const 3; - print v1_; +.b0_: + c1_: int = const 3; + print c1_; } diff --git a/tests/snapshots/files__unroll_and_constant_fold-optimize.snap b/tests/snapshots/files__unroll_and_constant_fold-optimize.snap index 8449ee79a..0020317f3 100644 --- a/tests/snapshots/files__unroll_and_constant_fold-optimize.snap +++ b/tests/snapshots/files__unroll_and_constant_fold-optimize.snap @@ -3,7 +3,7 @@ source: tests/files.rs expression: visualization.result --- @main { -.v0_: - v1_: int = const 1; - print v1_; +.b0_: + c1_: int = const 1; + print c1_; } diff --git a/tests/snapshots/files__unroll_multiple_4-optimize.snap b/tests/snapshots/files__unroll_multiple_4-optimize.snap index e338c81fa..aca316d41 100644 --- a/tests/snapshots/files__unroll_multiple_4-optimize.snap +++ b/tests/snapshots/files__unroll_multiple_4-optimize.snap @@ -3,14 +3,14 @@ source: tests/files.rs expression: visualization.result --- @main { -.v0_: - v1_: int = const 0; - v2_: int = const 16; - v3_: int = const 1; - v4_: int = id v1_; - v5_: int = id v2_; - v6_: int = id v3_; -.v7_: +.b0_: + c1_: int = const 0; + c2_: int = const 16; + c3_: int = const 1; + v4_: int = id c1_; + v5_: int = id c2_; + v6_: int = id c3_; +.b7_: v8_: int = add v4_ v6_; v9_: int = add v6_ v8_; v10_: int = add v6_ v9_; @@ -19,7 +19,7 @@ expression: visualization.result v4_: int = id v11_; v5_: int = id v5_; v6_: int = id v6_; - br v12_ .v7_ .v13_; -.v13_: + br v12_ .b7_ .b13_; +.b13_: print v4_; } From 648df416b9b1f8f3bf2da3c2e13e517bfb4339d4 Mon Sep 17 00:00:00 2001 From: Anjali Pal Date: Wed, 29 May 2024 13:02:02 -0700 Subject: [PATCH 42/47] snapshots --- ...ollatz_redundant_computation-optimize.snap | 4 +- .../files__fib_recursive-optimize.snap | 46 +++++++++---------- .../files__gamma_condition_and-optimize.snap | 4 +- .../snapshots/files__if_context-optimize.snap | 21 +++++---- .../files__if_interval-optimize.snap | 15 +++--- tests/snapshots/files__reassoc-optimize.snap | 8 ++-- 6 files changed, 50 insertions(+), 48 deletions(-) diff --git a/tests/snapshots/files__collatz_redundant_computation-optimize.snap b/tests/snapshots/files__collatz_redundant_computation-optimize.snap index 80ca1983d..acd19c5d7 100644 --- a/tests/snapshots/files__collatz_redundant_computation-optimize.snap +++ b/tests/snapshots/files__collatz_redundant_computation-optimize.snap @@ -19,8 +19,8 @@ expression: visualization.result c14_: bool = const false; v15_: int = id v6_; v16_: bool = id c14_; - v17_: int = id v7_; - v18_: int = id v7_; + v17_: int = id v8_; + v18_: int = id v8_; v19_: int = id v9_; v20_: int = id v10_; v21_: int = id v11_; diff --git a/tests/snapshots/files__fib_recursive-optimize.snap b/tests/snapshots/files__fib_recursive-optimize.snap index 248e01f79..6266f3b18 100644 --- a/tests/snapshots/files__fib_recursive-optimize.snap +++ b/tests/snapshots/files__fib_recursive-optimize.snap @@ -14,35 +14,35 @@ expression: visualization.result br v8_ .b9_ .b10_; .b9_: v11_: bool = eq c2_ c2_; - v12_: int = id c4_; + v12_: int = id v0; br v11_ .b13_ .b14_; .b14_: - v15_: bool = eq c2_ c4_; + v15_: bool = eq c2_ v0; br v15_ .b16_ .b17_; .b16_: v18_: bool = eq c2_ c2_; - v19_: int = id c4_; + v19_: int = id c2_; br v18_ .b20_ .b21_; .b21_: - v22_: bool = eq c2_ c4_; + v22_: bool = eq c2_ c2_; br v22_ .b23_ .b24_; .b23_: v25_: int = call @fac c2_; - v26_: int = id c4_; + v26_: int = id c2_; .b27_: v19_: int = id v26_; .b20_: - v28_: int = id c4_; + v28_: int = id c2_; .b29_: v12_: int = id v28_; .b13_: - v30_: int = id c4_; + v30_: int = id v0; .b31_: v5_: int = id v30_; ret v5_; .b24_: c32_: int = const -1; - v33_: int = sub c32_ c4_; + v33_: int = sub c32_ c2_; v34_: int = call @fac c32_; v35_: int = call @fac v33_; v36_: int = add v34_ v35_; @@ -53,25 +53,25 @@ expression: visualization.result v38_: bool = eq c2_ c37_; c39_: int = const -1; v40_: bool = eq c2_ c39_; - v41_: int = id c4_; + v41_: int = id v0; br v40_ .b42_ .b43_; .b43_: - v44_: bool = eq c39_ c4_; + v44_: bool = eq c39_ v0; br v44_ .b45_ .b46_; .b45_: v47_: int = call @fac c2_; - v48_: int = id c4_; + v48_: int = id c39_; .b49_: v41_: int = id v48_; .b42_: - v50_: int = id c4_; + v50_: int = id v0; br v38_ .b51_ .b52_; .b52_: - v53_: bool = eq c37_ c4_; + v53_: bool = eq c37_ v0; br v53_ .b54_ .b55_; .b54_: v56_: int = call @fac c2_; - v57_: int = id c4_; + v57_: int = id v0; .b58_: v50_: int = id v57_; .b51_: @@ -135,7 +135,7 @@ expression: visualization.result br v102_ .b103_ .b104_; .b103_: v105_: int = call @fac c2_; - v106_: int = id v71_; + v106_: int = id c2_; .b107_: v99_: int = id v106_; .b100_: @@ -166,7 +166,7 @@ expression: visualization.result br v123_ .b124_ .b125_; .b124_: v126_: int = call @fac c2_; - v127_: int = id v116_; + v127_: int = id c4_; .b128_: v120_: int = id v127_; .b121_: @@ -220,7 +220,7 @@ expression: visualization.result br v161_ .b162_ .b163_; .b162_: v164_: int = call @fac c2_; - v165_: int = id c4_; + v165_: int = id v154_; .b166_: v158_: int = id v165_; .b159_: @@ -270,25 +270,25 @@ expression: visualization.result br v8_ .b9_ .b10_; .b9_: v11_: bool = eq c2_ c2_; - v12_: int = id c4_; + v12_: int = id c1_; br v11_ .b13_ .b14_; .b14_: - v15_: bool = eq c2_ c4_; + v15_: bool = eq c1_ c2_; br v15_ .b16_ .b17_; .b16_: v18_: int = call @fac c2_; - v19_: int = id c4_; + v19_: int = id c1_; .b20_: v12_: int = id v19_; .b13_: - v21_: int = id c4_; + v21_: int = id c1_; .b22_: v5_: int = id v21_; print v5_; ret; .b17_: c23_: int = const -1; - v24_: int = sub c23_ c4_; + v24_: int = sub c23_ c1_; v25_: int = call @fac c23_; v26_: int = call @fac v24_; v27_: int = add v25_ v26_; @@ -315,7 +315,7 @@ expression: visualization.result br v42_ .b43_ .b44_; .b43_: v45_: int = call @fac c2_; - v46_: int = id c4_; + v46_: int = id c2_; .b47_: v39_: int = id v46_; .b40_: diff --git a/tests/snapshots/files__gamma_condition_and-optimize.snap b/tests/snapshots/files__gamma_condition_and-optimize.snap index 587bd7e9e..7c5c9df1f 100644 --- a/tests/snapshots/files__gamma_condition_and-optimize.snap +++ b/tests/snapshots/files__gamma_condition_and-optimize.snap @@ -5,8 +5,8 @@ expression: visualization.result @main(v0: int) { .b1_: c2_: int = const 0; - v3_: bool = lt c2_ v0; - v4_: bool = lt v0 c2_; + v3_: bool = lt v0 c2_; + v4_: bool = gt v0 c2_; c5_: int = const 1; c6_: int = const 3; v7_: int = id c6_; diff --git a/tests/snapshots/files__if_context-optimize.snap b/tests/snapshots/files__if_context-optimize.snap index 1ec15577f..ed9361eee 100644 --- a/tests/snapshots/files__if_context-optimize.snap +++ b/tests/snapshots/files__if_context-optimize.snap @@ -5,16 +5,17 @@ expression: visualization.result @main(v0: int) { .b1_: c2_: bool = const true; - c3_: int = const 0; - v4_: bool = le v0 c3_; - v5_: int = id v0; - v6_: int = id c3_; - br v4_ .b7_ .b8_; + c3_: int = const 1; + v4_: bool = lt v0 c3_; + c5_: int = const 0; + v6_: int = id v0; + v7_: int = id c5_; + br v4_ .b8_ .b9_; +.b9_: + c10_: int = const -1; + v11_: int = mul c10_ v0; + v6_: int = id v11_; + v7_: int = id c5_; .b8_: - c9_: int = const -1; - v10_: int = mul c9_ v0; - v5_: int = id v10_; - v6_: int = id c3_; -.b7_: print c2_; } diff --git a/tests/snapshots/files__if_interval-optimize.snap b/tests/snapshots/files__if_interval-optimize.snap index 4fd11f29d..39cb07d09 100644 --- a/tests/snapshots/files__if_interval-optimize.snap +++ b/tests/snapshots/files__if_interval-optimize.snap @@ -5,13 +5,14 @@ expression: visualization.result @main(v0: int) { .b1_: c2_: bool = const true; - c3_: int = const 0; - v4_: bool = le v0 c3_; - c5_: int = const 3; - v6_: int = id c5_; - br v4_ .b7_ .b8_; -.b7_: - v6_: int = id c3_; + c3_: int = const 1; + v4_: bool = lt v0 c3_; + c5_: int = const 0; + c6_: int = const 3; + v7_: int = id c6_; + br v4_ .b8_ .b9_; .b8_: + v7_: int = id c5_; +.b9_: print c2_; } diff --git a/tests/snapshots/files__reassoc-optimize.snap b/tests/snapshots/files__reassoc-optimize.snap index 505472839..8066f2b27 100644 --- a/tests/snapshots/files__reassoc-optimize.snap +++ b/tests/snapshots/files__reassoc-optimize.snap @@ -5,10 +5,10 @@ expression: visualization.result @main(v0: int, v1: int) { .b2_: c3_: int = const 1; - c4_: int = const 4; - v5_: int = add c4_ v1; - c6_: int = const 3; - v7_: int = add c6_ v0; + c4_: int = const 3; + v5_: int = add c4_ v0; + c6_: int = const 4; + v7_: int = add c6_ v1; v8_: int = add v5_ v7_; v9_: int = add c3_ v8_; print v9_; From fa073ba3d0d8b46be42bbc609e2cafd812c9f0f8 Mon Sep 17 00:00:00 2001 From: Kirsten <32720576+kirstenmg@users.noreply.github.com> Date: Wed, 29 May 2024 15:08:14 -0700 Subject: [PATCH 43/47] Add type helper error checking --- dag_in_context/src/utility/canonicalize.egg | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/dag_in_context/src/utility/canonicalize.egg b/dag_in_context/src/utility/canonicalize.egg index 32a1fac84..eaa86d5d0 100644 --- a/dag_in_context/src/utility/canonicalize.egg +++ b/dag_in_context/src/utility/canonicalize.egg @@ -71,17 +71,24 @@ ; Helper functions to remove one element from a tuple or type list ; tuple idx (function TupleRemoveAt (Expr i64) Expr :unextractable) -(function TypeListRemoveAt (TypeList i64) TypeList :unextractable) - (rewrite (TupleRemoveAt tuple idx) (Concat (SubTuple tuple 0 idx) (SubTuple tuple (+ idx 1) (- len (+ idx 1)))) :when ((= len (tuple-length tuple))) :ruleset always-run) +(rule ((TupleRemoveAt tuple idx) + (= len (tuple-length tuple)) + (>= idx len)) + ((panic "Index out of bounds for TupleRemoveAt")) :ruleset always-run) + -(rewrite (TypeListRemoveAt (TNil) _idx) (TNil) :ruleset always-run) -(rewrite (TypeListRemoveAt (TCons x xs) 0 ) xs :ruleset always-run) +(function TypeListRemoveAt (TypeList i64) TypeList :unextractable) +(rewrite (TypeListRemoveAt (TNil) _idx) (TNil) :ruleset type-helpers) +(rewrite (TypeListRemoveAt (TCons x xs) 0 ) xs :ruleset type-helpers) (rewrite (TypeListRemoveAt (TCons x xs) idx) (TCons x (TypeListRemoveAt xs (- idx 1))) :when ((> idx 0)) - :ruleset always-run) + :ruleset type-helpers) + +(rule ((TypeListRemoveAt (TNil) _idx)) + ((panic "Index out of bounds for TypeListRemoveAt.")) :ruleset type-helpers) From 46554ccdb849748b839c2f47b9180bba9814489a Mon Sep 17 00:00:00 2001 From: Anjali Pal Date: Thu, 30 May 2024 10:11:01 -0700 Subject: [PATCH 44/47] rewrite if a b then a else b to min/max --- .../src/optimizations/switch_rewrites.egg | 28 +++++++++++++++++++ tests/passing/small/max.bril | 14 ++++++++++ tests/passing/small/min.bril | 11 ++++++++ tests/snapshots/files__max-optimize.snap | 15 ++++++++++ tests/snapshots/files__min-optimize.snap | 15 ++++++++++ 5 files changed, 83 insertions(+) create mode 100644 tests/passing/small/max.bril create mode 100644 tests/passing/small/min.bril create mode 100644 tests/snapshots/files__max-optimize.snap create mode 100644 tests/snapshots/files__min-optimize.snap diff --git a/dag_in_context/src/optimizations/switch_rewrites.egg b/dag_in_context/src/optimizations/switch_rewrites.egg index 778c6eb95..fede9243c 100644 --- a/dag_in_context/src/optimizations/switch_rewrites.egg +++ b/dag_in_context/src/optimizations/switch_rewrites.egg @@ -1,6 +1,34 @@ (ruleset switch_rewrite) (ruleset always-switch-rewrite) +(rule ( + (= pred (Bop (LessThan) a b)) + (= if_e (If pred inputs thn els)) + ; a is an input to the if region + (= a (Get inputs i)) + ; b is an input to the if region + (= b (Get inputs j)) + ; if a < b then a else b + (= (Get thn k) (Get (Arg ty (InIf true pred inputs)) i)) + (= (Get els k) (Get (Arg ty (InIf false pred inputs)) j)) + ) + ((union (Get if_e k) (Bop (Smin) a b))) + :ruleset switch_rewrite) + +(rule ( + (= pred (Bop (LessThan) a b)) + (= if_e (If pred inputs thn els)) + ; a is an input to the if region + (= a (Get inputs i)) + ; b is an input to the if region + (= b (Get inputs j)) + ; if a < b then b else a + (= (Get thn k) (Get (Arg ty (InIf true pred inputs)) j)) + (= (Get els k) (Get (Arg ty (InIf false pred inputs)) i)) + ) + ((union (Get if_e k) (Bop (Smax) a b))) + :ruleset switch_rewrite) + ; if (a and b) X Y ~~> if a (if b X Y) Y (rule ((= lhs (If (Bop (And) a b) ins X Y)) (HasType ins (TupleT ins_ty)) diff --git a/tests/passing/small/max.bril b/tests/passing/small/max.bril new file mode 100644 index 000000000..acffa30ee --- /dev/null +++ b/tests/passing/small/max.bril @@ -0,0 +1,14 @@ +# ARGS: 20 30 +@main(x: int, y: int) { + cmp: bool = gt x y; + one: int = const 1; + br cmp .then .else; + .then: + res: int = id x; + jmp .done; + .else: + res: int = id y; + jmp .done; + .done: + print res; +} \ No newline at end of file diff --git a/tests/passing/small/min.bril b/tests/passing/small/min.bril new file mode 100644 index 000000000..d3ce58408 --- /dev/null +++ b/tests/passing/small/min.bril @@ -0,0 +1,11 @@ +# ARGS: 20 30 +@main(x: int, y: int) { + cmp: bool = lt x y; + res: int = id y; + br cmp .then .else; + .then: + res: int = id x; + .else: + .done: + print res; +} \ No newline at end of file diff --git a/tests/snapshots/files__max-optimize.snap b/tests/snapshots/files__max-optimize.snap new file mode 100644 index 000000000..2f6ffb690 --- /dev/null +++ b/tests/snapshots/files__max-optimize.snap @@ -0,0 +1,15 @@ +--- +source: tests/files.rs +expression: visualization.result +--- +@main(v0: int, v1: int) { +.b2_: + v3_: int = smax v1 v0; + v4_: bool = lt v1 v0; + v5_: int = id v1; + br v4_ .b6_ .b7_; +.b6_: + v5_: int = id v0; +.b7_: + print v3_; +} diff --git a/tests/snapshots/files__min-optimize.snap b/tests/snapshots/files__min-optimize.snap new file mode 100644 index 000000000..790aceb52 --- /dev/null +++ b/tests/snapshots/files__min-optimize.snap @@ -0,0 +1,15 @@ +--- +source: tests/files.rs +expression: visualization.result +--- +@main(v0: int, v1: int) { +.b2_: + v3_: int = smin v0 v1; + v4_: bool = lt v0 v1; + v5_: int = id v1; + br v4_ .b6_ .b7_; +.b6_: + v5_: int = id v0; +.b7_: + print v3_; +} From 516a10690ec4abdd52ecba275a6ddc7a5db72f17 Mon Sep 17 00:00:00 2001 From: Eli Rosenthal Date: Thu, 30 May 2024 13:01:39 -0700 Subject: [PATCH 45/47] Simplify control flow for CFGs generated by eggcc. (#610) Add a new branch simplification pass to reduce overhead introduced by RVSDGs --- Cargo.lock | 94 +-- dag_in_context/Cargo.toml | 2 +- dag_in_context/rust-toolchain | 2 +- dag_in_context/src/typechecker.rs | 3 +- rust-toolchain | 2 +- src/rvsdg/mod.rs | 1 + src/rvsdg/optimize_direct_jumps.rs | 11 +- src/rvsdg/rvsdg2svg.rs | 23 +- src/rvsdg/simplify_branches.rs | 652 ++++++++++++++++++ src/rvsdg/to_dag.rs | 2 +- .../snapshots/files__fib_shape-optimize.snap | 6 +- .../files__flatten_loop-optimize.snap | 19 +- .../files__implicit-return-optimize.snap | 14 +- tests/snapshots/files__loop_if-optimize.snap | 23 +- .../files__range_check-optimize.snap | 10 +- .../files__range_splitting-optimize.snap | 10 +- .../snapshots/files__small-fib-optimize.snap | 6 +- tests/snapshots/files__sqrt-optimize.snap | 13 +- 18 files changed, 788 insertions(+), 105 deletions(-) create mode 100644 src/rvsdg/simplify_branches.rs diff --git a/Cargo.lock b/Cargo.lock index 68ff4942f..800bc9486 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -91,9 +91,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.83" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "arbitrary" @@ -130,7 +130,7 @@ dependencies = [ "argh_shared", "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -196,7 +196,7 @@ dependencies = [ [[package]] name = "bril-rs" version = "0.1.0" -source = "git+https://github.com/uwplse/bril?rev=78881c45aa53231915f333d1d6dcc26cedc63b57#78881c45aa53231915f333d1d6dcc26cedc63b57" +source = "git+https://github.com/uwplse/bril?rev=e2be3f5#e2be3f5d7e160f02b7aed0ef2bcc3e13ae722d2b" dependencies = [ "serde", "serde_json", @@ -290,9 +290,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.0.97" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" +checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" [[package]] name = "cfg-if" @@ -331,7 +331,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -504,9 +504,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] @@ -531,7 +531,7 @@ dependencies = [ name = "dag_in_context" version = "0.1.0" dependencies = [ - "bril-rs 0.1.0 (git+https://github.com/uwplse/bril?rev=78881c45aa53231915f333d1d6dcc26cedc63b57)", + "bril-rs 0.1.0 (git+https://github.com/uwplse/bril?rev=e2be3f5)", "dot-structures", "egglog", "egraph-serialize", @@ -633,7 +633,7 @@ dependencies = [ "rs2bril", "serde_json", "smallvec", - "syn 2.0.64", + "syn 2.0.66", "tempfile", "thiserror", ] @@ -718,7 +718,7 @@ checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -817,9 +817,9 @@ source = "git+https://github.com/oflatt/symbolic-expressions?rev=655b6a4c06b4b3d [[package]] name = "getrandom" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -958,7 +958,7 @@ source = "git+https://github.com/TheDan64/inkwell.git?rev=6c0fb56b3554e939f9ca61 dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -976,9 +976,9 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ "cfg-if", ] @@ -1076,15 +1076,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libmimalloc-sys" -version = "0.1.37" +version = "0.1.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81eb4061c0582dedea1cbc7aff2240300dd6982e0239d1c99e65c1dbf4a30ba7" +checksum = "0e7bb23d733dfcc8af652a78b7bf232f0e967710d044732185e561e47c0336b6" dependencies = [ "cc", "libc", @@ -1119,9 +1119,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "llvm-sys" @@ -1176,9 +1176,9 @@ checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "mimalloc" -version = "0.1.41" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f41a2280ded0da56c8cf898babb86e8f10651a34adcfff190ae9a1159c6908d" +checksum = "e9186d86b79b52f4a77af65604b51225e8db1d6ee7e3f41aec1e40829c71a176" dependencies = [ "libmimalloc-sys", ] @@ -1284,9 +1284,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -1336,7 +1336,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1395,9 +1395,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "proc-macro2" -version = "1.0.82" +version = "1.0.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" +checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6" dependencies = [ "unicode-ident", ] @@ -1540,7 +1540,7 @@ dependencies = [ "bril-rs 0.1.0 (git+https://github.com/uwplse/bril?rev=e2be3f5d7e160f02b7aed0ef2bcc3e13ae722d2b)", "clap", "proc-macro2", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1597,22 +1597,22 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.202" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.202" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1720,7 +1720,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1746,9 +1746,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.64" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ad3dee41f36859875573074334c200d1add8e4a87bb37113ebd31d926b7b11f" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote", @@ -1795,22 +1795,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.60" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.60" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1866,9 +1866,9 @@ dependencies = [ [[package]] name = "triomphe" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3" +checksum = "1b2cb4fbb9995eeb36ac86fadf24031ccd58f99d6b4b2d7b911db70bddb80d90" [[package]] name = "typenum" @@ -2054,5 +2054,5 @@ checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] diff --git a/dag_in_context/Cargo.toml b/dag_in_context/Cargo.toml index 5e2ba1741..da7a5d891 100644 --- a/dag_in_context/Cargo.toml +++ b/dag_in_context/Cargo.toml @@ -12,7 +12,7 @@ strum_macros = "0.25" main_error = "0.1.2" thiserror = "1.0" egraph-serialize = "0.1.0" -bril-rs = { git = "https://github.com/uwplse/bril", rev = "78881c45aa53231915f333d1d6dcc26cedc63b57" } +bril-rs = { git = "https://github.com/uwplse/bril", rev = "e2be3f5" } indexmap = "2.0.0" rustc-hash = "1.1.0" ordered-float = "3" diff --git a/dag_in_context/rust-toolchain b/dag_in_context/rust-toolchain index 283edc6d7..54227249d 100644 --- a/dag_in_context/rust-toolchain +++ b/dag_in_context/rust-toolchain @@ -1 +1 @@ -1.74.0 \ No newline at end of file +1.78.0 diff --git a/dag_in_context/src/typechecker.rs b/dag_in_context/src/typechecker.rs index 48d2d9920..5d933a5db 100644 --- a/dag_in_context/src/typechecker.rs +++ b/dag_in_context/src/typechecker.rs @@ -62,8 +62,8 @@ impl Expr { ); new_expr } - /// Adds argument types to the expression. + #[allow(dead_code)] pub(crate) fn add_arg_type(self: RcExpr, input_ty: Type) -> RcExpr { // we need a dummy program, since there are no calls in self let prog = program!(function("dummy", tuplet!(), tuplet!(), empty()),); @@ -73,6 +73,7 @@ impl Expr { new_expr } + #[allow(dead_code)] pub(crate) fn func_with_arg_types(self: RcExpr) -> RcExpr { match self.as_ref() { Expr::Function(name, in_ty, out_ty, body) => RcExpr::new(Expr::Function( diff --git a/rust-toolchain b/rust-toolchain index 283edc6d7..54227249d 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -1.74.0 \ No newline at end of file +1.78.0 diff --git a/src/rvsdg/mod.rs b/src/rvsdg/mod.rs index bf91a8a17..5ffb1914a 100644 --- a/src/rvsdg/mod.rs +++ b/src/rvsdg/mod.rs @@ -34,6 +34,7 @@ pub(crate) mod live_variables; pub(crate) mod optimize_direct_jumps; pub(crate) mod restructure; pub(crate) mod rvsdg2svg; +pub(crate) mod simplify_branches; pub(crate) mod to_cfg; mod to_dag; diff --git a/src/rvsdg/optimize_direct_jumps.rs b/src/rvsdg/optimize_direct_jumps.rs index dab0c1a28..016f865f9 100644 --- a/src/rvsdg/optimize_direct_jumps.rs +++ b/src/rvsdg/optimize_direct_jumps.rs @@ -168,7 +168,16 @@ impl SimpleCfgFunction { impl SimpleCfgProgram { pub fn optimize_jumps(&self) -> Self { SimpleCfgProgram { - functions: self.functions.iter().map(|f| f.optimize_jumps()).collect(), + functions: self + .functions + .iter() + .map(|f| { + // NB: We could avoid this copy by having `optimize_jumps` take `self` by value. + let mut res = f.optimize_jumps(); + res.simplify_branches(); + res + }) + .collect(), } } } diff --git a/src/rvsdg/rvsdg2svg.rs b/src/rvsdg/rvsdg2svg.rs index b044ed04b..8c1559725 100644 --- a/src/rvsdg/rvsdg2svg.rs +++ b/src/rvsdg/rvsdg2svg.rs @@ -1,4 +1,5 @@ use std::collections::{BTreeMap, BTreeSet}; +use std::fmt; use std::iter::once; use bril_rs::ConstOps; @@ -70,22 +71,18 @@ impl Xml { } } -impl ToString for Xml { - fn to_string(self: &Xml) -> String { - use std::fmt::Write; - let mut out = String::new(); - - write!(out, "<{}", self.tag).unwrap(); +impl fmt::Display for Xml { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "<{}", self.tag)?; for (key, value) in &self.attributes { - write!(out, "\n\t{key}=\"{value}\"").unwrap(); + write!(f, "\n\t{key}=\"{value}\"")?; } - writeln!(out, ">").unwrap(); + writeln!(f, ">")?; for line in self.body.lines() { - writeln!(out, "\t{line}").unwrap(); + writeln!(f, "\t{line}")?; } - writeln!(out, "", self.tag).unwrap(); - - out + writeln!(f, "", self.tag)?; + Ok(()) } } @@ -655,7 +652,7 @@ impl RvsdgProgram { let (size, mut xml) = function.to_region().to_xml(false); // assert that it doesn't have a transform yet - assert!(xml.attributes.get("transform").is_none()); + assert!(!xml.attributes.contains_key("transform")); xml.attributes .insert("transform".to_owned(), format!("translate(0, {})", height)); xmls.push(xml); diff --git a/src/rvsdg/simplify_branches.rs b/src/rvsdg/simplify_branches.rs new file mode 100644 index 000000000..6822bed7f --- /dev/null +++ b/src/rvsdg/simplify_branches.rs @@ -0,0 +1,652 @@ +//! A pass over a CFG returned from the RVSDG=>CFG [conversion module](crate::rvsdg::to_cfg) +//! to simplify branch structures. +//! +//! # Introduction +//! RVSDGs are more structured than arbitrary CFGs. The only control strutures +//! that RVSDGs support directly are ifs (with an else) and tail-controlled +//! loops. This means that any other control flow constructs, from `for` loops +//! all the way to `goto`s need to be simulated using auxiliary predicate +//! variables introduced during translation time. +//! +//! The resulting representation is great for declarative rewrites, but can +//! generate slower code when directly interpreted as a CFG, e.g. to break out +//! of multiple layers of nested loop, CFGs only require a single jump but +//! RVSDGs require a branch for every layer of nesting. +//! +//! The algorithm in this module aims to recover more natural, efficient +//! control-flow structure from the raw CFG generated by an RVSDG. It is +//! inspired by the PCFR algorithm described in "Perfect Reconstructability of +//! Control Flow from Demand Dependence Graphs" by Bahman, Reissmann, Jahre, and +//! Meyer, but it has a different structure: +//! +//! * PCFR operates on the RVSDG directly, while this algorithm operates on the +//! resulting CFG. This is pragmatically useful for eggcc, which already has +//! fairly involved RVSDG=>CFG conversion code. +//! * PCFR expects an RVSDG in _predicate continuation form_, where predicates +//! are introduced immediately before they are used. eggcc almost certainly +//! does not preserve this property, and we want to avoid duplicating or +//! splitting RVSDG nodes to reintroduce it. The algorithm in this module is +//! robust to some predicates being used more than once, sometiems across +//! branches. +//! * The algorithm in this module has not been optimized for efficiency and as +//! a result is likely slower than a good implementation of PCFR. This doesn't +//! seem like an inherent issue and the performance of the two should be +//! similar after some optimization. +//! * The paper from Bahman et. al. also sketches a "ShortCircuitCFG" algorithm +//! that is similar to the algorithm here, but makes some simplifying +//! assumptions, potentially based again on predicate continuation form. +//! +//! # Algorithm Overview +//! The algorithm code is fairly heavily commented. It relies on computing the +//! fixpoint of a monotone dataflow analysis tracking the value of boolean +//! identifiers at each CFG node. The analysis takes branches into account: +//! successors along the "true" edge of a branch on 'x' know that 'x' is true. +//! With that information in place (along with a few technical details explained +//! in code comments), we apply two kinds of rewrites on the CFG: +//! +//! * For patterns like `X -[e]-> Y -[if a=1]-> Z` where we know that `a=1` in `X` +//! (and `Y` doesn't overwrite `a`), rewrite to `X -[e]-> Z`. +//! * For patterns like `X -[if a=1]-> Y` where we know that `a=1` in `X`, +//! rewrite to `X -[jump]-> Y` and remove all other outgoing edges from `X`. +//! If this is the only incoming branch to `Y`, a future optimize_direct_jumps +//! pass will merge the two blocks entirely. +//! +//! The boolean value analysis should converge quickly given the structure of +//! the CFGs we generate, but the current implementation involves lots of +//! copying of data: If the CFG were in SSI form (SSA + variable splits on +//! branches), I believe that we could build a more efficient analysis by +//! looking at nodes where variables are assigned (or branch targets) and +//! relying on dominance information to infer whether a boolean variable has a +//! known value at a node. + +use std::{collections::VecDeque, io::Write, mem}; + +use crate::cfg::{BasicBlock, BlockName, Branch, BranchOp, CondVal, Identifier, SimpleCfgFunction}; +use bril_rs::{Argument, Instruction, Literal, Type, ValueOps}; +use hashbrown::{HashMap, HashSet}; +use indexmap::{IndexMap, IndexSet}; +use petgraph::{ + graph::{EdgeIndex, NodeIndex}, + visit::Dfs, + Direction, +}; + +impl SimpleCfgFunction { + pub(crate) fn simplify_branches(&mut self) { + // Run the whole thing in a fixpoint loop. Question: does doing reverse + // post-order iteration + incrementally maintaining the value analysis + // allow us to converge in a single iteration? + let mut changed = true; + let mut var_counter = 0; + while changed { + // Step 1: compute some information about the CFG. + // * Find "administrative" nodes. + // * Find conditional branches. + // * Start off a Value Analysis for the function. + let branch_meta = self.get_branch_metadata(); + let mut val_analysis = ValueAnalysis::new(self); + // Step 2: split conditional branches and mark the relevant constants as + // known in the later nodes. This lets us simplify the value analysis by + // having empty nodes enncapsulate the information imparted by the + // branch. + for (id, edge, val) in branch_meta + .branches + .iter() + .flat_map(|(id, edges)| edges.iter().map(move |(edge, val)| (id, *edge, val))) + { + let Some(lit) = to_lit(val) else { + continue; + }; + // Count downwards from usize::MAX to avoid collisions with other placeholders + let node_bound = usize::MAX - var_counter; + var_counter += 1; + let (source, target) = self.graph.edge_endpoints(edge).unwrap(); + let weight = self.graph.remove_edge(edge).unwrap(); + let block_name = BlockName::Placeholder(node_bound); + let mid = self.graph.add_node(BasicBlock::empty(block_name)); + self.graph.add_edge(source, mid, weight); + // NB: We rely on the optimize_direct_jumps pass to collapse this + // back down. + self.graph.add_edge( + mid, + target, + Branch { + op: BranchOp::Jmp, + pos: None, + }, + ); + val_analysis.add_assignment(mid, id.clone(), ValueInfo::Known(lit)); + } + // Step 3: Compute the fixpoint of the value analysis. + val_analysis.compute_fixpoint(self); + // Step 4: Rewrite branches + changed = self.rewrite_branches(&branch_meta, &val_analysis); + // Step 5: Remove any nodes no longer reachable from the entry. + self.retain_reachable(); + + // Step 6: Rewrite direct jumps. This will un-split any edges split + // in step 2, and potentially merge nodes where a conditional branch + // was replaced with a jump. + *self = self.optimize_jumps(); + } + } + + fn get_branch_metadata(&self) -> BranchMetadata { + let mut res = BranchMetadata::default(); + for node in self.graph.node_indices() { + let block = &self.graph[node]; + if block.footer.is_empty() && block.instrs.iter().all(is_admin_instr) { + res.admin_nodes.insert(node); + } + for (id, lit) in block.instrs.iter().filter_map(constants_assigned) { + res.constants_known.add_constant(node, id, lit); + } + let mut walker = self + .graph + .neighbors_directed(node, Direction::Outgoing) + .detach(); + while let Some((edge, _)) = walker.next(&self.graph) { + if let BranchOp::Cond { arg, val, .. } = &self.graph[edge].op { + res.branches + .entry(arg.clone()) + .or_default() + .insert(edge, *val); + } + } + } + res + } + + /// Remove any nodes that are no longer reachable from the entry node. + fn retain_reachable(&mut self) { + let mut walker = Dfs::new(&self.graph, self.entry); + while walker.next(&self.graph).is_some() {} + let mut to_remove = vec![]; + for node_id in self.graph.node_indices() { + if !walker.discovered.contains(node_id.index()) { + to_remove.push(node_id); + assert_ne!( + node_id, self.exit, + "branch simplification removed the exit node!" + ); + } + } + for node_id in to_remove { + self.graph.remove_node(node_id); + } + } + + /// Simplify control flow using the information gathered in the initial steps. + /// * For each administrative node `n``... + /// * For each outgoing branch [edge e1] with cond val `v` for `id` + /// * Check if `id` was written to in `n`, if it was, then move on + /// _unless_ we know the value of `id`; in which case we can replace the branch with a jump. + /// * Otherwise, check if a predecessor [via edge e2] node has `v` as a + /// known value for `id`. + /// * If so, copy the contents of the admin node to that predecessor, and + /// reroute e2 to the target of e1. + fn rewrite_branches( + &mut self, + branch_meta: &BranchMetadata, + val_analysis: &ValueAnalysis, + ) -> bool { + let mut scratch = Vec::new(); + let mut changed = false; + for admin_node in &branch_meta.admin_nodes { + let mut walker = self + .graph + .neighbors_directed(*admin_node, Direction::Outgoing) + .detach(); + // Don't reroute past the exit node. We want to make sure it stays reachable. + if admin_node == &self.exit { + continue; + } + while let Some((outgoing, succ)) = walker.next(&self.graph) { + let BranchOp::Cond { arg, val, .. } = self.graph[outgoing].op.clone() else { + continue; + }; + let Some(val) = to_lit(&val) else { + continue; + }; + if val_analysis.data[admin_node].kills.contains(&arg) { + if succ != self.exit + && self.graph.neighbors(*admin_node).any(|x| x == self.exit) + { + // Don't remove any outgoing links to the exit node. + break; + } + // We assign to the branched-on argument in the admin + // node. See if we can fold the constant branch here. + let ValueInfo::Known(lit) = val_analysis.data[admin_node].get_output(&arg) + else { + continue; + }; + if lit != val { + continue; + } + // okay, we have found a matching edge. Replace this branch + // with a jump. + let mut walker = self + .graph + .neighbors_directed(*admin_node, Direction::Outgoing) + .detach(); + while let Some((outgoing, _)) = walker.next(&self.graph) { + self.graph.remove_edge(outgoing); + } + self.graph.add_edge( + *admin_node, + succ, + Branch { + op: BranchOp::Jmp, + pos: None, + }, + ); + changed = true; + // Don't run the rest of the inner loop. + break; + } + let mut incoming_walker = self + .graph + .neighbors_directed(*admin_node, Direction::Incoming) + .detach(); + while let Some((incoming, pred)) = incoming_walker.next(&self.graph) { + // We may be able to reroute a branch if the value in + // question is known to equal the branch value in a + // predecessor block. + if !matches!(val_analysis.data[&pred].get_output(&arg), ValueInfo::Known(v) if v == val) + { + continue; + } + + // We only have to worry about `instrs` because we + // checked that the footer was empty when we populated + // admin_nodes. We do this because we more or less don't + // use footers on our way back to bril. + scratch.extend(self.graph[*admin_node].instrs.iter().cloned()); + let (_, target) = self.graph.edge_endpoints(outgoing).unwrap(); + let target_incoming = self + .graph + .neighbors_directed(target, Direction::Incoming) + .count(); + let is_jump = matches!(self.graph[incoming].op, BranchOp::Jmp); + // Now it comes to move the block somewhere: if the + // incoming edge is a jump, then we would run all of the + // instructions in the current block anyway, we can just + // move them up. + if is_jump { + let weight = self.graph.remove_edge(incoming).unwrap(); + self.graph[pred].instrs.append(&mut scratch); + self.graph.add_edge(pred, target, weight); + changed = true; + break; + } else if target_incoming == 1 { + // The next safe case is if we are replacing the targets + // only incoming edge. In that case, we can move the + // data down. + let weight = self.graph.remove_edge(incoming).unwrap(); + let target_block = &mut self.graph[target]; + scratch.append(&mut target_block.instrs); + mem::swap(&mut target_block.instrs, &mut scratch); + self.graph.add_edge(pred, target, weight); + changed = true; + break; + } else { + scratch.clear(); + // Otherwise we may need some sort of compatibility check to + // merge the block somewhere. Add the edge back for now: + } + } + } + } + changed + } +} + +#[derive(Default, Debug)] +struct BranchMetadata { + /// Nodes that only contain administrative instructions. + admin_nodes: IndexSet, + /// Information about known constant values at particular nodes. + constants_known: ConstantInfo, + /// Relevant values used as branches. + branches: IndexMap>, +} + +/// Constants with a known value as of a given node. +/// +/// For now, the constants are always booleans, but we keep arbitrary +/// Literals around to make it easier to handle multi-way branches later. +#[derive(Default, Debug)] +struct ConstantInfo { + by_node: IndexMap>, + by_id: IndexMap>, +} + +impl ConstantInfo { + fn add_constant(&mut self, node: NodeIndex, id: Identifier, lit: Literal) { + if self + .by_node + .entry(node) + .or_default() + .insert(id.clone(), lit.clone()) + .is_none() + { + self.by_id.entry(id).or_default().push((node, lit)); + } + } +} + +/// "Administrative Instructions" are ones that will have essentially no runtime +/// cost once they go through instruction selection / register allocation. We +/// use these as a heuristic to find blocks that are safe to merge into their +/// predecessors in exchange for simpler control flow: RVSDG conversion overhead +/// is largely contained in blocks only containing these instructions. +fn is_admin_instr(inst: &Instruction) -> bool { + matches!( + inst, + Instruction::Constant { .. } + | Instruction::Value { + op: ValueOps::Id, + .. + } + ) +} + +fn constants_assigned(inst: &Instruction) -> Option<(Identifier, Literal)> { + if let Instruction::Constant { + dest, + value: value @ Literal::Bool(..), + .. + } = inst + { + Some((dest.into(), value.clone())) + } else { + None + } +} + +fn to_lit(cv: &CondVal) -> Option { + if cv.of == 2 { + Some(if cv.val == 0 { + Literal::Bool(false) + } else { + Literal::Bool(true) + }) + } else { + // Not handling multi-way branches for now. + None + } +} + +/// A basic semilattice describing the state of a value. +#[derive(Clone, Default, Debug)] +enum ValueInfo { + /// Nothing is currently known about the value. + #[default] + Bot, + /// The value is known to hold a concrete value. + Known(Literal), + /// We know that we cannot approximate the value with a single constant. + Top, +} + +impl ValueInfo { + /// Merge two ValueInfos, returning true if `self` changed. + fn merge(&mut self, other: &ValueInfo) -> bool { + match (self, other) { + (ValueInfo::Bot, ValueInfo::Bot) => false, + (slf @ ValueInfo::Bot, x) => { + *slf = x.clone(); + true + } + (ValueInfo::Top, _) => false, + (slf, ValueInfo::Top) => { + *slf = ValueInfo::Top; + true + } + (ValueInfo::Known(l), ValueInfo::Known(r)) if l == r => false, + (slf @ ValueInfo::Known(_), ValueInfo::Known(_)) => { + *slf = ValueInfo::Top; + true + } + (ValueInfo::Known(_), ValueInfo::Bot) => false, + } + } +} + +/// Monotone transforms on ValueInfos. +#[derive(Debug)] +enum Transform { + Id, + Negate, + OverWrite(ValueInfo), +} + +impl Transform { + fn apply(&self, val: &ValueInfo) -> ValueInfo { + match self { + Transform::Id => val.clone(), + Transform::Negate => match val { + ValueInfo::Bot => ValueInfo::Bot, + ValueInfo::Known(Literal::Bool(b)) => ValueInfo::Known(Literal::Bool(!b)), + ValueInfo::Known(..) => ValueInfo::Top, + ValueInfo::Top => ValueInfo::Top, + }, + Transform::OverWrite(info) => info.clone(), + } + } +} + +/// The state of the (boolean) values in a particular basic block. +#[derive(Default, Debug)] +struct ValueState { + /// The (pointwise) join of all of the values in incoming branches. + inherited: IndexMap, + /// The transforms induced by any operations on variables in the block. + /// + /// These are computed during initialization from instructions in a basic + /// block and during step 2 of the main algorithm to add values for the + /// targets of conditional branches. + transforms: VecDeque<( + Identifier, /* dst */ + Identifier, /* src */ + Transform, + )>, + /// The set of variables written to in this basic block. + kills: HashSet, + /// The materialized output of transforms on inherited. + outputs: IndexMap, + /// A variable indicating if `outputs` is stale. + recompute: bool, +} + +impl ValueState { + /// Recompute the outputs for this state, if necessary. + fn maybe_recompute(&mut self) -> bool { + let res = self.recompute; + if self.recompute { + self.outputs.clear(); + for (id, info) in &self.inherited { + self.outputs.insert(id.clone(), info.clone()); + } + for (dst, src, transform) in &self.transforms { + let src_val = self.outputs.get(src).unwrap_or(&ValueInfo::Bot); + let dst_val = transform.apply(src_val); + self.outputs.insert(dst.clone(), dst_val); + self.kills.insert(dst.clone()); + } + + self.recompute = false; + } + res + } + fn outputs(&self) -> impl Iterator { + assert!(!self.recompute); + self.outputs.iter() + } + + fn get_output(&self, id: &Identifier) -> ValueInfo { + assert!(!self.recompute); + self.outputs.get(id).cloned().unwrap_or(ValueInfo::Bot) + } + + /// A special case of `merge_from` to handle self-loops. + fn merge_self(&mut self) { + let mut changed = false; + for (id, out) in self.outputs.iter() { + changed |= self.inherited.entry(id.clone()).or_default().merge(out); + } + if changed { + self.recompute = true; + } + } + + /// Update the given inputs with the contents of `other`. + fn merge_from(&mut self, other: &ValueState) { + let mut changed = false; + for (id, out) in other.outputs() { + changed |= self.inherited.entry(id.clone()).or_default().merge(out); + } + if changed { + self.recompute = true; + } + } + + /// Populate the ValueState with relevant instructions from the given basic + /// block. + fn new(block: &BasicBlock) -> ValueState { + let mut transforms = VecDeque::new(); + for instr in &block.instrs { + match instr { + Instruction::Constant { + dest, + value: lit @ Literal::Bool(..), + .. + } => { + // The `src` identifier is unused in this case. + transforms.push_back(( + Identifier::from(dest.clone()), + Identifier::Num(usize::MAX), + Transform::OverWrite(ValueInfo::Known(lit.clone())), + )); + } + Instruction::Value { + args, + dest, + op, + op_type: Type::Bool, + .. + } => match op { + ValueOps::Id => { + assert_eq!(args.len(), 1); + transforms.push_back(( + Identifier::from(dest.clone()), + args[0].clone().into(), + Transform::Id, + )); + } + ValueOps::Not => { + assert_eq!(args.len(), 1); + transforms.push_back(( + Identifier::from(dest.clone()), + args[0].clone().into(), + Transform::Negate, + )); + } + _ => { + transforms.push_back(( + Identifier::from(dest.clone()), + Identifier::Num(usize::MAX), + Transform::OverWrite(ValueInfo::Top), + )); + } + }, + Instruction::Effect { .. } => {} + Instruction::Constant { .. } => {} + Instruction::Value { .. } => {} + } + } + ValueState { + transforms, + recompute: true, + ..Default::default() + } + } +} + +struct ValueAnalysis { + data: HashMap, +} + +impl ValueAnalysis { + fn new(graph: &SimpleCfgFunction) -> ValueAnalysis { + let mut res = ValueAnalysis { + data: Default::default(), + }; + for node in graph.graph.node_indices() { + res.data.insert(node, ValueState::new(&graph.graph[node])); + } + for Argument { name, arg_type } in &graph.args { + if let Type::Bool = arg_type { + let id = Identifier::from(name.clone()); + res.add_assignment(graph.entry, id, ValueInfo::Top); + } + } + res + } + + /// Prepend a virtual `id` instruction to the analysis for this node. + fn add_assignment(&mut self, node: NodeIndex, dst: Identifier, val: ValueInfo) { + let state = self.data.entry(node).or_default(); + state + .transforms + .push_front((dst, Identifier::Num(usize::MAX), Transform::OverWrite(val))); + state.recompute = true; + } + + /// A simple worklist algorithm for propagating values through the CFG. + fn compute_fixpoint(&mut self, func: &SimpleCfgFunction) { + let mut worklist = IndexSet::::default(); + for node in func.graph.node_indices() { + self.data.entry(node).or_default().maybe_recompute(); + worklist.insert(node); + } + while let Some(node) = worklist.pop() { + let mut cur = mem::take(self.data.get_mut(&node).unwrap()); + for incoming in func.graph.neighbors_directed(node, Direction::Incoming) { + if incoming == node { + cur.merge_self(); + } else { + cur.merge_from(&self.data[&incoming]); + } + } + let changed = cur.maybe_recompute(); + self.data.insert(node, cur); + if changed { + for outgoing in func.graph.neighbors_directed(node, Direction::Outgoing) { + worklist.insert(outgoing); + } + } + } + } + + /// Debugging routine for printing out the state of the analysis. + #[allow(unused)] + fn render(&self, func: &SimpleCfgFunction) -> String { + let mut buf = Vec::::new(); + for (node, state) in &self.data { + let name = &func.graph[*node].name; + writeln!(buf, "{name}.inputs: {{").unwrap(); + for (id, info) in &state.inherited { + writeln!(buf, " {id:?}: {info:?}").unwrap(); + } + writeln!(buf, "}}").unwrap(); + writeln!(buf, "{name}.outputs: {{").unwrap(); + for (id, info) in &state.outputs { + writeln!(buf, " {id:?}: {info:?}").unwrap(); + } + writeln!(buf, "}}").unwrap(); + } + String::from_utf8(buf).unwrap() + } +} diff --git a/src/rvsdg/to_dag.rs b/src/rvsdg/to_dag.rs index a6b410435..ccb9a3be4 100644 --- a/src/rvsdg/to_dag.rs +++ b/src/rvsdg/to_dag.rs @@ -123,7 +123,7 @@ impl<'a> DagTranslator<'a> { /// the first output using `skip_outputs`. fn translate_subregion( &mut self, - operands: impl Iterator + DoubleEndedIterator, + operands: impl DoubleEndedIterator, ) -> RcExpr { let resulting_exprs = operands.map(|operand| { let res = self.translate_operand(operand); diff --git a/tests/snapshots/files__fib_shape-optimize.snap b/tests/snapshots/files__fib_shape-optimize.snap index 28e318faf..662af857c 100644 --- a/tests/snapshots/files__fib_shape-optimize.snap +++ b/tests/snapshots/files__fib_shape-optimize.snap @@ -20,11 +20,13 @@ expression: visualization.result v9_: int = id v14_; v10_: int = id v5_; v11_: int = id v6_; + v4_: int = id v9_; + v5_: int = id v10_; + v6_: int = id v11_; + jmp .b7_; .b13_: v4_: int = id v9_; v5_: int = id v10_; v6_: int = id v11_; - br v8_ .b7_ .b15_; -.b15_: print v4_; } diff --git a/tests/snapshots/files__flatten_loop-optimize.snap b/tests/snapshots/files__flatten_loop-optimize.snap index f6eccb4d9..a3c090de6 100644 --- a/tests/snapshots/files__flatten_loop-optimize.snap +++ b/tests/snapshots/files__flatten_loop-optimize.snap @@ -42,25 +42,32 @@ expression: visualization.result v27_: int = id v34_; v28_: int = id v21_; v29_: int = id v22_; + v18_: int = id v25_; + v19_: int = id v26_; + v20_: int = id v27_; + v21_: int = id v28_; + v22_: int = id v29_; + jmp .b23_; .b31_: v18_: int = id v25_; v19_: int = id v26_; v20_: int = id v27_; v21_: int = id v28_; v22_: int = id v29_; - br v24_ .b23_ .b35_; -.b35_: - v36_: int = add v5_ v6_; - v11_: int = id v36_; + v35_: int = add v5_ v6_; + v11_: int = id v35_; v12_: int = id v6_; v13_: int = id v7_; v14_: int = id v8_; + v5_: int = id v11_; + v6_: int = id v12_; + v7_: int = id v13_; + v8_: int = id v14_; + jmp .b9_; .b16_: v5_: int = id v11_; v6_: int = id v12_; v7_: int = id v13_; v8_: int = id v14_; - br v10_ .b9_ .b37_; -.b37_: print v5_; } diff --git a/tests/snapshots/files__implicit-return-optimize.snap b/tests/snapshots/files__implicit-return-optimize.snap index 13def91e7..da3565f39 100644 --- a/tests/snapshots/files__implicit-return-optimize.snap +++ b/tests/snapshots/files__implicit-return-optimize.snap @@ -26,13 +26,16 @@ expression: visualization.result v13_: int = id v20_; v14_: int = id v6_; v15_: int = id v7_; + v4_: int = id v12_; + v5_: int = id v13_; + v6_: int = id v14_; + v7_: int = id v15_; + jmp .b8_; .b17_: v4_: int = id v12_; v5_: int = id v13_; v6_: int = id v14_; v7_: int = id v15_; - br v11_ .b8_ .b21_; -.b21_: print v4_; } @main { @@ -60,12 +63,15 @@ expression: visualization.result v12_: int = id v19_; v13_: int = id v6_; v14_: int = id v7_; + v4_: int = id v11_; + v5_: int = id v12_; + v6_: int = id v13_; + v7_: int = id v14_; + jmp .b8_; .b16_: v4_: int = id v11_; v5_: int = id v12_; v6_: int = id v13_; v7_: int = id v14_; - br v10_ .b8_ .b20_; -.b20_: print v4_; } diff --git a/tests/snapshots/files__loop_if-optimize.snap b/tests/snapshots/files__loop_if-optimize.snap index bbf8b9417..5d1067a5c 100644 --- a/tests/snapshots/files__loop_if-optimize.snap +++ b/tests/snapshots/files__loop_if-optimize.snap @@ -20,22 +20,25 @@ expression: visualization.result v6_: int = id v12_; v7_: bool = id v5_; v8_: int = id v13_; -.b9_: c14_: bool = const true; v15_: int = id v6_; v16_: bool = id c14_; v17_: int = id v8_; - br v5_ .b18_ .b19_; .b18_: - c20_: bool = const false; - v15_: int = id v6_; - v16_: bool = id c20_; - v17_: int = id v8_; -.b19_: - v21_: bool = not v5_; + v19_: bool = not v5_; v2_: int = id v6_; v3_: int = id v8_; - br v21_ .b4_ .b22_; -.b22_: + br v19_ .b4_ .b20_; +.b9_: + c14_: bool = const true; + v15_: int = id v6_; + v16_: bool = id c14_; + v17_: int = id v8_; + c21_: bool = const false; + v15_: int = id v6_; + v16_: bool = id c21_; + v17_: int = id v8_; + jmp .b18_; +.b20_: print v2_; } diff --git a/tests/snapshots/files__range_check-optimize.snap b/tests/snapshots/files__range_check-optimize.snap index cfecc22af..20046716a 100644 --- a/tests/snapshots/files__range_check-optimize.snap +++ b/tests/snapshots/files__range_check-optimize.snap @@ -23,14 +23,14 @@ expression: visualization.result br v5_ .b16_ .b17_; .b16_: v15_: int = id v14_; -.b17_: v2_: int = id v15_; - br v5_ .b3_ .b18_; + jmp .b3_; .b9_: - c19_: int = const 2; - print c19_; + c18_: int = const 2; + print c18_; v11_: int = id v2_; jmp .b12_; -.b18_: +.b17_: + v2_: int = id v15_; print v2_; } diff --git a/tests/snapshots/files__range_splitting-optimize.snap b/tests/snapshots/files__range_splitting-optimize.snap index 156f153b9..d99cbf262 100644 --- a/tests/snapshots/files__range_splitting-optimize.snap +++ b/tests/snapshots/files__range_splitting-optimize.snap @@ -22,14 +22,14 @@ expression: visualization.result br v7_ .b15_ .b16_; .b15_: v14_: int = id v5_; -.b16_: v2_: int = id v14_; - br v7_ .b3_ .b17_; + jmp .b3_; .b10_: - c18_: int = const 2; - print c18_; + c17_: int = const 2; + print c17_; v12_: int = id v2_; jmp .b13_; -.b17_: +.b16_: + v2_: int = id v14_; print v2_; } diff --git a/tests/snapshots/files__small-fib-optimize.snap b/tests/snapshots/files__small-fib-optimize.snap index 6899c481e..aa255d216 100644 --- a/tests/snapshots/files__small-fib-optimize.snap +++ b/tests/snapshots/files__small-fib-optimize.snap @@ -31,11 +31,15 @@ expression: visualization.result v14_: int = id v19_; v15_: int = id v8_; v16_: int = id v10_; + v7_: int = id v13_; + v8_: int = id v14_; + v9_: int = id v15_; + v10_: int = id v16_; + jmp .b11_; .b18_: v7_: int = id v13_; v8_: int = id v14_; v9_: int = id v15_; v10_: int = id v16_; - br v12_ .b11_ .b5_; .b5_: } diff --git a/tests/snapshots/files__sqrt-optimize.snap b/tests/snapshots/files__sqrt-optimize.snap index 24a54e20c..69c298317 100644 --- a/tests/snapshots/files__sqrt-optimize.snap +++ b/tests/snapshots/files__sqrt-optimize.snap @@ -72,11 +72,12 @@ expression: visualization.result .b14_: v8_: float = id v13_; v9_: bool = id v12_; -.b11_: - br v9_ .b47_ .b48_; + br v9_ .b11_ .b47_; .b47_: - v49_: float = fdiv v8_ v8_; - print v49_; -.b48_: -.b50_: + ret; +.b11_: + v48_: float = fdiv v8_ v8_; + print v48_; + jmp .b47_; +.b49_: } From d7eb479a1e8223c2af52b152c835d96df2f121d3 Mon Sep 17 00:00:00 2001 From: Yihong Zhang Date: Thu, 30 May 2024 15:13:40 -0700 Subject: [PATCH 46/47] fix ternary operator rules --- dag_in_context/src/type_analysis.egg | 14 +++++++++++++- dag_in_context/src/utility/add_context.egg | 6 ++++++ dag_in_context/src/utility/drop_at.egg | 8 ++++++++ dag_in_context/src/utility/expr_size.egg | 6 +++++- dag_in_context/src/utility/subst.egg | 8 ++++++++ 5 files changed, 40 insertions(+), 2 deletions(-) diff --git a/dag_in_context/src/type_analysis.egg b/dag_in_context/src/type_analysis.egg index c22bde6d7..72706aaa4 100644 --- a/dag_in_context/src/type_analysis.egg +++ b/dag_in_context/src/type_analysis.egg @@ -73,6 +73,18 @@ (HasArgType b ty)) ((HasArgType lhs ty)) :ruleset type-analysis) +(rule ((= lhs (Top _ a b c)) + (HasArgType a ty)) + ((HasArgType lhs ty)) + :ruleset type-analysis) +(rule ((= lhs (Top _ a b c)) + (HasArgType b ty)) + ((HasArgType lhs ty)) + :ruleset type-analysis) +(rule ((= lhs (Top _ a b c)) + (HasArgType c ty)) + ((HasArgType lhs ty)) + :ruleset type-analysis) (rule ((= lhs (Get e _)) (HasArgType e ty)) ((HasArgType lhs ty)) @@ -285,7 +297,7 @@ (rule ( (= lhs (Top (Write) ptr val state)) (HasType ptr (Base (PointerT ty))) - (HasType val (Base t)) ; TODO need to support pointers to pointers + (HasType val (Base ty)) ; TODO need to support pointers to pointers ) ((HasType lhs (Base (StateT)))) ; Write returns () :ruleset type-analysis) diff --git a/dag_in_context/src/utility/add_context.egg b/dag_in_context/src/utility/add_context.egg index 58e76f65c..ff601a7b5 100644 --- a/dag_in_context/src/utility/add_context.egg +++ b/dag_in_context/src/utility/add_context.egg @@ -36,6 +36,12 @@ ;; ######################################### Operators +(rewrite (AddContext ctx (Top op c1 c2 c3)) + (Top op + (AddContext ctx c1) + (AddContext ctx c2) + (AddContext ctx c3)) + :ruleset context) (rewrite (AddContext ctx (Bop op c1 c2)) (Bop op (AddContext ctx c1) diff --git a/dag_in_context/src/utility/drop_at.egg b/dag_in_context/src/utility/drop_at.egg index 91f24a0db..69992490b 100644 --- a/dag_in_context/src/utility/drop_at.egg +++ b/dag_in_context/src/utility/drop_at.egg @@ -38,6 +38,14 @@ :ruleset drop) ;; Operators +(rule ((= lhs (DropAtInternal newty newctx idx (Top op c1 c2 c3))) + (ExprIsResolved (Top op c1 c2 c3))) + ((DelayedDropUnion lhs (Top op + (DropAtInternal newty newctx idx c1) + (DropAtInternal newty newctx idx c2) + (DropAtInternal newty newctx idx c3)))) + :ruleset drop) + (rule ((= lhs (DropAtInternal newty newctx idx (Bop op c1 c2))) (ExprIsResolved (Bop op c1 c2))) ((DelayedDropUnion lhs (Bop op diff --git a/dag_in_context/src/utility/expr_size.egg b/dag_in_context/src/utility/expr_size.egg index 4f80805e2..664605698 100644 --- a/dag_in_context/src/utility/expr_size.egg +++ b/dag_in_context/src/utility/expr_size.egg @@ -9,6 +9,10 @@ (rule ((= expr (Const n ty assum))) ((set (Expr-size expr) 1)) :ruleset always-run) +(rule ((= expr (Top op x y z)) + (= sum (+ (Expr-size z) (+ (Expr-size y) (Expr-size x))))) + ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) + (rule ((= expr (Bop op x y)) (= sum (+ (Expr-size y) (Expr-size x)))) ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) @@ -59,4 +63,4 @@ (rule ((= expr (Alloc id e state ty)) ;; do state edge's expr should be counted? (= sum (Expr-size e))) - ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) \ No newline at end of file + ((set (Expr-size expr) (+ sum 1))) :ruleset always-run) diff --git a/dag_in_context/src/utility/subst.egg b/dag_in_context/src/utility/subst.egg index e6fc57017..00d34d476 100644 --- a/dag_in_context/src/utility/subst.egg +++ b/dag_in_context/src/utility/subst.egg @@ -44,6 +44,14 @@ :ruleset subst) ;; Operators +(rule ((= lhs (Subst assum to (Top op c1 c2 c3))) + (ExprIsResolved (Top op c1 c2 c3))) + ((DelayedSubstUnion lhs + (Top op (Subst assum to c1) + (Subst assum to c2) + (Subst assum to c3)))) + :ruleset subst) + (rule ((= lhs (Subst assum to (Bop op c1 c2))) (ExprIsResolved (Bop op c1 c2))) ((DelayedSubstUnion lhs From f011b91323f371c175bfb8159358e5e32bb4af2a Mon Sep 17 00:00:00 2001 From: Yihong Zhang Date: Thu, 30 May 2024 15:20:08 -0700 Subject: [PATCH 47/47] snapshot --- tests/snapshots/files__gamma_condition_and-optimize.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/snapshots/files__gamma_condition_and-optimize.snap b/tests/snapshots/files__gamma_condition_and-optimize.snap index 7c5c9df1f..e55e8d259 100644 --- a/tests/snapshots/files__gamma_condition_and-optimize.snap +++ b/tests/snapshots/files__gamma_condition_and-optimize.snap @@ -6,7 +6,7 @@ expression: visualization.result .b1_: c2_: int = const 0; v3_: bool = lt v0 c2_; - v4_: bool = gt v0 c2_; + v4_: bool = lt c2_ v0; c5_: int = const 1; c6_: int = const 3; v7_: int = id c6_;