1use std::cmp::Reverse;
16use std::collections::{BinaryHeap, HashMap};
17
18pub const CUTS: usize = 8;
20
21pub const MAX_K: usize = 8;
23
24pub type Lit = u32;
26
27pub const FALSE: Lit = 0;
28pub const TRUE: Lit = 1;
29
30pub fn node(l: Lit) -> usize {
31 (l >> 1) as usize
32}
33
34pub fn complemented(l: Lit) -> bool {
35 l & 1 == 1
36}
37
38#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
40pub enum Gate {
41 Constant,
43 Input,
44 And(Lit, Lit),
45 Xor(Lit, Lit),
46}
47
48#[derive(Clone, Debug)]
50pub struct Xag {
51 gates: Vec<Gate>,
52 hash: HashMap<Gate, u32>,
53}
54
55impl Default for Xag {
56 fn default() -> Xag {
57 Xag::new()
58 }
59}
60
61impl Xag {
62 pub fn new() -> Xag {
63 Xag { gates: vec![Gate::Constant], hash: HashMap::new() }
64 }
65
66 pub fn len(&self) -> usize {
67 self.gates.len()
68 }
69
70 pub fn is_empty(&self) -> bool {
71 self.gates.len() == 1
72 }
73
74 pub fn gate(&self, n: usize) -> Gate {
75 self.gates[n]
76 }
77
78 pub fn input(&mut self) -> Lit {
79 self.gates.push(Gate::Input);
80 ((self.gates.len() - 1) as u32) << 1
81 }
82
83 fn hashed(&mut self, g: Gate) -> Lit {
84 if let Some(&n) = self.hash.get(&g) {
85 return n << 1;
86 }
87 let n = self.gates.len() as u32;
88 self.gates.push(g);
89 self.hash.insert(g, n);
90 n << 1
91 }
92
93 pub fn and(&mut self, a: Lit, b: Lit) -> Lit {
94 let (a, b) = if a <= b { (a, b) } else { (b, a) };
95 match (a, b) {
96 (FALSE, _) => FALSE,
97 (TRUE, _) => b,
98 _ if a == b => a,
99 _ if a ^ 1 == b => FALSE,
100 _ => self.hashed(Gate::And(a, b)),
101 }
102 }
103
104 pub fn xor(&mut self, a: Lit, b: Lit) -> Lit {
105 let parity = (a ^ b) & 1;
106 let (a, b) = (a & !1, b & !1);
107 let (a, b) = if a <= b { (a, b) } else { (b, a) };
108 if a == FALSE {
109 return b ^ parity;
110 }
111 if a == b {
112 return FALSE ^ parity;
113 }
114 self.hashed(Gate::Xor(a, b)) ^ parity
115 }
116
117 pub fn or(&mut self, a: Lit, b: Lit) -> Lit {
118 self.and(a ^ 1, b ^ 1) ^ 1
119 }
120
121 pub fn mux(&mut self, s: Lit, t: Lit, e: Lit) -> Lit {
123 let on = self.and(s, t);
124 let off = self.and(s ^ 1, e);
125 self.or(on, off)
126 }
127
128 pub fn simulate(&self, inputs: &[u64]) -> Vec<u64> {
130 let mut v = vec![0u64; self.gates.len()];
131 let lit = |v: &[u64], l: Lit| if complemented(l) { !v[node(l)] } else { v[node(l)] };
132 let mut next = 0;
133 for n in 0..self.gates.len() {
134 v[n] = match self.gates[n] {
135 Gate::Constant => 0,
136 Gate::Input => {
137 next += 1;
138 inputs.get(next - 1).copied().unwrap_or(0)
139 }
140 Gate::And(a, b) => lit(&v, a) & lit(&v, b),
141 Gate::Xor(a, b) => lit(&v, a) ^ lit(&v, b),
142 };
143 }
144 v
145 }
146}
147
148#[derive(Clone, Copy, Debug, PartialEq, Eq)]
150struct Cut {
151 len: u8,
152 leaves: [u32; MAX_K],
153 arrival: u32,
154}
155
156impl Cut {
157 fn leaves(&self) -> &[u32] {
158 &self.leaves[..self.len as usize]
159 }
160
161 fn unit(n: u32) -> Cut {
162 let mut leaves = [0; MAX_K];
163 leaves[0] = n;
164 Cut { len: 1, leaves, arrival: 0 }
165 }
166
167 fn merge(a: &Cut, b: &Cut, k: usize) -> Option<Cut> {
169 let (x, y) = (a.leaves(), b.leaves());
170 let mut out = [0u32; MAX_K];
171 let (mut i, mut j, mut n) = (0, 0, 0);
172 while i < x.len() || j < y.len() {
173 let take = match (x.get(i), y.get(j)) {
174 (Some(&p), Some(&q)) if p == q => {
175 i += 1;
176 j += 1;
177 p
178 }
179 (Some(&p), Some(&q)) if p < q => {
180 i += 1;
181 p
182 }
183 (Some(&p), None) => {
184 i += 1;
185 p
186 }
187 (_, Some(&q)) => {
188 j += 1;
189 q
190 }
191 (None, None) => unreachable!(),
192 };
193 if n == k {
194 return None;
195 }
196 out[n] = take;
197 n += 1;
198 }
199 Some(Cut { len: n as u8, leaves: out, arrival: 0 })
200 }
201}
202
203#[derive(Clone, Debug, PartialEq, Eq)]
205pub struct Lut {
206 pub root: u32,
207 pub leaves: Vec<u32>,
208}
209
210#[derive(Clone, Debug)]
212pub struct Mapping {
213 pub xag: Xag,
215 pub image: Vec<Option<Lit>>,
218 pub origin: Vec<u32>,
221 pub exact: Vec<bool>,
222 pub level: Vec<u32>,
224 pub luts: Vec<Lut>,
226}
227
228struct Builder<'a> {
229 k: usize,
230 old: &'a Xag,
231 xag: Xag,
232 cuts: Vec<Vec<Cut>>,
233 level: Vec<u32>,
234 origin: Vec<u32>,
235 exact: Vec<bool>,
236}
237
238impl Builder<'_> {
239 fn note(&mut self, l: Lit, origin: u32, exact: bool) -> Lit {
241 let n = node(l);
242 if n < self.cuts.len() {
243 return l;
244 }
245 self.origin.push(origin);
246 self.exact.push(exact);
247 let (cuts, level) = match self.xag.gate(n) {
248 Gate::Constant | Gate::Input => (Vec::new(), 0),
249 Gate::And(a, b) | Gate::Xor(a, b) => {
250 let (a, b) = (node(a), node(b));
251 let mut found: Vec<Cut> = Vec::with_capacity(CUTS * 4);
252 let side = |m: usize, cuts: &[Vec<Cut>], level: &[u32]| {
253 let mut unit = Cut::unit(m as u32);
254 unit.arrival = level[m];
255 std::iter::once(unit).chain(cuts[m].iter().copied()).collect::<Vec<_>>()
256 };
257 let (left, right) = (side(a, &self.cuts, &self.level), side(b, &self.cuts, &self.level));
258 for x in &left {
259 for y in &right {
260 if let Some(mut c) = Cut::merge(x, y, self.k) {
261 c.arrival = c.leaves().iter().map(|&m| self.level[m as usize]).max().unwrap_or(0) + 1;
262 if !found.iter().any(|f| f.leaves() == c.leaves()) {
263 found.push(c);
264 }
265 }
266 }
267 }
268 found.sort_by_key(|c| (c.arrival, c.len));
269 found.truncate(CUTS);
270 let level = found.first().map_or(0, |c| c.arrival);
271 (found, level)
272 }
273 };
274 self.cuts.push(cuts);
275 self.level.push(level);
276 l
277 }
278
279 fn input(&mut self, origin: u32) -> Lit {
280 let l = self.xag.input();
281 self.note(l, origin, true)
282 }
283
284 fn gate(&mut self, xor: bool, a: Lit, b: Lit, origin: u32) -> Lit {
285 let l = if xor { self.xag.xor(a, b) } else { self.xag.and(a, b) };
286 self.note(l, origin, false)
287 }
288
289 fn supergate(&mut self, xor: bool, leaves: Vec<Lit>, origin: u32) -> Lit {
291 let mut heap: BinaryHeap<Reverse<(u32, Lit)>> = leaves.into_iter().map(|l| Reverse((self.level[node(l)], l))).collect();
292 loop {
293 let take = heap.len().min(self.k);
294 let mut group: Vec<Lit> = (0..take).map(|_| heap.pop().expect("take ≤ len").0 .1).collect();
295 while group.len() > 1 {
296 group = group.chunks(2).map(|p| if p.len() == 2 { self.gate(xor, p[0], p[1], origin) } else { p[0] }).collect();
297 }
298 let root = group.first().copied().unwrap_or(if xor { FALSE } else { TRUE });
299 if heap.is_empty() {
300 return root;
301 }
302 heap.push(Reverse((self.level[node(root)], root)));
303 }
304 }
305}
306
307pub fn map(xag: &Xag, group: &[u32], outputs: &[Lit], k: usize) -> Mapping {
310 assert!((2..=MAX_K).contains(&k), "a LUT has 2 to {MAX_K} inputs");
311 assert_eq!(group.len(), xag.len(), "a group for every node");
312 let n = xag.len();
313 let mut fanout = vec![0u32; n];
314 let mut reader = vec![usize::MAX; n];
315 for (m, g) in xag.gates.iter().enumerate() {
316 if let Gate::And(a, b) | Gate::Xor(a, b) = *g {
317 for l in [a, b] {
318 fanout[node(l)] += 1;
319 reader[node(l)] = m;
320 }
321 }
322 }
323 for &l in outputs {
324 fanout[node(l)] += 1;
325 reader[node(l)] = usize::MAX;
326 }
327 let inner: Vec<bool> = (0..n)
329 .map(|m| {
330 let r = reader[m];
331 if fanout[m] != 1 || r == usize::MAX || group[r] != group[m] {
332 return false;
333 }
334 match (xag.gates[m], xag.gates[r]) {
335 (Gate::And(..), Gate::And(a, b)) => [a, b].iter().any(|&l| node(l) == m && !complemented(l)),
336 (Gate::Xor(..), Gate::Xor(..)) => true,
337 _ => false,
338 }
339 })
340 .collect();
341 let mut b = Builder { k, old: xag, xag: Xag::new(), cuts: vec![Vec::new()], level: vec![0], origin: vec![0], exact: vec![true] };
342 let mut image: Vec<Option<Lit>> = vec![None; n];
343 image[0] = Some(FALSE);
344 for m in 1..n {
345 if inner[m] {
346 continue;
347 }
348 let gate = b.old.gates[m];
349 let img = match gate {
350 Gate::Constant => FALSE,
351 Gate::Input => b.input(m as u32),
352 Gate::And(x, y) | Gate::Xor(x, y) => {
353 let xor = matches!(gate, Gate::Xor(..));
354 let mut parity = 0;
355 let mut leaves = Vec::new();
356 let mut stack = vec![x, y];
357 while let Some(l) = stack.pop() {
358 let f = node(l);
359 if inner[f] {
360 if xor {
361 parity ^= l & 1;
362 }
363 if let Gate::And(p, q) | Gate::Xor(p, q) = b.old.gates[f] {
364 stack.push(p);
365 stack.push(q);
366 }
367 continue;
368 }
369 let mapped = image[f].expect("a leaf comes before its supergate") ^ (l & 1);
370 if xor {
371 parity ^= mapped & 1;
372 leaves.push(mapped & !1);
373 } else {
374 leaves.push(mapped);
375 }
376 }
377 leaves.sort_unstable();
378 if xor {
379 let mut kept: Vec<Lit> = Vec::with_capacity(leaves.len());
380 for l in leaves {
381 if kept.last() == Some(&l) {
382 kept.pop();
383 } else {
384 kept.push(l);
385 }
386 }
387 leaves = kept;
388 } else {
389 leaves.dedup();
390 }
391 let out = if !xor && leaves.windows(2).any(|w| w[0] ^ 1 == w[1]) || !xor && leaves.contains(&FALSE) {
392 FALSE
393 } else {
394 leaves.retain(|&l| l != if xor { FALSE } else { TRUE });
395 b.supergate(xor, leaves, m as u32) ^ parity
396 };
397 let n_out = node(out);
398 if n_out < b.exact.len() && b.origin[n_out] == m as u32 {
399 b.exact[n_out] = true;
400 }
401 out
402 }
403 };
404 image[m] = Some(img);
405 }
406 let size = b.xag.len();
407 let mut required = vec![false; size];
408 for &l in outputs {
409 if let Some(img) = image[node(l)] {
410 required[node(img)] = true;
411 }
412 }
413 let mut luts = Vec::new();
414 for m in (1..size).rev() {
415 if !required[m] {
416 continue;
417 }
418 if let Some(best) = b.cuts[m].first() {
419 for &leaf in best.leaves() {
420 required[leaf as usize] = true;
421 }
422 luts.push(Lut { root: m as u32, leaves: best.leaves().to_vec() });
423 }
424 }
425 Mapping { xag: b.xag, image, origin: b.origin, exact: b.exact, level: b.level, luts }
426}
427
428pub fn function(xag: &Xag, root: u32, leaves: &[u32]) -> u64 {
431 assert!(leaves.len() <= 6, "a table of at most six inputs");
432 const VARS: [u64; 6] = [
433 0xAAAA_AAAA_AAAA_AAAA,
434 0xCCCC_CCCC_CCCC_CCCC,
435 0xF0F0_F0F0_F0F0_F0F0,
436 0xFF00_FF00_FF00_FF00,
437 0xFFFF_0000_FFFF_0000,
438 0xFFFF_FFFF_0000_0000,
439 ];
440 let mut value: HashMap<u32, u64> = leaves.iter().enumerate().map(|(i, &l)| (l, VARS[i])).collect();
441 value.entry(0).or_insert(0);
442 let mut stack = vec![root];
443 while let Some(&n) = stack.last() {
444 if value.contains_key(&n) {
445 stack.pop();
446 continue;
447 }
448 let (a, b) = match xag.gate(n as usize) {
449 Gate::And(a, b) | Gate::Xor(a, b) => (a, b),
450 Gate::Input | Gate::Constant => panic!("node {n} is below the cut"),
451 };
452 let missing: Vec<u32> = [a, b].iter().map(|&l| node(l) as u32).filter(|m| !value.contains_key(m)).collect();
453 if !missing.is_empty() {
454 stack.extend(missing);
455 continue;
456 }
457 let lit = |l: Lit| if complemented(l) { !value[&(node(l) as u32)] } else { value[&(node(l) as u32)] };
458 let v = match xag.gate(n as usize) {
459 Gate::And(..) => lit(a) & lit(b),
460 _ => lit(a) ^ lit(b),
461 };
462 value.insert(n, v);
463 stack.pop();
464 }
465 let width = 1u32 << leaves.len();
466 let mask = if width == 64 { u64::MAX } else { (1u64 << width) - 1 };
467 value[&root] & mask
468}
469
470#[cfg(test)]
471#[path = "../../../logicaffeine_tests/unit/logicaffeine_compile/codegen_sva/lutmap/tests.rs"]
472mod tests;