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