|
6 | 6 | from kirin.analysis import ForwardFrame, const |
7 | 7 | from kirin.dialects import cf, py, scf, func, ilist |
8 | 8 |
|
9 | | -from .lattice import Address, NotQubit, AddressReg, AddressQubit, AddressTuple |
| 9 | +from bloqade import squin |
| 10 | + |
| 11 | +from .lattice import ( |
| 12 | + Address, |
| 13 | + NotQubit, |
| 14 | + AddressReg, |
| 15 | + AddressWire, |
| 16 | + AddressQubit, |
| 17 | + AddressTuple, |
| 18 | +) |
10 | 19 | from .analysis import AddressAnalysis |
11 | 20 |
|
12 | 21 |
|
@@ -64,10 +73,16 @@ def new_ilist( |
64 | 73 | class PyIndexing(interp.MethodTable): |
65 | 74 | @interp.impl(py.GetItem) |
66 | 75 | def getitem(self, interp: AddressAnalysis, frame: interp.Frame, stmt: py.GetItem): |
| 76 | + # Integer index into the thing being indexed |
67 | 77 | idx = interp.get_const_value(int, stmt.index) |
| 78 | + # The object being indexed into |
68 | 79 | obj = frame.get(stmt.obj) |
| 80 | + # The `data` attributes holds onto other Address types |
| 81 | + # so we just extract that here |
69 | 82 | if isinstance(obj, AddressTuple): |
70 | 83 | return (obj.data[idx],) |
| 84 | + # an AddressReg is guaranteed to just have some sequence |
| 85 | + # of integers which is directly pluggable to AddressQubit |
71 | 86 | elif isinstance(obj, AddressReg): |
72 | 87 | return (AddressQubit(obj.data[idx]),) |
73 | 88 | else: |
@@ -147,3 +162,67 @@ def for_loop( |
147 | 162 | return # if terminate is Return, there is no result |
148 | 163 |
|
149 | 164 | return loop_vars |
| 165 | + |
| 166 | + |
| 167 | +# Address lattice elements we can work with: |
| 168 | +## NotQubit (bottom), AnyAddress (top) |
| 169 | + |
| 170 | +## AddressTuple -> data: tuple[Address, ...] |
| 171 | +### Recursive type, could contain itself or other variants |
| 172 | +### This pops up in cases where you can have an IList/Tuple |
| 173 | +### That contains elements that could be other Address types |
| 174 | + |
| 175 | +## AddressReg -> data: Sequence[int] |
| 176 | +### specific to creation of a register of qubits |
| 177 | + |
| 178 | +## AddressQubit -> data: int |
| 179 | +### Base qubit address type |
| 180 | + |
| 181 | + |
| 182 | +@squin.wire.dialect.register(key="qubit.address") |
| 183 | +class SquinWireMethodTable(interp.MethodTable): |
| 184 | + |
| 185 | + @interp.impl(squin.wire.Unwrap) |
| 186 | + def unwrap( |
| 187 | + self, |
| 188 | + interp_: AddressAnalysis, |
| 189 | + frame: ForwardFrame[Address], |
| 190 | + stmt: squin.wire.Unwrap, |
| 191 | + ): |
| 192 | + |
| 193 | + origin_qubit = frame.get(stmt.qubit) |
| 194 | + |
| 195 | + return (AddressWire(origin_qubit=origin_qubit),) |
| 196 | + |
| 197 | + @interp.impl(squin.wire.Apply) |
| 198 | + def apply( |
| 199 | + self, |
| 200 | + interp_: AddressAnalysis, |
| 201 | + frame: ForwardFrame[Address], |
| 202 | + stmt: squin.wire.Apply, |
| 203 | + ): |
| 204 | + |
| 205 | + origin_qubits = tuple( |
| 206 | + [frame.get(input_elem).origin_qubit for input_elem in stmt.inputs] |
| 207 | + ) |
| 208 | + new_address_wires = tuple( |
| 209 | + [AddressWire(origin_qubit=origin_qubit) for origin_qubit in origin_qubits] |
| 210 | + ) |
| 211 | + return new_address_wires |
| 212 | + |
| 213 | + |
| 214 | +@squin.qubit.dialect.register(key="qubit.address") |
| 215 | +class SquinQubitMethodTable(interp.MethodTable): |
| 216 | + |
| 217 | + # This can be treated like a QRegNew impl |
| 218 | + @interp.impl(squin.qubit.New) |
| 219 | + def new( |
| 220 | + self, |
| 221 | + interp_: AddressAnalysis, |
| 222 | + frame: ForwardFrame[Address], |
| 223 | + stmt: squin.qubit.New, |
| 224 | + ): |
| 225 | + n_qubits = interp_.get_const_value(int, stmt.n_qubits) |
| 226 | + addr = AddressReg(range(interp_.next_address, interp_.next_address + n_qubits)) |
| 227 | + interp_.next_address += n_qubits |
| 228 | + return (addr,) |
0 commit comments