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