1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
//! 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!("Expected register: {:?}", self),
        }
    }

    /// Get the stack slot of this location, or panic.
    pub fn unwrap_stack(self) -> StackSlot {
        match self {
            Self::Stack(ss) => ss,
            _ => panic!("Expected stack slot: {:?}", 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)]
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),
        }
    }
}