1 use crate::abi::{self, LocalSlot, align_to}; 2 use crate::codegen::{CodeGenContext, Emission, FuncEnv}; 3 use crate::isa::{ 4 CallingConvention, 5 reg::{Reg, RegClass, WritableReg, writable}, 6 }; 7 use anyhow::Result; 8 use cranelift_codegen::{ 9 Final, MachBufferFinalized, MachLabel, 10 binemit::CodeOffset, 11 ir::{Endianness, MemFlags, RelSourceLoc, SourceLoc, UserExternalNameRef}, 12 }; 13 use std::{fmt::Debug, ops::Range}; 14 use wasmtime_environ::{PtrSize, WasmHeapType, WasmRefType, WasmValType}; 15 16 pub(crate) use cranelift_codegen::ir::TrapCode; 17 18 #[derive(Eq, PartialEq)] 19 pub(crate) enum DivKind { 20 /// Signed division. 21 Signed, 22 /// Unsigned division. 23 Unsigned, 24 } 25 26 /// Represents the `memory.atomic.wait*` kind. 27 #[derive(Debug, Clone, Copy)] 28 pub(crate) enum AtomicWaitKind { 29 Wait32, 30 Wait64, 31 } 32 33 /// Remainder kind. 34 #[derive(Copy, Clone)] 35 pub(crate) enum RemKind { 36 /// Signed remainder. 37 Signed, 38 /// Unsigned remainder. 39 Unsigned, 40 } 41 42 impl RemKind { 43 pub fn is_signed(&self) -> bool { 44 matches!(self, Self::Signed) 45 } 46 } 47 48 /// Kinds of vector min operation supported by WebAssembly. 49 pub(crate) enum V128MinKind { 50 /// 4 lanes of 32-bit floats. 51 F32x4, 52 /// 2 lanes of 64-bit floats. 53 F64x2, 54 /// 16 lanes of signed 8-bit integers. 55 I8x16S, 56 /// 16 lanes of unsigned 8-bit integers. 57 I8x16U, 58 /// 8 lanes of signed 16-bit integers. 59 I16x8S, 60 /// 8 lanes of unsigned 16-bit integers. 61 I16x8U, 62 /// 4 lanes of signed 32-bit integers. 63 I32x4S, 64 /// 4 lanes of unsigned 32-bit integers. 65 I32x4U, 66 } 67 68 impl V128MinKind { 69 /// The size of each lane. 70 pub(crate) fn lane_size(&self) -> OperandSize { 71 match self { 72 Self::F32x4 | Self::I32x4S | Self::I32x4U => OperandSize::S32, 73 Self::F64x2 => OperandSize::S64, 74 Self::I8x16S | Self::I8x16U => OperandSize::S8, 75 Self::I16x8S | Self::I16x8U => OperandSize::S16, 76 } 77 } 78 } 79 80 /// Kinds of vector max operation supported by WebAssembly. 81 pub(crate) enum V128MaxKind { 82 /// 4 lanes of 32-bit floats. 83 F32x4, 84 /// 2 lanes of 64-bit floats. 85 F64x2, 86 /// 16 lanes of signed 8-bit integers. 87 I8x16S, 88 /// 16 lanes of unsigned 8-bit integers. 89 I8x16U, 90 /// 8 lanes of signed 16-bit integers. 91 I16x8S, 92 /// 8 lanes of unsigned 16-bit integers. 93 I16x8U, 94 /// 4 lanes of signed 32-bit integers. 95 I32x4S, 96 /// 4 lanes of unsigned 32-bit integers. 97 I32x4U, 98 } 99 100 impl V128MaxKind { 101 /// The size of each lane. 102 pub(crate) fn lane_size(&self) -> OperandSize { 103 match self { 104 Self::F32x4 | Self::I32x4S | Self::I32x4U => OperandSize::S32, 105 Self::F64x2 => OperandSize::S64, 106 Self::I8x16S | Self::I8x16U => OperandSize::S8, 107 Self::I16x8S | Self::I16x8U => OperandSize::S16, 108 } 109 } 110 } 111 112 #[derive(Eq, PartialEq)] 113 pub(crate) enum MulWideKind { 114 Signed, 115 Unsigned, 116 } 117 118 /// Type of operation for a read-modify-write instruction. 119 pub(crate) enum RmwOp { 120 Add, 121 Sub, 122 Xchg, 123 And, 124 Or, 125 Xor, 126 } 127 128 /// The direction to perform the memory move. 129 #[derive(Debug, Clone, Eq, PartialEq)] 130 pub(crate) enum MemMoveDirection { 131 /// From high memory addresses to low memory addresses. 132 /// Invariant: the source location is closer to the FP than the destination 133 /// location, which will be closer to the SP. 134 HighToLow, 135 /// From low memory addresses to high memory addresses. 136 /// Invariant: the source location is closer to the SP than the destination 137 /// location, which will be closer to the FP. 138 LowToHigh, 139 } 140 141 /// Classifies how to treat float-to-int conversions. 142 #[derive(Debug, Copy, Clone, Eq, PartialEq)] 143 pub(crate) enum TruncKind { 144 /// Saturating conversion. If the source value is greater than the maximum 145 /// value of the destination type, the result is clamped to the 146 /// destination maximum value. 147 Checked, 148 /// An exception is raised if the source value is greater than the maximum 149 /// value of the destination type. 150 Unchecked, 151 } 152 153 impl TruncKind { 154 /// Returns true if the truncation kind is checked. 155 pub(crate) fn is_checked(&self) -> bool { 156 *self == TruncKind::Checked 157 } 158 159 /// Returns `true` if the trunc kind is [`Unchecked`]. 160 /// 161 /// [`Unchecked`]: TruncKind::Unchecked 162 #[must_use] 163 pub(crate) fn is_unchecked(&self) -> bool { 164 matches!(self, Self::Unchecked) 165 } 166 } 167 168 /// Representation of the stack pointer offset. 169 #[derive(Copy, Clone, Eq, PartialEq, Debug, PartialOrd, Ord, Default)] 170 pub struct SPOffset(u32); 171 172 impl SPOffset { 173 pub fn from_u32(offs: u32) -> Self { 174 Self(offs) 175 } 176 177 pub fn as_u32(&self) -> u32 { 178 self.0 179 } 180 } 181 182 /// A stack slot. 183 #[derive(Debug, Clone, Copy, Eq, PartialEq)] 184 pub struct StackSlot { 185 /// The location of the slot, relative to the stack pointer. 186 pub offset: SPOffset, 187 /// The size of the slot, in bytes. 188 pub size: u32, 189 } 190 191 impl StackSlot { 192 pub fn new(offs: SPOffset, size: u32) -> Self { 193 Self { offset: offs, size } 194 } 195 } 196 197 pub trait ScratchType { 198 /// Derive the register class from the scratch register type. 199 fn reg_class() -> RegClass; 200 } 201 202 /// A scratch register type of integer class. 203 pub struct IntScratch; 204 /// A scratch register type of floating point class. 205 pub struct FloatScratch; 206 207 impl ScratchType for IntScratch { 208 fn reg_class() -> RegClass { 209 RegClass::Int 210 } 211 } 212 213 impl ScratchType for FloatScratch { 214 fn reg_class() -> RegClass { 215 RegClass::Float 216 } 217 } 218 219 /// A scratch register scope. 220 pub struct Scratch(Reg); 221 222 impl Scratch { 223 pub fn new(r: Reg) -> Self { 224 Self(r) 225 } 226 227 #[inline] 228 pub fn inner(&self) -> Reg { 229 self.0 230 } 231 232 #[inline] 233 pub fn writable(&self) -> WritableReg { 234 writable!(self.0) 235 } 236 } 237 238 /// Kinds of integer binary comparison in WebAssembly. The [`MacroAssembler`] 239 /// implementation for each ISA is responsible for emitting the correct 240 /// sequence of instructions when lowering to machine code. 241 #[derive(Debug, Clone, Copy, Eq, PartialEq)] 242 pub(crate) enum IntCmpKind { 243 /// Equal. 244 Eq, 245 /// Not equal. 246 Ne, 247 /// Signed less than. 248 LtS, 249 /// Unsigned less than. 250 LtU, 251 /// Signed greater than. 252 GtS, 253 /// Unsigned greater than. 254 GtU, 255 /// Signed less than or equal. 256 LeS, 257 /// Unsigned less than or equal. 258 LeU, 259 /// Signed greater than or equal. 260 GeS, 261 /// Unsigned greater than or equal. 262 GeU, 263 } 264 265 /// Kinds of float binary comparison in WebAssembly. The [`MacroAssembler`] 266 /// implementation for each ISA is responsible for emitting the correct 267 /// sequence of instructions when lowering code. 268 #[derive(Debug)] 269 pub(crate) enum FloatCmpKind { 270 /// Equal. 271 Eq, 272 /// Not equal. 273 Ne, 274 /// Less than. 275 Lt, 276 /// Greater than. 277 Gt, 278 /// Less than or equal. 279 Le, 280 /// Greater than or equal. 281 Ge, 282 } 283 284 /// Kinds of shifts in WebAssembly.The [`masm`] implementation for each ISA is 285 /// responsible for emitting the correct sequence of instructions when 286 /// lowering to machine code. 287 #[derive(Debug, Clone, Copy, Eq, PartialEq)] 288 pub(crate) enum ShiftKind { 289 /// Left shift. 290 Shl, 291 /// Signed right shift. 292 ShrS, 293 /// Unsigned right shift. 294 ShrU, 295 /// Left rotate. 296 Rotl, 297 /// Right rotate. 298 Rotr, 299 } 300 301 /// Kinds of extends in WebAssembly. Each MacroAssembler implementation 302 /// is responsible for emitting the correct sequence of instructions when 303 /// lowering to machine code. 304 #[derive(Copy, Clone)] 305 pub(crate) enum ExtendKind { 306 Signed(Extend<Signed>), 307 Unsigned(Extend<Zero>), 308 } 309 310 #[derive(Copy, Clone)] 311 pub(crate) enum Signed {} 312 #[derive(Copy, Clone)] 313 pub(crate) enum Zero {} 314 315 pub(crate) trait ExtendType {} 316 317 impl ExtendType for Signed {} 318 impl ExtendType for Zero {} 319 320 #[derive(Copy, Clone)] 321 pub(crate) enum Extend<T: ExtendType> { 322 /// 8 to 32 bit extend. 323 I32Extend8, 324 /// 16 to 32 bit extend. 325 I32Extend16, 326 /// 8 to 64 bit extend. 327 I64Extend8, 328 /// 16 to 64 bit extend. 329 I64Extend16, 330 /// 32 to 64 bit extend. 331 I64Extend32, 332 333 /// Variant to hold the kind of extend marker. 334 /// 335 /// This is `Signed` or `Zero`, that are empty enums, which means that this variant cannot be 336 /// constructed. 337 __Kind(T), 338 } 339 340 impl From<Extend<Zero>> for ExtendKind { 341 fn from(value: Extend<Zero>) -> Self { 342 ExtendKind::Unsigned(value) 343 } 344 } 345 346 impl<T: ExtendType> Extend<T> { 347 pub fn from_size(&self) -> OperandSize { 348 match self { 349 Extend::I32Extend8 | Extend::I64Extend8 => OperandSize::S8, 350 Extend::I32Extend16 | Extend::I64Extend16 => OperandSize::S16, 351 Extend::I64Extend32 => OperandSize::S32, 352 Extend::__Kind(_) => unreachable!(), 353 } 354 } 355 356 pub fn to_size(&self) -> OperandSize { 357 match self { 358 Extend::I32Extend8 | Extend::I32Extend16 => OperandSize::S32, 359 Extend::I64Extend8 | Extend::I64Extend16 | Extend::I64Extend32 => OperandSize::S64, 360 Extend::__Kind(_) => unreachable!(), 361 } 362 } 363 364 pub fn from_bits(&self) -> u8 { 365 self.from_size().num_bits() 366 } 367 368 pub fn to_bits(&self) -> u8 { 369 self.to_size().num_bits() 370 } 371 } 372 373 impl From<Extend<Signed>> for ExtendKind { 374 fn from(value: Extend<Signed>) -> Self { 375 ExtendKind::Signed(value) 376 } 377 } 378 379 impl ExtendKind { 380 pub fn signed(&self) -> bool { 381 match self { 382 Self::Signed(_) => true, 383 _ => false, 384 } 385 } 386 387 pub fn from_bits(&self) -> u8 { 388 match self { 389 Self::Signed(s) => s.from_bits(), 390 Self::Unsigned(u) => u.from_bits(), 391 } 392 } 393 394 pub fn to_bits(&self) -> u8 { 395 match self { 396 Self::Signed(s) => s.to_bits(), 397 Self::Unsigned(u) => u.to_bits(), 398 } 399 } 400 } 401 402 /// Kinds of vector load and extends in WebAssembly. Each MacroAssembler 403 /// implementation is responsible for emitting the correct sequence of 404 /// instructions when lowering to machine code. 405 #[derive(Copy, Clone)] 406 pub(crate) enum V128LoadExtendKind { 407 /// Sign extends eight 8 bit integers to eight 16 bit lanes. 408 E8x8S, 409 /// Zero extends eight 8 bit integers to eight 16 bit lanes. 410 E8x8U, 411 /// Sign extends four 16 bit integers to four 32 bit lanes. 412 E16x4S, 413 /// Zero extends four 16 bit integers to four 32 bit lanes. 414 E16x4U, 415 /// Sign extends two 32 bit integers to two 64 bit lanes. 416 E32x2S, 417 /// Zero extends two 32 bit integers to two 64 bit lanes. 418 E32x2U, 419 } 420 421 /// Kinds of splat loads supported by WebAssembly. 422 pub(crate) enum SplatLoadKind { 423 /// 8 bits. 424 S8, 425 /// 16 bits. 426 S16, 427 /// 32 bits. 428 S32, 429 /// 64 bits. 430 S64, 431 } 432 433 /// Kinds of splat supported by WebAssembly. 434 #[derive(Copy, Debug, Clone, Eq, PartialEq)] 435 pub(crate) enum SplatKind { 436 /// 8 bit integer. 437 I8x16, 438 /// 16 bit integer. 439 I16x8, 440 /// 32 bit integer. 441 I32x4, 442 /// 64 bit integer. 443 I64x2, 444 /// 32 bit float. 445 F32x4, 446 /// 64 bit float. 447 F64x2, 448 } 449 450 impl SplatKind { 451 /// The lane size to use for different kinds of splats. 452 pub(crate) fn lane_size(&self) -> OperandSize { 453 match self { 454 SplatKind::I8x16 => OperandSize::S8, 455 SplatKind::I16x8 => OperandSize::S16, 456 SplatKind::I32x4 | SplatKind::F32x4 => OperandSize::S32, 457 SplatKind::I64x2 | SplatKind::F64x2 => OperandSize::S64, 458 } 459 } 460 } 461 462 /// Kinds of extract lane supported by WebAssembly. 463 #[derive(Copy, Debug, Clone, Eq, PartialEq)] 464 pub(crate) enum ExtractLaneKind { 465 /// 16 lanes of 8-bit integers sign extended to 32-bits. 466 I8x16S, 467 /// 16 lanes of 8-bit integers zero extended to 32-bits. 468 I8x16U, 469 /// 8 lanes of 16-bit integers sign extended to 32-bits. 470 I16x8S, 471 /// 8 lanes of 16-bit integers zero extended to 32-bits. 472 I16x8U, 473 /// 4 lanes of 32-bit integers. 474 I32x4, 475 /// 2 lanes of 64-bit integers. 476 I64x2, 477 /// 4 lanes of 32-bit floats. 478 F32x4, 479 /// 2 lanes of 64-bit floats. 480 F64x2, 481 } 482 483 impl ExtractLaneKind { 484 /// The lane size to use for different kinds of extract lane kinds. 485 pub(crate) fn lane_size(&self) -> OperandSize { 486 match self { 487 ExtractLaneKind::I8x16S | ExtractLaneKind::I8x16U => OperandSize::S8, 488 ExtractLaneKind::I16x8S | ExtractLaneKind::I16x8U => OperandSize::S16, 489 ExtractLaneKind::I32x4 | ExtractLaneKind::F32x4 => OperandSize::S32, 490 ExtractLaneKind::I64x2 | ExtractLaneKind::F64x2 => OperandSize::S64, 491 } 492 } 493 } 494 495 impl From<ExtractLaneKind> for Extend<Signed> { 496 fn from(value: ExtractLaneKind) -> Self { 497 match value { 498 ExtractLaneKind::I8x16S => Extend::I32Extend8, 499 ExtractLaneKind::I16x8S => Extend::I32Extend16, 500 _ => unimplemented!(), 501 } 502 } 503 } 504 505 /// Kinds of replace lane supported by WebAssembly. 506 pub(crate) enum ReplaceLaneKind { 507 /// 16 lanes of 8 bit integers. 508 I8x16, 509 /// 8 lanes of 16 bit integers. 510 I16x8, 511 /// 4 lanes of 32 bit integers. 512 I32x4, 513 /// 2 lanes of 64 bit integers. 514 I64x2, 515 /// 4 lanes of 32 bit floats. 516 F32x4, 517 /// 2 lanes of 64 bit floats. 518 F64x2, 519 } 520 521 impl ReplaceLaneKind { 522 /// The lane size to use for different kinds of replace lane kinds. 523 pub(crate) fn lane_size(&self) -> OperandSize { 524 match self { 525 ReplaceLaneKind::I8x16 => OperandSize::S8, 526 ReplaceLaneKind::I16x8 => OperandSize::S16, 527 ReplaceLaneKind::I32x4 => OperandSize::S32, 528 ReplaceLaneKind::I64x2 => OperandSize::S64, 529 ReplaceLaneKind::F32x4 => OperandSize::S32, 530 ReplaceLaneKind::F64x2 => OperandSize::S64, 531 } 532 } 533 } 534 535 /// Kinds of behavior supported by Wasm loads. 536 pub(crate) enum LoadKind { 537 /// Load the entire bytes of the operand size without any modifications. 538 Operand(OperandSize), 539 /// Atomic load, with optional scalar extend. 540 Atomic(OperandSize, Option<ExtendKind>), 541 /// Duplicate value into vector lanes. 542 Splat(SplatLoadKind), 543 /// Scalar (non-vector) extend. 544 ScalarExtend(ExtendKind), 545 /// Vector extend. 546 VectorExtend(V128LoadExtendKind), 547 /// Load content into select lane. 548 VectorLane(LaneSelector), 549 /// Load a single element into the lowest bits of a vector and initialize 550 /// all other bits to zero. 551 VectorZero(OperandSize), 552 } 553 554 impl LoadKind { 555 /// Returns the [`OperandSize`] used in the load operation. 556 pub(crate) fn derive_operand_size(&self) -> OperandSize { 557 match self { 558 Self::ScalarExtend(extend) | Self::Atomic(_, Some(extend)) => { 559 Self::operand_size_for_scalar(extend) 560 } 561 Self::VectorExtend(_) => OperandSize::S64, 562 Self::Splat(kind) => Self::operand_size_for_splat(kind), 563 Self::Operand(size) 564 | Self::Atomic(size, None) 565 | Self::VectorLane(LaneSelector { size, .. }) 566 | Self::VectorZero(size) => *size, 567 } 568 } 569 570 pub fn vector_lane(lane: u8, size: OperandSize) -> Self { 571 Self::VectorLane(LaneSelector { lane, size }) 572 } 573 574 fn operand_size_for_scalar(extend_kind: &ExtendKind) -> OperandSize { 575 match extend_kind { 576 ExtendKind::Signed(s) => s.from_size(), 577 ExtendKind::Unsigned(u) => u.from_size(), 578 } 579 } 580 581 fn operand_size_for_splat(kind: &SplatLoadKind) -> OperandSize { 582 match kind { 583 SplatLoadKind::S8 => OperandSize::S8, 584 SplatLoadKind::S16 => OperandSize::S16, 585 SplatLoadKind::S32 => OperandSize::S32, 586 SplatLoadKind::S64 => OperandSize::S64, 587 } 588 } 589 590 pub(crate) fn is_atomic(&self) -> bool { 591 matches!(self, Self::Atomic(_, _)) 592 } 593 } 594 595 /// Kinds of behavior supported by Wasm loads. 596 #[derive(Copy, Clone)] 597 pub enum StoreKind { 598 /// Store the entire bytes of the operand size without any modifications. 599 Operand(OperandSize), 600 /// Store the entire bytes of the operand size without any modifications, atomically. 601 Atomic(OperandSize), 602 /// Store the content of selected lane. 603 VectorLane(LaneSelector), 604 } 605 606 impl StoreKind { 607 pub fn vector_lane(lane: u8, size: OperandSize) -> Self { 608 Self::VectorLane(LaneSelector { lane, size }) 609 } 610 } 611 612 #[derive(Copy, Clone)] 613 pub struct LaneSelector { 614 pub lane: u8, 615 pub size: OperandSize, 616 } 617 618 /// Types of vector integer to float conversions supported by WebAssembly. 619 pub(crate) enum V128ConvertKind { 620 /// 4 lanes of signed 32-bit integers to 4 lanes of 32-bit floats. 621 I32x4S, 622 /// 4 lanes of unsigned 32-bit integers to 4 lanes of 32-bit floats. 623 I32x4U, 624 /// 4 lanes of signed 32-bit integers to low bits of 2 lanes of 64-bit 625 /// floats. 626 I32x4LowS, 627 /// 4 lanes of unsigned 32-bit integers to low bits of 2 lanes of 64-bit 628 /// floats. 629 I32x4LowU, 630 } 631 632 impl V128ConvertKind { 633 pub(crate) fn src_lane_size(&self) -> OperandSize { 634 match self { 635 V128ConvertKind::I32x4S 636 | V128ConvertKind::I32x4U 637 | V128ConvertKind::I32x4LowS 638 | V128ConvertKind::I32x4LowU => OperandSize::S32, 639 } 640 } 641 642 pub(crate) fn dst_lane_size(&self) -> OperandSize { 643 match self { 644 V128ConvertKind::I32x4S | V128ConvertKind::I32x4U => OperandSize::S32, 645 V128ConvertKind::I32x4LowS | V128ConvertKind::I32x4LowU => OperandSize::S64, 646 } 647 } 648 } 649 650 /// Kinds of vector narrowing operations supported by WebAssembly. 651 pub(crate) enum V128NarrowKind { 652 /// Narrow 8 lanes of 16-bit integers to 16 lanes of 8-bit integers using 653 /// signed saturation. 654 I16x8S, 655 /// Narrow 8 lanes of 16-bit integers to 16 lanes of 8-bit integers using 656 /// unsigned saturation. 657 I16x8U, 658 /// Narrow 4 lanes of 32-bit integers to 8 lanes of 16-bit integers using 659 /// signed saturation. 660 I32x4S, 661 /// Narrow 4 lanes of 32-bit integers to 8 lanes of 16-bit integers using 662 /// unsigned saturation. 663 I32x4U, 664 } 665 666 impl V128NarrowKind { 667 /// Return the size of the destination lanes. 668 pub(crate) fn dst_lane_size(&self) -> OperandSize { 669 match self { 670 Self::I16x8S | Self::I16x8U => OperandSize::S8, 671 Self::I32x4S | Self::I32x4U => OperandSize::S16, 672 } 673 } 674 } 675 676 /// Kinds of vector extending operations supported by WebAssembly. 677 #[derive(Debug, Copy, Clone)] 678 pub(crate) enum V128ExtendKind { 679 /// Low half of i8x16 sign extended. 680 LowI8x16S, 681 /// High half of i8x16 sign extended. 682 HighI8x16S, 683 /// Low half of i8x16 zero extended. 684 LowI8x16U, 685 /// High half of i8x16 zero extended. 686 HighI8x16U, 687 /// Low half of i16x8 sign extended. 688 LowI16x8S, 689 /// High half of i16x8 sign extended. 690 HighI16x8S, 691 /// Low half of i16x8 zero extended. 692 LowI16x8U, 693 /// High half of i16x8 zero extended. 694 HighI16x8U, 695 /// Low half of i32x4 sign extended. 696 LowI32x4S, 697 /// High half of i32x4 sign extended. 698 HighI32x4S, 699 /// Low half of i32x4 zero extended. 700 LowI32x4U, 701 /// High half of i32x4 zero extended. 702 HighI32x4U, 703 } 704 705 impl V128ExtendKind { 706 /// The size of the source's lanes. 707 pub(crate) fn src_lane_size(&self) -> OperandSize { 708 match self { 709 Self::LowI8x16S | Self::LowI8x16U | Self::HighI8x16S | Self::HighI8x16U => { 710 OperandSize::S8 711 } 712 Self::LowI16x8S | Self::LowI16x8U | Self::HighI16x8S | Self::HighI16x8U => { 713 OperandSize::S16 714 } 715 Self::LowI32x4S | Self::LowI32x4U | Self::HighI32x4S | Self::HighI32x4U => { 716 OperandSize::S32 717 } 718 } 719 } 720 } 721 722 /// Kinds of vector equalities and non-equalities supported by WebAssembly. 723 pub(crate) enum VectorEqualityKind { 724 /// 16 lanes of 8 bit integers. 725 I8x16, 726 /// 8 lanes of 16 bit integers. 727 I16x8, 728 /// 4 lanes of 32 bit integers. 729 I32x4, 730 /// 2 lanes of 64 bit integers. 731 I64x2, 732 /// 4 lanes of 32 bit floats. 733 F32x4, 734 /// 2 lanes of 64 bit floats. 735 F64x2, 736 } 737 738 impl VectorEqualityKind { 739 /// Get the lane size to use. 740 pub(crate) fn lane_size(&self) -> OperandSize { 741 match self { 742 Self::I8x16 => OperandSize::S8, 743 Self::I16x8 => OperandSize::S16, 744 Self::I32x4 | Self::F32x4 => OperandSize::S32, 745 Self::I64x2 | Self::F64x2 => OperandSize::S64, 746 } 747 } 748 } 749 750 /// Kinds of vector comparisons supported by WebAssembly. 751 pub(crate) enum VectorCompareKind { 752 /// 16 lanes of signed 8 bit integers. 753 I8x16S, 754 /// 16 lanes of unsigned 8 bit integers. 755 I8x16U, 756 /// 8 lanes of signed 16 bit integers. 757 I16x8S, 758 /// 8 lanes of unsigned 16 bit integers. 759 I16x8U, 760 /// 4 lanes of signed 32 bit integers. 761 I32x4S, 762 /// 4 lanes of unsigned 32 bit integers. 763 I32x4U, 764 /// 2 lanes of signed 64 bit integers. 765 I64x2S, 766 /// 4 lanes of 32 bit floats. 767 F32x4, 768 /// 2 lanes of 64 bit floats. 769 F64x2, 770 } 771 772 impl VectorCompareKind { 773 /// Get the lane size to use. 774 pub(crate) fn lane_size(&self) -> OperandSize { 775 match self { 776 Self::I8x16S | Self::I8x16U => OperandSize::S8, 777 Self::I16x8S | Self::I16x8U => OperandSize::S16, 778 Self::I32x4S | Self::I32x4U | Self::F32x4 => OperandSize::S32, 779 Self::I64x2S | Self::F64x2 => OperandSize::S64, 780 } 781 } 782 } 783 784 /// Kinds of vector absolute operations supported by WebAssembly. 785 #[derive(Copy, Debug, Clone, Eq, PartialEq)] 786 pub(crate) enum V128AbsKind { 787 /// 8 bit integers. 788 I8x16, 789 /// 16 bit integers. 790 I16x8, 791 /// 32 bit integers. 792 I32x4, 793 /// 64 bit integers. 794 I64x2, 795 /// 32 bit floats. 796 F32x4, 797 /// 64 bit floats. 798 F64x2, 799 } 800 801 impl V128AbsKind { 802 /// The lane size to use. 803 pub(crate) fn lane_size(&self) -> OperandSize { 804 match self { 805 Self::I8x16 => OperandSize::S8, 806 Self::I16x8 => OperandSize::S16, 807 Self::I32x4 | Self::F32x4 => OperandSize::S32, 808 Self::I64x2 | Self::F64x2 => OperandSize::S64, 809 } 810 } 811 } 812 813 /// Kinds of truncation for vectors supported by WebAssembly. 814 pub(crate) enum V128TruncKind { 815 /// Truncates 4 lanes of 32-bit floats to nearest integral value. 816 F32x4, 817 /// Truncates 2 lanes of 64-bit floats to nearest integral value. 818 F64x2, 819 /// Integers from signed F32x4. 820 I32x4FromF32x4S, 821 /// Integers from unsigned F32x4. 822 I32x4FromF32x4U, 823 /// Integers from signed F64x2. 824 I32x4FromF64x2SZero, 825 /// Integers from unsigned F64x2. 826 I32x4FromF64x2UZero, 827 } 828 829 impl V128TruncKind { 830 /// The size of the source lanes. 831 pub(crate) fn src_lane_size(&self) -> OperandSize { 832 match self { 833 V128TruncKind::F32x4 834 | V128TruncKind::I32x4FromF32x4S 835 | V128TruncKind::I32x4FromF32x4U => OperandSize::S32, 836 V128TruncKind::F64x2 837 | V128TruncKind::I32x4FromF64x2SZero 838 | V128TruncKind::I32x4FromF64x2UZero => OperandSize::S64, 839 } 840 } 841 842 /// The size of the destination lanes. 843 pub(crate) fn dst_lane_size(&self) -> OperandSize { 844 if let V128TruncKind::F64x2 = self { 845 OperandSize::S64 846 } else { 847 OperandSize::S32 848 } 849 } 850 } 851 852 /// Kinds of vector addition supported by WebAssembly. 853 pub(crate) enum V128AddKind { 854 /// 4 lanes of 32-bit floats wrapping. 855 F32x4, 856 /// 2 lanes of 64-bit floats wrapping. 857 F64x2, 858 /// 16 lanes of 8-bit integers wrapping. 859 I8x16, 860 /// 16 lanes of 8-bit integers signed saturating. 861 I8x16SatS, 862 /// 16 lanes of 8-bit integers unsigned saturating. 863 I8x16SatU, 864 /// 8 lanes of 16-bit integers wrapping. 865 I16x8, 866 /// 8 lanes of 16-bit integers signed saturating. 867 I16x8SatS, 868 /// 8 lanes of 16-bit integers unsigned saturating. 869 I16x8SatU, 870 /// 4 lanes of 32-bit integers wrapping. 871 I32x4, 872 /// 2 lanes of 64-bit integers wrapping. 873 I64x2, 874 } 875 876 /// Kinds of vector subtraction supported by WebAssembly. 877 pub(crate) enum V128SubKind { 878 /// 4 lanes of 32-bit floats wrapping. 879 F32x4, 880 /// 2 lanes of 64-bit floats wrapping. 881 F64x2, 882 /// 16 lanes of 8-bit integers wrapping. 883 I8x16, 884 /// 16 lanes of 8-bit integers signed saturating. 885 I8x16SatS, 886 /// 16 lanes of 8-bit integers unsigned saturating. 887 I8x16SatU, 888 /// 8 lanes of 16-bit integers wrapping. 889 I16x8, 890 /// 8 lanes of 16-bit integers signed saturating. 891 I16x8SatS, 892 /// 8 lanes of 16-bit integers unsigned saturating. 893 I16x8SatU, 894 /// 4 lanes of 32-bit integers wrapping. 895 I32x4, 896 /// 2 lanes of 64-bit integers wrapping. 897 I64x2, 898 } 899 900 impl From<V128NegKind> for V128SubKind { 901 fn from(value: V128NegKind) -> Self { 902 match value { 903 V128NegKind::I8x16 => Self::I8x16, 904 V128NegKind::I16x8 => Self::I16x8, 905 V128NegKind::I32x4 => Self::I32x4, 906 V128NegKind::I64x2 => Self::I64x2, 907 V128NegKind::F32x4 | V128NegKind::F64x2 => unimplemented!(), 908 } 909 } 910 } 911 912 /// Kinds of vector multiplication supported by WebAssembly. 913 pub(crate) enum V128MulKind { 914 /// 4 lanes of 32-bit floats. 915 F32x4, 916 /// 2 lanes of 64-bit floats. 917 F64x2, 918 /// 8 lanes of 16-bit integers. 919 I16x8, 920 /// 4 lanes of 32-bit integers. 921 I32x4, 922 /// 2 lanes of 64-bit integers. 923 I64x2, 924 } 925 926 /// Kinds of vector negation supported by WebAssembly. 927 #[derive(Copy, Clone)] 928 pub(crate) enum V128NegKind { 929 /// 4 lanes of 32-bit floats. 930 F32x4, 931 /// 2 lanes of 64-bit floats. 932 F64x2, 933 /// 16 lanes of 8-bit integers. 934 I8x16, 935 /// 8 lanes of 16-bit integers. 936 I16x8, 937 /// 4 lanes of 32-bit integers. 938 I32x4, 939 /// 2 lanes of 64-bit integers. 940 I64x2, 941 } 942 943 impl V128NegKind { 944 /// The size of the lanes. 945 pub(crate) fn lane_size(&self) -> OperandSize { 946 match self { 947 Self::F32x4 | Self::I32x4 => OperandSize::S32, 948 Self::F64x2 | Self::I64x2 => OperandSize::S64, 949 Self::I8x16 => OperandSize::S8, 950 Self::I16x8 => OperandSize::S16, 951 } 952 } 953 } 954 955 /// Kinds of extended pairwise addition supported by WebAssembly. 956 pub(crate) enum V128ExtAddKind { 957 /// 16 lanes of signed 8-bit integers. 958 I8x16S, 959 /// 16 lanes of unsigned 8-bit integers. 960 I8x16U, 961 /// 8 lanes of signed 16-bit integers. 962 I16x8S, 963 /// 8 lanes of unsigned 16-bit integers. 964 I16x8U, 965 } 966 967 /// Kinds of vector extended multiplication supported by WebAssembly. 968 #[derive(Debug, Clone, Copy)] 969 pub(crate) enum V128ExtMulKind { 970 LowI8x16S, 971 HighI8x16S, 972 LowI8x16U, 973 HighI8x16U, 974 LowI16x8S, 975 HighI16x8S, 976 LowI16x8U, 977 HighI16x8U, 978 LowI32x4S, 979 HighI32x4S, 980 LowI32x4U, 981 HighI32x4U, 982 } 983 984 impl From<V128ExtMulKind> for V128ExtendKind { 985 fn from(value: V128ExtMulKind) -> Self { 986 match value { 987 V128ExtMulKind::LowI8x16S => Self::LowI8x16S, 988 V128ExtMulKind::HighI8x16S => Self::HighI8x16S, 989 V128ExtMulKind::LowI8x16U => Self::LowI8x16U, 990 V128ExtMulKind::HighI8x16U => Self::HighI8x16U, 991 V128ExtMulKind::LowI16x8S => Self::LowI16x8S, 992 V128ExtMulKind::HighI16x8S => Self::HighI16x8S, 993 V128ExtMulKind::LowI16x8U => Self::LowI16x8U, 994 V128ExtMulKind::HighI16x8U => Self::HighI16x8U, 995 V128ExtMulKind::LowI32x4S => Self::LowI32x4S, 996 V128ExtMulKind::HighI32x4S => Self::HighI32x4S, 997 V128ExtMulKind::LowI32x4U => Self::LowI32x4U, 998 V128ExtMulKind::HighI32x4U => Self::HighI32x4U, 999 } 1000 } 1001 } 1002 1003 impl From<V128ExtMulKind> for V128MulKind { 1004 fn from(value: V128ExtMulKind) -> Self { 1005 match value { 1006 V128ExtMulKind::LowI8x16S 1007 | V128ExtMulKind::HighI8x16S 1008 | V128ExtMulKind::LowI8x16U 1009 | V128ExtMulKind::HighI8x16U => Self::I16x8, 1010 V128ExtMulKind::LowI16x8S 1011 | V128ExtMulKind::HighI16x8S 1012 | V128ExtMulKind::LowI16x8U 1013 | V128ExtMulKind::HighI16x8U => Self::I32x4, 1014 V128ExtMulKind::LowI32x4S 1015 | V128ExtMulKind::HighI32x4S 1016 | V128ExtMulKind::LowI32x4U 1017 | V128ExtMulKind::HighI32x4U => Self::I64x2, 1018 } 1019 } 1020 } 1021 1022 /// Operand size, in bits. 1023 #[derive(Copy, Debug, Clone, Eq, PartialEq)] 1024 pub(crate) enum OperandSize { 1025 /// 8 bits. 1026 S8, 1027 /// 16 bits. 1028 S16, 1029 /// 32 bits. 1030 S32, 1031 /// 64 bits. 1032 S64, 1033 /// 128 bits. 1034 S128, 1035 } 1036 1037 impl OperandSize { 1038 /// The number of bits in the operand. 1039 pub fn num_bits(&self) -> u8 { 1040 match self { 1041 OperandSize::S8 => 8, 1042 OperandSize::S16 => 16, 1043 OperandSize::S32 => 32, 1044 OperandSize::S64 => 64, 1045 OperandSize::S128 => 128, 1046 } 1047 } 1048 1049 /// The number of bytes in the operand. 1050 pub fn bytes(&self) -> u32 { 1051 match self { 1052 Self::S8 => 1, 1053 Self::S16 => 2, 1054 Self::S32 => 4, 1055 Self::S64 => 8, 1056 Self::S128 => 16, 1057 } 1058 } 1059 1060 /// The binary logarithm of the number of bits in the operand. 1061 pub fn log2(&self) -> u8 { 1062 match self { 1063 OperandSize::S8 => 3, 1064 OperandSize::S16 => 4, 1065 OperandSize::S32 => 5, 1066 OperandSize::S64 => 6, 1067 OperandSize::S128 => 7, 1068 } 1069 } 1070 1071 /// Create an [`OperandSize`] from the given number of bytes. 1072 pub fn from_bytes(bytes: u8) -> Self { 1073 use OperandSize::*; 1074 match bytes { 1075 4 => S32, 1076 8 => S64, 1077 16 => S128, 1078 _ => panic!("Invalid bytes {bytes} for OperandSize"), 1079 } 1080 } 1081 1082 pub fn extend_to<T: ExtendType>(&self, to: Self) -> Option<Extend<T>> { 1083 match to { 1084 OperandSize::S32 => match self { 1085 OperandSize::S8 => Some(Extend::I32Extend8), 1086 OperandSize::S16 => Some(Extend::I32Extend16), 1087 _ => None, 1088 }, 1089 OperandSize::S64 => match self { 1090 OperandSize::S8 => Some(Extend::I64Extend8), 1091 OperandSize::S16 => Some(Extend::I64Extend16), 1092 OperandSize::S32 => Some(Extend::I64Extend32), 1093 _ => None, 1094 }, 1095 _ => None, 1096 } 1097 } 1098 1099 /// The number of bits in the mantissa. 1100 /// 1101 /// Only implemented for floats. 1102 pub fn mantissa_bits(&self) -> u8 { 1103 match self { 1104 Self::S32 => 8, 1105 Self::S64 => 11, 1106 _ => unimplemented!(), 1107 } 1108 } 1109 } 1110 1111 /// An abstraction over a register or immediate. 1112 #[derive(Copy, Clone, Debug, PartialEq, Eq)] 1113 pub(crate) enum RegImm { 1114 /// A register. 1115 Reg(Reg), 1116 /// A tagged immediate argument. 1117 Imm(Imm), 1118 } 1119 1120 /// An tagged representation of an immediate. 1121 #[derive(Copy, Clone, Debug, PartialEq, Eq)] 1122 pub(crate) enum Imm { 1123 /// I32 immediate. 1124 I32(u32), 1125 /// I64 immediate. 1126 I64(u64), 1127 /// F32 immediate. 1128 F32(u32), 1129 /// F64 immediate. 1130 F64(u64), 1131 /// V128 immediate. 1132 V128(i128), 1133 } 1134 1135 impl Imm { 1136 /// Create a new I64 immediate. 1137 pub fn i64(val: i64) -> Self { 1138 Self::I64(val as u64) 1139 } 1140 1141 /// Create a new I32 immediate. 1142 pub fn i32(val: i32) -> Self { 1143 Self::I32(val as u32) 1144 } 1145 1146 /// Create a new F32 immediate. 1147 pub fn f32(bits: u32) -> Self { 1148 Self::F32(bits) 1149 } 1150 1151 /// Create a new F64 immediate. 1152 pub fn f64(bits: u64) -> Self { 1153 Self::F64(bits) 1154 } 1155 1156 /// Create a new V128 immediate. 1157 pub fn v128(bits: i128) -> Self { 1158 Self::V128(bits) 1159 } 1160 1161 /// Convert the immediate to i32, if possible. 1162 pub fn to_i32(&self) -> Option<i32> { 1163 match self { 1164 Self::I32(v) => Some(*v as i32), 1165 Self::I64(v) => i32::try_from(*v as i64).ok(), 1166 _ => None, 1167 } 1168 } 1169 1170 /// Unwraps the underlying integer value as u64. 1171 /// # Panics 1172 /// This function panics if the underlying value can't be represented 1173 /// as u64. 1174 pub fn unwrap_as_u64(&self) -> u64 { 1175 match self { 1176 Self::I32(v) => *v as u64, 1177 Self::I64(v) => *v, 1178 Self::F32(v) => *v as u64, 1179 Self::F64(v) => *v, 1180 _ => unreachable!(), 1181 } 1182 } 1183 1184 /// Get the operand size of the immediate. 1185 pub fn size(&self) -> OperandSize { 1186 match self { 1187 Self::I32(_) | Self::F32(_) => OperandSize::S32, 1188 Self::I64(_) | Self::F64(_) => OperandSize::S64, 1189 Self::V128(_) => OperandSize::S128, 1190 } 1191 } 1192 1193 /// Get a little endian representation of the immediate. 1194 /// 1195 /// This method heap allocates and is intended to be used when adding 1196 /// values to the constant pool. 1197 pub fn to_bytes(&self) -> Vec<u8> { 1198 match self { 1199 Imm::I32(n) => n.to_le_bytes().to_vec(), 1200 Imm::I64(n) => n.to_le_bytes().to_vec(), 1201 Imm::F32(n) => n.to_le_bytes().to_vec(), 1202 Imm::F64(n) => n.to_le_bytes().to_vec(), 1203 Imm::V128(n) => n.to_le_bytes().to_vec(), 1204 } 1205 } 1206 } 1207 1208 /// The location of the [VMcontext] used for function calls. 1209 #[derive(Copy, Clone, Debug, Eq, PartialEq)] 1210 pub(crate) enum VMContextLoc { 1211 /// Dynamic, stored in the given register. 1212 Reg(Reg), 1213 /// The pinned [VMContext] register. 1214 Pinned, 1215 } 1216 1217 /// The maximum number of context arguments currently used across the compiler. 1218 pub(crate) const MAX_CONTEXT_ARGS: usize = 2; 1219 1220 /// Out-of-band special purpose arguments used for function call emission. 1221 /// 1222 /// We cannot rely on the value stack for these values given that inserting 1223 /// register or memory values at arbitrary locations of the value stack has the 1224 /// potential to break the stack ordering principle, which states that older 1225 /// values must always precede newer values, effectively simulating the order of 1226 /// values in the machine stack. 1227 /// The [ContextArgs] are meant to be resolved at every callsite; in some cases 1228 /// it might be possible to construct it early on, but given that it might 1229 /// contain allocatable registers, it's preferred to construct it in 1230 /// [FnCall::emit]. 1231 #[derive(Clone, Debug)] 1232 pub(crate) enum ContextArgs { 1233 /// A single context argument is required; the current pinned [VMcontext] 1234 /// register must be passed as the first argument of the function call. 1235 VMContext([VMContextLoc; 1]), 1236 /// The callee and caller context arguments are required. In this case, the 1237 /// callee context argument is usually stored into an allocatable register 1238 /// and the caller is always the current pinned [VMContext] pointer. 1239 CalleeAndCallerVMContext([VMContextLoc; MAX_CONTEXT_ARGS]), 1240 } 1241 1242 impl ContextArgs { 1243 /// Construct a [ContextArgs] declaring the usage of the pinned [VMContext] 1244 /// register as both the caller and callee context arguments. 1245 pub fn pinned_callee_and_caller_vmctx() -> Self { 1246 Self::CalleeAndCallerVMContext([VMContextLoc::Pinned, VMContextLoc::Pinned]) 1247 } 1248 1249 /// Construct a [ContextArgs] that declares the usage of the pinned 1250 /// [VMContext] register as the only context argument. 1251 pub fn pinned_vmctx() -> Self { 1252 Self::VMContext([VMContextLoc::Pinned]) 1253 } 1254 1255 /// Construct a [ContextArgs] that declares a dynamic callee context and the 1256 /// pinned [VMContext] register as the context arguments. 1257 pub fn with_callee_and_pinned_caller(callee_vmctx: Reg) -> Self { 1258 Self::CalleeAndCallerVMContext([VMContextLoc::Reg(callee_vmctx), VMContextLoc::Pinned]) 1259 } 1260 1261 /// Get the length of the [ContextArgs]. 1262 pub fn len(&self) -> usize { 1263 self.as_slice().len() 1264 } 1265 1266 /// Get a slice of the context arguments. 1267 pub fn as_slice(&self) -> &[VMContextLoc] { 1268 match self { 1269 Self::VMContext(a) => a.as_slice(), 1270 Self::CalleeAndCallerVMContext(a) => a.as_slice(), 1271 } 1272 } 1273 } 1274 1275 #[derive(Copy, Clone, Debug)] 1276 pub(crate) enum CalleeKind { 1277 /// A function call to a raw address. 1278 Indirect(Reg), 1279 /// A function call to a local function. 1280 Direct(UserExternalNameRef), 1281 } 1282 1283 impl CalleeKind { 1284 /// Creates a callee kind from a register. 1285 pub fn indirect(reg: Reg) -> Self { 1286 Self::Indirect(reg) 1287 } 1288 1289 /// Creates a direct callee kind from a function name. 1290 pub fn direct(name: UserExternalNameRef) -> Self { 1291 Self::Direct(name) 1292 } 1293 } 1294 1295 impl RegImm { 1296 /// Register constructor. 1297 pub fn reg(r: Reg) -> Self { 1298 RegImm::Reg(r) 1299 } 1300 1301 /// I64 immediate constructor. 1302 pub fn i64(val: i64) -> Self { 1303 RegImm::Imm(Imm::i64(val)) 1304 } 1305 1306 /// I32 immediate constructor. 1307 pub fn i32(val: i32) -> Self { 1308 RegImm::Imm(Imm::i32(val)) 1309 } 1310 1311 /// F32 immediate, stored using its bits representation. 1312 pub fn f32(bits: u32) -> Self { 1313 RegImm::Imm(Imm::f32(bits)) 1314 } 1315 1316 /// F64 immediate, stored using its bits representation. 1317 pub fn f64(bits: u64) -> Self { 1318 RegImm::Imm(Imm::f64(bits)) 1319 } 1320 1321 /// V128 immediate. 1322 pub fn v128(bits: i128) -> Self { 1323 RegImm::Imm(Imm::v128(bits)) 1324 } 1325 } 1326 1327 impl From<Reg> for RegImm { 1328 fn from(r: Reg) -> Self { 1329 Self::Reg(r) 1330 } 1331 } 1332 1333 #[derive(Debug)] 1334 pub enum RoundingMode { 1335 Nearest, 1336 Up, 1337 Down, 1338 Zero, 1339 } 1340 1341 /// Memory flags for trusted loads/stores. 1342 pub const TRUSTED_FLAGS: MemFlags = MemFlags::trusted(); 1343 1344 /// Flags used for WebAssembly loads / stores. 1345 /// Untrusted by default so we don't set `no_trap`. 1346 /// We also ensure that the endianness is the right one for WebAssembly. 1347 pub const UNTRUSTED_FLAGS: MemFlags = MemFlags::new().with_endianness(Endianness::Little); 1348 1349 /// Generic MacroAssembler interface used by the code generation. 1350 /// 1351 /// The MacroAssembler trait aims to expose an interface, high-level enough, 1352 /// so that each ISA can provide its own lowering to machine code. For example, 1353 /// for WebAssembly operators that don't have a direct mapping to a machine 1354 /// a instruction, the interface defines a signature matching the WebAssembly 1355 /// operator, allowing each implementation to lower such operator entirely. 1356 /// This approach attributes more responsibility to the MacroAssembler, but frees 1357 /// the caller from concerning about assembling the right sequence of 1358 /// instructions at the operator callsite. 1359 /// 1360 /// The interface defaults to a three-argument form for binary operations; 1361 /// this allows a natural mapping to instructions for RISC architectures, 1362 /// that use three-argument form. 1363 /// This approach allows for a more general interface that can be restricted 1364 /// where needed, in the case of architectures that use a two-argument form. 1365 1366 pub(crate) trait MacroAssembler { 1367 /// The addressing mode. 1368 type Address: Copy + Debug; 1369 1370 /// The pointer representation of the target ISA, 1371 /// used to access information from [`VMOffsets`]. 1372 type Ptr: PtrSize; 1373 1374 /// The ABI details of the target. 1375 type ABI: abi::ABI; 1376 1377 /// Emit the function prologue. 1378 fn prologue(&mut self, vmctx: Reg) -> Result<()> { 1379 self.frame_setup()?; 1380 self.check_stack(vmctx) 1381 } 1382 1383 /// Generate the frame setup sequence. 1384 fn frame_setup(&mut self) -> Result<()>; 1385 1386 /// Generate the frame restore sequence. 1387 fn frame_restore(&mut self) -> Result<()>; 1388 1389 /// Emit a stack check. 1390 fn check_stack(&mut self, vmctx: Reg) -> Result<()>; 1391 1392 /// Emit the function epilogue. 1393 fn epilogue(&mut self) -> Result<()> { 1394 self.frame_restore() 1395 } 1396 1397 /// Reserve stack space. 1398 fn reserve_stack(&mut self, bytes: u32) -> Result<()>; 1399 1400 /// Free stack space. 1401 fn free_stack(&mut self, bytes: u32) -> Result<()>; 1402 1403 /// Reset the stack pointer to the given offset; 1404 /// 1405 /// Used to reset the stack pointer to a given offset 1406 /// when dealing with unreachable code. 1407 fn reset_stack_pointer(&mut self, offset: SPOffset) -> Result<()>; 1408 1409 /// Get the address of a local slot. 1410 fn local_address(&mut self, local: &LocalSlot) -> Result<Self::Address>; 1411 1412 /// Constructs an address with an offset that is relative to the 1413 /// current position of the stack pointer (e.g. [sp + (sp_offset - 1414 /// offset)]. 1415 fn address_from_sp(&self, offset: SPOffset) -> Result<Self::Address>; 1416 1417 /// Constructs an address with an offset that is absolute to the 1418 /// current position of the stack pointer (e.g. [sp + offset]. 1419 fn address_at_sp(&self, offset: SPOffset) -> Result<Self::Address>; 1420 1421 /// Alias for [`Self::address_at_reg`] using the VMContext register as 1422 /// a base. The VMContext register is derived from the ABI type that is 1423 /// associated to the MacroAssembler. 1424 fn address_at_vmctx(&self, offset: u32) -> Result<Self::Address>; 1425 1426 /// Construct an address that is absolute to the current position 1427 /// of the given register. 1428 fn address_at_reg(&self, reg: Reg, offset: u32) -> Result<Self::Address>; 1429 1430 /// Emit a function call to either a local or external function. 1431 fn call( 1432 &mut self, 1433 stack_args_size: u32, 1434 f: impl FnMut(&mut Self) -> Result<(CalleeKind, CallingConvention)>, 1435 ) -> Result<u32>; 1436 1437 /// Acquire a scratch register and execute the given callback. 1438 fn with_scratch<T: ScratchType, R>(&mut self, f: impl FnOnce(&mut Self, Scratch) -> R) -> R; 1439 1440 /// Convenience wrapper over [`Self::with_scratch`], derives the register class 1441 /// for a particular Wasm value type. 1442 fn with_scratch_for<R>( 1443 &mut self, 1444 ty: WasmValType, 1445 f: impl FnOnce(&mut Self, Scratch) -> R, 1446 ) -> R { 1447 match ty { 1448 WasmValType::I32 1449 | WasmValType::I64 1450 | WasmValType::Ref(WasmRefType { 1451 heap_type: WasmHeapType::Func, 1452 .. 1453 }) => self.with_scratch::<IntScratch, _>(f), 1454 WasmValType::F32 | WasmValType::F64 | WasmValType::V128 => { 1455 self.with_scratch::<FloatScratch, _>(f) 1456 } 1457 _ => unimplemented!(), 1458 } 1459 } 1460 1461 /// Get stack pointer offset. 1462 fn sp_offset(&self) -> Result<SPOffset>; 1463 1464 /// Perform a stack store. 1465 fn store(&mut self, src: RegImm, dst: Self::Address, size: OperandSize) -> Result<()>; 1466 1467 /// Alias for `MacroAssembler::store` with the operand size corresponding 1468 /// to the pointer size of the target. 1469 fn store_ptr(&mut self, src: Reg, dst: Self::Address) -> Result<()>; 1470 1471 /// Perform a WebAssembly store. 1472 /// A WebAssembly store introduces several additional invariants compared to 1473 /// [Self::store], more precisely, it can implicitly trap, in certain 1474 /// circumstances, even if explicit bounds checks are elided, in that sense, 1475 /// we consider this type of load as untrusted. It can also differ with 1476 /// regards to the endianness depending on the target ISA. For this reason, 1477 /// [Self::wasm_store], should be explicitly used when emitting WebAssembly 1478 /// stores. 1479 fn wasm_store(&mut self, src: Reg, dst: Self::Address, store_kind: StoreKind) -> Result<()>; 1480 1481 /// Perform a zero-extended stack load. 1482 fn load(&mut self, src: Self::Address, dst: WritableReg, size: OperandSize) -> Result<()>; 1483 1484 /// Perform a WebAssembly load. 1485 /// A WebAssembly load introduces several additional invariants compared to 1486 /// [Self::load], more precisely, it can implicitly trap, in certain 1487 /// circumstances, even if explicit bounds checks are elided, in that sense, 1488 /// we consider this type of load as untrusted. It can also differ with 1489 /// regards to the endianness depending on the target ISA. For this reason, 1490 /// [Self::wasm_load], should be explicitly used when emitting WebAssembly 1491 /// loads. 1492 fn wasm_load(&mut self, src: Self::Address, dst: WritableReg, kind: LoadKind) -> Result<()>; 1493 1494 /// Alias for `MacroAssembler::load` with the operand size corresponding 1495 /// to the pointer size of the target. 1496 fn load_ptr(&mut self, src: Self::Address, dst: WritableReg) -> Result<()>; 1497 1498 /// Computes the effective address and stores the result in the destination 1499 /// register. 1500 fn compute_addr( 1501 &mut self, 1502 _src: Self::Address, 1503 _dst: WritableReg, 1504 _size: OperandSize, 1505 ) -> Result<()>; 1506 1507 /// Pop a value from the machine stack into the given register. 1508 fn pop(&mut self, dst: WritableReg, size: OperandSize) -> Result<()>; 1509 1510 /// Perform a move. 1511 fn mov(&mut self, dst: WritableReg, src: RegImm, size: OperandSize) -> Result<()>; 1512 1513 /// Perform a conditional move. 1514 fn cmov(&mut self, dst: WritableReg, src: Reg, cc: IntCmpKind, size: OperandSize) 1515 -> Result<()>; 1516 1517 /// Performs a memory move of bytes from src to dest. 1518 /// Bytes are moved in blocks of 8 bytes, where possible. 1519 fn memmove( 1520 &mut self, 1521 src: SPOffset, 1522 dst: SPOffset, 1523 bytes: u32, 1524 direction: MemMoveDirection, 1525 ) -> Result<()> { 1526 match direction { 1527 MemMoveDirection::LowToHigh => debug_assert!(dst.as_u32() < src.as_u32()), 1528 MemMoveDirection::HighToLow => debug_assert!(dst.as_u32() > src.as_u32()), 1529 } 1530 // At least 4 byte aligned. 1531 debug_assert!(bytes % 4 == 0); 1532 let mut remaining = bytes; 1533 let word_bytes = <Self::ABI as abi::ABI>::word_bytes(); 1534 1535 let word_bytes = word_bytes as u32; 1536 1537 let mut dst_offs; 1538 let mut src_offs; 1539 match direction { 1540 MemMoveDirection::LowToHigh => { 1541 dst_offs = dst.as_u32() - bytes; 1542 src_offs = src.as_u32() - bytes; 1543 self.with_scratch::<IntScratch, _>(|masm, scratch| { 1544 while remaining >= word_bytes { 1545 remaining -= word_bytes; 1546 dst_offs += word_bytes; 1547 src_offs += word_bytes; 1548 1549 masm.load_ptr( 1550 masm.address_from_sp(SPOffset::from_u32(src_offs))?, 1551 scratch.writable(), 1552 )?; 1553 masm.store_ptr( 1554 scratch.inner(), 1555 masm.address_from_sp(SPOffset::from_u32(dst_offs))?, 1556 )?; 1557 } 1558 anyhow::Ok(()) 1559 })?; 1560 } 1561 MemMoveDirection::HighToLow => { 1562 // Go from the end to the beginning to handle overlapping addresses. 1563 src_offs = src.as_u32(); 1564 dst_offs = dst.as_u32(); 1565 self.with_scratch::<IntScratch, _>(|masm, scratch| { 1566 while remaining >= word_bytes { 1567 masm.load_ptr( 1568 masm.address_from_sp(SPOffset::from_u32(src_offs))?, 1569 scratch.writable(), 1570 )?; 1571 masm.store_ptr( 1572 scratch.inner(), 1573 masm.address_from_sp(SPOffset::from_u32(dst_offs))?, 1574 )?; 1575 1576 remaining -= word_bytes; 1577 src_offs -= word_bytes; 1578 dst_offs -= word_bytes; 1579 } 1580 anyhow::Ok(()) 1581 })?; 1582 } 1583 } 1584 1585 if remaining > 0 { 1586 let half_word = word_bytes / 2; 1587 let ptr_size = OperandSize::from_bytes(half_word as u8); 1588 debug_assert!(remaining == half_word); 1589 // Need to move the offsets ahead in the `LowToHigh` case to 1590 // compensate for the initial subtraction of `bytes`. 1591 if direction == MemMoveDirection::LowToHigh { 1592 dst_offs += half_word; 1593 src_offs += half_word; 1594 } 1595 1596 self.with_scratch::<IntScratch, _>(|masm, scratch| { 1597 masm.load( 1598 masm.address_from_sp(SPOffset::from_u32(src_offs))?, 1599 scratch.writable(), 1600 ptr_size, 1601 )?; 1602 masm.store( 1603 scratch.inner().into(), 1604 masm.address_from_sp(SPOffset::from_u32(dst_offs))?, 1605 ptr_size, 1606 )?; 1607 anyhow::Ok(()) 1608 })?; 1609 } 1610 Ok(()) 1611 } 1612 1613 /// Perform add operation. 1614 fn add(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>; 1615 1616 /// Perform a checked unsigned integer addition, emitting the provided trap 1617 /// if the addition overflows. 1618 fn checked_uadd( 1619 &mut self, 1620 dst: WritableReg, 1621 lhs: Reg, 1622 rhs: RegImm, 1623 size: OperandSize, 1624 trap: TrapCode, 1625 ) -> Result<()>; 1626 1627 /// Perform subtraction operation. 1628 fn sub(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>; 1629 1630 /// Perform multiplication operation. 1631 fn mul(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>; 1632 1633 /// Perform a floating point add operation. 1634 fn float_add(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>; 1635 1636 /// Perform a floating point subtraction operation. 1637 fn float_sub(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>; 1638 1639 /// Perform a floating point multiply operation. 1640 fn float_mul(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>; 1641 1642 /// Perform a floating point divide operation. 1643 fn float_div(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>; 1644 1645 /// Perform a floating point minimum operation. In x86, this will emit 1646 /// multiple instructions. 1647 fn float_min(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>; 1648 1649 /// Perform a floating point maximum operation. In x86, this will emit 1650 /// multiple instructions. 1651 fn float_max(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, size: OperandSize) -> Result<()>; 1652 1653 /// Perform a floating point copysign operation. In x86, this will emit 1654 /// multiple instructions. 1655 fn float_copysign( 1656 &mut self, 1657 dst: WritableReg, 1658 lhs: Reg, 1659 rhs: Reg, 1660 size: OperandSize, 1661 ) -> Result<()>; 1662 1663 /// Perform a floating point abs operation. 1664 fn float_abs(&mut self, dst: WritableReg, size: OperandSize) -> Result<()>; 1665 1666 /// Perform a floating point negation operation. 1667 fn float_neg(&mut self, dst: WritableReg, size: OperandSize) -> Result<()>; 1668 1669 /// Perform a floating point floor operation. 1670 fn float_round< 1671 F: FnMut(&mut FuncEnv<Self::Ptr>, &mut CodeGenContext<Emission>, &mut Self) -> Result<()>, 1672 >( 1673 &mut self, 1674 mode: RoundingMode, 1675 env: &mut FuncEnv<Self::Ptr>, 1676 context: &mut CodeGenContext<Emission>, 1677 size: OperandSize, 1678 fallback: F, 1679 ) -> Result<()>; 1680 1681 /// Perform a floating point square root operation. 1682 fn float_sqrt(&mut self, dst: WritableReg, src: Reg, size: OperandSize) -> Result<()>; 1683 1684 /// Perform logical and operation. 1685 fn and(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>; 1686 1687 /// Perform logical or operation. 1688 fn or(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>; 1689 1690 /// Perform logical exclusive or operation. 1691 fn xor(&mut self, dst: WritableReg, lhs: Reg, rhs: RegImm, size: OperandSize) -> Result<()>; 1692 1693 /// Perform a shift operation between a register and an immediate. 1694 fn shift_ir( 1695 &mut self, 1696 dst: WritableReg, 1697 imm: Imm, 1698 lhs: Reg, 1699 kind: ShiftKind, 1700 size: OperandSize, 1701 ) -> Result<()>; 1702 1703 /// Perform a shift operation between two registers. 1704 /// This case is special in that some architectures have specific expectations 1705 /// regarding the location of the instruction arguments. To free the 1706 /// caller from having to deal with the architecture specific constraints 1707 /// we give this function access to the code generation context, allowing 1708 /// each implementation to decide the lowering path. 1709 fn shift( 1710 &mut self, 1711 context: &mut CodeGenContext<Emission>, 1712 kind: ShiftKind, 1713 size: OperandSize, 1714 ) -> Result<()>; 1715 1716 /// Perform division operation. 1717 /// Division is special in that some architectures have specific 1718 /// expectations regarding the location of the instruction 1719 /// arguments and regarding the location of the quotient / 1720 /// remainder. To free the caller from having to deal with the 1721 /// architecture specific constraints we give this function access 1722 /// to the code generation context, allowing each implementation 1723 /// to decide the lowering path. For cases in which division is a 1724 /// unconstrained binary operation, the caller can decide to use 1725 /// the `CodeGenContext::i32_binop` or `CodeGenContext::i64_binop` 1726 /// functions. 1727 fn div( 1728 &mut self, 1729 context: &mut CodeGenContext<Emission>, 1730 kind: DivKind, 1731 size: OperandSize, 1732 ) -> Result<()>; 1733 1734 /// Calculate remainder. 1735 fn rem( 1736 &mut self, 1737 context: &mut CodeGenContext<Emission>, 1738 kind: RemKind, 1739 size: OperandSize, 1740 ) -> Result<()>; 1741 1742 /// Compares `src1` against `src2` for the side effect of setting processor 1743 /// flags. 1744 /// 1745 /// Note that `src1` is the left-hand-side of the comparison and `src2` is 1746 /// the right-hand-side, so if testing `a < b` then `src1 == a` and 1747 /// `src2 == b` 1748 fn cmp(&mut self, src1: Reg, src2: RegImm, size: OperandSize) -> Result<()>; 1749 1750 /// Compare src and dst and put the result in dst. 1751 /// This function will potentially emit a series of instructions. 1752 /// 1753 /// The initial value in `dst` is the left-hand-side of the comparison and 1754 /// the initial value in `src` is the right-hand-side of the comparison. 1755 /// That means for `a < b` then `dst == a` and `src == b`. 1756 fn cmp_with_set( 1757 &mut self, 1758 dst: WritableReg, 1759 src: RegImm, 1760 kind: IntCmpKind, 1761 size: OperandSize, 1762 ) -> Result<()>; 1763 1764 /// Compare floats in src1 and src2 and put the result in dst. 1765 /// In x86, this will emit multiple instructions. 1766 fn float_cmp_with_set( 1767 &mut self, 1768 dst: WritableReg, 1769 src1: Reg, 1770 src2: Reg, 1771 kind: FloatCmpKind, 1772 size: OperandSize, 1773 ) -> Result<()>; 1774 1775 /// Count the number of leading zeroes in src and put the result in dst. 1776 /// In x64, this will emit multiple instructions if the `has_lzcnt` flag is 1777 /// false. 1778 fn clz(&mut self, dst: WritableReg, src: Reg, size: OperandSize) -> Result<()>; 1779 1780 /// Count the number of trailing zeroes in src and put the result in dst.masm 1781 /// In x64, this will emit multiple instructions if the `has_tzcnt` flag is 1782 /// false. 1783 fn ctz(&mut self, dst: WritableReg, src: Reg, size: OperandSize) -> Result<()>; 1784 1785 /// Push the register to the stack, returning the stack slot metadata. 1786 // NB 1787 // The stack alignment should not be assumed after any call to `push`, 1788 // unless explicitly aligned otherwise. Typically, stack alignment is 1789 // maintained at call sites and during the execution of 1790 // epilogues. 1791 fn push(&mut self, src: Reg, size: OperandSize) -> Result<StackSlot>; 1792 1793 /// Finalize the assembly and return the result. 1794 fn finalize(self, base: Option<SourceLoc>) -> Result<MachBufferFinalized<Final>>; 1795 1796 /// Zero a particular register. 1797 fn zero(&mut self, reg: WritableReg) -> Result<()>; 1798 1799 /// Count the number of 1 bits in src and put the result in dst. In x64, 1800 /// this will emit multiple instructions if the `has_popcnt` flag is false. 1801 fn popcnt(&mut self, context: &mut CodeGenContext<Emission>, size: OperandSize) -> Result<()>; 1802 1803 /// Converts an i64 to an i32 by discarding the high 32 bits. 1804 fn wrap(&mut self, dst: WritableReg, src: Reg) -> Result<()>; 1805 1806 /// Extends an integer of a given size to a larger size. 1807 fn extend(&mut self, dst: WritableReg, src: Reg, kind: ExtendKind) -> Result<()>; 1808 1809 /// Emits one or more instructions to perform a signed truncation of a 1810 /// float into an integer. 1811 fn signed_truncate( 1812 &mut self, 1813 dst: WritableReg, 1814 src: Reg, 1815 src_size: OperandSize, 1816 dst_size: OperandSize, 1817 kind: TruncKind, 1818 ) -> Result<()>; 1819 1820 /// Emits one or more instructions to perform an unsigned truncation of a 1821 /// float into an integer. 1822 fn unsigned_truncate( 1823 &mut self, 1824 context: &mut CodeGenContext<Emission>, 1825 src_size: OperandSize, 1826 dst_size: OperandSize, 1827 kind: TruncKind, 1828 ) -> Result<()>; 1829 1830 /// Emits one or more instructions to perform a signed convert of an 1831 /// integer into a float. 1832 fn signed_convert( 1833 &mut self, 1834 dst: WritableReg, 1835 src: Reg, 1836 src_size: OperandSize, 1837 dst_size: OperandSize, 1838 ) -> Result<()>; 1839 1840 /// Emits one or more instructions to perform an unsigned convert of an 1841 /// integer into a float. 1842 fn unsigned_convert( 1843 &mut self, 1844 dst: WritableReg, 1845 src: Reg, 1846 tmp_gpr: Reg, 1847 src_size: OperandSize, 1848 dst_size: OperandSize, 1849 ) -> Result<()>; 1850 1851 /// Reinterpret a float as an integer. 1852 fn reinterpret_float_as_int( 1853 &mut self, 1854 dst: WritableReg, 1855 src: Reg, 1856 size: OperandSize, 1857 ) -> Result<()>; 1858 1859 /// Reinterpret an integer as a float. 1860 fn reinterpret_int_as_float( 1861 &mut self, 1862 dst: WritableReg, 1863 src: Reg, 1864 size: OperandSize, 1865 ) -> Result<()>; 1866 1867 /// Demote an f64 to an f32. 1868 fn demote(&mut self, dst: WritableReg, src: Reg) -> Result<()>; 1869 1870 /// Promote an f32 to an f64. 1871 fn promote(&mut self, dst: WritableReg, src: Reg) -> Result<()>; 1872 1873 /// Zero a given memory range. 1874 /// 1875 /// The default implementation divides the given memory range 1876 /// into word-sized slots. Then it unrolls a series of store 1877 /// instructions, effectively assigning zero to each slot. 1878 fn zero_mem_range(&mut self, mem: &Range<u32>) -> Result<()> { 1879 let word_size = <Self::ABI as abi::ABI>::word_bytes() as u32; 1880 if mem.is_empty() { 1881 return Ok(()); 1882 } 1883 1884 let start = if mem.start % word_size == 0 { 1885 mem.start 1886 } else { 1887 // Ensure that the start of the range is at least 4-byte aligned. 1888 assert!(mem.start % 4 == 0); 1889 let start = align_to(mem.start, word_size); 1890 let addr: Self::Address = self.local_address(&LocalSlot::i32(start))?; 1891 self.store(RegImm::i32(0), addr, OperandSize::S32)?; 1892 // Ensure that the new start of the range, is word-size aligned. 1893 assert!(start % word_size == 0); 1894 start 1895 }; 1896 1897 let end = align_to(mem.end, word_size); 1898 let slots = (end - start) / word_size; 1899 1900 if slots == 1 { 1901 let slot = LocalSlot::i64(start + word_size); 1902 let addr: Self::Address = self.local_address(&slot)?; 1903 self.store(RegImm::i64(0), addr, OperandSize::S64)?; 1904 } else { 1905 // TODO 1906 // Add an upper bound to this generation; 1907 // given a considerably large amount of slots 1908 // this will be inefficient. 1909 self.with_scratch::<IntScratch, _>(|masm, scratch| { 1910 masm.zero(scratch.writable())?; 1911 let zero = RegImm::reg(scratch.inner()); 1912 1913 for step in (start..end).step_by(word_size as usize) { 1914 let slot = LocalSlot::i64(step + word_size); 1915 let addr: Self::Address = masm.local_address(&slot)?; 1916 masm.store(zero, addr, OperandSize::S64)?; 1917 } 1918 anyhow::Ok(()) 1919 })?; 1920 } 1921 1922 Ok(()) 1923 } 1924 1925 /// Generate a label. 1926 fn get_label(&mut self) -> Result<MachLabel>; 1927 1928 /// Bind the given label at the current code offset. 1929 fn bind(&mut self, label: MachLabel) -> Result<()>; 1930 1931 /// Conditional branch. 1932 /// 1933 /// Performs a comparison between the two operands, 1934 /// and immediately after emits a jump to the given 1935 /// label destination if the condition is met. 1936 fn branch( 1937 &mut self, 1938 kind: IntCmpKind, 1939 lhs: Reg, 1940 rhs: RegImm, 1941 taken: MachLabel, 1942 size: OperandSize, 1943 ) -> Result<()>; 1944 1945 /// Emits and unconditional jump to the given label. 1946 fn jmp(&mut self, target: MachLabel) -> Result<()>; 1947 1948 /// Emits a jump table sequence. The default label is specified as 1949 /// the last element of the targets slice. 1950 fn jmp_table(&mut self, targets: &[MachLabel], index: Reg, tmp: Reg) -> Result<()>; 1951 1952 /// Emit an unreachable code trap. 1953 fn unreachable(&mut self) -> Result<()>; 1954 1955 /// Emit an unconditional trap. 1956 fn trap(&mut self, code: TrapCode) -> Result<()>; 1957 1958 /// Traps if the condition code is met. 1959 fn trapif(&mut self, cc: IntCmpKind, code: TrapCode) -> Result<()>; 1960 1961 /// Trap if the source register is zero. 1962 fn trapz(&mut self, src: Reg, code: TrapCode) -> Result<()>; 1963 1964 /// Ensures that the stack pointer is correctly positioned before an unconditional 1965 /// jump according to the requirements of the destination target. 1966 fn ensure_sp_for_jump(&mut self, target: SPOffset) -> Result<()> { 1967 let bytes = self 1968 .sp_offset()? 1969 .as_u32() 1970 .checked_sub(target.as_u32()) 1971 .unwrap_or(0); 1972 1973 if bytes > 0 { 1974 self.free_stack(bytes)?; 1975 } 1976 1977 Ok(()) 1978 } 1979 1980 /// Mark the start of a source location returning the machine code offset 1981 /// and the relative source code location. 1982 fn start_source_loc(&mut self, loc: RelSourceLoc) -> Result<(CodeOffset, RelSourceLoc)>; 1983 1984 /// Mark the end of a source location. 1985 fn end_source_loc(&mut self) -> Result<()>; 1986 1987 /// The current offset, in bytes from the beginning of the function. 1988 fn current_code_offset(&self) -> Result<CodeOffset>; 1989 1990 /// Performs a 128-bit addition 1991 fn add128( 1992 &mut self, 1993 dst_lo: WritableReg, 1994 dst_hi: WritableReg, 1995 lhs_lo: Reg, 1996 lhs_hi: Reg, 1997 rhs_lo: Reg, 1998 rhs_hi: Reg, 1999 ) -> Result<()>; 2000 2001 /// Performs a 128-bit subtraction 2002 fn sub128( 2003 &mut self, 2004 dst_lo: WritableReg, 2005 dst_hi: WritableReg, 2006 lhs_lo: Reg, 2007 lhs_hi: Reg, 2008 rhs_lo: Reg, 2009 rhs_hi: Reg, 2010 ) -> Result<()>; 2011 2012 /// Performs a widening multiplication from two 64-bit operands into a 2013 /// 128-bit result. 2014 /// 2015 /// Note that some platforms require special handling of registers in this 2016 /// instruction (e.g. x64) so full access to `CodeGenContext` is provided. 2017 fn mul_wide(&mut self, context: &mut CodeGenContext<Emission>, kind: MulWideKind) 2018 -> Result<()>; 2019 2020 /// Takes the value in a src operand and replicates it across lanes of 2021 /// `size` in a destination result. 2022 fn splat(&mut self, context: &mut CodeGenContext<Emission>, size: SplatKind) -> Result<()>; 2023 2024 /// Performs a shuffle between two 128-bit vectors into a 128-bit result 2025 /// using lanes as a mask to select which indexes to copy. 2026 fn shuffle(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg, lanes: [u8; 16]) -> Result<()>; 2027 2028 /// Performs a swizzle between two 128-bit vectors into a 128-bit result. 2029 fn swizzle(&mut self, dst: WritableReg, lhs: Reg, rhs: Reg) -> Result<()>; 2030 2031 /// Performs the RMW `op` operation on the passed `addr`. 2032 /// 2033 /// The value *before* the operation was performed is written back to the `operand` register. 2034 fn atomic_rmw( 2035 &mut self, 2036 context: &mut CodeGenContext<Emission>, 2037 addr: Self::Address, 2038 size: OperandSize, 2039 op: RmwOp, 2040 flags: MemFlags, 2041 extend: Option<Extend<Zero>>, 2042 ) -> Result<()>; 2043 2044 /// Extracts the scalar value from `src` in `lane` to `dst`. 2045 fn extract_lane( 2046 &mut self, 2047 src: Reg, 2048 dst: WritableReg, 2049 lane: u8, 2050 kind: ExtractLaneKind, 2051 ) -> Result<()>; 2052 2053 /// Replaces the value in `lane` in `dst` with the value in `src`. 2054 fn replace_lane( 2055 &mut self, 2056 src: RegImm, 2057 dst: WritableReg, 2058 lane: u8, 2059 kind: ReplaceLaneKind, 2060 ) -> Result<()>; 2061 2062 /// Perform an atomic CAS (compare-and-swap) operation with the value at `addr`, and `expected` 2063 /// and `replacement` (at the top of the context's stack). 2064 /// 2065 /// This method takes the `CodeGenContext` as an arguments to accommodate architectures that 2066 /// expect parameters in specific registers. The context stack contains the `replacement`, 2067 /// and `expected` values in that order. The implementer is expected to push the value at 2068 /// `addr` before the update to the context's stack before returning. 2069 fn atomic_cas( 2070 &mut self, 2071 context: &mut CodeGenContext<Emission>, 2072 addr: Self::Address, 2073 size: OperandSize, 2074 flags: MemFlags, 2075 extend: Option<Extend<Zero>>, 2076 ) -> Result<()>; 2077 2078 /// Compares vector registers `lhs` and `rhs` for equality and puts the 2079 /// vector of results in `dst`. 2080 fn v128_eq( 2081 &mut self, 2082 dst: WritableReg, 2083 lhs: Reg, 2084 rhs: Reg, 2085 kind: VectorEqualityKind, 2086 ) -> Result<()>; 2087 2088 /// Compares vector registers `lhs` and `rhs` for inequality and puts the 2089 /// vector of results in `dst`. 2090 fn v128_ne( 2091 &mut self, 2092 dst: WritableReg, 2093 lhs: Reg, 2094 rhs: Reg, 2095 kind: VectorEqualityKind, 2096 ) -> Result<()>; 2097 2098 /// Performs a less than comparison with vector registers `lhs` and `rhs` 2099 /// and puts the vector of results in `dst`. 2100 fn v128_lt( 2101 &mut self, 2102 dst: WritableReg, 2103 lhs: Reg, 2104 rhs: Reg, 2105 kind: VectorCompareKind, 2106 ) -> Result<()>; 2107 2108 /// Performs a less than or equal comparison with vector registers `lhs` 2109 /// and `rhs` and puts the vector of results in `dst`. 2110 fn v128_le( 2111 &mut self, 2112 dst: WritableReg, 2113 lhs: Reg, 2114 rhs: Reg, 2115 kind: VectorCompareKind, 2116 ) -> Result<()>; 2117 2118 /// Performs a greater than comparison with vector registers `lhs` and 2119 /// `rhs` and puts the vector of results in `dst`. 2120 fn v128_gt( 2121 &mut self, 2122 dst: WritableReg, 2123 lhs: Reg, 2124 rhs: Reg, 2125 kind: VectorCompareKind, 2126 ) -> Result<()>; 2127 2128 /// Performs a greater than or equal comparison with vector registers `lhs` 2129 /// and `rhs` and puts the vector of results in `dst`. 2130 fn v128_ge( 2131 &mut self, 2132 dst: WritableReg, 2133 lhs: Reg, 2134 rhs: Reg, 2135 kind: VectorCompareKind, 2136 ) -> Result<()>; 2137 2138 /// Emit a memory fence. 2139 fn fence(&mut self) -> Result<()>; 2140 2141 /// Perform a logical `not` operation on the 128bits vector value in `dst`. 2142 fn v128_not(&mut self, dst: WritableReg) -> Result<()>; 2143 2144 /// Perform a logical `and` operation on `src1` and `src1`, both 128bits vector values, writing 2145 /// the result to `dst`. 2146 fn v128_and(&mut self, src1: Reg, src2: Reg, dst: WritableReg) -> Result<()>; 2147 2148 /// Perform a logical `and_not` operation on `src1` and `src1`, both 128bits vector values, writing 2149 /// the result to `dst`. 2150 /// 2151 /// `and_not` is not commutative: dst = !src1 & src2. 2152 fn v128_and_not(&mut self, src1: Reg, src2: Reg, dst: WritableReg) -> Result<()>; 2153 2154 /// Perform a logical `or` operation on `src1` and `src1`, both 128bits vector values, writing 2155 /// the result to `dst`. 2156 fn v128_or(&mut self, src1: Reg, src2: Reg, dst: WritableReg) -> Result<()>; 2157 2158 /// Perform a logical `xor` operation on `src1` and `src1`, both 128bits vector values, writing 2159 /// the result to `dst`. 2160 fn v128_xor(&mut self, src1: Reg, src2: Reg, dst: WritableReg) -> Result<()>; 2161 2162 /// Given two 128bits vectors `src1` and `src2`, and a 128bits bitmask `mask`, selects bits 2163 /// from `src1` when mask is 1, and from `src2` when mask is 0. 2164 /// 2165 /// This is equivalent to: `v128.or(v128.and(src1, mask), v128.and(src2, v128.not(mask)))`. 2166 fn v128_bitselect(&mut self, src1: Reg, src2: Reg, mask: Reg, dst: WritableReg) -> Result<()>; 2167 2168 /// If any bit in `src` is 1, set `dst` to 1, or 0 otherwise. 2169 fn v128_any_true(&mut self, src: Reg, dst: WritableReg) -> Result<()>; 2170 2171 /// Convert vector of integers to vector of floating points. 2172 fn v128_convert(&mut self, src: Reg, dst: WritableReg, kind: V128ConvertKind) -> Result<()>; 2173 2174 /// Convert two input vectors into a smaller lane vector by narrowing each 2175 /// lane. 2176 fn v128_narrow( 2177 &mut self, 2178 src1: Reg, 2179 src2: Reg, 2180 dst: WritableReg, 2181 kind: V128NarrowKind, 2182 ) -> Result<()>; 2183 2184 /// Converts a vector containing two 64-bit floating point lanes to two 2185 /// 32-bit floating point lanes and setting the two higher lanes to 0. 2186 fn v128_demote(&mut self, src: Reg, dst: WritableReg) -> Result<()>; 2187 2188 /// Converts a vector containing four 32-bit floating point lanes to two 2189 /// 64-bit floating point lanes. Only the two lower lanes are converted. 2190 fn v128_promote(&mut self, src: Reg, dst: WritableReg) -> Result<()>; 2191 2192 /// Converts low or high half of the smaller lane vector to a larger lane 2193 /// vector. 2194 fn v128_extend(&mut self, src: Reg, dst: WritableReg, kind: V128ExtendKind) -> Result<()>; 2195 2196 /// Perform a vector add between `lsh` and `rhs`, placing the result in 2197 /// `dst`. 2198 fn v128_add(&mut self, lhs: Reg, rhs: Reg, dst: WritableReg, kind: V128AddKind) -> Result<()>; 2199 2200 /// Perform a vector sub between `lhs` and `rhs`, placing the result in `dst`. 2201 fn v128_sub(&mut self, lhs: Reg, rhs: Reg, dst: WritableReg, kind: V128SubKind) -> Result<()>; 2202 2203 /// Perform a vector lane-wise mul between `lhs` and `rhs`, placing the result in `dst`. 2204 fn v128_mul(&mut self, context: &mut CodeGenContext<Emission>, kind: V128MulKind) 2205 -> Result<()>; 2206 2207 /// Perform an absolute operation on a vector. 2208 fn v128_abs(&mut self, src: Reg, dst: WritableReg, kind: V128AbsKind) -> Result<()>; 2209 2210 /// Vectorized negate of the content of `op`. 2211 fn v128_neg(&mut self, op: WritableReg, kind: V128NegKind) -> Result<()>; 2212 2213 /// Perform the shift operation specified by `kind`, by the shift amount specified by the 32-bit 2214 /// integer at the top of the stack, on the 128-bit vector specified by the second value 2215 /// from the top of the stack, interpreted as packed integers of size `lane_width`. 2216 /// 2217 /// The shift amount is taken modulo `lane_width`. 2218 fn v128_shift( 2219 &mut self, 2220 context: &mut CodeGenContext<Emission>, 2221 lane_width: OperandSize, 2222 kind: ShiftKind, 2223 ) -> Result<()>; 2224 2225 /// Perform a saturating integer q-format rounding multiplication. 2226 fn v128_q15mulr_sat_s( 2227 &mut self, 2228 lhs: Reg, 2229 rhs: Reg, 2230 dst: WritableReg, 2231 size: OperandSize, 2232 ) -> Result<()>; 2233 2234 /// Sets `dst` to 1 if all lanes in `src` are non-zero, sets `dst` to 0 2235 /// otherwise. 2236 fn v128_all_true(&mut self, src: Reg, dst: WritableReg, size: OperandSize) -> Result<()>; 2237 2238 /// Extracts the high bit of each lane in `src` and produces a scalar mask 2239 /// with all bits concatenated in `dst`. 2240 fn v128_bitmask(&mut self, src: Reg, dst: WritableReg, size: OperandSize) -> Result<()>; 2241 2242 /// Lanewise truncation operation. 2243 /// 2244 /// If using an integer kind of truncation, then this performs a lane-wise 2245 /// saturating conversion from float to integer using the IEEE 2246 /// `convertToIntegerTowardZero` function. If any input lane is NaN, the 2247 /// resulting lane is 0. If the rounded integer value of a lane is outside 2248 /// the range of the destination type, the result is saturated to the 2249 /// nearest representable integer value. 2250 fn v128_trunc( 2251 &mut self, 2252 context: &mut CodeGenContext<Emission>, 2253 kind: V128TruncKind, 2254 ) -> Result<()>; 2255 2256 /// Perform a lane-wise `min` operation between `src1` and `src2`. 2257 fn v128_min(&mut self, src1: Reg, src2: Reg, dst: WritableReg, kind: V128MinKind) 2258 -> Result<()>; 2259 2260 /// Perform a lane-wise `max` operation between `src1` and `src2`. 2261 fn v128_max(&mut self, src1: Reg, src2: Reg, dst: WritableReg, kind: V128MaxKind) 2262 -> Result<()>; 2263 2264 /// Perform the lane-wise integer extended multiplication producing twice wider result than the 2265 /// inputs. This is equivalent to an extend followed by a multiply. 2266 /// 2267 /// The extension to be performed is inferred from the `lane_width` and the `kind` of extmul, 2268 /// e.g, if `lane_width` is `S16`, and `kind` is `LowSigned`, then we sign-extend the lower 2269 /// 8bits of the 16bits lanes. 2270 fn v128_extmul( 2271 &mut self, 2272 context: &mut CodeGenContext<Emission>, 2273 kind: V128ExtMulKind, 2274 ) -> Result<()>; 2275 2276 /// Perform the lane-wise integer extended pairwise addition producing extended results (twice 2277 /// wider results than the inputs). 2278 fn v128_extadd_pairwise( 2279 &mut self, 2280 src: Reg, 2281 dst: WritableReg, 2282 kind: V128ExtAddKind, 2283 ) -> Result<()>; 2284 2285 /// Lane-wise multiply signed 16-bit integers in `lhs` and `rhs` and add 2286 /// adjacent pairs of the 32-bit results. 2287 fn v128_dot(&mut self, lhs: Reg, rhs: Reg, dst: WritableReg) -> Result<()>; 2288 2289 /// Count the number of bits set in each lane. 2290 fn v128_popcnt(&mut self, context: &mut CodeGenContext<Emission>) -> Result<()>; 2291 2292 /// Lane-wise rounding average of vectors of integers in `lhs` and `rhs` 2293 /// and put the results in `dst`. 2294 fn v128_avgr(&mut self, lhs: Reg, rhs: Reg, dst: WritableReg, size: OperandSize) -> Result<()>; 2295 2296 /// Lane-wise IEEE division on vectors of floats. 2297 fn v128_div(&mut self, lhs: Reg, rhs: Reg, dst: WritableReg, size: OperandSize) -> Result<()>; 2298 2299 /// Lane-wise IEEE square root of vector of floats. 2300 fn v128_sqrt(&mut self, src: Reg, dst: WritableReg, size: OperandSize) -> Result<()>; 2301 2302 /// Lane-wise ceiling of vector of floats. 2303 fn v128_ceil(&mut self, src: Reg, dst: WritableReg, size: OperandSize) -> Result<()>; 2304 2305 /// Lane-wise flooring of vector of floats. 2306 fn v128_floor(&mut self, src: Reg, dst: WritableReg, size: OperandSize) -> Result<()>; 2307 2308 /// Lane-wise rounding to nearest integer for vector of floats. 2309 fn v128_nearest(&mut self, src: Reg, dst: WritableReg, size: OperandSize) -> Result<()>; 2310 2311 /// Lane-wise minimum value defined as `rhs < lhs ? rhs : lhs`. 2312 fn v128_pmin(&mut self, lhs: Reg, rhs: Reg, dst: WritableReg, size: OperandSize) -> Result<()>; 2313 2314 /// Lane-wise maximum value defined as `lhs < rhs ? rhs : lhs`. 2315 fn v128_pmax(&mut self, lhs: Reg, rhs: Reg, dst: WritableReg, size: OperandSize) -> Result<()>; 2316 } 2317