1 //! Pulley instruction arguments. 2 3 use super::*; 4 use crate::ir::ExternalName; 5 use crate::machinst::abi::StackAMode; 6 use pulley_interpreter::encode; 7 use pulley_interpreter::regs::Reg as _; 8 use std::fmt; 9 10 /// A macro for defining a newtype of `Reg` that enforces some invariant about 11 /// the wrapped `Reg` (such as that it is of a particular register class). 12 macro_rules! newtype_of_reg { 13 ( 14 $newtype_reg:ident, 15 $newtype_writable_reg:ident, 16 $class:expr 17 ) => { 18 /// A newtype wrapper around `Reg`. 19 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 20 pub struct $newtype_reg(Reg); 21 22 impl PartialEq<Reg> for $newtype_reg { 23 fn eq(&self, other: &Reg) -> bool { 24 self.0 == *other 25 } 26 } 27 28 impl From<$newtype_reg> for Reg { 29 fn from(r: $newtype_reg) -> Self { 30 r.0 31 } 32 } 33 34 impl TryFrom<Reg> for $newtype_reg { 35 type Error = (); 36 fn try_from(r: Reg) -> Result<Self, Self::Error> { 37 Self::new(r).ok_or(()) 38 } 39 } 40 41 impl $newtype_reg { 42 /// Create this newtype from the given register, or return `None` if the register 43 /// is not a valid instance of this newtype. 44 pub fn new(reg: Reg) -> Option<Self> { 45 if reg.class() == $class { 46 Some(Self(reg)) 47 } else { 48 None 49 } 50 } 51 52 /// Get this newtype's underlying `Reg`. 53 pub fn to_reg(self) -> Reg { 54 self.0 55 } 56 } 57 58 // Convenience impl so that people working with this newtype can use it 59 // "just like" a plain `Reg`. 60 // 61 // NB: We cannot implement `DerefMut` because that would let people do 62 // nasty stuff like `*my_xreg.deref_mut() = some_freg`, breaking the 63 // invariants that `XReg` provides. 64 impl std::ops::Deref for $newtype_reg { 65 type Target = Reg; 66 67 fn deref(&self) -> &Reg { 68 &self.0 69 } 70 } 71 72 /// If you know what you're doing, you can explicitly mutably borrow the 73 /// underlying `Reg`. Don't make it point to the wrong type of register 74 /// please. 75 impl AsMut<Reg> for $newtype_reg { 76 fn as_mut(&mut self) -> &mut Reg { 77 &mut self.0 78 } 79 } 80 81 /// Writable Reg. 82 pub type $newtype_writable_reg = Writable<$newtype_reg>; 83 84 impl From<pulley_interpreter::regs::$newtype_reg> for $newtype_reg { 85 fn from(r: pulley_interpreter::regs::$newtype_reg) -> Self { 86 Self::new(regalloc2::PReg::new(usize::from(r as u8), $class).into()).unwrap() 87 } 88 } 89 impl From<$newtype_reg> for pulley_interpreter::regs::$newtype_reg { 90 fn from(r: $newtype_reg) -> Self { 91 Self::new(r.to_real_reg().unwrap().hw_enc()).unwrap() 92 } 93 } 94 impl<'a> From<&'a $newtype_reg> for pulley_interpreter::regs::$newtype_reg { 95 fn from(r: &'a $newtype_reg) -> Self { 96 Self::new(r.to_real_reg().unwrap().hw_enc()).unwrap() 97 } 98 } 99 impl From<$newtype_writable_reg> for pulley_interpreter::regs::$newtype_reg { 100 fn from(r: $newtype_writable_reg) -> Self { 101 Self::new(r.to_reg().to_real_reg().unwrap().hw_enc()).unwrap() 102 } 103 } 104 impl<'a> From<&'a $newtype_writable_reg> for pulley_interpreter::regs::$newtype_reg { 105 fn from(r: &'a $newtype_writable_reg) -> Self { 106 Self::new(r.to_reg().to_real_reg().unwrap().hw_enc()).unwrap() 107 } 108 } 109 110 impl TryFrom<Writable<Reg>> for $newtype_writable_reg { 111 type Error = (); 112 fn try_from(r: Writable<Reg>) -> Result<Self, Self::Error> { 113 let r = r.to_reg(); 114 match $newtype_reg::new(r) { 115 Some(r) => Ok(Writable::from_reg(r)), 116 None => Err(()), 117 } 118 } 119 } 120 }; 121 } 122 123 // Newtypes for registers classes. 124 newtype_of_reg!(XReg, WritableXReg, RegClass::Int); 125 newtype_of_reg!(FReg, WritableFReg, RegClass::Float); 126 newtype_of_reg!(VReg, WritableVReg, RegClass::Vector); 127 128 impl XReg { 129 /// Index of the first "special" register, or the end of which registers 130 /// regalloc is allowed to use. 131 pub const SPECIAL_START: u8 = pulley_interpreter::regs::XReg::SPECIAL_START; 132 133 /// Returns whether this is a "special" physical register for pulley. 134 pub fn is_special(&self) -> bool { 135 match self.as_pulley() { 136 Some(reg) => reg.is_special(), 137 None => false, 138 } 139 } 140 141 /// Returns the pulley-typed register, if this is a physical register. 142 pub fn as_pulley(&self) -> Option<pulley_interpreter::XReg> { 143 let enc = self.to_real_reg()?.hw_enc(); 144 Some(pulley_interpreter::XReg::new(enc).unwrap()) 145 } 146 } 147 148 pub use super::super::lower::isle::generated_code::Amode; 149 150 impl Amode { 151 /// Add the registers referenced by this Amode to `collector`. 152 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) { 153 match self { 154 Amode::RegOffset { base, offset: _ } => collector.reg_use(base), 155 // Registers used in these modes aren't allocatable. 156 Amode::SpOffset { .. } | Amode::Stack { .. } => {} 157 } 158 } 159 160 pub(crate) fn get_base_register(&self) -> Option<XReg> { 161 match self { 162 Amode::RegOffset { base, offset: _ } => Some(*base), 163 Amode::SpOffset { .. } | Amode::Stack { .. } => Some(XReg::new(stack_reg()).unwrap()), 164 } 165 } 166 167 pub(crate) fn get_offset_with_state<P>(&self, state: &EmitState<P>) -> i32 168 where 169 P: PulleyTargetKind, 170 { 171 match self { 172 Amode::RegOffset { base: _, offset } | Amode::SpOffset { offset } => *offset, 173 Amode::Stack { amode } => { 174 let offset64 = match amode { 175 StackAMode::IncomingArg(offset, stack_args_size) => { 176 let offset = i64::from(*stack_args_size) - *offset; 177 let frame_layout = state.frame_layout(); 178 let sp_offset = frame_layout.tail_args_size 179 + frame_layout.setup_area_size 180 + frame_layout.clobber_size 181 + frame_layout.fixed_frame_storage_size 182 + frame_layout.outgoing_args_size; 183 i64::from(sp_offset) - offset 184 } 185 StackAMode::Slot(offset) => { 186 offset + i64::from(state.frame_layout().outgoing_args_size) 187 } 188 StackAMode::OutgoingArg(offset) => *offset, 189 }; 190 i32::try_from(offset64).unwrap() 191 } 192 } 193 } 194 } 195 196 impl core::fmt::Display for Amode { 197 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 198 match self { 199 Amode::SpOffset { offset } => { 200 if *offset >= 0 { 201 write!(f, "sp+{offset}") 202 } else { 203 write!(f, "sp{offset}") 204 } 205 } 206 Amode::RegOffset { base, offset } => { 207 let name = reg_name(**base); 208 if *offset >= 0 { 209 write!(f, "{name}+{offset}") 210 } else { 211 write!(f, "{name}{offset}") 212 } 213 } 214 Amode::Stack { amode } => core::fmt::Debug::fmt(amode, f), 215 } 216 } 217 } 218 219 impl From<StackAMode> for Amode { 220 fn from(amode: StackAMode) -> Self { 221 Amode::Stack { amode } 222 } 223 } 224 225 /// The size of an operand or operation. 226 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 227 pub enum OperandSize { 228 /// 32 bits. 229 Size32, 230 /// 64 bits. 231 Size64, 232 } 233 234 pub use crate::isa::pulley_shared::lower::isle::generated_code::Cond; 235 236 impl Cond { 237 /// Collect register operands within `collector` for register allocation. 238 pub fn get_operands(&mut self, collector: &mut impl OperandVisitor) { 239 match self { 240 Cond::If32 { reg } | Cond::IfNot32 { reg } => collector.reg_use(reg), 241 242 Cond::IfXeq32 { src1, src2 } 243 | Cond::IfXneq32 { src1, src2 } 244 | Cond::IfXslt32 { src1, src2 } 245 | Cond::IfXslteq32 { src1, src2 } 246 | Cond::IfXult32 { src1, src2 } 247 | Cond::IfXulteq32 { src1, src2 } 248 | Cond::IfXeq64 { src1, src2 } 249 | Cond::IfXneq64 { src1, src2 } 250 | Cond::IfXslt64 { src1, src2 } 251 | Cond::IfXslteq64 { src1, src2 } 252 | Cond::IfXult64 { src1, src2 } 253 | Cond::IfXulteq64 { src1, src2 } => { 254 collector.reg_use(src1); 255 collector.reg_use(src2); 256 } 257 258 Cond::IfXeq32I32 { src1, src2 } 259 | Cond::IfXneq32I32 { src1, src2 } 260 | Cond::IfXslt32I32 { src1, src2 } 261 | Cond::IfXslteq32I32 { src1, src2 } 262 | Cond::IfXsgt32I32 { src1, src2 } 263 | Cond::IfXsgteq32I32 { src1, src2 } 264 | Cond::IfXeq64I32 { src1, src2 } 265 | Cond::IfXneq64I32 { src1, src2 } 266 | Cond::IfXslt64I32 { src1, src2 } 267 | Cond::IfXslteq64I32 { src1, src2 } 268 | Cond::IfXsgt64I32 { src1, src2 } 269 | Cond::IfXsgteq64I32 { src1, src2 } => { 270 collector.reg_use(src1); 271 let _: &mut i32 = src2; 272 } 273 274 Cond::IfXult32I32 { src1, src2 } 275 | Cond::IfXulteq32I32 { src1, src2 } 276 | Cond::IfXugt32I32 { src1, src2 } 277 | Cond::IfXugteq32I32 { src1, src2 } 278 | Cond::IfXult64I32 { src1, src2 } 279 | Cond::IfXulteq64I32 { src1, src2 } 280 | Cond::IfXugt64I32 { src1, src2 } 281 | Cond::IfXugteq64I32 { src1, src2 } => { 282 collector.reg_use(src1); 283 let _: &mut u32 = src2; 284 } 285 } 286 } 287 288 /// Encode this condition as a branch into `sink`. 289 /// 290 /// Note that the offset encoded to jump by is filled in as 0 and it's 291 /// assumed `MachBuffer` will come back and clean it up. 292 pub fn encode(&self, sink: &mut impl Extend<u8>, rel: i32) { 293 match *self { 294 Cond::If32 { reg } => encode::br_if32(sink, reg, rel), 295 Cond::IfNot32 { reg } => encode::br_if_not32(sink, reg, rel), 296 Cond::IfXeq32 { src1, src2 } => encode::br_if_xeq32(sink, src1, src2, rel), 297 Cond::IfXneq32 { src1, src2 } => encode::br_if_xneq32(sink, src1, src2, rel), 298 Cond::IfXslt32 { src1, src2 } => encode::br_if_xslt32(sink, src1, src2, rel), 299 Cond::IfXslteq32 { src1, src2 } => encode::br_if_xslteq32(sink, src1, src2, rel), 300 Cond::IfXult32 { src1, src2 } => encode::br_if_xult32(sink, src1, src2, rel), 301 Cond::IfXulteq32 { src1, src2 } => encode::br_if_xulteq32(sink, src1, src2, rel), 302 Cond::IfXeq64 { src1, src2 } => encode::br_if_xeq64(sink, src1, src2, rel), 303 Cond::IfXneq64 { src1, src2 } => encode::br_if_xneq64(sink, src1, src2, rel), 304 Cond::IfXslt64 { src1, src2 } => encode::br_if_xslt64(sink, src1, src2, rel), 305 Cond::IfXslteq64 { src1, src2 } => encode::br_if_xslteq64(sink, src1, src2, rel), 306 Cond::IfXult64 { src1, src2 } => encode::br_if_xult64(sink, src1, src2, rel), 307 Cond::IfXulteq64 { src1, src2 } => encode::br_if_xulteq64(sink, src1, src2, rel), 308 309 Cond::IfXeq32I32 { src1, src2 } => match i8::try_from(src2) { 310 Ok(src2) => encode::br_if_xeq32_i8(sink, src1, src2, rel), 311 Err(_) => encode::br_if_xeq32_i32(sink, src1, src2, rel), 312 }, 313 Cond::IfXneq32I32 { src1, src2 } => match i8::try_from(src2) { 314 Ok(src2) => encode::br_if_xneq32_i8(sink, src1, src2, rel), 315 Err(_) => encode::br_if_xneq32_i32(sink, src1, src2, rel), 316 }, 317 Cond::IfXslt32I32 { src1, src2 } => match i8::try_from(src2) { 318 Ok(src2) => encode::br_if_xslt32_i8(sink, src1, src2, rel), 319 Err(_) => encode::br_if_xslt32_i32(sink, src1, src2, rel), 320 }, 321 Cond::IfXslteq32I32 { src1, src2 } => match i8::try_from(src2) { 322 Ok(src2) => encode::br_if_xslteq32_i8(sink, src1, src2, rel), 323 Err(_) => encode::br_if_xslteq32_i32(sink, src1, src2, rel), 324 }, 325 Cond::IfXsgt32I32 { src1, src2 } => match i8::try_from(src2) { 326 Ok(src2) => encode::br_if_xsgt32_i8(sink, src1, src2, rel), 327 Err(_) => encode::br_if_xsgt32_i32(sink, src1, src2, rel), 328 }, 329 Cond::IfXsgteq32I32 { src1, src2 } => match i8::try_from(src2) { 330 Ok(src2) => encode::br_if_xsgteq32_i8(sink, src1, src2, rel), 331 Err(_) => encode::br_if_xsgteq32_i32(sink, src1, src2, rel), 332 }, 333 Cond::IfXult32I32 { src1, src2 } => match u8::try_from(src2) { 334 Ok(src2) => encode::br_if_xult32_u8(sink, src1, src2, rel), 335 Err(_) => encode::br_if_xult32_u32(sink, src1, src2, rel), 336 }, 337 Cond::IfXulteq32I32 { src1, src2 } => match u8::try_from(src2) { 338 Ok(src2) => encode::br_if_xulteq32_u8(sink, src1, src2, rel), 339 Err(_) => encode::br_if_xulteq32_u32(sink, src1, src2, rel), 340 }, 341 Cond::IfXugt32I32 { src1, src2 } => match u8::try_from(src2) { 342 Ok(src2) => encode::br_if_xugt32_u8(sink, src1, src2, rel), 343 Err(_) => encode::br_if_xugt32_u32(sink, src1, src2, rel), 344 }, 345 Cond::IfXugteq32I32 { src1, src2 } => match u8::try_from(src2) { 346 Ok(src2) => encode::br_if_xugteq32_u8(sink, src1, src2, rel), 347 Err(_) => encode::br_if_xugteq32_u32(sink, src1, src2, rel), 348 }, 349 350 Cond::IfXeq64I32 { src1, src2 } => match i8::try_from(src2) { 351 Ok(src2) => encode::br_if_xeq64_i8(sink, src1, src2, rel), 352 Err(_) => encode::br_if_xeq64_i32(sink, src1, src2, rel), 353 }, 354 Cond::IfXneq64I32 { src1, src2 } => match i8::try_from(src2) { 355 Ok(src2) => encode::br_if_xneq64_i8(sink, src1, src2, rel), 356 Err(_) => encode::br_if_xneq64_i32(sink, src1, src2, rel), 357 }, 358 Cond::IfXslt64I32 { src1, src2 } => match i8::try_from(src2) { 359 Ok(src2) => encode::br_if_xslt64_i8(sink, src1, src2, rel), 360 Err(_) => encode::br_if_xslt64_i32(sink, src1, src2, rel), 361 }, 362 Cond::IfXslteq64I32 { src1, src2 } => match i8::try_from(src2) { 363 Ok(src2) => encode::br_if_xslteq64_i8(sink, src1, src2, rel), 364 Err(_) => encode::br_if_xslteq64_i32(sink, src1, src2, rel), 365 }, 366 Cond::IfXsgt64I32 { src1, src2 } => match i8::try_from(src2) { 367 Ok(src2) => encode::br_if_xsgt64_i8(sink, src1, src2, rel), 368 Err(_) => encode::br_if_xsgt64_i32(sink, src1, src2, rel), 369 }, 370 Cond::IfXsgteq64I32 { src1, src2 } => match i8::try_from(src2) { 371 Ok(src2) => encode::br_if_xsgteq64_i8(sink, src1, src2, rel), 372 Err(_) => encode::br_if_xsgteq64_i32(sink, src1, src2, rel), 373 }, 374 Cond::IfXult64I32 { src1, src2 } => match u8::try_from(src2) { 375 Ok(src2) => encode::br_if_xult64_u8(sink, src1, src2, rel), 376 Err(_) => encode::br_if_xult64_u32(sink, src1, src2, rel), 377 }, 378 Cond::IfXulteq64I32 { src1, src2 } => match u8::try_from(src2) { 379 Ok(src2) => encode::br_if_xulteq64_u8(sink, src1, src2, rel), 380 Err(_) => encode::br_if_xulteq64_u32(sink, src1, src2, rel), 381 }, 382 Cond::IfXugt64I32 { src1, src2 } => match u8::try_from(src2) { 383 Ok(src2) => encode::br_if_xugt64_u8(sink, src1, src2, rel), 384 Err(_) => encode::br_if_xugt64_u32(sink, src1, src2, rel), 385 }, 386 Cond::IfXugteq64I32 { src1, src2 } => match u8::try_from(src2) { 387 Ok(src2) => encode::br_if_xugteq64_u8(sink, src1, src2, rel), 388 Err(_) => encode::br_if_xugteq64_u32(sink, src1, src2, rel), 389 }, 390 } 391 } 392 393 /// Inverts this conditional. 394 pub fn invert(&self) -> Cond { 395 match *self { 396 Cond::If32 { reg } => Cond::IfNot32 { reg }, 397 Cond::IfNot32 { reg } => Cond::If32 { reg }, 398 Cond::IfXeq32 { src1, src2 } => Cond::IfXneq32 { src1, src2 }, 399 Cond::IfXneq32 { src1, src2 } => Cond::IfXeq32 { src1, src2 }, 400 Cond::IfXeq64 { src1, src2 } => Cond::IfXneq64 { src1, src2 }, 401 Cond::IfXneq64 { src1, src2 } => Cond::IfXeq64 { src1, src2 }, 402 403 // Note that for below the condition changes but the operands are 404 // also swapped. 405 Cond::IfXslt32 { src1, src2 } => Cond::IfXslteq32 { 406 src1: src2, 407 src2: src1, 408 }, 409 Cond::IfXslteq32 { src1, src2 } => Cond::IfXslt32 { 410 src1: src2, 411 src2: src1, 412 }, 413 Cond::IfXult32 { src1, src2 } => Cond::IfXulteq32 { 414 src1: src2, 415 src2: src1, 416 }, 417 Cond::IfXulteq32 { src1, src2 } => Cond::IfXult32 { 418 src1: src2, 419 src2: src1, 420 }, 421 Cond::IfXslt64 { src1, src2 } => Cond::IfXslteq64 { 422 src1: src2, 423 src2: src1, 424 }, 425 Cond::IfXslteq64 { src1, src2 } => Cond::IfXslt64 { 426 src1: src2, 427 src2: src1, 428 }, 429 Cond::IfXult64 { src1, src2 } => Cond::IfXulteq64 { 430 src1: src2, 431 src2: src1, 432 }, 433 Cond::IfXulteq64 { src1, src2 } => Cond::IfXult64 { 434 src1: src2, 435 src2: src1, 436 }, 437 438 Cond::IfXeq32I32 { src1, src2 } => Cond::IfXneq32I32 { src1, src2 }, 439 Cond::IfXneq32I32 { src1, src2 } => Cond::IfXeq32I32 { src1, src2 }, 440 Cond::IfXslt32I32 { src1, src2 } => Cond::IfXsgteq32I32 { src1, src2 }, 441 Cond::IfXslteq32I32 { src1, src2 } => Cond::IfXsgt32I32 { src1, src2 }, 442 Cond::IfXult32I32 { src1, src2 } => Cond::IfXugteq32I32 { src1, src2 }, 443 Cond::IfXulteq32I32 { src1, src2 } => Cond::IfXugt32I32 { src1, src2 }, 444 Cond::IfXsgt32I32 { src1, src2 } => Cond::IfXslteq32I32 { src1, src2 }, 445 Cond::IfXsgteq32I32 { src1, src2 } => Cond::IfXslt32I32 { src1, src2 }, 446 Cond::IfXugt32I32 { src1, src2 } => Cond::IfXulteq32I32 { src1, src2 }, 447 Cond::IfXugteq32I32 { src1, src2 } => Cond::IfXult32I32 { src1, src2 }, 448 449 Cond::IfXeq64I32 { src1, src2 } => Cond::IfXneq64I32 { src1, src2 }, 450 Cond::IfXneq64I32 { src1, src2 } => Cond::IfXeq64I32 { src1, src2 }, 451 Cond::IfXslt64I32 { src1, src2 } => Cond::IfXsgteq64I32 { src1, src2 }, 452 Cond::IfXslteq64I32 { src1, src2 } => Cond::IfXsgt64I32 { src1, src2 }, 453 Cond::IfXult64I32 { src1, src2 } => Cond::IfXugteq64I32 { src1, src2 }, 454 Cond::IfXulteq64I32 { src1, src2 } => Cond::IfXugt64I32 { src1, src2 }, 455 Cond::IfXsgt64I32 { src1, src2 } => Cond::IfXslteq64I32 { src1, src2 }, 456 Cond::IfXsgteq64I32 { src1, src2 } => Cond::IfXslt64I32 { src1, src2 }, 457 Cond::IfXugt64I32 { src1, src2 } => Cond::IfXulteq64I32 { src1, src2 }, 458 Cond::IfXugteq64I32 { src1, src2 } => Cond::IfXult64I32 { src1, src2 }, 459 } 460 } 461 } 462 463 impl fmt::Display for Cond { 464 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 465 match self { 466 Cond::If32 { reg } => write!(f, "if32 {}", reg_name(**reg)), 467 Cond::IfNot32 { reg } => write!(f, "if_not32 {}", reg_name(**reg)), 468 Cond::IfXeq32 { src1, src2 } => { 469 write!(f, "if_xeq32 {}, {}", reg_name(**src1), reg_name(**src2)) 470 } 471 Cond::IfXneq32 { src1, src2 } => { 472 write!(f, "if_xneq32 {}, {}", reg_name(**src1), reg_name(**src2)) 473 } 474 Cond::IfXslt32 { src1, src2 } => { 475 write!(f, "if_xslt32 {}, {}", reg_name(**src1), reg_name(**src2)) 476 } 477 Cond::IfXslteq32 { src1, src2 } => { 478 write!(f, "if_xslteq32 {}, {}", reg_name(**src1), reg_name(**src2)) 479 } 480 Cond::IfXult32 { src1, src2 } => { 481 write!(f, "if_xult32 {}, {}", reg_name(**src1), reg_name(**src2)) 482 } 483 Cond::IfXulteq32 { src1, src2 } => { 484 write!(f, "if_xulteq32 {}, {}", reg_name(**src1), reg_name(**src2)) 485 } 486 Cond::IfXeq64 { src1, src2 } => { 487 write!(f, "if_xeq64 {}, {}", reg_name(**src1), reg_name(**src2)) 488 } 489 Cond::IfXneq64 { src1, src2 } => { 490 write!(f, "if_xneq64 {}, {}", reg_name(**src1), reg_name(**src2)) 491 } 492 Cond::IfXslt64 { src1, src2 } => { 493 write!(f, "if_xslt64 {}, {}", reg_name(**src1), reg_name(**src2)) 494 } 495 Cond::IfXslteq64 { src1, src2 } => { 496 write!(f, "if_xslteq64 {}, {}", reg_name(**src1), reg_name(**src2)) 497 } 498 Cond::IfXult64 { src1, src2 } => { 499 write!(f, "if_xult64 {}, {}", reg_name(**src1), reg_name(**src2)) 500 } 501 Cond::IfXulteq64 { src1, src2 } => { 502 write!(f, "if_xulteq64 {}, {}", reg_name(**src1), reg_name(**src2)) 503 } 504 Cond::IfXeq32I32 { src1, src2 } => { 505 write!(f, "if_xeq32_i32 {}, {src2}", reg_name(**src1)) 506 } 507 Cond::IfXneq32I32 { src1, src2 } => { 508 write!(f, "if_xneq32_i32 {}, {src2}", reg_name(**src1)) 509 } 510 Cond::IfXslt32I32 { src1, src2 } => { 511 write!(f, "if_xslt32_i32 {}, {src2}", reg_name(**src1)) 512 } 513 Cond::IfXslteq32I32 { src1, src2 } => { 514 write!(f, "if_xslteq32_i32 {}, {src2}", reg_name(**src1)) 515 } 516 Cond::IfXsgt32I32 { src1, src2 } => { 517 write!(f, "if_xsgt32_i32 {}, {src2}", reg_name(**src1)) 518 } 519 Cond::IfXsgteq32I32 { src1, src2 } => { 520 write!(f, "if_xsgteq32_i32 {}, {src2}", reg_name(**src1)) 521 } 522 Cond::IfXult32I32 { src1, src2 } => { 523 write!(f, "if_xult32_i32 {}, {src2}", reg_name(**src1)) 524 } 525 Cond::IfXulteq32I32 { src1, src2 } => { 526 write!(f, "if_xulteq32_i32 {}, {src2}", reg_name(**src1)) 527 } 528 Cond::IfXugt32I32 { src1, src2 } => { 529 write!(f, "if_xugt32_i32 {}, {src2}", reg_name(**src1)) 530 } 531 Cond::IfXugteq32I32 { src1, src2 } => { 532 write!(f, "if_xugteq32_i32 {}, {src2}", reg_name(**src1)) 533 } 534 Cond::IfXeq64I32 { src1, src2 } => { 535 write!(f, "if_xeq64_i32 {}, {src2}", reg_name(**src1)) 536 } 537 Cond::IfXneq64I32 { src1, src2 } => { 538 write!(f, "if_xneq64_i32 {}, {src2}", reg_name(**src1)) 539 } 540 Cond::IfXslt64I32 { src1, src2 } => { 541 write!(f, "if_xslt64_i32 {}, {src2}", reg_name(**src1)) 542 } 543 Cond::IfXslteq64I32 { src1, src2 } => { 544 write!(f, "if_xslteq64_i32 {}, {src2}", reg_name(**src1)) 545 } 546 Cond::IfXsgt64I32 { src1, src2 } => { 547 write!(f, "if_xsgt64_i32 {}, {src2}", reg_name(**src1)) 548 } 549 Cond::IfXsgteq64I32 { src1, src2 } => { 550 write!(f, "if_xsgteq64_i32 {}, {src2}", reg_name(**src1)) 551 } 552 Cond::IfXult64I32 { src1, src2 } => { 553 write!(f, "if_xult64_i32 {}, {src2}", reg_name(**src1)) 554 } 555 Cond::IfXulteq64I32 { src1, src2 } => { 556 write!(f, "if_xulteq64_i32 {}, {src2}", reg_name(**src1)) 557 } 558 Cond::IfXugt64I32 { src1, src2 } => { 559 write!(f, "if_xugt64_i32 {}, {src2}", reg_name(**src1)) 560 } 561 Cond::IfXugteq64I32 { src1, src2 } => { 562 write!(f, "if_xugteq64_i32 {}, {src2}", reg_name(**src1)) 563 } 564 } 565 } 566 } 567 568 /// Payload of `CallInfo` for call instructions 569 #[derive(Clone, Debug)] 570 pub struct PulleyCall { 571 /// The external name that's being called, or the Cranelift-generated 572 /// function that's being invoked. 573 pub name: ExternalName, 574 /// Arguments tracked in this call invocation which aren't assigned fixed 575 /// registers. This tracks up to 4 registers and all remaining registers 576 /// will be present and tracked in `CallInfo<T>` fields. 577 pub args: SmallVec<[XReg; 4]>, 578 } 579 580 pub use super::super::lower::isle::generated_code::AddrO32; 581 582 impl Copy for AddrO32 {} 583 584 impl AddrO32 { 585 /// Implementation of regalloc for this addressing mode. 586 pub fn collect_operands(&mut self, collector: &mut impl OperandVisitor) { 587 match self { 588 AddrO32::Base { addr, offset: _ } => { 589 collector.reg_use(addr); 590 } 591 } 592 } 593 } 594 595 impl From<AddrO32> for pulley_interpreter::AddrO32 { 596 fn from(addr: AddrO32) -> Self { 597 match addr { 598 AddrO32::Base { addr, offset } => Self { 599 addr: addr.into(), 600 offset, 601 }, 602 } 603 } 604 } 605 606 impl fmt::Display for AddrO32 { 607 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 608 match self { 609 AddrO32::Base { addr, offset } => { 610 let addr = reg_name(**addr); 611 write!(f, "{addr}, {offset}") 612 } 613 } 614 } 615 } 616 617 pub use super::super::lower::isle::generated_code::AddrZ; 618 619 impl Copy for AddrZ {} 620 621 impl AddrZ { 622 /// Implementation of regalloc for this addressing mode. 623 pub fn collect_operands(&mut self, collector: &mut impl OperandVisitor) { 624 match self { 625 AddrZ::Base { addr, offset: _ } => { 626 collector.reg_use(addr); 627 } 628 } 629 } 630 } 631 632 impl From<AddrZ> for pulley_interpreter::AddrZ { 633 fn from(addr: AddrZ) -> Self { 634 match addr { 635 AddrZ::Base { addr, offset } => Self { 636 addr: addr.into(), 637 offset, 638 }, 639 } 640 } 641 } 642 643 impl fmt::Display for AddrZ { 644 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 645 match self { 646 AddrZ::Base { addr, offset } => { 647 let addr = reg_name(**addr); 648 write!(f, "{addr}, {offset}") 649 } 650 } 651 } 652 } 653 654 pub use super::super::lower::isle::generated_code::AddrG32; 655 656 impl Copy for AddrG32 {} 657 658 impl AddrG32 { 659 /// Implementation of regalloc for this addressing mode. 660 pub fn collect_operands(&mut self, collector: &mut impl OperandVisitor) { 661 match self { 662 AddrG32::RegisterBound { 663 host_heap_base, 664 host_heap_bound, 665 wasm_addr, 666 offset: _, 667 } => { 668 collector.reg_use(host_heap_base); 669 collector.reg_use(host_heap_bound); 670 collector.reg_use(wasm_addr); 671 } 672 } 673 } 674 } 675 676 impl From<AddrG32> for pulley_interpreter::AddrG32 { 677 fn from(addr: AddrG32) -> Self { 678 match addr { 679 AddrG32::RegisterBound { 680 host_heap_base, 681 host_heap_bound, 682 wasm_addr, 683 offset, 684 } => Self { 685 host_heap_base: host_heap_base.into(), 686 host_heap_bound: host_heap_bound.into(), 687 wasm_addr: wasm_addr.into(), 688 offset, 689 }, 690 } 691 } 692 } 693 694 impl fmt::Display for AddrG32 { 695 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 696 match self { 697 AddrG32::RegisterBound { 698 host_heap_base, 699 host_heap_bound, 700 wasm_addr, 701 offset, 702 } => { 703 let host_heap_base = reg_name(**host_heap_base); 704 let host_heap_bound = reg_name(**host_heap_bound); 705 let wasm_addr = reg_name(**wasm_addr); 706 write!( 707 f, 708 "{host_heap_base}, {host_heap_bound}, {wasm_addr}, {offset}", 709 ) 710 } 711 } 712 } 713 } 714 715 pub use super::super::lower::isle::generated_code::AddrG32Bne; 716 717 impl Copy for AddrG32Bne {} 718 719 impl AddrG32Bne { 720 /// Implementation of regalloc for this addressing mode. 721 pub fn collect_operands(&mut self, collector: &mut impl OperandVisitor) { 722 match self { 723 AddrG32Bne::BoundNe { 724 host_heap_base, 725 host_heap_bound_addr, 726 host_heap_bound_offset: _, 727 wasm_addr, 728 offset: _, 729 } => { 730 collector.reg_use(host_heap_base); 731 collector.reg_use(host_heap_bound_addr); 732 collector.reg_use(wasm_addr); 733 } 734 } 735 } 736 } 737 738 impl From<AddrG32Bne> for pulley_interpreter::AddrG32Bne { 739 fn from(addr: AddrG32Bne) -> Self { 740 match addr { 741 AddrG32Bne::BoundNe { 742 host_heap_base, 743 host_heap_bound_addr, 744 host_heap_bound_offset, 745 wasm_addr, 746 offset, 747 } => Self { 748 host_heap_base: host_heap_base.into(), 749 host_heap_bound_addr: host_heap_bound_addr.into(), 750 host_heap_bound_offset, 751 wasm_addr: wasm_addr.into(), 752 offset, 753 }, 754 } 755 } 756 } 757 758 impl fmt::Display for AddrG32Bne { 759 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 760 match self { 761 AddrG32Bne::BoundNe { 762 host_heap_base, 763 host_heap_bound_addr, 764 host_heap_bound_offset, 765 wasm_addr, 766 offset, 767 } => { 768 let host_heap_base = reg_name(**host_heap_base); 769 let host_heap_bound_addr = reg_name(**host_heap_bound_addr); 770 let wasm_addr = reg_name(**wasm_addr); 771 write!( 772 f, 773 "{host_heap_base}, \ 774 *[{host_heap_bound_addr} + {host_heap_bound_offset}], \ 775 {wasm_addr}, \ 776 {offset}", 777 ) 778 } 779 } 780 } 781 } 782