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