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 let Some(rreg) = self.to_real_reg() {
86 let preg: PReg = rreg.into();
87 write!(f, "{preg}")
88 } else if let Some(vreg) = self.to_virtual_reg() {
89 let vreg: VReg = vreg.into();
90 write!(f, "{vreg}")
91 } else {
92 unreachable!()
93 }
94 }
95}
96
97impl AsMut<Reg> for Reg {
98 fn as_mut(&mut self) -> &mut Reg {
99 self
100 }
101}
102
103#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
106#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
107pub struct RealReg(PReg);
108
109impl RealReg {
110 pub fn class(self) -> RegClass {
112 self.0.class()
113 }
114
115 pub fn hw_enc(self) -> u8 {
117 self.0.hw_enc() as u8
118 }
119}
120
121impl std::fmt::Debug for RealReg {
122 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
123 Reg::from(*self).fmt(f)
124 }
125}
126
127#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
133#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
134pub struct VirtualReg(VReg);
135
136impl VirtualReg {
137 pub fn class(self) -> RegClass {
139 self.0.class()
140 }
141
142 pub fn index(self) -> usize {
143 self.0.vreg()
144 }
145}
146
147impl std::fmt::Debug for VirtualReg {
148 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
149 Reg::from(*self).fmt(f)
150 }
151}
152
153#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
163#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
164pub struct Writable<T> {
165 reg: T,
166}
167
168impl<T> Writable<T> {
169 pub fn from_reg(reg: T) -> Writable<T> {
174 Writable { reg }
175 }
176
177 pub fn to_reg(self) -> T {
179 self.reg
180 }
181
182 pub fn reg_mut(&mut self) -> &mut T {
184 &mut self.reg
185 }
186
187 pub fn map<U>(self, f: impl Fn(T) -> U) -> Writable<U> {
189 Writable { reg: f(self.reg) }
190 }
191}
192
193impl std::convert::From<regalloc2::VReg> for Reg {
197 fn from(vreg: regalloc2::VReg) -> Reg {
198 Reg(vreg)
199 }
200}
201
202impl std::convert::From<regalloc2::VReg> for VirtualReg {
203 fn from(vreg: regalloc2::VReg) -> VirtualReg {
204 debug_assert!(pinned_vreg_to_preg(vreg).is_none());
205 VirtualReg(vreg)
206 }
207}
208
209impl std::convert::From<Reg> for regalloc2::VReg {
210 fn from(reg: Reg) -> regalloc2::VReg {
214 reg.0
215 }
216}
217impl std::convert::From<&Reg> for regalloc2::VReg {
218 fn from(reg: &Reg) -> regalloc2::VReg {
219 reg.0
220 }
221}
222
223impl std::convert::From<VirtualReg> for regalloc2::VReg {
224 fn from(reg: VirtualReg) -> regalloc2::VReg {
225 reg.0
226 }
227}
228
229impl std::convert::From<RealReg> for regalloc2::VReg {
230 fn from(reg: RealReg) -> regalloc2::VReg {
231 VReg::new(reg.0.index(), reg.0.class())
234 }
235}
236
237impl std::convert::From<RealReg> for regalloc2::PReg {
238 fn from(reg: RealReg) -> regalloc2::PReg {
239 reg.0
240 }
241}
242
243impl std::convert::From<regalloc2::PReg> for RealReg {
244 fn from(preg: regalloc2::PReg) -> RealReg {
245 RealReg(preg)
246 }
247}
248
249impl std::convert::From<regalloc2::PReg> for Reg {
250 fn from(preg: regalloc2::PReg) -> Reg {
251 RealReg(preg).into()
252 }
253}
254
255impl std::convert::From<RealReg> for Reg {
256 fn from(reg: RealReg) -> Reg {
257 Reg(reg.into())
258 }
259}
260
261impl std::convert::From<VirtualReg> for Reg {
262 fn from(reg: VirtualReg) -> Reg {
263 Reg(reg.0)
264 }
265}
266
267pub type SpillSlot = regalloc2::SpillSlot;
269
270pub type RegClass = regalloc2::RegClass;
286
287#[derive(Debug)]
292pub struct OperandCollector<'a, F: Fn(VReg) -> VReg> {
293 operands: &'a mut Vec<Operand>,
294 clobbers: PRegSet,
295
296 allocatable: PRegSet,
298
299 renamer: F,
300}
301
302impl<'a, F: Fn(VReg) -> VReg> OperandCollector<'a, F> {
303 pub fn new(operands: &'a mut Vec<Operand>, allocatable: PRegSet, renamer: F) -> Self {
305 Self {
306 operands,
307 clobbers: PRegSet::default(),
308 allocatable,
309 renamer,
310 }
311 }
312
313 pub fn finish(self) -> (usize, PRegSet) {
317 let end = self.operands.len();
318 (end, self.clobbers)
319 }
320}
321
322pub trait OperandVisitor {
323 fn add_operand(
324 &mut self,
325 reg: &mut Reg,
326 constraint: OperandConstraint,
327 kind: OperandKind,
328 pos: OperandPos,
329 );
330
331 fn debug_assert_is_allocatable_preg(&self, _reg: PReg, _expected: bool) {}
332
333 fn reg_clobbers(&mut self, _regs: PRegSet) {}
337}
338
339pub trait OperandVisitorImpl: OperandVisitor {
340 fn reg_fixed_nonallocatable(&mut self, preg: PReg) {
342 self.debug_assert_is_allocatable_preg(preg, false);
343 }
346
347 fn reg_use(&mut self, reg: &mut impl AsMut<Reg>) {
350 self.reg_maybe_fixed(reg.as_mut(), OperandKind::Use, OperandPos::Early);
351 }
352
353 fn reg_late_use(&mut self, reg: &mut impl AsMut<Reg>) {
355 self.reg_maybe_fixed(reg.as_mut(), OperandKind::Use, OperandPos::Late);
356 }
357
358 fn reg_def(&mut self, reg: &mut Writable<impl AsMut<Reg>>) {
362 self.reg_maybe_fixed(reg.reg.as_mut(), OperandKind::Def, OperandPos::Late);
363 }
364
365 fn reg_early_def(&mut self, reg: &mut Writable<impl AsMut<Reg>>) {
370 self.reg_maybe_fixed(reg.reg.as_mut(), OperandKind::Def, OperandPos::Early);
371 }
372
373 fn reg_fixed_late_use(&mut self, reg: &mut impl AsMut<Reg>, rreg: Reg) {
376 self.reg_fixed(reg.as_mut(), rreg, OperandKind::Use, OperandPos::Late);
377 }
378
379 fn reg_fixed_use(&mut self, reg: &mut impl AsMut<Reg>, rreg: Reg) {
382 self.reg_fixed(reg.as_mut(), rreg, OperandKind::Use, OperandPos::Early);
383 }
384
385 fn reg_fixed_def(&mut self, reg: &mut Writable<impl AsMut<Reg>>, rreg: Reg) {
388 self.reg_fixed(reg.reg.as_mut(), rreg, OperandKind::Def, OperandPos::Late);
389 }
390
391 fn reg_fixed(&mut self, reg: &mut Reg, rreg: Reg, kind: OperandKind, pos: OperandPos) {
393 debug_assert!(reg.is_virtual());
394 let rreg = rreg.to_real_reg().expect("fixed reg is not a RealReg");
395 self.debug_assert_is_allocatable_preg(rreg.into(), true);
396 let constraint = OperandConstraint::FixedReg(rreg.into());
397 self.add_operand(reg, constraint, kind, pos);
398 }
399
400 fn reg_maybe_fixed(&mut self, reg: &mut Reg, kind: OperandKind, pos: OperandPos) {
402 if let Some(rreg) = reg.to_real_reg() {
403 self.reg_fixed_nonallocatable(rreg.into());
404 } else {
405 debug_assert!(reg.is_virtual());
406 self.add_operand(reg, OperandConstraint::Reg, kind, pos);
407 }
408 }
409
410 fn reg_reuse_def(&mut self, reg: &mut Writable<impl AsMut<Reg>>, idx: usize) {
414 let reg = reg.reg.as_mut();
415 if let Some(rreg) = reg.to_real_reg() {
416 self.reg_fixed_nonallocatable(rreg.into());
421 } else {
422 debug_assert!(reg.is_virtual());
423 let constraint = OperandConstraint::Reuse(idx);
427 self.add_operand(reg, constraint, OperandKind::Def, OperandPos::Late);
428 }
429 }
430}
431
432impl<T: OperandVisitor> OperandVisitorImpl for T {}
433
434impl<'a, F: Fn(VReg) -> VReg> OperandVisitor for OperandCollector<'a, F> {
435 fn add_operand(
436 &mut self,
437 reg: &mut Reg,
438 constraint: OperandConstraint,
439 kind: OperandKind,
440 pos: OperandPos,
441 ) {
442 reg.0 = (self.renamer)(reg.0);
443 self.operands
444 .push(Operand::new(reg.0, constraint, kind, pos));
445 }
446
447 fn debug_assert_is_allocatable_preg(&self, reg: PReg, expected: bool) {
448 debug_assert_eq!(
449 self.allocatable.contains(reg),
450 expected,
451 "{reg:?} should{} be allocatable",
452 if expected { "" } else { " not" }
453 );
454 }
455
456 fn reg_clobbers(&mut self, regs: PRegSet) {
457 self.clobbers.union_from(regs);
458 }
459}
460
461impl<T: FnMut(&mut Reg, OperandConstraint, OperandKind, OperandPos)> OperandVisitor for T {
462 fn add_operand(
463 &mut self,
464 reg: &mut Reg,
465 constraint: OperandConstraint,
466 kind: OperandKind,
467 pos: OperandPos,
468 ) {
469 self(reg, constraint, kind, pos)
470 }
471}
472
473pub trait PrettyPrint {
479 fn pretty_print(&self, size_bytes: u8) -> String;
480
481 fn pretty_print_default(&self) -> String {
482 self.pretty_print(0)
483 }
484}