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