1 //! Data flow graph tracking Instructions, Values, and EBBs.
2 
3 use crate::entity::{self, PrimaryMap, SecondaryMap};
4 use crate::ir;
5 use crate::ir::builder::ReplaceBuilder;
6 use crate::ir::extfunc::ExtFuncData;
7 use crate::ir::instructions::{BranchInfo, CallInfo, InstructionData};
8 use crate::ir::{types, ConstantPool, Immediate};
9 use crate::ir::{
10     Ebb, FuncRef, Inst, SigRef, Signature, Type, Value, ValueLabelAssignments, ValueList,
11     ValueListPool,
12 };
13 use crate::isa::TargetIsa;
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 use std::collections::HashMap;
22 use std::vec::Vec;
23 
24 /// A data flow graph defines all instructions and extended basic blocks in a function as well as
25 /// the data flow dependencies between them. The DFG also tracks values which can be either
26 /// instruction results or EBB parameters.
27 ///
28 /// The layout of EBBs in the function and of instructions in each EBB is recorded by the
29 /// `Layout` data structure which forms the other half of the function representation.
30 ///
31 #[derive(Clone)]
32 pub struct DataFlowGraph {
33     /// Data about all of the instructions in the function, including opcodes and operands.
34     /// The instructions in this map are not in program order. That is tracked by `Layout`, along
35     /// with the EBB containing each instruction.
36     insts: PrimaryMap<Inst, InstructionData>,
37 
38     /// List of result values for each instruction.
39     ///
40     /// This map gets resized automatically by `make_inst()` so it is always in sync with the
41     /// primary `insts` map.
42     results: SecondaryMap<Inst, ValueList>,
43 
44     /// Extended basic blocks in the function and their parameters.
45     ///
46     /// This map is not in program order. That is handled by `Layout`, and so is the sequence of
47     /// instructions contained in each EBB.
48     ebbs: PrimaryMap<Ebb, EbbData>,
49 
50     /// Memory pool of value lists.
51     ///
52     /// The `ValueList` references into this pool appear in many places:
53     ///
54     /// - Instructions in `insts` that don't have room for their entire argument list inline.
55     /// - Instruction result values in `results`.
56     /// - EBB parameters in `ebbs`.
57     pub value_lists: ValueListPool,
58 
59     /// Primary value table with entries for all values.
60     values: PrimaryMap<Value, ValueData>,
61 
62     /// Function signature table. These signatures are referenced by indirect call instructions as
63     /// well as the external function references.
64     pub signatures: PrimaryMap<SigRef, Signature>,
65 
66     /// External function references. These are functions that can be called directly.
67     pub ext_funcs: PrimaryMap<FuncRef, ExtFuncData>,
68 
69     /// Saves Value labels.
70     pub values_labels: Option<HashMap<Value, ValueLabelAssignments>>,
71 
72     /// Constants used within the function
73     pub constants: ConstantPool,
74 
75     /// Stores large immediates that otherwise will not fit on InstructionData
76     pub immediates: PrimaryMap<Immediate, Vec<u8>>,
77 }
78 
79 impl DataFlowGraph {
80     /// Create a new empty `DataFlowGraph`.
new() -> Self81     pub fn new() -> Self {
82         Self {
83             insts: PrimaryMap::new(),
84             results: SecondaryMap::new(),
85             ebbs: PrimaryMap::new(),
86             value_lists: ValueListPool::new(),
87             values: PrimaryMap::new(),
88             signatures: PrimaryMap::new(),
89             ext_funcs: PrimaryMap::new(),
90             values_labels: None,
91             constants: ConstantPool::new(),
92             immediates: PrimaryMap::new(),
93         }
94     }
95 
96     /// Clear everything.
clear(&mut self)97     pub fn clear(&mut self) {
98         self.insts.clear();
99         self.results.clear();
100         self.ebbs.clear();
101         self.value_lists.clear();
102         self.values.clear();
103         self.signatures.clear();
104         self.ext_funcs.clear();
105         self.values_labels = None;
106         self.constants.clear();
107         self.immediates.clear();
108     }
109 
110     /// Get the total number of instructions created in this function, whether they are currently
111     /// inserted in the layout or not.
112     ///
113     /// This is intended for use with `SecondaryMap::with_capacity`.
num_insts(&self) -> usize114     pub fn num_insts(&self) -> usize {
115         self.insts.len()
116     }
117 
118     /// Returns `true` if the given instruction reference is valid.
inst_is_valid(&self, inst: Inst) -> bool119     pub fn inst_is_valid(&self, inst: Inst) -> bool {
120         self.insts.is_valid(inst)
121     }
122 
123     /// Get the total number of extended basic blocks created in this function, whether they are
124     /// currently inserted in the layout or not.
125     ///
126     /// This is intended for use with `SecondaryMap::with_capacity`.
num_ebbs(&self) -> usize127     pub fn num_ebbs(&self) -> usize {
128         self.ebbs.len()
129     }
130 
131     /// Returns `true` if the given ebb reference is valid.
ebb_is_valid(&self, ebb: Ebb) -> bool132     pub fn ebb_is_valid(&self, ebb: Ebb) -> bool {
133         self.ebbs.is_valid(ebb)
134     }
135 
136     /// Get the total number of values.
num_values(&self) -> usize137     pub fn num_values(&self) -> usize {
138         self.values.len()
139     }
140 
141     /// Starts collection of debug information.
collect_debug_info(&mut self)142     pub fn collect_debug_info(&mut self) {
143         if self.values_labels.is_none() {
144             self.values_labels = Some(HashMap::new());
145         }
146     }
147 }
148 
149 /// Resolve value aliases.
150 ///
151 /// Find the original SSA value that `value` aliases, or None if an
152 /// alias cycle is detected.
maybe_resolve_aliases(values: &PrimaryMap<Value, ValueData>, value: Value) -> Option<Value>153 fn maybe_resolve_aliases(values: &PrimaryMap<Value, ValueData>, value: Value) -> Option<Value> {
154     let mut v = value;
155 
156     // Note that values may be empty here.
157     for _ in 0..=values.len() {
158         if let ValueData::Alias { original, .. } = values[v] {
159             v = original;
160         } else {
161             return Some(v);
162         }
163     }
164 
165     None
166 }
167 
168 /// Resolve value aliases.
169 ///
170 /// Find the original SSA value that `value` aliases.
resolve_aliases(values: &PrimaryMap<Value, ValueData>, value: Value) -> Value171 fn resolve_aliases(values: &PrimaryMap<Value, ValueData>, value: Value) -> Value {
172     if let Some(v) = maybe_resolve_aliases(values, value) {
173         v
174     } else {
175         panic!("Value alias loop detected for {}", value);
176     }
177 }
178 
179 /// Iterator over all Values in a DFG
180 pub struct Values<'a> {
181     inner: entity::Iter<'a, Value, ValueData>,
182 }
183 
184 /// Check for non-values
valid_valuedata(data: &ValueData) -> bool185 fn valid_valuedata(data: &ValueData) -> bool {
186     if let ValueData::Alias {
187         ty: types::INVALID,
188         original,
189     } = *data
190     {
191         if original == Value::reserved_value() {
192             return false;
193         }
194     }
195     true
196 }
197 
198 impl<'a> Iterator for Values<'a> {
199     type Item = Value;
200 
next(&mut self) -> Option<Self::Item>201     fn next(&mut self) -> Option<Self::Item> {
202         self.inner
203             .by_ref()
204             .find(|kv| valid_valuedata(kv.1))
205             .map(|kv| kv.0)
206     }
207 }
208 
209 /// Handling values.
210 ///
211 /// Values are either EBB parameters or instruction results.
212 impl DataFlowGraph {
213     /// Allocate an extended value entry.
make_value(&mut self, data: ValueData) -> Value214     fn make_value(&mut self, data: ValueData) -> Value {
215         self.values.push(data)
216     }
217 
218     /// Get an iterator over all values.
values<'a>(&'a self) -> Values219     pub fn values<'a>(&'a self) -> Values {
220         Values {
221             inner: self.values.iter(),
222         }
223     }
224 
225     /// Check if a value reference is valid.
value_is_valid(&self, v: Value) -> bool226     pub fn value_is_valid(&self, v: Value) -> bool {
227         self.values.is_valid(v)
228     }
229 
230     /// Get the type of a value.
value_type(&self, v: Value) -> Type231     pub fn value_type(&self, v: Value) -> Type {
232         match self.values[v] {
233             ValueData::Inst { ty, .. }
234             | ValueData::Param { ty, .. }
235             | ValueData::Alias { ty, .. } => ty,
236         }
237     }
238 
239     /// Get the definition of a value.
240     ///
241     /// This is either the instruction that defined it or the Ebb that has the value as an
242     /// parameter.
value_def(&self, v: Value) -> ValueDef243     pub fn value_def(&self, v: Value) -> ValueDef {
244         match self.values[v] {
245             ValueData::Inst { inst, num, .. } => ValueDef::Result(inst, num as usize),
246             ValueData::Param { ebb, num, .. } => ValueDef::Param(ebb, num as usize),
247             ValueData::Alias { original, .. } => {
248                 // Make sure we only recurse one level. `resolve_aliases` has safeguards to
249                 // detect alias loops without overrunning the stack.
250                 self.value_def(self.resolve_aliases(original))
251             }
252         }
253     }
254 
255     /// Determine if `v` is an attached instruction result / EBB parameter.
256     ///
257     /// An attached value can't be attached to something else without first being detached.
258     ///
259     /// Value aliases are not considered to be attached to anything. Use `resolve_aliases()` to
260     /// determine if the original aliased value is attached.
value_is_attached(&self, v: Value) -> bool261     pub fn value_is_attached(&self, v: Value) -> bool {
262         use self::ValueData::*;
263         match self.values[v] {
264             Inst { inst, num, .. } => Some(&v) == self.inst_results(inst).get(num as usize),
265             Param { ebb, num, .. } => Some(&v) == self.ebb_params(ebb).get(num as usize),
266             Alias { .. } => false,
267         }
268     }
269 
270     /// Resolve value aliases.
271     ///
272     /// Find the original SSA value that `value` aliases.
resolve_aliases(&self, value: Value) -> Value273     pub fn resolve_aliases(&self, value: Value) -> Value {
274         resolve_aliases(&self.values, value)
275     }
276 
277     /// Resolve all aliases among inst's arguments.
278     ///
279     /// For each argument of inst which is defined by an alias, replace the
280     /// alias with the aliased value.
resolve_aliases_in_arguments(&mut self, inst: Inst)281     pub fn resolve_aliases_in_arguments(&mut self, inst: Inst) {
282         for arg in self.insts[inst].arguments_mut(&mut self.value_lists) {
283             let resolved = resolve_aliases(&self.values, *arg);
284             if resolved != *arg {
285                 *arg = resolved;
286             }
287         }
288     }
289 
290     /// Turn a value into an alias of another.
291     ///
292     /// Change the `dest` value to behave as an alias of `src`. This means that all uses of `dest`
293     /// will behave as if they used that value `src`.
294     ///
295     /// The `dest` value can't be attached to an instruction or EBB.
change_to_alias(&mut self, dest: Value, src: Value)296     pub fn change_to_alias(&mut self, dest: Value, src: Value) {
297         debug_assert!(!self.value_is_attached(dest));
298         // Try to create short alias chains by finding the original source value.
299         // This also avoids the creation of loops.
300         let original = self.resolve_aliases(src);
301         debug_assert_ne!(
302             dest, original,
303             "Aliasing {} to {} would create a loop",
304             dest, src
305         );
306         let ty = self.value_type(original);
307         debug_assert_eq!(
308             self.value_type(dest),
309             ty,
310             "Aliasing {} to {} would change its type {} to {}",
311             dest,
312             src,
313             self.value_type(dest),
314             ty
315         );
316         debug_assert_ne!(ty, types::INVALID);
317 
318         self.values[dest] = ValueData::Alias { ty, original };
319     }
320 
321     /// Replace the results of one instruction with aliases to the results of another.
322     ///
323     /// Change all the results of `dest_inst` to behave as aliases of
324     /// corresponding results of `src_inst`, as if calling change_to_alias for
325     /// each.
326     ///
327     /// After calling this instruction, `dest_inst` will have had its results
328     /// cleared, so it likely needs to be removed from the graph.
329     ///
replace_with_aliases(&mut self, dest_inst: Inst, src_inst: Inst)330     pub fn replace_with_aliases(&mut self, dest_inst: Inst, src_inst: Inst) {
331         debug_assert_ne!(
332             dest_inst, src_inst,
333             "Replacing {} with itself would create a loop",
334             dest_inst
335         );
336         debug_assert_eq!(
337             self.results[dest_inst].len(&self.value_lists),
338             self.results[src_inst].len(&self.value_lists),
339             "Replacing {} with {} would produce a different number of results.",
340             dest_inst,
341             src_inst
342         );
343 
344         for (&dest, &src) in self.results[dest_inst]
345             .as_slice(&self.value_lists)
346             .iter()
347             .zip(self.results[src_inst].as_slice(&self.value_lists))
348         {
349             let original = src;
350             let ty = self.value_type(original);
351             debug_assert_eq!(
352                 self.value_type(dest),
353                 ty,
354                 "Aliasing {} to {} would change its type {} to {}",
355                 dest,
356                 src,
357                 self.value_type(dest),
358                 ty
359             );
360             debug_assert_ne!(ty, types::INVALID);
361 
362             self.values[dest] = ValueData::Alias { ty, original };
363         }
364 
365         self.clear_results(dest_inst);
366     }
367 }
368 
369 /// Where did a value come from?
370 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
371 pub enum ValueDef {
372     /// Value is the n'th result of an instruction.
373     Result(Inst, usize),
374     /// Value is the n'th parameter to an EBB.
375     Param(Ebb, usize),
376 }
377 
378 impl ValueDef {
379     /// Unwrap the instruction where the value was defined, or panic.
unwrap_inst(&self) -> Inst380     pub fn unwrap_inst(&self) -> Inst {
381         match *self {
382             ValueDef::Result(inst, _) => inst,
383             _ => panic!("Value is not an instruction result"),
384         }
385     }
386 
387     /// Unwrap the EBB there the parameter is defined, or panic.
unwrap_ebb(&self) -> Ebb388     pub fn unwrap_ebb(&self) -> Ebb {
389         match *self {
390             ValueDef::Param(ebb, _) => ebb,
391             _ => panic!("Value is not an EBB parameter"),
392         }
393     }
394 
395     /// Get the program point where the value was defined.
pp(self) -> ir::ExpandedProgramPoint396     pub fn pp(self) -> ir::ExpandedProgramPoint {
397         self.into()
398     }
399 
400     /// Get the number component of this definition.
401     ///
402     /// When multiple values are defined at the same program point, this indicates the index of
403     /// this value.
num(self) -> usize404     pub fn num(self) -> usize {
405         match self {
406             ValueDef::Result(_, n) | ValueDef::Param(_, n) => n,
407         }
408     }
409 }
410 
411 /// Internal table storage for extended values.
412 #[derive(Clone, Debug)]
413 enum ValueData {
414     /// Value is defined by an instruction.
415     Inst { ty: Type, num: u16, inst: Inst },
416 
417     /// Value is an EBB parameter.
418     Param { ty: Type, num: u16, ebb: Ebb },
419 
420     /// Value is an alias of another value.
421     /// An alias value can't be linked as an instruction result or EBB parameter. It is used as a
422     /// placeholder when the original instruction or EBB has been rewritten or modified.
423     Alias { ty: Type, original: Value },
424 }
425 
426 /// Instructions.
427 ///
428 impl DataFlowGraph {
429     /// Create a new instruction.
430     ///
431     /// The type of the first result is indicated by `data.ty`. If the instruction produces
432     /// multiple results, also call `make_inst_results` to allocate value table entries.
make_inst(&mut self, data: InstructionData) -> Inst433     pub fn make_inst(&mut self, data: InstructionData) -> Inst {
434         let n = self.num_insts() + 1;
435         self.results.resize(n);
436         self.insts.push(data)
437     }
438 
439     /// Returns an object that displays `inst`.
display_inst<'a, I: Into<Option<&'a dyn TargetIsa>>>( &'a self, inst: Inst, isa: I, ) -> DisplayInst<'a>440     pub fn display_inst<'a, I: Into<Option<&'a dyn TargetIsa>>>(
441         &'a self,
442         inst: Inst,
443         isa: I,
444     ) -> DisplayInst<'a> {
445         DisplayInst(self, isa.into(), inst)
446     }
447 
448     /// Get all value arguments on `inst` as a slice.
inst_args(&self, inst: Inst) -> &[Value]449     pub fn inst_args(&self, inst: Inst) -> &[Value] {
450         self.insts[inst].arguments(&self.value_lists)
451     }
452 
453     /// Get all value arguments on `inst` as a mutable slice.
inst_args_mut(&mut self, inst: Inst) -> &mut [Value]454     pub fn inst_args_mut(&mut self, inst: Inst) -> &mut [Value] {
455         self.insts[inst].arguments_mut(&mut self.value_lists)
456     }
457 
458     /// Get the fixed value arguments on `inst` as a slice.
inst_fixed_args(&self, inst: Inst) -> &[Value]459     pub fn inst_fixed_args(&self, inst: Inst) -> &[Value] {
460         let num_fixed_args = self[inst]
461             .opcode()
462             .constraints()
463             .num_fixed_value_arguments();
464         &self.inst_args(inst)[..num_fixed_args]
465     }
466 
467     /// Get the fixed value arguments on `inst` as a mutable slice.
inst_fixed_args_mut(&mut self, inst: Inst) -> &mut [Value]468     pub fn inst_fixed_args_mut(&mut self, inst: Inst) -> &mut [Value] {
469         let num_fixed_args = self[inst]
470             .opcode()
471             .constraints()
472             .num_fixed_value_arguments();
473         &mut self.inst_args_mut(inst)[..num_fixed_args]
474     }
475 
476     /// Get the variable value arguments on `inst` as a slice.
inst_variable_args(&self, inst: Inst) -> &[Value]477     pub fn inst_variable_args(&self, inst: Inst) -> &[Value] {
478         let num_fixed_args = self[inst]
479             .opcode()
480             .constraints()
481             .num_fixed_value_arguments();
482         &self.inst_args(inst)[num_fixed_args..]
483     }
484 
485     /// Get the variable value arguments on `inst` as a mutable slice.
inst_variable_args_mut(&mut self, inst: Inst) -> &mut [Value]486     pub fn inst_variable_args_mut(&mut self, inst: Inst) -> &mut [Value] {
487         let num_fixed_args = self[inst]
488             .opcode()
489             .constraints()
490             .num_fixed_value_arguments();
491         &mut self.inst_args_mut(inst)[num_fixed_args..]
492     }
493 
494     /// Create result values for an instruction that produces multiple results.
495     ///
496     /// Instructions that produce no result values only need to be created with `make_inst`,
497     /// otherwise call `make_inst_results` to allocate value table entries for the results.
498     ///
499     /// The result value types are determined from the instruction's value type constraints and the
500     /// provided `ctrl_typevar` type for polymorphic instructions. For non-polymorphic
501     /// instructions, `ctrl_typevar` is ignored, and `INVALID` can be used.
502     ///
503     /// The type of the first result value is also set, even if it was already set in the
504     /// `InstructionData` passed to `make_inst`. If this function is called with a single-result
505     /// instruction, that is the only effect.
make_inst_results(&mut self, inst: Inst, ctrl_typevar: Type) -> usize506     pub fn make_inst_results(&mut self, inst: Inst, ctrl_typevar: Type) -> usize {
507         self.make_inst_results_reusing(inst, ctrl_typevar, iter::empty())
508     }
509 
510     /// Create result values for `inst`, reusing the provided detached values.
511     ///
512     /// Create a new set of result values for `inst` using `ctrl_typevar` to determine the result
513     /// types. Any values provided by `reuse` will be reused. When `reuse` is exhausted or when it
514     /// 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>>,515     pub fn make_inst_results_reusing<I>(
516         &mut self,
517         inst: Inst,
518         ctrl_typevar: Type,
519         reuse: I,
520     ) -> usize
521     where
522         I: Iterator<Item = Option<Value>>,
523     {
524         let mut reuse = reuse.fuse();
525 
526         self.results[inst].clear(&mut self.value_lists);
527 
528         // Get the call signature if this is a function call.
529         if let Some(sig) = self.call_signature(inst) {
530             // Create result values corresponding to the call return types.
531             debug_assert_eq!(
532                 self.insts[inst].opcode().constraints().num_fixed_results(),
533                 0
534             );
535             let num_results = self.signatures[sig].returns.len();
536             for res_idx in 0..num_results {
537                 let ty = self.signatures[sig].returns[res_idx].value_type;
538                 if let Some(Some(v)) = reuse.next() {
539                     debug_assert_eq!(self.value_type(v), ty, "Reused {} is wrong type", ty);
540                     self.attach_result(inst, v);
541                 } else {
542                     self.append_result(inst, ty);
543                 }
544             }
545             num_results
546         } else {
547             // Create result values corresponding to the opcode's constraints.
548             let constraints = self.insts[inst].opcode().constraints();
549             let num_results = constraints.num_fixed_results();
550             for res_idx in 0..num_results {
551                 let ty = constraints.result_type(res_idx, ctrl_typevar);
552                 if let Some(Some(v)) = reuse.next() {
553                     debug_assert_eq!(self.value_type(v), ty, "Reused {} is wrong type", ty);
554                     self.attach_result(inst, v);
555                 } else {
556                     self.append_result(inst, ty);
557                 }
558             }
559             num_results
560         }
561     }
562 
563     /// Create a `ReplaceBuilder` that will replace `inst` with a new instruction in place.
replace(&mut self, inst: Inst) -> ReplaceBuilder564     pub fn replace(&mut self, inst: Inst) -> ReplaceBuilder {
565         ReplaceBuilder::new(self, inst)
566     }
567 
568     /// Detach the list of result values from `inst` and return it.
569     ///
570     /// This leaves `inst` without any result values. New result values can be created by calling
571     /// `make_inst_results` or by using a `replace(inst)` builder.
detach_results(&mut self, inst: Inst) -> ValueList572     pub fn detach_results(&mut self, inst: Inst) -> ValueList {
573         self.results[inst].take()
574     }
575 
576     /// Clear the list of result values from `inst`.
577     ///
578     /// This leaves `inst` without any result values. New result values can be created by calling
579     /// `make_inst_results` or by using a `replace(inst)` builder.
clear_results(&mut self, inst: Inst)580     pub fn clear_results(&mut self, inst: Inst) {
581         self.results[inst].clear(&mut self.value_lists)
582     }
583 
584     /// Attach an existing value to the result value list for `inst`.
585     ///
586     /// The `res` value is appended to the end of the result list.
587     ///
588     /// This is a very low-level operation. Usually, instruction results with the correct types are
589     /// created automatically. The `res` value must not be attached to anything else.
attach_result(&mut self, inst: Inst, res: Value)590     pub fn attach_result(&mut self, inst: Inst, res: Value) {
591         debug_assert!(!self.value_is_attached(res));
592         let num = self.results[inst].push(res, &mut self.value_lists);
593         debug_assert!(num <= u16::MAX as usize, "Too many result values");
594         let ty = self.value_type(res);
595         self.values[res] = ValueData::Inst {
596             ty,
597             num: num as u16,
598             inst,
599         };
600     }
601 
602     /// Replace an instruction result with a new value of type `new_type`.
603     ///
604     /// The `old_value` must be an attached instruction result.
605     ///
606     /// The old value is left detached, so it should probably be changed into something else.
607     ///
608     /// Returns the new value.
replace_result(&mut self, old_value: Value, new_type: Type) -> Value609     pub fn replace_result(&mut self, old_value: Value, new_type: Type) -> Value {
610         let (num, inst) = match self.values[old_value] {
611             ValueData::Inst { num, inst, .. } => (num, inst),
612             _ => panic!("{} is not an instruction result value", old_value),
613         };
614         let new_value = self.make_value(ValueData::Inst {
615             ty: new_type,
616             num,
617             inst,
618         });
619         let num = num as usize;
620         let attached = mem::replace(
621             self.results[inst]
622                 .get_mut(num, &mut self.value_lists)
623                 .expect("Replacing detached result"),
624             new_value,
625         );
626         debug_assert_eq!(
627             attached,
628             old_value,
629             "{} wasn't detached from {}",
630             old_value,
631             self.display_inst(inst, None)
632         );
633         new_value
634     }
635 
636     /// Append a new instruction result value to `inst`.
append_result(&mut self, inst: Inst, ty: Type) -> Value637     pub fn append_result(&mut self, inst: Inst, ty: Type) -> Value {
638         let res = self.values.next_key();
639         let num = self.results[inst].push(res, &mut self.value_lists);
640         debug_assert!(num <= u16::MAX as usize, "Too many result values");
641         self.make_value(ValueData::Inst {
642             ty,
643             inst,
644             num: num as u16,
645         })
646     }
647 
648     /// Append a new value argument to an instruction.
649     ///
650     /// Panics if the instruction doesn't support arguments.
append_inst_arg(&mut self, inst: Inst, new_arg: Value)651     pub fn append_inst_arg(&mut self, inst: Inst, new_arg: Value) {
652         let mut branch_values = self.insts[inst]
653             .take_value_list()
654             .expect("the instruction doesn't have value arguments");
655         branch_values.push(new_arg, &mut self.value_lists);
656         self.insts[inst].put_value_list(branch_values)
657     }
658 
659     /// Get the first result of an instruction.
660     ///
661     /// This function panics if the instruction doesn't have any result.
first_result(&self, inst: Inst) -> Value662     pub fn first_result(&self, inst: Inst) -> Value {
663         self.results[inst]
664             .first(&self.value_lists)
665             .expect("Instruction has no results")
666     }
667 
668     /// Test if `inst` has any result values currently.
has_results(&self, inst: Inst) -> bool669     pub fn has_results(&self, inst: Inst) -> bool {
670         !self.results[inst].is_empty()
671     }
672 
673     /// Return all the results of an instruction.
inst_results(&self, inst: Inst) -> &[Value]674     pub fn inst_results(&self, inst: Inst) -> &[Value] {
675         self.results[inst].as_slice(&self.value_lists)
676     }
677 
678     /// Get the call signature of a direct or indirect call instruction.
679     /// Returns `None` if `inst` is not a call instruction.
call_signature(&self, inst: Inst) -> Option<SigRef>680     pub fn call_signature(&self, inst: Inst) -> Option<SigRef> {
681         match self.insts[inst].analyze_call(&self.value_lists) {
682             CallInfo::NotACall => None,
683             CallInfo::Direct(f, _) => Some(self.ext_funcs[f].signature),
684             CallInfo::Indirect(s, _) => Some(s),
685         }
686     }
687 
688     /// Check if `inst` is a branch.
analyze_branch(&self, inst: Inst) -> BranchInfo689     pub fn analyze_branch(&self, inst: Inst) -> BranchInfo {
690         self.insts[inst].analyze_branch(&self.value_lists)
691     }
692 
693     /// Compute the type of an instruction result from opcode constraints and call signatures.
694     ///
695     /// This computes the same sequence of result types that `make_inst_results()` above would
696     /// assign to the created result values, but it does not depend on `make_inst_results()` being
697     /// called first.
698     ///
699     /// 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>700     pub fn compute_result_type(
701         &self,
702         inst: Inst,
703         result_idx: usize,
704         ctrl_typevar: Type,
705     ) -> Option<Type> {
706         let constraints = self.insts[inst].opcode().constraints();
707         let num_fixed_results = constraints.num_fixed_results();
708 
709         if result_idx < num_fixed_results {
710             return Some(constraints.result_type(result_idx, ctrl_typevar));
711         }
712 
713         // Not a fixed result, try to extract a return type from the call signature.
714         self.call_signature(inst).and_then(|sigref| {
715             self.signatures[sigref]
716                 .returns
717                 .get(result_idx - num_fixed_results)
718                 .map(|&arg| arg.value_type)
719         })
720     }
721 
722     /// Get the controlling type variable, or `INVALID` if `inst` isn't polymorphic.
ctrl_typevar(&self, inst: Inst) -> Type723     pub fn ctrl_typevar(&self, inst: Inst) -> Type {
724         let constraints = self[inst].opcode().constraints();
725 
726         if !constraints.is_polymorphic() {
727             types::INVALID
728         } else if constraints.requires_typevar_operand() {
729             // Not all instruction formats have a designated operand, but in that case
730             // `requires_typevar_operand()` should never be true.
731             self.value_type(
732                 self[inst]
733                     .typevar_operand(&self.value_lists)
734                     .expect("Instruction format doesn't have a designated operand, bad opcode."),
735             )
736         } else {
737             self.value_type(self.first_result(inst))
738         }
739     }
740 }
741 
742 /// Allow immutable access to instructions via indexing.
743 impl Index<Inst> for DataFlowGraph {
744     type Output = InstructionData;
745 
index(&self, inst: Inst) -> &InstructionData746     fn index(&self, inst: Inst) -> &InstructionData {
747         &self.insts[inst]
748     }
749 }
750 
751 /// Allow mutable access to instructions via indexing.
752 impl IndexMut<Inst> for DataFlowGraph {
index_mut(&mut self, inst: Inst) -> &mut InstructionData753     fn index_mut(&mut self, inst: Inst) -> &mut InstructionData {
754         &mut self.insts[inst]
755     }
756 }
757 
758 /// Extended basic blocks.
759 impl DataFlowGraph {
760     /// Create a new basic block.
make_ebb(&mut self) -> Ebb761     pub fn make_ebb(&mut self) -> Ebb {
762         self.ebbs.push(EbbData::new())
763     }
764 
765     /// Get the number of parameters on `ebb`.
num_ebb_params(&self, ebb: Ebb) -> usize766     pub fn num_ebb_params(&self, ebb: Ebb) -> usize {
767         self.ebbs[ebb].params.len(&self.value_lists)
768     }
769 
770     /// Get the parameters on `ebb`.
ebb_params(&self, ebb: Ebb) -> &[Value]771     pub fn ebb_params(&self, ebb: Ebb) -> &[Value] {
772         self.ebbs[ebb].params.as_slice(&self.value_lists)
773     }
774 
775     /// Append a parameter with type `ty` to `ebb`.
append_ebb_param(&mut self, ebb: Ebb, ty: Type) -> Value776     pub fn append_ebb_param(&mut self, ebb: Ebb, ty: Type) -> Value {
777         let param = self.values.next_key();
778         let num = self.ebbs[ebb].params.push(param, &mut self.value_lists);
779         debug_assert!(num <= u16::MAX as usize, "Too many parameters on EBB");
780         self.make_value(ValueData::Param {
781             ty,
782             num: num as u16,
783             ebb,
784         })
785     }
786 
787     /// Removes `val` from `ebb`'s parameters by swapping it with the last parameter on `ebb`.
788     /// Returns the position of `val` before removal.
789     ///
790     /// *Important*: to ensure O(1) deletion, this method swaps the removed parameter with the
791     /// last `ebb` parameter. This can disrupt all the branch instructions jumping to this
792     /// `ebb` for which you have to change the branch argument order if necessary.
793     ///
794     /// Panics if `val` is not an EBB parameter.
swap_remove_ebb_param(&mut self, val: Value) -> usize795     pub fn swap_remove_ebb_param(&mut self, val: Value) -> usize {
796         let (ebb, num) = if let ValueData::Param { num, ebb, .. } = self.values[val] {
797             (ebb, num)
798         } else {
799             panic!("{} must be an EBB parameter", val);
800         };
801         self.ebbs[ebb]
802             .params
803             .swap_remove(num as usize, &mut self.value_lists);
804         if let Some(last_arg_val) = self.ebbs[ebb].params.get(num as usize, &self.value_lists) {
805             // We update the position of the old last arg.
806             if let ValueData::Param {
807                 num: ref mut old_num,
808                 ..
809             } = self.values[last_arg_val]
810             {
811                 *old_num = num;
812             } else {
813                 panic!("{} should be an Ebb parameter", last_arg_val);
814             }
815         }
816         num as usize
817     }
818 
819     /// Removes `val` from `ebb`'s parameters by a standard linear time list removal which
820     /// preserves ordering. Also updates the values' data.
remove_ebb_param(&mut self, val: Value)821     pub fn remove_ebb_param(&mut self, val: Value) {
822         let (ebb, num) = if let ValueData::Param { num, ebb, .. } = self.values[val] {
823             (ebb, num)
824         } else {
825             panic!("{} must be an EBB parameter", val);
826         };
827         self.ebbs[ebb]
828             .params
829             .remove(num as usize, &mut self.value_lists);
830         for index in num..(self.num_ebb_params(ebb) as u16) {
831             match self.values[self.ebbs[ebb]
832                 .params
833                 .get(index as usize, &self.value_lists)
834                 .unwrap()]
835             {
836                 ValueData::Param { ref mut num, .. } => {
837                     *num -= 1;
838                 }
839                 _ => panic!(
840                     "{} must be an EBB parameter",
841                     self.ebbs[ebb]
842                         .params
843                         .get(index as usize, &self.value_lists)
844                         .unwrap()
845                 ),
846             }
847         }
848     }
849 
850     /// Append an existing value to `ebb`'s parameters.
851     ///
852     /// The appended value can't already be attached to something else.
853     ///
854     /// In almost all cases, you should be using `append_ebb_param()` instead of this method.
attach_ebb_param(&mut self, ebb: Ebb, param: Value)855     pub fn attach_ebb_param(&mut self, ebb: Ebb, param: Value) {
856         debug_assert!(!self.value_is_attached(param));
857         let num = self.ebbs[ebb].params.push(param, &mut self.value_lists);
858         debug_assert!(num <= u16::MAX as usize, "Too many parameters on EBB");
859         let ty = self.value_type(param);
860         self.values[param] = ValueData::Param {
861             ty,
862             num: num as u16,
863             ebb,
864         };
865     }
866 
867     /// Replace an EBB parameter with a new value of type `ty`.
868     ///
869     /// The `old_value` must be an attached EBB parameter. It is removed from its place in the list
870     /// of parameters and replaced by a new value of type `new_type`. The new value gets the same
871     /// position in the list, and other parameters are not disturbed.
872     ///
873     /// The old value is left detached, so it should probably be changed into something else.
874     ///
875     /// Returns the new value.
replace_ebb_param(&mut self, old_value: Value, new_type: Type) -> Value876     pub fn replace_ebb_param(&mut self, old_value: Value, new_type: Type) -> Value {
877         // Create new value identical to the old one except for the type.
878         let (ebb, num) = if let ValueData::Param { num, ebb, .. } = self.values[old_value] {
879             (ebb, num)
880         } else {
881             panic!("{} must be an EBB parameter", old_value);
882         };
883         let new_arg = self.make_value(ValueData::Param {
884             ty: new_type,
885             num,
886             ebb,
887         });
888 
889         self.ebbs[ebb].params.as_mut_slice(&mut self.value_lists)[num as usize] = new_arg;
890         new_arg
891     }
892 
893     /// Detach all the parameters from `ebb` and return them as a `ValueList`.
894     ///
895     /// This is a quite low-level operation. Sensible things to do with the detached EBB parameters
896     /// is to put them back on the same EBB with `attach_ebb_param()` or change them into aliases
897     /// with `change_to_alias()`.
detach_ebb_params(&mut self, ebb: Ebb) -> ValueList898     pub fn detach_ebb_params(&mut self, ebb: Ebb) -> ValueList {
899         self.ebbs[ebb].params.take()
900     }
901 }
902 
903 /// Contents of an extended basic block.
904 ///
905 /// Parameters on an extended basic block are values that dominate everything in the EBB. All
906 /// branches to this EBB must provide matching arguments, and the arguments to the entry EBB must
907 /// match the function arguments.
908 #[derive(Clone)]
909 struct EbbData {
910     /// List of parameters to this EBB.
911     params: ValueList,
912 }
913 
914 impl EbbData {
new() -> Self915     fn new() -> Self {
916         Self {
917             params: ValueList::new(),
918         }
919     }
920 }
921 
922 /// Object that can display an instruction.
923 pub struct DisplayInst<'a>(&'a DataFlowGraph, Option<&'a dyn TargetIsa>, Inst);
924 
925 impl<'a> fmt::Display for DisplayInst<'a> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result926     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
927         let dfg = self.0;
928         let isa = self.1;
929         let inst = self.2;
930 
931         if let Some((first, rest)) = dfg.inst_results(inst).split_first() {
932             write!(f, "{}", first)?;
933             for v in rest {
934                 write!(f, ", {}", v)?;
935             }
936             write!(f, " = ")?;
937         }
938 
939         let typevar = dfg.ctrl_typevar(inst);
940         if typevar.is_invalid() {
941             write!(f, "{}", dfg[inst].opcode())?;
942         } else {
943             write!(f, "{}.{}", dfg[inst].opcode(), typevar)?;
944         }
945         write_operands(f, dfg, isa, inst)
946     }
947 }
948 
949 /// Parser routines. These routines should not be used outside the parser.
950 impl DataFlowGraph {
951     /// Set the type of a value. This is only for use in the parser, which needs
952     /// to create invalid values for index padding which may be reassigned later.
953     #[cold]
set_value_type_for_parser(&mut self, v: Value, t: Type)954     fn set_value_type_for_parser(&mut self, v: Value, t: Type) {
955         assert_eq!(
956             self.value_type(v),
957             types::INVALID,
958             "this function is only for assigning types to previously invalid values"
959         );
960         match self.values[v] {
961             ValueData::Inst { ref mut ty, .. }
962             | ValueData::Param { ref mut ty, .. }
963             | ValueData::Alias { ref mut ty, .. } => *ty = t,
964         }
965     }
966 
967     /// Create result values for `inst`, reusing the provided detached values.
968     /// This is similar to `make_inst_results_reusing` except it's only for use
969     /// in the parser, which needs to reuse previously invalid values.
970     #[cold]
make_inst_results_for_parser( &mut self, inst: Inst, ctrl_typevar: Type, reuse: &[Value], ) -> usize971     pub fn make_inst_results_for_parser(
972         &mut self,
973         inst: Inst,
974         ctrl_typevar: Type,
975         reuse: &[Value],
976     ) -> usize {
977         // Get the call signature if this is a function call.
978         if let Some(sig) = self.call_signature(inst) {
979             assert_eq!(
980                 self.insts[inst].opcode().constraints().num_fixed_results(),
981                 0
982             );
983             for res_idx in 0..self.signatures[sig].returns.len() {
984                 let ty = self.signatures[sig].returns[res_idx].value_type;
985                 if let Some(v) = reuse.get(res_idx) {
986                     self.set_value_type_for_parser(*v, ty);
987                 }
988             }
989         } else {
990             let constraints = self.insts[inst].opcode().constraints();
991             for res_idx in 0..constraints.num_fixed_results() {
992                 let ty = constraints.result_type(res_idx, ctrl_typevar);
993                 if let Some(v) = reuse.get(res_idx) {
994                     self.set_value_type_for_parser(*v, ty);
995                 }
996             }
997         }
998 
999         self.make_inst_results_reusing(inst, ctrl_typevar, reuse.iter().map(|x| Some(*x)))
1000     }
1001 
1002     /// Similar to `append_ebb_param`, append a parameter with type `ty` to
1003     /// `ebb`, but using value `val`. This is only for use by the parser to
1004     /// create parameters with specific values.
1005     #[cold]
append_ebb_param_for_parser(&mut self, ebb: Ebb, ty: Type, val: Value)1006     pub fn append_ebb_param_for_parser(&mut self, ebb: Ebb, ty: Type, val: Value) {
1007         let num = self.ebbs[ebb].params.push(val, &mut self.value_lists);
1008         assert!(num <= u16::MAX as usize, "Too many parameters on EBB");
1009         self.values[val] = ValueData::Param {
1010             ty,
1011             num: num as u16,
1012             ebb,
1013         };
1014     }
1015 
1016     /// Create a new value alias. This is only for use by the parser to create
1017     /// aliases with specific values, and the printer for testing.
1018     #[cold]
make_value_alias_for_serialization(&mut self, src: Value, dest: Value)1019     pub fn make_value_alias_for_serialization(&mut self, src: Value, dest: Value) {
1020         assert_ne!(src, Value::reserved_value());
1021         assert_ne!(dest, Value::reserved_value());
1022 
1023         let ty = if self.values.is_valid(src) {
1024             self.value_type(src)
1025         } else {
1026             // As a special case, if we can't resolve the aliasee yet, use INVALID
1027             // temporarily. It will be resolved later in parsing.
1028             types::INVALID
1029         };
1030         let data = ValueData::Alias { ty, original: src };
1031         self.values[dest] = data;
1032     }
1033 
1034     /// If `v` is already defined as an alias, return its destination value.
1035     /// Otherwise return None. This allows the parser to coalesce identical
1036     /// alias definitions, and the printer to identify an alias's immediate target.
1037     #[cold]
value_alias_dest_for_serialization(&self, v: Value) -> Option<Value>1038     pub fn value_alias_dest_for_serialization(&self, v: Value) -> Option<Value> {
1039         if let ValueData::Alias { original, .. } = self.values[v] {
1040             Some(original)
1041         } else {
1042             None
1043         }
1044     }
1045 
1046     /// Compute the type of an alias. This is only for use in the parser.
1047     /// Returns false if an alias cycle was encountered.
1048     #[cold]
set_alias_type_for_parser(&mut self, v: Value) -> bool1049     pub fn set_alias_type_for_parser(&mut self, v: Value) -> bool {
1050         if let Some(resolved) = maybe_resolve_aliases(&self.values, v) {
1051             let old_ty = self.value_type(v);
1052             let new_ty = self.value_type(resolved);
1053             if old_ty == types::INVALID {
1054                 self.set_value_type_for_parser(v, new_ty);
1055             } else {
1056                 assert_eq!(old_ty, new_ty);
1057             }
1058             true
1059         } else {
1060             false
1061         }
1062     }
1063 
1064     /// Create an invalid value, to pad the index space. This is only for use by
1065     /// the parser to pad out the value index space.
1066     #[cold]
make_invalid_value_for_parser(&mut self)1067     pub fn make_invalid_value_for_parser(&mut self) {
1068         let data = ValueData::Alias {
1069             ty: types::INVALID,
1070             original: Value::reserved_value(),
1071         };
1072         self.make_value(data);
1073     }
1074 
1075     /// Check if a value reference is valid, while being aware of aliases which
1076     /// may be unresolved while parsing.
1077     #[cold]
value_is_valid_for_parser(&self, v: Value) -> bool1078     pub fn value_is_valid_for_parser(&self, v: Value) -> bool {
1079         if !self.value_is_valid(v) {
1080             return false;
1081         }
1082         if let ValueData::Alias { ty, .. } = self.values[v] {
1083             ty != types::INVALID
1084         } else {
1085             true
1086         }
1087     }
1088 }
1089 
1090 #[cfg(test)]
1091 mod tests {
1092     use super::*;
1093     use crate::cursor::{Cursor, FuncCursor};
1094     use crate::ir::types;
1095     use crate::ir::{Function, InstructionData, Opcode, TrapCode};
1096     use std::string::ToString;
1097 
1098     #[test]
make_inst()1099     fn make_inst() {
1100         let mut dfg = DataFlowGraph::new();
1101 
1102         let idata = InstructionData::UnaryImm {
1103             opcode: Opcode::Iconst,
1104             imm: 0.into(),
1105         };
1106         let inst = dfg.make_inst(idata);
1107 
1108         dfg.make_inst_results(inst, types::I32);
1109         assert_eq!(inst.to_string(), "inst0");
1110         assert_eq!(
1111             dfg.display_inst(inst, None).to_string(),
1112             "v0 = iconst.i32 0"
1113         );
1114 
1115         // Immutable reference resolution.
1116         {
1117             let immdfg = &dfg;
1118             let ins = &immdfg[inst];
1119             assert_eq!(ins.opcode(), Opcode::Iconst);
1120         }
1121 
1122         // Results.
1123         let val = dfg.first_result(inst);
1124         assert_eq!(dfg.inst_results(inst), &[val]);
1125 
1126         assert_eq!(dfg.value_def(val), ValueDef::Result(inst, 0));
1127         assert_eq!(dfg.value_type(val), types::I32);
1128 
1129         // Replacing results.
1130         assert!(dfg.value_is_attached(val));
1131         let v2 = dfg.replace_result(val, types::F64);
1132         assert!(!dfg.value_is_attached(val));
1133         assert!(dfg.value_is_attached(v2));
1134         assert_eq!(dfg.inst_results(inst), &[v2]);
1135         assert_eq!(dfg.value_def(v2), ValueDef::Result(inst, 0));
1136         assert_eq!(dfg.value_type(v2), types::F64);
1137     }
1138 
1139     #[test]
no_results()1140     fn no_results() {
1141         let mut dfg = DataFlowGraph::new();
1142 
1143         let idata = InstructionData::Trap {
1144             opcode: Opcode::Trap,
1145             code: TrapCode::User(0),
1146         };
1147         let inst = dfg.make_inst(idata);
1148         assert_eq!(dfg.display_inst(inst, None).to_string(), "trap user0");
1149 
1150         // Result slice should be empty.
1151         assert_eq!(dfg.inst_results(inst), &[]);
1152     }
1153 
1154     #[test]
ebb()1155     fn ebb() {
1156         let mut dfg = DataFlowGraph::new();
1157 
1158         let ebb = dfg.make_ebb();
1159         assert_eq!(ebb.to_string(), "ebb0");
1160         assert_eq!(dfg.num_ebb_params(ebb), 0);
1161         assert_eq!(dfg.ebb_params(ebb), &[]);
1162         assert!(dfg.detach_ebb_params(ebb).is_empty());
1163         assert_eq!(dfg.num_ebb_params(ebb), 0);
1164         assert_eq!(dfg.ebb_params(ebb), &[]);
1165 
1166         let arg1 = dfg.append_ebb_param(ebb, types::F32);
1167         assert_eq!(arg1.to_string(), "v0");
1168         assert_eq!(dfg.num_ebb_params(ebb), 1);
1169         assert_eq!(dfg.ebb_params(ebb), &[arg1]);
1170 
1171         let arg2 = dfg.append_ebb_param(ebb, types::I16);
1172         assert_eq!(arg2.to_string(), "v1");
1173         assert_eq!(dfg.num_ebb_params(ebb), 2);
1174         assert_eq!(dfg.ebb_params(ebb), &[arg1, arg2]);
1175 
1176         assert_eq!(dfg.value_def(arg1), ValueDef::Param(ebb, 0));
1177         assert_eq!(dfg.value_def(arg2), ValueDef::Param(ebb, 1));
1178         assert_eq!(dfg.value_type(arg1), types::F32);
1179         assert_eq!(dfg.value_type(arg2), types::I16);
1180 
1181         // Swap the two EBB parameters.
1182         let vlist = dfg.detach_ebb_params(ebb);
1183         assert_eq!(dfg.num_ebb_params(ebb), 0);
1184         assert_eq!(dfg.ebb_params(ebb), &[]);
1185         assert_eq!(vlist.as_slice(&dfg.value_lists), &[arg1, arg2]);
1186         dfg.attach_ebb_param(ebb, arg2);
1187         let arg3 = dfg.append_ebb_param(ebb, types::I32);
1188         dfg.attach_ebb_param(ebb, arg1);
1189         assert_eq!(dfg.ebb_params(ebb), &[arg2, arg3, arg1]);
1190     }
1191 
1192     #[test]
replace_ebb_params()1193     fn replace_ebb_params() {
1194         let mut dfg = DataFlowGraph::new();
1195 
1196         let ebb = dfg.make_ebb();
1197         let arg1 = dfg.append_ebb_param(ebb, types::F32);
1198 
1199         let new1 = dfg.replace_ebb_param(arg1, types::I64);
1200         assert_eq!(dfg.value_type(arg1), types::F32);
1201         assert_eq!(dfg.value_type(new1), types::I64);
1202         assert_eq!(dfg.ebb_params(ebb), &[new1]);
1203 
1204         dfg.attach_ebb_param(ebb, arg1);
1205         assert_eq!(dfg.ebb_params(ebb), &[new1, arg1]);
1206 
1207         let new2 = dfg.replace_ebb_param(arg1, types::I8);
1208         assert_eq!(dfg.value_type(arg1), types::F32);
1209         assert_eq!(dfg.value_type(new2), types::I8);
1210         assert_eq!(dfg.ebb_params(ebb), &[new1, new2]);
1211 
1212         dfg.attach_ebb_param(ebb, arg1);
1213         assert_eq!(dfg.ebb_params(ebb), &[new1, new2, arg1]);
1214 
1215         let new3 = dfg.replace_ebb_param(new2, types::I16);
1216         assert_eq!(dfg.value_type(new1), types::I64);
1217         assert_eq!(dfg.value_type(new2), types::I8);
1218         assert_eq!(dfg.value_type(new3), types::I16);
1219         assert_eq!(dfg.ebb_params(ebb), &[new1, new3, arg1]);
1220     }
1221 
1222     #[test]
swap_remove_ebb_params()1223     fn swap_remove_ebb_params() {
1224         let mut dfg = DataFlowGraph::new();
1225 
1226         let ebb = dfg.make_ebb();
1227         let arg1 = dfg.append_ebb_param(ebb, types::F32);
1228         let arg2 = dfg.append_ebb_param(ebb, types::F32);
1229         let arg3 = dfg.append_ebb_param(ebb, types::F32);
1230         assert_eq!(dfg.ebb_params(ebb), &[arg1, arg2, arg3]);
1231 
1232         dfg.swap_remove_ebb_param(arg1);
1233         assert_eq!(dfg.value_is_attached(arg1), false);
1234         assert_eq!(dfg.value_is_attached(arg2), true);
1235         assert_eq!(dfg.value_is_attached(arg3), true);
1236         assert_eq!(dfg.ebb_params(ebb), &[arg3, arg2]);
1237         dfg.swap_remove_ebb_param(arg2);
1238         assert_eq!(dfg.value_is_attached(arg2), false);
1239         assert_eq!(dfg.value_is_attached(arg3), true);
1240         assert_eq!(dfg.ebb_params(ebb), &[arg3]);
1241         dfg.swap_remove_ebb_param(arg3);
1242         assert_eq!(dfg.value_is_attached(arg3), false);
1243         assert_eq!(dfg.ebb_params(ebb), &[]);
1244     }
1245 
1246     #[test]
aliases()1247     fn aliases() {
1248         use crate::ir::InstBuilder;
1249 
1250         let mut func = Function::new();
1251         let ebb0 = func.dfg.make_ebb();
1252         let mut pos = FuncCursor::new(&mut func);
1253         pos.insert_ebb(ebb0);
1254 
1255         // Build a little test program.
1256         let v1 = pos.ins().iconst(types::I32, 42);
1257 
1258         // Make sure we can resolve value aliases even when values is empty.
1259         assert_eq!(pos.func.dfg.resolve_aliases(v1), v1);
1260 
1261         let arg0 = pos.func.dfg.append_ebb_param(ebb0, types::I32);
1262         let (s, c) = pos.ins().iadd_ifcout(v1, arg0);
1263         let iadd = match pos.func.dfg.value_def(s) {
1264             ValueDef::Result(i, 0) => i,
1265             _ => panic!(),
1266         };
1267 
1268         // Remove `c` from the result list.
1269         pos.func.dfg.clear_results(iadd);
1270         pos.func.dfg.attach_result(iadd, s);
1271 
1272         // Replace `iadd_ifcout` with a normal `iadd` and an `ifcmp`.
1273         pos.func.dfg.replace(iadd).iadd(v1, arg0);
1274         let c2 = pos.ins().ifcmp(s, v1);
1275         pos.func.dfg.change_to_alias(c, c2);
1276 
1277         assert_eq!(pos.func.dfg.resolve_aliases(c2), c2);
1278         assert_eq!(pos.func.dfg.resolve_aliases(c), c2);
1279 
1280         // Make a copy of the alias.
1281         let c3 = pos.ins().copy(c);
1282         // This does not see through copies.
1283         assert_eq!(pos.func.dfg.resolve_aliases(c3), c3);
1284     }
1285 }
1286