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 cranelift_codegen::{ 8 binemit::CodeOffset, 9 ir::{Endianness, LibCall, MemFlags, RelSourceLoc, SourceLoc, UserExternalNameRef}, 10 Final, MachBufferFinalized, MachLabel, 11 }; 12 use std::{fmt::Debug, ops::Range}; 13 use wasmtime_environ::PtrSize; 14 15 pub(crate) use cranelift_codegen::ir::TrapCode; 16 17 #[derive(Eq, PartialEq)] 18 pub(crate) enum DivKind { 19 /// Signed division. 20 Signed, 21 /// Unsigned division. 22 Unsigned, 23 } 24 25 /// Remainder kind. 26 #[derive(Copy, Clone)] 27 pub(crate) enum RemKind { 28 /// Signed remainder. 29 Signed, 30 /// Unsigned remainder. 31 Unsigned, 32 } 33 34 impl RemKind { 35 pub fn is_signed(&self) -> bool { 36 matches!(self, Self::Signed) 37 } 38 } 39 40 #[derive(Eq, PartialEq)] 41 pub(crate) enum MulWideKind { 42 Signed, 43 Unsigned, 44 } 45 46 /// The direction to perform the memory move. 47 #[derive(Debug, Clone, Eq, PartialEq)] 48 pub(crate) enum MemMoveDirection { 49 /// From high memory addresses to low memory addresses. 50 /// Invariant: the source location is closer to the FP than the destination 51 /// location, which will be closer to the SP. 52 HighToLow, 53 /// From low memory addresses to high memory addresses. 54 /// Invariant: the source location is closer to the SP than the destination 55 /// location, which will be closer to the FP. 56 LowToHigh, 57 } 58 59 /// Classifies how to treat float-to-int conversions. 60 #[derive(Debug, Copy, Clone, Eq, PartialEq)] 61 pub(crate) enum TruncKind { 62 /// Saturating conversion. If the source value is greater than the maximum 63 /// value of the destination type, the result is clamped to the 64 /// destination maximum value. 65 Checked, 66 /// An exception is raised if the source value is greater than the maximum 67 /// value of the destination type. 68 Unchecked, 69 } 70 71 impl TruncKind { 72 /// Returns true if the truncation kind is checked. 73 pub(crate) fn is_checked(&self) -> bool { 74 *self == TruncKind::Checked 75 } 76 } 77 78 /// Representation of the stack pointer offset. 79 #[derive(Copy, Clone, Eq, PartialEq, Debug, PartialOrd, Ord, Default)] 80 pub struct SPOffset(u32); 81 82 impl SPOffset { 83 pub fn from_u32(offs: u32) -> Self { 84 Self(offs) 85 } 86 87 pub fn as_u32(&self) -> u32 { 88 self.0 89 } 90 } 91 92 /// A stack slot. 93 #[derive(Debug, Clone, Copy, Eq, PartialEq)] 94 pub struct StackSlot { 95 /// The location of the slot, relative to the stack pointer. 96 pub offset: SPOffset, 97 /// The size of the slot, in bytes. 98 pub size: u32, 99 } 100 101 impl StackSlot { 102 pub fn new(offs: SPOffset, size: u32) -> Self { 103 Self { offset: offs, size } 104 } 105 } 106 107 /// Kinds of integer binary comparison in WebAssembly. The [`MacroAssembler`] 108 /// implementation for each ISA is responsible for emitting the correct 109 /// sequence of instructions when lowering to machine code. 110 #[derive(Debug, Clone, Copy, Eq, PartialEq)] 111 pub(crate) enum IntCmpKind { 112 /// Equal. 113 Eq, 114 /// Not equal. 115 Ne, 116 /// Signed less than. 117 LtS, 118 /// Unsigned less than. 119 LtU, 120 /// Signed greater than. 121 GtS, 122 /// Unsigned greater than. 123 GtU, 124 /// Signed less than or equal. 125 LeS, 126 /// Unsigned less than or equal. 127 LeU, 128 /// Signed greater than or equal. 129 GeS, 130 /// Unsigned greater than or equal. 131 GeU, 132 } 133 134 /// Kinds of float binary comparison in WebAssembly. The [`MacroAssembler`] 135 /// implementation for each ISA is responsible for emitting the correct 136 /// sequence of instructions when lowering code. 137 #[derive(Debug)] 138 pub(crate) enum FloatCmpKind { 139 /// Equal. 140 Eq, 141 /// Not equal. 142 Ne, 143 /// Less than. 144 Lt, 145 /// Greater than. 146 Gt, 147 /// Less than or equal. 148 Le, 149 /// Greater than or equal. 150 Ge, 151 } 152 153 /// Kinds of shifts in WebAssembly.The [`masm`] implementation for each ISA is 154 /// responsible for emitting the correct sequence of instructions when 155 /// lowering to machine code. 156 #[derive(Debug, Clone, Copy, Eq, PartialEq)] 157 pub(crate) enum ShiftKind { 158 /// Left shift. 159 Shl, 160 /// Signed right shift. 161 ShrS, 162 /// Unsigned right shift. 163 ShrU, 164 /// Left rotate. 165 Rotl, 166 /// Right rotate. 167 Rotr, 168 } 169 170 /// Kinds of extends in WebAssembly. Each MacroAssembler implementation 171 /// is responsible for emitting the correct sequence of instructions when 172 /// lowering to machine code. 173 #[derive(Copy, Clone)] 174 pub(crate) enum ExtendKind { 175 /// Sign extends i32 to i64. 176 I64ExtendI32S, 177 /// Zero extends i32 to i64. 178 I64ExtendI32U, 179 // Sign extends the 8 least significant bits to 32 bits. 180 I32Extend8S, 181 // Sign extends the 16 least significant bits to 32 bits. 182 I32Extend16S, 183 /// Sign extends the 8 least significant bits to 64 bits. 184 I64Extend8S, 185 /// Sign extends the 16 least significant bits to 64 bits. 186 I64Extend16S, 187 /// Sign extends the 32 least significant bits to 64 bits. 188 I64Extend32S, 189 } 190 191 impl ExtendKind { 192 pub fn signed(&self) -> bool { 193 if let Self::I64ExtendI32U = self { 194 false 195 } else { 196 true 197 } 198 } 199 200 pub fn from_bits(&self) -> u8 { 201 match self { 202 Self::I64ExtendI32S | Self::I64ExtendI32U | Self::I64Extend32S => 32, 203 Self::I32Extend8S | Self::I64Extend8S => 8, 204 Self::I32Extend16S | Self::I64Extend16S => 16, 205 } 206 } 207 208 pub fn to_bits(&self) -> u8 { 209 match self { 210 Self::I64ExtendI32S 211 | Self::I64ExtendI32U 212 | Self::I64Extend8S 213 | Self::I64Extend16S 214 | Self::I64Extend32S => 64, 215 Self::I32Extend8S | Self::I32Extend16S => 32, 216 } 217 } 218 } 219 220 /// Operand size, in bits. 221 #[derive(Copy, Debug, Clone, Eq, PartialEq)] 222 pub(crate) enum OperandSize { 223 /// 8 bits. 224 S8, 225 /// 16 bits. 226 S16, 227 /// 32 bits. 228 S32, 229 /// 64 bits. 230 S64, 231 /// 128 bits. 232 S128, 233 } 234 235 impl OperandSize { 236 /// The number of bits in the operand. 237 pub fn num_bits(&self) -> u8 { 238 match self { 239 OperandSize::S8 => 8, 240 OperandSize::S16 => 16, 241 OperandSize::S32 => 32, 242 OperandSize::S64 => 64, 243 OperandSize::S128 => 128, 244 } 245 } 246 247 /// The number of bytes in the operand. 248 pub fn bytes(&self) -> u32 { 249 match self { 250 Self::S8 => 1, 251 Self::S16 => 2, 252 Self::S32 => 4, 253 Self::S64 => 8, 254 Self::S128 => 16, 255 } 256 } 257 258 /// The binary logarithm of the number of bits in the operand. 259 pub fn log2(&self) -> u8 { 260 match self { 261 OperandSize::S8 => 3, 262 OperandSize::S16 => 4, 263 OperandSize::S32 => 5, 264 OperandSize::S64 => 6, 265 OperandSize::S128 => 7, 266 } 267 } 268 269 /// Create an [`OperandSize`] from the given number of bytes. 270 pub fn from_bytes(bytes: u8) -> Self { 271 use OperandSize::*; 272 match bytes { 273 4 => S32, 274 8 => S64, 275 16 => S128, 276 _ => panic!("Invalid bytes {bytes} for OperandSize"), 277 } 278 } 279 } 280 281 /// An abstraction over a register or immediate. 282 #[derive(Copy, Clone, Debug, PartialEq, Eq)] 283 pub(crate) enum RegImm { 284 /// A register. 285 Reg(Reg), 286 /// A tagged immediate argument. 287 Imm(Imm), 288 } 289 290 /// An tagged representation of an immediate. 291 #[derive(Copy, Clone, Debug, PartialEq, Eq)] 292 pub(crate) enum Imm { 293 /// I32 immediate. 294 I32(u32), 295 /// I64 immediate. 296 I64(u64), 297 /// F32 immediate. 298 F32(u32), 299 /// F64 immediate. 300 F64(u64), 301 /// V128 immediate. 302 V128(i128), 303 } 304 305 impl Imm { 306 /// Create a new I64 immediate. 307 pub fn i64(val: i64) -> Self { 308 Self::I64(val as u64) 309 } 310 311 /// Create a new I32 immediate. 312 pub fn i32(val: i32) -> Self { 313 Self::I32(val as u32) 314 } 315 316 /// Create a new F32 immediate. 317 pub fn f32(bits: u32) -> Self { 318 Self::F32(bits) 319 } 320 321 /// Create a new F64 immediate. 322 pub fn f64(bits: u64) -> Self { 323 Self::F64(bits) 324 } 325 326 /// Create a new V128 immediate. 327 pub fn v128(bits: i128) -> Self { 328 Self::V128(bits) 329 } 330 331 /// Convert the immediate to i32, if possible. 332 pub fn to_i32(&self) -> Option<i32> { 333 match self { 334 Self::I32(v) => Some(*v as i32), 335 Self::I64(v) => i32::try_from(*v as i64).ok(), 336 _ => None, 337 } 338 } 339 340 /// Returns true if the [`Imm`] is float. 341 pub fn is_float(&self) -> bool { 342 match self { 343 Self::F32(_) | Self::F64(_) => true, 344 _ => false, 345 } 346 } 347 348 /// Get the operand size of the immediate. 349 pub fn size(&self) -> OperandSize { 350 match self { 351 Self::I32(_) | Self::F32(_) => OperandSize::S32, 352 Self::I64(_) | Self::F64(_) => OperandSize::S64, 353 Self::V128(_) => OperandSize::S128, 354 } 355 } 356 } 357 358 /// The location of the [VMcontext] used for function calls. 359 #[derive(Copy, Clone, Debug, Eq, PartialEq)] 360 pub(crate) enum VMContextLoc { 361 /// Dynamic, stored in the given register. 362 Reg(Reg), 363 /// The pinned [VMContext] register. 364 Pinned, 365 } 366 367 /// The maximum number of context arguments currently used across the compiler. 368 pub(crate) const MAX_CONTEXT_ARGS: usize = 2; 369 370 /// Out-of-band special purpose arguments used for function call emission. 371 /// 372 /// We cannot rely on the value stack for these values given that inserting 373 /// register or memory values at arbitrary locations of the value stack has the 374 /// potential to break the stack ordering principle, which states that older 375 /// values must always precede newer values, effectively simulating the order of 376 /// values in the machine stack. 377 /// The [ContextArgs] are meant to be resolved at every callsite; in some cases 378 /// it might be possible to construct it early on, but given that it might 379 /// contain allocatable registers, it's preferred to construct it in 380 /// [FnCall::emit]. 381 #[derive(Clone, Debug)] 382 pub(crate) enum ContextArgs { 383 /// No context arguments required. This is used for libcalls that don't 384 /// require any special context arguments. For example builtin functions 385 /// that perform float calculations. 386 None, 387 /// A single context argument is required; the current pinned [VMcontext] 388 /// register must be passed as the first argument of the function call. 389 VMContext([VMContextLoc; 1]), 390 /// The callee and caller context arguments are required. In this case, the 391 /// callee context argument is usually stored into an allocatable register 392 /// and the caller is always the current pinned [VMContext] pointer. 393 CalleeAndCallerVMContext([VMContextLoc; MAX_CONTEXT_ARGS]), 394 } 395 396 impl ContextArgs { 397 /// Construct an empty [ContextArgs]. 398 pub fn none() -> Self { 399 Self::None 400 } 401 402 /// Construct a [ContextArgs] declaring the usage of the pinned [VMContext] 403 /// register as both the caller and callee context arguments. 404 pub fn pinned_callee_and_caller_vmctx() -> Self { 405 Self::CalleeAndCallerVMContext([VMContextLoc::Pinned, VMContextLoc::Pinned]) 406 } 407 408 /// Construct a [ContextArgs] that declares the usage of the pinned 409 /// [VMContext] register as the only context argument. 410 pub fn pinned_vmctx() -> Self { 411 Self::VMContext([VMContextLoc::Pinned]) 412 } 413 414 /// Construct a [ContextArgs] that declares a dynamic callee context and the 415 /// pinned [VMContext] register as the context arguments. 416 pub fn with_callee_and_pinned_caller(callee_vmctx: Reg) -> Self { 417 Self::CalleeAndCallerVMContext([VMContextLoc::Reg(callee_vmctx), VMContextLoc::Pinned]) 418 } 419 420 /// Get the length of the [ContextArgs]. 421 pub fn len(&self) -> usize { 422 self.as_slice().len() 423 } 424 425 /// Get a slice of the context arguments. 426 pub fn as_slice(&self) -> &[VMContextLoc] { 427 match self { 428 Self::None => &[], 429 Self::VMContext(a) => a.as_slice(), 430 Self::CalleeAndCallerVMContext(a) => a.as_slice(), 431 } 432 } 433 } 434 435 #[derive(Copy, Clone, Debug)] 436 pub(crate) enum CalleeKind { 437 /// A function call to a raw address. 438 Indirect(Reg), 439 /// A function call to a local function. 440 Direct(UserExternalNameRef), 441 /// Call to a well known LibCall. 442 LibCall(LibCall), 443 } 444 445 impl CalleeKind { 446 /// Creates a callee kind from a register. 447 pub fn indirect(reg: Reg) -> Self { 448 Self::Indirect(reg) 449 } 450 451 /// Creates a direct callee kind from a function name. 452 pub fn direct(name: UserExternalNameRef) -> Self { 453 Self::Direct(name) 454 } 455 456 /// Creates a known callee kind from a libcall. 457 pub fn libcall(call: LibCall) -> Self { 458 Self::LibCall(call) 459 } 460 } 461 462 impl RegImm { 463 /// Register constructor. 464 pub fn reg(r: Reg) -> Self { 465 RegImm::Reg(r) 466 } 467 468 /// I64 immediate constructor. 469 pub fn i64(val: i64) -> Self { 470 RegImm::Imm(Imm::i64(val)) 471 } 472 473 /// I32 immediate constructor. 474 pub fn i32(val: i32) -> Self { 475 RegImm::Imm(Imm::i32(val)) 476 } 477 478 /// F32 immediate, stored using its bits representation. 479 pub fn f32(bits: u32) -> Self { 480 RegImm::Imm(Imm::f32(bits)) 481 } 482 483 /// F64 immediate, stored using its bits representation. 484 pub fn f64(bits: u64) -> Self { 485 RegImm::Imm(Imm::f64(bits)) 486 } 487 488 /// V128 immediate. 489 pub fn v128(bits: i128) -> Self { 490 RegImm::Imm(Imm::v128(bits)) 491 } 492 } 493 494 impl From<Reg> for RegImm { 495 fn from(r: Reg) -> Self { 496 Self::Reg(r) 497 } 498 } 499 500 #[derive(Debug)] 501 pub enum RoundingMode { 502 Nearest, 503 Up, 504 Down, 505 Zero, 506 } 507 508 /// Memory flags for trusted loads/stores. 509 pub const TRUSTED_FLAGS: MemFlags = MemFlags::trusted(); 510 511 /// Flags used for WebAssembly loads / stores. 512 /// Untrusted by default so we don't set `no_trap`. 513 /// We also ensure that the endianness is the right one for WebAssembly. 514 pub const UNTRUSTED_FLAGS: MemFlags = MemFlags::new().with_endianness(Endianness::Little); 515 516 /// Generic MacroAssembler interface used by the code generation. 517 /// 518 /// The MacroAssembler trait aims to expose an interface, high-level enough, 519 /// so that each ISA can provide its own lowering to machine code. For example, 520 /// for WebAssembly operators that don't have a direct mapping to a machine 521 /// a instruction, the interface defines a signature matching the WebAssembly 522 /// operator, allowing each implementation to lower such operator entirely. 523 /// This approach attributes more responsibility to the MacroAssembler, but frees 524 /// the caller from concerning about assembling the right sequence of 525 /// instructions at the operator callsite. 526 /// 527 /// The interface defaults to a three-argument form for binary operations; 528 /// this allows a natural mapping to instructions for RISC architectures, 529 /// that use three-argument form. 530 /// This approach allows for a more general interface that can be restricted 531 /// where needed, in the case of architectures that use a two-argument form. 532 533 pub(crate) trait MacroAssembler { 534 /// The addressing mode. 535 type Address: Copy + Debug; 536 537 /// The pointer representation of the target ISA, 538 /// used to access information from [`VMOffsets`]. 539 type Ptr: PtrSize; 540 541 /// The ABI details of the target. 542 type ABI: abi::ABI; 543 544 /// Emit the function prologue. 545 fn prologue(&mut self, vmctx: Reg) { 546 self.frame_setup(); 547 self.check_stack(vmctx); 548 } 549 550 /// Generate the frame setup sequence. 551 fn frame_setup(&mut self); 552 553 /// Generate the frame restore sequence. 554 fn frame_restore(&mut self); 555 556 /// Emit a stack check. 557 fn check_stack(&mut self, vmctx: Reg); 558 559 /// Emit the function epilogue. 560 fn epilogue(&mut self) { 561 self.frame_restore(); 562 } 563 564 /// Reserve stack space. 565 fn reserve_stack(&mut self, bytes: u32); 566 567 /// Free stack space. 568 fn free_stack(&mut self, bytes: u32); 569 570 /// Reset the stack pointer to the given offset; 571 /// 572 /// Used to reset the stack pointer to a given offset 573 /// when dealing with unreachable code. 574 fn reset_stack_pointer(&mut self, offset: SPOffset); 575 576 /// Get the address of a local slot. 577 fn local_address(&mut self, local: &LocalSlot) -> Self::Address; 578 579 /// Constructs an address with an offset that is relative to the 580 /// current position of the stack pointer (e.g. [sp + (sp_offset - 581 /// offset)]. 582 fn address_from_sp(&self, offset: SPOffset) -> Self::Address; 583 584 /// Constructs an address with an offset that is absolute to the 585 /// current position of the stack pointer (e.g. [sp + offset]. 586 fn address_at_sp(&self, offset: SPOffset) -> Self::Address; 587 588 /// Alias for [`Self::address_at_reg`] using the VMContext register as 589 /// a base. The VMContext register is derived from the ABI type that is 590 /// associated to the MacroAssembler. 591 fn address_at_vmctx(&self, offset: u32) -> Self::Address; 592 593 /// Construct an address that is absolute to the current position 594 /// of the given register. 595 fn address_at_reg(&self, reg: Reg, offset: u32) -> Self::Address; 596 597 /// Emit a function call to either a local or external function. 598 fn call( 599 &mut self, 600 stack_args_size: u32, 601 f: impl FnMut(&mut Self) -> (CalleeKind, CallingConvention), 602 ) -> u32; 603 604 /// Get stack pointer offset. 605 fn sp_offset(&self) -> SPOffset; 606 607 /// Perform a stack store. 608 fn store(&mut self, src: RegImm, dst: Self::Address, size: OperandSize); 609 610 /// Alias for `MacroAssembler::store` with the operand size corresponding 611 /// to the pointer size of the target. 612 fn store_ptr(&mut self, src: Reg, dst: Self::Address); 613 614 /// Perform a WebAssembly store. 615 /// A WebAssembly store introduces several additional invariants compared to 616 /// [Self::store], more precisely, it can implicitly trap, in certain 617 /// circumstances, even if explicit bounds checks are elided, in that sense, 618 /// we consider this type of load as untrusted. It can also differ with 619 /// regards to the endianness depending on the target ISA. For this reason, 620 /// [Self::wasm_store], should be explicitly used when emitting WebAssembly 621 /// stores. 622 fn wasm_store(&mut self, src: Reg, dst: Self::Address, size: OperandSize); 623 624 /// Perform a zero-extended stack load. 625 fn load(&mut self, src: Self::Address, dst: WritableReg, size: OperandSize); 626 627 /// Perform a WebAssembly load. 628 /// A WebAssembly load introduces several additional invariants compared to 629 /// [Self::load], more precisely, it can implicitly trap, in certain 630 /// circumstances, even if explicit bounds checks are elided, in that sense, 631 /// we consider this type of load as untrusted. It can also differ with 632 /// regards to the endianness depending on the target ISA. For this reason, 633 /// [Self::wasm_load], should be explicitly used when emitting WebAssembly 634 /// loads. 635 fn wasm_load( 636 &mut self, 637 src: Self::Address, 638 dst: WritableReg, 639 size: OperandSize, 640 kind: Option<ExtendKind>, 641 ); 642 643 /// Alias for `MacroAssembler::load` with the operand size corresponding 644 /// to the pointer size of the target. 645 fn load_ptr(&mut self, src: Self::Address, dst: WritableReg); 646 647 /// Loads the effective address into destination. 648 fn load_addr(&mut self, _src: Self::Address, _dst: WritableReg, _size: OperandSize); 649 650 /// Pop a value from the machine stack into the given register. 651 fn pop(&mut self, dst: WritableReg, size: OperandSize); 652 653 /// Perform a move. 654 fn mov(&mut self, dst: WritableReg, src: RegImm, size: OperandSize); 655 656 /// Perform a conditional move. 657 fn cmov(&mut self, dst: WritableReg, src: Reg, cc: IntCmpKind, size: OperandSize); 658 659 /// Performs a memory move of bytes from src to dest. 660 /// Bytes are moved in blocks of 8 bytes, where possible. 661 fn memmove(&mut self, src: SPOffset, dst: SPOffset, bytes: u32, direction: MemMoveDirection) { 662 match direction { 663 MemMoveDirection::LowToHigh => debug_assert!(dst.as_u32() < src.as_u32()), 664 MemMoveDirection::HighToLow => debug_assert!(dst.as_u32() > src.as_u32()), 665 } 666 // At least 4 byte aligned. 667 debug_assert!(bytes % 4 == 0); 668 let mut remaining = bytes; 669 let word_bytes = <Self::ABI as abi::ABI>::word_bytes(); 670 let scratch = scratch!(Self); 671 672 let mut dst_offs = dst.as_u32() - bytes; 673 let mut src_offs = src.as_u32() - bytes; 674 675 let word_bytes = word_bytes as u32; 676 while remaining >= word_bytes { 677 remaining -= word_bytes; 678 dst_offs += word_bytes; 679 src_offs += word_bytes; 680 681 self.load_ptr( 682 self.address_from_sp(SPOffset::from_u32(src_offs)), 683 writable!(scratch), 684 ); 685 self.store_ptr( 686 scratch.into(), 687 self.address_from_sp(SPOffset::from_u32(dst_offs)), 688 ); 689 } 690 691 if remaining > 0 { 692 let half_word = word_bytes / 2; 693 let ptr_size = OperandSize::from_bytes(half_word as u8); 694 debug_assert!(remaining == half_word); 695 dst_offs += half_word; 696 src_offs += half_word; 697 698 self.load( 699 self.address_from_sp(SPOffset::from_u32(src_offs)), 700 writable!(scratch), 701 ptr_size, 702 ); 703 self.store( 704 scratch.into(), 705 self.address_from_sp(SPOffset::from_u32(dst_offs)), 706 ptr_size, 707 ); 708 } 709 } 710 711 /// Perform add operation. 712 fn add(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize); 713 714 /// Perform a checked unsigned integer addition, emitting the provided trap 715 /// if the addition overflows. 716 fn checked_uadd( 717 &mut self, 718 dst: WritableReg, 719 lhs: Reg, 720 rhs: RegImm, 721 size: OperandSize, 722 trap: TrapCode, 723 ); 724 725 /// Perform subtraction operation. 726 fn sub(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize); 727 728 /// Perform multiplication operation. 729 fn mul(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize); 730 731 /// Perform a floating point add operation. 732 fn float_add(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize); 733 734 /// Perform a floating point subtraction operation. 735 fn float_sub(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize); 736 737 /// Perform a floating point multiply operation. 738 fn float_mul(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize); 739 740 /// Perform a floating point divide operation. 741 fn float_div(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize); 742 743 /// Perform a floating point minimum operation. In x86, this will emit 744 /// multiple instructions. 745 fn float_min(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize); 746 747 /// Perform a floating point maximum operation. In x86, this will emit 748 /// multiple instructions. 749 fn float_max(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize); 750 751 /// Perform a floating point copysign operation. In x86, this will emit 752 /// multiple instructions. 753 fn float_copysign(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize); 754 755 /// Perform a floating point abs operation. 756 fn float_abs(&mut self, dst: WritableReg, size: OperandSize); 757 758 /// Perform a floating point negation operation. 759 fn float_neg(&mut self, dst: WritableReg, size: OperandSize); 760 761 /// Perform a floating point floor operation. 762 fn float_round<F: FnMut(&mut FuncEnv<Self::Ptr>, &mut CodeGenContext<Emission>, &mut Self)>( 763 &mut self, 764 mode: RoundingMode, 765 env: &mut FuncEnv<Self::Ptr>, 766 context: &mut CodeGenContext<Emission>, 767 size: OperandSize, 768 fallback: F, 769 ); 770 771 /// Perform a floating point square root operation. 772 fn float_sqrt(&mut self, dst: WritableReg, src: Reg, size: OperandSize); 773 774 /// Perform logical and operation. 775 fn and(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize); 776 777 /// Perform logical or operation. 778 fn or(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize); 779 780 /// Perform logical exclusive or operation. 781 fn xor(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize); 782 783 /// Perform a shift operation between a register and an immediate. 784 fn shift_ir( 785 &mut self, 786 dst: WritableReg, 787 imm: u64, 788 lhs: Reg, 789 kind: ShiftKind, 790 size: OperandSize, 791 ); 792 793 /// Perform a shift operation between two registers. 794 /// This case is special in that some architectures have specific expectations 795 /// regarding the location of the instruction arguments. To free the 796 /// caller from having to deal with the architecture specific constraints 797 /// we give this function access to the code generation context, allowing 798 /// each implementation to decide the lowering path. 799 fn shift(&mut self, context: &mut CodeGenContext<Emission>, kind: ShiftKind, size: OperandSize); 800 801 /// Perform division operation. 802 /// Division is special in that some architectures have specific 803 /// expectations regarding the location of the instruction 804 /// arguments and regarding the location of the quotient / 805 /// remainder. To free the caller from having to deal with the 806 /// architecture specific constraints we give this function access 807 /// to the code generation context, allowing each implementation 808 /// to decide the lowering path. For cases in which division is a 809 /// unconstrained binary operation, the caller can decide to use 810 /// the `CodeGenContext::i32_binop` or `CodeGenContext::i64_binop` 811 /// functions. 812 fn div(&mut self, context: &mut CodeGenContext<Emission>, kind: DivKind, size: OperandSize); 813 814 /// Calculate remainder. 815 fn rem(&mut self, context: &mut CodeGenContext<Emission>, kind: RemKind, size: OperandSize); 816 817 /// Compares `src1` against `src2` for the side effect of setting processor 818 /// flags. 819 /// 820 /// Note that `src1` is the left-hand-side of the comparison and `src2` is 821 /// the right-hand-side, so if testing `a < b` then `src1 == a` and 822 /// `src2 == b` 823 fn cmp(&mut self, src1: Reg, src2: RegImm, size: OperandSize); 824 825 /// Compare src and dst and put the result in dst. 826 /// This function will potentially emit a series of instructions. 827 /// 828 /// The initial value in `dst` is the left-hand-side of the comparison and 829 /// the initial value in `src` is the right-hand-side of the comparison. 830 /// That means for `a < b` then `dst == a` and `src == b`. 831 fn cmp_with_set(&mut self, dst: WritableReg, src: RegImm, kind: IntCmpKind, size: OperandSize); 832 833 /// Compare floats in src1 and src2 and put the result in dst. 834 /// In x86, this will emit multiple instructions. 835 fn float_cmp_with_set( 836 &mut self, 837 dst: WritableReg, 838 src1: Reg, 839 src2: Reg, 840 kind: FloatCmpKind, 841 size: OperandSize, 842 ); 843 844 /// Count the number of leading zeroes in src and put the result in dst. 845 /// In x64, this will emit multiple instructions if the `has_lzcnt` flag is 846 /// false. 847 fn clz(&mut self, dst: WritableReg, src: Reg, size: OperandSize); 848 849 /// Count the number of trailing zeroes in src and put the result in dst.masm 850 /// In x64, this will emit multiple instructions if the `has_tzcnt` flag is 851 /// false. 852 fn ctz(&mut self, dst: WritableReg, src: Reg, size: OperandSize); 853 854 /// Push the register to the stack, returning the stack slot metadata. 855 // NB 856 // The stack alignment should not be assumed after any call to `push`, 857 // unless explicitly aligned otherwise. Typically, stack alignment is 858 // maintained at call sites and during the execution of 859 // epilogues. 860 fn push(&mut self, src: Reg, size: OperandSize) -> StackSlot; 861 862 /// Finalize the assembly and return the result. 863 fn finalize(self, base: Option<SourceLoc>) -> MachBufferFinalized<Final>; 864 865 /// Zero a particular register. 866 fn zero(&mut self, reg: WritableReg); 867 868 /// Count the number of 1 bits in src and put the result in dst. In x64, 869 /// this will emit multiple instructions if the `has_popcnt` flag is false. 870 fn popcnt(&mut self, context: &mut CodeGenContext<Emission>, size: OperandSize); 871 872 /// Converts an i64 to an i32 by discarding the high 32 bits. 873 fn wrap(&mut self, dst: WritableReg, src: Reg); 874 875 /// Extends an integer of a given size to a larger size. 876 fn extend(&mut self, dst: WritableReg, src: Reg, kind: ExtendKind); 877 878 /// Emits one or more instructions to perform a signed truncation of a 879 /// float into an integer. 880 fn signed_truncate( 881 &mut self, 882 dst: WritableReg, 883 src: Reg, 884 src_size: OperandSize, 885 dst_size: OperandSize, 886 kind: TruncKind, 887 ); 888 889 /// Emits one or more instructions to perform an unsigned truncation of a 890 /// float into an integer. 891 fn unsigned_truncate( 892 &mut self, 893 dst: WritableReg, 894 src: Reg, 895 tmp_fpr: Reg, 896 src_size: OperandSize, 897 dst_size: OperandSize, 898 kind: TruncKind, 899 ); 900 901 /// Emits one or more instructions to perform a signed convert of an 902 /// integer into a float. 903 fn signed_convert( 904 &mut self, 905 dst: WritableReg, 906 src: Reg, 907 src_size: OperandSize, 908 dst_size: OperandSize, 909 ); 910 911 /// Emits one or more instructions to perform an unsigned convert of an 912 /// integer into a float. 913 fn unsigned_convert( 914 &mut self, 915 dst: WritableReg, 916 src: Reg, 917 tmp_gpr: Reg, 918 src_size: OperandSize, 919 dst_size: OperandSize, 920 ); 921 922 /// Reinterpret a float as an integer. 923 fn reinterpret_float_as_int(&mut self, dst: WritableReg, src: Reg, size: OperandSize); 924 925 /// Reinterpret an integer as a float. 926 fn reinterpret_int_as_float(&mut self, dst: WritableReg, src: Reg, size: OperandSize); 927 928 /// Demote an f64 to an f32. 929 fn demote(&mut self, dst: WritableReg, src: Reg); 930 931 /// Promote an f32 to an f64. 932 fn promote(&mut self, dst: WritableReg, src: Reg); 933 934 /// Zero a given memory range. 935 /// 936 /// The default implementation divides the given memory range 937 /// into word-sized slots. Then it unrolls a series of store 938 /// instructions, effectively assigning zero to each slot. 939 fn zero_mem_range(&mut self, mem: &Range<u32>) { 940 let word_size = <Self::ABI as abi::ABI>::word_bytes() as u32; 941 if mem.is_empty() { 942 return; 943 } 944 945 let start = if mem.start % word_size == 0 { 946 mem.start 947 } else { 948 // Ensure that the start of the range is at least 4-byte aligned. 949 assert!(mem.start % 4 == 0); 950 let start = align_to(mem.start, word_size); 951 let addr: Self::Address = self.local_address(&LocalSlot::i32(start)); 952 self.store(RegImm::i32(0), addr, OperandSize::S32); 953 // Ensure that the new start of the range, is word-size aligned. 954 assert!(start % word_size == 0); 955 start 956 }; 957 958 let end = align_to(mem.end, word_size); 959 let slots = (end - start) / word_size; 960 961 if slots == 1 { 962 let slot = LocalSlot::i64(start + word_size); 963 let addr: Self::Address = self.local_address(&slot); 964 self.store(RegImm::i64(0), addr, OperandSize::S64); 965 } else { 966 // TODO 967 // Add an upper bound to this generation; 968 // given a considerably large amount of slots 969 // this will be inefficient. 970 let zero = scratch!(Self); 971 self.zero(writable!(zero)); 972 let zero = RegImm::reg(zero); 973 974 for step in (start..end).into_iter().step_by(word_size as usize) { 975 let slot = LocalSlot::i64(step + word_size); 976 let addr: Self::Address = self.local_address(&slot); 977 self.store(zero, addr, OperandSize::S64); 978 } 979 } 980 } 981 982 /// Generate a label. 983 fn get_label(&mut self) -> MachLabel; 984 985 /// Bind the given label at the current code offset. 986 fn bind(&mut self, label: MachLabel); 987 988 /// Conditional branch. 989 /// 990 /// Performs a comparison between the two operands, 991 /// and immediately after emits a jump to the given 992 /// label destination if the condition is met. 993 fn branch( 994 &mut self, 995 kind: IntCmpKind, 996 lhs: Reg, 997 rhs: RegImm, 998 taken: MachLabel, 999 size: OperandSize, 1000 ); 1001 1002 /// Emits and unconditional jump to the given label. 1003 fn jmp(&mut self, target: MachLabel); 1004 1005 /// Emits a jump table sequence. The default label is specified as 1006 /// the last element of the targets slice. 1007 fn jmp_table(&mut self, targets: &[MachLabel], index: Reg, tmp: Reg); 1008 1009 /// Emit an unreachable code trap. 1010 fn unreachable(&mut self); 1011 1012 /// Emit an unconditional trap. 1013 fn trap(&mut self, code: TrapCode); 1014 1015 /// Traps if the condition code is met. 1016 fn trapif(&mut self, cc: IntCmpKind, code: TrapCode); 1017 1018 /// Trap if the source register is zero. 1019 fn trapz(&mut self, src: Reg, code: TrapCode); 1020 1021 /// Ensures that the stack pointer is correctly positioned before an unconditional 1022 /// jump according to the requirements of the destination target. 1023 fn ensure_sp_for_jump(&mut self, target: SPOffset) { 1024 let bytes = self 1025 .sp_offset() 1026 .as_u32() 1027 .checked_sub(target.as_u32()) 1028 .unwrap_or(0); 1029 if bytes > 0 { 1030 self.free_stack(bytes); 1031 } 1032 } 1033 1034 /// Mark the start of a source location returning the machine code offset 1035 /// and the relative source code location. 1036 fn start_source_loc(&mut self, loc: RelSourceLoc) -> (CodeOffset, RelSourceLoc); 1037 1038 /// Mark the end of a source location. 1039 fn end_source_loc(&mut self); 1040 1041 /// The current offset, in bytes from the beginning of the function. 1042 fn current_code_offset(&self) -> CodeOffset; 1043 1044 /// Performs a 128-bit addition 1045 fn add128( 1046 &mut self, 1047 dst_lo: WritableReg, 1048 dst_hi: WritableReg, 1049 lhs_lo: Reg, 1050 lhs_hi: Reg, 1051 rhs_lo: Reg, 1052 rhs_hi: Reg, 1053 ); 1054 1055 /// Performs a 128-bit subtraction 1056 fn sub128( 1057 &mut self, 1058 dst_lo: WritableReg, 1059 dst_hi: WritableReg, 1060 lhs_lo: Reg, 1061 lhs_hi: Reg, 1062 rhs_lo: Reg, 1063 rhs_hi: Reg, 1064 ); 1065 1066 /// Performs a widening multiplication from two 64-bit operands into a 1067 /// 128-bit result. 1068 /// 1069 /// Note that some platforms require special handling of registers in this 1070 /// instruction (e.g. x64) so full access to `CodeGenContext` is provided. 1071 fn mul_wide(&mut self, context: &mut CodeGenContext<Emission>, kind: MulWideKind); 1072 } 1073