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;
17
18pub fn pinned_vreg_to_preg(vreg: VReg) -> Option<PReg> {
20 if vreg.vreg() < PINNED_VREGS {
21 Some(PReg::from_index(vreg.vreg()))
22 } else {
23 None
24 }
25}
26
27pub const fn preg_to_pinned_vreg(preg: PReg) -> VReg {
29 VReg::new(preg.index(), preg.class())
30}
31
32pub fn first_user_vreg_index() -> usize {
35 PINNED_VREGS
40}
41
42#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
48#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
49pub struct Reg(u32);
50
51const REG_SPILLSLOT_BIT: u32 = 0x8000_0000;
52const REG_SPILLSLOT_MASK: u32 = !REG_SPILLSLOT_BIT;
53
54impl Reg {
55 pub const fn from_virtual_reg(vreg: regalloc2::VReg) -> Reg {
57 Reg(vreg.bits() as u32)
58 }
59
60 pub const fn from_real_reg(preg: regalloc2::PReg) -> Reg {
62 Reg(preg_to_pinned_vreg(preg).bits() as u32)
63 }
64
65 pub fn to_real_reg(self) -> Option<RealReg> {
68 pinned_vreg_to_preg(self.0.into()).map(RealReg)
69 }
70
71 pub fn to_virtual_reg(self) -> Option<VirtualReg> {
74 if self.to_spillslot().is_some() {
75 None
76 } else if pinned_vreg_to_preg(self.0.into()).is_none() {
77 Some(VirtualReg(self.0.into()))
78 } else {
79 None
80 }
81 }
82
83 pub fn to_spillslot(self) -> Option<SpillSlot> {
85 if (self.0 & REG_SPILLSLOT_BIT) != 0 {
86 Some(SpillSlot::new((self.0 & REG_SPILLSLOT_MASK) as usize))
87 } else {
88 None
89 }
90 }
91
92 pub fn class(self) -> RegClass {
94 assert!(!self.to_spillslot().is_some());
95 VReg::from(self.0).class()
96 }
97
98 pub fn is_real(self) -> bool {
100 self.to_real_reg().is_some()
101 }
102
103 pub fn is_virtual(self) -> bool {
105 self.to_virtual_reg().is_some()
106 }
107
108 pub fn is_spillslot(self) -> bool {
110 self.to_spillslot().is_some()
111 }
112}
113
114impl std::fmt::Debug for Reg {
115 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
116 if VReg::from(self.0) == VReg::invalid() {
117 write!(f, "<invalid>")
118 } else if let Some(spillslot) = self.to_spillslot() {
119 write!(f, "{spillslot}")
120 } else if let Some(rreg) = self.to_real_reg() {
121 let preg: PReg = rreg.into();
122 write!(f, "{preg}")
123 } else if let Some(vreg) = self.to_virtual_reg() {
124 let vreg: VReg = vreg.into();
125 write!(f, "{vreg}")
126 } else {
127 unreachable!()
128 }
129 }
130}
131
132impl AsMut<Reg> for Reg {
133 fn as_mut(&mut self) -> &mut Reg {
134 self
135 }
136}
137
138#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
141#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
142pub struct RealReg(PReg);
143
144impl RealReg {
145 pub fn class(self) -> RegClass {
147 self.0.class()
148 }
149
150 pub fn hw_enc(self) -> u8 {
152 self.0.hw_enc() as u8
153 }
154}
155
156impl std::fmt::Debug for RealReg {
157 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
158 Reg::from(*self).fmt(f)
159 }
160}
161
162#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
168#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
169pub struct VirtualReg(VReg);
170
171impl VirtualReg {
172 pub fn class(self) -> RegClass {
174 self.0.class()
175 }
176
177 pub fn index(self) -> usize {
178 self.0.vreg()
179 }
180}
181
182impl std::fmt::Debug for VirtualReg {
183 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
184 Reg::from(*self).fmt(f)
185 }
186}
187
188#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
198#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
199pub struct Writable<T> {
200 reg: T,
201}
202
203impl<T> Writable<T> {
204 pub fn from_reg(reg: T) -> Writable<T> {
209 Writable { reg }
210 }
211
212 pub fn to_reg(self) -> T {
214 self.reg
215 }
216
217 pub fn reg_mut(&mut self) -> &mut T {
219 &mut self.reg
220 }
221
222 pub fn map<U>(self, f: impl Fn(T) -> U) -> Writable<U> {
224 Writable { reg: f(self.reg) }
225 }
226}
227
228impl std::convert::From<regalloc2::VReg> for Reg {
232 fn from(vreg: regalloc2::VReg) -> Reg {
233 Reg(vreg.bits() as u32)
234 }
235}
236
237impl std::convert::From<regalloc2::VReg> for VirtualReg {
238 fn from(vreg: regalloc2::VReg) -> VirtualReg {
239 debug_assert!(pinned_vreg_to_preg(vreg).is_none());
240 VirtualReg(vreg)
241 }
242}
243
244impl std::convert::From<Reg> for regalloc2::VReg {
245 fn from(reg: Reg) -> regalloc2::VReg {
249 reg.0.into()
250 }
251}
252impl std::convert::From<&Reg> for regalloc2::VReg {
253 fn from(reg: &Reg) -> regalloc2::VReg {
254 reg.0.into()
255 }
256}
257
258impl std::convert::From<VirtualReg> for regalloc2::VReg {
259 fn from(reg: VirtualReg) -> regalloc2::VReg {
260 reg.0
261 }
262}
263
264impl std::convert::From<RealReg> for regalloc2::VReg {
265 fn from(reg: RealReg) -> regalloc2::VReg {
266 VReg::new(reg.0.index(), reg.0.class())
269 }
270}
271
272impl std::convert::From<RealReg> for regalloc2::PReg {
273 fn from(reg: RealReg) -> regalloc2::PReg {
274 reg.0
275 }
276}
277
278impl std::convert::From<regalloc2::PReg> for RealReg {
279 fn from(preg: regalloc2::PReg) -> RealReg {
280 RealReg(preg)
281 }
282}
283
284impl std::convert::From<regalloc2::PReg> for Reg {
285 fn from(preg: regalloc2::PReg) -> Reg {
286 RealReg(preg).into()
287 }
288}
289
290impl std::convert::From<RealReg> for Reg {
291 fn from(reg: RealReg) -> Reg {
292 Reg(VReg::from(reg).bits() as u32)
293 }
294}
295
296impl std::convert::From<VirtualReg> for Reg {
297 fn from(reg: VirtualReg) -> Reg {
298 Reg(reg.0.bits() as u32)
299 }
300}
301
302pub type SpillSlot = regalloc2::SpillSlot;
304
305impl std::convert::From<regalloc2::SpillSlot> for Reg {
306 fn from(spillslot: regalloc2::SpillSlot) -> Reg {
307 Reg(REG_SPILLSLOT_BIT | spillslot.index() as u32)
308 }
309}
310
311pub type RegClass = regalloc2::RegClass;
327
328#[derive(Debug)]
333pub struct OperandCollector<'a, F: Fn(VReg) -> VReg> {
334 operands: &'a mut Vec<Operand>,
335 clobbers: PRegSet,
336
337 allocatable: PRegSet,
339
340 renamer: F,
341}
342
343impl<'a, F: Fn(VReg) -> VReg> OperandCollector<'a, F> {
344 pub fn new(operands: &'a mut Vec<Operand>, allocatable: PRegSet, renamer: F) -> Self {
346 Self {
347 operands,
348 clobbers: PRegSet::default(),
349 allocatable,
350 renamer,
351 }
352 }
353
354 pub fn finish(self) -> (usize, PRegSet) {
358 let end = self.operands.len();
359 (end, self.clobbers)
360 }
361}
362
363pub trait OperandVisitor {
364 fn add_operand(
365 &mut self,
366 reg: &mut Reg,
367 constraint: OperandConstraint,
368 kind: OperandKind,
369 pos: OperandPos,
370 );
371
372 fn debug_assert_is_allocatable_preg(&self, _reg: PReg, _expected: bool) {}
373
374 fn reg_clobbers(&mut self, _regs: PRegSet) {}
378}
379
380pub trait OperandVisitorImpl: OperandVisitor {
381 fn reg_fixed_nonallocatable(&mut self, preg: PReg) {
383 self.debug_assert_is_allocatable_preg(preg, false);
384 }
387
388 fn reg_use(&mut self, reg: &mut impl AsMut<Reg>) {
391 self.reg_maybe_fixed(reg.as_mut(), OperandKind::Use, OperandPos::Early);
392 }
393
394 fn reg_late_use(&mut self, reg: &mut impl AsMut<Reg>) {
396 self.reg_maybe_fixed(reg.as_mut(), OperandKind::Use, OperandPos::Late);
397 }
398
399 fn reg_def(&mut self, reg: &mut Writable<impl AsMut<Reg>>) {
403 self.reg_maybe_fixed(reg.reg.as_mut(), OperandKind::Def, OperandPos::Late);
404 }
405
406 fn reg_early_def(&mut self, reg: &mut Writable<impl AsMut<Reg>>) {
411 self.reg_maybe_fixed(reg.reg.as_mut(), OperandKind::Def, OperandPos::Early);
412 }
413
414 fn reg_fixed_late_use(&mut self, reg: &mut impl AsMut<Reg>, rreg: Reg) {
417 self.reg_fixed(reg.as_mut(), rreg, OperandKind::Use, OperandPos::Late);
418 }
419
420 fn reg_fixed_use(&mut self, reg: &mut impl AsMut<Reg>, rreg: Reg) {
423 self.reg_fixed(reg.as_mut(), rreg, OperandKind::Use, OperandPos::Early);
424 }
425
426 fn reg_fixed_def(&mut self, reg: &mut Writable<impl AsMut<Reg>>, rreg: Reg) {
429 self.reg_fixed(reg.reg.as_mut(), rreg, OperandKind::Def, OperandPos::Late);
430 }
431
432 fn reg_fixed(&mut self, reg: &mut Reg, rreg: Reg, kind: OperandKind, pos: OperandPos) {
434 debug_assert!(reg.is_virtual());
435 let rreg = rreg.to_real_reg().expect("fixed reg is not a RealReg");
436 self.debug_assert_is_allocatable_preg(rreg.into(), true);
437 let constraint = OperandConstraint::FixedReg(rreg.into());
438 self.add_operand(reg, constraint, kind, pos);
439 }
440
441 fn reg_maybe_fixed(&mut self, reg: &mut Reg, kind: OperandKind, pos: OperandPos) {
443 if let Some(rreg) = reg.to_real_reg() {
444 self.reg_fixed_nonallocatable(rreg.into());
445 } else {
446 debug_assert!(reg.is_virtual());
447 self.add_operand(reg, OperandConstraint::Reg, kind, pos);
448 }
449 }
450
451 fn reg_reuse_def(&mut self, reg: &mut Writable<impl AsMut<Reg>>, idx: usize) {
455 let reg = reg.reg.as_mut();
456 if let Some(rreg) = reg.to_real_reg() {
457 self.reg_fixed_nonallocatable(rreg.into());
462 } else {
463 debug_assert!(reg.is_virtual());
464 let constraint = OperandConstraint::Reuse(idx);
468 self.add_operand(reg, constraint, OperandKind::Def, OperandPos::Late);
469 }
470 }
471
472 fn any_def(&mut self, reg: &mut Writable<impl AsMut<Reg>>) {
477 self.add_operand(
478 reg.reg.as_mut(),
479 OperandConstraint::Any,
480 OperandKind::Def,
481 OperandPos::Late,
482 );
483 }
484}
485
486impl<T: OperandVisitor> OperandVisitorImpl for T {}
487
488impl<'a, F: Fn(VReg) -> VReg> OperandVisitor for OperandCollector<'a, F> {
489 fn add_operand(
490 &mut self,
491 reg: &mut Reg,
492 constraint: OperandConstraint,
493 kind: OperandKind,
494 pos: OperandPos,
495 ) {
496 debug_assert!(!reg.is_spillslot());
497 reg.0 = (self.renamer)(VReg::from(reg.0)).bits() as u32;
498 self.operands
499 .push(Operand::new(VReg::from(reg.0), constraint, kind, pos));
500 }
501
502 fn debug_assert_is_allocatable_preg(&self, reg: PReg, expected: bool) {
503 debug_assert_eq!(
504 self.allocatable.contains(reg),
505 expected,
506 "{reg:?} should{} be allocatable",
507 if expected { "" } else { " not" }
508 );
509 }
510
511 fn reg_clobbers(&mut self, regs: PRegSet) {
512 self.clobbers.union_from(regs);
513 }
514}
515
516impl<T: FnMut(&mut Reg, OperandConstraint, OperandKind, OperandPos)> OperandVisitor for T {
517 fn add_operand(
518 &mut self,
519 reg: &mut Reg,
520 constraint: OperandConstraint,
521 kind: OperandKind,
522 pos: OperandPos,
523 ) {
524 self(reg, constraint, kind, pos)
525 }
526}
527
528pub trait PrettyPrint {
534 fn pretty_print(&self, size_bytes: u8) -> String;
535
536 fn pretty_print_default(&self) -> String {
537 self.pretty_print(0)
538 }
539}