/rust/registry/src/index.crates.io-6f17d22bba15001f/cranelift-codegen-0.91.1/src/ir/dfg.rs
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | //! Data flow graph tracking Instructions, Values, and blocks. | 
| 2 |  |  | 
| 3 |  | use crate::entity::{self, PrimaryMap, SecondaryMap}; | 
| 4 |  | use crate::ir; | 
| 5 |  | use crate::ir::builder::ReplaceBuilder; | 
| 6 |  | use crate::ir::dynamic_type::{DynamicTypeData, DynamicTypes}; | 
| 7 |  | use crate::ir::immediates::HeapImmData; | 
| 8 |  | use crate::ir::instructions::{BranchInfo, CallInfo, InstructionData}; | 
| 9 |  | use crate::ir::{types, ConstantData, ConstantPool, Immediate}; | 
| 10 |  | use crate::ir::{ | 
| 11 |  |     Block, DynamicType, FuncRef, HeapImm, Inst, SigRef, Signature, Type, Value, | 
| 12 |  |     ValueLabelAssignments, ValueList, ValueListPool, | 
| 13 |  | }; | 
| 14 |  | use crate::ir::{ExtFuncData, RelSourceLoc}; | 
| 15 |  | use crate::packed_option::ReservedValue; | 
| 16 |  | use crate::write::write_operands; | 
| 17 |  | use core::fmt; | 
| 18 |  | use core::iter; | 
| 19 |  | use core::mem; | 
| 20 |  | use core::ops::{Index, IndexMut}; | 
| 21 |  | use core::u16; | 
| 22 |  |  | 
| 23 |  | use alloc::collections::BTreeMap; | 
| 24 |  | #[cfg(feature = "enable-serde")] | 
| 25 |  | use serde::{Deserialize, Serialize}; | 
| 26 |  |  | 
| 27 |  | /// A data flow graph defines all instructions and basic blocks in a function as well as | 
| 28 |  | /// the data flow dependencies between them. The DFG also tracks values which can be either | 
| 29 |  | /// instruction results or block parameters. | 
| 30 |  | /// | 
| 31 |  | /// The layout of blocks in the function and of instructions in each block is recorded by the | 
| 32 |  | /// `Layout` data structure which forms the other half of the function representation. | 
| 33 |  | /// | 
| 34 |  | #[derive(Clone, PartialEq, Hash)] | 
| 35 |  | #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] | 
| 36 |  | pub struct DataFlowGraph { | 
| 37 |  |     /// Data about all of the instructions in the function, including opcodes and operands. | 
| 38 |  |     /// The instructions in this map are not in program order. That is tracked by `Layout`, along | 
| 39 |  |     /// with the block containing each instruction. | 
| 40 |  |     insts: PrimaryMap<Inst, InstructionData>, | 
| 41 |  |  | 
| 42 |  |     /// List of result values for each instruction. | 
| 43 |  |     /// | 
| 44 |  |     /// This map gets resized automatically by `make_inst()` so it is always in sync with the | 
| 45 |  |     /// primary `insts` map. | 
| 46 |  |     results: SecondaryMap<Inst, ValueList>, | 
| 47 |  |  | 
| 48 |  |     /// basic blocks in the function and their parameters. | 
| 49 |  |     /// | 
| 50 |  |     /// This map is not in program order. That is handled by `Layout`, and so is the sequence of | 
| 51 |  |     /// instructions contained in each block. | 
| 52 |  |     blocks: PrimaryMap<Block, BlockData>, | 
| 53 |  |  | 
| 54 |  |     /// Dynamic types created. | 
| 55 |  |     pub dynamic_types: DynamicTypes, | 
| 56 |  |  | 
| 57 |  |     /// Memory pool of value lists. | 
| 58 |  |     /// | 
| 59 |  |     /// The `ValueList` references into this pool appear in many places: | 
| 60 |  |     /// | 
| 61 |  |     /// - Instructions in `insts` that don't have room for their entire argument list inline. | 
| 62 |  |     /// - Instruction result values in `results`. | 
| 63 |  |     /// - block parameters in `blocks`. | 
| 64 |  |     pub value_lists: ValueListPool, | 
| 65 |  |  | 
| 66 |  |     /// Primary value table with entries for all values. | 
| 67 |  |     values: PrimaryMap<Value, ValueDataPacked>, | 
| 68 |  |  | 
| 69 |  |     /// Function signature table. These signatures are referenced by indirect call instructions as | 
| 70 |  |     /// well as the external function references. | 
| 71 |  |     pub signatures: PrimaryMap<SigRef, Signature>, | 
| 72 |  |  | 
| 73 |  |     /// The pre-legalization signature for each entry in `signatures`, if any. | 
| 74 |  |     pub old_signatures: SecondaryMap<SigRef, Option<Signature>>, | 
| 75 |  |  | 
| 76 |  |     /// External function references. These are functions that can be called directly. | 
| 77 |  |     pub ext_funcs: PrimaryMap<FuncRef, ExtFuncData>, | 
| 78 |  |  | 
| 79 |  |     /// Saves Value labels. | 
| 80 |  |     pub values_labels: Option<BTreeMap<Value, ValueLabelAssignments>>, | 
| 81 |  |  | 
| 82 |  |     /// Constants used within the function | 
| 83 |  |     pub constants: ConstantPool, | 
| 84 |  |  | 
| 85 |  |     /// Stores large immediates that otherwise will not fit on InstructionData | 
| 86 |  |     pub immediates: PrimaryMap<Immediate, ConstantData>, | 
| 87 |  |  | 
| 88 |  |     /// Out-of-line heap access immediates that don't fit in `InstructionData`. | 
| 89 |  |     pub heap_imms: PrimaryMap<HeapImm, HeapImmData>, | 
| 90 |  | } | 
| 91 |  |  | 
| 92 |  | impl DataFlowGraph { | 
| 93 |  |     /// Create a new empty `DataFlowGraph`. | 
| 94 | 191k |     pub fn new() -> Self { | 
| 95 | 191k |         Self { | 
| 96 | 191k |             insts: PrimaryMap::new(), | 
| 97 | 191k |             results: SecondaryMap::new(), | 
| 98 | 191k |             blocks: PrimaryMap::new(), | 
| 99 | 191k |             dynamic_types: DynamicTypes::new(), | 
| 100 | 191k |             value_lists: ValueListPool::new(), | 
| 101 | 191k |             values: PrimaryMap::new(), | 
| 102 | 191k |             signatures: PrimaryMap::new(), | 
| 103 | 191k |             old_signatures: SecondaryMap::new(), | 
| 104 | 191k |             ext_funcs: PrimaryMap::new(), | 
| 105 | 191k |             values_labels: None, | 
| 106 | 191k |             constants: ConstantPool::new(), | 
| 107 | 191k |             immediates: PrimaryMap::new(), | 
| 108 | 191k |             heap_imms: PrimaryMap::new(), | 
| 109 | 191k |         } | 
| 110 | 191k |     } | 
| 111 |  |  | 
| 112 |  |     /// Clear everything. | 
| 113 | 0 |     pub fn clear(&mut self) { | 
| 114 | 0 |         self.insts.clear(); | 
| 115 | 0 |         self.results.clear(); | 
| 116 | 0 |         self.blocks.clear(); | 
| 117 | 0 |         self.dynamic_types.clear(); | 
| 118 | 0 |         self.value_lists.clear(); | 
| 119 | 0 |         self.values.clear(); | 
| 120 | 0 |         self.signatures.clear(); | 
| 121 | 0 |         self.old_signatures.clear(); | 
| 122 | 0 |         self.ext_funcs.clear(); | 
| 123 | 0 |         self.values_labels = None; | 
| 124 | 0 |         self.constants.clear(); | 
| 125 | 0 |         self.immediates.clear(); | 
| 126 | 0 |     } | 
| 127 |  |  | 
| 128 |  |     /// Clear all instructions, but keep blocks and other metadata | 
| 129 |  |     /// (signatures, constants, immediates). Everything to do with | 
| 130 |  |     /// `Value`s is cleared, including block params and debug info. | 
| 131 |  |     /// | 
| 132 |  |     /// Used during egraph-based optimization to clear out the pre-opt | 
| 133 |  |     /// body so that we can regenerate it from the egraph. | 
| 134 | 0 |     pub(crate) fn clear_insts(&mut self) { | 
| 135 | 0 |         self.insts.clear(); | 
| 136 | 0 |         self.results.clear(); | 
| 137 | 0 |         self.value_lists.clear(); | 
| 138 | 0 |         self.values.clear(); | 
| 139 | 0 |         self.values_labels = None; | 
| 140 | 0 |         for block in self.blocks.values_mut() { | 
| 141 | 0 |             block.params = ValueList::new(); | 
| 142 | 0 |         } | 
| 143 | 0 |     } | 
| 144 |  |  | 
| 145 |  |     /// Get the total number of instructions created in this function, whether they are currently | 
| 146 |  |     /// inserted in the layout or not. | 
| 147 |  |     /// | 
| 148 |  |     /// This is intended for use with `SecondaryMap::with_capacity`. | 
| 149 | 3.03M |     pub fn num_insts(&self) -> usize { | 
| 150 | 3.03M |         self.insts.len() | 
| 151 | 3.03M |     } | 
| 152 |  |  | 
| 153 |  |     /// Returns `true` if the given instruction reference is valid. | 
| 154 | 13.9M |     pub fn inst_is_valid(&self, inst: Inst) -> bool { | 
| 155 | 13.9M |         self.insts.is_valid(inst) | 
| 156 | 13.9M |     } | 
| 157 |  |  | 
| 158 |  |     /// Get the total number of basic blocks created in this function, whether they are | 
| 159 |  |     /// currently inserted in the layout or not. | 
| 160 |  |     /// | 
| 161 |  |     /// This is intended for use with `SecondaryMap::with_capacity`. | 
| 162 | 3.62M |     pub fn num_blocks(&self) -> usize { | 
| 163 | 3.62M |         self.blocks.len() | 
| 164 | 3.62M |     } | 
| 165 |  |  | 
| 166 |  |     /// Returns `true` if the given block reference is valid. | 
| 167 | 4.81M |     pub fn block_is_valid(&self, block: Block) -> bool { | 
| 168 | 4.81M |         self.blocks.is_valid(block) | 
| 169 | 4.81M |     } | 
| 170 |  |  | 
| 171 |  |     /// Get the total number of values. | 
| 172 | 139k |     pub fn num_values(&self) -> usize { | 
| 173 | 139k |         self.values.len() | 
| 174 | 139k |     } | 
| 175 |  |  | 
| 176 |  |     /// Starts collection of debug information. | 
| 177 | 0 |     pub fn collect_debug_info(&mut self) { | 
| 178 | 0 |         if self.values_labels.is_none() { | 
| 179 | 0 |             self.values_labels = Some(Default::default()); | 
| 180 | 0 |         } | 
| 181 | 0 |     } | 
| 182 |  |  | 
| 183 |  |     /// Inserts a `ValueLabelAssignments::Alias` for `to_alias` if debug info | 
| 184 |  |     /// collection is enabled. | 
| 185 | 50.4k |     pub fn add_value_label_alias(&mut self, to_alias: Value, from: RelSourceLoc, value: Value) { | 
| 186 | 50.4k |         if let Some(values_labels) = self.values_labels.as_mut() { | 
| 187 | 0 |             values_labels.insert(to_alias, ir::ValueLabelAssignments::Alias { from, value }); | 
| 188 | 50.4k |         } | 
| 189 | 50.4k |     } | 
| 190 |  | } | 
| 191 |  |  | 
| 192 |  | /// Resolve value aliases. | 
| 193 |  | /// | 
| 194 |  | /// Find the original SSA value that `value` aliases, or None if an | 
| 195 |  | /// alias cycle is detected. | 
| 196 | 24.5M | fn maybe_resolve_aliases( | 
| 197 | 24.5M |     values: &PrimaryMap<Value, ValueDataPacked>, | 
| 198 | 24.5M |     value: Value, | 
| 199 | 24.5M | ) -> Option<Value> { | 
| 200 | 24.5M |     let mut v = value; | 
| 201 | 24.5M |  | 
| 202 | 24.5M |     // Note that values may be empty here. | 
| 203 | 24.5M |     for _ in 0..=values.len() { | 
| 204 | 25.4M |         if let ValueData::Alias { original, .. } = ValueData::from(values[v]) { | 
| 205 | 901k |             v = original; | 
| 206 | 901k |         } else { | 
| 207 | 24.5M |             return Some(v); | 
| 208 |  |         } | 
| 209 |  |     } | 
| 210 |  |  | 
| 211 | 0 |     None | 
| 212 | 24.5M | } | 
| 213 |  |  | 
| 214 |  | /// Resolve value aliases. | 
| 215 |  | /// | 
| 216 |  | /// Find the original SSA value that `value` aliases. | 
| 217 | 24.5M | fn resolve_aliases(values: &PrimaryMap<Value, ValueDataPacked>, value: Value) -> Value { | 
| 218 | 24.5M |     if let Some(v) = maybe_resolve_aliases(values, value) { | 
| 219 | 24.5M |         v | 
| 220 |  |     } else { | 
| 221 | 0 |         panic!("Value alias loop detected for {}", value); | 
| 222 |  |     } | 
| 223 | 24.5M | } | 
| 224 |  |  | 
| 225 |  | /// Iterator over all Values in a DFG | 
| 226 |  | pub struct Values<'a> { | 
| 227 |  |     inner: entity::Iter<'a, Value, ValueDataPacked>, | 
| 228 |  | } | 
| 229 |  |  | 
| 230 |  | /// Check for non-values | 
| 231 | 0 | fn valid_valuedata(data: ValueDataPacked) -> bool { | 
| 232 | 0 |     let data = ValueData::from(data); | 
| 233 |  |     if let ValueData::Alias { | 
| 234 |  |         ty: types::INVALID, | 
| 235 | 0 |         original, | 
| 236 | 0 |     } = ValueData::from(data) | 
| 237 |  |     { | 
| 238 | 0 |         if original == Value::reserved_value() { | 
| 239 | 0 |             return false; | 
| 240 | 0 |         } | 
| 241 | 0 |     } | 
| 242 | 0 |     true | 
| 243 | 0 | } | 
| 244 |  |  | 
| 245 |  | impl<'a> Iterator for Values<'a> { | 
| 246 |  |     type Item = Value; | 
| 247 |  |  | 
| 248 | 0 |     fn next(&mut self) -> Option<Self::Item> { | 
| 249 | 0 |         self.inner | 
| 250 | 0 |             .by_ref() | 
| 251 | 0 |             .find(|kv| valid_valuedata(*kv.1)) | 
| 252 | 0 |             .map(|kv| kv.0) | 
| 253 | 0 |     } | 
| 254 |  | } | 
| 255 |  |  | 
| 256 |  | /// Handling values. | 
| 257 |  | /// | 
| 258 |  | /// Values are either block parameters or instruction results. | 
| 259 |  | impl DataFlowGraph { | 
| 260 |  |     /// Allocate an extended value entry. | 
| 261 | 3.26M |     fn make_value(&mut self, data: ValueData) -> Value { | 
| 262 | 3.26M |         self.values.push(data.into()) | 
| 263 | 3.26M |     } | 
| 264 |  |  | 
| 265 |  |     /// Get an iterator over all values. | 
| 266 | 0 |     pub fn values<'a>(&'a self) -> Values { | 
| 267 | 0 |         Values { | 
| 268 | 0 |             inner: self.values.iter(), | 
| 269 | 0 |         } | 
| 270 | 0 |     } | 
| 271 |  |  | 
| 272 |  |     /// Check if a value reference is valid. | 
| 273 | 32.2M |     pub fn value_is_valid(&self, v: Value) -> bool { | 
| 274 | 32.2M |         self.values.is_valid(v) | 
| 275 | 32.2M |     } | 
| 276 |  |  | 
| 277 |  |     /// Get the type of a value. | 
| 278 | 86.4M |     pub fn value_type(&self, v: Value) -> Type { | 
| 279 | 86.4M |         self.values[v].ty() | 
| 280 | 86.4M |     } | 
| 281 |  |  | 
| 282 |  |     /// Fill in the type of a value, only if currently invalid (as a placeholder). | 
| 283 | 0 |     pub(crate) fn fill_in_value_type(&mut self, v: Value, ty: Type) { | 
| 284 | 0 |         debug_assert!(self.values[v].ty().is_invalid() || self.values[v].ty() == ty); | 
| 285 | 0 |         self.values[v].set_type(ty); | 
| 286 | 0 |     } | 
| 287 |  |  | 
| 288 |  |     /// Get the definition of a value. | 
| 289 |  |     /// | 
| 290 |  |     /// This is either the instruction that defined it or the Block that has the value as an | 
| 291 |  |     /// parameter. | 
| 292 | 79.4M |     pub fn value_def(&self, v: Value) -> ValueDef { | 
| 293 | 79.4M |         match ValueData::from(self.values[v]) { | 
| 294 | 31.9M |             ValueData::Inst { inst, num, .. } => ValueDef::Result(inst, num as usize), | 
| 295 | 47.1M |             ValueData::Param { block, num, .. } => ValueDef::Param(block, num as usize), | 
| 296 | 275k |             ValueData::Alias { original, .. } => { | 
| 297 | 275k |                 // Make sure we only recurse one level. `resolve_aliases` has safeguards to | 
| 298 | 275k |                 // detect alias loops without overrunning the stack. | 
| 299 | 275k |                 self.value_def(self.resolve_aliases(original)) | 
| 300 |  |             } | 
| 301 |  |         } | 
| 302 | 79.4M |     } | 
| 303 |  |  | 
| 304 |  |     /// Determine if `v` is an attached instruction result / block parameter. | 
| 305 |  |     /// | 
| 306 |  |     /// An attached value can't be attached to something else without first being detached. | 
| 307 |  |     /// | 
| 308 |  |     /// Value aliases are not considered to be attached to anything. Use `resolve_aliases()` to | 
| 309 |  |     /// determine if the original aliased value is attached. | 
| 310 | 16.8M |     pub fn value_is_attached(&self, v: Value) -> bool { | 
| 311 | 16.8M |         use self::ValueData::*; | 
| 312 | 16.8M |         match ValueData::from(self.values[v]) { | 
| 313 | 13.9M |             Inst { inst, num, .. } => Some(&v) == self.inst_results(inst).get(num as usize), | 
| 314 | 2.89M |             Param { block, num, .. } => Some(&v) == self.block_params(block).get(num as usize), | 
| 315 | 0 |             Alias { .. } => false, | 
| 316 |  |         } | 
| 317 | 16.8M |     } | 
| 318 |  |  | 
| 319 |  |     /// Resolve value aliases. | 
| 320 |  |     /// | 
| 321 |  |     /// Find the original SSA value that `value` aliases. | 
| 322 | 21.1M |     pub fn resolve_aliases(&self, value: Value) -> Value { | 
| 323 | 21.1M |         resolve_aliases(&self.values, value) | 
| 324 | 21.1M |     } | 
| 325 |  |  | 
| 326 |  |     /// Resolve all aliases among inst's arguments. | 
| 327 |  |     /// | 
| 328 |  |     /// For each argument of inst which is defined by an alias, replace the | 
| 329 |  |     /// alias with the aliased value. | 
| 330 | 3.98M |     pub fn resolve_aliases_in_arguments(&mut self, inst: Inst) { | 
| 331 | 3.98M |         for arg in self.insts[inst].arguments_mut(&mut self.value_lists) { | 
| 332 | 3.42M |             let resolved = resolve_aliases(&self.values, *arg); | 
| 333 | 3.42M |             if resolved != *arg { | 
| 334 | 476k |                 *arg = resolved; | 
| 335 | 2.94M |             } | 
| 336 |  |         } | 
| 337 | 3.98M |     } | 
| 338 |  |  | 
| 339 |  |     /// Turn a value into an alias of another. | 
| 340 |  |     /// | 
| 341 |  |     /// Change the `dest` value to behave as an alias of `src`. This means that all uses of `dest` | 
| 342 |  |     /// will behave as if they used that value `src`. | 
| 343 |  |     /// | 
| 344 |  |     /// The `dest` value can't be attached to an instruction or block. | 
| 345 | 88.2k |     pub fn change_to_alias(&mut self, dest: Value, src: Value) { | 
| 346 | 88.2k |         debug_assert!(!self.value_is_attached(dest)); | 
| 347 |  |         // Try to create short alias chains by finding the original source value. | 
| 348 |  |         // This also avoids the creation of loops. | 
| 349 | 88.2k |         let original = self.resolve_aliases(src); | 
| 350 | 88.2k |         debug_assert_ne!( | 
| 351 |  |             dest, original, | 
| 352 | 0 |             "Aliasing {} to {} would create a loop", | 
| 353 |  |             dest, src | 
| 354 |  |         ); | 
| 355 | 88.2k |         let ty = self.value_type(original); | 
| 356 | 88.2k |         debug_assert_eq!( | 
| 357 | 0 |             self.value_type(dest), | 
| 358 |  |             ty, | 
| 359 | 0 |             "Aliasing {} to {} would change its type {} to {}", | 
| 360 | 0 |             dest, | 
| 361 | 0 |             src, | 
| 362 | 0 |             self.value_type(dest), | 
| 363 |  |             ty | 
| 364 |  |         ); | 
| 365 | 88.2k |         debug_assert_ne!(ty, types::INVALID); | 
| 366 |  |  | 
| 367 | 88.2k |         self.values[dest] = ValueData::Alias { ty, original }.into(); | 
| 368 | 88.2k |     } | 
| 369 |  |  | 
| 370 |  |     /// Replace the results of one instruction with aliases to the results of another. | 
| 371 |  |     /// | 
| 372 |  |     /// Change all the results of `dest_inst` to behave as aliases of | 
| 373 |  |     /// corresponding results of `src_inst`, as if calling change_to_alias for | 
| 374 |  |     /// each. | 
| 375 |  |     /// | 
| 376 |  |     /// After calling this instruction, `dest_inst` will have had its results | 
| 377 |  |     /// cleared, so it likely needs to be removed from the graph. | 
| 378 |  |     /// | 
| 379 | 1.25M |     pub fn replace_with_aliases(&mut self, dest_inst: Inst, src_inst: Inst) { | 
| 380 | 1.25M |         debug_assert_ne!( | 
| 381 |  |             dest_inst, src_inst, | 
| 382 | 0 |             "Replacing {} with itself would create a loop", | 
| 383 |  |             dest_inst | 
| 384 |  |         ); | 
| 385 | 1.25M |         debug_assert_eq!( | 
| 386 | 0 |             self.results[dest_inst].len(&self.value_lists), | 
| 387 | 0 |             self.results[src_inst].len(&self.value_lists), | 
| 388 | 0 |             "Replacing {} with {} would produce a different number of results.", | 
| 389 |  |             dest_inst, | 
| 390 |  |             src_inst | 
| 391 |  |         ); | 
| 392 |  |  | 
| 393 | 1.25M |         for (&dest, &src) in self.results[dest_inst] | 
| 394 | 1.25M |             .as_slice(&self.value_lists) | 
| 395 | 1.25M |             .iter() | 
| 396 | 1.25M |             .zip(self.results[src_inst].as_slice(&self.value_lists)) | 
| 397 |  |         { | 
| 398 | 1.21M |             let original = src; | 
| 399 | 1.21M |             let ty = self.value_type(original); | 
| 400 | 1.21M |             debug_assert_eq!( | 
| 401 | 0 |                 self.value_type(dest), | 
| 402 |  |                 ty, | 
| 403 | 0 |                 "Aliasing {} to {} would change its type {} to {}", | 
| 404 | 0 |                 dest, | 
| 405 | 0 |                 src, | 
| 406 | 0 |                 self.value_type(dest), | 
| 407 |  |                 ty | 
| 408 |  |             ); | 
| 409 | 1.21M |             debug_assert_ne!(ty, types::INVALID); | 
| 410 |  |  | 
| 411 | 1.21M |             self.values[dest] = ValueData::Alias { ty, original }.into(); | 
| 412 |  |         } | 
| 413 |  |  | 
| 414 | 1.25M |         self.clear_results(dest_inst); | 
| 415 | 1.25M |     } | 
| 416 |  | } | 
| 417 |  |  | 
| 418 |  | /// Where did a value come from? | 
| 419 |  | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | 
| 420 |  | pub enum ValueDef { | 
| 421 |  |     /// Value is the n'th result of an instruction. | 
| 422 |  |     Result(Inst, usize), | 
| 423 |  |     /// Value is the n'th parameter to a block. | 
| 424 |  |     Param(Block, usize), | 
| 425 |  | } | 
| 426 |  |  | 
| 427 |  | impl ValueDef { | 
| 428 |  |     /// Unwrap the instruction where the value was defined, or panic. | 
| 429 | 50.4k |     pub fn unwrap_inst(&self) -> Inst { | 
| 430 | 50.4k |         self.inst().expect("Value is not an instruction result") | 
| 431 | 50.4k |     } | 
| 432 |  |  | 
| 433 |  |     /// Get the instruction where the value was defined, if any. | 
| 434 | 2.76M |     pub fn inst(&self) -> Option<Inst> { | 
| 435 | 2.76M |         match *self { | 
| 436 | 1.95M |             Self::Result(inst, _) => Some(inst), | 
| 437 | 812k |             _ => None, | 
| 438 |  |         } | 
| 439 | 2.76M |     } | 
| 440 |  |  | 
| 441 |  |     /// Unwrap the block there the parameter is defined, or panic. | 
| 442 | 0 |     pub fn unwrap_block(&self) -> Block { | 
| 443 | 0 |         match *self { | 
| 444 | 0 |             Self::Param(block, _) => block, | 
| 445 | 0 |             _ => panic!("Value is not a block parameter"), | 
| 446 |  |         } | 
| 447 | 0 |     } | 
| 448 |  |  | 
| 449 |  |     /// Get the program point where the value was defined. | 
| 450 | 0 |     pub fn pp(self) -> ir::ExpandedProgramPoint { | 
| 451 | 0 |         self.into() | 
| 452 | 0 |     } | 
| 453 |  |  | 
| 454 |  |     /// Get the number component of this definition. | 
| 455 |  |     /// | 
| 456 |  |     /// When multiple values are defined at the same program point, this indicates the index of | 
| 457 |  |     /// this value. | 
| 458 | 0 |     pub fn num(self) -> usize { | 
| 459 | 0 |         match self { | 
| 460 | 0 |             Self::Result(_, n) | Self::Param(_, n) => n, | 
| 461 | 0 |         } | 
| 462 | 0 |     } | 
| 463 |  | } | 
| 464 |  |  | 
| 465 |  | /// Internal table storage for extended values. | 
| 466 |  | #[derive(Clone, Debug, PartialEq, Hash)] | 
| 467 |  | #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] | 
| 468 |  | enum ValueData { | 
| 469 |  |     /// Value is defined by an instruction. | 
| 470 |  |     Inst { ty: Type, num: u16, inst: Inst }, | 
| 471 |  |  | 
| 472 |  |     /// Value is a block parameter. | 
| 473 |  |     Param { ty: Type, num: u16, block: Block }, | 
| 474 |  |  | 
| 475 |  |     /// Value is an alias of another value. | 
| 476 |  |     /// An alias value can't be linked as an instruction result or block parameter. It is used as a | 
| 477 |  |     /// placeholder when the original instruction or block has been rewritten or modified. | 
| 478 |  |     Alias { ty: Type, original: Value }, | 
| 479 |  | } | 
| 480 |  |  | 
| 481 |  | /// Bit-packed version of ValueData, for efficiency. | 
| 482 |  | /// | 
| 483 |  | /// Layout: | 
| 484 |  | /// | 
| 485 |  | /// ```plain | 
| 486 |  | ///        | tag:2 |  type:14        |    num:16       | index:32          | | 
| 487 |  | /// ``` | 
| 488 |  | #[derive(Clone, Copy, Debug, PartialEq, Hash)] | 
| 489 |  | #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] | 
| 490 |  | struct ValueDataPacked(u64); | 
| 491 |  |  | 
| 492 |  | impl ValueDataPacked { | 
| 493 |  |     const INDEX_SHIFT: u64 = 0; | 
| 494 |  |     const INDEX_BITS: u64 = 32; | 
| 495 |  |     const NUM_SHIFT: u64 = Self::INDEX_SHIFT + Self::INDEX_BITS; | 
| 496 |  |     const NUM_BITS: u64 = 16; | 
| 497 |  |     const TYPE_SHIFT: u64 = Self::NUM_SHIFT + Self::NUM_BITS; | 
| 498 |  |     const TYPE_BITS: u64 = 14; | 
| 499 |  |     const TAG_SHIFT: u64 = Self::TYPE_SHIFT + Self::TYPE_BITS; | 
| 500 |  |     const TAG_BITS: u64 = 2; | 
| 501 |  |  | 
| 502 |  |     const TAG_INST: u64 = 1; | 
| 503 |  |     const TAG_PARAM: u64 = 2; | 
| 504 |  |     const TAG_ALIAS: u64 = 3; | 
| 505 |  |  | 
| 506 | 4.72M |     fn make(tag: u64, ty: Type, num: u16, index: u32) -> ValueDataPacked { | 
| 507 | 4.72M |         debug_assert!(tag < (1 << Self::TAG_BITS)); | 
| 508 | 4.72M |         debug_assert!(ty.repr() < (1 << Self::TYPE_BITS)); | 
| 509 |  |  | 
| 510 | 4.72M |         ValueDataPacked( | 
| 511 | 4.72M |             (tag << Self::TAG_SHIFT) | 
| 512 | 4.72M |                 | ((ty.repr() as u64) << Self::TYPE_SHIFT) | 
| 513 | 4.72M |                 | ((num as u64) << Self::NUM_SHIFT) | 
| 514 | 4.72M |                 | ((index as u64) << Self::INDEX_SHIFT), | 
| 515 | 4.72M |         ) | 
| 516 | 4.72M |     } | 
| 517 |  |  | 
| 518 |  |     #[inline(always)] | 
| 519 | 574M |     fn field(self, shift: u64, bits: u64) -> u64 { | 
| 520 | 574M |         (self.0 >> shift) & ((1 << bits) - 1) | 
| 521 | 574M |     } | 
| 522 |  |  | 
| 523 |  |     #[inline(always)] | 
| 524 | 86.4M |     fn ty(self) -> Type { | 
| 525 | 86.4M |         let ty = self.field(ValueDataPacked::TYPE_SHIFT, ValueDataPacked::TYPE_BITS) as u16; | 
| 526 | 86.4M |         Type::from_repr(ty) | 
| 527 | 86.4M |     } | 
| 528 |  |  | 
| 529 |  |     #[inline(always)] | 
| 530 | 0 |     fn set_type(&mut self, ty: Type) { | 
| 531 | 0 |         self.0 &= !(((1 << Self::TYPE_BITS) - 1) << Self::TYPE_SHIFT); | 
| 532 | 0 |         self.0 |= (ty.repr() as u64) << Self::TYPE_SHIFT; | 
| 533 | 0 |     } | 
| 534 |  | } | 
| 535 |  |  | 
| 536 |  | impl From<ValueData> for ValueDataPacked { | 
| 537 | 4.72M |     fn from(data: ValueData) -> Self { | 
| 538 | 4.72M |         match data { | 
| 539 | 2.76M |             ValueData::Inst { ty, num, inst } => { | 
| 540 | 2.76M |                 Self::make(Self::TAG_INST, ty, num, inst.as_bits()) | 
| 541 |  |             } | 
| 542 | 666k |             ValueData::Param { ty, num, block } => { | 
| 543 | 666k |                 Self::make(Self::TAG_PARAM, ty, num, block.as_bits()) | 
| 544 |  |             } | 
| 545 | 1.29M |             ValueData::Alias { ty, original } => { | 
| 546 | 1.29M |                 Self::make(Self::TAG_ALIAS, ty, 0, original.as_bits()) | 
| 547 |  |             } | 
| 548 |  |         } | 
| 549 | 4.72M |     } | 
| 550 |  | } | 
| 551 |  |  | 
| 552 |  | impl From<ValueDataPacked> for ValueData { | 
| 553 | 121M |     fn from(data: ValueDataPacked) -> Self { | 
| 554 | 121M |         let tag = data.field(ValueDataPacked::TAG_SHIFT, ValueDataPacked::TAG_BITS); | 
| 555 | 121M |         let ty = data.field(ValueDataPacked::TYPE_SHIFT, ValueDataPacked::TYPE_BITS) as u16; | 
| 556 | 121M |         let num = data.field(ValueDataPacked::NUM_SHIFT, ValueDataPacked::NUM_BITS) as u16; | 
| 557 | 121M |         let index = data.field(ValueDataPacked::INDEX_SHIFT, ValueDataPacked::INDEX_BITS) as u32; | 
| 558 | 121M |  | 
| 559 | 121M |         let ty = Type::from_repr(ty); | 
| 560 | 121M |         match tag { | 
| 561 | 65.9M |             ValueDataPacked::TAG_INST => ValueData::Inst { | 
| 562 | 65.9M |                 ty, | 
| 563 | 65.9M |                 num, | 
| 564 | 65.9M |                 inst: Inst::from_bits(index), | 
| 565 | 65.9M |             }, | 
| 566 | 54.7M |             ValueDataPacked::TAG_PARAM => ValueData::Param { | 
| 567 | 54.7M |                 ty, | 
| 568 | 54.7M |                 num, | 
| 569 | 54.7M |                 block: Block::from_bits(index), | 
| 570 | 54.7M |             }, | 
| 571 | 1.17M |             ValueDataPacked::TAG_ALIAS => ValueData::Alias { | 
| 572 | 1.17M |                 ty, | 
| 573 | 1.17M |                 original: Value::from_bits(index), | 
| 574 | 1.17M |             }, | 
| 575 | 0 |             _ => panic!("Invalid tag {} in ValueDataPacked 0x{:x}", tag, data.0), | 
| 576 |  |         } | 
| 577 | 121M |     } | 
| 578 |  | } | 
| 579 |  |  | 
| 580 |  | /// Instructions. | 
| 581 |  | /// | 
| 582 |  | impl DataFlowGraph { | 
| 583 |  |     /// Create a new instruction. | 
| 584 |  |     /// | 
| 585 |  |     /// The type of the first result is indicated by `data.ty`. If the instruction produces | 
| 586 |  |     /// multiple results, also call `make_inst_results` to allocate value table entries. | 
| 587 | 3.03M |     pub fn make_inst(&mut self, data: InstructionData) -> Inst { | 
| 588 | 3.03M |         let n = self.num_insts() + 1; | 
| 589 | 3.03M |         self.results.resize(n); | 
| 590 | 3.03M |         self.insts.push(data) | 
| 591 | 3.03M |     } | 
| 592 |  |  | 
| 593 |  |     /// Declares a dynamic vector type | 
| 594 | 0 |     pub fn make_dynamic_ty(&mut self, data: DynamicTypeData) -> DynamicType { | 
| 595 | 0 |         self.dynamic_types.push(data) | 
| 596 | 0 |     } | 
| 597 |  |  | 
| 598 |  |     /// Returns an object that displays `inst`. | 
| 599 | 0 |     pub fn display_inst<'a>(&'a self, inst: Inst) -> DisplayInst<'a> { | 
| 600 | 0 |         DisplayInst(self, inst) | 
| 601 | 0 |     } | 
| 602 |  |  | 
| 603 |  |     /// Returns an object that displays the given `value`'s defining instruction. | 
| 604 |  |     /// | 
| 605 |  |     /// Panics if the value is not defined by an instruction (i.e. it is a basic | 
| 606 |  |     /// block argument). | 
| 607 | 0 |     pub fn display_value_inst(&self, value: Value) -> DisplayInst<'_> { | 
| 608 | 0 |         match self.value_def(value) { | 
| 609 | 0 |             ir::ValueDef::Result(inst, _) => self.display_inst(inst), | 
| 610 | 0 |             ir::ValueDef::Param(_, _) => panic!("value is not defined by an instruction"), | 
| 611 |  |         } | 
| 612 | 0 |     } | 
| 613 |  |  | 
| 614 |  |     /// Get all value arguments on `inst` as a slice. | 
| 615 | 66.4M |     pub fn inst_args(&self, inst: Inst) -> &[Value] { | 
| 616 | 66.4M |         self.insts[inst].arguments(&self.value_lists) | 
| 617 | 66.4M |     } | 
| 618 |  |  | 
| 619 |  |     /// Get all value arguments on `inst` as a mutable slice. | 
| 620 | 0 |     pub fn inst_args_mut(&mut self, inst: Inst) -> &mut [Value] { | 
| 621 | 0 |         self.insts[inst].arguments_mut(&mut self.value_lists) | 
| 622 | 0 |     } | 
| 623 |  |  | 
| 624 |  |     /// Get the fixed value arguments on `inst` as a slice. | 
| 625 | 19.9M |     pub fn inst_fixed_args(&self, inst: Inst) -> &[Value] { | 
| 626 | 19.9M |         let num_fixed_args = self[inst] | 
| 627 | 19.9M |             .opcode() | 
| 628 | 19.9M |             .constraints() | 
| 629 | 19.9M |             .num_fixed_value_arguments(); | 
| 630 | 19.9M |         &self.inst_args(inst)[..num_fixed_args] | 
| 631 | 19.9M |     } | 
| 632 |  |  | 
| 633 |  |     /// Get the fixed value arguments on `inst` as a mutable slice. | 
| 634 | 0 |     pub fn inst_fixed_args_mut(&mut self, inst: Inst) -> &mut [Value] { | 
| 635 | 0 |         let num_fixed_args = self[inst] | 
| 636 | 0 |             .opcode() | 
| 637 | 0 |             .constraints() | 
| 638 | 0 |             .num_fixed_value_arguments(); | 
| 639 | 0 |         &mut self.inst_args_mut(inst)[..num_fixed_args] | 
| 640 | 0 |     } | 
| 641 |  |  | 
| 642 |  |     /// Get the variable value arguments on `inst` as a slice. | 
| 643 | 4.24M |     pub fn inst_variable_args(&self, inst: Inst) -> &[Value] { | 
| 644 | 4.24M |         let num_fixed_args = self[inst] | 
| 645 | 4.24M |             .opcode() | 
| 646 | 4.24M |             .constraints() | 
| 647 | 4.24M |             .num_fixed_value_arguments(); | 
| 648 | 4.24M |         &self.inst_args(inst)[num_fixed_args..] | 
| 649 | 4.24M |     } | 
| 650 |  |  | 
| 651 |  |     /// Get the variable value arguments on `inst` as a mutable slice. | 
| 652 | 0 |     pub fn inst_variable_args_mut(&mut self, inst: Inst) -> &mut [Value] { | 
| 653 | 0 |         let num_fixed_args = self[inst] | 
| 654 | 0 |             .opcode() | 
| 655 | 0 |             .constraints() | 
| 656 | 0 |             .num_fixed_value_arguments(); | 
| 657 | 0 |         &mut self.inst_args_mut(inst)[num_fixed_args..] | 
| 658 | 0 |     } | 
| 659 |  |  | 
| 660 |  |     /// Create result values for an instruction that produces multiple results. | 
| 661 |  |     /// | 
| 662 |  |     /// Instructions that produce no result values only need to be created with `make_inst`, | 
| 663 |  |     /// otherwise call `make_inst_results` to allocate value table entries for the results. | 
| 664 |  |     /// | 
| 665 |  |     /// The result value types are determined from the instruction's value type constraints and the | 
| 666 |  |     /// provided `ctrl_typevar` type for polymorphic instructions. For non-polymorphic | 
| 667 |  |     /// instructions, `ctrl_typevar` is ignored, and `INVALID` can be used. | 
| 668 |  |     /// | 
| 669 |  |     /// The type of the first result value is also set, even if it was already set in the | 
| 670 |  |     /// `InstructionData` passed to `make_inst`. If this function is called with a single-result | 
| 671 |  |     /// instruction, that is the only effect. | 
| 672 | 2.93M |     pub fn make_inst_results(&mut self, inst: Inst, ctrl_typevar: Type) -> usize { | 
| 673 | 2.93M |         self.make_inst_results_reusing(inst, ctrl_typevar, iter::empty()) | 
| 674 | 2.93M |     } | 
| 675 |  |  | 
| 676 |  |     /// Create result values for `inst`, reusing the provided detached values. | 
| 677 |  |     /// | 
| 678 |  |     /// Create a new set of result values for `inst` using `ctrl_typevar` to determine the result | 
| 679 |  |     /// types. Any values provided by `reuse` will be reused. When `reuse` is exhausted or when it | 
| 680 |  |     /// produces `None`, a new value is created. | 
| 681 | 3.09M |     pub fn make_inst_results_reusing<I>( | 
| 682 | 3.09M |         &mut self, | 
| 683 | 3.09M |         inst: Inst, | 
| 684 | 3.09M |         ctrl_typevar: Type, | 
| 685 | 3.09M |         reuse: I, | 
| 686 | 3.09M |     ) -> usize | 
| 687 | 3.09M |     where | 
| 688 | 3.09M |         I: Iterator<Item = Option<Value>>, | 
| 689 | 3.09M |     { | 
| 690 | 3.09M |         let mut reuse = reuse.fuse(); | 
| 691 | 3.09M |  | 
| 692 | 3.09M |         self.results[inst].clear(&mut self.value_lists); | 
| 693 |  |  | 
| 694 |  |         // Get the call signature if this is a function call. | 
| 695 | 3.09M |         if let Some(sig) = self.call_signature(inst) { | 
| 696 |  |             // Create result values corresponding to the call return types. | 
| 697 | 104k |             debug_assert_eq!( | 
| 698 | 0 |                 self.insts[inst].opcode().constraints().num_fixed_results(), | 
| 699 |  |                 0 | 
| 700 |  |             ); | 
| 701 | 104k |             let num_results = self.signatures[sig].returns.len(); | 
| 702 | 104k |             for res_idx in 0..num_results { | 
| 703 | 49.6k |                 let ty = self.signatures[sig].returns[res_idx].value_type; | 
| 704 | 49.6k |                 if let Some(Some(v)) = reuse.next() { | 
| 705 | 0 |                     debug_assert_eq!(self.value_type(v), ty, "Reused {} is wrong type", ty); | 
| 706 | 0 |                     self.attach_result(inst, v); | 
| 707 | 49.6k |                 } else { | 
| 708 | 49.6k |                     self.append_result(inst, ty); | 
| 709 | 49.6k |                 } | 
| 710 |  |             } | 
| 711 | 104k |             num_results | 
| 712 |  |         } else { | 
| 713 |  |             // Create result values corresponding to the opcode's constraints. | 
| 714 | 2.99M |             let constraints = self.insts[inst].opcode().constraints(); | 
| 715 | 2.99M |             let num_results = constraints.num_fixed_results(); | 
| 716 | 2.99M |             for res_idx in 0..num_results { | 
| 717 | 2.54M |                 let ty = constraints.result_type(res_idx, ctrl_typevar); | 
| 718 | 2.54M |                 if let Some(Some(v)) = reuse.next() { | 
| 719 | 165k |                     debug_assert_eq!(self.value_type(v), ty, "Reused {} is wrong type", ty); | 
| 720 | 165k |                     self.attach_result(inst, v); | 
| 721 | 2.38M |                 } else { | 
| 722 | 2.38M |                     self.append_result(inst, ty); | 
| 723 | 2.38M |                 } | 
| 724 |  |             } | 
| 725 | 2.99M |             num_results | 
| 726 |  |         } | 
| 727 | 3.09M |     } <cranelift_codegen::ir::dfg::DataFlowGraph>::make_inst_results_reusing::<core::iter::sources::empty::Empty<core::option::Option<cranelift_codegen::ir::entities::Value>>>| Line | Count | Source |  | 681 | 2.93M |     pub fn make_inst_results_reusing<I>( |  | 682 | 2.93M |         &mut self, |  | 683 | 2.93M |         inst: Inst, |  | 684 | 2.93M |         ctrl_typevar: Type, |  | 685 | 2.93M |         reuse: I, |  | 686 | 2.93M |     ) -> usize |  | 687 | 2.93M |     where |  | 688 | 2.93M |         I: Iterator<Item = Option<Value>>, |  | 689 | 2.93M |     { |  | 690 | 2.93M |         let mut reuse = reuse.fuse(); |  | 691 | 2.93M |  |  | 692 | 2.93M |         self.results[inst].clear(&mut self.value_lists); |  | 693 |  |  |  | 694 |  |         // Get the call signature if this is a function call. |  | 695 | 2.93M |         if let Some(sig) = self.call_signature(inst) { |  | 696 |  |             // Create result values corresponding to the call return types. |  | 697 | 104k |             debug_assert_eq!( |  | 698 | 0 |                 self.insts[inst].opcode().constraints().num_fixed_results(), |  | 699 |  |                 0 |  | 700 |  |             ); |  | 701 | 104k |             let num_results = self.signatures[sig].returns.len(); |  | 702 | 104k |             for res_idx in 0..num_results { |  | 703 | 49.6k |                 let ty = self.signatures[sig].returns[res_idx].value_type; |  | 704 | 49.6k |                 if let Some(Some(v)) = reuse.next() { |  | 705 | 0 |                     debug_assert_eq!(self.value_type(v), ty, "Reused {} is wrong type", ty); |  | 706 | 0 |                     self.attach_result(inst, v); |  | 707 | 49.6k |                 } else { |  | 708 | 49.6k |                     self.append_result(inst, ty); |  | 709 | 49.6k |                 } |  | 710 |  |             } |  | 711 | 104k |             num_results |  | 712 |  |         } else { |  | 713 |  |             // Create result values corresponding to the opcode's constraints. |  | 714 | 2.82M |             let constraints = self.insts[inst].opcode().constraints(); |  | 715 | 2.82M |             let num_results = constraints.num_fixed_results(); |  | 716 | 2.82M |             for res_idx in 0..num_results { |  | 717 | 2.38M |                 let ty = constraints.result_type(res_idx, ctrl_typevar); |  | 718 | 2.38M |                 if let Some(Some(v)) = reuse.next() { |  | 719 | 0 |                     debug_assert_eq!(self.value_type(v), ty, "Reused {} is wrong type", ty); |  | 720 | 0 |                     self.attach_result(inst, v); |  | 721 | 2.38M |                 } else { |  | 722 | 2.38M |                     self.append_result(inst, ty); |  | 723 | 2.38M |                 } |  | 724 |  |             } |  | 725 | 2.82M |             num_results |  | 726 |  |         } |  | 727 | 2.93M |     } | 
Unexecuted instantiation: <cranelift_codegen::ir::dfg::DataFlowGraph>::make_inst_results_reusing::<core::iter::adapters::map::Map<core::slice::iter::Iter<cranelift_codegen::ir::entities::Value>, <cranelift_codegen::ir::dfg::DataFlowGraph>::make_inst_results_for_parser::{closure#1}>><cranelift_codegen::ir::dfg::DataFlowGraph>::make_inst_results_reusing::<core::iter::adapters::cloned::Cloned<core::slice::iter::Iter<core::option::Option<cranelift_codegen::ir::entities::Value>>>>| Line | Count | Source |  | 681 | 165k |     pub fn make_inst_results_reusing<I>( |  | 682 | 165k |         &mut self, |  | 683 | 165k |         inst: Inst, |  | 684 | 165k |         ctrl_typevar: Type, |  | 685 | 165k |         reuse: I, |  | 686 | 165k |     ) -> usize |  | 687 | 165k |     where |  | 688 | 165k |         I: Iterator<Item = Option<Value>>, |  | 689 | 165k |     { |  | 690 | 165k |         let mut reuse = reuse.fuse(); |  | 691 | 165k |  |  | 692 | 165k |         self.results[inst].clear(&mut self.value_lists); |  | 693 |  |  |  | 694 |  |         // Get the call signature if this is a function call. |  | 695 | 165k |         if let Some(sig) = self.call_signature(inst) { |  | 696 |  |             // Create result values corresponding to the call return types. |  | 697 | 0 |             debug_assert_eq!( |  | 698 | 0 |                 self.insts[inst].opcode().constraints().num_fixed_results(), |  | 699 |  |                 0 |  | 700 |  |             ); |  | 701 | 0 |             let num_results = self.signatures[sig].returns.len(); |  | 702 | 0 |             for res_idx in 0..num_results { |  | 703 | 0 |                 let ty = self.signatures[sig].returns[res_idx].value_type; |  | 704 | 0 |                 if let Some(Some(v)) = reuse.next() { |  | 705 | 0 |                     debug_assert_eq!(self.value_type(v), ty, "Reused {} is wrong type", ty); |  | 706 | 0 |                     self.attach_result(inst, v); |  | 707 | 0 |                 } else { |  | 708 | 0 |                     self.append_result(inst, ty); |  | 709 | 0 |                 } |  | 710 |  |             } |  | 711 | 0 |             num_results |  | 712 |  |         } else { |  | 713 |  |             // Create result values corresponding to the opcode's constraints. |  | 714 | 165k |             let constraints = self.insts[inst].opcode().constraints(); |  | 715 | 165k |             let num_results = constraints.num_fixed_results(); |  | 716 | 165k |             for res_idx in 0..num_results { |  | 717 | 165k |                 let ty = constraints.result_type(res_idx, ctrl_typevar); |  | 718 | 165k |                 if let Some(Some(v)) = reuse.next() { |  | 719 | 165k |                     debug_assert_eq!(self.value_type(v), ty, "Reused {} is wrong type", ty); |  | 720 | 165k |                     self.attach_result(inst, v); |  | 721 | 0 |                 } else { |  | 722 | 0 |                     self.append_result(inst, ty); |  | 723 | 0 |                 } |  | 724 |  |             } |  | 725 | 165k |             num_results |  | 726 |  |         } |  | 727 | 165k |     } | 
 | 
| 728 |  |  | 
| 729 |  |     /// Create a `ReplaceBuilder` that will replace `inst` with a new instruction in place. | 
| 730 | 232k |     pub fn replace(&mut self, inst: Inst) -> ReplaceBuilder { | 
| 731 | 232k |         ReplaceBuilder::new(self, inst) | 
| 732 | 232k |     } | 
| 733 |  |  | 
| 734 |  |     /// Detach the list of result values from `inst` and return it. | 
| 735 |  |     /// | 
| 736 |  |     /// This leaves `inst` without any result values. New result values can be created by calling | 
| 737 |  |     /// `make_inst_results` or by using a `replace(inst)` builder. | 
| 738 | 51.1k |     pub fn detach_results(&mut self, inst: Inst) -> ValueList { | 
| 739 | 51.1k |         self.results[inst].take() | 
| 740 | 51.1k |     } | 
| 741 |  |  | 
| 742 |  |     /// Clear the list of result values from `inst`. | 
| 743 |  |     /// | 
| 744 |  |     /// This leaves `inst` without any result values. New result values can be created by calling | 
| 745 |  |     /// `make_inst_results` or by using a `replace(inst)` builder. | 
| 746 | 1.28M |     pub fn clear_results(&mut self, inst: Inst) { | 
| 747 | 1.28M |         self.results[inst].clear(&mut self.value_lists) | 
| 748 | 1.28M |     } | 
| 749 |  |  | 
| 750 |  |     /// Attach an existing value to the result value list for `inst`. | 
| 751 |  |     /// | 
| 752 |  |     /// The `res` value is appended to the end of the result list. | 
| 753 |  |     /// | 
| 754 |  |     /// This is a very low-level operation. Usually, instruction results with the correct types are | 
| 755 |  |     /// created automatically. The `res` value must not be attached to anything else. | 
| 756 | 165k |     pub fn attach_result(&mut self, inst: Inst, res: Value) { | 
| 757 | 165k |         debug_assert!(!self.value_is_attached(res)); | 
| 758 | 165k |         let num = self.results[inst].push(res, &mut self.value_lists); | 
| 759 | 165k |         debug_assert!(num <= u16::MAX as usize, "Too many result values"); | 
| 760 | 165k |         let ty = self.value_type(res); | 
| 761 | 165k |         self.values[res] = ValueData::Inst { | 
| 762 | 165k |             ty, | 
| 763 | 165k |             num: num as u16, | 
| 764 | 165k |             inst, | 
| 765 | 165k |         } | 
| 766 | 165k |         .into(); | 
| 767 | 165k |     } | 
| 768 |  |  | 
| 769 |  |     /// Replace an instruction result with a new value of type `new_type`. | 
| 770 |  |     /// | 
| 771 |  |     /// The `old_value` must be an attached instruction result. | 
| 772 |  |     /// | 
| 773 |  |     /// The old value is left detached, so it should probably be changed into something else. | 
| 774 |  |     /// | 
| 775 |  |     /// Returns the new value. | 
| 776 | 165k |     pub fn replace_result(&mut self, old_value: Value, new_type: Type) -> Value { | 
| 777 | 165k |         let (num, inst) = match ValueData::from(self.values[old_value]) { | 
| 778 | 165k |             ValueData::Inst { num, inst, .. } => (num, inst), | 
| 779 | 0 |             _ => panic!("{} is not an instruction result value", old_value), | 
| 780 |  |         }; | 
| 781 | 165k |         let new_value = self.make_value(ValueData::Inst { | 
| 782 | 165k |             ty: new_type, | 
| 783 | 165k |             num, | 
| 784 | 165k |             inst, | 
| 785 | 165k |         }); | 
| 786 | 165k |         let num = num as usize; | 
| 787 | 165k |         let attached = mem::replace( | 
| 788 | 165k |             self.results[inst] | 
| 789 | 165k |                 .get_mut(num, &mut self.value_lists) | 
| 790 | 165k |                 .expect("Replacing detached result"), | 
| 791 | 165k |             new_value, | 
| 792 | 165k |         ); | 
| 793 | 165k |         debug_assert_eq!( | 
| 794 |  |             attached, | 
| 795 |  |             old_value, | 
| 796 | 0 |             "{} wasn't detached from {}", | 
| 797 | 0 |             old_value, | 
| 798 | 0 |             self.display_inst(inst) | 
| 799 |  |         ); | 
| 800 | 165k |         new_value | 
| 801 | 165k |     } | 
| 802 |  |  | 
| 803 |  |     /// Append a new instruction result value to `inst`. | 
| 804 | 2.43M |     pub fn append_result(&mut self, inst: Inst, ty: Type) -> Value { | 
| 805 | 2.43M |         let res = self.values.next_key(); | 
| 806 | 2.43M |         let num = self.results[inst].push(res, &mut self.value_lists); | 
| 807 | 2.43M |         debug_assert!(num <= u16::MAX as usize, "Too many result values"); | 
| 808 | 2.43M |         self.make_value(ValueData::Inst { | 
| 809 | 2.43M |             ty, | 
| 810 | 2.43M |             inst, | 
| 811 | 2.43M |             num: num as u16, | 
| 812 | 2.43M |         }) | 
| 813 | 2.43M |     } | 
| 814 |  |  | 
| 815 |  |     /// Append a new value argument to an instruction. | 
| 816 |  |     /// | 
| 817 |  |     /// Panics if the instruction doesn't support arguments. | 
| 818 | 194 |     pub fn append_inst_arg(&mut self, inst: Inst, new_arg: Value) { | 
| 819 | 194 |         let mut branch_values = self.insts[inst] | 
| 820 | 194 |             .take_value_list() | 
| 821 | 194 |             .expect("the instruction doesn't have value arguments"); | 
| 822 | 194 |         branch_values.push(new_arg, &mut self.value_lists); | 
| 823 | 194 |         self.insts[inst].put_value_list(branch_values) | 
| 824 | 194 |     } | 
| 825 |  |  | 
| 826 |  |     /// Get the first result of an instruction. | 
| 827 |  |     /// | 
| 828 |  |     /// This function panics if the instruction doesn't have any result. | 
| 829 | 15.3M |     pub fn first_result(&self, inst: Inst) -> Value { | 
| 830 | 15.3M |         self.results[inst] | 
| 831 | 15.3M |             .first(&self.value_lists) | 
| 832 | 15.3M |             .expect("Instruction has no results") | 
| 833 | 15.3M |     } | 
| 834 |  |  | 
| 835 |  |     /// Test if `inst` has any result values currently. | 
| 836 | 232k |     pub fn has_results(&self, inst: Inst) -> bool { | 
| 837 | 232k |         !self.results[inst].is_empty() | 
| 838 | 232k |     } | 
| 839 |  |  | 
| 840 |  |     /// Return all the results of an instruction. | 
| 841 | 85.9M |     pub fn inst_results(&self, inst: Inst) -> &[Value] { | 
| 842 | 85.9M |         self.results[inst].as_slice(&self.value_lists) | 
| 843 | 85.9M |     } | 
| 844 |  |  | 
| 845 |  |     /// Return all the results of an instruction as ValueList. | 
| 846 | 0 |     pub fn inst_results_list(&self, inst: Inst) -> ValueList { | 
| 847 | 0 |         self.results[inst] | 
| 848 | 0 |     } | 
| 849 |  |  | 
| 850 |  |     /// Get the call signature of a direct or indirect call instruction. | 
| 851 |  |     /// Returns `None` if `inst` is not a call instruction. | 
| 852 | 43.2M |     pub fn call_signature(&self, inst: Inst) -> Option<SigRef> { | 
| 853 | 43.2M |         match self.insts[inst].analyze_call(&self.value_lists) { | 
| 854 | 40.5M |             CallInfo::NotACall => None, | 
| 855 | 602k |             CallInfo::Direct(f, _) => Some(self.ext_funcs[f].signature), | 
| 856 | 2.09M |             CallInfo::Indirect(s, _) => Some(s), | 
| 857 |  |         } | 
| 858 | 43.2M |     } | 
| 859 |  |  | 
| 860 |  |     /// Check if `inst` is a branch. | 
| 861 | 50.6M |     pub fn analyze_branch(&self, inst: Inst) -> BranchInfo { | 
| 862 | 50.6M |         self.insts[inst].analyze_branch(&self.value_lists) | 
| 863 | 50.6M |     } | 
| 864 |  |  | 
| 865 |  |     /// Compute the type of an instruction result from opcode constraints and call signatures. | 
| 866 |  |     /// | 
| 867 |  |     /// This computes the same sequence of result types that `make_inst_results()` above would | 
| 868 |  |     /// assign to the created result values, but it does not depend on `make_inst_results()` being | 
| 869 |  |     /// called first. | 
| 870 |  |     /// | 
| 871 |  |     /// Returns `None` if asked about a result index that is too large. | 
| 872 | 35.1M |     pub fn compute_result_type( | 
| 873 | 35.1M |         &self, | 
| 874 | 35.1M |         inst: Inst, | 
| 875 | 35.1M |         result_idx: usize, | 
| 876 | 35.1M |         ctrl_typevar: Type, | 
| 877 | 35.1M |     ) -> Option<Type> { | 
| 878 | 35.1M |         let constraints = self.insts[inst].opcode().constraints(); | 
| 879 | 35.1M |         let num_fixed_results = constraints.num_fixed_results(); | 
| 880 | 35.1M |  | 
| 881 | 35.1M |         if result_idx < num_fixed_results { | 
| 882 | 14.8M |             return Some(constraints.result_type(result_idx, ctrl_typevar)); | 
| 883 | 20.3M |         } | 
| 884 | 20.3M |  | 
| 885 | 20.3M |         // Not a fixed result, try to extract a return type from the call signature. | 
| 886 | 20.3M |         self.call_signature(inst).and_then(|sigref| { | 
| 887 | 1.54M |             self.signatures[sigref] | 
| 888 | 1.54M |                 .returns | 
| 889 | 1.54M |                 .get(result_idx - num_fixed_results) | 
| 890 | 1.54M |                 .map(|&arg| arg.value_type) | 
| 891 | 20.3M |         }) | 
| 892 | 35.1M |     } | 
| 893 |  |  | 
| 894 |  |     /// Get the controlling type variable, or `INVALID` if `inst` isn't polymorphic. | 
| 895 | 15.8M |     pub fn ctrl_typevar(&self, inst: Inst) -> Type { | 
| 896 | 15.8M |         let constraints = self[inst].opcode().constraints(); | 
| 897 | 15.8M |  | 
| 898 | 15.8M |         if !constraints.is_polymorphic() { | 
| 899 | 730k |             types::INVALID | 
| 900 | 15.1M |         } else if constraints.requires_typevar_operand() { | 
| 901 |  |             // Not all instruction formats have a designated operand, but in that case | 
| 902 |  |             // `requires_typevar_operand()` should never be true. | 
| 903 | 2.75M |             self.value_type( | 
| 904 | 2.75M |                 self[inst] | 
| 905 | 2.75M |                     .typevar_operand(&self.value_lists) | 
| 906 | 2.75M |                     .unwrap_or_else(|| { | 
| 907 | 0 |                         panic!( | 
| 908 | 0 |                             "Instruction format for {:?} doesn't have a designated operand", | 
| 909 | 0 |                             self[inst] | 
| 910 | 0 |                         ) | 
| 911 | 2.75M |                     }), | 
| 912 | 2.75M |             ) | 
| 913 |  |         } else { | 
| 914 | 12.3M |             self.value_type(self.first_result(inst)) | 
| 915 |  |         } | 
| 916 | 15.8M |     } | 
| 917 |  | } | 
| 918 |  |  | 
| 919 |  | /// Allow immutable access to instructions via indexing. | 
| 920 |  | impl Index<Inst> for DataFlowGraph { | 
| 921 |  |     type Output = InstructionData; | 
| 922 |  |  | 
| 923 | 294M |     fn index(&self, inst: Inst) -> &InstructionData { | 
| 924 | 294M |         &self.insts[inst] | 
| 925 | 294M |     } | 
| 926 |  | } | 
| 927 |  |  | 
| 928 |  | /// Allow mutable access to instructions via indexing. | 
| 929 |  | impl IndexMut<Inst> for DataFlowGraph { | 
| 930 | 241k |     fn index_mut(&mut self, inst: Inst) -> &mut InstructionData { | 
| 931 | 241k |         &mut self.insts[inst] | 
| 932 | 241k |     } | 
| 933 |  | } | 
| 934 |  |  | 
| 935 |  | /// basic blocks. | 
| 936 |  | impl DataFlowGraph { | 
| 937 |  |     /// Create a new basic block. | 
| 938 | 505k |     pub fn make_block(&mut self) -> Block { | 
| 939 | 505k |         self.blocks.push(BlockData::new()) | 
| 940 | 505k |     } | 
| 941 |  |  | 
| 942 |  |     /// Get the number of parameters on `block`. | 
| 943 | 1.43M |     pub fn num_block_params(&self, block: Block) -> usize { | 
| 944 | 1.43M |         self.blocks[block].params.len(&self.value_lists) | 
| 945 | 1.43M |     } | 
| 946 |  |  | 
| 947 |  |     /// Get the parameters on `block`. | 
| 948 | 28.1M |     pub fn block_params(&self, block: Block) -> &[Value] { | 
| 949 | 28.1M |         self.blocks[block].params.as_slice(&self.value_lists) | 
| 950 | 28.1M |     } | 
| 951 |  |  | 
| 952 |  |     /// Get the types of the parameters on `block`. | 
| 953 | 8.60k |     pub fn block_param_types(&self, block: Block) -> impl Iterator<Item = Type> + '_ { | 
| 954 | 8.60k |         self.block_params(block).iter().map(|&v| self.value_type(v)) | 
| 955 | 8.60k |     } | 
| 956 |  |  | 
| 957 |  |     /// Append a parameter with type `ty` to `block`. | 
| 958 | 665k |     pub fn append_block_param(&mut self, block: Block, ty: Type) -> Value { | 
| 959 | 665k |         let param = self.values.next_key(); | 
| 960 | 665k |         let num = self.blocks[block].params.push(param, &mut self.value_lists); | 
| 961 | 665k |         debug_assert!(num <= u16::MAX as usize, "Too many parameters on block"); | 
| 962 | 665k |         self.make_value(ValueData::Param { | 
| 963 | 665k |             ty, | 
| 964 | 665k |             num: num as u16, | 
| 965 | 665k |             block, | 
| 966 | 665k |         }) | 
| 967 | 665k |     } | 
| 968 |  |  | 
| 969 |  |     /// Removes `val` from `block`'s parameters by swapping it with the last parameter on `block`. | 
| 970 |  |     /// Returns the position of `val` before removal. | 
| 971 |  |     /// | 
| 972 |  |     /// *Important*: to ensure O(1) deletion, this method swaps the removed parameter with the | 
| 973 |  |     /// last `block` parameter. This can disrupt all the branch instructions jumping to this | 
| 974 |  |     /// `block` for which you have to change the branch argument order if necessary. | 
| 975 |  |     /// | 
| 976 |  |     /// Panics if `val` is not a block parameter. | 
| 977 | 0 |     pub fn swap_remove_block_param(&mut self, val: Value) -> usize { | 
| 978 | 0 |         let (block, num) = | 
| 979 | 0 |             if let ValueData::Param { num, block, .. } = ValueData::from(self.values[val]) { | 
| 980 | 0 |                 (block, num) | 
| 981 |  |             } else { | 
| 982 | 0 |                 panic!("{} must be a block parameter", val); | 
| 983 |  |             }; | 
| 984 | 0 |         self.blocks[block] | 
| 985 | 0 |             .params | 
| 986 | 0 |             .swap_remove(num as usize, &mut self.value_lists); | 
| 987 | 0 |         if let Some(last_arg_val) = self.blocks[block] | 
| 988 | 0 |             .params | 
| 989 | 0 |             .get(num as usize, &self.value_lists) | 
| 990 |  |         { | 
| 991 |  |             // We update the position of the old last arg. | 
| 992 | 0 |             let mut last_arg_data = ValueData::from(self.values[last_arg_val]); | 
| 993 |  |             if let ValueData::Param { | 
| 994 | 0 |                 num: ref mut old_num, | 
| 995 |  |                 .. | 
| 996 | 0 |             } = &mut last_arg_data | 
| 997 | 0 |             { | 
| 998 | 0 |                 *old_num = num; | 
| 999 | 0 |                 self.values[last_arg_val] = last_arg_data.into(); | 
| 1000 | 0 |             } else { | 
| 1001 | 0 |                 panic!("{} should be a Block parameter", last_arg_val); | 
| 1002 |  |             } | 
| 1003 | 0 |         } | 
| 1004 | 0 |         num as usize | 
| 1005 | 0 |     } | 
| 1006 |  |  | 
| 1007 |  |     /// Removes `val` from `block`'s parameters by a standard linear time list removal which | 
| 1008 |  |     /// preserves ordering. Also updates the values' data. | 
| 1009 | 10.7k |     pub fn remove_block_param(&mut self, val: Value) { | 
| 1010 | 10.7k |         let (block, num) = | 
| 1011 | 10.7k |             if let ValueData::Param { num, block, .. } = ValueData::from(self.values[val]) { | 
| 1012 | 10.7k |                 (block, num) | 
| 1013 |  |             } else { | 
| 1014 | 0 |                 panic!("{} must be a block parameter", val); | 
| 1015 |  |             }; | 
| 1016 | 10.7k |         self.blocks[block] | 
| 1017 | 10.7k |             .params | 
| 1018 | 10.7k |             .remove(num as usize, &mut self.value_lists); | 
| 1019 | 10.7k |         for index in num..(self.num_block_params(block) as u16) { | 
| 1020 | 828 |             let packed = &mut self.values[self.blocks[block] | 
| 1021 | 828 |                 .params | 
| 1022 | 828 |                 .get(index as usize, &self.value_lists) | 
| 1023 | 828 |                 .unwrap()]; | 
| 1024 | 828 |             let mut data = ValueData::from(*packed); | 
| 1025 | 828 |             match &mut data { | 
| 1026 | 828 |                 ValueData::Param { ref mut num, .. } => { | 
| 1027 | 828 |                     *num -= 1; | 
| 1028 | 828 |                     *packed = data.into(); | 
| 1029 | 828 |                 } | 
| 1030 | 0 |                 _ => panic!( | 
| 1031 | 0 |                     "{} must be a block parameter", | 
| 1032 | 0 |                     self.blocks[block] | 
| 1033 | 0 |                         .params | 
| 1034 | 0 |                         .get(index as usize, &self.value_lists) | 
| 1035 | 0 |                         .unwrap() | 
| 1036 | 0 |                 ), | 
| 1037 |  |             } | 
| 1038 |  |         } | 
| 1039 | 10.7k |     } | 
| 1040 |  |  | 
| 1041 |  |     /// Append an existing value to `block`'s parameters. | 
| 1042 |  |     /// | 
| 1043 |  |     /// The appended value can't already be attached to something else. | 
| 1044 |  |     /// | 
| 1045 |  |     /// In almost all cases, you should be using `append_block_param()` instead of this method. | 
| 1046 | 0 |     pub fn attach_block_param(&mut self, block: Block, param: Value) { | 
| 1047 | 0 |         debug_assert!(!self.value_is_attached(param)); | 
| 1048 | 0 |         let num = self.blocks[block].params.push(param, &mut self.value_lists); | 
| 1049 | 0 |         debug_assert!(num <= u16::MAX as usize, "Too many parameters on block"); | 
| 1050 | 0 |         let ty = self.value_type(param); | 
| 1051 | 0 |         self.values[param] = ValueData::Param { | 
| 1052 | 0 |             ty, | 
| 1053 | 0 |             num: num as u16, | 
| 1054 | 0 |             block, | 
| 1055 | 0 |         } | 
| 1056 | 0 |         .into(); | 
| 1057 | 0 |     } | 
| 1058 |  |  | 
| 1059 |  |     /// Replace a block parameter with a new value of type `ty`. | 
| 1060 |  |     /// | 
| 1061 |  |     /// The `old_value` must be an attached block parameter. It is removed from its place in the list | 
| 1062 |  |     /// of parameters and replaced by a new value of type `new_type`. The new value gets the same | 
| 1063 |  |     /// position in the list, and other parameters are not disturbed. | 
| 1064 |  |     /// | 
| 1065 |  |     /// The old value is left detached, so it should probably be changed into something else. | 
| 1066 |  |     /// | 
| 1067 |  |     /// Returns the new value. | 
| 1068 | 0 |     pub fn replace_block_param(&mut self, old_value: Value, new_type: Type) -> Value { | 
| 1069 |  |         // Create new value identical to the old one except for the type. | 
| 1070 | 0 |         let (block, num) = | 
| 1071 | 0 |             if let ValueData::Param { num, block, .. } = ValueData::from(self.values[old_value]) { | 
| 1072 | 0 |                 (block, num) | 
| 1073 |  |             } else { | 
| 1074 | 0 |                 panic!("{} must be a block parameter", old_value); | 
| 1075 |  |             }; | 
| 1076 | 0 |         let new_arg = self.make_value(ValueData::Param { | 
| 1077 | 0 |             ty: new_type, | 
| 1078 | 0 |             num, | 
| 1079 | 0 |             block, | 
| 1080 | 0 |         }); | 
| 1081 | 0 | 
 | 
| 1082 | 0 |         self.blocks[block] | 
| 1083 | 0 |             .params | 
| 1084 | 0 |             .as_mut_slice(&mut self.value_lists)[num as usize] = new_arg; | 
| 1085 | 0 |         new_arg | 
| 1086 | 0 |     } | 
| 1087 |  |  | 
| 1088 |  |     /// Detach all the parameters from `block` and return them as a `ValueList`. | 
| 1089 |  |     /// | 
| 1090 |  |     /// This is a quite low-level operation. Sensible things to do with the detached block parameters | 
| 1091 |  |     /// is to put them back on the same block with `attach_block_param()` or change them into aliases | 
| 1092 |  |     /// with `change_to_alias()`. | 
| 1093 | 0 |     pub fn detach_block_params(&mut self, block: Block) -> ValueList { | 
| 1094 | 0 |         self.blocks[block].params.take() | 
| 1095 | 0 |     } | 
| 1096 |  | } | 
| 1097 |  |  | 
| 1098 |  | /// Contents of a basic block. | 
| 1099 |  | /// | 
| 1100 |  | /// Parameters on a basic block are values that dominate everything in the block. All | 
| 1101 |  | /// branches to this block must provide matching arguments, and the arguments to the entry block must | 
| 1102 |  | /// match the function arguments. | 
| 1103 |  | #[derive(Clone, PartialEq, Hash)] | 
| 1104 |  | #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] | 
| 1105 |  | struct BlockData { | 
| 1106 |  |     /// List of parameters to this block. | 
| 1107 |  |     params: ValueList, | 
| 1108 |  | } | 
| 1109 |  |  | 
| 1110 |  | impl BlockData { | 
| 1111 | 505k |     fn new() -> Self { | 
| 1112 | 505k |         Self { | 
| 1113 | 505k |             params: ValueList::new(), | 
| 1114 | 505k |         } | 
| 1115 | 505k |     } | 
| 1116 |  | } | 
| 1117 |  |  | 
| 1118 |  | /// Object that can display an instruction. | 
| 1119 |  | pub struct DisplayInst<'a>(&'a DataFlowGraph, Inst); | 
| 1120 |  |  | 
| 1121 |  | impl<'a> fmt::Display for DisplayInst<'a> { | 
| 1122 | 0 |     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | 
| 1123 | 0 |         let dfg = self.0; | 
| 1124 | 0 |         let inst = self.1; | 
| 1125 |  |  | 
| 1126 | 0 |         if let Some((first, rest)) = dfg.inst_results(inst).split_first() { | 
| 1127 | 0 |             write!(f, "{}", first)?; | 
| 1128 | 0 |             for v in rest { | 
| 1129 | 0 |                 write!(f, ", {}", v)?; | 
| 1130 |  |             } | 
| 1131 | 0 |             write!(f, " = ")?; | 
| 1132 | 0 |         } | 
| 1133 |  |  | 
| 1134 | 0 |         let typevar = dfg.ctrl_typevar(inst); | 
| 1135 | 0 |         if typevar.is_invalid() { | 
| 1136 | 0 |             write!(f, "{}", dfg[inst].opcode())?; | 
| 1137 |  |         } else { | 
| 1138 | 0 |             write!(f, "{}.{}", dfg[inst].opcode(), typevar)?; | 
| 1139 |  |         } | 
| 1140 | 0 |         write_operands(f, dfg, inst) | 
| 1141 | 0 |     } | 
| 1142 |  | } | 
| 1143 |  |  | 
| 1144 |  | /// Parser routines. These routines should not be used outside the parser. | 
| 1145 |  | impl DataFlowGraph { | 
| 1146 |  |     /// Set the type of a value. This is only for use in the parser, which needs | 
| 1147 |  |     /// to create invalid values for index padding which may be reassigned later. | 
| 1148 |  |     #[cold] | 
| 1149 | 0 |     fn set_value_type_for_parser(&mut self, v: Value, t: Type) { | 
| 1150 | 0 |         assert_eq!( | 
| 1151 | 0 |             self.value_type(v), | 
| 1152 |  |             types::INVALID, | 
| 1153 | 0 |             "this function is only for assigning types to previously invalid values" | 
| 1154 |  |         ); | 
| 1155 | 0 |         self.values[v].set_type(t); | 
| 1156 | 0 |     } | 
| 1157 |  |  | 
| 1158 |  |     /// Check that the given concrete `Type` has been defined in the function. | 
| 1159 | 0 |     pub fn check_dynamic_type(&mut self, ty: Type) -> Option<Type> { | 
| 1160 | 0 |         debug_assert!(ty.is_dynamic_vector()); | 
| 1161 | 0 |         if self | 
| 1162 | 0 |             .dynamic_types | 
| 1163 | 0 |             .values() | 
| 1164 | 0 |             .any(|dyn_ty_data| dyn_ty_data.concrete().unwrap() == ty) | 
| 1165 |  |         { | 
| 1166 | 0 |             Some(ty) | 
| 1167 |  |         } else { | 
| 1168 | 0 |             None | 
| 1169 |  |         } | 
| 1170 | 0 |     } | 
| 1171 |  |  | 
| 1172 |  |     /// Create result values for `inst`, reusing the provided detached values. | 
| 1173 |  |     /// This is similar to `make_inst_results_reusing` except it's only for use | 
| 1174 |  |     /// in the parser, which needs to reuse previously invalid values. | 
| 1175 |  |     #[cold] | 
| 1176 | 0 |     pub fn make_inst_results_for_parser( | 
| 1177 | 0 |         &mut self, | 
| 1178 | 0 |         inst: Inst, | 
| 1179 | 0 |         ctrl_typevar: Type, | 
| 1180 | 0 |         reuse: &[Value], | 
| 1181 | 0 |     ) -> usize { | 
| 1182 |  |         // Get the call signature if this is a function call. | 
| 1183 | 0 |         if let Some(sig) = self.call_signature(inst) { | 
| 1184 | 0 |             assert_eq!( | 
| 1185 | 0 |                 self.insts[inst].opcode().constraints().num_fixed_results(), | 
| 1186 | 0 |                 0 | 
| 1187 | 0 |             ); | 
| 1188 | 0 |             for res_idx in 0..self.signatures[sig].returns.len() { | 
| 1189 | 0 |                 let ty = self.signatures[sig].returns[res_idx].value_type; | 
| 1190 | 0 |                 if let Some(v) = reuse.get(res_idx) { | 
| 1191 | 0 |                     self.set_value_type_for_parser(*v, ty); | 
| 1192 | 0 |                 } | 
| 1193 |  |             } | 
| 1194 |  |         } else { | 
| 1195 | 0 |             let constraints = self.insts[inst].opcode().constraints(); | 
| 1196 | 0 |             for res_idx in 0..constraints.num_fixed_results() { | 
| 1197 | 0 |                 let ty = constraints.result_type(res_idx, ctrl_typevar); | 
| 1198 | 0 |                 if ty.is_dynamic_vector() { | 
| 1199 | 0 |                     self.check_dynamic_type(ty) | 
| 1200 | 0 |                         .unwrap_or_else(|| panic!("Use of undeclared dynamic type: {}", ty)); | 
| 1201 | 0 |                 } | 
| 1202 | 0 |                 if let Some(v) = reuse.get(res_idx) { | 
| 1203 | 0 |                     self.set_value_type_for_parser(*v, ty); | 
| 1204 | 0 |                 } | 
| 1205 |  |             } | 
| 1206 |  |         } | 
| 1207 |  |  | 
| 1208 | 0 |         self.make_inst_results_reusing(inst, ctrl_typevar, reuse.iter().map(|x| Some(*x))) | 
| 1209 | 0 |     } | 
| 1210 |  |  | 
| 1211 |  |     /// Similar to `append_block_param`, append a parameter with type `ty` to | 
| 1212 |  |     /// `block`, but using value `val`. This is only for use by the parser to | 
| 1213 |  |     /// create parameters with specific values. | 
| 1214 |  |     #[cold] | 
| 1215 | 0 |     pub fn append_block_param_for_parser(&mut self, block: Block, ty: Type, val: Value) { | 
| 1216 | 0 |         let num = self.blocks[block].params.push(val, &mut self.value_lists); | 
| 1217 | 0 |         assert!(num <= u16::MAX as usize, "Too many parameters on block"); | 
| 1218 | 0 |         self.values[val] = ValueData::Param { | 
| 1219 | 0 |             ty, | 
| 1220 | 0 |             num: num as u16, | 
| 1221 | 0 |             block, | 
| 1222 | 0 |         } | 
| 1223 | 0 |         .into(); | 
| 1224 | 0 |     } | 
| 1225 |  |  | 
| 1226 |  |     /// Create a new value alias. This is only for use by the parser to create | 
| 1227 |  |     /// aliases with specific values, and the printer for testing. | 
| 1228 |  |     #[cold] | 
| 1229 | 0 |     pub fn make_value_alias_for_serialization(&mut self, src: Value, dest: Value) { | 
| 1230 | 0 |         assert_ne!(src, Value::reserved_value()); | 
| 1231 | 0 |         assert_ne!(dest, Value::reserved_value()); | 
| 1232 |  |  | 
| 1233 | 0 |         let ty = if self.values.is_valid(src) { | 
| 1234 | 0 |             self.value_type(src) | 
| 1235 |  |         } else { | 
| 1236 |  |             // As a special case, if we can't resolve the aliasee yet, use INVALID | 
| 1237 |  |             // temporarily. It will be resolved later in parsing. | 
| 1238 | 0 |             types::INVALID | 
| 1239 |  |         }; | 
| 1240 | 0 |         let data = ValueData::Alias { ty, original: src }; | 
| 1241 | 0 |         self.values[dest] = data.into(); | 
| 1242 | 0 |     } | 
| 1243 |  |  | 
| 1244 |  |     /// If `v` is already defined as an alias, return its destination value. | 
| 1245 |  |     /// Otherwise return None. This allows the parser to coalesce identical | 
| 1246 |  |     /// alias definitions, and the printer to identify an alias's immediate target. | 
| 1247 |  |     #[cold] | 
| 1248 | 0 |     pub fn value_alias_dest_for_serialization(&self, v: Value) -> Option<Value> { | 
| 1249 | 0 |         if let ValueData::Alias { original, .. } = ValueData::from(self.values[v]) { | 
| 1250 | 0 |             Some(original) | 
| 1251 |  |         } else { | 
| 1252 | 0 |             None | 
| 1253 |  |         } | 
| 1254 | 0 |     } | 
| 1255 |  |  | 
| 1256 |  |     /// Compute the type of an alias. This is only for use in the parser. | 
| 1257 |  |     /// Returns false if an alias cycle was encountered. | 
| 1258 |  |     #[cold] | 
| 1259 | 0 |     pub fn set_alias_type_for_parser(&mut self, v: Value) -> bool { | 
| 1260 | 0 |         if let Some(resolved) = maybe_resolve_aliases(&self.values, v) { | 
| 1261 | 0 |             let old_ty = self.value_type(v); | 
| 1262 | 0 |             let new_ty = self.value_type(resolved); | 
| 1263 | 0 |             if old_ty == types::INVALID { | 
| 1264 | 0 |                 self.set_value_type_for_parser(v, new_ty); | 
| 1265 | 0 |             } else { | 
| 1266 | 0 |                 assert_eq!(old_ty, new_ty); | 
| 1267 |  |             } | 
| 1268 | 0 |             true | 
| 1269 |  |         } else { | 
| 1270 | 0 |             false | 
| 1271 |  |         } | 
| 1272 | 0 |     } | 
| 1273 |  |  | 
| 1274 |  |     /// Create an invalid value, to pad the index space. This is only for use by | 
| 1275 |  |     /// the parser to pad out the value index space. | 
| 1276 |  |     #[cold] | 
| 1277 | 0 |     pub fn make_invalid_value_for_parser(&mut self) { | 
| 1278 | 0 |         let data = ValueData::Alias { | 
| 1279 | 0 |             ty: types::INVALID, | 
| 1280 | 0 |             original: Value::reserved_value(), | 
| 1281 | 0 |         }; | 
| 1282 | 0 |         self.make_value(data); | 
| 1283 | 0 |     } | 
| 1284 |  |  | 
| 1285 |  |     /// Check if a value reference is valid, while being aware of aliases which | 
| 1286 |  |     /// may be unresolved while parsing. | 
| 1287 |  |     #[cold] | 
| 1288 | 0 |     pub fn value_is_valid_for_parser(&self, v: Value) -> bool { | 
| 1289 | 0 |         if !self.value_is_valid(v) { | 
| 1290 | 0 |             return false; | 
| 1291 | 0 |         } | 
| 1292 | 0 |         if let ValueData::Alias { ty, .. } = ValueData::from(self.values[v]) { | 
| 1293 | 0 |             ty != types::INVALID | 
| 1294 |  |         } else { | 
| 1295 | 0 |             true | 
| 1296 |  |         } | 
| 1297 | 0 |     } | 
| 1298 |  | } | 
| 1299 |  |  | 
| 1300 |  | #[cfg(test)] | 
| 1301 |  | mod tests { | 
| 1302 |  |     use super::*; | 
| 1303 |  |     use crate::cursor::{Cursor, FuncCursor}; | 
| 1304 |  |     use crate::ir::types; | 
| 1305 |  |     use crate::ir::{Function, InstructionData, Opcode, TrapCode}; | 
| 1306 |  |     use alloc::string::ToString; | 
| 1307 |  |  | 
| 1308 |  |     #[test] | 
| 1309 |  |     fn make_inst() { | 
| 1310 |  |         let mut dfg = DataFlowGraph::new(); | 
| 1311 |  |  | 
| 1312 |  |         let idata = InstructionData::UnaryImm { | 
| 1313 |  |             opcode: Opcode::Iconst, | 
| 1314 |  |             imm: 0.into(), | 
| 1315 |  |         }; | 
| 1316 |  |         let inst = dfg.make_inst(idata); | 
| 1317 |  |  | 
| 1318 |  |         dfg.make_inst_results(inst, types::I32); | 
| 1319 |  |         assert_eq!(inst.to_string(), "inst0"); | 
| 1320 |  |         assert_eq!(dfg.display_inst(inst).to_string(), "v0 = iconst.i32 0"); | 
| 1321 |  |  | 
| 1322 |  |         // Immutable reference resolution. | 
| 1323 |  |         { | 
| 1324 |  |             let immdfg = &dfg; | 
| 1325 |  |             let ins = &immdfg[inst]; | 
| 1326 |  |             assert_eq!(ins.opcode(), Opcode::Iconst); | 
| 1327 |  |         } | 
| 1328 |  |  | 
| 1329 |  |         // Results. | 
| 1330 |  |         let val = dfg.first_result(inst); | 
| 1331 |  |         assert_eq!(dfg.inst_results(inst), &[val]); | 
| 1332 |  |  | 
| 1333 |  |         assert_eq!(dfg.value_def(val), ValueDef::Result(inst, 0)); | 
| 1334 |  |         assert_eq!(dfg.value_type(val), types::I32); | 
| 1335 |  |  | 
| 1336 |  |         // Replacing results. | 
| 1337 |  |         assert!(dfg.value_is_attached(val)); | 
| 1338 |  |         let v2 = dfg.replace_result(val, types::F64); | 
| 1339 |  |         assert!(!dfg.value_is_attached(val)); | 
| 1340 |  |         assert!(dfg.value_is_attached(v2)); | 
| 1341 |  |         assert_eq!(dfg.inst_results(inst), &[v2]); | 
| 1342 |  |         assert_eq!(dfg.value_def(v2), ValueDef::Result(inst, 0)); | 
| 1343 |  |         assert_eq!(dfg.value_type(v2), types::F64); | 
| 1344 |  |     } | 
| 1345 |  |  | 
| 1346 |  |     #[test] | 
| 1347 |  |     fn no_results() { | 
| 1348 |  |         let mut dfg = DataFlowGraph::new(); | 
| 1349 |  |  | 
| 1350 |  |         let idata = InstructionData::Trap { | 
| 1351 |  |             opcode: Opcode::Trap, | 
| 1352 |  |             code: TrapCode::User(0), | 
| 1353 |  |         }; | 
| 1354 |  |         let inst = dfg.make_inst(idata); | 
| 1355 |  |         assert_eq!(dfg.display_inst(inst).to_string(), "trap user0"); | 
| 1356 |  |  | 
| 1357 |  |         // Result slice should be empty. | 
| 1358 |  |         assert_eq!(dfg.inst_results(inst), &[]); | 
| 1359 |  |     } | 
| 1360 |  |  | 
| 1361 |  |     #[test] | 
| 1362 |  |     fn block() { | 
| 1363 |  |         let mut dfg = DataFlowGraph::new(); | 
| 1364 |  |  | 
| 1365 |  |         let block = dfg.make_block(); | 
| 1366 |  |         assert_eq!(block.to_string(), "block0"); | 
| 1367 |  |         assert_eq!(dfg.num_block_params(block), 0); | 
| 1368 |  |         assert_eq!(dfg.block_params(block), &[]); | 
| 1369 |  |         assert!(dfg.detach_block_params(block).is_empty()); | 
| 1370 |  |         assert_eq!(dfg.num_block_params(block), 0); | 
| 1371 |  |         assert_eq!(dfg.block_params(block), &[]); | 
| 1372 |  |  | 
| 1373 |  |         let arg1 = dfg.append_block_param(block, types::F32); | 
| 1374 |  |         assert_eq!(arg1.to_string(), "v0"); | 
| 1375 |  |         assert_eq!(dfg.num_block_params(block), 1); | 
| 1376 |  |         assert_eq!(dfg.block_params(block), &[arg1]); | 
| 1377 |  |  | 
| 1378 |  |         let arg2 = dfg.append_block_param(block, types::I16); | 
| 1379 |  |         assert_eq!(arg2.to_string(), "v1"); | 
| 1380 |  |         assert_eq!(dfg.num_block_params(block), 2); | 
| 1381 |  |         assert_eq!(dfg.block_params(block), &[arg1, arg2]); | 
| 1382 |  |  | 
| 1383 |  |         assert_eq!(dfg.value_def(arg1), ValueDef::Param(block, 0)); | 
| 1384 |  |         assert_eq!(dfg.value_def(arg2), ValueDef::Param(block, 1)); | 
| 1385 |  |         assert_eq!(dfg.value_type(arg1), types::F32); | 
| 1386 |  |         assert_eq!(dfg.value_type(arg2), types::I16); | 
| 1387 |  |  | 
| 1388 |  |         // Swap the two block parameters. | 
| 1389 |  |         let vlist = dfg.detach_block_params(block); | 
| 1390 |  |         assert_eq!(dfg.num_block_params(block), 0); | 
| 1391 |  |         assert_eq!(dfg.block_params(block), &[]); | 
| 1392 |  |         assert_eq!(vlist.as_slice(&dfg.value_lists), &[arg1, arg2]); | 
| 1393 |  |         dfg.attach_block_param(block, arg2); | 
| 1394 |  |         let arg3 = dfg.append_block_param(block, types::I32); | 
| 1395 |  |         dfg.attach_block_param(block, arg1); | 
| 1396 |  |         assert_eq!(dfg.block_params(block), &[arg2, arg3, arg1]); | 
| 1397 |  |     } | 
| 1398 |  |  | 
| 1399 |  |     #[test] | 
| 1400 |  |     fn replace_block_params() { | 
| 1401 |  |         let mut dfg = DataFlowGraph::new(); | 
| 1402 |  |  | 
| 1403 |  |         let block = dfg.make_block(); | 
| 1404 |  |         let arg1 = dfg.append_block_param(block, types::F32); | 
| 1405 |  |  | 
| 1406 |  |         let new1 = dfg.replace_block_param(arg1, types::I64); | 
| 1407 |  |         assert_eq!(dfg.value_type(arg1), types::F32); | 
| 1408 |  |         assert_eq!(dfg.value_type(new1), types::I64); | 
| 1409 |  |         assert_eq!(dfg.block_params(block), &[new1]); | 
| 1410 |  |  | 
| 1411 |  |         dfg.attach_block_param(block, arg1); | 
| 1412 |  |         assert_eq!(dfg.block_params(block), &[new1, arg1]); | 
| 1413 |  |  | 
| 1414 |  |         let new2 = dfg.replace_block_param(arg1, types::I8); | 
| 1415 |  |         assert_eq!(dfg.value_type(arg1), types::F32); | 
| 1416 |  |         assert_eq!(dfg.value_type(new2), types::I8); | 
| 1417 |  |         assert_eq!(dfg.block_params(block), &[new1, new2]); | 
| 1418 |  |  | 
| 1419 |  |         dfg.attach_block_param(block, arg1); | 
| 1420 |  |         assert_eq!(dfg.block_params(block), &[new1, new2, arg1]); | 
| 1421 |  |  | 
| 1422 |  |         let new3 = dfg.replace_block_param(new2, types::I16); | 
| 1423 |  |         assert_eq!(dfg.value_type(new1), types::I64); | 
| 1424 |  |         assert_eq!(dfg.value_type(new2), types::I8); | 
| 1425 |  |         assert_eq!(dfg.value_type(new3), types::I16); | 
| 1426 |  |         assert_eq!(dfg.block_params(block), &[new1, new3, arg1]); | 
| 1427 |  |     } | 
| 1428 |  |  | 
| 1429 |  |     #[test] | 
| 1430 |  |     fn swap_remove_block_params() { | 
| 1431 |  |         let mut dfg = DataFlowGraph::new(); | 
| 1432 |  |  | 
| 1433 |  |         let block = dfg.make_block(); | 
| 1434 |  |         let arg1 = dfg.append_block_param(block, types::F32); | 
| 1435 |  |         let arg2 = dfg.append_block_param(block, types::F32); | 
| 1436 |  |         let arg3 = dfg.append_block_param(block, types::F32); | 
| 1437 |  |         assert_eq!(dfg.block_params(block), &[arg1, arg2, arg3]); | 
| 1438 |  |  | 
| 1439 |  |         dfg.swap_remove_block_param(arg1); | 
| 1440 |  |         assert_eq!(dfg.value_is_attached(arg1), false); | 
| 1441 |  |         assert_eq!(dfg.value_is_attached(arg2), true); | 
| 1442 |  |         assert_eq!(dfg.value_is_attached(arg3), true); | 
| 1443 |  |         assert_eq!(dfg.block_params(block), &[arg3, arg2]); | 
| 1444 |  |         dfg.swap_remove_block_param(arg2); | 
| 1445 |  |         assert_eq!(dfg.value_is_attached(arg2), false); | 
| 1446 |  |         assert_eq!(dfg.value_is_attached(arg3), true); | 
| 1447 |  |         assert_eq!(dfg.block_params(block), &[arg3]); | 
| 1448 |  |         dfg.swap_remove_block_param(arg3); | 
| 1449 |  |         assert_eq!(dfg.value_is_attached(arg3), false); | 
| 1450 |  |         assert_eq!(dfg.block_params(block), &[]); | 
| 1451 |  |     } | 
| 1452 |  |  | 
| 1453 |  |     #[test] | 
| 1454 |  |     fn aliases() { | 
| 1455 |  |         use crate::ir::InstBuilder; | 
| 1456 |  |  | 
| 1457 |  |         let mut func = Function::new(); | 
| 1458 |  |         let block0 = func.dfg.make_block(); | 
| 1459 |  |         let mut pos = FuncCursor::new(&mut func); | 
| 1460 |  |         pos.insert_block(block0); | 
| 1461 |  |  | 
| 1462 |  |         // Build a little test program. | 
| 1463 |  |         let v1 = pos.ins().iconst(types::I32, 42); | 
| 1464 |  |  | 
| 1465 |  |         // Make sure we can resolve value aliases even when values is empty. | 
| 1466 |  |         assert_eq!(pos.func.dfg.resolve_aliases(v1), v1); | 
| 1467 |  |  | 
| 1468 |  |         let arg0 = pos.func.dfg.append_block_param(block0, types::I32); | 
| 1469 |  |         let (s, c) = pos.ins().iadd_ifcout(v1, arg0); | 
| 1470 |  |         let iadd = match pos.func.dfg.value_def(s) { | 
| 1471 |  |             ValueDef::Result(i, 0) => i, | 
| 1472 |  |             _ => panic!(), | 
| 1473 |  |         }; | 
| 1474 |  |  | 
| 1475 |  |         // Remove `c` from the result list. | 
| 1476 |  |         pos.func.dfg.clear_results(iadd); | 
| 1477 |  |         pos.func.dfg.attach_result(iadd, s); | 
| 1478 |  |  | 
| 1479 |  |         // Replace `iadd_ifcout` with a normal `iadd` and an `ifcmp`. | 
| 1480 |  |         pos.func.dfg.replace(iadd).iadd(v1, arg0); | 
| 1481 |  |         let c2 = pos.ins().ifcmp(s, v1); | 
| 1482 |  |         pos.func.dfg.change_to_alias(c, c2); | 
| 1483 |  |  | 
| 1484 |  |         assert_eq!(pos.func.dfg.resolve_aliases(c2), c2); | 
| 1485 |  |         assert_eq!(pos.func.dfg.resolve_aliases(c), c2); | 
| 1486 |  |     } | 
| 1487 |  | } |