Skip to content

Commit f27d970

Browse files
committed
add multi-event support
1 parent 3ea8a3c commit f27d970

File tree

5 files changed

+176
-42
lines changed

5 files changed

+176
-42
lines changed

crates/filament/src/ir_passes/schedule/solve.rs

Lines changed: 131 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
use super::CombDataflow;
22
use crate::ir_visitor::{Action, Construct, Visitor, VisitorData};
3-
use core::time;
43
use easy_smt::{self as smt, SExpr, SExprData};
5-
use fil_ir::{self as ir, AddCtx, Ctx, DisplayCtx, MutCtx, PortOwner};
4+
use fil_ir::{self as ir, AddCtx, Ctx, DisplayCtx, MutCtx, PortOwner, Subst};
65
use fil_utils::{AttrCtx, CompNum};
76
use itertools::Itertools;
87
use std::{collections::HashMap, fs};
@@ -102,6 +101,128 @@ impl Solve {
102101
self.sol.assert(self.sol.not(equalities)).unwrap();
103102
}
104103
}
104+
105+
pub fn timesub_to_sexp(
106+
&self,
107+
ctx: &ir::Component,
108+
event_bind: &ir::SparseInfoMap<ir::Event, SExpr>,
109+
time_sub: &ir::TimeSub,
110+
) -> SExpr {
111+
match time_sub {
112+
fil_ir::TimeSub::Unit(idx) => {
113+
self.expr_to_sexp(ctx, event_bind, *idx)
114+
}
115+
fil_ir::TimeSub::Sym { l, r } => {
116+
let l = self.time_to_sexp(ctx, event_bind, *l);
117+
let r = self.time_to_sexp(ctx, event_bind, *r);
118+
self.sol.sub(l, r)
119+
}
120+
}
121+
}
122+
123+
pub fn time_to_sexp(
124+
&self,
125+
ctx: &ir::Component,
126+
event_bind: &ir::SparseInfoMap<ir::Event, SExpr>,
127+
time: ir::TimeIdx,
128+
) -> SExpr {
129+
let ir::Time { event, offset } = ctx.get(time);
130+
131+
let offset = self.expr_to_sexp(ctx, event_bind, *offset);
132+
let event = *event_bind.get(*event);
133+
134+
self.sol.plus(event, offset)
135+
}
136+
137+
/// Fold an expression to an SExpr
138+
pub fn expr_to_sexp(
139+
&self,
140+
ctx: &ir::Component,
141+
event_bind: &ir::SparseInfoMap<ir::Event, SExpr>,
142+
expr: ir::ExprIdx,
143+
) -> SExpr {
144+
match ctx.get(expr) {
145+
fil_ir::Expr::Concrete(n) => self.sol.numeral(*n),
146+
fil_ir::Expr::Bin { op, lhs, rhs } => {
147+
let lhs = self.expr_to_sexp(ctx, event_bind, *lhs);
148+
let rhs = self.expr_to_sexp(ctx, event_bind, *rhs);
149+
match op {
150+
fil_ast::Op::Add => self.sol.plus(lhs, rhs),
151+
fil_ast::Op::Sub => self.sol.sub(lhs, rhs),
152+
fil_ast::Op::Mul => self.sol.times(lhs, rhs),
153+
fil_ast::Op::Div => self.sol.div(lhs, rhs),
154+
fil_ast::Op::Mod => self.sol.modulo(lhs, rhs),
155+
}
156+
}
157+
fil_ir::Expr::If { cond, then, alt } => {
158+
let cond = self.prop_to_sexp(ctx, event_bind, *cond);
159+
let then = self.expr_to_sexp(ctx, event_bind, *then);
160+
let alt = self.expr_to_sexp(ctx, event_bind, *alt);
161+
self.sol.ite(cond, then, alt)
162+
}
163+
fil_ir::Expr::Fn { .. } => unreachable!(
164+
"Constraints on scheduled components do not support custom function calls."
165+
),
166+
fil_ir::Expr::Param(_) => {
167+
unreachable!("Parameters should have been monomorphized")
168+
}
169+
}
170+
}
171+
172+
/// Fold a proposition on events to an SExpr
173+
pub fn prop_to_sexp(
174+
&self,
175+
ctx: &ir::Component,
176+
event_bind: &ir::SparseInfoMap<ir::Event, SExpr>,
177+
prop: ir::PropIdx,
178+
) -> SExpr {
179+
match ctx.get(prop) {
180+
fil_ir::Prop::True => self.sol.atom("true"),
181+
fil_ir::Prop::False => self.sol.atom("false"),
182+
fil_ir::Prop::Cmp(ir::CmpOp { op, lhs, rhs }) => {
183+
let lhs = self.expr_to_sexp(ctx, event_bind, *lhs);
184+
let rhs = self.expr_to_sexp(ctx, event_bind, *rhs);
185+
match op {
186+
fil_ir::Cmp::Gt => self.sol.gt(lhs, rhs),
187+
fil_ir::Cmp::Gte => self.sol.gte(lhs, rhs),
188+
fil_ir::Cmp::Eq => self.sol.eq(lhs, rhs),
189+
}
190+
}
191+
fil_ir::Prop::TimeCmp(ir::CmpOp { op, lhs, rhs }) => {
192+
let lhs = self.time_to_sexp(ctx, event_bind, *lhs);
193+
let rhs = self.time_to_sexp(ctx, event_bind, *rhs);
194+
match op {
195+
fil_ir::Cmp::Gt => self.sol.gt(lhs, rhs),
196+
fil_ir::Cmp::Gte => self.sol.gte(lhs, rhs),
197+
fil_ir::Cmp::Eq => self.sol.eq(lhs, rhs),
198+
}
199+
}
200+
fil_ir::Prop::TimeSubCmp(ir::CmpOp { op, lhs, rhs }) => {
201+
let lhs = self.timesub_to_sexp(ctx, event_bind, lhs);
202+
let rhs = self.timesub_to_sexp(ctx, event_bind, rhs);
203+
match op {
204+
fil_ir::Cmp::Gt => self.sol.gt(lhs, rhs),
205+
fil_ir::Cmp::Gte => self.sol.gte(lhs, rhs),
206+
fil_ir::Cmp::Eq => self.sol.eq(lhs, rhs),
207+
}
208+
}
209+
fil_ir::Prop::Not(idx) => {
210+
self.sol.not(self.prop_to_sexp(ctx, event_bind, *idx))
211+
}
212+
fil_ir::Prop::And(idx, idx1) => self.sol.and(
213+
self.prop_to_sexp(ctx, event_bind, *idx),
214+
self.prop_to_sexp(ctx, event_bind, *idx1),
215+
),
216+
fil_ir::Prop::Or(idx, idx1) => self.sol.or(
217+
self.prop_to_sexp(ctx, event_bind, *idx),
218+
self.prop_to_sexp(ctx, event_bind, *idx1),
219+
),
220+
fil_ir::Prop::Implies(idx, idx1) => self.sol.imp(
221+
self.prop_to_sexp(ctx, event_bind, *idx),
222+
self.prop_to_sexp(ctx, event_bind, *idx1),
223+
),
224+
}
225+
}
105226
}
106227

