cranelift_codegen/machinst/
reg.rs1use alloc::{string::String, vec::Vec};
6use core::{fmt::Debug, hash::Hash};
7use regalloc2::{Operand, OperandConstraint, OperandKind, OperandPos, PReg, PRegSet, VReg};
8
9#[cfg(feature = "enable-serde")]
10use serde_derive::{Deserialize, Serialize};
11
12const PINNED_VREGS: usize = 192;
21
22pub fn pinned_vreg_to_preg(vreg: VReg) -> Option<PReg> {
24 if vreg.vreg() < PINNED_VREGS {
25 Some(PReg::from_index(vreg.vreg()))
26 } else {
27 None
28 }
29}
30
31pub fn first_user_vreg_index() -> usize {
34 PINNED_VREGS
39}
40
41#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
47#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
48pub struct Reg(VReg);
49
50impl Reg {
51 pub fn to_real_reg(self) -> Option<RealReg> {
54 pinned_vreg_to_preg(self.0).map(RealReg)
55 }
56
57 pub fn to_virtual_reg(self) -> Option<VirtualReg> {
60 if pinned_vreg_to_preg(self.0).is_none() {
61 Some(VirtualReg(self.0))
62 } else {
63 None
64 }
65 }
66
67 pub fn class(self) -> RegClass {
69 self.0.class()
70 }
71
72 pub fn is_real(self) -> bool {
74 self.to_real_reg().is_some()
75 }
76
77 pub fn is_virtual(self) -> bool {
79 self.to_virtual_reg().is_some()
80 }
81}
82
83impl std::fmt::Debug for Reg {
84 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
85 if self.0 == VReg::invalid() {
86 write!(f, "<invalid>")
87 } else if let Some(rreg) = self.to_real_reg() {
88 let preg: PReg = rreg.into();
89 write!(f, "{preg}")
90 } else if let Some(vreg) = self.to_virtual_reg() {
91 let vreg: VReg = vreg.into();
92 write!(f, "{vreg}")
93 } else {
94 unreachable!()
95 }
96 }
97}
98
99impl AsMut<Reg> for Reg {
100 fn as_mut(&mut self) -> &mut Reg {
101 self
102 }
103}
104
105#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
108#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
109pub struct RealReg(PReg);
110
111impl RealReg {
112 pub fn class(self) -> RegClass {
114 self.0.class()
115 }
116
117 pub fn hw_enc(self) -> u8 {
119 self.0.hw_enc() as u8
120 }
121}
122
123impl std::fmt::Debug for RealReg {
124 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
125 Reg::from(*self).fmt(f)
126 }
127}
128
129#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
135#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
136pub struct VirtualReg(VReg);
137
138impl VirtualReg {
139 pub fn class(self) -> RegClass {
141 self.0.class()
142 }
143
144 pub fn index(self) -> usize {
145 self.0.vreg()
146 }
147}
148
149impl std::fmt::Debug for VirtualReg {
150 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
151 Reg::from(*self).fmt(f)
152 }
153}
154
155#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
165#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
166pub struct Writable<T> {
167 reg: T,
168}
169
170impl<T> Writable<T> {
171 pub fn from_reg(reg: T) -> Writable<T> {
176 Writable { reg }
177 }
178
179 pub fn to_reg(self) -> T {
181 self.reg
182 }
183
184 pub fn reg_mut(&mut self) -> &mut T {
186 &mut self.reg
187 }
188
189 pub fn map<U>(self, f: impl Fn(T) -> U) -> Writable<U> {
191 Writable { reg: f(self.reg) }
192 }
193}
194
195impl std::convert::From<regalloc2::VReg> for Reg {
199 fn from(vreg: regalloc2::VReg) -> Reg {
200 Reg(vreg)
201 }
202}
203
204impl std::convert::From<regalloc2::VReg> for VirtualReg {
205 fn from(vreg: regalloc2::VReg) -> VirtualReg {
206 debug_assert!(pinned_vreg_to_preg(vreg).is_none());
207 VirtualReg(vreg)
208 }
209}
210
211impl std::convert::From<Reg> for regalloc2::VReg {
212 fn from(reg: Reg) -> regalloc2::VReg {
216 reg.0
217 }
218}
219impl std::convert::From<&Reg> for regalloc2::VReg {
220 fn from(reg: &Reg) -> regalloc2::VReg {
221 reg.0
222 }
223}
224
225impl std::convert::From<VirtualReg> for regalloc2::VReg {
226 fn from(reg: VirtualReg) -> regalloc2::VReg {
227 reg.0
228 }
229}
230
231impl std::convert::From<RealReg> for regalloc2::VReg {
232 fn from(reg: RealReg) -> regalloc2::VReg {
233 VReg::new(reg.0.index(), reg.0.class())
236 }
237}
238
239impl std::convert::From<RealReg> for regalloc2::PReg {
240 fn from(reg: RealReg) -> regalloc2::PReg {
241 reg.0
242 }
243}
244
245impl std::convert::From<regalloc2::PReg> for RealReg {
246 fn from(preg: regalloc2::PReg) -> RealReg {
247 RealReg(preg)
248 }
249}
250
251impl std::convert::From<regalloc2::PReg> for Reg {
252 fn from(preg: regalloc2::PReg) -> Reg {
253 RealReg(preg).into()
254 }
255}
256
257impl std::convert::From<RealReg> for Reg {
258 fn from(reg: RealReg) -> Reg {
259 Reg(reg.into())
260 }
261}
262
263impl std::convert::From<VirtualReg> for Reg {
264 fn from(reg: VirtualReg) -> Reg {
265 Reg(reg.0)
266 }
267}
268
269pub type SpillSlot = regalloc2::SpillSlot;
271
272pub type RegClass = regalloc2::RegClass;
288
289#[derive(Debug)]
294pub struct OperandCollector<'a, F: Fn(VReg) -> VReg> {
295 operands: &'a mut Vec<Operand>,
296 clobbers: PRegSet,
297
298 allocatable: PRegSet,
300
301 renamer: F,
302}
303
304impl<'a, F: Fn(VReg) -> VReg> OperandCollector<'a, F> {
305 pub fn new(operands: &'a mut Vec<Operand>, allocatable: PRegSet, renamer: F) -> Self {
307 Self {
308 operands,
309 clobbers: PRegSet::default(),
310 allocatable,
311 renamer,
312 }
313 }
314
315 pub fn finish(self) -> (usize, PRegSet) {
319 let end = self.operands.len();
320 (end, self.clobbers)
321 }
322}
323
324pub trait OperandVisitor {
325 fn add_operand(
326 &mut self,
327 reg: &mut Reg,
328 constraint: OperandConstraint,
329 kind: OperandKind,
330 pos: OperandPos,
331 );
332
333 fn debug_assert_is_allocatable_preg(&self, _reg: PReg, _expected: bool) {}
334
335 fn reg_clobbers(&mut self, _regs: PRegSet) {}
339}
340
341pub trait OperandVisitorImpl: OperandVisitor {
342 fn reg_fixed_nonallocatable(&mut self, preg: PReg) {
344 self.debug_assert_is_allocatable_preg(preg, false);
345 }
348
349 fn reg_use(&mut self, reg: &mut impl AsMut<Reg>) {
352 self.reg_maybe_fixed(reg.as_mut(), OperandKind::Use, OperandPos::Early);
353 }
354
355 fn reg_late_use(&mut self, reg: &mut impl AsMut<Reg>) {
357 self.reg_maybe_fixed(reg.as_mut(), OperandKind::Use, OperandPos::Late);
358 }
359
360 fn reg_def(&mut self, reg: &mut Writable<impl AsMut<Reg>>) {
364 self.reg_maybe_fixed(reg.reg.as_mut(), OperandKind::Def, OperandPos::Late);
365 }
366
367 fn reg_early_def(&mut self, reg: &mut Writable<impl AsMut<Reg>>) {
372 self.reg_maybe_fixed(reg.reg.as_mut(), OperandKind::Def, OperandPos::Early);
373 }
374
375 fn reg_fixed_late_use(&mut self, reg: &mut impl AsMut<Reg>, rreg: Reg) {
378 self.reg_fixed(reg.as_mut(), rreg, OperandKind::Use, OperandPos::Late);
379 }
380
381 fn reg_fixed_use(&mut self, reg: &mut impl AsMut<Reg>, rreg: Reg) {
384 self.reg_fixed(reg.as_mut(), rreg, OperandKind::Use, OperandPos::Early);
385 }
386
387 fn reg_fixed_def(&mut self, reg: &mut Writable<impl AsMut<Reg>>, rreg: Reg) {
390 self.reg_fixed(reg.reg.as_mut(), rreg, OperandKind::Def, OperandPos::Late);
391 }
392
393 fn reg_fixed(&mut self, reg: &mut Reg, rreg: Reg, kind: OperandKind, pos: OperandPos) {
395 debug_assert!(reg.is_virtual());
396 let rreg = rreg.to_real_reg().expect("fixed reg is not a RealReg");
397 self.debug_assert_is_allocatable_preg(rreg.into(), true);
398 let constraint = OperandConstraint::FixedReg(rreg.into());
399 self.add_operand(reg, constraint, kind, pos);
400 }
401
402 fn reg_maybe_fixed(&mut self, reg: &mut Reg, kind: OperandKind, pos: OperandPos) {
404 if let Some(rreg) = reg.to_real_reg() {
405 self.reg_fixed_nonallocatable(rreg.into());
406 } else {
407 debug_assert!(reg.is_virtual());
408 self.add_operand(reg, OperandConstraint::Reg, kind, pos);
409 }
410 }
411
412 fn reg_reuse_def(&mut self, reg: &mut Writable<impl AsMut<Reg>>, idx: usize) {
416 let reg = reg.reg.as_mut();
417 if let Some(rreg) = reg.to_real_reg() {
418 self.reg_fixed_nonallocatable(rreg.into());
423 } else {
424 debug_assert!(reg.is_virtual());
425 let constraint = OperandConstraint::Reuse(idx);
429 self.add_operand(reg, constraint, OperandKind::Def, OperandPos::Late);
430 }
431 }
432}
433
434impl<T: OperandVisitor> OperandVisitorImpl for T {}
435
436impl<'a, F: Fn(VReg) -> VReg> OperandVisitor for OperandCollector<'a, F> {
437 fn add_operand(
438 &mut self,
439 reg: &mut Reg,
440 constraint: OperandConstraint,
441 kind: OperandKind,
442 pos: OperandPos,
443 ) {
444 reg.0 = (self.renamer)(reg.0);
445 self.operands
446 .push(Operand::new(reg.0, constraint, kind, pos));
447 }
448
449 fn debug_assert_is_allocatable_preg(&self, reg: PReg, expected: bool) {
450 debug_assert_eq!(
451 self.allocatable.contains(reg),
452 expected,
453 "{reg:?} should{} be allocatable",
454 if expected { "" } else { " not" }
455 );
456 }
457
458 fn reg_clobbers(&mut self, regs: PRegSet) {
459 self.clobbers.union_from(regs);
460 }
461}
462
463impl<T: FnMut(&mut Reg, OperandConstraint, OperandKind, OperandPos)> OperandVisitor for T {
464 fn add_operand(
465 &mut self,
466 reg: &mut Reg,
467 constraint: OperandConstraint,
468 kind: OperandKind,
469 pos: OperandPos,
470 ) {
471 self(reg, constraint, kind, pos)
472 }
473}
474
475pub trait PrettyPrint {
481 fn pretty_print(&self, size_bytes: u8) -> String;
482
483 fn pretty_print_default(&self) -> String {
484 self.pretty_print(0)
485 }
486}