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