Skip to content

Commit 9fbe500

Browse files
authored
Refactor driver optimization strategies (#147)
1 parent bf120e8 commit 9fbe500

File tree

2 files changed

+90
-37
lines changed

2 files changed

+90
-37
lines changed

src/bin/optcell.rs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use clap::Parser;
22
use egg::{FromOpError, RecExpr, RecExprParseError};
33
use lut_synth::{
4-
asic::{CellAnalysis, CellLang, CellRpt, asic_rewrites},
4+
asic::{CellAnalysis, CellLang, CellRpt, asic_rewrites, get_boolean_algebra_rewrites},
55
driver::{SynthRequest, process_string_expression, simple_reader},
66
verilog::SVModule,
77
};
@@ -56,7 +56,7 @@ struct Args {
5656
#[arg(short = 'f', long, default_value_t = false)]
5757
verify: bool,
5858

59-
/// Don't canonicalize the input expression
59+
/// Only do algebraic simplification
6060
#[arg(short = 'c', long, default_value_t = false)]
6161
canonicalize: bool,
6262

@@ -107,13 +107,20 @@ fn main() -> std::io::Result<()> {
107107

108108
let buf = simple_reader(args.command, args.input)?;
109109

110-
let rules = asic_rewrites();
110+
let rules = if args.canonicalize {
111+
get_boolean_algebra_rewrites()
112+
} else {
113+
asic_rewrites()
114+
};
111115

112116
if args.verbose {
113117
eprintln!("INFO: Running with {} rewrite rules", rules.len());
114118
}
115119

116-
let req = SynthRequest::default().with_rules(rules).with_k(args.k);
120+
let req = SynthRequest::default()
121+
.with_rules(rules)
122+
.with_k(args.k)
123+
.without_canonicalization();
117124

118125
let req = match (args.timeout, args.node_limit, args.iter_limit) {
119126
(None, None, None) => req.with_joint_limits(2, 20_000, 9),
@@ -134,12 +141,6 @@ fn main() -> std::io::Result<()> {
134141
req
135142
};
136143

137-
let req = if args.canonicalize {
138-
req
139-
} else {
140-
req.without_canonicalization()
141-
};
142-
143144
let req = if args.verbose { req.with_proof() } else { req };
144145

145146
#[cfg(feature = "graph_dumps")]
@@ -148,10 +149,12 @@ fn main() -> std::io::Result<()> {
148149
None => req,
149150
};
150151

151-
let req = if args.min_depth {
152+
let req = if args.canonicalize {
153+
req.with_ast_size()
154+
} else if args.min_depth {
152155
req.with_min_depth()
153156
} else {
154-
req.with_k(args.k)
157+
req.with_area()
155158
};
156159

157160
#[cfg(feature = "exactness")]

src/driver.rs

Lines changed: 75 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -337,10 +337,11 @@ enum BuildStrat {
337337
Custom(u64, usize, usize),
338338
}
339339

340-
/// An enum for the extraction strategies used to synthesize LUT networks.
341-
/// Only [ExtractStrat::Exact] uses ILP.
340+
/// An enum for the optimization strategies used to synthesize LUT/cell networks.
342341
#[derive(Debug, Clone)]
343-
enum ExtractStrat {
342+
enum OptStrat {
343+
/// Extract the circuit by the syntax of the expression
344+
AstSize,
344345
/// Extract the cirucit using exact cell areas.
345346
Area,
346347
/// Extract maximum circuit depth (RAM bomb).
@@ -353,8 +354,15 @@ enum ExtractStrat {
353354
CellCountRegWeighted(usize, u64),
354355
/// Disassemble into set of logic gates.
355356
Disassemble(HashSet<String>),
356-
#[cfg(feature = "exactness")]
357-
/// Extract LUTs exactly using ILP with timeout in seconds.
357+
}
358+
359+
/// An enum for the extraction strategies used to synthesize LUT/cell networks.
360+
#[derive(Debug, Clone)]
361+
enum ExtractStrat {
362+
/// Use greedy extraction algorithm.
363+
Greedy,
364+
#[allow(dead_code)]
365+
/// Use exact ILP extraction with timeout in seconds.
358366
Exact(u64),
359367
}
360368

@@ -366,7 +374,7 @@ pub const GATE_WHITELIST: [&str; 9] = [
366374
"MUX", "AND", "OR", "XOR", "NOT", "INV", "REG", "NAND", "NOR",
367375
];
368376

369-
impl ExtractStrat {
377+
impl OptStrat {
370378
/// Create an extraction strategy from a comma-separated list of gates.
371379
/// For example, `list` can be `"MUX,AND,NOT"`.
372380
pub fn from_gate_set(list: &str) -> Result<Self, String> {
@@ -384,7 +392,7 @@ impl ExtractStrat {
384392
));
385393
}
386394
}
387-
Ok(ExtractStrat::Disassemble(gates))
395+
Ok(OptStrat::Disassemble(gates))
388396
}
389397
}
390398

@@ -481,6 +489,9 @@ where
481489
/// The rewrite rules used to simplify the expression.
482490
rules: Vec<Rewrite<L, A>>,
483491

492+
/// The optimization strategy to use.
493+
opt_strat: OptStrat,
494+
484495
/// The extraction strategy to use.
485496
extract_strat: ExtractStrat,
486497

@@ -522,7 +533,8 @@ impl<L: Language, A: Analysis<L>> std::default::Default for SynthRequest<L, A> {
522533
Self {
523534
expr: RecExpr::default(),
524535
rules: Vec::new(),
525-
extract_strat: ExtractStrat::CellCount(6),
536+
opt_strat: OptStrat::CellCount(6),
537+
extract_strat: ExtractStrat::Greedy,
526538
build_strat: BuildStrat::Custom(10, 20_000, 16),
527539
no_canonicalize: false,
528540
assert_sat: false,
@@ -543,6 +555,7 @@ impl<L: Language, A: Analysis<L> + std::clone::Clone> std::clone::Clone for Synt
543555
Self {
544556
expr: self.expr.clone(),
545557
rules: self.rules.clone(),
558+
opt_strat: self.opt_strat.clone(),
546559
extract_strat: self.extract_strat.clone(),
547560
build_strat: self.build_strat.clone(),
548561
no_canonicalize: self.no_canonicalize,
@@ -567,28 +580,40 @@ where
567580
/// Request greedy extraction of cells/LUTs with at most `k` inputs.
568581
pub fn with_k(self, k: usize) -> Self {
569582
Self {
570-
extract_strat: ExtractStrat::CellCount(k),
583+
opt_strat: OptStrat::CellCount(k),
584+
extract_strat: ExtractStrat::Greedy,
571585
..self
572586
}
573587
}
574588

575589
/// Request greedy extraction of cells/LUTs with at most `k` inputs and registers with weight `w`.
576590
pub fn with_klut_regw(self, k: usize, w: u64) -> Self {
577591
Self {
578-
extract_strat: ExtractStrat::CellCountRegWeighted(k, w),
592+
opt_strat: OptStrat::CellCountRegWeighted(k, w),
593+
extract_strat: ExtractStrat::Greedy,
579594
..self
580595
}
581596
}
582597

583598
/// Request greedy extraction using exact cell areas.
584599
pub fn with_area(self) -> Self {
585600
Self {
586-
extract_strat: ExtractStrat::Area,
601+
opt_strat: OptStrat::Area,
602+
extract_strat: ExtractStrat::Greedy,
603+
..self
604+
}
605+
}
606+
607+
/// Request greedy extraction by syntax complexity.
608+
pub fn with_ast_size(self) -> Self {
609+
Self {
610+
opt_strat: OptStrat::AstSize,
611+
extract_strat: ExtractStrat::Greedy,
587612
..self
588613
}
589614
}
590615

591-
/// Request exact LUT extraction using ILP with `timeout` in seconds.
616+
/// Request exact extraction using ILP with `timeout` in seconds.
592617
#[cfg(feature = "exactness")]
593618
pub fn with_exactness(self, timeout: u64) -> Self {
594619
Self {
@@ -600,31 +625,35 @@ where
600625
/// Extract based on minimum circuit depth.
601626
pub fn with_min_depth(self) -> Self {
602627
Self {
603-
extract_strat: ExtractStrat::MinDepth,
628+
opt_strat: OptStrat::MinDepth,
629+
extract_strat: ExtractStrat::Greedy,
604630
..self
605631
}
606632
}
607633

608-
/// Extract based on maximum circuit depth.
634+
/// Extract based on maximum circuit depth. *Does not work with cycles in e-graph.*
609635
pub fn with_max_depth(self) -> Self {
610636
Self {
611-
extract_strat: ExtractStrat::MaxDepth,
637+
opt_strat: OptStrat::MaxDepth,
638+
extract_strat: ExtractStrat::Greedy,
612639
..self
613640
}
614641
}
615642

616643
/// Extract by disassembling into basic logic gates. The exact list can be found at [GATE_WHITELIST].
617644
pub fn with_disassembler(self) -> Self {
618645
Self {
619-
extract_strat: ExtractStrat::from_gate_set(GATE_WHITELIST_STR).unwrap(),
646+
opt_strat: OptStrat::from_gate_set(GATE_WHITELIST_STR).unwrap(),
647+
extract_strat: ExtractStrat::Greedy,
620648
..self
621649
}
622650
}
623651

624652
/// Extract by disassembling into logic gates in the `list`. Elements in the list must be matched against elements in [GATE_WHITELIST].
625653
pub fn with_disassembly_into(self, list: &str) -> Result<Self, String> {
626654
Ok(Self {
627-
extract_strat: ExtractStrat::from_gate_set(list)?,
655+
opt_strat: OptStrat::from_gate_set(list)?,
656+
extract_strat: ExtractStrat::Greedy,
628657
..self
629658
})
630659
}
@@ -1006,24 +1035,45 @@ where
10061035
where
10071036
R: Report<L>,
10081037
{
1009-
match self.extract_strat.to_owned() {
1010-
ExtractStrat::Area => self.greedy_extract_with(L::exact_area_cost_fn()),
1011-
ExtractStrat::MinDepth => self.greedy_extract_with(L::depth_cost_fn()),
1012-
ExtractStrat::MaxDepth => {
1038+
match (self.opt_strat.to_owned(), self.extract_strat.to_owned()) {
1039+
(OptStrat::AstSize, ExtractStrat::Greedy) => self.greedy_extract_with(egg::AstSize),
1040+
(OptStrat::Area, ExtractStrat::Greedy) => {
1041+
self.greedy_extract_with(L::exact_area_cost_fn())
1042+
}
1043+
(OptStrat::MinDepth, ExtractStrat::Greedy) => {
1044+
self.greedy_extract_with(L::depth_cost_fn())
1045+
}
1046+
(OptStrat::MaxDepth, ExtractStrat::Greedy) => {
10131047
eprintln!("WARNING: Maximizing cost on e-graphs with cycles will crash.");
10141048
self.greedy_extract_with(NegativeCostFn::new(L::depth_cost_fn()))
10151049
}
1016-
ExtractStrat::CellCount(k) => self.greedy_extract_with(L::cell_cost_fn(k)),
1017-
ExtractStrat::CellCountRegWeighted(k, w) => {
1050+
(OptStrat::CellCount(k), ExtractStrat::Greedy) => {
1051+
self.greedy_extract_with(L::cell_cost_fn(k))
1052+
}
1053+
(OptStrat::CellCountRegWeighted(k, w), ExtractStrat::Greedy) => {
10181054
self.greedy_extract_with(L::cell_cost_with_reg_weight_fn(k, w))
10191055
}
1020-
ExtractStrat::Disassemble(set) => self.greedy_extract_with(L::filter_cost_fn(set)),
1056+
(OptStrat::Disassemble(set), ExtractStrat::Greedy) => {
1057+
self.greedy_extract_with(L::filter_cost_fn(set))
1058+
}
1059+
#[cfg(feature = "exactness")]
1060+
(OptStrat::CellCountRegWeighted(6, 1), ExtractStrat::Exact(t)) => {
1061+
self.extract_with(|egraph, root| {
1062+
eprintln!("INFO: ILP ON");
1063+
let mut e = egg::LpExtractor::new(egraph, egg::AstSize);
1064+
L::canonicalize_expr(e.timeout(t as f64).solve(root))
1065+
})
1066+
}
10211067
#[cfg(feature = "exactness")]
1022-
ExtractStrat::Exact(t) => self.extract_with(|egraph, root| {
1068+
(OptStrat::AstSize, ExtractStrat::Exact(t)) => self.extract_with(|egraph, root| {
10231069
eprintln!("INFO: ILP ON");
10241070
let mut e = egg::LpExtractor::new(egraph, egg::AstSize);
10251071
L::canonicalize_expr(e.timeout(t as f64).solve(root))
10261072
}),
1073+
_ => Err(format!(
1074+
"{:?} optimization strategy is incomptabile with {:?} extraction.",
1075+
self.opt_strat, self.extract_strat
1076+
)),
10271077
}
10281078
}
10291079
}

0 commit comments

Comments
 (0)