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