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