1use crate::attributes::Attributes;
2use crate::blocks::{BlockData, BlockKey};
3use crate::dialect::{register_builtin_dialects, DialectRegistry};
4use crate::functions::FunctionData;
5use crate::interning::{StringId, StringInterner, TypeInterner};
6use crate::location::Location;
7use crate::module::ModuleData;
8use crate::operations::{OpKey, OperationData};
9use crate::regions::{RegionData, RegionKey};
10use crate::types::{
11 CoreType, DataType, Dimension, MemoryLayout, QubitTypeInfo, TensorTypeInfo, TypeData, TypeId,
12};
13use crate::values::{DefSite, ValueData, ValueKey};
14use slotmap::SlotMap;
15
16#[derive(Debug)]
17pub struct Context {
18 pub values: SlotMap<ValueKey, ValueData>,
19 pub ops: SlotMap<OpKey, OperationData>,
20 pub blocks: SlotMap<BlockKey, BlockData>,
21 pub regions: SlotMap<RegionKey, RegionData>,
22 pub strings: StringInterner,
23 pub types: TypeInterner,
24 pub modules: Vec<ModuleData>,
25 pub dialects: DialectRegistry,
26}
27
28impl Context {
29 pub fn new() -> Self {
30 let mut ctx = Self {
31 values: SlotMap::with_key(),
32 ops: SlotMap::with_key(),
33 blocks: SlotMap::with_key(),
34 regions: SlotMap::with_key(),
35 strings: StringInterner::new(),
36 types: TypeInterner::new(),
37 modules: Vec::new(),
38 dialects: DialectRegistry::new(),
39 };
40 register_builtin_dialects(&mut ctx.dialects);
41 ctx
42 }
43
44 pub fn intern_string(&mut self, s: &str) -> StringId {
47 self.strings.intern(s)
48 }
49
50 pub fn resolve_string(&self, id: StringId) -> &str {
51 self.strings.resolve(id)
52 }
53
54 pub fn intern_type(&mut self, ty: CoreType) -> TypeId {
57 self.types.intern(ty)
58 }
59
60 pub fn resolve_type(&self, id: TypeId) -> &CoreType {
61 self.types.resolve(id)
62 }
63
64 pub fn make_integer_type(&mut self, bits: u32, signed: bool) -> TypeId {
67 self.intern_type(CoreType::Integer { bits, signed })
68 }
69
70 pub fn make_float_type(&mut self, bits: u32) -> TypeId {
71 self.intern_type(CoreType::Float { bits })
72 }
73
74 pub fn make_bool_type(&mut self) -> TypeId {
75 self.intern_type(CoreType::Boolean)
76 }
77
78 pub fn make_void_type(&mut self) -> TypeId {
79 self.intern_type(CoreType::Void)
80 }
81
82 pub fn make_index_type(&mut self) -> TypeId {
83 self.intern_type(CoreType::Index)
84 }
85
86 pub fn make_tensor_type(
87 &mut self,
88 shape: Vec<Dimension>,
89 dtype: DataType,
90 layout: MemoryLayout,
91 ) -> TypeId {
92 let dialect = self.intern_string("tensor");
93 let name = self.intern_string("tensor");
94 self.intern_type(CoreType::Opaque {
95 dialect,
96 name,
97 data: TypeData::Tensor(TensorTypeInfo {
98 shape,
99 dtype,
100 layout,
101 }),
102 })
103 }
104
105 pub fn make_qubit_type(&mut self) -> TypeId {
106 let dialect = self.intern_string("quantum");
107 let name = self.intern_string("qubit");
108 self.intern_type(CoreType::Opaque {
109 dialect,
110 name,
111 data: TypeData::Qubit(QubitTypeInfo::Logical),
112 })
113 }
114
115 pub fn make_physical_qubit_type(
116 &mut self,
117 id: usize,
118 t1: f64,
119 t2: f64,
120 freq: f64,
121 fidelity: f64,
122 ) -> TypeId {
123 let dialect = self.intern_string("quantum");
124 let name = self.intern_string("physical_qubit");
125 use crate::types::OrderedFloat;
126 self.intern_type(CoreType::Opaque {
127 dialect,
128 name,
129 data: TypeData::Qubit(QubitTypeInfo::Physical {
130 id,
131 t1_us: OrderedFloat::from_f64(t1),
132 t2_us: OrderedFloat::from_f64(t2),
133 freq_ghz: OrderedFloat::from_f64(freq),
134 fidelity: OrderedFloat::from_f64(fidelity),
135 }),
136 })
137 }
138
139 pub fn make_bit_type(&mut self) -> TypeId {
140 let dialect = self.intern_string("quantum");
141 let name = self.intern_string("bit");
142 self.intern_type(CoreType::Opaque {
143 dialect,
144 name,
145 data: TypeData::ClassicalBit,
146 })
147 }
148
149 pub fn make_hamiltonian_type(&mut self, num_qubits: usize) -> TypeId {
150 let dialect = self.intern_string("quantum");
151 let name = self.intern_string("hamiltonian");
152 self.intern_type(CoreType::Opaque {
153 dialect,
154 name,
155 data: TypeData::Hamiltonian { num_qubits },
156 })
157 }
158
159 pub fn make_function_type(&mut self, params: Vec<TypeId>, returns: Vec<TypeId>) -> TypeId {
160 self.intern_type(CoreType::Function { params, returns })
161 }
162
163 pub fn make_tuple_type(&mut self, elems: Vec<TypeId>) -> TypeId {
164 self.intern_type(CoreType::Tuple(elems))
165 }
166
167 pub fn create_value(&mut self, ty: TypeId, name: Option<StringId>, def: DefSite) -> ValueKey {
170 self.values.insert(ValueData { ty, name, def })
171 }
172
173 pub fn get_value(&self, key: ValueKey) -> Option<&ValueData> {
174 self.values.get(key)
175 }
176
177 pub fn value_type(&self, key: ValueKey) -> Option<TypeId> {
178 self.values.get(key).map(|v| v.ty)
179 }
180
181 pub fn create_op(
184 &mut self,
185 name: &str,
186 dialect: &str,
187 inputs: Vec<ValueKey>,
188 result_types: Vec<TypeId>,
189 attrs: Attributes,
190 location: Location,
191 ) -> (OpKey, Vec<ValueKey>) {
192 let name_id = self.intern_string(name);
193 let dialect_id = self.intern_string(dialect);
194
195 let op_key = self.ops.insert(OperationData {
196 name: name_id,
197 dialect: dialect_id,
198 inputs,
199 results: Vec::new(),
200 attrs,
201 regions: Vec::new(),
202 location,
203 parent_block: None,
204 });
205
206 let mut result_keys = Vec::with_capacity(result_types.len());
207 for (i, ty) in result_types.iter().enumerate() {
208 let val_key = self.create_value(
209 *ty,
210 None,
211 DefSite::OpResult {
212 op: op_key,
213 result_index: i as u32,
214 },
215 );
216 result_keys.push(val_key);
217 }
218
219 self.ops[op_key].results = result_keys.clone();
220 (op_key, result_keys)
221 }
222
223 pub fn get_op(&self, key: OpKey) -> Option<&OperationData> {
224 self.ops.get(key)
225 }
226
227 pub fn get_op_mut(&mut self, key: OpKey) -> Option<&mut OperationData> {
228 self.ops.get_mut(key)
229 }
230
231 pub fn op_name(&self, key: OpKey) -> &str {
232 let op = &self.ops[key];
233 self.strings.resolve(op.name)
234 }
235
236 pub fn op_dialect(&self, key: OpKey) -> &str {
237 let op = &self.ops[key];
238 self.strings.resolve(op.dialect)
239 }
240
241 pub fn create_block(&mut self) -> BlockKey {
244 self.blocks.insert(BlockData::new())
245 }
246
247 pub fn create_block_arg(&mut self, block: BlockKey, ty: TypeId) -> ValueKey {
248 let arg_index = self.blocks[block].args.len() as u32;
249 let val_key = self.create_value(ty, None, DefSite::BlockArg { block, arg_index });
250 self.blocks[block].args.push(val_key);
251 val_key
252 }
253
254 pub fn add_op_to_block(&mut self, block: BlockKey, op: OpKey) {
255 self.blocks[block].ops.push(op);
256 self.ops[op].parent_block = Some(block);
257 }
258
259 pub fn insert_op_before(&mut self, before: OpKey, op: OpKey) {
262 let parent = match self.ops.get(before) {
263 Some(b) => b.parent_block,
264 None => None,
265 };
266 let Some(block) = parent else {
267 return;
269 };
270 if let Some(ops) = self.blocks.get_mut(block) {
271 if let Some(pos) = ops.ops.iter().position(|&k| k == before) {
272 ops.ops.insert(pos, op);
273 } else {
274 ops.ops.push(op);
275 }
276 }
277 self.ops[op].parent_block = Some(block);
278 }
279
280 pub fn get_block(&self, key: BlockKey) -> Option<&BlockData> {
281 self.blocks.get(key)
282 }
283
284 pub fn create_region(&mut self) -> RegionKey {
287 self.regions.insert(RegionData::new())
288 }
289
290 pub fn add_block_to_region(&mut self, region: RegionKey, block: BlockKey) {
291 if self.regions[region].entry_block.is_none() {
292 self.regions[region].entry_block = Some(block);
293 }
294 self.regions[region].blocks.push(block);
295 self.blocks[block].parent_region = Some(region);
296 }
297
298 pub fn attach_region_to_op(&mut self, op: OpKey, region: RegionKey) {
299 self.ops[op].regions.push(region);
300 self.regions[region].parent_op = Some(op);
301 }
302
303 pub fn get_region(&self, key: RegionKey) -> Option<&RegionData> {
304 self.regions.get(key)
305 }
306
307 pub fn create_module(&mut self, name: &str) -> usize {
310 let name_id = self.intern_string(name);
311 let module = ModuleData::new(name_id);
312 self.modules.push(module);
313 self.modules.len() - 1
314 }
315
316 pub fn get_module(&self, index: usize) -> Option<&ModuleData> {
317 self.modules.get(index)
318 }
319
320 pub fn get_module_mut(&mut self, index: usize) -> Option<&mut ModuleData> {
321 self.modules.get_mut(index)
322 }
323
324 pub fn add_function_to_module(&mut self, module_index: usize, func: FunctionData) {
325 if let Some(module) = self.modules.get_mut(module_index) {
326 module.add_function(func);
327 }
328 }
329
330 pub fn snapshot(&self) -> ContextSnapshot {
333 ContextSnapshot {
334 num_values: self.values.len(),
335 num_ops: self.ops.len(),
336 num_blocks: self.blocks.len(),
337 num_regions: self.regions.len(),
338 }
339 }
340
341 pub fn is_qubit_type(&self, ty: TypeId) -> bool {
344 matches!(
345 self.resolve_type(ty),
346 CoreType::Opaque {
347 data: TypeData::Qubit(_),
348 ..
349 }
350 )
351 }
352
353 pub fn is_tensor_type(&self, ty: TypeId) -> bool {
354 matches!(
355 self.resolve_type(ty),
356 CoreType::Opaque {
357 data: TypeData::Tensor(_),
358 ..
359 }
360 )
361 }
362
363 pub fn is_bit_type(&self, ty: TypeId) -> bool {
364 matches!(
365 self.resolve_type(ty),
366 CoreType::Opaque {
367 data: TypeData::ClassicalBit,
368 ..
369 }
370 )
371 }
372
373 pub fn get_tensor_info(&self, ty: TypeId) -> Option<&TensorTypeInfo> {
374 match self.resolve_type(ty) {
375 CoreType::Opaque {
376 data: TypeData::Tensor(info),
377 ..
378 } => Some(info),
379 _ => None,
380 }
381 }
382}
383
384impl Default for Context {
385 fn default() -> Self {
386 Self::new()
387 }
388}
389
390#[derive(Debug, Clone)]
391pub struct ContextSnapshot {
392 pub num_values: usize,
393 pub num_ops: usize,
394 pub num_blocks: usize,
395 pub num_regions: usize,
396}