summaryrefslogtreecommitdiffstats
path: root/third_party/rust/cranelift-codegen/src/regalloc/affinity.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/cranelift-codegen/src/regalloc/affinity.rs')
-rw-r--r--third_party/rust/cranelift-codegen/src/regalloc/affinity.rs126
1 files changed, 126 insertions, 0 deletions
diff --git a/third_party/rust/cranelift-codegen/src/regalloc/affinity.rs b/third_party/rust/cranelift-codegen/src/regalloc/affinity.rs
new file mode 100644
index 0000000000..efcc4dabfa
--- /dev/null
+++ b/third_party/rust/cranelift-codegen/src/regalloc/affinity.rs
@@ -0,0 +1,126 @@
+//! Value affinity for register allocation.
+//!
+//! An SSA value's affinity is a hint used to guide the register allocator. It specifies the class
+//! of allocation that is likely to cause the least amount of fixup moves in order to satisfy
+//! instruction operand constraints.
+//!
+//! For values that want to be in registers, the affinity hint includes a register class or
+//! subclass. This is just a hint, and the register allocator is allowed to pick a register from a
+//! larger register class instead.
+
+use crate::ir::{AbiParam, ArgumentLoc};
+use crate::isa::{ConstraintKind, OperandConstraint, RegClassIndex, RegInfo, TargetIsa};
+use core::fmt;
+
+/// Preferred register allocation for an SSA value.
+#[derive(Clone, Copy, Debug)]
+pub enum Affinity {
+ /// No affinity.
+ ///
+ /// This indicates a value that is not defined or used by any real instructions. It is a ghost
+ /// value that won't appear in the final program.
+ Unassigned,
+
+ /// This value should be placed in a spill slot on the stack.
+ Stack,
+
+ /// This value prefers a register from the given register class.
+ Reg(RegClassIndex),
+}
+
+impl Default for Affinity {
+ fn default() -> Self {
+ Self::Unassigned
+ }
+}
+
+impl Affinity {
+ /// Create an affinity that satisfies a single constraint.
+ ///
+ /// This will never create an `Affinity::Unassigned`.
+ /// Use the `Default` implementation for that.
+ pub fn new(constraint: &OperandConstraint) -> Self {
+ if constraint.kind == ConstraintKind::Stack {
+ Self::Stack
+ } else {
+ Self::Reg(constraint.regclass.into())
+ }
+ }
+
+ /// Create an affinity that matches an ABI argument for `isa`.
+ pub fn abi(arg: &AbiParam, isa: &dyn TargetIsa) -> Self {
+ match arg.location {
+ ArgumentLoc::Unassigned => Self::Unassigned,
+ ArgumentLoc::Reg(_) => Self::Reg(isa.regclass_for_abi_type(arg.value_type).into()),
+ ArgumentLoc::Stack(_) => Self::Stack,
+ }
+ }
+
+ /// Is this the `Unassigned` affinity?
+ pub fn is_unassigned(self) -> bool {
+ match self {
+ Self::Unassigned => true,
+ _ => false,
+ }
+ }
+
+ /// Is this the `Reg` affinity?
+ pub fn is_reg(self) -> bool {
+ match self {
+ Self::Reg(_) => true,
+ _ => false,
+ }
+ }
+
+ /// Is this the `Stack` affinity?
+ pub fn is_stack(self) -> bool {
+ match self {
+ Self::Stack => true,
+ _ => false,
+ }
+ }
+
+ /// Merge an operand constraint into this affinity.
+ ///
+ /// Note that this does not guarantee that the register allocator will pick a register that
+ /// satisfies the constraint.
+ pub fn merge(&mut self, constraint: &OperandConstraint, reginfo: &RegInfo) {
+ match *self {
+ Self::Unassigned => *self = Self::new(constraint),
+ Self::Reg(rc) => {
+ // If the preferred register class is a subclass of the constraint, there's no need
+ // to change anything.
+ if constraint.kind != ConstraintKind::Stack && !constraint.regclass.has_subclass(rc)
+ {
+ // If the register classes overlap, try to shrink our preferred register class.
+ if let Some(subclass) = constraint.regclass.intersect_index(reginfo.rc(rc)) {
+ *self = Self::Reg(subclass);
+ }
+ }
+ }
+ Self::Stack => {}
+ }
+ }
+
+ /// Return an object that can display this value affinity, using the register info from the
+ /// target ISA.
+ pub fn display<'a, R: Into<Option<&'a RegInfo>>>(self, regs: R) -> DisplayAffinity<'a> {
+ DisplayAffinity(self, regs.into())
+ }
+}
+
+/// Displaying an `Affinity` correctly requires the associated `RegInfo` from the target ISA.
+pub struct DisplayAffinity<'a>(Affinity, Option<&'a RegInfo>);
+
+impl<'a> fmt::Display for DisplayAffinity<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self.0 {
+ Affinity::Unassigned => write!(f, "unassigned"),
+ Affinity::Stack => write!(f, "stack"),
+ Affinity::Reg(rci) => match self.1 {
+ Some(regs) => write!(f, "{}", regs.rc(rci)),
+ None => write!(f, "{}", rci),
+ },
+ }
+ }
+}