Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/codegen/src/machinst/valueregs.rs
1693 views
1
//! Data structure for tracking the (possibly multiple) registers that hold one
2
//! SSA `Value`.
3
4
use regalloc2::{PReg, VReg};
5
6
use super::{RealReg, Reg, VirtualReg, Writable};
7
use std::fmt::Debug;
8
9
const VALUE_REGS_PARTS: usize = 2;
10
11
/// Location at which a `Value` is stored in register(s): the value is located
12
/// in one or more registers, depending on its width. A value may be stored in
13
/// more than one register if the machine has no registers wide enough
14
/// otherwise: for example, on a 32-bit architecture, we may store `I64` values
15
/// in two registers, and `I128` values in four.
16
///
17
/// By convention, the register parts are kept in machine-endian order here.
18
///
19
/// N.B.: we cap the capacity of this at four (when any 32-bit target is
20
/// enabled) or two (otherwise), and we use special in-band sentinel `Reg`
21
/// values (`Reg::invalid()`) to avoid the need to carry a separate length. This
22
/// allows the struct to be `Copy` (no heap or drop overhead) and be only 16 or
23
/// 8 bytes, which is important for compiler performance.
24
#[derive(Clone, Copy, PartialEq, Eq)]
25
pub struct ValueRegs<R: Clone + Copy + Debug + PartialEq + Eq + InvalidSentinel> {
26
parts: [R; VALUE_REGS_PARTS],
27
}
28
29
impl<R: Clone + Copy + Debug + PartialEq + Eq + InvalidSentinel> Debug for ValueRegs<R> {
30
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
31
let mut f = f.debug_tuple("ValueRegs");
32
let mut last_valid = true;
33
for part in self.parts {
34
if part.is_invalid_sentinel() {
35
last_valid = false;
36
} else {
37
debug_assert!(last_valid);
38
f.field(&part);
39
}
40
}
41
f.finish()
42
}
43
}
44
45
/// A type with an "invalid" sentinel value.
46
pub trait InvalidSentinel: Copy + Eq {
47
/// The invalid sentinel value.
48
fn invalid_sentinel() -> Self;
49
/// Is this the invalid sentinel?
50
fn is_invalid_sentinel(self) -> bool {
51
self == Self::invalid_sentinel()
52
}
53
}
54
impl InvalidSentinel for Reg {
55
fn invalid_sentinel() -> Self {
56
Reg::from(VReg::invalid())
57
}
58
}
59
impl InvalidSentinel for VirtualReg {
60
fn invalid_sentinel() -> Self {
61
VirtualReg::from(VReg::invalid())
62
}
63
}
64
impl InvalidSentinel for RealReg {
65
fn invalid_sentinel() -> Self {
66
RealReg::from(PReg::invalid())
67
}
68
}
69
impl InvalidSentinel for Writable<Reg> {
70
fn invalid_sentinel() -> Self {
71
Writable::from_reg(Reg::invalid_sentinel())
72
}
73
}
74
75
impl<R: Clone + Copy + Debug + PartialEq + Eq + InvalidSentinel> ValueRegs<R> {
76
/// Create an invalid Value-in-Reg.
77
pub fn invalid() -> Self {
78
ValueRegs {
79
parts: [R::invalid_sentinel(); VALUE_REGS_PARTS],
80
}
81
}
82
83
/// Is this Value-to-Reg mapping valid?
84
pub fn is_valid(self) -> bool {
85
!self.parts[0].is_invalid_sentinel()
86
}
87
/// Is this Value-to-Reg mapping invalid?
88
pub fn is_invalid(self) -> bool {
89
self.parts[0].is_invalid_sentinel()
90
}
91
92
/// Return the single register used for this value, if any.
93
pub fn only_reg(self) -> Option<R> {
94
if self.len() == 1 {
95
Some(self.parts[0])
96
} else {
97
None
98
}
99
}
100
101
/// Return a slice of the registers storing this value.
102
pub fn regs(&self) -> &[R] {
103
&self.parts[0..self.len()]
104
}
105
106
/// Return a mutable slice of the registers storing this value.
107
pub fn regs_mut(&mut self) -> &mut [R] {
108
let len = self.len();
109
&mut self.parts[0..len]
110
}
111
}
112
113
impl<R: Clone + Copy + Debug + PartialEq + Eq + InvalidSentinel> ValueRegs<R> {
114
/// Create a Value-in-R location for a value stored in one register.
115
pub fn one(reg: R) -> Self {
116
ValueRegs {
117
parts: [reg, R::invalid_sentinel()],
118
}
119
}
120
/// Create a Value-in-R location for a value stored in two registers.
121
pub fn two(r1: R, r2: R) -> Self {
122
ValueRegs { parts: [r1, r2] }
123
}
124
125
/// Return the number of registers used.
126
pub fn len(self) -> usize {
127
// If rustc/LLVM is smart enough, this might even be vectorized...
128
(self.parts[0] != R::invalid_sentinel()) as usize
129
+ (self.parts[1] != R::invalid_sentinel()) as usize
130
}
131
132
/// Map individual registers via a map function.
133
pub fn map<NewR, F>(self, f: F) -> ValueRegs<NewR>
134
where
135
NewR: Clone + Copy + Debug + PartialEq + Eq + InvalidSentinel,
136
F: Fn(R) -> NewR,
137
{
138
ValueRegs {
139
parts: [f(self.parts[0]), f(self.parts[1])],
140
}
141
}
142
}
143
144
/// Create a writable ValueRegs.
145
pub(crate) fn writable_value_regs(regs: ValueRegs<Reg>) -> ValueRegs<Writable<Reg>> {
146
regs.map(|r| Writable::from_reg(r))
147
}
148
149
/// Strip a writable ValueRegs down to a readonly ValueRegs.
150
pub(crate) fn non_writable_value_regs(regs: ValueRegs<Writable<Reg>>) -> ValueRegs<Reg> {
151
regs.map(|r| r.to_reg())
152
}
153
154