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 map<U>(self, f: impl Fn(T) -> U) -> Writable<U> {
184 Writable { reg: f(self.reg) }
185 }
186}
187
188impl std::convert::From<regalloc2::VReg> for Reg {
192 fn from(vreg: regalloc2::VReg) -> Reg {
193 Reg(vreg)
194 }
195}
196
197impl std::convert::From<regalloc2::VReg> for VirtualReg {
198 fn from(vreg: regalloc2::VReg) -> VirtualReg {
199 debug_assert!(pinned_vreg_to_preg(vreg).is_none());
200 VirtualReg(vreg)
201 }
202}
203
204impl std::convert::From<Reg> for regalloc2::VReg {
205 fn from(reg: Reg) -> regalloc2::VReg {
209 reg.0
210 }
211}
212impl std::convert::From<&Reg> for regalloc2::VReg {
213 fn from(reg: &Reg) -> regalloc2::VReg {
214 reg.0
215 }
216}
217
218impl std::convert::From<VirtualReg> for regalloc2::VReg {
219 fn from(reg: VirtualReg) -> regalloc2::VReg {
220 reg.0
221 }
222}
223
224impl std::convert::From<RealReg> for regalloc2::VReg {
225 fn from(reg: RealReg) -> regalloc2::VReg {
226 VReg::new(reg.0.index(), reg.0.class())
229 }
230}
231
232impl std::convert::From<RealReg> for regalloc2::PReg {
233 fn from(reg: RealReg) -> regalloc2::PReg {
234 reg.0
235 }
236}
237
238impl std::convert::From<regalloc2::PReg> for RealReg {
239 fn from(preg: regalloc2::PReg) -> RealReg {
240 RealReg(preg)
241 }
242}
243
244impl std::convert::From<regalloc2::PReg> for Reg {
245 fn from(preg: regalloc2::PReg) -> Reg {
246 RealReg(preg).into()
247 }
248}
249
250impl std::convert::From<RealReg> for Reg {
251 fn from(reg: RealReg) -> Reg {
252 Reg(reg.into())
253 }
254}
255
256impl std::convert::From<VirtualReg> for Reg {
257 fn from(reg: VirtualReg) -> Reg {
258 Reg(reg.0)
259 }
260}
261
262pub type SpillSlot = regalloc2::SpillSlot;
264
265pub type RegClass = regalloc2::RegClass;
281
282#[derive(Debug)]
287pub struct OperandCollector<'a, F: Fn(VReg) -> VReg> {
288 operands: &'a mut Vec<Operand>,
289 clobbers: PRegSet,
290
291 allocatable: PRegSet,
293
294 renamer: F,
295}
296
297impl<'a, F: Fn(VReg) -> VReg> OperandCollector<'a, F> {
298 pub fn new(operands: &'a mut Vec<Operand>, allocatable: PRegSet, renamer: F) -> Self {
300 Self {
301 operands,
302 clobbers: PRegSet::default(),
303 allocatable,
304 renamer,
305 }
306 }
307
308 pub fn finish(self) -> (usize, PRegSet) {
312 let end = self.operands.len();
313 (end, self.clobbers)
314 }
315}
316
317pub trait OperandVisitor {
318 fn add_operand(
319 &mut self,
320 reg: &mut Reg,
321 constraint: OperandConstraint,
322 kind: OperandKind,
323 pos: OperandPos,
324 );
325
326 fn debug_assert_is_allocatable_preg(&self, _reg: PReg, _expected: bool) {}
327
328 fn reg_clobbers(&mut self, _regs: PRegSet) {}
332}
333
334pub trait OperandVisitorImpl: OperandVisitor {
335 fn reg_fixed_nonallocatable(&mut self, preg: PReg) {
337 self.debug_assert_is_allocatable_preg(preg, false);
338 }
341
342 fn reg_use(&mut self, reg: &mut impl AsMut<Reg>) {
345 self.reg_maybe_fixed(reg.as_mut(), OperandKind::Use, OperandPos::Early);
346 }
347
348 fn reg_late_use(&mut self, reg: &mut impl AsMut<Reg>) {
350 self.reg_maybe_fixed(reg.as_mut(), OperandKind::Use, OperandPos::Late);
351 }
352
353 fn reg_def(&mut self, reg: &mut Writable<impl AsMut<Reg>>) {
357 self.reg_maybe_fixed(reg.reg.as_mut(), OperandKind::Def, OperandPos::Late);
358 }
359
360 fn reg_early_def(&mut self, reg: &mut Writable<impl AsMut<Reg>>) {
365 self.reg_maybe_fixed(reg.reg.as_mut(), OperandKind::Def, OperandPos::Early);
366 }
367
368 fn reg_fixed_late_use(&mut self, reg: &mut impl AsMut<Reg>, rreg: Reg) {
371 self.reg_fixed(reg.as_mut(), rreg, OperandKind::Use, OperandPos::Late);
372 }
373
374 fn reg_fixed_use(&mut self, reg: &mut impl AsMut<Reg>, rreg: Reg) {
377 self.reg_fixed(reg.as_mut(), rreg, OperandKind::Use, OperandPos::Early);
378 }
379
380 fn reg_fixed_def(&mut self, reg: &mut Writable<impl AsMut<Reg>>, rreg: Reg) {
383 self.reg_fixed(reg.reg.as_mut(), rreg, OperandKind::Def, OperandPos::Late);
384 }
385
386 fn reg_fixed(&mut self, reg: &mut Reg, rreg: Reg, kind: OperandKind, pos: OperandPos) {
388 debug_assert!(reg.is_virtual());
389 let rreg = rreg.to_real_reg().expect("fixed reg is not a RealReg");
390 self.debug_assert_is_allocatable_preg(rreg.into(), true);
391 let constraint = OperandConstraint::FixedReg(rreg.into());
392 self.add_operand(reg, constraint, kind, pos);
393 }
394
395 fn reg_maybe_fixed(&mut self, reg: &mut Reg, kind: OperandKind, pos: OperandPos) {
397 if let Some(rreg) = reg.to_real_reg() {
398 self.reg_fixed_nonallocatable(rreg.into());
399 } else {
400 debug_assert!(reg.is_virtual());
401 self.add_operand(reg, OperandConstraint::Reg, kind, pos);
402 }
403 }
404
405 fn reg_reuse_def(&mut self, reg: &mut Writable<impl AsMut<Reg>>, idx: usize) {
409 let reg = reg.reg.as_mut();
410 if let Some(rreg) = reg.to_real_reg() {
411 self.reg_fixed_nonallocatable(rreg.into());
416 } else {
417 debug_assert!(reg.is_virtual());
418 let constraint = OperandConstraint::Reuse(idx);
422 self.add_operand(reg, constraint, OperandKind::Def, OperandPos::Late);
423 }
424 }
425}
426
427impl<T: OperandVisitor> OperandVisitorImpl for T {}
428
429impl<'a, F: Fn(VReg) -> VReg> OperandVisitor for OperandCollector<'a, F> {
430 fn add_operand(
431 &mut self,
432 reg: &mut Reg,
433 constraint: OperandConstraint,
434 kind: OperandKind,
435 pos: OperandPos,
436 ) {
437 reg.0 = (self.renamer)(reg.0);
438 self.operands
439 .push(Operand::new(reg.0, constraint, kind, pos));
440 }
441
442 fn debug_assert_is_allocatable_preg(&self, reg: PReg, expected: bool) {
443 debug_assert_eq!(
444 self.allocatable.contains(reg),
445 expected,
446 "{reg:?} should{} be allocatable",
447 if expected { "" } else { " not" }
448 );
449 }
450
451 fn reg_clobbers(&mut self, regs: PRegSet) {
452 self.clobbers.union_from(regs);
453 }
454}
455
456impl<T: FnMut(&mut Reg, OperandConstraint, OperandKind, OperandPos)> OperandVisitor for T {
457 fn add_operand(
458 &mut self,
459 reg: &mut Reg,
460 constraint: OperandConstraint,
461 kind: OperandKind,
462 pos: OperandPos,
463 ) {
464 self(reg, constraint, kind, pos)
465 }
466}
467
468pub trait PrettyPrint {
474 fn pretty_print(&self, size_bytes: u8) -> String;
475
476 fn pretty_print_default(&self) -> String {
477 self.pretty_print(0)
478 }
479}