107228
impl Construct for Solve {
@@ -270,7 +391,9 @@ impl Visitor for Solve {
270391
// Intern all the constraints for the events
271392
let foreign_comp = data.ctx().get(inv.inst.comp(comp));
272393
for &constraint in foreign_comp.get_event_asserts() {
273-
let prop = foreign_comp.get(constraint);
394+
self.sol
395+
.assert(self.prop_to_sexp(foreign_comp, &events, constraint))
396+
.unwrap();
274397
}
275398

276399
for pidx in inv.ports.iter() {
@@ -280,32 +403,26 @@ impl Visitor for Solve {
280403
ir::PortOwner::Inv {
281404
base: foreign_pidx, ..
282405
},
283-
live:
284-
ir::Liveness {
285-
range: ir::Range { start, end },
286-
..
287-
},
288406
..
289407
} = port
290408
else {
291409
unreachable!("Port {} is not owned by an invocation", pidx)
292410
};
293411

294-
// Find the events associated with the start and end of the port
295-
let start_expr = *events.get(comp.get(*start).event);
296-
let end_expr = *events.get(comp.get(*end).event);
297-
298-
let (start, end) = foreign_pidx.apply(
412+
let (start_expr, end_expr, start, end) = foreign_pidx.apply(
299413
|p, foreign_comp| {
300414
let ir::Range { start, end } =
301415
foreign_comp.get(p).live.range;
302416

417+
let start_expr = *events.get(foreign_comp.get(start).event);
418+
let end_expr = *events.get(foreign_comp.get(end).event);
419+
303420
let start =
304421
foreign_comp.get(start).offset.concrete(foreign_comp);
305422
let end =
306423
foreign_comp.get(end).offset.concrete(foreign_comp);
307424

308-
(start, end)
425+
(start_expr, end_expr, start, end)
309426
},
310427
data.ctx(),
311428
);

crates/ir/src/utils/subst.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,15 @@ where
8181
}
8282
}
8383

84+
impl<K, V> FromIterator<(K, V)> for Bind<K, V>
85+
where
86+
K: Eq,
87+
{
88+
fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
89+
Self(iter.into_iter().collect())
90+
}
91+
}
92+
8493
/// A substitution for a type `T` that contains type `K` inside it.
8594
/// Substitutions cannot be applied with a type that implements [Ctx].
8695
pub struct Subst<'a, T, K, V>

fud/filament.py

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
from fud import errors
99
from fud.stages import Stage, SourceType, Source
10-
from fud.utils import shell, TmpDir,unwrap_or
10+
from fud.utils import shell, TmpDir, unwrap_or
1111
from enum import Enum
1212

1313

@@ -115,26 +115,32 @@ def transform_data(data_path, dir):
115115
for i in range(len(data_dict[key])):
116116
val = data_dict[key][i]
117117
# if it is a string, check if it is in binary or hex
118-
if isinstance(val,str):
119-
if val.startswith('0b'): # binary format
118+
if isinstance(val, str):
119+
if val.startswith("0b"): # binary format
120120
binary_data = val[2:]
121121
try:
122-
conv = int(binary_data,2)
122+
conv = int(binary_data, 2)
123123
except ValueError:
124-
raise errors.InvalidNumericType("\"" + str(val) + "\"" + " in " + data)
125-
elif val.startswith('0x'): # hex format
124+
raise errors.InvalidNumericType(
125+
'"' + str(val) + '"' + " in " + data
126+
)
127+
elif val.startswith("0x"): # hex format
126128
binary_data = val[2:]
127129
try:
128-
conv = int(binary_data,16)
130+
conv = int(binary_data, 16)
129131
except ValueError:
130-
raise errors.InvalidNumericType("\"" + str(val) + "\"" + " in " + data)
131-
else: # none of the above -> unsupported
132-
raise errors.InvalidNumericType("\"" + str(val) + "\"" + " in " + data)
133-
else: # already in decimal
132+
raise errors.InvalidNumericType(
133+
'"' + str(val) + '"' + " in " + data
134+
)
135+
else: # none of the above -> unsupported
136+
raise errors.InvalidNumericType(
137+
'"' + str(val) + '"' + " in " + data
138+
)
139+
else: # already in decimal
134140
conv = val
135141
# update info in json
136142
data_dict[key][i] = conv
137-
json_obj = json.dumps(data_dict,indent=4)
143+
json_obj = json.dumps(data_dict, indent=4)
138144
file_new.write(json_obj)
139145
return Path(file_new.name).resolve()
140146

@@ -164,18 +170,15 @@ def mktmp() -> SourceType.Directory:
164170
return TmpDir()
165171

166172
@builder.step()
167-
def data_gen(file: SourceType.Path, dir: SourceType.Directory) -> SourceType.Stream:
173+
def data_gen(
174+
file: SourceType.Path, dir: SourceType.Directory
175+
) -> SourceType.Stream:
168176
"""
169177
Generate data file in dir with binary/hex converted to decimal
170178
"""
171179
data_transformed = transform_data(file, dir)
172-
cmd = " ".join(
173-
[
174-
"cat ",
175-
"{path}"
176-
]
177-
)
178-
return shell(cmd.format(path = data_transformed))
180+
cmd = " ".join(["cat ", "{path}"])
181+
return shell(cmd.format(path=data_transformed))
179182

180183
@builder.step()
181184
def interface_gen(file: SourceType.Path) -> SourceType.Stream:
@@ -303,7 +306,7 @@ def read_vcd(dir: SourceType.String) -> SourceType.String:
303306

304307
# Generate modified data file
305308
data_stream = data_gen(data, dir)
306-
data_path = self.save_file(builder,data_stream,dir,"data_1.json")
309+
data_path = self.save_file(builder, data_stream, dir, "data_1.json")
307310

308311
# Run the program
309312
out = run(dir, interface_path, data_path)

tests/schedule/add-tree.expect

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
{"out": {"0": [36]}, "cycles": 11}
2+

tests/schedule/add-tree.fil.data

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,26 @@
11
{
22
"in0": [
3-
1,
3+
1
44
],
55
"in1": [
6-
1,
6+
2
7+
],
8+
"in2": [
9+
3
710
],
811
"in3": [
9-
1,
12+
4
1013
],
1114
"in4": [
12-
1,
15+
5
1316
],
1417
"in5": [
15-
1,
18+
6
1619
],
1720
"in6": [
18-
1,
21+
7
1922
],
2023
"in7": [
21-
1,
24+
8
2225
]
2326
}

0 commit comments

Comments
 (0)