1use crate::aig::gate::PirNodeIds;
4use crate::aig::{AigOperand, AigRef, GateFn};
5use anyhow::Result;
6use std::fmt::{self, Debug};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
11pub enum TransformKind {
12 SwapOperands,
13 ToggleOutputBit,
14 DoubleNegate,
15 InsertRedundantAnd,
16 RemoveRedundantAnd,
17 DuplicateGate,
18 UnduplicateGate,
19 InsertFalseAnd,
20 RemoveFalseAnd,
21 InsertTrueAnd,
22 RemoveTrueAnd,
23 SwapOutputBits,
24 RotateAndRight,
25 RotateAndLeft,
26 AndAbsorbRight,
27 AndAbsorbLeft,
28 BalanceAndTree,
29 UnbalanceAndTree,
30 ToggleOperandNegation,
31 RewireOperand,
32 PushNegation,
33 MergeEquivLeaves,
34 SplitFanout,
35 MergeFanout,
36 FactorSharedAnd,
37 UnfactorSharedAnd,
38}
39
40impl fmt::Display for TransformKind {
41 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42 match self {
43 TransformKind::SwapOperands => write!(f, "SwapOp"),
44 TransformKind::ToggleOutputBit => write!(f, "ToggleOut"),
45 TransformKind::DoubleNegate => write!(f, "DblNeg"),
46 TransformKind::InsertRedundantAnd => write!(f, "InsRedAnd"),
47 TransformKind::RemoveRedundantAnd => write!(f, "RemRedAnd"),
48 TransformKind::DuplicateGate => write!(f, "DupGate"),
49 TransformKind::UnduplicateGate => write!(f, "UndupGate"),
50 TransformKind::InsertFalseAnd => write!(f, "InsFalseAnd"),
51 TransformKind::RemoveFalseAnd => write!(f, "RemFalseAnd"),
52 TransformKind::InsertTrueAnd => write!(f, "InsTrueAnd"),
53 TransformKind::RemoveTrueAnd => write!(f, "RemTrueAnd"),
54 TransformKind::SwapOutputBits => write!(f, "SwapOutBits"),
55 TransformKind::RotateAndRight => write!(f, "RotAndR"),
56 TransformKind::RotateAndLeft => write!(f, "RotAndL"),
57 TransformKind::AndAbsorbRight => write!(f, "AbsorbR"),
58 TransformKind::AndAbsorbLeft => write!(f, "AbsorbL"),
59 TransformKind::BalanceAndTree => write!(f, "BalTree"),
60 TransformKind::UnbalanceAndTree => write!(f, "UnbalTree"),
61 TransformKind::ToggleOperandNegation => write!(f, "TogOpNeg"),
62 TransformKind::RewireOperand => write!(f, "RewireOp"),
63 TransformKind::PushNegation => write!(f, "PushNeg"),
64 TransformKind::MergeEquivLeaves => write!(f, "MergeLeaves"),
65 TransformKind::SplitFanout => write!(f, "SplitFan"),
66 TransformKind::MergeFanout => write!(f, "MergeFan"),
67 TransformKind::FactorSharedAnd => write!(f, "FactorAnd"),
68 TransformKind::UnfactorSharedAnd => write!(f, "UnfactorAnd"),
69 }
70 }
71}
72
73#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
75pub enum TransformDirection {
76 Forward,
77 Backward,
78}
79
80#[derive(Debug, Clone)]
83pub enum TransformLocation {
84 Node(AigRef),
85 Operand(AigRef, bool),
86 OutputPortBit {
87 output_idx: usize,
88 bit_idx: usize,
89 },
90 OperandReplacement {
91 parent: AigRef,
92 is_rhs: bool,
93 old_op: AigOperand,
94 new_op: AigOperand,
95 },
96 SwapOutputBits {
97 out_a_idx: usize,
98 bit_a_idx: usize,
99 out_b_idx: usize,
100 bit_b_idx: usize,
101 },
102 OperandTarget {
103 parent: AigRef,
104 is_rhs: bool,
105 old_op: AigOperand,
106 },
107 FanoutEdge {
108 parent: AigRef,
109 child: AigRef,
110 },
111}
112
113pub trait Transform: Debug + Send + Sync {
115 fn kind(&self) -> TransformKind;
117
118 fn display_name(&self) -> String {
121 format!("{:?}", self.kind())
122 }
123
124 fn find_candidates(
127 &mut self,
128 g: &GateFn,
129 direction: TransformDirection,
130 ) -> Vec<TransformLocation>;
131
132 fn apply(
137 &self,
138 g: &mut GateFn,
139 candidate_location: &TransformLocation,
140 direction: TransformDirection,
141 ) -> Result<()>;
142
143 fn always_equivalent(&self) -> bool;
147}
148
149pub(crate) fn collect_node_provenance(g: &GateFn, source_refs: &[AigRef]) -> PirNodeIds {
152 let mut pir_node_ids = PirNodeIds::new();
153 for source_ref in source_refs {
154 for pir_node_id in g.gates[source_ref.id].get_pir_node_ids() {
155 match pir_node_ids.binary_search(pir_node_id) {
156 Ok(_) => {}
157 Err(index) => pir_node_ids.insert(index, *pir_node_id),
158 }
159 }
160 }
161 pir_node_ids
162}
163
164pub(crate) fn union_node_provenance_into_node(
166 g: &mut GateFn,
167 dst_ref: AigRef,
168 source_refs: &[AigRef],
169) {
170 let pir_node_ids = collect_node_provenance(g, source_refs);
171 g.gates[dst_ref.id].try_add_pir_node_ids(pir_node_ids.as_slice());
172}