1 //! The pulley bytecode for fast interpreters. 2 3 #![cfg_attr(docsrs, feature(doc_cfg))] 4 #![cfg_attr(pulley_tail_calls, feature(explicit_tail_calls))] 5 #![cfg_attr(pulley_tail_calls, allow(incomplete_features, unstable_features))] 6 #![deny(missing_docs)] 7 #![no_std] 8 9 #[cfg(feature = "std")] 10 #[macro_use] 11 extern crate std; 12 13 #[cfg(feature = "decode")] 14 extern crate alloc; 15 16 /// Calls the given macro with each opcode. 17 /// 18 /// # Instruction Guidelines 19 /// 20 /// We're inventing an instruction set here which naturally brings a whole set 21 /// of design questions. Note that this is explicitly intended to be only ever 22 /// used for Pulley where there are a different set of design constraints than 23 /// other instruction sets (e.g. general-purpose CPU ISAs). Some examples of 24 /// constraints for Pulley are: 25 /// 26 /// * Instructions must be portable to many architectures. 27 /// * The Pulley ISA is mostly target-independent as the compilation target is 28 /// currently only parameterized on pointer width and endianness. 29 /// * Pulley instructions should be balance of time-to-decode and code size. For 30 /// example super fancy bit-packing tricks might be tough to decode in 31 /// software but might be worthwhile if it's quite common and greatly reduces 32 /// the size of bytecode. There's not a hard-and-fast answer here, but a 33 /// balance to be made. 34 /// * Many "macro ops" are present to reduce the size of compiled bytecode so 35 /// there is a wide set of duplicate functionality between opcodes (and this 36 /// is expected). 37 /// 38 /// Given all this it's also useful to have a set of guidelines used to name and 39 /// develop Pulley instructions. As of the time of this writing it's still 40 /// pretty early days for Pulley so some of these guidelines may change over 41 /// time. Additionally instructions don't necessarily all follow these 42 /// conventions and that may also change over time. With that in mind, here's a 43 /// rough set of guidelines: 44 /// 45 /// * Most instructions are prefixed with `x`, `f`, or `v`, indicating which 46 /// type of register they're operating on. (e.g. `xadd32` operates on the `x` 47 /// integer registers and `fadd32` operates on the `f` float registers). 48 /// 49 /// * Most instructions are suffixed or otherwise contain the bit width they're 50 /// operating on. For example `xadd32` is a 32-bit addition. 51 /// 52 /// * If an instruction operates on signed or unsigned data (such as division 53 /// and remainder), then the instruction is suffixed with `_s` or `_u`. 54 /// 55 /// * Instructions operate on either 32 or 64-bit parts of a register. 56 /// Instructions modifying only 32-bits of a register always modify the "low" 57 /// part of a register and leave the upper part unmodified. This is intended 58 /// to help 32-bit platforms where if most operations are 32-bit there's no 59 /// need for extra instructions to sign or zero extend and modify the upper 60 /// half of the register. 61 /// 62 /// * Binops use `BinaryOperands<T>` for the destination and argument registers. 63 /// 64 /// * Instructions operating on memory contain a few pieces of information: 65 /// 66 /// ```text 67 /// xload16le_u32_o32 68 /// │└─┬┘└┤└┤ └┬┘ └┬┘ 69 /// │ │ │ │ │ ▼ 70 /// │ │ │ │ │ addressing mode 71 /// │ │ │ │ ▼ 72 /// │ │ │ │ width of register modified + sign-extension (optional) 73 /// │ │ │ ▼ 74 /// │ │ │ endianness of the operation (le/be) 75 /// │ │ ▼ 76 /// │ │ bit-width of the operation 77 /// │ ▼ 78 /// │ what's happening (load/store) 79 /// ▼ 80 /// register being operated on (x/f/z) 81 /// ``` 82 /// 83 /// More guidelines might get added here over time, and if you have any 84 /// questions feel free to raise them and we can try to add them here as well! 85 #[macro_export] 86 macro_rules! for_each_op { 87 ( $macro:ident ) => { 88 $macro! { 89 /// Transfer control the address in the `lr` register. 90 ret = Ret; 91 92 /// Transfer control to the PC at the given offset and set the `lr` 93 /// register to the PC just after this instruction. 94 /// 95 /// This instruction generally assumes that the Pulley ABI is being 96 /// respected where arguments are in argument registers (starting at 97 /// x0 for integer arguments) and results are in result registers. 98 /// This instruction itself assume that all arguments are already in 99 /// their registers. Subsequent instructions below enable moving 100 /// arguments into the correct registers as part of the same call 101 /// instruction. 102 call = Call { offset: PcRelOffset }; 103 /// Like `call`, but also `x0 = arg1` 104 call1 = Call1 { arg1: XReg, offset: PcRelOffset }; 105 /// Like `call`, but also `x0, x1 = arg1, arg2` 106 call2 = Call2 { arg1: XReg, arg2: XReg, offset: PcRelOffset }; 107 /// Like `call`, but also `x0, x1, x2 = arg1, arg2, arg3` 108 call3 = Call3 { arg1: XReg, arg2: XReg, arg3: XReg, offset: PcRelOffset }; 109 /// Like `call`, but also `x0, x1, x2, x3 = arg1, arg2, arg3, arg4` 110 call4 = Call4 { arg1: XReg, arg2: XReg, arg3: XReg, arg4: XReg, offset: PcRelOffset }; 111 112 /// Transfer control to the PC in `reg` and set `lr` to the PC just 113 /// after this instruction. 114 call_indirect = CallIndirect { reg: XReg }; 115 116 /// Unconditionally transfer control to the PC at the given offset. 117 jump = Jump { offset: PcRelOffset }; 118 119 /// Unconditionally transfer control to the PC at specified 120 /// register. 121 xjump = XJump { reg: XReg }; 122 123 /// Conditionally transfer control to the given PC offset if 124 /// `low32(cond)` contains a non-zero value. 125 br_if32 = BrIf { cond: XReg, offset: PcRelOffset }; 126 127 /// Conditionally transfer control to the given PC offset if 128 /// `low32(cond)` contains a zero value. 129 br_if_not32 = BrIfNot { cond: XReg, offset: PcRelOffset }; 130 131 /// Branch if `a == b`. 132 br_if_xeq32 = BrIfXeq32 { a: XReg, b: XReg, offset: PcRelOffset }; 133 /// Branch if `a != `b. 134 br_if_xneq32 = BrIfXneq32 { a: XReg, b: XReg, offset: PcRelOffset }; 135 /// Branch if signed `a < b`. 136 br_if_xslt32 = BrIfXslt32 { a: XReg, b: XReg, offset: PcRelOffset }; 137 /// Branch if signed `a <= b`. 138 br_if_xslteq32 = BrIfXslteq32 { a: XReg, b: XReg, offset: PcRelOffset }; 139 /// Branch if unsigned `a < b`. 140 br_if_xult32 = BrIfXult32 { a: XReg, b: XReg, offset: PcRelOffset }; 141 /// Branch if unsigned `a <= b`. 142 br_if_xulteq32 = BrIfXulteq32 { a: XReg, b: XReg, offset: PcRelOffset }; 143 /// Branch if `a == b`. 144 br_if_xeq64 = BrIfXeq64 { a: XReg, b: XReg, offset: PcRelOffset }; 145 /// Branch if `a != `b. 146 br_if_xneq64 = BrIfXneq64 { a: XReg, b: XReg, offset: PcRelOffset }; 147 /// Branch if signed `a < b`. 148 br_if_xslt64 = BrIfXslt64 { a: XReg, b: XReg, offset: PcRelOffset }; 149 /// Branch if signed `a <= b`. 150 br_if_xslteq64 = BrIfXslteq64 { a: XReg, b: XReg, offset: PcRelOffset }; 151 /// Branch if unsigned `a < b`. 152 br_if_xult64 = BrIfXult64 { a: XReg, b: XReg, offset: PcRelOffset }; 153 /// Branch if unsigned `a <= b`. 154 br_if_xulteq64 = BrIfXulteq64 { a: XReg, b: XReg, offset: PcRelOffset }; 155 156 /// Branch if `a == b`. 157 br_if_xeq32_i8 = BrIfXeq32I8 { a: XReg, b: i8, offset: PcRelOffset }; 158 /// Branch if `a == b`. 159 br_if_xeq32_i32 = BrIfXeq32I32 { a: XReg, b: i32, offset: PcRelOffset }; 160 /// Branch if `a != `b. 161 br_if_xneq32_i8 = BrIfXneq32I8 { a: XReg, b: i8, offset: PcRelOffset }; 162 /// Branch if `a != `b. 163 br_if_xneq32_i32 = BrIfXneq32I32 { a: XReg, b: i32, offset: PcRelOffset }; 164 /// Branch if signed `a < b`. 165 br_if_xslt32_i8 = BrIfXslt32I8 { a: XReg, b: i8, offset: PcRelOffset }; 166 /// Branch if signed `a < b`. 167 br_if_xslt32_i32 = BrIfXslt32I32 { a: XReg, b: i32, offset: PcRelOffset }; 168 /// Branch if signed `a > b`. 169 br_if_xsgt32_i8 = BrIfXsgt32I8 { a: XReg, b: i8, offset: PcRelOffset }; 170 /// Branch if signed `a > b`. 171 br_if_xsgt32_i32 = BrIfXsgt32I32 { a: XReg, b: i32, offset: PcRelOffset }; 172 /// Branch if signed `a <= b`. 173 br_if_xslteq32_i8 = BrIfXslteq32I8 { a: XReg, b: i8, offset: PcRelOffset }; 174 /// Branch if signed `a <= b`. 175 br_if_xslteq32_i32 = BrIfXslteq32I32 { a: XReg, b: i32, offset: PcRelOffset }; 176 /// Branch if signed `a >= b`. 177 br_if_xsgteq32_i8 = BrIfXsgteq32I8 { a: XReg, b: i8, offset: PcRelOffset }; 178 /// Branch if signed `a >= b`. 179 br_if_xsgteq32_i32 = BrIfXsgteq32I32 { a: XReg, b: i32, offset: PcRelOffset }; 180 /// Branch if unsigned `a < b`. 181 br_if_xult32_u8 = BrIfXult32U8 { a: XReg, b: u8, offset: PcRelOffset }; 182 /// Branch if unsigned `a < b`. 183 br_if_xult32_u32 = BrIfXult32U32 { a: XReg, b: u32, offset: PcRelOffset }; 184 /// Branch if unsigned `a <= b`. 185 br_if_xulteq32_u8 = BrIfXulteq32U8 { a: XReg, b: u8, offset: PcRelOffset }; 186 /// Branch if unsigned `a <= b`. 187 br_if_xulteq32_u32 = BrIfXulteq32U32 { a: XReg, b: u32, offset: PcRelOffset }; 188 /// Branch if unsigned `a > b`. 189 br_if_xugt32_u8 = BrIfXugt32U8 { a: XReg, b: u8, offset: PcRelOffset }; 190 /// Branch if unsigned `a > b`. 191 br_if_xugt32_u32 = BrIfXugt32U32 { a: XReg, b: u32, offset: PcRelOffset }; 192 /// Branch if unsigned `a >= b`. 193 br_if_xugteq32_u8 = BrIfXugteq32U8 { a: XReg, b: u8, offset: PcRelOffset }; 194 /// Branch if unsigned `a >= b`. 195 br_if_xugteq32_u32 = BrIfXugteq32U32 { a: XReg, b: u32, offset: PcRelOffset }; 196 197 /// Branch if `a == b`. 198 br_if_xeq64_i8 = BrIfXeq64I8 { a: XReg, b: i8, offset: PcRelOffset }; 199 /// Branch if `a == b`. 200 br_if_xeq64_i32 = BrIfXeq64I32 { a: XReg, b: i32, offset: PcRelOffset }; 201 /// Branch if `a != `b. 202 br_if_xneq64_i8 = BrIfXneq64I8 { a: XReg, b: i8, offset: PcRelOffset }; 203 /// Branch if `a != `b. 204 br_if_xneq64_i32 = BrIfXneq64I32 { a: XReg, b: i32, offset: PcRelOffset }; 205 /// Branch if signed `a < b`. 206 br_if_xslt64_i8 = BrIfXslt64I8 { a: XReg, b: i8, offset: PcRelOffset }; 207 /// Branch if signed `a < b`. 208 br_if_xslt64_i32 = BrIfXslt64I32 { a: XReg, b: i32, offset: PcRelOffset }; 209 /// Branch if signed `a > b`. 210 br_if_xsgt64_i8 = BrIfXsgt64I8 { a: XReg, b: i8, offset: PcRelOffset }; 211 /// Branch if signed `a > b`. 212 br_if_xsgt64_i32 = BrIfXsgt64I32 { a: XReg, b: i32, offset: PcRelOffset }; 213 /// Branch if signed `a <= b`. 214 br_if_xslteq64_i8 = BrIfXslteq64I8 { a: XReg, b: i8, offset: PcRelOffset }; 215 /// Branch if signed `a <= b`. 216 br_if_xslteq64_i32 = BrIfXslteq64I32 { a: XReg, b: i32, offset: PcRelOffset }; 217 /// Branch if signed `a >= b`. 218 br_if_xsgteq64_i8 = BrIfXsgteq64I8 { a: XReg, b: i8, offset: PcRelOffset }; 219 /// Branch if signed `a >= b`. 220 br_if_xsgteq64_i32 = BrIfXsgteq64I32 { a: XReg, b: i32, offset: PcRelOffset }; 221 /// Branch if unsigned `a < b`. 222 br_if_xult64_u8 = BrIfXult64U8 { a: XReg, b: u8, offset: PcRelOffset }; 223 /// Branch if unsigned `a < b`. 224 br_if_xult64_u32 = BrIfXult64U32 { a: XReg, b: u32, offset: PcRelOffset }; 225 /// Branch if unsigned `a <= b`. 226 br_if_xulteq64_u8 = BrIfXulteq64U8 { a: XReg, b: u8, offset: PcRelOffset }; 227 /// Branch if unsigned `a <= b`. 228 br_if_xulteq64_u32 = BrIfXulteq64U32 { a: XReg, b: u32, offset: PcRelOffset }; 229 /// Branch if unsigned `a > b`. 230 br_if_xugt64_u8 = BrIfXugt64U8 { a: XReg, b: u8, offset: PcRelOffset }; 231 /// Branch if unsigned `a > b`. 232 br_if_xugt64_u32 = BrIfXugt64U32 { a: XReg, b: u32, offset: PcRelOffset }; 233 /// Branch if unsigned `a >= b`. 234 br_if_xugteq64_u8 = BrIfXugteq64U8 { a: XReg, b: u8, offset: PcRelOffset }; 235 /// Branch if unsigned `a >= b`. 236 br_if_xugteq64_u32 = BrIfXugteq64U32 { a: XReg, b: u32, offset: PcRelOffset }; 237 238 /// Branch to the label indicated by `low32(idx)`. 239 /// 240 /// After this instruction are `amt` instances of `PcRelOffset` 241 /// and the `idx` selects which one will be branched to. The value 242 /// of `idx` is clamped to `amt - 1` (e.g. the last offset is the 243 /// "default" one. 244 br_table32 = BrTable32 { idx: XReg, amt: u32 }; 245 246 /// Move between `x` registers. 247 xmov = Xmov { dst: XReg, src: XReg }; 248 249 /// Set `dst = 0` 250 xzero = Xzero { dst: XReg }; 251 /// Set `dst = 1` 252 xone = Xone { dst: XReg }; 253 /// Set `dst = sign_extend(imm8)`. 254 xconst8 = Xconst8 { dst: XReg, imm: i8 }; 255 /// Set `dst = sign_extend(imm16)`. 256 xconst16 = Xconst16 { dst: XReg, imm: i16 }; 257 /// Set `dst = sign_extend(imm32)`. 258 xconst32 = Xconst32 { dst: XReg, imm: i32 }; 259 /// Set `dst = imm64`. 260 xconst64 = Xconst64 { dst: XReg, imm: i64 }; 261 262 /// 32-bit wrapping addition: `low32(dst) = low32(src1) + low32(src2)`. 263 /// 264 /// The upper 32-bits of `dst` are unmodified. 265 xadd32 = Xadd32 { operands: BinaryOperands<XReg> }; 266 /// Same as `xadd32` but `src2` is a zero-extended 8-bit immediate. 267 xadd32_u8 = Xadd32U8 { dst: XReg, src1: XReg, src2: u8 }; 268 /// Same as `xadd32` but `src2` is a 32-bit immediate. 269 xadd32_u32 = Xadd32U32 { dst: XReg, src1: XReg, src2: u32 }; 270 271 /// 64-bit wrapping addition: `dst = src1 + src2`. 272 xadd64 = Xadd64 { operands: BinaryOperands<XReg> }; 273 /// Same as `xadd64` but `src2` is a zero-extended 8-bit immediate. 274 xadd64_u8 = Xadd64U8 { dst: XReg, src1: XReg, src2: u8 }; 275 /// Same as `xadd64` but `src2` is a zero-extended 32-bit immediate. 276 xadd64_u32 = Xadd64U32 { dst: XReg, src1: XReg, src2: u32 }; 277 278 /// `low32(dst) = low32(src1) * low32(src2) + low32(src3)` 279 xmadd32 = Xmadd32 { dst: XReg, src1: XReg, src2: XReg, src3: XReg }; 280 /// `dst = src1 * src2 + src3` 281 xmadd64 = Xmadd64 { dst: XReg, src1: XReg, src2: XReg, src3: XReg }; 282 283 /// 32-bit wrapping subtraction: `low32(dst) = low32(src1) - low32(src2)`. 284 /// 285 /// The upper 32-bits of `dst` are unmodified. 286 xsub32 = Xsub32 { operands: BinaryOperands<XReg> }; 287 /// Same as `xsub32` but `src2` is a zero-extended 8-bit immediate. 288 xsub32_u8 = Xsub32U8 { dst: XReg, src1: XReg, src2: u8 }; 289 /// Same as `xsub32` but `src2` is a 32-bit immediate. 290 xsub32_u32 = Xsub32U32 { dst: XReg, src1: XReg, src2: u32 }; 291 292 /// 64-bit wrapping subtraction: `dst = src1 - src2`. 293 xsub64 = Xsub64 { operands: BinaryOperands<XReg> }; 294 /// Same as `xsub64` but `src2` is a zero-extended 8-bit immediate. 295 xsub64_u8 = Xsub64U8 { dst: XReg, src1: XReg, src2: u8 }; 296 /// Same as `xsub64` but `src2` is a zero-extended 32-bit immediate. 297 xsub64_u32 = Xsub64U32 { dst: XReg, src1: XReg, src2: u32 }; 298 299 /// `low32(dst) = low32(src1) * low32(src2)` 300 xmul32 = XMul32 { operands: BinaryOperands<XReg> }; 301 /// Same as `xmul64` but `src2` is a sign-extended 8-bit immediate. 302 xmul32_s8 = Xmul32S8 { dst: XReg, src1: XReg, src2: i8 }; 303 /// Same as `xmul32` but `src2` is a sign-extended 32-bit immediate. 304 xmul32_s32 = Xmul32S32 { dst: XReg, src1: XReg, src2: i32 }; 305 306 /// `dst = src1 * src2` 307 xmul64 = XMul64 { operands: BinaryOperands<XReg> }; 308 /// Same as `xmul64` but `src2` is a sign-extended 8-bit immediate. 309 xmul64_s8 = Xmul64S8 { dst: XReg, src1: XReg, src2: i8 }; 310 /// Same as `xmul64` but `src2` is a sign-extended 64-bit immediate. 311 xmul64_s32 = Xmul64S32 { dst: XReg, src1: XReg, src2: i32 }; 312 313 /// `low32(dst) = trailing_zeros(low32(src))` 314 xctz32 = Xctz32 { dst: XReg, src: XReg }; 315 /// `dst = trailing_zeros(src)` 316 xctz64 = Xctz64 { dst: XReg, src: XReg }; 317 318 /// `low32(dst) = leading_zeros(low32(src))` 319 xclz32 = Xclz32 { dst: XReg, src: XReg }; 320 /// `dst = leading_zeros(src)` 321 xclz64 = Xclz64 { dst: XReg, src: XReg }; 322 323 /// `low32(dst) = count_ones(low32(src))` 324 xpopcnt32 = Xpopcnt32 { dst: XReg, src: XReg }; 325 /// `dst = count_ones(src)` 326 xpopcnt64 = Xpopcnt64 { dst: XReg, src: XReg }; 327 328 /// `low32(dst) = rotate_left(low32(src1), low32(src2))` 329 xrotl32 = Xrotl32 { operands: BinaryOperands<XReg> }; 330 /// `dst = rotate_left(src1, src2)` 331 xrotl64 = Xrotl64 { operands: BinaryOperands<XReg> }; 332 333 /// `low32(dst) = rotate_right(low32(src1), low32(src2))` 334 xrotr32 = Xrotr32 { operands: BinaryOperands<XReg> }; 335 /// `dst = rotate_right(src1, src2)` 336 xrotr64 = Xrotr64 { operands: BinaryOperands<XReg> }; 337 338 /// `low32(dst) = low32(src1) << low5(src2)` 339 xshl32 = Xshl32 { operands: BinaryOperands<XReg> }; 340 /// `low32(dst) = low32(src1) >> low5(src2)` 341 xshr32_s = Xshr32S { operands: BinaryOperands<XReg> }; 342 /// `low32(dst) = low32(src1) >> low5(src2)` 343 xshr32_u = Xshr32U { operands: BinaryOperands<XReg> }; 344 /// `dst = src1 << low5(src2)` 345 xshl64 = Xshl64 { operands: BinaryOperands<XReg> }; 346 /// `dst = src1 >> low6(src2)` 347 xshr64_s = Xshr64S { operands: BinaryOperands<XReg> }; 348 /// `dst = src1 >> low6(src2)` 349 xshr64_u = Xshr64U { operands: BinaryOperands<XReg> }; 350 351 /// `low32(dst) = low32(src1) << low5(src2)` 352 xshl32_u6 = Xshl32U6 { operands: BinaryOperands<XReg, XReg, U6> }; 353 /// `low32(dst) = low32(src1) >> low5(src2)` 354 xshr32_s_u6 = Xshr32SU6 { operands: BinaryOperands<XReg, XReg, U6> }; 355 /// `low32(dst) = low32(src1) >> low5(src2)` 356 xshr32_u_u6 = Xshr32UU6 { operands: BinaryOperands<XReg, XReg, U6> }; 357 /// `dst = src1 << low5(src2)` 358 xshl64_u6 = Xshl64U6 { operands: BinaryOperands<XReg, XReg, U6> }; 359 /// `dst = src1 >> low6(src2)` 360 xshr64_s_u6 = Xshr64SU6 { operands: BinaryOperands<XReg, XReg, U6> }; 361 /// `dst = src1 >> low6(src2)` 362 xshr64_u_u6 = Xshr64UU6 { operands: BinaryOperands<XReg, XReg, U6> }; 363 364 /// `low32(dst) = -low32(src)` 365 xneg32 = Xneg32 { dst: XReg, src: XReg }; 366 /// `dst = -src` 367 xneg64 = Xneg64 { dst: XReg, src: XReg }; 368 369 /// `low32(dst) = src1 == src2` 370 xeq64 = Xeq64 { operands: BinaryOperands<XReg> }; 371 /// `low32(dst) = src1 != src2` 372 xneq64 = Xneq64 { operands: BinaryOperands<XReg> }; 373 /// `low32(dst) = src1 < src2` (signed) 374 xslt64 = Xslt64 { operands: BinaryOperands<XReg> }; 375 /// `low32(dst) = src1 <= src2` (signed) 376 xslteq64 = Xslteq64 { operands: BinaryOperands<XReg> }; 377 /// `low32(dst) = src1 < src2` (unsigned) 378 xult64 = Xult64 { operands: BinaryOperands<XReg> }; 379 /// `low32(dst) = src1 <= src2` (unsigned) 380 xulteq64 = Xulteq64 { operands: BinaryOperands<XReg> }; 381 /// `low32(dst) = low32(src1) == low32(src2)` 382 xeq32 = Xeq32 { operands: BinaryOperands<XReg> }; 383 /// `low32(dst) = low32(src1) != low32(src2)` 384 xneq32 = Xneq32 { operands: BinaryOperands<XReg> }; 385 /// `low32(dst) = low32(src1) < low32(src2)` (signed) 386 xslt32 = Xslt32 { operands: BinaryOperands<XReg> }; 387 /// `low32(dst) = low32(src1) <= low32(src2)` (signed) 388 xslteq32 = Xslteq32 { operands: BinaryOperands<XReg> }; 389 /// `low32(dst) = low32(src1) < low32(src2)` (unsigned) 390 xult32 = Xult32 { operands: BinaryOperands<XReg> }; 391 /// `low32(dst) = low32(src1) <= low32(src2)` (unsigned) 392 xulteq32 = Xulteq32 { operands: BinaryOperands<XReg> }; 393 394 // Loads/stores with various addressing modes. Note that each style 395 // of addressing mode is split to its own suite of instructions to 396 // simplify the implementation of each opcode and avoid internal 397 // branching when using one addressing mode vs another. 398 // 399 // Note that big-endian, float, and vector loads are deferred to 400 // the "extended" opcode set below. 401 402 /// `low32(dst) = zext_8_32(*addr)` 403 xload8_u32_o32 = XLoad8U32O32 { dst: XReg, addr: AddrO32 }; 404 /// `low32(dst) = sext_8_32(*addr)` 405 xload8_s32_o32 = XLoad8S32O32 { dst: XReg, addr: AddrO32 }; 406 /// `low32(dst) = o32ext_16_32(*addr)` 407 xload16le_u32_o32 = XLoad16LeU32O32 { dst: XReg, addr: AddrO32 }; 408 /// `low32(dst) = sext_16_32(*addr)` 409 xload16le_s32_o32 = XLoad16LeS32O32 { dst: XReg, addr: AddrO32 }; 410 /// `low32(dst) = *addr` 411 xload32le_o32 = XLoad32LeO32 { dst: XReg, addr: AddrO32 }; 412 /// `dst = *addr` 413 xload64le_o32 = XLoad64LeO32 { dst: XReg, addr: AddrO32 }; 414 /// `*addr = low8(src)` 415 xstore8_o32 = XStore8O32 { addr: AddrO32, src: XReg }; 416 /// `*addr = low16(src)` 417 xstore16le_o32 = XStore16LeO32 { addr: AddrO32, src: XReg }; 418 /// `*addr = low32(src)` 419 xstore32le_o32 = XStore32LeO32 { addr: AddrO32, src: XReg }; 420 /// `*addr = src` 421 xstore64le_o32 = XStore64LeO32 { addr: AddrO32, src: XReg }; 422 423 /// `low32(dst) = zext_8_32(*addr)` 424 xload8_u32_z = XLoad8U32Z { dst: XReg, addr: AddrZ }; 425 /// `low32(dst) = sext_8_32(*addr)` 426 xload8_s32_z = XLoad8S32Z { dst: XReg, addr: AddrZ }; 427 /// `low32(dst) = zext_16_32(*addr)` 428 xload16le_u32_z = XLoad16LeU32Z { dst: XReg, addr: AddrZ }; 429 /// `low32(dst) = sext_16_32(*addr)` 430 xload16le_s32_z = XLoad16LeS32Z { dst: XReg, addr: AddrZ }; 431 /// `low32(dst) = *addr` 432 xload32le_z = XLoad32LeZ { dst: XReg, addr: AddrZ }; 433 /// `dst = *addr` 434 xload64le_z = XLoad64LeZ { dst: XReg, addr: AddrZ }; 435 /// `*addr = low8(src)` 436 xstore8_z = XStore8Z { addr: AddrZ, src: XReg }; 437 /// `*addr = low16(src)` 438 xstore16le_z = XStore16LeZ { addr: AddrZ, src: XReg }; 439 /// `*addr = low32(src)` 440 xstore32le_z = XStore32LeZ { addr: AddrZ, src: XReg }; 441 /// `*addr = src` 442 xstore64le_z = XStore64LeZ { addr: AddrZ, src: XReg }; 443 444 /// `low32(dst) = zext_8_32(*addr)` 445 xload8_u32_g32 = XLoad8U32G32 { dst: XReg, addr: AddrG32 }; 446 /// `low32(dst) = sext_8_32(*addr)` 447 xload8_s32_g32 = XLoad8S32G32 { dst: XReg, addr: AddrG32 }; 448 /// `low32(dst) = zext_16_32(*addr)` 449 xload16le_u32_g32 = XLoad16LeU32G32 { dst: XReg, addr: AddrG32 }; 450 /// `low32(dst) = sext_16_32(*addr)` 451 xload16le_s32_g32 = XLoad16LeS32G32 { dst: XReg, addr: AddrG32 }; 452 /// `low32(dst) = *addr` 453 xload32le_g32 = XLoad32LeG32 { dst: XReg, addr: AddrG32 }; 454 /// `dst = *addr` 455 xload64le_g32 = XLoad64LeG32 { dst: XReg, addr: AddrG32 }; 456 /// `*addr = low8(src)` 457 xstore8_g32 = XStore8G32 { addr: AddrG32, src: XReg }; 458 /// `*addr = low16(src)` 459 xstore16le_g32 = XStore16LeG32 { addr: AddrG32, src: XReg }; 460 /// `*addr = low32(src)` 461 xstore32le_g32 = XStore32LeG32 { addr: AddrG32, src: XReg }; 462 /// `*addr = src` 463 xstore64le_g32 = XStore64LeG32 { addr: AddrG32, src: XReg }; 464 465 /// `low32(dst) = zext_8_32(*addr)` 466 xload8_u32_g32bne = XLoad8U32G32Bne { dst: XReg, addr: AddrG32Bne }; 467 /// `low32(dst) = sext_8_32(*addr)` 468 xload8_s32_g32bne = XLoad8S32G32Bne { dst: XReg, addr: AddrG32Bne }; 469 /// `low32(dst) = zext_16_32(*addr)` 470 xload16le_u32_g32bne = XLoad16LeU32G32Bne { dst: XReg, addr: AddrG32Bne }; 471 /// `low32(dst) = sext_16_32(*addr)` 472 xload16le_s32_g32bne = XLoad16LeS32G32Bne { dst: XReg, addr: AddrG32Bne }; 473 /// `low32(dst) = *addr` 474 xload32le_g32bne = XLoad32LeG32Bne { dst: XReg, addr: AddrG32Bne }; 475 /// `dst = *addr` 476 xload64le_g32bne = XLoad64LeG32Bne { dst: XReg, addr: AddrG32Bne }; 477 /// `*addr = low8(src)` 478 xstore8_g32bne = XStore8G32Bne { addr: AddrG32Bne, src: XReg }; 479 /// `*addr = low16(src)` 480 xstore16le_g32bne = XStore16LeG32Bne { addr: AddrG32Bne, src: XReg }; 481 /// `*addr = low32(src)` 482 xstore32le_g32bne = XStore32LeG32Bne { addr: AddrG32Bne, src: XReg }; 483 /// `*addr = src` 484 xstore64le_g32bne = XStore64LeG32Bne { addr: AddrG32Bne, src: XReg }; 485 486 487 /// `push lr; push fp; fp = sp` 488 push_frame = PushFrame ; 489 /// `sp = fp; pop fp; pop lr` 490 pop_frame = PopFrame ; 491 492 /// Macro-instruction to enter a function, allocate some stack, and 493 /// then save some registers. 494 /// 495 /// This is equivalent to `push_frame`, `stack_alloc32 amt`, then 496 /// saving all of `regs` to the top of the stack just allocated. 497 push_frame_save = PushFrameSave { amt: u16, regs: UpperRegSet<XReg> }; 498 /// Inverse of `push_frame_save`. Restores `regs` from the top of 499 /// the stack, then runs `stack_free32 amt`, then runs `pop_frame`. 500 pop_frame_restore = PopFrameRestore { amt: u16, regs: UpperRegSet<XReg> }; 501 502 /// `sp = sp.checked_sub(amt)` 503 stack_alloc32 = StackAlloc32 { amt: u32 }; 504 505 /// `sp = sp + amt` 506 stack_free32 = StackFree32 { amt: u32 }; 507 508 /// `dst = zext(low8(src))` 509 zext8 = Zext8 { dst: XReg, src: XReg }; 510 /// `dst = zext(low16(src))` 511 zext16 = Zext16 { dst: XReg, src: XReg }; 512 /// `dst = zext(low32(src))` 513 zext32 = Zext32 { dst: XReg, src: XReg }; 514 /// `dst = sext(low8(src))` 515 sext8 = Sext8 { dst: XReg, src: XReg }; 516 /// `dst = sext(low16(src))` 517 sext16 = Sext16 { dst: XReg, src: XReg }; 518 /// `dst = sext(low32(src))` 519 sext32 = Sext32 { dst: XReg, src: XReg }; 520 521 /// `low32(dst) = |low32(src)|` 522 xabs32 = XAbs32 { dst: XReg, src: XReg }; 523 /// `dst = |src|` 524 xabs64 = XAbs64 { dst: XReg, src: XReg }; 525 526 /// `low32(dst) = low32(src1) / low32(src2)` (signed) 527 xdiv32_s = XDiv32S { operands: BinaryOperands<XReg> }; 528 529 /// `dst = src1 / src2` (signed) 530 xdiv64_s = XDiv64S { operands: BinaryOperands<XReg> }; 531 532 /// `low32(dst) = low32(src1) / low32(src2)` (unsigned) 533 xdiv32_u = XDiv32U { operands: BinaryOperands<XReg> }; 534 535 /// `dst = src1 / src2` (unsigned) 536 xdiv64_u = XDiv64U { operands: BinaryOperands<XReg> }; 537 538 /// `low32(dst) = low32(src1) % low32(src2)` (signed) 539 xrem32_s = XRem32S { operands: BinaryOperands<XReg> }; 540 541 /// `dst = src1 / src2` (signed) 542 xrem64_s = XRem64S { operands: BinaryOperands<XReg> }; 543 544 /// `low32(dst) = low32(src1) % low32(src2)` (unsigned) 545 xrem32_u = XRem32U { operands: BinaryOperands<XReg> }; 546 547 /// `dst = src1 / src2` (unsigned) 548 xrem64_u = XRem64U { operands: BinaryOperands<XReg> }; 549 550 /// `low32(dst) = low32(src1) & low32(src2)` 551 xband32 = XBand32 { operands: BinaryOperands<XReg> }; 552 /// Same as `xband64` but `src2` is a sign-extended 8-bit immediate. 553 xband32_s8 = Xband32S8 { dst: XReg, src1: XReg, src2: i8 }; 554 /// Same as `xband32` but `src2` is a sign-extended 32-bit immediate. 555 xband32_s32 = Xband32S32 { dst: XReg, src1: XReg, src2: i32 }; 556 /// `dst = src1 & src2` 557 xband64 = XBand64 { operands: BinaryOperands<XReg> }; 558 /// Same as `xband64` but `src2` is a sign-extended 8-bit immediate. 559 xband64_s8 = Xband64S8 { dst: XReg, src1: XReg, src2: i8 }; 560 /// Same as `xband64` but `src2` is a sign-extended 32-bit immediate. 561 xband64_s32 = Xband64S32 { dst: XReg, src1: XReg, src2: i32 }; 562 /// `low32(dst) = low32(src1) | low32(src2)` 563 xbor32 = XBor32 { operands: BinaryOperands<XReg> }; 564 /// Same as `xbor64` but `src2` is a sign-extended 8-bit immediate. 565 xbor32_s8 = Xbor32S8 { dst: XReg, src1: XReg, src2: i8 }; 566 /// Same as `xbor32` but `src2` is a sign-extended 32-bit immediate. 567 xbor32_s32 = Xbor32S32 { dst: XReg, src1: XReg, src2: i32 }; 568 /// `dst = src1 | src2` 569 xbor64 = XBor64 { operands: BinaryOperands<XReg> }; 570 /// Same as `xbor64` but `src2` is a sign-extended 8-bit immediate. 571 xbor64_s8 = Xbor64S8 { dst: XReg, src1: XReg, src2: i8 }; 572 /// Same as `xbor64` but `src2` is a sign-extended 32-bit immediate. 573 xbor64_s32 = Xbor64S32 { dst: XReg, src1: XReg, src2: i32 }; 574 575 /// `low32(dst) = low32(src1) ^ low32(src2)` 576 xbxor32 = XBxor32 { operands: BinaryOperands<XReg> }; 577 /// Same as `xbxor64` but `src2` is a sign-extended 8-bit immediate. 578 xbxor32_s8 = Xbxor32S8 { dst: XReg, src1: XReg, src2: i8 }; 579 /// Same as `xbxor32` but `src2` is a sign-extended 32-bit immediate. 580 xbxor32_s32 = Xbxor32S32 { dst: XReg, src1: XReg, src2: i32 }; 581 /// `dst = src1 ^ src2` 582 xbxor64 = XBxor64 { operands: BinaryOperands<XReg> }; 583 /// Same as `xbxor64` but `src2` is a sign-extended 8-bit immediate. 584 xbxor64_s8 = Xbxor64S8 { dst: XReg, src1: XReg, src2: i8 }; 585 /// Same as `xbxor64` but `src2` is a sign-extended 32-bit immediate. 586 xbxor64_s32 = Xbxor64S32 { dst: XReg, src1: XReg, src2: i32 }; 587 588 /// `low32(dst) = !low32(src1)` 589 xbnot32 = XBnot32 { dst: XReg, src: XReg }; 590 /// `dst = !src1` 591 xbnot64 = XBnot64 { dst: XReg, src: XReg }; 592 593 /// `low32(dst) = min(low32(src1), low32(src2))` (unsigned) 594 xmin32_u = Xmin32U { operands: BinaryOperands<XReg> }; 595 /// `low32(dst) = min(low32(src1), low32(src2))` (signed) 596 xmin32_s = Xmin32S { operands: BinaryOperands<XReg> }; 597 /// `low32(dst) = max(low32(src1), low32(src2))` (unsigned) 598 xmax32_u = Xmax32U { operands: BinaryOperands<XReg> }; 599 /// `low32(dst) = max(low32(src1), low32(src2))` (signed) 600 xmax32_s = Xmax32S { operands: BinaryOperands<XReg> }; 601 /// `dst = min(src1, src2)` (unsigned) 602 xmin64_u = Xmin64U { operands: BinaryOperands<XReg> }; 603 /// `dst = min(src1, src2)` (signed) 604 xmin64_s = Xmin64S { operands: BinaryOperands<XReg> }; 605 /// `dst = max(src1, src2)` (unsigned) 606 xmax64_u = Xmax64U { operands: BinaryOperands<XReg> }; 607 /// `dst = max(src1, src2)` (signed) 608 xmax64_s = Xmax64S { operands: BinaryOperands<XReg> }; 609 610 /// `low32(dst) = low32(cond) ? low32(if_nonzero) : low32(if_zero)` 611 xselect32 = XSelect32 { dst: XReg, cond: XReg, if_nonzero: XReg, if_zero: XReg }; 612 /// `dst = low32(cond) ? if_nonzero : if_zero` 613 xselect64 = XSelect64 { dst: XReg, cond: XReg, if_nonzero: XReg, if_zero: XReg }; 614 } 615 }; 616 } 617 618 /// Calls the given macro with each extended opcode. 619 #[macro_export] 620 macro_rules! for_each_extended_op { 621 ( $macro:ident ) => { 622 $macro! { 623 /// Raise a trap. 624 trap = Trap; 625 626 /// Do nothing. 627 nop = Nop; 628 629 /// A special opcode to halt interpreter execution and yield control 630 /// back to the host. 631 /// 632 /// This opcode results in `DoneReason::CallIndirectHost` where the 633 /// `id` here is shepherded along to the embedder. It's up to the 634 /// embedder to determine what to do with the `id` and the current 635 /// state of registers and the stack. 636 /// 637 /// In Wasmtime this is used to implement interpreter-to-host calls. 638 /// This is modeled as a `call` instruction where the first 639 /// parameter is the native function pointer to invoke and all 640 /// remaining parameters for the native function are in following 641 /// parameter positions (e.g. `x1`, `x2`, ...). The results of the 642 /// host call are then store in `x0`. 643 /// 644 /// Handling this in Wasmtime is done through a "relocation" which 645 /// is resolved at link-time when raw bytecode from Cranelift is 646 /// assembled into the final object that Wasmtime will interpret. 647 call_indirect_host = CallIndirectHost { id: u8 }; 648 649 /// Adds `offset` to the pc of this instruction and stores it in 650 /// `dst`. 651 xpcadd = Xpcadd { dst: XReg, offset: PcRelOffset }; 652 653 /// Gets the special "fp" register and moves it into `dst`. 654 xmov_fp = XmovFp { dst: XReg }; 655 656 /// Gets the special "lr" register and moves it into `dst`. 657 xmov_lr = XmovLr { dst: XReg }; 658 659 /// `dst = byteswap(low32(src))` 660 bswap32 = Bswap32 { dst: XReg, src: XReg }; 661 /// `dst = byteswap(src)` 662 bswap64 = Bswap64 { dst: XReg, src: XReg }; 663 664 /// 32-bit checked unsigned addition: `low32(dst) = low32(src1) + 665 /// low32(src2)`. 666 /// 667 /// The upper 32-bits of `dst` are unmodified. Traps if the addition 668 /// overflows. 669 xadd32_uoverflow_trap = Xadd32UoverflowTrap { operands: BinaryOperands<XReg> }; 670 671 /// 64-bit checked unsigned addition: `dst = src1 + src2`. 672 xadd64_uoverflow_trap = Xadd64UoverflowTrap { operands: BinaryOperands<XReg> }; 673 674 /// `dst = high64(src1 * src2)` (signed) 675 xmulhi64_s = XMulHi64S { operands: BinaryOperands<XReg> }; 676 /// `dst = high64(src1 * src2)` (unsigned) 677 xmulhi64_u = XMulHi64U { operands: BinaryOperands<XReg> }; 678 679 /// low32(dst) = if low32(src) == 0 { 0 } else { -1 } 680 xbmask32 = Xbmask32 { dst: XReg, src: XReg }; 681 /// dst = if src == 0 { 0 } else { -1 } 682 xbmask64 = Xbmask64 { dst: XReg, src: XReg }; 683 684 // Big-endian loads/stores of X-registers using the "o32" 685 // addressing mode 686 687 /// `low32(dst) = zext(*addr)` 688 xload16be_u32_o32 = XLoad16BeU32O32 { dst: XReg, addr: AddrO32 }; 689 /// `low32(dst) = sext(*addr)` 690 xload16be_s32_o32 = XLoad16BeS32O32 { dst: XReg, addr: AddrO32 }; 691 /// `low32(dst) = zext(*addr)` 692 xload32be_o32 = XLoad32BeO32 { dst: XReg, addr: AddrO32 }; 693 /// `dst = *addr` 694 xload64be_o32 = XLoad64BeO32 { dst: XReg, addr: AddrO32 }; 695 /// `*addr = low16(src)` 696 xstore16be_o32 = XStore16BeO32 { addr: AddrO32, src: XReg }; 697 /// `*addr = low32(src)` 698 xstore32be_o32 = XStore32BeO32 { addr: AddrO32, src: XReg }; 699 /// `*addr = low64(src)` 700 xstore64be_o32 = XStore64BeO32 { addr: AddrO32, src: XReg }; 701 702 // Big and little endian float loads/stores. Note that the "Z" 703 // addressing mode only has little-endian variants. 704 705 /// `low32(dst) = zext(*addr)` 706 fload32be_o32 = Fload32BeO32 { dst: FReg, addr: AddrO32 }; 707 /// `dst = *addr` 708 fload64be_o32 = Fload64BeO32 { dst: FReg, addr: AddrO32 }; 709 /// `*addr = low32(src)` 710 fstore32be_o32 = Fstore32BeO32 { addr: AddrO32, src: FReg }; 711 /// `*addr = src` 712 fstore64be_o32 = Fstore64BeO32 { addr: AddrO32, src: FReg }; 713 714 /// `low32(dst) = zext(*addr)` 715 fload32le_o32 = Fload32LeO32 { dst: FReg, addr: AddrO32 }; 716 /// `dst = *addr` 717 fload64le_o32 = Fload64LeO32 { dst: FReg, addr: AddrO32 }; 718 /// `*addr = low32(src)` 719 fstore32le_o32 = Fstore32LeO32 { addr: AddrO32, src: FReg }; 720 /// `*addr = src` 721 fstore64le_o32 = Fstore64LeO32 { addr: AddrO32, src: FReg }; 722 723 /// `low32(dst) = zext(*addr)` 724 fload32le_z = Fload32LeZ { dst: FReg, addr: AddrZ }; 725 /// `dst = *addr` 726 fload64le_z = Fload64LeZ { dst: FReg, addr: AddrZ }; 727 /// `*addr = low32(src)` 728 fstore32le_z = Fstore32LeZ { addr: AddrZ, src: FReg }; 729 /// `*addr = src` 730 fstore64le_z = Fstore64LeZ { addr: AddrZ, src: FReg }; 731 732 /// `low32(dst) = zext(*addr)` 733 fload32le_g32 = Fload32LeG32 { dst: FReg, addr: AddrG32 }; 734 /// `dst = *addr` 735 fload64le_g32 = Fload64LeG32 { dst: FReg, addr: AddrG32 }; 736 /// `*addr = low32(src)` 737 fstore32le_g32 = Fstore32LeG32 { addr: AddrG32, src: FReg }; 738 /// `*addr = src` 739 fstore64le_g32 = Fstore64LeG32 { addr: AddrG32, src: FReg }; 740 741 // Vector loads/stores. Note that big-endian variants are all 742 // omitted. 743 744 /// `dst = *addr` 745 vload128le_o32 = VLoad128O32 { dst: VReg, addr: AddrO32 }; 746 /// `*addr = src` 747 vstore128le_o32 = Vstore128LeO32 { addr: AddrO32, src: VReg }; 748 /// `dst = *(ptr + offset)` 749 vload128le_z = VLoad128Z { dst: VReg, addr: AddrZ }; 750 /// `*(ptr + offset) = src` 751 vstore128le_z = Vstore128LeZ { addr: AddrZ, src: VReg }; 752 /// `dst = *(ptr + offset)` 753 vload128le_g32 = VLoad128G32 { dst: VReg, addr: AddrG32 }; 754 /// `*(ptr + offset) = src` 755 vstore128le_g32 = Vstore128LeG32 { addr: AddrG32, src: VReg }; 756 757 /// Move between `f` registers. 758 fmov = Fmov { dst: FReg, src: FReg }; 759 /// Move between `v` registers. 760 vmov = Vmov { dst: VReg, src: VReg }; 761 762 /// `low32(dst) = bitcast low32(src) as i32` 763 bitcast_int_from_float_32 = BitcastIntFromFloat32 { dst: XReg, src: FReg }; 764 /// `dst = bitcast src as i64` 765 bitcast_int_from_float_64 = BitcastIntFromFloat64 { dst: XReg, src: FReg }; 766 /// `low32(dst) = bitcast low32(src) as f32` 767 bitcast_float_from_int_32 = BitcastFloatFromInt32 { dst: FReg, src: XReg }; 768 /// `dst = bitcast src as f64` 769 bitcast_float_from_int_64 = BitcastFloatFromInt64 { dst: FReg, src: XReg }; 770 771 /// `low32(dst) = bits` 772 fconst32 = FConst32 { dst: FReg, bits: u32 }; 773 /// `dst = bits` 774 fconst64 = FConst64 { dst: FReg, bits: u64 }; 775 776 /// `low32(dst) = zext(src1 == src2)` 777 feq32 = Feq32 { dst: XReg, src1: FReg, src2: FReg }; 778 /// `low32(dst) = zext(src1 != src2)` 779 fneq32 = Fneq32 { dst: XReg, src1: FReg, src2: FReg }; 780 /// `low32(dst) = zext(src1 < src2)` 781 flt32 = Flt32 { dst: XReg, src1: FReg, src2: FReg }; 782 /// `low32(dst) = zext(src1 <= src2)` 783 flteq32 = Flteq32 { dst: XReg, src1: FReg, src2: FReg }; 784 /// `low32(dst) = zext(src1 == src2)` 785 feq64 = Feq64 { dst: XReg, src1: FReg, src2: FReg }; 786 /// `low32(dst) = zext(src1 != src2)` 787 fneq64 = Fneq64 { dst: XReg, src1: FReg, src2: FReg }; 788 /// `low32(dst) = zext(src1 < src2)` 789 flt64 = Flt64 { dst: XReg, src1: FReg, src2: FReg }; 790 /// `low32(dst) = zext(src1 <= src2)` 791 flteq64 = Flteq64 { dst: XReg, src1: FReg, src2: FReg }; 792 793 /// `low32(dst) = low32(cond) ? low32(if_nonzero) : low32(if_zero)` 794 fselect32 = FSelect32 { dst: FReg, cond: XReg, if_nonzero: FReg, if_zero: FReg }; 795 /// `dst = low32(cond) ? if_nonzero : if_zero` 796 fselect64 = FSelect64 { dst: FReg, cond: XReg, if_nonzero: FReg, if_zero: FReg }; 797 798 /// `low32(dst) = demote(src)` 799 f32_from_f64 = F32FromF64 { dst: FReg, src: FReg }; 800 /// `(st) = promote(low32(src))` 801 f64_from_f32 = F64FromF32 { dst: FReg, src: FReg }; 802 803 /// `low32(dst) = checked_f32_from_signed(low32(src))` 804 f32_from_x32_s = F32FromX32S { dst: FReg, src: XReg }; 805 /// `low32(dst) = checked_f32_from_unsigned(low32(src))` 806 f32_from_x32_u = F32FromX32U { dst: FReg, src: XReg }; 807 /// `low32(dst) = checked_f32_from_signed(src)` 808 f32_from_x64_s = F32FromX64S { dst: FReg, src: XReg }; 809 /// `low32(dst) = checked_f32_from_unsigned(src)` 810 f32_from_x64_u = F32FromX64U { dst: FReg, src: XReg }; 811 /// `dst = checked_f64_from_signed(low32(src))` 812 f64_from_x32_s = F64FromX32S { dst: FReg, src: XReg }; 813 /// `dst = checked_f64_from_unsigned(low32(src))` 814 f64_from_x32_u = F64FromX32U { dst: FReg, src: XReg }; 815 /// `dst = checked_f64_from_signed(src)` 816 f64_from_x64_s = F64FromX64S { dst: FReg, src: XReg }; 817 /// `dst = checked_f64_from_unsigned(src)` 818 f64_from_x64_u = F64FromX64U { dst: FReg, src: XReg }; 819 820 /// `low32(dst) = checked_signed_from_f32(low32(src))` 821 x32_from_f32_s = X32FromF32S { dst: XReg, src: FReg }; 822 /// `low32(dst) = checked_unsigned_from_f32(low32(src))` 823 x32_from_f32_u = X32FromF32U { dst: XReg, src: FReg }; 824 /// `low32(dst) = checked_signed_from_f64(src)` 825 x32_from_f64_s = X32FromF64S { dst: XReg, src: FReg }; 826 /// `low32(dst) = checked_unsigned_from_f64(src)` 827 x32_from_f64_u = X32FromF64U { dst: XReg, src: FReg }; 828 /// `dst = checked_signed_from_f32(low32(src))` 829 x64_from_f32_s = X64FromF32S { dst: XReg, src: FReg }; 830 /// `dst = checked_unsigned_from_f32(low32(src))` 831 x64_from_f32_u = X64FromF32U { dst: XReg, src: FReg }; 832 /// `dst = checked_signed_from_f64(src)` 833 x64_from_f64_s = X64FromF64S { dst: XReg, src: FReg }; 834 /// `dst = checked_unsigned_from_f64(src)` 835 x64_from_f64_u = X64FromF64U { dst: XReg, src: FReg }; 836 837 /// `low32(dst) = saturating_signed_from_f32(low32(src))` 838 x32_from_f32_s_sat = X32FromF32SSat { dst: XReg, src: FReg }; 839 /// `low32(dst) = saturating_unsigned_from_f32(low32(src))` 840 x32_from_f32_u_sat = X32FromF32USat { dst: XReg, src: FReg }; 841 /// `low32(dst) = saturating_signed_from_f64(src)` 842 x32_from_f64_s_sat = X32FromF64SSat { dst: XReg, src: FReg }; 843 /// `low32(dst) = saturating_unsigned_from_f64(src)` 844 x32_from_f64_u_sat = X32FromF64USat { dst: XReg, src: FReg }; 845 /// `dst = saturating_signed_from_f32(low32(src))` 846 x64_from_f32_s_sat = X64FromF32SSat { dst: XReg, src: FReg }; 847 /// `dst = saturating_unsigned_from_f32(low32(src))` 848 x64_from_f32_u_sat = X64FromF32USat { dst: XReg, src: FReg }; 849 /// `dst = saturating_signed_from_f64(src)` 850 x64_from_f64_s_sat = X64FromF64SSat { dst: XReg, src: FReg }; 851 /// `dst = saturating_unsigned_from_f64(src)` 852 x64_from_f64_u_sat = X64FromF64USat { dst: XReg, src: FReg }; 853 854 /// `low32(dst) = copysign(low32(src1), low32(src2))` 855 fcopysign32 = FCopySign32 { operands: BinaryOperands<FReg> }; 856 /// `dst = copysign(src1, src2)` 857 fcopysign64 = FCopySign64 { operands: BinaryOperands<FReg> }; 858 859 /// `low32(dst) = low32(src1) + low32(src2)` 860 fadd32 = Fadd32 { operands: BinaryOperands<FReg> }; 861 /// `low32(dst) = low32(src1) - low32(src2)` 862 fsub32 = Fsub32 { operands: BinaryOperands<FReg> }; 863 /// `low128(dst) = low128(src1) - low128(src2)` 864 vsubf32x4 = Vsubf32x4 { operands: BinaryOperands<VReg> }; 865 /// `low32(dst) = low32(src1) * low32(src2)` 866 fmul32 = Fmul32 { operands: BinaryOperands<FReg> }; 867 /// `low128(dst) = low128(src1) * low128(src2)` 868 vmulf32x4 = Vmulf32x4 { operands: BinaryOperands<VReg> }; 869 /// `low32(dst) = low32(src1) / low32(src2)` 870 fdiv32 = Fdiv32 { operands: BinaryOperands<FReg> }; 871 /// `low128(dst) = low128(src1) / low128(src2)` 872 vdivf32x4 = Vdivf32x4 { operands: BinaryOperands<VReg> }; 873 /// `low32(dst) = ieee_maximum(low32(src1), low32(src2))` 874 fmaximum32 = Fmaximum32 { operands: BinaryOperands<FReg> }; 875 /// `low32(dst) = ieee_minimum(low32(src1), low32(src2))` 876 fminimum32 = Fminimum32 { operands: BinaryOperands<FReg> }; 877 /// `low32(dst) = ieee_trunc(low32(src))` 878 ftrunc32 = Ftrunc32 { dst: FReg, src: FReg }; 879 /// `low128(dst) = ieee_trunc(low128(src))` 880 vtrunc32x4 = Vtrunc32x4 { dst: VReg, src: VReg }; 881 /// `low128(dst) = ieee_trunc(low128(src))` 882 vtrunc64x2 = Vtrunc64x2 { dst: VReg, src: VReg }; 883 /// `low32(dst) = ieee_floor(low32(src))` 884 ffloor32 = Ffloor32 { dst: FReg, src: FReg }; 885 /// `low128(dst) = ieee_floor(low128(src))` 886 vfloor32x4 = Vfloor32x4 { dst: VReg, src: VReg }; 887 /// `low128(dst) = ieee_floor(low128(src))` 888 vfloor64x2 = Vfloor64x2 { dst: VReg, src: VReg }; 889 /// `low32(dst) = ieee_ceil(low32(src))` 890 fceil32 = Fceil32 { dst: FReg, src: FReg }; 891 /// `low128(dst) = ieee_ceil(low128(src))` 892 vceil32x4 = Vceil32x4 { dst: VReg, src: VReg }; 893 /// `low128(dst) = ieee_ceil(low128(src))` 894 vceil64x2 = Vceil64x2 { dst: VReg, src: VReg }; 895 /// `low32(dst) = ieee_nearest(low32(src))` 896 fnearest32 = Fnearest32 { dst: FReg, src: FReg }; 897 /// `low32(dst) = ieee_sqrt(low32(src))` 898 fsqrt32 = Fsqrt32 { dst: FReg, src: FReg }; 899 /// `low32(dst) = ieee_sqrt(low32(src))` 900 vsqrt32x4 = Vsqrt32x4 { dst: VReg, src: VReg }; 901 /// `low32(dst) = ieee_sqrt(low32(src))` 902 vsqrt64x2 = Vsqrt64x2 { dst: VReg, src: VReg }; 903 /// `low32(dst) = -low32(src)` 904 fneg32 = Fneg32 { dst: FReg, src: FReg }; 905 /// `low128(dst) = -low128(src)` 906 vnegf32x4 = Vnegf32x4 { dst: VReg, src: VReg }; 907 /// `low32(dst) = |low32(src)|` 908 fabs32 = Fabs32 { dst: FReg, src: FReg }; 909 910 /// `dst = src1 + src2` 911 fadd64 = Fadd64 { operands: BinaryOperands<FReg> }; 912 /// `dst = src1 - src2` 913 fsub64 = Fsub64 { operands: BinaryOperands<FReg> }; 914 /// `dst = src1 * src2` 915 fmul64 = Fmul64 { operands: BinaryOperands<FReg> }; 916 /// `dst = src1 / src2` 917 fdiv64 = Fdiv64 { operands: BinaryOperands<FReg> }; 918 /// `dst = src1 / src2` 919 vdivf64x2 = VDivF64x2 { operands: BinaryOperands<VReg> }; 920 /// `dst = ieee_maximum(src1, src2)` 921 fmaximum64 = Fmaximum64 { operands: BinaryOperands<FReg> }; 922 /// `dst = ieee_minimum(src1, src2)` 923 fminimum64 = Fminimum64 { operands: BinaryOperands<FReg> }; 924 /// `dst = ieee_trunc(src)` 925 ftrunc64 = Ftrunc64 { dst: FReg, src: FReg }; 926 /// `dst = ieee_floor(src)` 927 ffloor64 = Ffloor64 { dst: FReg, src: FReg }; 928 /// `dst = ieee_ceil(src)` 929 fceil64 = Fceil64 { dst: FReg, src: FReg }; 930 /// `dst = ieee_nearest(src)` 931 fnearest64 = Fnearest64 { dst: FReg, src: FReg }; 932 /// `low128(dst) = ieee_nearest(low128(src))` 933 vnearest32x4 = Vnearest32x4 { dst: VReg, src: VReg }; 934 /// `low128(dst) = ieee_nearest(low128(src))` 935 vnearest64x2 = Vnearest64x2 { dst: VReg, src: VReg }; 936 /// `dst = ieee_sqrt(src)` 937 fsqrt64 = Fsqrt64 { dst: FReg, src: FReg }; 938 /// `dst = -src` 939 fneg64 = Fneg64 { dst: FReg, src: FReg }; 940 /// `dst = |src|` 941 fabs64 = Fabs64 { dst: FReg, src: FReg }; 942 943 /// `dst = imm` 944 vconst128 = Vconst128 { dst: VReg, imm: u128 }; 945 946 /// `dst = src1 + src2` 947 vaddi8x16 = VAddI8x16 { operands: BinaryOperands<VReg> }; 948 /// `dst = src1 + src2` 949 vaddi16x8 = VAddI16x8 { operands: BinaryOperands<VReg> }; 950 /// `dst = src1 + src2` 951 vaddi32x4 = VAddI32x4 { operands: BinaryOperands<VReg> }; 952 /// `dst = src1 + src2` 953 vaddi64x2 = VAddI64x2 { operands: BinaryOperands<VReg> }; 954 /// `dst = src1 + src2` 955 vaddf32x4 = VAddF32x4 { operands: BinaryOperands<VReg> }; 956 /// `dst = src1 + src2` 957 vaddf64x2 = VAddF64x2 { operands: BinaryOperands<VReg> }; 958 959 /// `dst = satruating_add(src1, src2)` 960 vaddi8x16_sat = VAddI8x16Sat { operands: BinaryOperands<VReg> }; 961 /// `dst = satruating_add(src1, src2)` 962 vaddu8x16_sat = VAddU8x16Sat { operands: BinaryOperands<VReg> }; 963 /// `dst = satruating_add(src1, src2)` 964 vaddi16x8_sat = VAddI16x8Sat { operands: BinaryOperands<VReg> }; 965 /// `dst = satruating_add(src1, src2)` 966 vaddu16x8_sat = VAddU16x8Sat { operands: BinaryOperands<VReg> }; 967 968 /// `dst = [src1[0] + src1[1], ..., src2[6] + src2[7]]` 969 vaddpairwisei16x8_s = VAddpairwiseI16x8S { operands: BinaryOperands<VReg> }; 970 /// `dst = [src1[0] + src1[1], ..., src2[2] + src2[3]]` 971 vaddpairwisei32x4_s = VAddpairwiseI32x4S { operands: BinaryOperands<VReg> }; 972 973 /// `dst = src1 << src2` 974 vshli8x16 = VShlI8x16 { operands: BinaryOperands<VReg, VReg, XReg> }; 975 /// `dst = src1 << src2` 976 vshli16x8 = VShlI16x8 { operands: BinaryOperands<VReg, VReg, XReg> }; 977 /// `dst = src1 << src2` 978 vshli32x4 = VShlI32x4 { operands: BinaryOperands<VReg, VReg, XReg> }; 979 /// `dst = src1 << src2` 980 vshli64x2 = VShlI64x2 { operands: BinaryOperands<VReg, VReg, XReg> }; 981 /// `dst = src1 >> src2` (signed) 982 vshri8x16_s = VShrI8x16S { operands: BinaryOperands<VReg, VReg, XReg> }; 983 /// `dst = src1 >> src2` (signed) 984 vshri16x8_s = VShrI16x8S { operands: BinaryOperands<VReg, VReg, XReg> }; 985 /// `dst = src1 >> src2` (signed) 986 vshri32x4_s = VShrI32x4S { operands: BinaryOperands<VReg, VReg, XReg> }; 987 /// `dst = src1 >> src2` (signed) 988 vshri64x2_s = VShrI64x2S { operands: BinaryOperands<VReg, VReg, XReg> }; 989 /// `dst = src1 >> src2` (unsigned) 990 vshri8x16_u = VShrI8x16U { operands: BinaryOperands<VReg, VReg, XReg> }; 991 /// `dst = src1 >> src2` (unsigned) 992 vshri16x8_u = VShrI16x8U { operands: BinaryOperands<VReg, VReg, XReg> }; 993 /// `dst = src1 >> src2` (unsigned) 994 vshri32x4_u = VShrI32x4U { operands: BinaryOperands<VReg, VReg, XReg> }; 995 /// `dst = src1 >> src2` (unsigned) 996 vshri64x2_u = VShrI64x2U { operands: BinaryOperands<VReg, VReg, XReg> }; 997 998 /// `dst = splat(low8(src))` 999 vsplatx8 = VSplatX8 { dst: VReg, src: XReg }; 1000 /// `dst = splat(low16(src))` 1001 vsplatx16 = VSplatX16 { dst: VReg, src: XReg }; 1002 /// `dst = splat(low32(src))` 1003 vsplatx32 = VSplatX32 { dst: VReg, src: XReg }; 1004 /// `dst = splat(src)` 1005 vsplatx64 = VSplatX64 { dst: VReg, src: XReg }; 1006 /// `dst = splat(low32(src))` 1007 vsplatf32 = VSplatF32 { dst: VReg, src: FReg }; 1008 /// `dst = splat(src)` 1009 vsplatf64 = VSplatF64 { dst: VReg, src: FReg }; 1010 1011 /// Load the 64-bit source as i8x8 and sign-extend to i16x8. 1012 vload8x8_s_z = VLoad8x8SZ { dst: VReg, addr: AddrZ }; 1013 /// Load the 64-bit source as u8x8 and zero-extend to i16x8. 1014 vload8x8_u_z = VLoad8x8UZ { dst: VReg, addr: AddrZ }; 1015 /// Load the 64-bit source as i16x4 and sign-extend to i32x4. 1016 vload16x4le_s_z = VLoad16x4LeSZ { dst: VReg, addr: AddrZ }; 1017 /// Load the 64-bit source as u16x4 and zero-extend to i32x4. 1018 vload16x4le_u_z = VLoad16x4LeUZ { dst: VReg, addr: AddrZ }; 1019 /// Load the 64-bit source as i32x2 and sign-extend to i64x2. 1020 vload32x2le_s_z = VLoad32x2LeSZ { dst: VReg, addr: AddrZ }; 1021 /// Load the 64-bit source as u32x2 and zero-extend to i64x2. 1022 vload32x2le_u_z = VLoad32x2LeUZ { dst: VReg, addr: AddrZ }; 1023 1024 /// `dst = src1 & src2` 1025 vband128 = VBand128 { operands: BinaryOperands<VReg> }; 1026 /// `dst = src1 | src2` 1027 vbor128 = VBor128 { operands: BinaryOperands<VReg> }; 1028 /// `dst = src1 ^ src2` 1029 vbxor128 = VBxor128 { operands: BinaryOperands<VReg> }; 1030 /// `dst = !src1` 1031 vbnot128 = VBnot128 { dst: VReg, src: VReg }; 1032 /// `dst = (c & x) | (!c & y)` 1033 vbitselect128 = VBitselect128 { dst: VReg, c: VReg, x: VReg, y: VReg }; 1034 /// Collect high bits of each lane into the low 32-bits of the 1035 /// destination. 1036 vbitmask8x16 = Vbitmask8x16 { dst: XReg, src: VReg }; 1037 /// Collect high bits of each lane into the low 32-bits of the 1038 /// destination. 1039 vbitmask16x8 = Vbitmask16x8 { dst: XReg, src: VReg }; 1040 /// Collect high bits of each lane into the low 32-bits of the 1041 /// destination. 1042 vbitmask32x4 = Vbitmask32x4 { dst: XReg, src: VReg }; 1043 /// Collect high bits of each lane into the low 32-bits of the 1044 /// destination. 1045 vbitmask64x2 = Vbitmask64x2 { dst: XReg, src: VReg }; 1046 /// Store whether all lanes are nonzero in `dst`. 1047 valltrue8x16 = Valltrue8x16 { dst: XReg, src: VReg }; 1048 /// Store whether all lanes are nonzero in `dst`. 1049 valltrue16x8 = Valltrue16x8 { dst: XReg, src: VReg }; 1050 /// Store whether all lanes are nonzero in `dst`. 1051 valltrue32x4 = Valltrue32x4 { dst: XReg, src: VReg }; 1052 /// Store whether any lanes are nonzero in `dst`. 1053 valltrue64x2 = Valltrue64x2 { dst: XReg, src: VReg }; 1054 /// Store whether any lanes are nonzero in `dst`. 1055 vanytrue8x16 = Vanytrue8x16 { dst: XReg, src: VReg }; 1056 /// Store whether any lanes are nonzero in `dst`. 1057 vanytrue16x8 = Vanytrue16x8 { dst: XReg, src: VReg }; 1058 /// Store whether any lanes are nonzero in `dst`. 1059 vanytrue32x4 = Vanytrue32x4 { dst: XReg, src: VReg }; 1060 /// Store whether any lanes are nonzero in `dst`. 1061 vanytrue64x2 = Vanytrue64x2 { dst: XReg, src: VReg }; 1062 1063 /// Int-to-float conversion (same as `f32_from_x32_s`) 1064 vf32x4_from_i32x4_s = VF32x4FromI32x4S { dst: VReg, src: VReg }; 1065 /// Int-to-float conversion (same as `f32_from_x32_u`) 1066 vf32x4_from_i32x4_u = VF32x4FromI32x4U { dst: VReg, src: VReg }; 1067 /// Int-to-float conversion (same as `f64_from_x64_s`) 1068 vf64x2_from_i64x2_s = VF64x2FromI64x2S { dst: VReg, src: VReg }; 1069 /// Int-to-float conversion (same as `f64_from_x64_u`) 1070 vf64x2_from_i64x2_u = VF64x2FromI64x2U { dst: VReg, src: VReg }; 1071 /// Float-to-int conversion (same as `x32_from_f32_s` 1072 vi32x4_from_f32x4_s = VI32x4FromF32x4S { dst: VReg, src: VReg }; 1073 /// Float-to-int conversion (same as `x32_from_f32_u` 1074 vi32x4_from_f32x4_u = VI32x4FromF32x4U { dst: VReg, src: VReg }; 1075 /// Float-to-int conversion (same as `x64_from_f64_s` 1076 vi64x2_from_f64x2_s = VI64x2FromF64x2S { dst: VReg, src: VReg }; 1077 /// Float-to-int conversion (same as `x64_from_f64_u` 1078 vi64x2_from_f64x2_u = VI64x2FromF64x2U { dst: VReg, src: VReg }; 1079 1080 /// Widens the low lanes of the input vector, as signed, to twice 1081 /// the width. 1082 vwidenlow8x16_s = VWidenLow8x16S { dst: VReg, src: VReg }; 1083 /// Widens the low lanes of the input vector, as unsigned, to twice 1084 /// the width. 1085 vwidenlow8x16_u = VWidenLow8x16U { dst: VReg, src: VReg }; 1086 /// Widens the low lanes of the input vector, as signed, to twice 1087 /// the width. 1088 vwidenlow16x8_s = VWidenLow16x8S { dst: VReg, src: VReg }; 1089 /// Widens the low lanes of the input vector, as unsigned, to twice 1090 /// the width. 1091 vwidenlow16x8_u = VWidenLow16x8U { dst: VReg, src: VReg }; 1092 /// Widens the low lanes of the input vector, as signed, to twice 1093 /// the width. 1094 vwidenlow32x4_s = VWidenLow32x4S { dst: VReg, src: VReg }; 1095 /// Widens the low lanes of the input vector, as unsigned, to twice 1096 /// the width. 1097 vwidenlow32x4_u = VWidenLow32x4U { dst: VReg, src: VReg }; 1098 /// Widens the high lanes of the input vector, as signed, to twice 1099 /// the width. 1100 vwidenhigh8x16_s = VWidenHigh8x16S { dst: VReg, src: VReg }; 1101 /// Widens the high lanes of the input vector, as unsigned, to twice 1102 /// the width. 1103 vwidenhigh8x16_u = VWidenHigh8x16U { dst: VReg, src: VReg }; 1104 /// Widens the high lanes of the input vector, as signed, to twice 1105 /// the width. 1106 vwidenhigh16x8_s = VWidenHigh16x8S { dst: VReg, src: VReg }; 1107 /// Widens the high lanes of the input vector, as unsigned, to twice 1108 /// the width. 1109 vwidenhigh16x8_u = VWidenHigh16x8U { dst: VReg, src: VReg }; 1110 /// Widens the high lanes of the input vector, as signed, to twice 1111 /// the width. 1112 vwidenhigh32x4_s = VWidenHigh32x4S { dst: VReg, src: VReg }; 1113 /// Widens the high lanes of the input vector, as unsigned, to twice 1114 /// the width. 1115 vwidenhigh32x4_u = VWidenHigh32x4U { dst: VReg, src: VReg }; 1116 1117 /// Narrows the two 16x8 vectors, assuming all input lanes are 1118 /// signed, to half the width. Narrowing is signed and saturating. 1119 vnarrow16x8_s = Vnarrow16x8S { operands: BinaryOperands<VReg> }; 1120 /// Narrows the two 16x8 vectors, assuming all input lanes are 1121 /// signed, to half the width. Narrowing is unsigned and saturating. 1122 vnarrow16x8_u = Vnarrow16x8U { operands: BinaryOperands<VReg> }; 1123 /// Narrows the two 32x4 vectors, assuming all input lanes are 1124 /// signed, to half the width. Narrowing is signed and saturating. 1125 vnarrow32x4_s = Vnarrow32x4S { operands: BinaryOperands<VReg> }; 1126 /// Narrows the two 32x4 vectors, assuming all input lanes are 1127 /// signed, to half the width. Narrowing is unsigned and saturating. 1128 vnarrow32x4_u = Vnarrow32x4U { operands: BinaryOperands<VReg> }; 1129 /// Narrows the two 64x2 vectors, assuming all input lanes are 1130 /// signed, to half the width. Narrowing is signed and saturating. 1131 vnarrow64x2_s = Vnarrow64x2S { operands: BinaryOperands<VReg> }; 1132 /// Narrows the two 64x2 vectors, assuming all input lanes are 1133 /// signed, to half the width. Narrowing is unsigned and saturating. 1134 vnarrow64x2_u = Vnarrow64x2U { operands: BinaryOperands<VReg> }; 1135 /// Narrows the two 64x2 vectors, assuming all input lanes are 1136 /// unsigned, to half the width. Narrowing is unsigned and saturating. 1137 vunarrow64x2_u = Vunarrow64x2U { operands: BinaryOperands<VReg> }; 1138 /// Promotes the low two lanes of the f32x4 input to f64x2. 1139 vfpromotelow = VFpromoteLow { dst: VReg, src: VReg }; 1140 /// Demotes the two f64x2 lanes to f32x2 and then extends with two 1141 /// more zero lanes. 1142 vfdemote = VFdemote { dst: VReg, src: VReg }; 1143 1144 /// `dst = src1 - src2` 1145 vsubi8x16 = VSubI8x16 { operands: BinaryOperands<VReg> }; 1146 /// `dst = src1 - src2` 1147 vsubi16x8 = VSubI16x8 { operands: BinaryOperands<VReg> }; 1148 /// `dst = src1 - src2` 1149 vsubi32x4 = VSubI32x4 { operands: BinaryOperands<VReg> }; 1150 /// `dst = src1 - src2` 1151 vsubi64x2 = VSubI64x2 { operands: BinaryOperands<VReg> }; 1152 /// `dst = src1 - src2` 1153 vsubf64x2 = VSubF64x2 { operands: BinaryOperands<VReg> }; 1154 1155 /// `dst = saturating_sub(src1, src2)` 1156 vsubi8x16_sat = VSubI8x16Sat { operands: BinaryOperands<VReg> }; 1157 /// `dst = saturating_sub(src1, src2)` 1158 vsubu8x16_sat = VSubU8x16Sat { operands: BinaryOperands<VReg> }; 1159 /// `dst = saturating_sub(src1, src2)` 1160 vsubi16x8_sat = VSubI16x8Sat { operands: BinaryOperands<VReg> }; 1161 /// `dst = saturating_sub(src1, src2)` 1162 vsubu16x8_sat = VSubU16x8Sat { operands: BinaryOperands<VReg> }; 1163 1164 /// `dst = src1 * src2` 1165 vmuli8x16 = VMulI8x16 { operands: BinaryOperands<VReg> }; 1166 /// `dst = src1 * src2` 1167 vmuli16x8 = VMulI16x8 { operands: BinaryOperands<VReg> }; 1168 /// `dst = src1 * src2` 1169 vmuli32x4 = VMulI32x4 { operands: BinaryOperands<VReg> }; 1170 /// `dst = src1 * src2` 1171 vmuli64x2 = VMulI64x2 { operands: BinaryOperands<VReg> }; 1172 /// `dst = src1 * src2` 1173 vmulf64x2 = VMulF64x2 { operands: BinaryOperands<VReg> }; 1174 1175 /// `dst = signed_saturate(src1 * src2 + (1 << (Q - 1)) >> Q)` 1176 vqmulrsi16x8 = VQmulrsI16x8 { operands: BinaryOperands<VReg> }; 1177 1178 /// `dst = count_ones(src)` 1179 vpopcnt8x16 = VPopcnt8x16 { dst: VReg, src: VReg }; 1180 1181 /// `low32(dst) = zext(src[lane])` 1182 xextractv8x16 = XExtractV8x16 { dst: XReg, src: VReg, lane: u8 }; 1183 /// `low32(dst) = zext(src[lane])` 1184 xextractv16x8 = XExtractV16x8 { dst: XReg, src: VReg, lane: u8 }; 1185 /// `low32(dst) = src[lane]` 1186 xextractv32x4 = XExtractV32x4 { dst: XReg, src: VReg, lane: u8 }; 1187 /// `dst = src[lane]` 1188 xextractv64x2 = XExtractV64x2 { dst: XReg, src: VReg, lane: u8 }; 1189 /// `low32(dst) = src[lane]` 1190 fextractv32x4 = FExtractV32x4 { dst: FReg, src: VReg, lane: u8 }; 1191 /// `dst = src[lane]` 1192 fextractv64x2 = FExtractV64x2 { dst: FReg, src: VReg, lane: u8 }; 1193 1194 /// `dst = src1; dst[lane] = src2` 1195 vinsertx8 = VInsertX8 { operands: BinaryOperands<VReg, VReg, XReg>, lane: u8 }; 1196 /// `dst = src1; dst[lane] = src2` 1197 vinsertx16 = VInsertX16 { operands: BinaryOperands<VReg, VReg, XReg>, lane: u8 }; 1198 /// `dst = src1; dst[lane] = src2` 1199 vinsertx32 = VInsertX32 { operands: BinaryOperands<VReg, VReg, XReg>, lane: u8 }; 1200 /// `dst = src1; dst[lane] = src2` 1201 vinsertx64 = VInsertX64 { operands: BinaryOperands<VReg, VReg, XReg>, lane: u8 }; 1202 /// `dst = src1; dst[lane] = src2` 1203 vinsertf32 = VInsertF32 { operands: BinaryOperands<VReg, VReg, FReg>, lane: u8 }; 1204 /// `dst = src1; dst[lane] = src2` 1205 vinsertf64 = VInsertF64 { operands: BinaryOperands<VReg, VReg, FReg>, lane: u8 }; 1206 1207 /// `dst = src == dst` 1208 veq8x16 = Veq8x16 { operands: BinaryOperands<VReg> }; 1209 /// `dst = src != dst` 1210 vneq8x16 = Vneq8x16 { operands: BinaryOperands<VReg> }; 1211 /// `dst = src < dst` (signed) 1212 vslt8x16 = Vslt8x16 { operands: BinaryOperands<VReg> }; 1213 /// `dst = src <= dst` (signed) 1214 vslteq8x16 = Vslteq8x16 { operands: BinaryOperands<VReg> }; 1215 /// `dst = src < dst` (unsigned) 1216 vult8x16 = Vult8x16 { operands: BinaryOperands<VReg> }; 1217 /// `dst = src <= dst` (unsigned) 1218 vulteq8x16 = Vulteq8x16 { operands: BinaryOperands<VReg> }; 1219 /// `dst = src == dst` 1220 veq16x8 = Veq16x8 { operands: BinaryOperands<VReg> }; 1221 /// `dst = src != dst` 1222 vneq16x8 = Vneq16x8 { operands: BinaryOperands<VReg> }; 1223 /// `dst = src < dst` (signed) 1224 vslt16x8 = Vslt16x8 { operands: BinaryOperands<VReg> }; 1225 /// `dst = src <= dst` (signed) 1226 vslteq16x8 = Vslteq16x8 { operands: BinaryOperands<VReg> }; 1227 /// `dst = src < dst` (unsigned) 1228 vult16x8 = Vult16x8 { operands: BinaryOperands<VReg> }; 1229 /// `dst = src <= dst` (unsigned) 1230 vulteq16x8 = Vulteq16x8 { operands: BinaryOperands<VReg> }; 1231 /// `dst = src == dst` 1232 veq32x4 = Veq32x4 { operands: BinaryOperands<VReg> }; 1233 /// `dst = src != dst` 1234 vneq32x4 = Vneq32x4 { operands: BinaryOperands<VReg> }; 1235 /// `dst = src < dst` (signed) 1236 vslt32x4 = Vslt32x4 { operands: BinaryOperands<VReg> }; 1237 /// `dst = src <= dst` (signed) 1238 vslteq32x4 = Vslteq32x4 { operands: BinaryOperands<VReg> }; 1239 /// `dst = src < dst` (unsigned) 1240 vult32x4 = Vult32x4 { operands: BinaryOperands<VReg> }; 1241 /// `dst = src <= dst` (unsigned) 1242 vulteq32x4 = Vulteq32x4 { operands: BinaryOperands<VReg> }; 1243 /// `dst = src == dst` 1244 veq64x2 = Veq64x2 { operands: BinaryOperands<VReg> }; 1245 /// `dst = src != dst` 1246 vneq64x2 = Vneq64x2 { operands: BinaryOperands<VReg> }; 1247 /// `dst = src < dst` (signed) 1248 vslt64x2 = Vslt64x2 { operands: BinaryOperands<VReg> }; 1249 /// `dst = src <= dst` (signed) 1250 vslteq64x2 = Vslteq64x2 { operands: BinaryOperands<VReg> }; 1251 /// `dst = src < dst` (unsigned) 1252 vult64x2 = Vult64x2 { operands: BinaryOperands<VReg> }; 1253 /// `dst = src <= dst` (unsigned) 1254 vulteq64x2 = Vulteq64x2 { operands: BinaryOperands<VReg> }; 1255 1256 /// `dst = -src` 1257 vneg8x16 = Vneg8x16 { dst: VReg, src: VReg }; 1258 /// `dst = -src` 1259 vneg16x8 = Vneg16x8 { dst: VReg, src: VReg }; 1260 /// `dst = -src` 1261 vneg32x4 = Vneg32x4 { dst: VReg, src: VReg }; 1262 /// `dst = -src` 1263 vneg64x2 = Vneg64x2 { dst: VReg, src: VReg }; 1264 /// `dst = -src` 1265 vnegf64x2 = VnegF64x2 { dst: VReg, src: VReg }; 1266 1267 /// `dst = min(src1, src2)` (signed) 1268 vmin8x16_s = Vmin8x16S { operands: BinaryOperands<VReg> }; 1269 /// `dst = min(src1, src2)` (unsigned) 1270 vmin8x16_u = Vmin8x16U { operands: BinaryOperands<VReg> }; 1271 /// `dst = min(src1, src2)` (signed) 1272 vmin16x8_s = Vmin16x8S { operands: BinaryOperands<VReg> }; 1273 /// `dst = min(src1, src2)` (unsigned) 1274 vmin16x8_u = Vmin16x8U { operands: BinaryOperands<VReg> }; 1275 /// `dst = max(src1, src2)` (signed) 1276 vmax8x16_s = Vmax8x16S { operands: BinaryOperands<VReg> }; 1277 /// `dst = max(src1, src2)` (unsigned) 1278 vmax8x16_u = Vmax8x16U { operands: BinaryOperands<VReg> }; 1279 /// `dst = max(src1, src2)` (signed) 1280 vmax16x8_s = Vmax16x8S { operands: BinaryOperands<VReg> }; 1281 /// `dst = max(src1, src2)` (unsigned) 1282 vmax16x8_u = Vmax16x8U { operands: BinaryOperands<VReg> }; 1283 1284 /// `dst = min(src1, src2)` (signed) 1285 vmin32x4_s = Vmin32x4S { operands: BinaryOperands<VReg> }; 1286 /// `dst = min(src1, src2)` (unsigned) 1287 vmin32x4_u = Vmin32x4U { operands: BinaryOperands<VReg> }; 1288 /// `dst = max(src1, src2)` (signed) 1289 vmax32x4_s = Vmax32x4S { operands: BinaryOperands<VReg> }; 1290 /// `dst = max(src1, src2)` (unsigned) 1291 vmax32x4_u = Vmax32x4U { operands: BinaryOperands<VReg> }; 1292 1293 /// `dst = |src|` 1294 vabs8x16 = Vabs8x16 { dst: VReg, src: VReg }; 1295 /// `dst = |src|` 1296 vabs16x8 = Vabs16x8 { dst: VReg, src: VReg }; 1297 /// `dst = |src|` 1298 vabs32x4 = Vabs32x4 { dst: VReg, src: VReg }; 1299 /// `dst = |src|` 1300 vabs64x2 = Vabs64x2 { dst: VReg, src: VReg }; 1301 1302 /// `dst = |src|` 1303 vabsf32x4 = Vabsf32x4 { dst: VReg, src: VReg }; 1304 /// `dst = |src|` 1305 vabsf64x2 = Vabsf64x2 { dst: VReg, src: VReg }; 1306 /// `dst = ieee_maximum(src1, src2)` 1307 vmaximumf32x4 = Vmaximumf32x4 { operands: BinaryOperands<VReg> }; 1308 /// `dst = ieee_maximum(src1, src2)` 1309 vmaximumf64x2 = Vmaximumf64x2 { operands: BinaryOperands<VReg> }; 1310 /// `dst = ieee_minimum(src1, src2)` 1311 vminimumf32x4 = Vminimumf32x4 { operands: BinaryOperands<VReg> }; 1312 /// `dst = ieee_minimum(src1, src2)` 1313 vminimumf64x2 = Vminimumf64x2 { operands: BinaryOperands<VReg> }; 1314 1315 /// `dst = shuffle(src1, src2, mask)` 1316 vshuffle = VShuffle { dst: VReg, src1: VReg, src2: VReg, mask: u128 }; 1317 1318 /// `dst = swizzle(src1, src2)` 1319 vswizzlei8x16 = Vswizzlei8x16 { operands: BinaryOperands<VReg> }; 1320 1321 /// `dst = (src1 + src2 + 1) // 2` 1322 vavground8x16 = Vavground8x16 { operands: BinaryOperands<VReg> }; 1323 /// `dst = (src1 + src2 + 1) // 2` 1324 vavground16x8 = Vavground16x8 { operands: BinaryOperands<VReg> }; 1325 1326 /// `dst = src == dst` 1327 veqf32x4 = VeqF32x4 { operands: BinaryOperands<VReg> }; 1328 /// `dst = src != dst` 1329 vneqf32x4 = VneqF32x4 { operands: BinaryOperands<VReg> }; 1330 /// `dst = src < dst` 1331 vltf32x4 = VltF32x4 { operands: BinaryOperands<VReg> }; 1332 /// `dst = src <= dst` 1333 vlteqf32x4 = VlteqF32x4 { operands: BinaryOperands<VReg> }; 1334 /// `dst = src == dst` 1335 veqf64x2 = VeqF64x2 { operands: BinaryOperands<VReg> }; 1336 /// `dst = src != dst` 1337 vneqf64x2 = VneqF64x2 { operands: BinaryOperands<VReg> }; 1338 /// `dst = src < dst` 1339 vltf64x2 = VltF64x2 { operands: BinaryOperands<VReg> }; 1340 /// `dst = src <= dst` 1341 vlteqf64x2 = VlteqF64x2 { operands: BinaryOperands<VReg> }; 1342 1343 /// `dst = ieee_fma(a, b, c)` 1344 vfma32x4 = Vfma32x4 { dst: VReg, a: VReg, b: VReg, c: VReg }; 1345 /// `dst = ieee_fma(a, b, c)` 1346 vfma64x2 = Vfma64x2 { dst: VReg, a: VReg, b: VReg, c: VReg }; 1347 1348 /// `dst = low32(cond) ? if_nonzero : if_zero` 1349 vselect = Vselect { dst: VReg, cond: XReg, if_nonzero: VReg, if_zero: VReg }; 1350 1351 /// `dst_hi:dst_lo = lhs_hi:lhs_lo + rhs_hi:rhs_lo` 1352 xadd128 = Xadd128 { 1353 dst_lo: XReg, 1354 dst_hi: XReg, 1355 lhs_lo: XReg, 1356 lhs_hi: XReg, 1357 rhs_lo: XReg, 1358 rhs_hi: XReg 1359 }; 1360 /// `dst_hi:dst_lo = lhs_hi:lhs_lo - rhs_hi:rhs_lo` 1361 xsub128 = Xsub128 { 1362 dst_lo: XReg, 1363 dst_hi: XReg, 1364 lhs_lo: XReg, 1365 lhs_hi: XReg, 1366 rhs_lo: XReg, 1367 rhs_hi: XReg 1368 }; 1369 /// `dst_hi:dst_lo = sext(lhs) * sext(rhs)` 1370 xwidemul64_s = Xwidemul64S { 1371 dst_lo: XReg, 1372 dst_hi: XReg, 1373 lhs: XReg, 1374 rhs: XReg 1375 }; 1376 /// `dst_hi:dst_lo = zext(lhs) * zext(rhs)` 1377 xwidemul64_u = Xwidemul64U { 1378 dst_lo: XReg, 1379 dst_hi: XReg, 1380 lhs: XReg, 1381 rhs: XReg 1382 }; 1383 } 1384 }; 1385 } 1386 1387 #[cfg(feature = "decode")] 1388 pub mod decode; 1389 #[cfg(feature = "disas")] 1390 pub mod disas; 1391 #[cfg(feature = "encode")] 1392 pub mod encode; 1393 #[cfg(feature = "interp")] 1394 pub mod interp; 1395 #[cfg(feature = "profile")] 1396 pub mod profile; 1397 #[cfg(all(not(feature = "profile"), feature = "interp"))] 1398 mod profile_disabled; 1399 #[cfg(all(not(feature = "profile"), feature = "interp"))] 1400 use profile_disabled as profile; 1401 1402 pub mod regs; 1403 pub use regs::*; 1404 1405 pub mod imms; 1406 pub use imms::*; 1407 1408 pub mod op; 1409 pub use op::*; 1410 1411 pub mod opcode; 1412 pub use opcode::*; 1413 1414 #[cfg(any(feature = "encode", feature = "decode"))] 1415 pub(crate) unsafe fn unreachable_unchecked<T>() -> T { 1416 #[cfg(debug_assertions)] 1417 unreachable!(); 1418 1419 #[cfg(not(debug_assertions))] 1420 unsafe { 1421 core::hint::unreachable_unchecked() 1422 } 1423 } 1424