summaryrefslogtreecommitdiffstats
path: root/third_party/rust/cranelift-codegen/src/ir/valueloc.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/cranelift-codegen/src/ir/valueloc.rs')
-rw-r--r--third_party/rust/cranelift-codegen/src/ir/valueloc.rs166
1 files changed, 166 insertions, 0 deletions
diff --git a/third_party/rust/cranelift-codegen/src/ir/valueloc.rs b/third_party/rust/cranelift-codegen/src/ir/valueloc.rs
new file mode 100644
index 0000000000..d0b924886a
--- /dev/null
+++ b/third_party/rust/cranelift-codegen/src/ir/valueloc.rs
@@ -0,0 +1,166 @@
+//! Value locations.
+//!
+//! The register allocator assigns every SSA value to either a register or a stack slot. This
+//! assignment is represented by a `ValueLoc` object.
+
+use crate::ir::StackSlot;
+use crate::isa::{RegInfo, RegUnit};
+use core::fmt;
+
+#[cfg(feature = "enable-serde")]
+use serde::{Deserialize, Serialize};
+
+/// Value location.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+pub enum ValueLoc {
+ /// This value has not been assigned to a location yet.
+ Unassigned,
+ /// Value is assigned to a register.
+ Reg(RegUnit),
+ /// Value is assigned to a stack slot.
+ Stack(StackSlot),
+}
+
+impl Default for ValueLoc {
+ fn default() -> Self {
+ Self::Unassigned
+ }
+}
+
+impl ValueLoc {
+ /// Is this an assigned location? (That is, not `Unassigned`).
+ pub fn is_assigned(self) -> bool {
+ match self {
+ Self::Unassigned => false,
+ _ => true,
+ }
+ }
+
+ /// Get the register unit of this location, or panic.
+ pub fn unwrap_reg(self) -> RegUnit {
+ match self {
+ Self::Reg(ru) => ru,
+ _ => panic!("unwrap_reg expected register, found {:?}", self),
+ }
+ }
+
+ /// Get the stack slot of this location, or panic.
+ pub fn unwrap_stack(self) -> StackSlot {
+ match self {
+ Self::Stack(ss) => ss,
+ _ => panic!("unwrap_stack expected stack slot, found {:?}", self),
+ }
+ }
+
+ /// Return an object that can display this value location, using the register info from the
+ /// target ISA.
+ pub fn display<'a, R: Into<Option<&'a RegInfo>>>(self, regs: R) -> DisplayValueLoc<'a> {
+ DisplayValueLoc(self, regs.into())
+ }
+}
+
+/// Displaying a `ValueLoc` correctly requires the associated `RegInfo` from the target ISA.
+/// Without the register info, register units are simply show as numbers.
+///
+/// The `DisplayValueLoc` type can display the contained `ValueLoc`.
+pub struct DisplayValueLoc<'a>(ValueLoc, Option<&'a RegInfo>);
+
+impl<'a> fmt::Display for DisplayValueLoc<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self.0 {
+ ValueLoc::Unassigned => write!(f, "-"),
+ ValueLoc::Reg(ru) => match self.1 {
+ Some(regs) => write!(f, "{}", regs.display_regunit(ru)),
+ None => write!(f, "%{}", ru),
+ },
+ ValueLoc::Stack(ss) => write!(f, "{}", ss),
+ }
+ }
+}
+
+/// Function argument location.
+///
+/// The ABI specifies how arguments are passed to a function, and where return values appear after
+/// the call. Just like a `ValueLoc`, function arguments can be passed in registers or on the
+/// stack.
+///
+/// Function arguments on the stack are accessed differently for the incoming arguments to the
+/// current function and the outgoing arguments to a called external function. For this reason,
+/// the location of stack arguments is described as an offset into the array of function arguments
+/// on the stack.
+///
+/// An `ArgumentLoc` can be translated to a `ValueLoc` only when we know if we're talking about an
+/// incoming argument or an outgoing argument.
+///
+/// - For stack arguments, different `StackSlot` entities are used to represent incoming and
+/// outgoing arguments.
+/// - For register arguments, there is usually no difference, but if we ever add support for a
+/// register-window ISA like SPARC, register arguments would also need to be translated.
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
+#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
+pub enum ArgumentLoc {
+ /// This argument has not been assigned to a location yet.
+ Unassigned,
+ /// Argument is passed in a register.
+ Reg(RegUnit),
+ /// Argument is passed on the stack, at the given byte offset into the argument array.
+ Stack(i32),
+}
+
+impl Default for ArgumentLoc {
+ fn default() -> Self {
+ Self::Unassigned
+ }
+}
+
+impl ArgumentLoc {
+ /// Is this an assigned location? (That is, not `Unassigned`).
+ pub fn is_assigned(self) -> bool {
+ match self {
+ Self::Unassigned => false,
+ _ => true,
+ }
+ }
+
+ /// Is this a register location?
+ pub fn is_reg(self) -> bool {
+ match self {
+ Self::Reg(_) => true,
+ _ => false,
+ }
+ }
+
+ /// Is this a stack location?
+ pub fn is_stack(self) -> bool {
+ match self {
+ Self::Stack(_) => true,
+ _ => false,
+ }
+ }
+
+ /// Return an object that can display this argument location, using the register info from the
+ /// target ISA.
+ pub fn display<'a, R: Into<Option<&'a RegInfo>>>(self, regs: R) -> DisplayArgumentLoc<'a> {
+ DisplayArgumentLoc(self, regs.into())
+ }
+}
+
+/// Displaying a `ArgumentLoc` correctly requires the associated `RegInfo` from the target ISA.
+/// Without the register info, register units are simply show as numbers.
+///
+/// The `DisplayArgumentLoc` type can display the contained `ArgumentLoc`.
+pub struct DisplayArgumentLoc<'a>(ArgumentLoc, Option<&'a RegInfo>);
+
+impl<'a> fmt::Display for DisplayArgumentLoc<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self.0 {
+ ArgumentLoc::Unassigned => write!(f, "-"),
+ ArgumentLoc::Reg(ru) => match self.1 {
+ Some(regs) => write!(f, "{}", regs.display_regunit(ru)),
+ None => write!(f, "%{}", ru),
+ },
+ ArgumentLoc::Stack(offset) => write!(f, "{}", offset),
+ }
+ }
+}