cranelift_codegen/isa/s390x/inst/
args.rs

1//! S390x ISA definitions: instruction arguments.
2
3use crate::ir::condcodes::{FloatCC, IntCC};
4use crate::ir::MemFlags;
5use crate::isa::s390x::inst::*;
6
7//=============================================================================
8// Instruction sub-components (memory addresses): definitions
9
10/// A memory argument to load/store, encapsulating the possible addressing modes.
11#[derive(Clone, Debug)]
12pub enum MemArg {
13    //
14    // Real IBM Z addressing modes:
15    //
16    /// Base register, index register, and 12-bit unsigned displacement.
17    BXD12 {
18        base: Reg,
19        index: Reg,
20        disp: UImm12,
21        flags: MemFlags,
22    },
23
24    /// Base register, index register, and 20-bit signed displacement.
25    BXD20 {
26        base: Reg,
27        index: Reg,
28        disp: SImm20,
29        flags: MemFlags,
30    },
31
32    /// PC-relative Reference to a label.
33    Label { target: MachLabel },
34
35    /// PC-relative Reference to a near symbol.
36    Symbol {
37        name: Box<ExternalName>,
38        offset: i32,
39        flags: MemFlags,
40    },
41
42    //
43    // Virtual addressing modes that are lowered at emission time:
44    //
45    /// Arbitrary offset from a register. Converted to generation of large
46    /// offsets with multiple instructions as necessary during code emission.
47    RegOffset { reg: Reg, off: i64, flags: MemFlags },
48
49    /// Offset from the stack pointer at function entry.
50    InitialSPOffset { off: i64 },
51
52    /// Offset from the (nominal) stack pointer during this function.
53    NominalSPOffset { off: i64 },
54
55    /// Offset into the slot area of the stack, which lies just above the
56    /// outgoing argument area that's setup by the function prologue.
57    /// At emission time, this is converted to `SPOffset` with a fixup added to
58    /// the offset constant. The fixup is a running value that is tracked as
59    /// emission iterates through instructions in linear order, and can be
60    /// adjusted up and down with [Inst::VirtualSPOffsetAdj].
61    ///
62    /// The standard ABI is in charge of handling this (by emitting the
63    /// adjustment meta-instructions). See the diagram in the documentation
64    /// for [crate::isa::aarch64::abi](the ABI module) for more details.
65    SlotOffset { off: i64 },
66}
67
68impl MemArg {
69    /// Memory reference using an address in a register.
70    pub fn reg(reg: Reg, flags: MemFlags) -> MemArg {
71        MemArg::BXD12 {
72            base: reg,
73            index: zero_reg(),
74            disp: UImm12::zero(),
75            flags,
76        }
77    }
78
79    /// Memory reference using the sum of two registers as an address.
80    pub fn reg_plus_reg(reg1: Reg, reg2: Reg, flags: MemFlags) -> MemArg {
81        MemArg::BXD12 {
82            base: reg1,
83            index: reg2,
84            disp: UImm12::zero(),
85            flags,
86        }
87    }
88
89    /// Memory reference using the sum of a register an an offset as address.
90    pub fn reg_plus_off(reg: Reg, off: i64, flags: MemFlags) -> MemArg {
91        MemArg::RegOffset { reg, off, flags }
92    }
93
94    /// Add an offset to a virtual addressing mode.
95    pub fn offset(base: &MemArg, offset: i64) -> MemArg {
96        match base {
97            &MemArg::RegOffset { reg, off, flags } => MemArg::RegOffset {
98                reg,
99                off: off + offset,
100                flags,
101            },
102            &MemArg::InitialSPOffset { off } => MemArg::InitialSPOffset { off: off + offset },
103            &MemArg::NominalSPOffset { off } => MemArg::NominalSPOffset { off: off + offset },
104            &MemArg::SlotOffset { off } => MemArg::SlotOffset { off: off + offset },
105            // This routine is only defined for virtual addressing modes.
106            &MemArg::BXD12 { .. }
107            | &MemArg::BXD20 { .. }
108            | &MemArg::Label { .. }
109            | &MemArg::Symbol { .. } => unreachable!(),
110        }
111    }
112
113    pub(crate) fn get_flags(&self) -> MemFlags {
114        match self {
115            MemArg::BXD12 { flags, .. } => *flags,
116            MemArg::BXD20 { flags, .. } => *flags,
117            MemArg::RegOffset { flags, .. } => *flags,
118            MemArg::Label { .. } => MemFlags::trusted(),
119            MemArg::Symbol { flags, .. } => *flags,
120            MemArg::InitialSPOffset { .. } => MemFlags::trusted(),
121            MemArg::NominalSPOffset { .. } => MemFlags::trusted(),
122            MemArg::SlotOffset { .. } => MemFlags::trusted(),
123        }
124    }
125}
126
127//=============================================================================
128// Instruction sub-components (conditions, branches and branch targets):
129// definitions
130
131/// Condition for conditional branches.
132#[derive(Clone, Copy, Debug, PartialEq, Eq)]
133pub struct Cond {
134    mask: u8,
135}
136
137impl Cond {
138    pub fn from_mask(mask: u8) -> Cond {
139        assert!(mask >= 1 && mask <= 14);
140        Cond { mask }
141    }
142
143    pub fn from_intcc(cc: IntCC) -> Cond {
144        let mask = match cc {
145            IntCC::Equal => 8,
146            IntCC::NotEqual => 4 | 2,
147            IntCC::SignedGreaterThanOrEqual => 8 | 2,
148            IntCC::SignedGreaterThan => 2,
149            IntCC::SignedLessThanOrEqual => 8 | 4,
150            IntCC::SignedLessThan => 4,
151            IntCC::UnsignedGreaterThanOrEqual => 8 | 2,
152            IntCC::UnsignedGreaterThan => 2,
153            IntCC::UnsignedLessThanOrEqual => 8 | 4,
154            IntCC::UnsignedLessThan => 4,
155        };
156        Cond { mask }
157    }
158
159    pub fn from_floatcc(cc: FloatCC) -> Cond {
160        let mask = match cc {
161            FloatCC::Ordered => 8 | 4 | 2,
162            FloatCC::Unordered => 1,
163            FloatCC::Equal => 8,
164            FloatCC::NotEqual => 4 | 2 | 1,
165            FloatCC::OrderedNotEqual => 4 | 2,
166            FloatCC::UnorderedOrEqual => 8 | 1,
167            FloatCC::LessThan => 4,
168            FloatCC::LessThanOrEqual => 8 | 4,
169            FloatCC::GreaterThan => 2,
170            FloatCC::GreaterThanOrEqual => 8 | 2,
171            FloatCC::UnorderedOrLessThan => 4 | 1,
172            FloatCC::UnorderedOrLessThanOrEqual => 8 | 4 | 1,
173            FloatCC::UnorderedOrGreaterThan => 2 | 1,
174            FloatCC::UnorderedOrGreaterThanOrEqual => 8 | 2 | 1,
175        };
176        Cond { mask }
177    }
178
179    /// Return the inverted condition.
180    pub fn invert(self) -> Cond {
181        Cond {
182            mask: !self.mask & 15,
183        }
184    }
185
186    /// Return the machine encoding of this condition.
187    pub fn bits(self) -> u8 {
188        self.mask
189    }
190}
191
192impl PrettyPrint for MemArg {
193    fn pretty_print(&self, _: u8) -> String {
194        match self {
195            &MemArg::BXD12 {
196                base, index, disp, ..
197            } => {
198                if base != zero_reg() {
199                    if index != zero_reg() {
200                        format!(
201                            "{}({},{})",
202                            disp.pretty_print_default(),
203                            show_reg(index),
204                            show_reg(base),
205                        )
206                    } else {
207                        format!("{}({})", disp.pretty_print_default(), show_reg(base))
208                    }
209                } else {
210                    if index != zero_reg() {
211                        format!("{}({},)", disp.pretty_print_default(), show_reg(index))
212                    } else {
213                        format!("{}", disp.pretty_print_default())
214                    }
215                }
216            }
217            &MemArg::BXD20 {
218                base, index, disp, ..
219            } => {
220                if base != zero_reg() {
221                    if index != zero_reg() {
222                        format!(
223                            "{}({},{})",
224                            disp.pretty_print_default(),
225                            show_reg(index),
226                            show_reg(base),
227                        )
228                    } else {
229                        format!("{}({})", disp.pretty_print_default(), show_reg(base))
230                    }
231                } else {
232                    if index != zero_reg() {
233                        format!("{}({},)", disp.pretty_print_default(), show_reg(index))
234                    } else {
235                        format!("{}", disp.pretty_print_default())
236                    }
237                }
238            }
239            &MemArg::Label { target } => target.to_string(),
240            &MemArg::Symbol {
241                ref name, offset, ..
242            } => format!("{} + {}", name.display(None), offset),
243            // Eliminated by `mem_finalize()`.
244            &MemArg::InitialSPOffset { .. }
245            | &MemArg::NominalSPOffset { .. }
246            | &MemArg::SlotOffset { .. }
247            | &MemArg::RegOffset { .. } => {
248                panic!("Unexpected pseudo mem-arg mode (stack-offset or generic reg-offset)!")
249            }
250        }
251    }
252}
253
254impl PrettyPrint for Cond {
255    fn pretty_print(&self, _: u8) -> String {
256        let s = match self.mask {
257            1 => "o",
258            2 => "h",
259            3 => "nle",
260            4 => "l",
261            5 => "nhe",
262            6 => "lh",
263            7 => "ne",
264            8 => "e",
265            9 => "nlh",
266            10 => "he",
267            11 => "nl",
268            12 => "le",
269            13 => "nh",
270            14 => "no",
271            _ => unreachable!(),
272        };
273        s.to_string()
274    }
275}