-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Dataflow analysis framework #1476
base: main
Are you sure you want to change the base?
Changes from all commits
c7a9d89
ac45e53
8adaa6e
098c735
706c892
63bc944
5fa7edb
98bf94a
295ec32
5c8289e
bf173ab
0ae4d19
8608ba9
2dca3e9
51e68ea
8635474
80d5b86
1c8be99
b0afa54
d09a1fe
af8827b
4b61436
8b31d8c
6a72961
780af9b
cabcf04
5e4a04f
1453886
221e96c
cd4e15c
c5ab2a9
6c80acf
636f14d
0acdcc5
1012e0a
6bd8dba
f7d288f
a62eb0f
f0ec237
82a3f22
e6dc114
03ff165
25ed1fb
09911df
248fb07
e2ad079
95e2dd9
7f1e122
faff556
401354d
c468387
88db5b1
738b61b
8f9c1ed
a71ba97
05280a8
96b0856
f21e278
ce53b1c
13f29a9
9f1a5cd
15e642e
514af13
5d86f46
d8c8140
1315685
2aaaeb9
5619761
f3c175c
aad2ef0
0a8cc12
bfcd0a6
248fb23
5b8654e
c40e718
8732a63
346187d
a139f9e
7f2a91a
1680829
2a57a15
fcfcb6b
dcaa928
bcacbcc
5192ed8
e21bbd7
22e0192
cae5e4f
3014827
64b9bb7
8bc5e12
a3a6213
a96ab20
3051183
777694c
5a16e6b
4f31178
2b523c9
1d2cb9b
ee91bbe
e67051f
94cee55
5cf5ff0
7381087
60e33db
ef4f433
5935489
b198681
ed30f80
3f7808a
436b635
0374d13
6a2dd9e
a75fee9
151e571
e15b04d
dc08f0d
436dcd2
e817bbe
b06cfad
fd717be
9b17439
846d1ee
328e7f8
da3c05c
6930ad4
0a3e281
b1e0bfd
355e814
22f3ce8
68b1d48
77a5fa3
2cc62f0
8254771
7e81b15
34e82ed
015707f
ff39f7d
ada7ee1
7c02d41
3d4f016
8bab4d5
3eccadf
0f4fa52
caa8aca
e7f61fc
811802c
3713ea7
d317809
69c3270
dc56686
33a8592
b153ada
5052ac0
ad0c6f2
16a18f4
a0f2b2c
87eb700
a49221b
71ea55d
ea9db2e
df31523
a490874
3af39aa
dc15999
2d81264
b61d252
8cac194
fb3816e
19571f6
69d0f5e
cb60b5b
2624ee8
ec526e8
5650ee4
da2981c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
#![warn(missing_docs)] | ||
//! Dataflow analysis of Hugrs. | ||
|
||
mod datalog; | ||
pub use datalog::Machine; | ||
mod value_row; | ||
|
||
mod results; | ||
pub use results::{AnalysisResults, TailLoopTermination}; | ||
|
||
mod partial_value; | ||
pub use partial_value::{AbstractValue, PartialSum, PartialValue, Sum}; | ||
|
||
use hugr_core::ops::constant::OpaqueValue; | ||
use hugr_core::ops::{ExtensionOp, Value}; | ||
use hugr_core::types::TypeArg; | ||
use hugr_core::{Hugr, HugrView, Node}; | ||
|
||
/// Clients of the dataflow framework (particular analyses, such as constant folding) | ||
/// must implement this trait (including providing an appropriate domain type `V`). | ||
pub trait DFContext<V>: ConstLoader<V> + std::ops::Deref<Target = Self::View> { | ||
/// Type of view contained within this context. (Ideally we'd constrain | ||
/// by `std::ops::Deref<Target: impl HugrView>` but that's not stable yet.) | ||
type View: HugrView; | ||
|
||
/// Given lattice values for each input, update lattice values for the (dataflow) outputs. | ||
/// For extension ops only, excluding [MakeTuple] and [UnpackTuple]. | ||
/// `_outs` is an array with one element per dataflow output, each initialized to [PartialValue::Top] | ||
/// which is the correct value to leave if nothing can be deduced about that output. | ||
/// (The default does nothing, i.e. leaves `Top` for all outputs.) | ||
/// | ||
/// [MakeTuple]: hugr_core::extension::prelude::MakeTuple | ||
/// [UnpackTuple]: hugr_core::extension::prelude::UnpackTuple | ||
fn interpret_leaf_op( | ||
&self, | ||
_node: Node, | ||
_e: &ExtensionOp, | ||
_ins: &[PartialValue<V>], | ||
_outs: &mut [PartialValue<V>], | ||
) { | ||
} | ||
} | ||
|
||
/// Trait for loading [PartialValue]s from constant [Value]s in a Hugr. | ||
/// Implementors will likely want to override some/all of [Self::value_from_opaque], | ||
/// [Self::value_from_const_hugr], and [Self::value_from_function]: the defaults | ||
/// are "correct" but maximally conservative (minimally informative). | ||
pub trait ConstLoader<V> { | ||
/// Produces a [PartialValue] from a constant. The default impl (expected | ||
/// to be appropriate in most cases) traverses [Sum](Value::Sum) constants | ||
/// to their leaves ([Value::Extension] and [Value::Function]), | ||
/// converts these using [Self::value_from_opaque] and [Self::value_from_const_hugr], | ||
/// and builds nested [PartialValue::new_variant] to represent the structure. | ||
fn value_from_const(&self, n: Node, cst: &Value) -> PartialValue<V> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Alternatives include |
||
traverse_value(self, n, &mut Vec::new(), cst) | ||
} | ||
|
||
/// Produces an abstract value from an [OpaqueValue], if possible. | ||
/// The default just returns `None`, which will be interpreted as [PartialValue::Top]. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why don't these functions just return |
||
fn value_from_opaque(&self, _node: Node, _fields: &[usize], _val: &OpaqueValue) -> Option<V> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
None | ||
} | ||
|
||
/// Produces an abstract value from a Hugr in a [Value::Function], if possible. | ||
/// The default just returns `None`, which will be interpreted as [PartialValue::Top]. | ||
fn value_from_const_hugr(&self, _node: Node, _fields: &[usize], _h: &Hugr) -> Option<V> { | ||
None | ||
} | ||
|
||
/// Produces an abstract value from a [FuncDefn] or [FuncDecl] node | ||
/// (that has been loaded via a [LoadFunction]), if possible. | ||
/// The default just returns `None`, which will be interpreted as [PartialValue::Top]. | ||
/// | ||
/// [FuncDefn]: hugr_core::ops::FuncDefn | ||
/// [FuncDecl]: hugr_core::ops::FuncDecl | ||
/// [LoadFunction]: hugr_core::ops::LoadFunction | ||
fn value_from_function(&self, _node: Node, _type_args: &[TypeArg]) -> Option<V> { | ||
None | ||
} | ||
} | ||
|
||
fn traverse_value<V>( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why isn't this a method on |
||
s: &(impl ConstLoader<V> + ?Sized), | ||
n: Node, | ||
fields: &mut Vec<usize>, | ||
cst: &Value, | ||
) -> PartialValue<V> { | ||
match cst { | ||
Value::Sum(hugr_core::ops::constant::Sum { tag, values, .. }) => { | ||
let elems = values.iter().enumerate().map(|(idx, elem)| { | ||
fields.push(idx); | ||
let r = traverse_value(s, n, fields, elem); | ||
fields.pop(); | ||
r | ||
}); | ||
PartialValue::new_variant(*tag, elems) | ||
} | ||
Value::Extension { e } => s | ||
.value_from_opaque(n, fields, e) | ||
.map(PartialValue::from) | ||
.unwrap_or(PartialValue::Top), | ||
Value::Function { hugr } => s | ||
.value_from_const_hugr(n, fields, hugr) | ||
.map(PartialValue::from) | ||
.unwrap_or(PartialValue::Top), | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod test; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't need to provide default implementations for trait methods, you can just write
fn f(...);
instead offn f(...) { }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But this impl is totally ok as a default - it means, I know nothing about any leaf op