cranelift_codegen/ir/
dfg.rs

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