lift_opt/
layout_mapping.rs1use lift_core::context::Context;
2use lift_core::pass::{AnalysisCache, Pass, PassResult};
3
4#[derive(Debug)]
8pub struct LayoutMapping;
9
10impl Pass for LayoutMapping {
11 fn name(&self) -> &str {
12 "layout-mapping"
13 }
14
15 fn run(&self, ctx: &mut Context, _cache: &mut AnalysisCache) -> PassResult {
16 let mut swaps_inserted = 0usize;
17
18 let block_keys: Vec<_> = ctx.blocks.keys().collect();
19
20 for block_key in block_keys {
21 let op_list = match ctx.blocks.get(block_key) {
22 Some(b) => b.ops.clone(),
23 None => continue,
24 };
25
26 for &op_key in &op_list {
28 let needs_swap = if let Some(op) = ctx.ops.get(op_key) {
29 let name = ctx.strings.resolve(op.name);
30 if !name.starts_with("quantum.") {
31 continue;
32 }
33
34 let q0 = op.attrs.get_integer("qubit0");
36 let q1 = op.attrs.get_integer("qubit1");
37 let max_distance = op.attrs.get_integer("max_coupling_distance").unwrap_or(1);
38
39 match (q0, q1) {
40 (Some(a), Some(b)) => {
41 let dist = (a - b).unsigned_abs() as i64;
42 dist > max_distance
43 }
44 _ => false,
45 }
46 } else {
47 false
48 };
49
50 if needs_swap {
51 if let Some(op) = ctx.ops.get_mut(op_key) {
53 op.attrs
54 .set("needs_swap", lift_core::attributes::Attribute::Bool(true));
55 swaps_inserted += 1;
56 }
57 }
58 }
59 }
60
61 if swaps_inserted > 0 {
62 tracing::info!(
63 pass = "layout-mapping",
64 swaps_needed = swaps_inserted,
65 "Layout mapping annotations applied"
66 );
67 PassResult::Changed
68 } else {
69 PassResult::Unchanged
70 }
71 }
72
73 fn invalidates(&self) -> Vec<&str> {
74 vec!["quantum_analysis"]
75 }
76}