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