1 use crate::abi::{self, align_to, scratch, LocalSlot}; 2 use crate::codegen::{CodeGenContext, Emission, FuncEnv}; 3 use crate::isa::{ 4 reg::{writable, Reg, WritableReg}, 5 CallingConvention, 6 }; 7 use anyhow::Result; 8 use cranelift_codegen::{ 9 binemit::CodeOffset, 10 ir::{Endianness, LibCall, MemFlags, RelSourceLoc, SourceLoc, UserExternalNameRef}, 11 Final, MachBufferFinalized, MachLabel, 12 }; 13 use std::{fmt::Debug, ops::Range}; 14 use wasmtime_environ::PtrSize; 15 16 pub(crate) use cranelift_codegen::ir::TrapCode; 17 18 #[derive(Eq, PartialEq)] 19 pub(crate) enum DivKind { 20 /// Signed division. 21 Signed, 22 /// Unsigned division. 23 Unsigned, 24 } 25 26 /// Remainder kind. 27 #[derive(Copy, Clone)] 28 pub(crate) enum RemKind { 29 /// Signed remainder. 30 Signed, 31 /// Unsigned remainder. 32 Unsigned, 33 } 34 35 impl RemKind { 36 pub fn is_signed(&self) -> bool { 37 matches!(self, Self::Signed) 38 } 39 } 40 41 #[derive(Copy, Clone, PartialEq, Eq)] 42 pub(crate) enum MemOpKind { 43 /// An atomic memory operation with SeqCst memory ordering. 44 Atomic, 45 /// A memory operation with no memory ordering constraint. 46 Normal, 47 } 48 49 #[derive(Eq, PartialEq)] 50 pub(crate) enum MulWideKind { 51 Signed, 52 Unsigned, 53 } 54 55 /// Type of operation for a read-modify-write instruction. 56 pub(crate) enum RmwOp { 57 Add, 58 Sub, 59 Xchg, 60 And, 61 Or, 62 Xor, 63 } 64 65 /// The direction to perform the memory move. 66 #[derive(Debug, Clone, Eq, PartialEq)] 67 pub(crate) enum MemMoveDirection { 68 /// From high memory addresses to low memory addresses. 69 /// Invariant: the source location is closer to the FP than the destination 70 /// location, which will be closer to the SP. 71 HighToLow, 72 /// From low memory addresses to high memory addresses. 73 /// Invariant: the source location is closer to the SP than the destination 74 /// location, which will be closer to the FP. 75 LowToHigh, 76 } 77 78 /// Classifies how to treat float-to-int conversions. 79 #[derive(Debug, Copy, Clone, Eq, PartialEq)] 80 pub(crate) enum TruncKind { 81 /// Saturating conversion. If the source value is greater than the maximum 82 /// value of the destination type, the result is clamped to the 83 /// destination maximum value. 84 Checked, 85 /// An exception is raised if the source value is greater than the maximum 86 /// value of the destination type. 87 Unchecked, 88 } 89 90 impl TruncKind { 91 /// Returns true if the truncation kind is checked. 92 pub(crate) fn is_checked(&self) -> bool { 93 *self == TruncKind::Checked 94 } 95 96 /// Returns `true` if the trunc kind is [`Unchecked`]. 97 /// 98 /// [`Unchecked`]: TruncKind::Unchecked 99 #[must_use] 100 pub(crate) fn is_unchecked(&self) -> bool { 101 matches!(self, Self::Unchecked) 102 } 103 } 104 105 /// Representation of the stack pointer offset. 106 #[derive(Copy, Clone, Eq, PartialEq, Debug, PartialOrd, Ord, Default)] 107 pub struct SPOffset(u32); 108 109 impl SPOffset { 110 pub fn from_u32(offs: u32) -> Self { 111 Self(offs) 112 } 113 114 pub fn as_u32(&self) -> u32 { 115 self.0 116 } 117 } 118 119 /// A stack slot. 120 #[derive(Debug, Clone, Copy, Eq, PartialEq)] 121 pub struct StackSlot { 122 /// The location of the slot, relative to the stack pointer. 123 pub offset: SPOffset, 124 /// The size of the slot, in bytes. 125 pub size: u32, 126 } 127 128 impl StackSlot { 129 pub fn new(offs: SPOffset, size: u32) -> Self { 130 Self { offset: offs, size } 131 } 132 } 133 134 /// Kinds of integer binary comparison in WebAssembly. The [`MacroAssembler`] 135 /// implementation for each ISA is responsible for emitting the correct 136 /// sequence of instructions when lowering to machine code. 137 #[derive(Debug, Clone, Copy, Eq, PartialEq)] 138 pub(crate) enum IntCmpKind { 139 /// Equal. 140 Eq, 141 /// Not equal. 142 Ne, 143 /// Signed less than. 144 LtS, 145 /// Unsigned less than. 146 LtU, 147 /// Signed greater than. 148 GtS, 149 /// Unsigned greater than. 150 GtU, 151 /// Signed less than or equal. 152 LeS, 153 /// Unsigned less than or equal. 154 LeU, 155 /// Signed greater than or equal. 156 GeS, 157 /// Unsigned greater than or equal. 158 GeU, 159 } 160 161 /// Kinds of float binary comparison in WebAssembly. The [`MacroAssembler`] 162 /// implementation for each ISA is responsible for emitting the correct 163 /// sequence of instructions when lowering code. 164 #[derive(Debug)] 165 pub(crate) enum FloatCmpKind { 166 /// Equal. 167 Eq, 168 /// Not equal. 169 Ne, 170 /// Less than. 171 Lt, 172 /// Greater than. 173 Gt, 174 /// Less than or equal. 175 Le, 176 /// Greater than or equal. 177 Ge, 178 } 179 180 /// Kinds of shifts in WebAssembly.The [`masm`] implementation for each ISA is 181 /// responsible for emitting the correct sequence of instructions when 182 /// lowering to machine code. 183 #[derive(Debug, Clone, Copy, Eq, PartialEq)] 184 pub(crate) enum ShiftKind { 185 /// Left shift. 186 Shl, 187 /// Signed right shift. 188 ShrS, 189 /// Unsigned right shift. 190 ShrU, 191 /// Left rotate. 192 Rotl, 193 /// Right rotate. 194 Rotr, 195 } 196 197 /// Kinds of extends in WebAssembly. Each MacroAssembler implementation 198 /// is responsible for emitting the correct sequence of instructions when 199 /// lowering to machine code. 200 #[derive(Copy, Clone)] 201 pub(crate) enum ExtendKind { 202 Signed(Extend<Signed>), 203 Unsigned(Extend<Zero>), 204 } 205 206 #[derive(Copy, Clone)] 207 pub(crate) enum Signed {} 208 #[derive(Copy, Clone)] 209 pub(crate) enum Zero {} 210 211 pub(crate) trait ExtendType {} 212 213 impl ExtendType for Signed {} 214 impl ExtendType for Zero {} 215 216 #[derive(Copy, Clone)] 217 pub(crate) enum Extend<T: ExtendType> { 218 /// 8 to 32 bit extend. 219 I32Extend8, 220 /// 16 to 32 bit extend. 221 I32Extend16, 222 /// 8 to 64 bit extend. 223 I64Extend8, 224 /// 16 to 64 bit extend. 225 I64Extend16, 226 /// 32 to 64 bit extend. 227 I64Extend32, 228 229 /// Variant to hold the kind of extend marker. 230 /// 231 /// This is `Signed` or `Zero`, that are empty enums, which means that this variant cannot be 232 /// constructed. 233 __Kind(T), 234 } 235 236 impl From<Extend<Zero>> for ExtendKind { 237 fn from(value: Extend<Zero>) -> Self { 238 ExtendKind::Unsigned(value) 239 } 240 } 241 242 impl<T: ExtendType> Extend<T> { 243 pub fn from_size(&self) -> OperandSize { 244 match self { 245 Extend::I32Extend8 | Extend::I64Extend8 => OperandSize::S8, 246 Extend::I32Extend16 | Extend::I64Extend16 => OperandSize::S16, 247 Extend::I64Extend32 => OperandSize::S32, 248 Extend::__Kind(_) => unreachable!(), 249 } 250 } 251 252 pub fn to_size(&self) -> OperandSize { 253 match self { 254 Extend::I32Extend8 | Extend::I32Extend16 => OperandSize::S32, 255 Extend::I64Extend8 | Extend::I64Extend16 | Extend::I64Extend32 => OperandSize::S64, 256 Extend::__Kind(_) => unreachable!(), 257 } 258 } 259 260 pub fn from_bits(&self) -> u8 { 261 self.from_size().num_bits() 262 } 263 264 pub fn to_bits(&self) -> u8 { 265 self.to_size().num_bits() 266 } 267 } 268 269 impl From<Extend<Signed>> for ExtendKind { 270 fn from(value: Extend<Signed>) -> Self { 271 ExtendKind::Signed(value) 272 } 273 } 274 275 impl ExtendKind { 276 pub fn signed(&self) -> bool { 277 match self { 278 Self::Signed(_) => true, 279 _ => false, 280 } 281 } 282 283 pub fn from_bits(&self) -> u8 { 284 match self { 285 Self::Signed(s) => s.from_bits(), 286 Self::Unsigned(u) => u.from_bits(), 287 } 288 } 289 290 pub fn to_bits(&self) -> u8 { 291 match self { 292 Self::Signed(s) => s.to_bits(), 293 Self::Unsigned(u) => u.to_bits(), 294 } 295 } 296 } 297 298 /// Kinds of vector extends in WebAssembly. Each MacroAssembler implementation 299 /// is responsible for emitting the correct sequence of instructions when 300 /// lowering to machine code. 301 pub(crate) enum VectorExtendKind { 302 /// Sign extends eight 8 bit integers to eight 16 bit lanes. 303 V128Extend8x8S, 304 /// Zero extends eight 8 bit integers to eight 16 bit lanes. 305 V128Extend8x8U, 306 /// Sign extends four 16 bit integers to four 32 bit lanes. 307 V128Extend16x4S, 308 /// Zero extends four 16 bit integers to four 32 bit lanes. 309 V128Extend16x4U, 310 /// Sign extends two 32 bit integers to two 64 bit lanes. 311 V128Extend32x2S, 312 /// Zero extends two 32 bit integers to two 64 bit lanes. 313 V128Extend32x2U, 314 } 315 316 /// Kinds of splat loads supported by WebAssembly. 317 pub(crate) enum SplatLoadKind { 318 /// 8 bits. 319 S8, 320 /// 16 bits. 321 S16, 322 /// 32 bits. 323 S32, 324 /// 64 bits. 325 S64, 326 } 327 328 /// Kinds of splat supported by WebAssembly. 329 #[derive(Copy, Debug, Clone, Eq, PartialEq)] 330 pub(crate) enum SplatKind { 331 /// 8 bit integer. 332 I8x16, 333 /// 16 bit integer. 334 I16x8, 335 /// 32 bit integer. 336 I32x4, 337 /// 64 bit integer. 338 I64x2, 339 /// 32 bit float. 340 F32x4, 341 /// 64 bit float. 342 F64x2, 343 } 344 345 impl SplatKind { 346 /// The lane size to use for different kinds of splats. 347 pub(crate) fn lane_size(&self) -> OperandSize { 348 match self { 349 SplatKind::I8x16 => OperandSize::S8, 350 SplatKind::I16x8 => OperandSize::S16, 351 SplatKind::I32x4 | SplatKind::F32x4 => OperandSize::S32, 352 SplatKind::I64x2 | SplatKind::F64x2 => OperandSize::S64, 353 } 354 } 355 } 356 357 /// Kinds of extract lane supported by WebAssembly. 358 #[derive(Copy, Debug, Clone, Eq, PartialEq)] 359 pub(crate) enum ExtractLaneKind { 360 /// 16 lanes of 8-bit integers sign extended to 32-bits. 361 I8x16S, 362 /// 16 lanes of 8-bit integers zero extended to 32-bits. 363 I8x16U, 364 /// 8 lanes of 16-bit integers sign extended to 32-bits. 365 I16x8S, 366 /// 8 lanes of 16-bit integers zero extended to 32-bits. 367 I16x8U, 368 /// 4 lanes of 32-bit integers. 369 I32x4, 370 /// 2 lanes of 64-bit integers. 371 I64x2, 372 /// 4 lanes of 32-bit floats. 373 F32x4, 374 /// 2 lanes of 64-bit floats. 375 F64x2, 376 } 377 378 impl ExtractLaneKind { 379 /// The lane size to use for different kinds of extract lane kinds. 380 pub(crate) fn lane_size(&self) -> OperandSize { 381 match self { 382 ExtractLaneKind::I8x16S | ExtractLaneKind::I8x16U => OperandSize::S8, 383 ExtractLaneKind::I16x8S | ExtractLaneKind::I16x8U => OperandSize::S16, 384 ExtractLaneKind::I32x4 | ExtractLaneKind::F32x4 => OperandSize::S32, 385 ExtractLaneKind::I64x2 | ExtractLaneKind::F64x2 => OperandSize::S64, 386 } 387 } 388 } 389 390 impl From<ExtractLaneKind> for Extend<Signed> { 391 fn from(value: ExtractLaneKind) -> Self { 392 match value { 393 ExtractLaneKind::I8x16S => Extend::I32Extend8, 394 ExtractLaneKind::I16x8S => Extend::I32Extend16, 395 _ => unimplemented!(), 396 } 397 } 398 } 399 400 /// Kinds of replace lane supported by WebAssembly. 401 pub(crate) enum ReplaceLaneKind { 402 /// 16 lanes of 8 bit integers. 403 I8x16, 404 /// 8 lanes of 16 bit integers. 405 I16x8, 406 /// 4 lanes of 32 bit integers. 407 I32x4, 408 /// 2 lanes of 64 bit integers. 409 I64x2, 410 /// 4 lanes of 32 bit floats. 411 F32x4, 412 /// 2 lanes of 64 bit floats. 413 F64x2, 414 } 415 416 impl ReplaceLaneKind { 417 /// The lane size to use for different kinds of replace lane kinds. 418 pub(crate) fn lane_size(&self) -> OperandSize { 419 match self { 420 ReplaceLaneKind::I8x16 => OperandSize::S8, 421 ReplaceLaneKind::I16x8 => OperandSize::S16, 422 ReplaceLaneKind::I32x4 => OperandSize::S32, 423 ReplaceLaneKind::I64x2 => OperandSize::S64, 424 ReplaceLaneKind::F32x4 => OperandSize::S32, 425 ReplaceLaneKind::F64x2 => OperandSize::S64, 426 } 427 } 428 } 429 430 /// Kinds of behavior supported by Wasm loads. 431 pub(crate) enum LoadKind { 432 /// Load the entire bytes of the operand size without any modifications. 433 Operand(OperandSize), 434 /// Duplicate value into vector lanes. 435 Splat(SplatLoadKind), 436 /// Scalar (non-vector) extend. 437 ScalarExtend(ExtendKind), 438 /// Vector extend. 439 VectorExtend(VectorExtendKind), 440 } 441 442 impl LoadKind { 443 /// Returns the [`OperandSize`] used in the load operation. 444 pub(crate) fn derive_operand_size(&self) -> OperandSize { 445 match self { 446 Self::ScalarExtend(scalar) => Self::operand_size_for_scalar(scalar), 447 Self::VectorExtend(_) => OperandSize::S64, 448 Self::Splat(kind) => Self::operand_size_for_splat(kind), 449 Self::Operand(op) => *op, 450 } 451 } 452 453 fn operand_size_for_scalar(extend_kind: &ExtendKind) -> OperandSize { 454 match extend_kind { 455 ExtendKind::Signed(s) => s.from_size(), 456 ExtendKind::Unsigned(u) => u.from_size(), 457 } 458 } 459 460 fn operand_size_for_splat(kind: &SplatLoadKind) -> OperandSize { 461 match kind { 462 SplatLoadKind::S8 => OperandSize::S8, 463 SplatLoadKind::S16 => OperandSize::S16, 464 SplatLoadKind::S32 => OperandSize::S32, 465 SplatLoadKind::S64 => OperandSize::S64, 466 } 467 } 468 } 469 470 /// Operand size, in bits. 471 #[derive(Copy, Debug, Clone, Eq, PartialEq)] 472 pub(crate) enum OperandSize { 473 /// 8 bits. 474 S8, 475 /// 16 bits. 476 S16, 477 /// 32 bits. 478 S32, 479 /// 64 bits. 480 S64, 481 /// 128 bits. 482 S128, 483 } 484 485 impl OperandSize { 486 /// The number of bits in the operand. 487 pub fn num_bits(&self) -> u8 { 488 match self { 489 OperandSize::S8 => 8, 490 OperandSize::S16 => 16, 491 OperandSize::S32 => 32, 492 OperandSize::S64 => 64, 493 OperandSize::S128 => 128, 494 } 495 } 496 497 /// The number of bytes in the operand. 498 pub fn bytes(&self) -> u32 { 499 match self { 500 Self::S8 => 1, 501 Self::S16 => 2, 502 Self::S32 => 4, 503 Self::S64 => 8, 504 Self::S128 => 16, 505 } 506 } 507 508 /// The binary logarithm of the number of bits in the operand. 509 pub fn log2(&self) -> u8 { 510 match self { 511 OperandSize::S8 => 3, 512 OperandSize::S16 => 4, 513 OperandSize::S32 => 5, 514 OperandSize::S64 => 6, 515 OperandSize::S128 => 7, 516 } 517 } 518 519 /// Create an [`OperandSize`] from the given number of bytes. 520 pub fn from_bytes(bytes: u8) -> Self { 521 use OperandSize::*; 522 match bytes { 523 4 => S32, 524 8 => S64, 525 16 => S128, 526 _ => panic!("Invalid bytes {bytes} for OperandSize"), 527 } 528 } 529 530 pub fn extend_to<T: ExtendType>(&self, to: Self) -> Option<Extend<T>> { 531 match to { 532 OperandSize::S32 => match self { 533 OperandSize::S8 => Some(Extend::I32Extend8), 534 OperandSize::S16 => Some(Extend::I32Extend16), 535 _ => None, 536 }, 537 OperandSize::S64 => match self { 538 OperandSize::S8 => Some(Extend::I64Extend8), 539 OperandSize::S16 => Some(Extend::I64Extend16), 540 OperandSize::S32 => Some(Extend::I64Extend32), 541 _ => None, 542 }, 543 _ => None, 544 } 545 } 546 } 547 548 /// An abstraction over a register or immediate. 549 #[derive(Copy, Clone, Debug, PartialEq, Eq)] 550 pub(crate) enum RegImm { 551 /// A register. 552 Reg(Reg), 553 /// A tagged immediate argument. 554 Imm(Imm), 555 } 556 557 /// An tagged representation of an immediate. 558 #[derive(Copy, Clone, Debug, PartialEq, Eq)] 559 pub(crate) enum Imm { 560 /// I32 immediate. 561 I32(u32), 562 /// I64 immediate. 563 I64(u64), 564 /// F32 immediate. 565 F32(u32), 566 /// F64 immediate. 567 F64(u64), 568 /// V128 immediate. 569 V128(i128), 570 } 571 572 impl Imm { 573 /// Create a new I64 immediate. 574 pub fn i64(val: i64) -> Self { 575 Self::I64(val as u64) 576 } 577 578 /// Create a new I32 immediate. 579 pub fn i32(val: i32) -> Self { 580 Self::I32(val as u32) 581 } 582 583 /// Create a new F32 immediate. 584 pub fn f32(bits: u32) -> Self { 585 Self::F32(bits) 586 } 587 588 /// Create a new F64 immediate. 589 pub fn f64(bits: u64) -> Self { 590 Self::F64(bits) 591 } 592 593 /// Create a new V128 immediate. 594 pub fn v128(bits: i128) -> Self { 595 Self::V128(bits) 596 } 597 598 /// Convert the immediate to i32, if possible. 599 pub fn to_i32(&self) -> Option<i32> { 600 match self { 601 Self::I32(v) => Some(*v as i32), 602 Self::I64(v) => i32::try_from(*v as i64).ok(), 603 _ => None, 604 } 605 } 606 607 /// Returns true if the [`Imm`] is float. 608 pub fn is_float(&self) -> bool { 609 match self { 610 Self::F32(_) | Self::F64(_) => true, 611 _ => false, 612 } 613 } 614 615 /// Get the operand size of the immediate. 616 pub fn size(&self) -> OperandSize { 617 match self { 618 Self::I32(_) | Self::F32(_) => OperandSize::S32, 619 Self::I64(_) | Self::F64(_) => OperandSize::S64, 620 Self::V128(_) => OperandSize::S128, 621 } 622 } 623 624 /// Get a little endian representation of the immediate. 625 /// 626 /// This method heap allocates and is intended to be used when adding 627 /// values to the constant pool. 628 pub fn to_bytes(&self) -> Vec<u8> { 629 match self { 630 Imm::I32(n) => n.to_le_bytes().to_vec(), 631 Imm::I64(n) => n.to_le_bytes().to_vec(), 632 Imm::F32(n) => n.to_le_bytes().to_vec(), 633 Imm::F64(n) => n.to_le_bytes().to_vec(), 634 Imm::V128(n) => n.to_le_bytes().to_vec(), 635 } 636 } 637 } 638 639 /// The location of the [VMcontext] used for function calls. 640 #[derive(Copy, Clone, Debug, Eq, PartialEq)] 641 pub(crate) enum VMContextLoc { 642 /// Dynamic, stored in the given register. 643 Reg(Reg), 644 /// The pinned [VMContext] register. 645 Pinned, 646 } 647 648 /// The maximum number of context arguments currently used across the compiler. 649 pub(crate) const MAX_CONTEXT_ARGS: usize = 2; 650 651 /// Out-of-band special purpose arguments used for function call emission. 652 /// 653 /// We cannot rely on the value stack for these values given that inserting 654 /// register or memory values at arbitrary locations of the value stack has the 655 /// potential to break the stack ordering principle, which states that older 656 /// values must always precede newer values, effectively simulating the order of 657 /// values in the machine stack. 658 /// The [ContextArgs] are meant to be resolved at every callsite; in some cases 659 /// it might be possible to construct it early on, but given that it might 660 /// contain allocatable registers, it's preferred to construct it in 661 /// [FnCall::emit]. 662 #[derive(Clone, Debug)] 663 pub(crate) enum ContextArgs { 664 /// No context arguments required. This is used for libcalls that don't 665 /// require any special context arguments. For example builtin functions 666 /// that perform float calculations. 667 None, 668 /// A single context argument is required; the current pinned [VMcontext] 669 /// register must be passed as the first argument of the function call. 670 VMContext([VMContextLoc; 1]), 671 /// The callee and caller context arguments are required. In this case, the 672 /// callee context argument is usually stored into an allocatable register 673 /// and the caller is always the current pinned [VMContext] pointer. 674 CalleeAndCallerVMContext([VMContextLoc; MAX_CONTEXT_ARGS]), 675 } 676 677 impl ContextArgs { 678 /// Construct an empty [ContextArgs]. 679 pub fn none() -> Self { 680 Self::None 681 } 682 683 /// Construct a [ContextArgs] declaring the usage of the pinned [VMContext] 684 /// register as both the caller and callee context arguments. 685 pub fn pinned_callee_and_caller_vmctx() -> Self { 686 Self::CalleeAndCallerVMContext([VMContextLoc::Pinned, VMContextLoc::Pinned]) 687 } 688 689 /// Construct a [ContextArgs] that declares the usage of the pinned 690 /// [VMContext] register as the only context argument. 691 pub fn pinned_vmctx() -> Self { 692 Self::VMContext([VMContextLoc::Pinned]) 693 } 694 695 /// Construct a [ContextArgs] that declares a dynamic callee context and the 696 /// pinned [VMContext] register as the context arguments. 697 pub fn with_callee_and_pinned_caller(callee_vmctx: Reg) -> Self { 698 Self::CalleeAndCallerVMContext([VMContextLoc::Reg(callee_vmctx), VMContextLoc::Pinned]) 699 } 700 701 /// Get the length of the [ContextArgs]. 702 pub fn len(&self) -> usize { 703 self.as_slice().len() 704 } 705 706 /// Get a slice of the context arguments. 707 pub fn as_slice(&self) -> &[VMContextLoc] { 708 match self { 709 Self::None => &[], 710 Self::VMContext(a) => a.as_slice(), 711 Self::CalleeAndCallerVMContext(a) => a.as_slice(), 712 } 713 } 714 } 715 716 #[derive(Copy, Clone, Debug)] 717 pub(crate) enum CalleeKind { 718 /// A function call to a raw address. 719 Indirect(Reg), 720 /// A function call to a local function. 721 Direct(UserExternalNameRef), 722 /// Call to a well known LibCall. 723 LibCall(LibCall), 724 } 725 726 impl CalleeKind { 727 /// Creates a callee kind from a register. 728 pub fn indirect(reg: Reg) -> Self { 729 Self::Indirect(reg) 730 } 731 732 /// Creates a direct callee kind from a function name. 733 pub fn direct(name: UserExternalNameRef) -> Self { 734 Self::Direct(name) 735 } 736 737 /// Creates a known callee kind from a libcall. 738 pub fn libcall(call: LibCall) -> Self { 739 Self::LibCall(call) 740 } 741 } 742 743 impl RegImm { 744 /// Register constructor. 745 pub fn reg(r: Reg) -> Self { 746 RegImm::Reg(r) 747 } 748 749 /// I64 immediate constructor. 750 pub fn i64(val: i64) -> Self { 751 RegImm::Imm(Imm::i64(val)) 752 } 753 754 /// I32 immediate constructor. 755 pub fn i32(val: i32) -> Self { 756 RegImm::Imm(Imm::i32(val)) 757 } 758 759 /// F32 immediate, stored using its bits representation. 760 pub fn f32(bits: u32) -> Self { 761 RegImm::Imm(Imm::f32(bits)) 762 } 763 764 /// F64 immediate, stored using its bits representation. 765 pub fn f64(bits: u64) -> Self { 766 RegImm::Imm(Imm::f64(bits)) 767 } 768 769 /// V128 immediate. 770 pub fn v128(bits: i128) -> Self { 771 RegImm::Imm(Imm::v128(bits)) 772 } 773 } 774 775 impl From<Reg> for RegImm { 776 fn from(r: Reg) -> Self { 777 Self::Reg(r) 778 } 779 } 780 781 #[derive(Debug)] 782 pub enum RoundingMode { 783 Nearest, 784 Up, 785 Down, 786 Zero, 787 } 788 789 /// Memory flags for trusted loads/stores. 790 pub const TRUSTED_FLAGS: MemFlags = MemFlags::trusted(); 791 792 /// Flags used for WebAssembly loads / stores. 793 /// Untrusted by default so we don't set `no_trap`. 794 /// We also ensure that the endianness is the right one for WebAssembly. 795 pub const UNTRUSTED_FLAGS: MemFlags = MemFlags::new().with_endianness(Endianness::Little); 796 797 /// Generic MacroAssembler interface used by the code generation. 798 /// 799 /// The MacroAssembler trait aims to expose an interface, high-level enough, 800 /// so that each ISA can provide its own lowering to machine code. For example, 801 /// for WebAssembly operators that don't have a direct mapping to a machine 802 /// a instruction, the interface defines a signature matching the WebAssembly 803 /// operator, allowing each implementation to lower such operator entirely. 804 /// This approach attributes more responsibility to the MacroAssembler, but frees 805 /// the caller from concerning about assembling the right sequence of 806 /// instructions at the operator callsite. 807 /// 808 /// The interface defaults to a three-argument form for binary operations; 809 /// this allows a natural mapping to instructions for RISC architectures, 810 /// that use three-argument form. 811 /// This approach allows for a more general interface that can be restricted 812 /// where needed, in the case of architectures that use a two-argument form. 813 814 pub(crate) trait MacroAssembler { 815 /// The addressing mode. 816 type Address: Copy + Debug; 817 818 /// The pointer representation of the target ISA, 819 /// used to access information from [`VMOffsets`]. 820 type Ptr: PtrSize; 821 822 /// The ABI details of the target. 823 type ABI: abi::ABI; 824 825 /// Emit the function prologue. 826 fn prologue(&mut self, vmctx: Reg) -> Result<()> { 827 self.frame_setup()?; 828 self.check_stack(vmctx) 829 } 830 831 /// Generate the frame setup sequence. 832 fn frame_setup(&mut self) -> Result<()>; 833 834 /// Generate the frame restore sequence. 835 fn frame_restore(&mut self) -> Result<()>; 836 837 /// Emit a stack check. 838 fn check_stack(&mut self, vmctx: Reg) -> Result<()>; 839 840 /// Emit the function epilogue. 841 fn epilogue(&mut self) -> Result<()> { 842 self.frame_restore() 843 } 844 845 /// Reserve stack space. 846 fn reserve_stack(&mut self, bytes: u32) -> Result<()>; 847 848 /// Free stack space. 849 fn free_stack(&mut self, bytes: u32) -> Result<()>; 850 851 /// Reset the stack pointer to the given offset; 852 /// 853 /// Used to reset the stack pointer to a given offset 854 /// when dealing with unreachable code. 855 fn reset_stack_pointer(&mut self, offset: SPOffset) -> Result<()>; 856 857 /// Get the address of a local slot. 858 fn local_address(&mut self, local: &LocalSlot) -> Result<Self::Address>; 859 860 /// Constructs an address with an offset that is relative to the 861 /// current position of the stack pointer (e.g. [sp + (sp_offset - 862 /// offset)]. 863 fn address_from_sp(&self, offset: SPOffset) -> Result<Self::Address>; 864 865 /// Constructs an address with an offset that is absolute to the 866 /// current position of the stack pointer (e.g. [sp + offset]. 867 fn address_at_sp(&self, offset: SPOffset) -> Result<Self::Address>; 868 869 /// Alias for [`Self::address_at_reg`] using the VMContext register as 870 /// a base. The VMContext register is derived from the ABI type that is 871 /// associated to the MacroAssembler. 872 fn address_at_vmctx(&self, offset: u32) -> Result<Self::Address>; 873 874 /// Construct an address that is absolute to the current position 875 /// of the given register. 876 fn address_at_reg(&self, reg: Reg, offset: u32) -> Result<Self::Address>; 877 878 /// Emit a function call to either a local or external function. 879 fn call( 880 &mut self, 881 stack_args_size: u32, 882 f: impl FnMut(&mut Self) -> Result<(CalleeKind, CallingConvention)>, 883 ) -> Result<u32>; 884 885 /// Get stack pointer offset. 886 fn sp_offset(&self) -> Result<SPOffset>; 887 888 /// Perform a stack store. 889 fn store(&mut self, src: RegImm, dst: Self::Address, size: OperandSize) -> Result<()>; 890 891 /// Alias for `MacroAssembler::store` with the operand size corresponding 892 /// to the pointer size of the target. 893 fn store_ptr(&mut self, src: Reg, dst: Self::Address) -> Result<()>; 894 895 /// Perform a WebAssembly store. 896 /// A WebAssembly store introduces several additional invariants compared to 897 /// [Self::store], more precisely, it can implicitly trap, in certain 898 /// circumstances, even if explicit bounds checks are elided, in that sense, 899 /// we consider this type of load as untrusted. It can also differ with 900 /// regards to the endianness depending on the target ISA. For this reason, 901 /// [Self::wasm_store], should be explicitly used when emitting WebAssembly 902 /// stores. 903 fn wasm_store( 904 &mut self, 905 src: Reg, 906 dst: Self::Address, 907 size: OperandSize, 908 op_kind: MemOpKind, 909 ) -> Result<()>; 910 911 /// Perform a zero-extended stack load. 912 fn load(&mut self, src: Self::Address, dst: WritableReg, size: OperandSize) -> Result<()>; 913 914 /// Perform a WebAssembly load. 915 /// A WebAssembly load introduces several additional invariants compared to 916 /// [Self::load], more precisely, it can implicitly trap, in certain 917 /// circumstances, even if explicit bounds checks are elided, in that sense, 918 /// we consider this type of load as untrusted. It can also differ with 919 /// regards to the endianness depending on the target ISA. For this reason, 920 /// [Self::wasm_load], should be explicitly used when emitting WebAssembly 921 /// loads. 922 fn wasm_load( 923 &mut self, 924 src: Self::Address, 925 dst: WritableReg, 926 kind: LoadKind, 927 op_kind: MemOpKind, 928 ) -> Result<()>; 929 930 /// Alias for `MacroAssembler::load` with the operand size corresponding 931 /// to the pointer size of the target. 932 fn load_ptr(&mut self, src: Self::Address, dst: WritableReg) -> Result<()>; 933 934 /// Loads the effective address into destination. 935 fn load_addr( 936 &mut self, 937 _src: Self::Address, 938 _dst: WritableReg, 939 _size: OperandSize, 940 ) -> Result<()>; 941 942 /// Pop a value from the machine stack into the given register. 943 fn pop(&mut self, dst: WritableReg, size: OperandSize) -> Result<()>; 944 945 /// Perform a move. 946 fn mov(&mut self, dst: WritableReg, src: RegImm, size: OperandSize) -> Result<()>; 947 948 /// Perform a conditional move. 949 fn cmov(&mut self, dst: WritableReg, src: Reg, cc: IntCmpKind, size: OperandSize) 950 -> Result<()>; 951 952 /// Performs a memory move of bytes from src to dest. 953 /// Bytes are moved in blocks of 8 bytes, where possible. 954 fn memmove( 955 &mut self, 956 src: SPOffset, 957 dst: SPOffset, 958 bytes: u32, 959 direction: MemMoveDirection, 960 ) -> Result<()> { 961 match direction { 962 MemMoveDirection::LowToHigh => debug_assert!(dst.as_u32() < src.as_u32()), 963 MemMoveDirection::HighToLow => debug_assert!(dst.as_u32() > src.as_u32()), 964 } 965 // At least 4 byte aligned. 966 debug_assert!(bytes % 4 == 0); 967 let mut remaining = bytes; 968 let word_bytes = <Self::ABI as abi::ABI>::word_bytes(); 969 let scratch = scratch!(Self); 970 971 let mut dst_offs = dst.as_u32() - bytes; 972 let mut src_offs = src.as_u32() - bytes; 973 974 let word_bytes = word_bytes as u32; 975 while remaining >= word_bytes { 976 remaining -= word_bytes; 977 dst_offs += word_bytes; 978 src_offs += word_bytes; 979 980 self.load_ptr( 981 self.address_from_sp(SPOffset::from_u32(src_offs))?, 982 writable!(scratch), 983 )?; 984 self.store_ptr( 985 scratch.into(), 986 self.address_from_sp(SPOffset::from_u32(dst_offs))?, 987 )?; 988 } 989 990 if remaining > 0 { 991 let half_word = word_bytes / 2; 992 let ptr_size = OperandSize::from_bytes(half_word as u8); 993 debug_assert!(remaining == half_word); 994 dst_offs += half_word; 995 src_offs += half_word; 996 997 self.load( 998 self.address_from_sp(SPOffset::from_u32(src_offs))?, 999 writable!(scratch), 1000 ptr_size, 1001 )?; 1002 self.store( 1003 scratch.into(), 1004 self.address_from_sp(SPOffset::from_u32(dst_offs))?, 1005 ptr_size, 1006 )?; 1007 } 1008 Ok(()) 1009 } 1010 1011 /// Perform add operation. 1012 fn add(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>; 1013 1014 /// Perform a checked unsigned integer addition, emitting the provided trap 1015 /// if the addition overflows. 1016 fn checked_uadd( 1017 &mut self, 1018 dst: WritableReg, 1019 lhs: Reg, 1020 rhs: RegImm, 1021 size: OperandSize, 1022 trap: TrapCode, 1023 ) -> Result<()>; 1024 1025 /// Perform subtraction operation. 1026 fn sub(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>; 1027 1028 /// Perform multiplication operation. 1029 fn mul(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>; 1030 1031 /// Perform a floating point add operation. 1032 fn float_add(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>; 1033 1034 /// Perform a floating point subtraction operation. 1035 fn float_sub(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>; 1036 1037 /// Perform a floating point multiply operation. 1038 fn float_mul(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>; 1039 1040 /// Perform a floating point divide operation. 1041 fn float_div(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>; 1042 1043 /// Perform a floating point minimum operation. In x86, this will emit 1044 /// multiple instructions. 1045 fn float_min(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>; 1046 1047 /// Perform a floating point maximum operation. In x86, this will emit 1048 /// multiple instructions. 1049 fn float_max(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>; 1050 1051 /// Perform a floating point copysign operation. In x86, this will emit 1052 /// multiple instructions. 1053 fn float_copysign( 1054 &mut self, 1055 dst: WritableReg, 1056 lhs: Reg, 1057 rhs: Reg, 1058 size: OperandSize, 1059 ) -> Result<()>; 1060 1061 /// Perform a floating point abs operation. 1062 fn float_abs(&mut self, dst: WritableReg, size: OperandSize) -> Result<()>; 1063 1064 /// Perform a floating point negation operation. 1065 fn float_neg(&mut self, dst: WritableReg, size: OperandSize) -> Result<()>; 1066 1067 /// Perform a floating point floor operation. 1068 fn float_round< 1069 F: FnMut(&mut FuncEnv<Self::Ptr>, &mut CodeGenContext<Emission>, &mut Self) -> Result<()>, 1070 >( 1071 &mut self, 1072 mode: RoundingMode, 1073 env: &mut FuncEnv<Self::Ptr>, 1074 context: &mut CodeGenContext<Emission>, 1075 size: OperandSize, 1076 fallback: F, 1077 ) -> Result<()>; 1078 1079 /// Perform a floating point square root operation. 1080 fn float_sqrt(&mut self, dst: WritableReg, src: Reg, size: OperandSize) -> Result<()>; 1081 1082 /// Perform logical and operation. 1083 fn and(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>; 1084 1085 /// Perform logical or operation. 1086 fn or(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>; 1087 1088 /// Perform logical exclusive or operation. 1089 fn xor(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>; 1090 1091 /// Perform a shift operation between a register and an immediate. 1092 fn shift_ir( 1093 &mut self, 1094 dst: WritableReg, 1095 imm: u64, 1096 lhs: Reg, 1097 kind: ShiftKind, 1098 size: OperandSize, 1099 ) -> Result<()>; 1100 1101 /// Perform a shift operation between two registers. 1102 /// This case is special in that some architectures have specific expectations 1103 /// regarding the location of the instruction arguments. To free the 1104 /// caller from having to deal with the architecture specific constraints 1105 /// we give this function access to the code generation context, allowing 1106 /// each implementation to decide the lowering path. 1107 fn shift( 1108 &mut self, 1109 context: &mut CodeGenContext<Emission>, 1110 kind: ShiftKind, 1111 size: OperandSize, 1112 ) -> Result<()>; 1113 1114 /// Perform division operation. 1115 /// Division is special in that some architectures have specific 1116 /// expectations regarding the location of the instruction 1117 /// arguments and regarding the location of the quotient / 1118 /// remainder. To free the caller from having to deal with the 1119 /// architecture specific constraints we give this function access 1120 /// to the code generation context, allowing each implementation 1121 /// to decide the lowering path. For cases in which division is a 1122 /// unconstrained binary operation, the caller can decide to use 1123 /// the `CodeGenContext::i32_binop` or `CodeGenContext::i64_binop` 1124 /// functions. 1125 fn div( 1126 &mut self, 1127 context: &mut CodeGenContext<Emission>, 1128 kind: DivKind, 1129 size: OperandSize, 1130 ) -> Result<()>; 1131 1132 /// Calculate remainder. 1133 fn rem( 1134 &mut self, 1135 context: &mut CodeGenContext<Emission>, 1136 kind: RemKind, 1137 size: OperandSize, 1138 ) -> Result<()>; 1139 1140 /// Compares `src1` against `src2` for the side effect of setting processor 1141 /// flags. 1142 /// 1143 /// Note that `src1` is the left-hand-side of the comparison and `src2` is 1144 /// the right-hand-side, so if testing `a < b` then `src1 == a` and 1145 /// `src2 == b` 1146 fn cmp(&mut self, src1: Reg, src2: RegImm, size: OperandSize) -> Result<()>; 1147 1148 /// Compare src and dst and put the result in dst. 1149 /// This function will potentially emit a series of instructions. 1150 /// 1151 /// The initial value in `dst` is the left-hand-side of the comparison and 1152 /// the initial value in `src` is the right-hand-side of the comparison. 1153 /// That means for `a < b` then `dst == a` and `src == b`. 1154 fn cmp_with_set( 1155 &mut self, 1156 dst: WritableReg, 1157 src: RegImm, 1158 kind: IntCmpKind, 1159 size: OperandSize, 1160 ) -> Result<()>; 1161 1162 /// Compare floats in src1 and src2 and put the result in dst. 1163 /// In x86, this will emit multiple instructions. 1164 fn float_cmp_with_set( 1165 &mut self, 1166 dst: WritableReg, 1167 src1: Reg, 1168 src2: Reg, 1169 kind: FloatCmpKind, 1170 size: OperandSize, 1171 ) -> Result<()>; 1172 1173 /// Count the number of leading zeroes in src and put the result in dst. 1174 /// In x64, this will emit multiple instructions if the `has_lzcnt` flag is 1175 /// false. 1176 fn clz(&mut self, dst: WritableReg, src: Reg, size: OperandSize) -> Result<()>; 1177 1178 /// Count the number of trailing zeroes in src and put the result in dst.masm 1179 /// In x64, this will emit multiple instructions if the `has_tzcnt` flag is 1180 /// false. 1181 fn ctz(&mut self, dst: WritableReg, src: Reg, size: OperandSize) -> Result<()>; 1182 1183 /// Push the register to the stack, returning the stack slot metadata. 1184 // NB 1185 // The stack alignment should not be assumed after any call to `push`, 1186 // unless explicitly aligned otherwise. Typically, stack alignment is 1187 // maintained at call sites and during the execution of 1188 // epilogues. 1189 fn push(&mut self, src: Reg, size: OperandSize) -> Result<StackSlot>; 1190 1191 /// Finalize the assembly and return the result. 1192 fn finalize(self, base: Option<SourceLoc>) -> Result<MachBufferFinalized<Final>>; 1193 1194 /// Zero a particular register. 1195 fn zero(&mut self, reg: WritableReg) -> Result<()>; 1196 1197 /// Count the number of 1 bits in src and put the result in dst. In x64, 1198 /// this will emit multiple instructions if the `has_popcnt` flag is false. 1199 fn popcnt(&mut self, context: &mut CodeGenContext<Emission>, size: OperandSize) -> Result<()>; 1200 1201 /// Converts an i64 to an i32 by discarding the high 32 bits. 1202 fn wrap(&mut self, dst: WritableReg, src: Reg) -> Result<()>; 1203 1204 /// Extends an integer of a given size to a larger size. 1205 fn extend(&mut self, dst: WritableReg, src: Reg, kind: ExtendKind) -> Result<()>; 1206 1207 /// Emits one or more instructions to perform a signed truncation of a 1208 /// float into an integer. 1209 fn signed_truncate( 1210 &mut self, 1211 dst: WritableReg, 1212 src: Reg, 1213 src_size: OperandSize, 1214 dst_size: OperandSize, 1215 kind: TruncKind, 1216 ) -> Result<()>; 1217 1218 /// Emits one or more instructions to perform an unsigned truncation of a 1219 /// float into an integer. 1220 fn unsigned_truncate( 1221 &mut self, 1222 context: &mut CodeGenContext<Emission>, 1223 src_size: OperandSize, 1224 dst_size: OperandSize, 1225 kind: TruncKind, 1226 ) -> Result<()>; 1227 1228 /// Emits one or more instructions to perform a signed convert of an 1229 /// integer into a float. 1230 fn signed_convert( 1231 &mut self, 1232 dst: WritableReg, 1233 src: Reg, 1234 src_size: OperandSize, 1235 dst_size: OperandSize, 1236 ) -> Result<()>; 1237 1238 /// Emits one or more instructions to perform an unsigned convert of an 1239 /// integer into a float. 1240 fn unsigned_convert( 1241 &mut self, 1242 dst: WritableReg, 1243 src: Reg, 1244 tmp_gpr: Reg, 1245 src_size: OperandSize, 1246 dst_size: OperandSize, 1247 ) -> Result<()>; 1248 1249 /// Reinterpret a float as an integer. 1250 fn reinterpret_float_as_int( 1251 &mut self, 1252 dst: WritableReg, 1253 src: Reg, 1254 size: OperandSize, 1255 ) -> Result<()>; 1256 1257 /// Reinterpret an integer as a float. 1258 fn reinterpret_int_as_float( 1259 &mut self, 1260 dst: WritableReg, 1261 src: Reg, 1262 size: OperandSize, 1263 ) -> Result<()>; 1264 1265 /// Demote an f64 to an f32. 1266 fn demote(&mut self, dst: WritableReg, src: Reg) -> Result<()>; 1267 1268 /// Promote an f32 to an f64. 1269 fn promote(&mut self, dst: WritableReg, src: Reg) -> Result<()>; 1270 1271 /// Zero a given memory range. 1272 /// 1273 /// The default implementation divides the given memory range 1274 /// into word-sized slots. Then it unrolls a series of store 1275 /// instructions, effectively assigning zero to each slot. 1276 fn zero_mem_range(&mut self, mem: &Range<u32>) -> Result<()> { 1277 let word_size = <Self::ABI as abi::ABI>::word_bytes() as u32; 1278 if mem.is_empty() { 1279 return Ok(()); 1280 } 1281 1282 let start = if mem.start % word_size == 0 { 1283 mem.start 1284 } else { 1285 // Ensure that the start of the range is at least 4-byte aligned. 1286 assert!(mem.start % 4 == 0); 1287 let start = align_to(mem.start, word_size); 1288 let addr: Self::Address = self.local_address(&LocalSlot::i32(start))?; 1289 self.store(RegImm::i32(0), addr, OperandSize::S32)?; 1290 // Ensure that the new start of the range, is word-size aligned. 1291 assert!(start % word_size == 0); 1292 start 1293 }; 1294 1295 let end = align_to(mem.end, word_size); 1296 let slots = (end - start) / word_size; 1297 1298 if slots == 1 { 1299 let slot = LocalSlot::i64(start + word_size); 1300 let addr: Self::Address = self.local_address(&slot)?; 1301 self.store(RegImm::i64(0), addr, OperandSize::S64)?; 1302 } else { 1303 // TODO 1304 // Add an upper bound to this generation; 1305 // given a considerably large amount of slots 1306 // this will be inefficient. 1307 let zero = scratch!(Self); 1308 self.zero(writable!(zero))?; 1309 let zero = RegImm::reg(zero); 1310 1311 for step in (start..end).into_iter().step_by(word_size as usize) { 1312 let slot = LocalSlot::i64(step + word_size); 1313 let addr: Self::Address = self.local_address(&slot)?; 1314 self.store(zero, addr, OperandSize::S64)?; 1315 } 1316 } 1317 1318 Ok(()) 1319 } 1320 1321 /// Generate a label. 1322 fn get_label(&mut self) -> Result<MachLabel>; 1323 1324 /// Bind the given label at the current code offset. 1325 fn bind(&mut self, label: MachLabel) -> Result<()>; 1326 1327 /// Conditional branch. 1328 /// 1329 /// Performs a comparison between the two operands, 1330 /// and immediately after emits a jump to the given 1331 /// label destination if the condition is met. 1332 fn branch( 1333 &mut self, 1334 kind: IntCmpKind, 1335 lhs: Reg, 1336 rhs: RegImm, 1337 taken: MachLabel, 1338 size: OperandSize, 1339 ) -> Result<()>; 1340 1341 /// Emits and unconditional jump to the given label. 1342 fn jmp(&mut self, target: MachLabel) -> Result<()>; 1343 1344 /// Emits a jump table sequence. The default label is specified as 1345 /// the last element of the targets slice. 1346 fn jmp_table(&mut self, targets: &[MachLabel], index: Reg, tmp: Reg) -> Result<()>; 1347 1348 /// Emit an unreachable code trap. 1349 fn unreachable(&mut self) -> Result<()>; 1350 1351 /// Emit an unconditional trap. 1352 fn trap(&mut self, code: TrapCode) -> Result<()>; 1353 1354 /// Traps if the condition code is met. 1355 fn trapif(&mut self, cc: IntCmpKind, code: TrapCode) -> Result<()>; 1356 1357 /// Trap if the source register is zero. 1358 fn trapz(&mut self, src: Reg, code: TrapCode) -> Result<()>; 1359 1360 /// Ensures that the stack pointer is correctly positioned before an unconditional 1361 /// jump according to the requirements of the destination target. 1362 fn ensure_sp_for_jump(&mut self, target: SPOffset) -> Result<()> { 1363 let bytes = self 1364 .sp_offset()? 1365 .as_u32() 1366 .checked_sub(target.as_u32()) 1367 .unwrap_or(0); 1368 1369 if bytes > 0 { 1370 self.free_stack(bytes)?; 1371 } 1372 1373 Ok(()) 1374 } 1375 1376 /// Mark the start of a source location returning the machine code offset 1377 /// and the relative source code location. 1378 fn start_source_loc(&mut self, loc: RelSourceLoc) -> Result<(CodeOffset, RelSourceLoc)>; 1379 1380 /// Mark the end of a source location. 1381 fn end_source_loc(&mut self) -> Result<()>; 1382 1383 /// The current offset, in bytes from the beginning of the function. 1384 fn current_code_offset(&self) -> Result<CodeOffset>; 1385 1386 /// Performs a 128-bit addition 1387 fn add128( 1388 &mut self, 1389 dst_lo: WritableReg, 1390 dst_hi: WritableReg, 1391 lhs_lo: Reg, 1392 lhs_hi: Reg, 1393 rhs_lo: Reg, 1394 rhs_hi: Reg, 1395 ) -> Result<()>; 1396 1397 /// Performs a 128-bit subtraction 1398 fn sub128( 1399 &mut self, 1400 dst_lo: WritableReg, 1401 dst_hi: WritableReg, 1402 lhs_lo: Reg, 1403 lhs_hi: Reg, 1404 rhs_lo: Reg, 1405 rhs_hi: Reg, 1406 ) -> Result<()>; 1407 1408 /// Performs a widening multiplication from two 64-bit operands into a 1409 /// 128-bit result. 1410 /// 1411 /// Note that some platforms require special handling of registers in this 1412 /// instruction (e.g. x64) so full access to `CodeGenContext` is provided. 1413 fn mul_wide(&mut self, context: &mut CodeGenContext<Emission>, kind: MulWideKind) 1414 -> Result<()>; 1415 1416 /// Takes the value in a src operand and replicates it across lanes of 1417 /// `size` in a destination result. 1418 fn splat(&mut self, context: &mut CodeGenContext<Emission>, size: SplatKind) -> Result<()>; 1419 1420 /// Performs a shuffle between two 128-bit vectors into a 128-bit result 1421 /// using lanes as a mask to select which indexes to copy. 1422 fn shuffle(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, lanes: [u8; 16]) -> Result<()>; 1423 1424 /// Performs a swizzle between two 128-bit vectors into a 128-bit result. 1425 fn swizzle(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg) -> Result<()>; 1426 1427 /// Performs the RMW `op` operation on the passed `addr`. 1428 /// 1429 /// The value *before* the operation was performed is written back to the `operand` register. 1430 fn atomic_rmw( 1431 &mut self, 1432 context: &mut CodeGenContext<Emission>, 1433 addr: Self::Address, 1434 size: OperandSize, 1435 op: RmwOp, 1436 flags: MemFlags, 1437 extend: Option<Extend<Zero>>, 1438 ) -> Result<()>; 1439 1440 /// Extracts the scalar value from `src` in `lane` to `dst`. 1441 fn extract_lane( 1442 &mut self, 1443 src: Reg, 1444 dst: WritableReg, 1445 lane: u8, 1446 kind: ExtractLaneKind, 1447 ) -> Result<()>; 1448 1449 /// Replaces the value in `lane` in `dst` with the value in `src`. 1450 fn replace_lane( 1451 &mut self, 1452 src: RegImm, 1453 dst: WritableReg, 1454 lane: u8, 1455 kind: ReplaceLaneKind, 1456 ) -> Result<()>; 1457 1458 /// Perform an atomic CAS (compare-and-swap) operation with the value at `addr`, and `expected` 1459 /// and `replacement` (at the top of the context's stack). 1460 /// 1461 /// This method takes the `CodeGenContext` as an arguments to accommodate architectures that 1462 /// expect parameters in specific registers. The context stack contains the `replacement`, 1463 /// and `expected` values in that order. The implementer is expected to push the value at 1464 /// `addr` before the update to the context's stack before returning. 1465 fn atomic_cas( 1466 &mut self, 1467 context: &mut CodeGenContext<Emission>, 1468 addr: Self::Address, 1469 size: OperandSize, 1470 flags: MemFlags, 1471 extend: Option<Extend<Zero>>, 1472 ) -> Result<()>; 1473 1474 /// Emit a memory fence. 1475 fn fence(&mut self) -> Result<()>; 1476 } 1477