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