1 //! This module is the central place for machine code emission. 2 //! It defines an implementation of wasmparser's Visitor trait 3 //! for `CodeGen`; which defines a visitor per op-code, 4 //! which validates and dispatches to the corresponding 5 //! machine code emitter. 6 7 use crate::abi::RetArea; 8 use crate::codegen::{ 9 control_index, AtomicWaitKind, Callee, CodeGen, CodeGenError, ControlStackFrame, Emission, 10 FnCall, 11 }; 12 use crate::masm::{ 13 DivKind, Extend, ExtractLaneKind, FloatCmpKind, IntCmpKind, LoadKind, MacroAssembler, 14 MemMoveDirection, MulWideKind, OperandSize, RegImm, RemKind, ReplaceLaneKind, RmwOp, 15 RoundingMode, SPOffset, ShiftKind, Signed, SplatKind, SplatLoadKind, StoreKind, TruncKind, 16 V128AbsKind, V128AddKind, V128ConvertKind, V128ExtAddKind, V128ExtMulKind, V128ExtendKind, 17 V128LoadExtendKind, V128MaxKind, V128MinKind, V128MulKind, V128NarrowKind, V128NegKind, 18 V128SubKind, V128TruncKind, VectorCompareKind, VectorEqualityKind, Zero, 19 }; 20 21 use crate::reg::{writable, Reg}; 22 use crate::stack::{TypedReg, Val}; 23 use anyhow::{anyhow, bail, ensure, Result}; 24 use regalloc2::RegClass; 25 use smallvec::{smallvec, SmallVec}; 26 use wasmparser::{ 27 BlockType, BrTable, Ieee32, Ieee64, MemArg, VisitOperator, VisitSimdOperator, V128, 28 }; 29 use wasmtime_cranelift::TRAP_INDIRECT_CALL_TO_NULL; 30 use wasmtime_environ::{ 31 FuncIndex, GlobalIndex, MemoryIndex, TableIndex, TypeIndex, WasmHeapType, WasmValType, 32 FUNCREF_INIT_BIT, 33 }; 34 35 /// A macro to define unsupported WebAssembly operators. 36 /// 37 /// This macro calls itself recursively; 38 /// 1. It no-ops when matching a supported operator. 39 /// 2. Defines the visitor function and panics when 40 /// matching an unsupported operator. 41 macro_rules! def_unsupported { 42 ($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident $ann:tt)*) => { 43 $( 44 def_unsupported!( 45 emit 46 $op 47 48 fn $visit(&mut self $($(,$arg: $argty)*)?) -> Self::Output { 49 $($(let _ = $arg;)*)? 50 51 Err(anyhow!(CodeGenError::unimplemented_wasm_instruction())) 52 } 53 ); 54 )* 55 }; 56 57 (emit I32Const $($rest:tt)*) => {}; 58 (emit I64Const $($rest:tt)*) => {}; 59 (emit F32Const $($rest:tt)*) => {}; 60 (emit F64Const $($rest:tt)*) => {}; 61 (emit V128Const $($rest:tt)*) => {}; 62 (emit F32Add $($rest:tt)*) => {}; 63 (emit F64Add $($rest:tt)*) => {}; 64 (emit F32Sub $($rest:tt)*) => {}; 65 (emit F64Sub $($rest:tt)*) => {}; 66 (emit F32Mul $($rest:tt)*) => {}; 67 (emit F64Mul $($rest:tt)*) => {}; 68 (emit F32Div $($rest:tt)*) => {}; 69 (emit F64Div $($rest:tt)*) => {}; 70 (emit F32Min $($rest:tt)*) => {}; 71 (emit F64Min $($rest:tt)*) => {}; 72 (emit F32Max $($rest:tt)*) => {}; 73 (emit F64Max $($rest:tt)*) => {}; 74 (emit F32Copysign $($rest:tt)*) => {}; 75 (emit F64Copysign $($rest:tt)*) => {}; 76 (emit F32Abs $($rest:tt)*) => {}; 77 (emit F64Abs $($rest:tt)*) => {}; 78 (emit F32Neg $($rest:tt)*) => {}; 79 (emit F64Neg $($rest:tt)*) => {}; 80 (emit F32Floor $($rest:tt)*) => {}; 81 (emit F64Floor $($rest:tt)*) => {}; 82 (emit F32Ceil $($rest:tt)*) => {}; 83 (emit F64Ceil $($rest:tt)*) => {}; 84 (emit F32Nearest $($rest:tt)*) => {}; 85 (emit F64Nearest $($rest:tt)*) => {}; 86 (emit F32Trunc $($rest:tt)*) => {}; 87 (emit F64Trunc $($rest:tt)*) => {}; 88 (emit F32Sqrt $($rest:tt)*) => {}; 89 (emit F64Sqrt $($rest:tt)*) => {}; 90 (emit F32Eq $($rest:tt)*) => {}; 91 (emit F64Eq $($rest:tt)*) => {}; 92 (emit F32Ne $($rest:tt)*) => {}; 93 (emit F64Ne $($rest:tt)*) => {}; 94 (emit F32Lt $($rest:tt)*) => {}; 95 (emit F64Lt $($rest:tt)*) => {}; 96 (emit F32Gt $($rest:tt)*) => {}; 97 (emit F64Gt $($rest:tt)*) => {}; 98 (emit F32Le $($rest:tt)*) => {}; 99 (emit F64Le $($rest:tt)*) => {}; 100 (emit F32Ge $($rest:tt)*) => {}; 101 (emit F64Ge $($rest:tt)*) => {}; 102 (emit F32ConvertI32S $($rest:tt)*) => {}; 103 (emit F32ConvertI32U $($rest:tt)*) => {}; 104 (emit F32ConvertI64S $($rest:tt)*) => {}; 105 (emit F32ConvertI64U $($rest:tt)*) => {}; 106 (emit F64ConvertI32S $($rest:tt)*) => {}; 107 (emit F64ConvertI32U $($rest:tt)*) => {}; 108 (emit F64ConvertI64S $($rest:tt)*) => {}; 109 (emit F64ConvertI64U $($rest:tt)*) => {}; 110 (emit F32ReinterpretI32 $($rest:tt)*) => {}; 111 (emit F64ReinterpretI64 $($rest:tt)*) => {}; 112 (emit F32DemoteF64 $($rest:tt)*) => {}; 113 (emit F64PromoteF32 $($rest:tt)*) => {}; 114 (emit I32Add $($rest:tt)*) => {}; 115 (emit I64Add $($rest:tt)*) => {}; 116 (emit I32Sub $($rest:tt)*) => {}; 117 (emit I32Mul $($rest:tt)*) => {}; 118 (emit I32DivS $($rest:tt)*) => {}; 119 (emit I32DivU $($rest:tt)*) => {}; 120 (emit I64DivS $($rest:tt)*) => {}; 121 (emit I64DivU $($rest:tt)*) => {}; 122 (emit I64RemU $($rest:tt)*) => {}; 123 (emit I64RemS $($rest:tt)*) => {}; 124 (emit I32RemU $($rest:tt)*) => {}; 125 (emit I32RemS $($rest:tt)*) => {}; 126 (emit I64Mul $($rest:tt)*) => {}; 127 (emit I64Sub $($rest:tt)*) => {}; 128 (emit I32Eq $($rest:tt)*) => {}; 129 (emit I64Eq $($rest:tt)*) => {}; 130 (emit I32Ne $($rest:tt)*) => {}; 131 (emit I64Ne $($rest:tt)*) => {}; 132 (emit I32LtS $($rest:tt)*) => {}; 133 (emit I64LtS $($rest:tt)*) => {}; 134 (emit I32LtU $($rest:tt)*) => {}; 135 (emit I64LtU $($rest:tt)*) => {}; 136 (emit I32LeS $($rest:tt)*) => {}; 137 (emit I64LeS $($rest:tt)*) => {}; 138 (emit I32LeU $($rest:tt)*) => {}; 139 (emit I64LeU $($rest:tt)*) => {}; 140 (emit I32GtS $($rest:tt)*) => {}; 141 (emit I64GtS $($rest:tt)*) => {}; 142 (emit I32GtU $($rest:tt)*) => {}; 143 (emit I64GtU $($rest:tt)*) => {}; 144 (emit I32GeS $($rest:tt)*) => {}; 145 (emit I64GeS $($rest:tt)*) => {}; 146 (emit I32GeU $($rest:tt)*) => {}; 147 (emit I64GeU $($rest:tt)*) => {}; 148 (emit I32Eqz $($rest:tt)*) => {}; 149 (emit I64Eqz $($rest:tt)*) => {}; 150 (emit I32And $($rest:tt)*) => {}; 151 (emit I64And $($rest:tt)*) => {}; 152 (emit I32Or $($rest:tt)*) => {}; 153 (emit I64Or $($rest:tt)*) => {}; 154 (emit I32Xor $($rest:tt)*) => {}; 155 (emit I64Xor $($rest:tt)*) => {}; 156 (emit I32Shl $($rest:tt)*) => {}; 157 (emit I64Shl $($rest:tt)*) => {}; 158 (emit I32ShrS $($rest:tt)*) => {}; 159 (emit I64ShrS $($rest:tt)*) => {}; 160 (emit I32ShrU $($rest:tt)*) => {}; 161 (emit I64ShrU $($rest:tt)*) => {}; 162 (emit I32Rotl $($rest:tt)*) => {}; 163 (emit I64Rotl $($rest:tt)*) => {}; 164 (emit I32Rotr $($rest:tt)*) => {}; 165 (emit I64Rotr $($rest:tt)*) => {}; 166 (emit I32Clz $($rest:tt)*) => {}; 167 (emit I64Clz $($rest:tt)*) => {}; 168 (emit I32Ctz $($rest:tt)*) => {}; 169 (emit I64Ctz $($rest:tt)*) => {}; 170 (emit I32Popcnt $($rest:tt)*) => {}; 171 (emit I64Popcnt $($rest:tt)*) => {}; 172 (emit I32WrapI64 $($rest:tt)*) => {}; 173 (emit I64ExtendI32S $($rest:tt)*) => {}; 174 (emit I64ExtendI32U $($rest:tt)*) => {}; 175 (emit I32Extend8S $($rest:tt)*) => {}; 176 (emit I32Extend16S $($rest:tt)*) => {}; 177 (emit I64Extend8S $($rest:tt)*) => {}; 178 (emit I64Extend16S $($rest:tt)*) => {}; 179 (emit I64Extend32S $($rest:tt)*) => {}; 180 (emit I32TruncF32S $($rest:tt)*) => {}; 181 (emit I32TruncF32U $($rest:tt)*) => {}; 182 (emit I32TruncF64S $($rest:tt)*) => {}; 183 (emit I32TruncF64U $($rest:tt)*) => {}; 184 (emit I64TruncF32S $($rest:tt)*) => {}; 185 (emit I64TruncF32U $($rest:tt)*) => {}; 186 (emit I64TruncF64S $($rest:tt)*) => {}; 187 (emit I64TruncF64U $($rest:tt)*) => {}; 188 (emit I32ReinterpretF32 $($rest:tt)*) => {}; 189 (emit I64ReinterpretF64 $($rest:tt)*) => {}; 190 (emit LocalGet $($rest:tt)*) => {}; 191 (emit LocalSet $($rest:tt)*) => {}; 192 (emit Call $($rest:tt)*) => {}; 193 (emit End $($rest:tt)*) => {}; 194 (emit Nop $($rest:tt)*) => {}; 195 (emit If $($rest:tt)*) => {}; 196 (emit Else $($rest:tt)*) => {}; 197 (emit Block $($rest:tt)*) => {}; 198 (emit Loop $($rest:tt)*) => {}; 199 (emit Br $($rest:tt)*) => {}; 200 (emit BrIf $($rest:tt)*) => {}; 201 (emit Return $($rest:tt)*) => {}; 202 (emit Unreachable $($rest:tt)*) => {}; 203 (emit LocalTee $($rest:tt)*) => {}; 204 (emit GlobalGet $($rest:tt)*) => {}; 205 (emit GlobalSet $($rest:tt)*) => {}; 206 (emit Select $($rest:tt)*) => {}; 207 (emit Drop $($rest:tt)*) => {}; 208 (emit BrTable $($rest:tt)*) => {}; 209 (emit CallIndirect $($rest:tt)*) => {}; 210 (emit TableInit $($rest:tt)*) => {}; 211 (emit TableCopy $($rest:tt)*) => {}; 212 (emit TableGet $($rest:tt)*) => {}; 213 (emit TableSet $($rest:tt)*) => {}; 214 (emit TableGrow $($rest:tt)*) => {}; 215 (emit TableSize $($rest:tt)*) => {}; 216 (emit TableFill $($rest:tt)*) => {}; 217 (emit ElemDrop $($rest:tt)*) => {}; 218 (emit MemoryInit $($rest:tt)*) => {}; 219 (emit MemoryCopy $($rest:tt)*) => {}; 220 (emit DataDrop $($rest:tt)*) => {}; 221 (emit MemoryFill $($rest:tt)*) => {}; 222 (emit MemorySize $($rest:tt)*) => {}; 223 (emit MemoryGrow $($rest:tt)*) => {}; 224 (emit I32Load $($rest:tt)*) => {}; 225 (emit I32Load8S $($rest:tt)*) => {}; 226 (emit I32Load8U $($rest:tt)*) => {}; 227 (emit I32Load16S $($rest:tt)*) => {}; 228 (emit I32Load16U $($rest:tt)*) => {}; 229 (emit I64Load8S $($rest:tt)*) => {}; 230 (emit I64Load8U $($rest:tt)*) => {}; 231 (emit I64Load16S $($rest:tt)*) => {}; 232 (emit I64Load16U $($rest:tt)*) => {}; 233 (emit I64Load32S $($rest:tt)*) => {}; 234 (emit I64Load32U $($rest:tt)*) => {}; 235 (emit I64Load $($rest:tt)*) => {}; 236 (emit I32Store $($rest:tt)*) => {}; 237 (emit I32Store8 $($rest:tt)*) => {}; 238 (emit I32Store16 $($rest:tt)*) => {}; 239 (emit I64Store $($rest:tt)*) => {}; 240 (emit I64Store8 $($rest:tt)*) => {}; 241 (emit I64Store16 $($rest:tt)*) => {}; 242 (emit I64Store32 $($rest:tt)*) => {}; 243 (emit F32Load $($rest:tt)*) => {}; 244 (emit F32Store $($rest:tt)*) => {}; 245 (emit F64Load $($rest:tt)*) => {}; 246 (emit F64Store $($rest:tt)*) => {}; 247 (emit I32TruncSatF32S $($rest:tt)*) => {}; 248 (emit I32TruncSatF32U $($rest:tt)*) => {}; 249 (emit I32TruncSatF64S $($rest:tt)*) => {}; 250 (emit I32TruncSatF64U $($rest:tt)*) => {}; 251 (emit I64TruncSatF32S $($rest:tt)*) => {}; 252 (emit I64TruncSatF32U $($rest:tt)*) => {}; 253 (emit I64TruncSatF64S $($rest:tt)*) => {}; 254 (emit I64TruncSatF64U $($rest:tt)*) => {}; 255 (emit V128Load $($rest:tt)*) => {}; 256 (emit V128Store $($rest:tt)*) => {}; 257 (emit I64Add128 $($rest:tt)*) => {}; 258 (emit I64Sub128 $($rest:tt)*) => {}; 259 (emit I64MulWideS $($rest:tt)*) => {}; 260 (emit I64MulWideU $($rest:tt)*) => {}; 261 (emit I32AtomicLoad8U $($rest:tt)*) => {}; 262 (emit I32AtomicLoad16U $($rest:tt)*) => {}; 263 (emit I32AtomicLoad $($rest:tt)*) => {}; 264 (emit I64AtomicLoad8U $($rest:tt)*) => {}; 265 (emit I64AtomicLoad16U $($rest:tt)*) => {}; 266 (emit I64AtomicLoad32U $($rest:tt)*) => {}; 267 (emit I64AtomicLoad $($rest:tt)*) => {}; 268 (emit V128Load8x8S $($rest:tt)*) => {}; 269 (emit V128Load8x8U $($rest:tt)*) => {}; 270 (emit V128Load16x4S $($rest:tt)*) => {}; 271 (emit V128Load16x4U $($rest:tt)*) => {}; 272 (emit V128Load32x2S $($rest:tt)*) => {}; 273 (emit V128Load32x2U $($rest:tt)*) => {}; 274 (emit V128Load8Splat $($rest:tt)*) => {}; 275 (emit V128Load16Splat $($rest:tt)*) => {}; 276 (emit V128Load32Splat $($rest:tt)*) => {}; 277 (emit V128Load64Splat $($rest:tt)*) => {}; 278 (emit I8x16Splat $($rest:tt)*) => {}; 279 (emit I16x8Splat $($rest:tt)*) => {}; 280 (emit I32x4Splat $($rest:tt)*) => {}; 281 (emit I64x2Splat $($rest:tt)*) => {}; 282 (emit F32x4Splat $($rest:tt)*) => {}; 283 (emit F64x2Splat $($rest:tt)*) => {}; 284 (emit I32AtomicStore8 $($rest:tt)*) => {}; 285 (emit I32AtomicStore16 $($rest:tt)*) => {}; 286 (emit I32AtomicStore $($rest:tt)*) => {}; 287 (emit I64AtomicStore8 $($rest:tt)*) => {}; 288 (emit I64AtomicStore16 $($rest:tt)*) => {}; 289 (emit I64AtomicStore32 $($rest:tt)*) => {}; 290 (emit I64AtomicStore $($rest:tt)*) => {}; 291 (emit I32AtomicRmw8AddU $($rest:tt)*) => {}; 292 (emit I32AtomicRmw16AddU $($rest:tt)*) => {}; 293 (emit I32AtomicRmwAdd $($rest:tt)*) => {}; 294 (emit I64AtomicRmw8AddU $($rest:tt)*) => {}; 295 (emit I64AtomicRmw16AddU $($rest:tt)*) => {}; 296 (emit I64AtomicRmw32AddU $($rest:tt)*) => {}; 297 (emit I64AtomicRmwAdd $($rest:tt)*) => {}; 298 (emit I8x16Shuffle $($rest:tt)*) => {}; 299 (emit I8x16Swizzle $($rest:tt)*) => {}; 300 (emit I32AtomicRmw8SubU $($rest:tt)*) => {}; 301 (emit I32AtomicRmw16SubU $($rest:tt)*) => {}; 302 (emit I32AtomicRmwSub $($rest:tt)*) => {}; 303 (emit I64AtomicRmw8SubU $($rest:tt)*) => {}; 304 (emit I64AtomicRmw16SubU $($rest:tt)*) => {}; 305 (emit I64AtomicRmw32SubU $($rest:tt)*) => {}; 306 (emit I64AtomicRmwSub $($rest:tt)*) => {}; 307 (emit I32AtomicRmw8XchgU $($rest:tt)*) => {}; 308 (emit I32AtomicRmw16XchgU $($rest:tt)*) => {}; 309 (emit I32AtomicRmwXchg $($rest:tt)*) => {}; 310 (emit I64AtomicRmw8XchgU $($rest:tt)*) => {}; 311 (emit I64AtomicRmw16XchgU $($rest:tt)*) => {}; 312 (emit I64AtomicRmw32XchgU $($rest:tt)*) => {}; 313 (emit I64AtomicRmwXchg $($rest:tt)*) => {}; 314 (emit I8x16ExtractLaneS $($rest:tt)*) => {}; 315 (emit I8x16ExtractLaneU $($rest:tt)*) => {}; 316 (emit I16x8ExtractLaneS $($rest:tt)*) => {}; 317 (emit I16x8ExtractLaneU $($rest:tt)*) => {}; 318 (emit I32x4ExtractLane $($rest:tt)*) => {}; 319 (emit I64x2ExtractLane $($rest:tt)*) => {}; 320 (emit F32x4ExtractLane $($rest:tt)*) => {}; 321 (emit F64x2ExtractLane $($rest:tt)*) => {}; 322 (emit I32AtomicRmw8AndU $($rest:tt)*) => {}; 323 (emit I32AtomicRmw16AndU $($rest:tt)*) => {}; 324 (emit I32AtomicRmwAnd $($rest:tt)*) => {}; 325 (emit I64AtomicRmw8AndU $($rest:tt)*) => {}; 326 (emit I64AtomicRmw16AndU $($rest:tt)*) => {}; 327 (emit I64AtomicRmw32AndU $($rest:tt)*) => {}; 328 (emit I64AtomicRmwAnd $($rest:tt)*) => {}; 329 (emit I32AtomicRmw8OrU $($rest:tt)*) => {}; 330 (emit I32AtomicRmw16OrU $($rest:tt)*) => {}; 331 (emit I32AtomicRmwOr $($rest:tt)*) => {}; 332 (emit I64AtomicRmw8OrU $($rest:tt)*) => {}; 333 (emit I64AtomicRmw16OrU $($rest:tt)*) => {}; 334 (emit I64AtomicRmw32OrU $($rest:tt)*) => {}; 335 (emit I64AtomicRmwOr $($rest:tt)*) => {}; 336 (emit I32AtomicRmw8XorU $($rest:tt)*) => {}; 337 (emit I32AtomicRmw16XorU $($rest:tt)*) => {}; 338 (emit I32AtomicRmwXor $($rest:tt)*) => {}; 339 (emit I64AtomicRmw8XorU $($rest:tt)*) => {}; 340 (emit I64AtomicRmw16XorU $($rest:tt)*) => {}; 341 (emit I64AtomicRmw32XorU $($rest:tt)*) => {}; 342 (emit I64AtomicRmwXor $($rest:tt)*) => {}; 343 (emit I8x16ReplaceLane $($rest:tt)*) => {}; 344 (emit I16x8ReplaceLane $($rest:tt)*) => {}; 345 (emit I32x4ReplaceLane $($rest:tt)*) => {}; 346 (emit I64x2ReplaceLane $($rest:tt)*) => {}; 347 (emit F32x4ReplaceLane $($rest:tt)*) => {}; 348 (emit F64x2ReplaceLane $($rest:tt)*) => {}; 349 (emit I32AtomicRmw8CmpxchgU $($rest:tt)*) => {}; 350 (emit I32AtomicRmw16CmpxchgU $($rest:tt)*) => {}; 351 (emit I32AtomicRmwCmpxchg $($rest:tt)*) => {}; 352 (emit I64AtomicRmw8CmpxchgU $($rest:tt)*) => {}; 353 (emit I64AtomicRmw16CmpxchgU $($rest:tt)*) => {}; 354 (emit I64AtomicRmw32CmpxchgU $($rest:tt)*) => {}; 355 (emit I64AtomicRmwCmpxchg $($rest:tt)*) => {}; 356 (emit I8x16Eq $($rest:tt)*) => {}; 357 (emit I16x8Eq $($rest:tt)*) => {}; 358 (emit I32x4Eq $($rest:tt)*) => {}; 359 (emit I64x2Eq $($rest:tt)*) => {}; 360 (emit F32x4Eq $($rest:tt)*) => {}; 361 (emit F64x2Eq $($rest:tt)*) => {}; 362 (emit I8x16Ne $($rest:tt)*) => {}; 363 (emit I16x8Ne $($rest:tt)*) => {}; 364 (emit I32x4Ne $($rest:tt)*) => {}; 365 (emit I64x2Ne $($rest:tt)*) => {}; 366 (emit F32x4Ne $($rest:tt)*) => {}; 367 (emit F64x2Ne $($rest:tt)*) => {}; 368 (emit I8x16LtS $($rest:tt)*) => {}; 369 (emit I8x16LtU $($rest:tt)*) => {}; 370 (emit I16x8LtS $($rest:tt)*) => {}; 371 (emit I16x8LtU $($rest:tt)*) => {}; 372 (emit I32x4LtS $($rest:tt)*) => {}; 373 (emit I32x4LtU $($rest:tt)*) => {}; 374 (emit I64x2LtS $($rest:tt)*) => {}; 375 (emit F32x4Lt $($rest:tt)*) => {}; 376 (emit F64x2Lt $($rest:tt)*) => {}; 377 (emit I8x16LeS $($rest:tt)*) => {}; 378 (emit I8x16LeU $($rest:tt)*) => {}; 379 (emit I16x8LeS $($rest:tt)*) => {}; 380 (emit I16x8LeU $($rest:tt)*) => {}; 381 (emit I32x4LeS $($rest:tt)*) => {}; 382 (emit I32x4LeU $($rest:tt)*) => {}; 383 (emit I64x2LeS $($rest:tt)*) => {}; 384 (emit F32x4Le $($rest:tt)*) => {}; 385 (emit F64x2Le $($rest:tt)*) => {}; 386 (emit I8x16GtS $($rest:tt)*) => {}; 387 (emit I8x16GtU $($rest:tt)*) => {}; 388 (emit I16x8GtS $($rest:tt)*) => {}; 389 (emit I16x8GtU $($rest:tt)*) => {}; 390 (emit I32x4GtS $($rest:tt)*) => {}; 391 (emit I32x4GtU $($rest:tt)*) => {}; 392 (emit I64x2GtS $($rest:tt)*) => {}; 393 (emit F32x4Gt $($rest:tt)*) => {}; 394 (emit F64x2Gt $($rest:tt)*) => {}; 395 (emit I8x16GeS $($rest:tt)*) => {}; 396 (emit I8x16GeU $($rest:tt)*) => {}; 397 (emit I16x8GeS $($rest:tt)*) => {}; 398 (emit I16x8GeU $($rest:tt)*) => {}; 399 (emit I32x4GeS $($rest:tt)*) => {}; 400 (emit I32x4GeU $($rest:tt)*) => {}; 401 (emit I64x2GeS $($rest:tt)*) => {}; 402 (emit F32x4Ge $($rest:tt)*) => {}; 403 (emit F64x2Ge $($rest:tt)*) => {}; 404 (emit MemoryAtomicWait32 $($rest:tt)*) => {}; 405 (emit MemoryAtomicWait64 $($rest:tt)*) => {}; 406 (emit MemoryAtomicNotify $($rest:tt)*) => {}; 407 (emit AtomicFence $($rest:tt)*) => {}; 408 (emit V128Not $($rest:tt)*) => {}; 409 (emit V128And $($rest:tt)*) => {}; 410 (emit V128AndNot $($rest:tt)*) => {}; 411 (emit V128Or $($rest:tt)*) => {}; 412 (emit V128Xor $($rest:tt)*) => {}; 413 (emit V128Bitselect $($rest:tt)*) => {}; 414 (emit V128AnyTrue $($rest:tt)*) => {}; 415 (emit V128Load8Lane $($rest:tt)*) => {}; 416 (emit V128Load16Lane $($rest:tt)*) => {}; 417 (emit V128Load32Lane $($rest:tt)*) => {}; 418 (emit V128Load64Lane $($rest:tt)*) => {}; 419 (emit V128Store8Lane $($rest:tt)*) => {}; 420 (emit V128Store16Lane $($rest:tt)*) => {}; 421 (emit V128Store32Lane $($rest:tt)*) => {}; 422 (emit V128Store64Lane $($rest:tt)*) => {}; 423 (emit F32x4ConvertI32x4S $($rest:tt)*) => {}; 424 (emit F32x4ConvertI32x4U $($rest:tt)*) => {}; 425 (emit F64x2ConvertLowI32x4S $($rest:tt)*) => {}; 426 (emit F64x2ConvertLowI32x4U $($rest:tt)*) => {}; 427 (emit I8x16NarrowI16x8S $($rest:tt)*) => {}; 428 (emit I8x16NarrowI16x8U $($rest:tt)*) => {}; 429 (emit I16x8NarrowI32x4S $($rest:tt)*) => {}; 430 (emit I16x8NarrowI32x4U $($rest:tt)*) => {}; 431 (emit F32x4DemoteF64x2Zero $($rest:tt)*) => {}; 432 (emit F64x2PromoteLowF32x4 $($rest:tt)*) => {}; 433 (emit I16x8ExtendLowI8x16S $($rest:tt)*) => {}; 434 (emit I16x8ExtendHighI8x16S $($rest:tt)*) => {}; 435 (emit I16x8ExtendLowI8x16U $($rest:tt)*) => {}; 436 (emit I16x8ExtendHighI8x16U $($rest:tt)*) => {}; 437 (emit I32x4ExtendLowI16x8S $($rest:tt)*) => {}; 438 (emit I32x4ExtendHighI16x8S $($rest:tt)*) => {}; 439 (emit I32x4ExtendLowI16x8U $($rest:tt)*) => {}; 440 (emit I32x4ExtendHighI16x8U $($rest:tt)*) => {}; 441 (emit I64x2ExtendLowI32x4S $($rest:tt)*) => {}; 442 (emit I64x2ExtendHighI32x4S $($rest:tt)*) => {}; 443 (emit I64x2ExtendLowI32x4U $($rest:tt)*) => {}; 444 (emit I64x2ExtendHighI32x4U $($rest:tt)*) => {}; 445 (emit I8x16Add $($rest:tt)*) => {}; 446 (emit I16x8Add $($rest:tt)*) => {}; 447 (emit I32x4Add $($rest:tt)*) => {}; 448 (emit I64x2Add $($rest:tt)*) => {}; 449 (emit I8x16Sub $($rest:tt)*) => {}; 450 (emit I16x8Sub $($rest:tt)*) => {}; 451 (emit I32x4Sub $($rest:tt)*) => {}; 452 (emit I64x2Sub $($rest:tt)*) => {}; 453 (emit I16x8Mul $($rest:tt)*) => {}; 454 (emit I32x4Mul $($rest:tt)*) => {}; 455 (emit I64x2Mul $($rest:tt)*) => {}; 456 (emit I8x16AddSatS $($rest:tt)*) => {}; 457 (emit I16x8AddSatS $($rest:tt)*) => {}; 458 (emit I8x16AddSatU $($rest:tt)*) => {}; 459 (emit I16x8AddSatU $($rest:tt)*) => {}; 460 (emit I8x16SubSatS $($rest:tt)*) => {}; 461 (emit I16x8SubSatS $($rest:tt)*) => {}; 462 (emit I8x16SubSatU $($rest:tt)*) => {}; 463 (emit I16x8SubSatU $($rest:tt)*) => {}; 464 (emit I8x16Abs $($rest:tt)*) => {}; 465 (emit I16x8Abs $($rest:tt)*) => {}; 466 (emit I32x4Abs $($rest:tt)*) => {}; 467 (emit I64x2Abs $($rest:tt)*) => {}; 468 (emit F32x4Abs $($rest:tt)*) => {}; 469 (emit F64x2Abs $($rest:tt)*) => {}; 470 (emit I8x16Neg $($rest:tt)*) => {}; 471 (emit I16x8Neg $($rest:tt)*) => {}; 472 (emit I32x4Neg $($rest:tt)*) => {}; 473 (emit I64x2Neg $($rest:tt)*) => {}; 474 (emit I8x16Shl $($rest:tt)*) => {}; 475 (emit I16x8Shl $($rest:tt)*) => {}; 476 (emit I32x4Shl $($rest:tt)*) => {}; 477 (emit I64x2Shl $($rest:tt)*) => {}; 478 (emit I8x16ShrU $($rest:tt)*) => {}; 479 (emit I16x8ShrU $($rest:tt)*) => {}; 480 (emit I32x4ShrU $($rest:tt)*) => {}; 481 (emit I64x2ShrU $($rest:tt)*) => {}; 482 (emit I8x16ShrS $($rest:tt)*) => {}; 483 (emit I16x8ShrS $($rest:tt)*) => {}; 484 (emit I32x4ShrS $($rest:tt)*) => {}; 485 (emit I64x2ShrS $($rest:tt)*) => {}; 486 (emit I16x8Q15MulrSatS $($rest:tt)*) => {}; 487 (emit I8x16AllTrue $($rest:tt)*) => {}; 488 (emit I16x8AllTrue $($rest:tt)*) => {}; 489 (emit I32x4AllTrue $($rest:tt)*) => {}; 490 (emit I64x2AllTrue $($rest:tt)*) => {}; 491 (emit I8x16Bitmask $($rest:tt)*) => {}; 492 (emit I16x8Bitmask $($rest:tt)*) => {}; 493 (emit I32x4Bitmask $($rest:tt)*) => {}; 494 (emit I64x2Bitmask $($rest:tt)*) => {}; 495 (emit I32x4TruncSatF32x4S $($rest:tt)*) => {}; 496 (emit I32x4TruncSatF32x4U $($rest:tt)*) => {}; 497 (emit I32x4TruncSatF64x2SZero $($rest:tt)*) => {}; 498 (emit I32x4TruncSatF64x2UZero $($rest:tt)*) => {}; 499 (emit I8x16MinU $($rest:tt)*) => {}; 500 (emit I16x8MinU $($rest:tt)*) => {}; 501 (emit I32x4MinU $($rest:tt)*) => {}; 502 (emit I8x16MinS $($rest:tt)*) => {}; 503 (emit I16x8MinS $($rest:tt)*) => {}; 504 (emit I32x4MinS $($rest:tt)*) => {}; 505 (emit I8x16MaxU $($rest:tt)*) => {}; 506 (emit I16x8MaxU $($rest:tt)*) => {}; 507 (emit I32x4MaxU $($rest:tt)*) => {}; 508 (emit I8x16MaxS $($rest:tt)*) => {}; 509 (emit I16x8MaxS $($rest:tt)*) => {}; 510 (emit I32x4MaxS $($rest:tt)*) => {}; 511 (emit I16x8ExtMulLowI8x16S $($rest:tt)*) => {}; 512 (emit I32x4ExtMulLowI16x8S $($rest:tt)*) => {}; 513 (emit I64x2ExtMulLowI32x4S $($rest:tt)*) => {}; 514 (emit I16x8ExtMulHighI8x16S $($rest:tt)*) => {}; 515 (emit I32x4ExtMulHighI16x8S $($rest:tt)*) => {}; 516 (emit I64x2ExtMulHighI32x4S $($rest:tt)*) => {}; 517 (emit I16x8ExtMulLowI8x16U $($rest:tt)*) => {}; 518 (emit I32x4ExtMulLowI16x8U $($rest:tt)*) => {}; 519 (emit I64x2ExtMulLowI32x4U $($rest:tt)*) => {}; 520 (emit I16x8ExtMulHighI8x16U $($rest:tt)*) => {}; 521 (emit I32x4ExtMulHighI16x8U $($rest:tt)*) => {}; 522 (emit I64x2ExtMulHighI32x4U $($rest:tt)*) => {}; 523 (emit I16x8ExtAddPairwiseI8x16U $($rest:tt)*) => {}; 524 (emit I16x8ExtAddPairwiseI8x16S $($rest:tt)*) => {}; 525 (emit I32x4ExtAddPairwiseI16x8U $($rest:tt)*) => {}; 526 (emit I32x4ExtAddPairwiseI16x8S $($rest:tt)*) => {}; 527 (emit I32x4DotI16x8S $($rest:tt)*) => {}; 528 (emit I8x16Popcnt $($rest:tt)*) => {}; 529 (emit I8x16AvgrU $($rest:tt)*) => {}; 530 (emit I16x8AvgrU $($rest:tt)*) => {}; 531 (emit F32x4Ceil $($rest:tt)*) => {}; 532 (emit F64x2Ceil $($rest:tt)*) => {}; 533 (emit F32x4Floor $($rest:tt)*) => {}; 534 (emit F64x2Floor $($rest:tt)*) => {}; 535 (emit F32x4Nearest $($rest:tt)*) => {}; 536 (emit F64x2Nearest $($rest:tt)*) => {}; 537 (emit F32x4Trunc $($rest:tt)*) => {}; 538 (emit F64x2Trunc $($rest:tt)*) => {}; 539 540 (emit $unsupported:tt $($rest:tt)*) => {$($rest)*}; 541 } 542 543 impl<'a, 'translation, 'data, M> VisitOperator<'a> for CodeGen<'a, 'translation, 'data, M, Emission> 544 where 545 M: MacroAssembler, 546 { 547 type Output = Result<()>; 548 549 fn visit_i32_const(&mut self, val: i32) -> Self::Output { 550 self.context.stack.push(Val::i32(val)); 551 552 Ok(()) 553 } 554 555 fn visit_i64_const(&mut self, val: i64) -> Self::Output { 556 self.context.stack.push(Val::i64(val)); 557 Ok(()) 558 } 559 560 fn visit_f32_const(&mut self, val: Ieee32) -> Self::Output { 561 self.context.stack.push(Val::f32(val)); 562 Ok(()) 563 } 564 565 fn visit_f64_const(&mut self, val: Ieee64) -> Self::Output { 566 self.context.stack.push(Val::f64(val)); 567 Ok(()) 568 } 569 570 fn visit_f32_add(&mut self) -> Self::Output { 571 self.context.binop( 572 self.masm, 573 OperandSize::S32, 574 &mut |masm: &mut M, dst, src, size| { 575 masm.float_add(writable!(dst), dst, src, size)?; 576 Ok(TypedReg::f32(dst)) 577 }, 578 ) 579 } 580 581 fn visit_f64_add(&mut self) -> Self::Output { 582 self.context.binop( 583 self.masm, 584 OperandSize::S64, 585 &mut |masm: &mut M, dst, src, size| { 586 masm.float_add(writable!(dst), dst, src, size)?; 587 Ok(TypedReg::f64(dst)) 588 }, 589 ) 590 } 591 592 fn visit_f32_sub(&mut self) -> Self::Output { 593 self.context.binop( 594 self.masm, 595 OperandSize::S32, 596 &mut |masm: &mut M, dst, src, size| { 597 masm.float_sub(writable!(dst), dst, src, size)?; 598 Ok(TypedReg::f32(dst)) 599 }, 600 ) 601 } 602 603 fn visit_f64_sub(&mut self) -> Self::Output { 604 self.context.binop( 605 self.masm, 606 OperandSize::S64, 607 &mut |masm: &mut M, dst, src, size| { 608 masm.float_sub(writable!(dst), dst, src, size)?; 609 Ok(TypedReg::f64(dst)) 610 }, 611 ) 612 } 613 614 fn visit_f32_mul(&mut self) -> Self::Output { 615 self.context.binop( 616 self.masm, 617 OperandSize::S32, 618 &mut |masm: &mut M, dst, src, size| { 619 masm.float_mul(writable!(dst), dst, src, size)?; 620 Ok(TypedReg::f32(dst)) 621 }, 622 ) 623 } 624 625 fn visit_f64_mul(&mut self) -> Self::Output { 626 self.context.binop( 627 self.masm, 628 OperandSize::S64, 629 &mut |masm: &mut M, dst, src, size| { 630 masm.float_mul(writable!(dst), dst, src, size)?; 631 Ok(TypedReg::f64(dst)) 632 }, 633 ) 634 } 635 636 fn visit_f32_div(&mut self) -> Self::Output { 637 self.context.binop( 638 self.masm, 639 OperandSize::S32, 640 &mut |masm: &mut M, dst, src, size| { 641 masm.float_div(writable!(dst), dst, src, size)?; 642 Ok(TypedReg::f32(dst)) 643 }, 644 ) 645 } 646 647 fn visit_f64_div(&mut self) -> Self::Output { 648 self.context.binop( 649 self.masm, 650 OperandSize::S64, 651 &mut |masm: &mut M, dst, src, size| { 652 masm.float_div(writable!(dst), dst, src, size)?; 653 Ok(TypedReg::f64(dst)) 654 }, 655 ) 656 } 657 658 fn visit_f32_min(&mut self) -> Self::Output { 659 self.context.binop( 660 self.masm, 661 OperandSize::S32, 662 &mut |masm: &mut M, dst, src, size| { 663 masm.float_min(writable!(dst), dst, src, size)?; 664 Ok(TypedReg::f32(dst)) 665 }, 666 ) 667 } 668 669 fn visit_f64_min(&mut self) -> Self::Output { 670 self.context.binop( 671 self.masm, 672 OperandSize::S64, 673 &mut |masm: &mut M, dst, src, size| { 674 masm.float_min(writable!(dst), dst, src, size)?; 675 Ok(TypedReg::f64(dst)) 676 }, 677 ) 678 } 679 680 fn visit_f32_max(&mut self) -> Self::Output { 681 self.context.binop( 682 self.masm, 683 OperandSize::S32, 684 &mut |masm: &mut M, dst, src, size| { 685 masm.float_max(writable!(dst), dst, src, size)?; 686 Ok(TypedReg::f32(dst)) 687 }, 688 ) 689 } 690 691 fn visit_f64_max(&mut self) -> Self::Output { 692 self.context.binop( 693 self.masm, 694 OperandSize::S64, 695 &mut |masm: &mut M, dst, src, size| { 696 masm.float_max(writable!(dst), dst, src, size)?; 697 Ok(TypedReg::f64(dst)) 698 }, 699 ) 700 } 701 702 fn visit_f32_copysign(&mut self) -> Self::Output { 703 self.context.binop( 704 self.masm, 705 OperandSize::S32, 706 &mut |masm: &mut M, dst, src, size| { 707 masm.float_copysign(writable!(dst), dst, src, size)?; 708 Ok(TypedReg::f32(dst)) 709 }, 710 ) 711 } 712 713 fn visit_f64_copysign(&mut self) -> Self::Output { 714 self.context.binop( 715 self.masm, 716 OperandSize::S64, 717 &mut |masm: &mut M, dst, src, size| { 718 masm.float_copysign(writable!(dst), dst, src, size)?; 719 Ok(TypedReg::f64(dst)) 720 }, 721 ) 722 } 723 724 fn visit_f32_abs(&mut self) -> Self::Output { 725 self.context.unop(self.masm, |masm, reg| { 726 masm.float_abs(writable!(reg), OperandSize::S32)?; 727 Ok(TypedReg::f32(reg)) 728 }) 729 } 730 731 fn visit_f64_abs(&mut self) -> Self::Output { 732 self.context.unop(self.masm, |masm, reg| { 733 masm.float_abs(writable!(reg), OperandSize::S64)?; 734 Ok(TypedReg::f64(reg)) 735 }) 736 } 737 738 fn visit_f32_neg(&mut self) -> Self::Output { 739 self.context.unop(self.masm, |masm, reg| { 740 masm.float_neg(writable!(reg), OperandSize::S32)?; 741 Ok(TypedReg::f32(reg)) 742 }) 743 } 744 745 fn visit_f64_neg(&mut self) -> Self::Output { 746 self.context.unop(self.masm, |masm, reg| { 747 masm.float_neg(writable!(reg), OperandSize::S64)?; 748 Ok(TypedReg::f64(reg)) 749 }) 750 } 751 752 fn visit_f32_floor(&mut self) -> Self::Output { 753 self.masm.float_round( 754 RoundingMode::Down, 755 &mut self.env, 756 &mut self.context, 757 OperandSize::S32, 758 |env, cx, masm| { 759 let builtin = env.builtins.floor_f32::<M::ABI>()?; 760 FnCall::emit::<M>(env, masm, cx, Callee::Builtin(builtin)) 761 }, 762 ) 763 } 764 765 fn visit_f64_floor(&mut self) -> Self::Output { 766 self.masm.float_round( 767 RoundingMode::Down, 768 &mut self.env, 769 &mut self.context, 770 OperandSize::S64, 771 |env, cx, masm| { 772 let builtin = env.builtins.floor_f64::<M::ABI>()?; 773 FnCall::emit::<M>(env, masm, cx, Callee::Builtin(builtin)) 774 }, 775 ) 776 } 777 778 fn visit_f32_ceil(&mut self) -> Self::Output { 779 self.masm.float_round( 780 RoundingMode::Up, 781 &mut self.env, 782 &mut self.context, 783 OperandSize::S32, 784 |env, cx, masm| { 785 let builtin = env.builtins.ceil_f32::<M::ABI>()?; 786 FnCall::emit::<M>(env, masm, cx, Callee::Builtin(builtin)) 787 }, 788 ) 789 } 790 791 fn visit_f64_ceil(&mut self) -> Self::Output { 792 self.masm.float_round( 793 RoundingMode::Up, 794 &mut self.env, 795 &mut self.context, 796 OperandSize::S64, 797 |env, cx, masm| { 798 let builtin = env.builtins.ceil_f64::<M::ABI>()?; 799 FnCall::emit::<M>(env, masm, cx, Callee::Builtin(builtin)) 800 }, 801 ) 802 } 803 804 fn visit_f32_nearest(&mut self) -> Self::Output { 805 self.masm.float_round( 806 RoundingMode::Nearest, 807 &mut self.env, 808 &mut self.context, 809 OperandSize::S32, 810 |env, cx, masm| { 811 let builtin = env.builtins.nearest_f32::<M::ABI>()?; 812 FnCall::emit::<M>(env, masm, cx, Callee::Builtin(builtin)) 813 }, 814 ) 815 } 816 817 fn visit_f64_nearest(&mut self) -> Self::Output { 818 self.masm.float_round( 819 RoundingMode::Nearest, 820 &mut self.env, 821 &mut self.context, 822 OperandSize::S64, 823 |env, cx, masm| { 824 let builtin = env.builtins.nearest_f64::<M::ABI>()?; 825 FnCall::emit::<M>(env, masm, cx, Callee::Builtin(builtin)) 826 }, 827 ) 828 } 829 830 fn visit_f32_trunc(&mut self) -> Self::Output { 831 self.masm.float_round( 832 RoundingMode::Zero, 833 &mut self.env, 834 &mut self.context, 835 OperandSize::S32, 836 |env, cx, masm| { 837 let builtin = env.builtins.trunc_f32::<M::ABI>()?; 838 FnCall::emit::<M>(env, masm, cx, Callee::Builtin(builtin)) 839 }, 840 ) 841 } 842 843 fn visit_f64_trunc(&mut self) -> Self::Output { 844 self.masm.float_round( 845 RoundingMode::Zero, 846 &mut self.env, 847 &mut self.context, 848 OperandSize::S64, 849 |env, cx, masm| { 850 let builtin = env.builtins.trunc_f64::<M::ABI>()?; 851 FnCall::emit::<M>(env, masm, cx, Callee::Builtin(builtin)) 852 }, 853 ) 854 } 855 856 fn visit_f32_sqrt(&mut self) -> Self::Output { 857 self.context.unop(self.masm, |masm, reg| { 858 masm.float_sqrt(writable!(reg), reg, OperandSize::S32)?; 859 Ok(TypedReg::f32(reg)) 860 }) 861 } 862 863 fn visit_f64_sqrt(&mut self) -> Self::Output { 864 self.context.unop(self.masm, |masm, reg| { 865 masm.float_sqrt(writable!(reg), reg, OperandSize::S64)?; 866 Ok(TypedReg::f64(reg)) 867 }) 868 } 869 870 fn visit_f32_eq(&mut self) -> Self::Output { 871 self.context.float_cmp_op( 872 self.masm, 873 OperandSize::S32, 874 &mut |masm: &mut M, dst, src1, src2, size| { 875 masm.float_cmp_with_set(writable!(dst), src1, src2, FloatCmpKind::Eq, size) 876 }, 877 ) 878 } 879 880 fn visit_f64_eq(&mut self) -> Self::Output { 881 self.context.float_cmp_op( 882 self.masm, 883 OperandSize::S64, 884 &mut |masm: &mut M, dst, src1, src2, size| { 885 masm.float_cmp_with_set(writable!(dst), src1, src2, FloatCmpKind::Eq, size) 886 }, 887 ) 888 } 889 890 fn visit_f32_ne(&mut self) -> Self::Output { 891 self.context.float_cmp_op( 892 self.masm, 893 OperandSize::S32, 894 &mut |masm: &mut M, dst, src1, src2, size| { 895 masm.float_cmp_with_set(writable!(dst), src1, src2, FloatCmpKind::Ne, size) 896 }, 897 ) 898 } 899 900 fn visit_f64_ne(&mut self) -> Self::Output { 901 self.context.float_cmp_op( 902 self.masm, 903 OperandSize::S64, 904 &mut |masm: &mut M, dst, src1, src2, size| { 905 masm.float_cmp_with_set(writable!(dst), src1, src2, FloatCmpKind::Ne, size) 906 }, 907 ) 908 } 909 910 fn visit_f32_lt(&mut self) -> Self::Output { 911 self.context.float_cmp_op( 912 self.masm, 913 OperandSize::S32, 914 &mut |masm: &mut M, dst, src1, src2, size| { 915 masm.float_cmp_with_set(writable!(dst), src1, src2, FloatCmpKind::Lt, size) 916 }, 917 ) 918 } 919 920 fn visit_f64_lt(&mut self) -> Self::Output { 921 self.context.float_cmp_op( 922 self.masm, 923 OperandSize::S64, 924 &mut |masm: &mut M, dst, src1, src2, size| { 925 masm.float_cmp_with_set(writable!(dst), src1, src2, FloatCmpKind::Lt, size) 926 }, 927 ) 928 } 929 930 fn visit_f32_gt(&mut self) -> Self::Output { 931 self.context.float_cmp_op( 932 self.masm, 933 OperandSize::S32, 934 &mut |masm: &mut M, dst, src1, src2, size| { 935 masm.float_cmp_with_set(writable!(dst), src1, src2, FloatCmpKind::Gt, size) 936 }, 937 ) 938 } 939 940 fn visit_f64_gt(&mut self) -> Self::Output { 941 self.context.float_cmp_op( 942 self.masm, 943 OperandSize::S64, 944 &mut |masm: &mut M, dst, src1, src2, size| { 945 masm.float_cmp_with_set(writable!(dst), src1, src2, FloatCmpKind::Gt, size) 946 }, 947 ) 948 } 949 950 fn visit_f32_le(&mut self) -> Self::Output { 951 self.context.float_cmp_op( 952 self.masm, 953 OperandSize::S32, 954 &mut |masm: &mut M, dst, src1, src2, size| { 955 masm.float_cmp_with_set(writable!(dst), src1, src2, FloatCmpKind::Le, size) 956 }, 957 ) 958 } 959 960 fn visit_f64_le(&mut self) -> Self::Output { 961 self.context.float_cmp_op( 962 self.masm, 963 OperandSize::S64, 964 &mut |masm: &mut M, dst, src1, src2, size| { 965 masm.float_cmp_with_set(writable!(dst), src1, src2, FloatCmpKind::Le, size) 966 }, 967 ) 968 } 969 970 fn visit_f32_ge(&mut self) -> Self::Output { 971 self.context.float_cmp_op( 972 self.masm, 973 OperandSize::S32, 974 &mut |masm: &mut M, dst, src1, src2, size| { 975 masm.float_cmp_with_set(writable!(dst), src1, src2, FloatCmpKind::Ge, size) 976 }, 977 ) 978 } 979 980 fn visit_f64_ge(&mut self) -> Self::Output { 981 self.context.float_cmp_op( 982 self.masm, 983 OperandSize::S64, 984 &mut |masm: &mut M, dst, src1, src2, size| { 985 masm.float_cmp_with_set(writable!(dst), src1, src2, FloatCmpKind::Ge, size) 986 }, 987 ) 988 } 989 990 fn visit_f32_convert_i32_s(&mut self) -> Self::Output { 991 self.context 992 .convert_op(self.masm, WasmValType::F32, |masm, dst, src, dst_size| { 993 masm.signed_convert(writable!(dst), src, OperandSize::S32, dst_size) 994 }) 995 } 996 997 fn visit_f32_convert_i32_u(&mut self) -> Self::Output { 998 self.context.convert_op_with_tmp_reg( 999 self.masm, 1000 WasmValType::F32, 1001 RegClass::Int, 1002 |masm, dst, src, tmp_gpr, dst_size| { 1003 masm.unsigned_convert(writable!(dst), src, tmp_gpr, OperandSize::S32, dst_size) 1004 }, 1005 ) 1006 } 1007 1008 fn visit_f32_convert_i64_s(&mut self) -> Self::Output { 1009 self.context 1010 .convert_op(self.masm, WasmValType::F32, |masm, dst, src, dst_size| { 1011 masm.signed_convert(writable!(dst), src, OperandSize::S64, dst_size) 1012 }) 1013 } 1014 1015 fn visit_f32_convert_i64_u(&mut self) -> Self::Output { 1016 self.context.convert_op_with_tmp_reg( 1017 self.masm, 1018 WasmValType::F32, 1019 RegClass::Int, 1020 |masm, dst, src, tmp_gpr, dst_size| { 1021 masm.unsigned_convert(writable!(dst), src, tmp_gpr, OperandSize::S64, dst_size) 1022 }, 1023 ) 1024 } 1025 1026 fn visit_f64_convert_i32_s(&mut self) -> Self::Output { 1027 self.context 1028 .convert_op(self.masm, WasmValType::F64, |masm, dst, src, dst_size| { 1029 masm.signed_convert(writable!(dst), src, OperandSize::S32, dst_size) 1030 }) 1031 } 1032 1033 fn visit_f64_convert_i32_u(&mut self) -> Self::Output { 1034 self.context.convert_op_with_tmp_reg( 1035 self.masm, 1036 WasmValType::F64, 1037 RegClass::Int, 1038 |masm, dst, src, tmp_gpr, dst_size| { 1039 masm.unsigned_convert(writable!(dst), src, tmp_gpr, OperandSize::S32, dst_size) 1040 }, 1041 ) 1042 } 1043 1044 fn visit_f64_convert_i64_s(&mut self) -> Self::Output { 1045 self.context 1046 .convert_op(self.masm, WasmValType::F64, |masm, dst, src, dst_size| { 1047 masm.signed_convert(writable!(dst), src, OperandSize::S64, dst_size) 1048 }) 1049 } 1050 1051 fn visit_f64_convert_i64_u(&mut self) -> Self::Output { 1052 self.context.convert_op_with_tmp_reg( 1053 self.masm, 1054 WasmValType::F64, 1055 RegClass::Int, 1056 |masm, dst, src, tmp_gpr, dst_size| { 1057 masm.unsigned_convert(writable!(dst), src, tmp_gpr, OperandSize::S64, dst_size) 1058 }, 1059 ) 1060 } 1061 1062 fn visit_f32_reinterpret_i32(&mut self) -> Self::Output { 1063 self.context 1064 .convert_op(self.masm, WasmValType::F32, |masm, dst, src, size| { 1065 masm.reinterpret_int_as_float(writable!(dst), src.into(), size) 1066 }) 1067 } 1068 1069 fn visit_f64_reinterpret_i64(&mut self) -> Self::Output { 1070 self.context 1071 .convert_op(self.masm, WasmValType::F64, |masm, dst, src, size| { 1072 masm.reinterpret_int_as_float(writable!(dst), src.into(), size) 1073 }) 1074 } 1075 1076 fn visit_f32_demote_f64(&mut self) -> Self::Output { 1077 self.context.unop(self.masm, |masm, reg| { 1078 masm.demote(writable!(reg), reg)?; 1079 Ok(TypedReg::f32(reg)) 1080 }) 1081 } 1082 1083 fn visit_f64_promote_f32(&mut self) -> Self::Output { 1084 self.context.unop(self.masm, |masm, reg| { 1085 masm.promote(writable!(reg), reg)?; 1086 Ok(TypedReg::f64(reg)) 1087 }) 1088 } 1089 1090 fn visit_i32_add(&mut self) -> Self::Output { 1091 self.context.i32_binop(self.masm, |masm, dst, src, size| { 1092 masm.add(writable!(dst), dst, src, size)?; 1093 Ok(TypedReg::i32(dst)) 1094 }) 1095 } 1096 1097 fn visit_i64_add(&mut self) -> Self::Output { 1098 self.context.i64_binop(self.masm, |masm, dst, src, size| { 1099 masm.add(writable!(dst), dst, src, size)?; 1100 Ok(TypedReg::i64(dst)) 1101 }) 1102 } 1103 1104 fn visit_i32_sub(&mut self) -> Self::Output { 1105 self.context.i32_binop(self.masm, |masm, dst, src, size| { 1106 masm.sub(writable!(dst), dst, src, size)?; 1107 Ok(TypedReg::i32(dst)) 1108 }) 1109 } 1110 1111 fn visit_i64_sub(&mut self) -> Self::Output { 1112 self.context.i64_binop(self.masm, |masm, dst, src, size| { 1113 masm.sub(writable!(dst), dst, src, size)?; 1114 Ok(TypedReg::i64(dst)) 1115 }) 1116 } 1117 1118 fn visit_i32_mul(&mut self) -> Self::Output { 1119 self.context.i32_binop(self.masm, |masm, dst, src, size| { 1120 masm.mul(writable!(dst), dst, src, size)?; 1121 Ok(TypedReg::i32(dst)) 1122 }) 1123 } 1124 1125 fn visit_i64_mul(&mut self) -> Self::Output { 1126 self.context.i64_binop(self.masm, |masm, dst, src, size| { 1127 masm.mul(writable!(dst), dst, src, size)?; 1128 Ok(TypedReg::i64(dst)) 1129 }) 1130 } 1131 1132 fn visit_i32_div_s(&mut self) -> Self::Output { 1133 use DivKind::*; 1134 use OperandSize::*; 1135 1136 self.masm.div(&mut self.context, Signed, S32) 1137 } 1138 1139 fn visit_i32_div_u(&mut self) -> Self::Output { 1140 use DivKind::*; 1141 use OperandSize::*; 1142 1143 self.masm.div(&mut self.context, Unsigned, S32) 1144 } 1145 1146 fn visit_i64_div_s(&mut self) -> Self::Output { 1147 use DivKind::*; 1148 use OperandSize::*; 1149 1150 self.masm.div(&mut self.context, Signed, S64) 1151 } 1152 1153 fn visit_i64_div_u(&mut self) -> Self::Output { 1154 use DivKind::*; 1155 use OperandSize::*; 1156 1157 self.masm.div(&mut self.context, Unsigned, S64) 1158 } 1159 1160 fn visit_i32_rem_s(&mut self) -> Self::Output { 1161 use OperandSize::*; 1162 use RemKind::*; 1163 1164 self.masm.rem(&mut self.context, Signed, S32) 1165 } 1166 1167 fn visit_i32_rem_u(&mut self) -> Self::Output { 1168 use OperandSize::*; 1169 use RemKind::*; 1170 1171 self.masm.rem(&mut self.context, Unsigned, S32) 1172 } 1173 1174 fn visit_i64_rem_s(&mut self) -> Self::Output { 1175 use OperandSize::*; 1176 use RemKind::*; 1177 1178 self.masm.rem(&mut self.context, Signed, S64) 1179 } 1180 1181 fn visit_i64_rem_u(&mut self) -> Self::Output { 1182 use OperandSize::*; 1183 use RemKind::*; 1184 1185 self.masm.rem(&mut self.context, Unsigned, S64) 1186 } 1187 1188 fn visit_i32_eq(&mut self) -> Self::Output { 1189 self.cmp_i32s(IntCmpKind::Eq) 1190 } 1191 1192 fn visit_i64_eq(&mut self) -> Self::Output { 1193 self.cmp_i64s(IntCmpKind::Eq) 1194 } 1195 1196 fn visit_i32_ne(&mut self) -> Self::Output { 1197 self.cmp_i32s(IntCmpKind::Ne) 1198 } 1199 1200 fn visit_i64_ne(&mut self) -> Self::Output { 1201 self.cmp_i64s(IntCmpKind::Ne) 1202 } 1203 1204 fn visit_i32_lt_s(&mut self) -> Self::Output { 1205 self.cmp_i32s(IntCmpKind::LtS) 1206 } 1207 1208 fn visit_i64_lt_s(&mut self) -> Self::Output { 1209 self.cmp_i64s(IntCmpKind::LtS) 1210 } 1211 1212 fn visit_i32_lt_u(&mut self) -> Self::Output { 1213 self.cmp_i32s(IntCmpKind::LtU) 1214 } 1215 1216 fn visit_i64_lt_u(&mut self) -> Self::Output { 1217 self.cmp_i64s(IntCmpKind::LtU) 1218 } 1219 1220 fn visit_i32_le_s(&mut self) -> Self::Output { 1221 self.cmp_i32s(IntCmpKind::LeS) 1222 } 1223 1224 fn visit_i64_le_s(&mut self) -> Self::Output { 1225 self.cmp_i64s(IntCmpKind::LeS) 1226 } 1227 1228 fn visit_i32_le_u(&mut self) -> Self::Output { 1229 self.cmp_i32s(IntCmpKind::LeU) 1230 } 1231 1232 fn visit_i64_le_u(&mut self) -> Self::Output { 1233 self.cmp_i64s(IntCmpKind::LeU) 1234 } 1235 1236 fn visit_i32_gt_s(&mut self) -> Self::Output { 1237 self.cmp_i32s(IntCmpKind::GtS) 1238 } 1239 1240 fn visit_i64_gt_s(&mut self) -> Self::Output { 1241 self.cmp_i64s(IntCmpKind::GtS) 1242 } 1243 1244 fn visit_i32_gt_u(&mut self) -> Self::Output { 1245 self.cmp_i32s(IntCmpKind::GtU) 1246 } 1247 1248 fn visit_i64_gt_u(&mut self) -> Self::Output { 1249 self.cmp_i64s(IntCmpKind::GtU) 1250 } 1251 1252 fn visit_i32_ge_s(&mut self) -> Self::Output { 1253 self.cmp_i32s(IntCmpKind::GeS) 1254 } 1255 1256 fn visit_i64_ge_s(&mut self) -> Self::Output { 1257 self.cmp_i64s(IntCmpKind::GeS) 1258 } 1259 1260 fn visit_i32_ge_u(&mut self) -> Self::Output { 1261 self.cmp_i32s(IntCmpKind::GeU) 1262 } 1263 1264 fn visit_i64_ge_u(&mut self) -> Self::Output { 1265 self.cmp_i64s(IntCmpKind::GeU) 1266 } 1267 1268 fn visit_i32_eqz(&mut self) -> Self::Output { 1269 use OperandSize::*; 1270 1271 self.context.unop(self.masm, |masm, reg| { 1272 masm.cmp_with_set(writable!(reg.into()), RegImm::i32(0), IntCmpKind::Eq, S32)?; 1273 Ok(TypedReg::i32(reg)) 1274 }) 1275 } 1276 1277 fn visit_i64_eqz(&mut self) -> Self::Output { 1278 use OperandSize::*; 1279 1280 self.context.unop(self.masm, |masm, reg| { 1281 masm.cmp_with_set(writable!(reg.into()), RegImm::i64(0), IntCmpKind::Eq, S64)?; 1282 Ok(TypedReg::i32(reg)) // Return value for `i64.eqz` is an `i32`. 1283 }) 1284 } 1285 1286 fn visit_i32_clz(&mut self) -> Self::Output { 1287 use OperandSize::*; 1288 1289 self.context.unop(self.masm, |masm, reg| { 1290 masm.clz(writable!(reg), reg, S32)?; 1291 Ok(TypedReg::i32(reg)) 1292 }) 1293 } 1294 1295 fn visit_i64_clz(&mut self) -> Self::Output { 1296 use OperandSize::*; 1297 1298 self.context.unop(self.masm, |masm, reg| { 1299 masm.clz(writable!(reg), reg, S64)?; 1300 Ok(TypedReg::i64(reg)) 1301 }) 1302 } 1303 1304 fn visit_i32_ctz(&mut self) -> Self::Output { 1305 use OperandSize::*; 1306 1307 self.context.unop(self.masm, |masm, reg| { 1308 masm.ctz(writable!(reg), reg, S32)?; 1309 Ok(TypedReg::i32(reg)) 1310 }) 1311 } 1312 1313 fn visit_i64_ctz(&mut self) -> Self::Output { 1314 use OperandSize::*; 1315 1316 self.context.unop(self.masm, |masm, reg| { 1317 masm.ctz(writable!(reg), reg, S64)?; 1318 Ok(TypedReg::i64(reg)) 1319 }) 1320 } 1321 1322 fn visit_i32_and(&mut self) -> Self::Output { 1323 self.context.i32_binop(self.masm, |masm, dst, src, size| { 1324 masm.and(writable!(dst), dst, src, size)?; 1325 Ok(TypedReg::i32(dst)) 1326 }) 1327 } 1328 1329 fn visit_i64_and(&mut self) -> Self::Output { 1330 self.context.i64_binop(self.masm, |masm, dst, src, size| { 1331 masm.and(writable!(dst), dst, src, size)?; 1332 Ok(TypedReg::i64(dst)) 1333 }) 1334 } 1335 1336 fn visit_i32_or(&mut self) -> Self::Output { 1337 self.context.i32_binop(self.masm, |masm, dst, src, size| { 1338 masm.or(writable!(dst), dst, src, size)?; 1339 Ok(TypedReg::i32(dst)) 1340 }) 1341 } 1342 1343 fn visit_i64_or(&mut self) -> Self::Output { 1344 self.context.i64_binop(self.masm, |masm, dst, src, size| { 1345 masm.or(writable!(dst), dst, src, size)?; 1346 Ok(TypedReg::i64(dst)) 1347 }) 1348 } 1349 1350 fn visit_i32_xor(&mut self) -> Self::Output { 1351 self.context.i32_binop(self.masm, |masm, dst, src, size| { 1352 masm.xor(writable!(dst), dst, src, size)?; 1353 Ok(TypedReg::i32(dst)) 1354 }) 1355 } 1356 1357 fn visit_i64_xor(&mut self) -> Self::Output { 1358 self.context.i64_binop(self.masm, |masm, dst, src, size| { 1359 masm.xor(writable!(dst), dst, src, size)?; 1360 Ok(TypedReg::i64(dst)) 1361 }) 1362 } 1363 1364 fn visit_i32_shl(&mut self) -> Self::Output { 1365 use ShiftKind::*; 1366 1367 self.context.i32_shift(self.masm, Shl) 1368 } 1369 1370 fn visit_i64_shl(&mut self) -> Self::Output { 1371 use ShiftKind::*; 1372 1373 self.context.i64_shift(self.masm, Shl) 1374 } 1375 1376 fn visit_i32_shr_s(&mut self) -> Self::Output { 1377 use ShiftKind::*; 1378 1379 self.context.i32_shift(self.masm, ShrS) 1380 } 1381 1382 fn visit_i64_shr_s(&mut self) -> Self::Output { 1383 use ShiftKind::*; 1384 1385 self.context.i64_shift(self.masm, ShrS) 1386 } 1387 1388 fn visit_i32_shr_u(&mut self) -> Self::Output { 1389 use ShiftKind::*; 1390 1391 self.context.i32_shift(self.masm, ShrU) 1392 } 1393 1394 fn visit_i64_shr_u(&mut self) -> Self::Output { 1395 use ShiftKind::*; 1396 1397 self.context.i64_shift(self.masm, ShrU) 1398 } 1399 1400 fn visit_i32_rotl(&mut self) -> Self::Output { 1401 use ShiftKind::*; 1402 1403 self.context.i32_shift(self.masm, Rotl) 1404 } 1405 1406 fn visit_i64_rotl(&mut self) -> Self::Output { 1407 use ShiftKind::*; 1408 1409 self.context.i64_shift(self.masm, Rotl) 1410 } 1411 1412 fn visit_i32_rotr(&mut self) -> Self::Output { 1413 use ShiftKind::*; 1414 1415 self.context.i32_shift(self.masm, Rotr) 1416 } 1417 1418 fn visit_i64_rotr(&mut self) -> Self::Output { 1419 use ShiftKind::*; 1420 1421 self.context.i64_shift(self.masm, Rotr) 1422 } 1423 1424 fn visit_end(&mut self) -> Self::Output { 1425 if !self.context.reachable { 1426 self.handle_unreachable_end() 1427 } else { 1428 let mut control = self.pop_control_frame()?; 1429 control.emit_end(self.masm, &mut self.context) 1430 } 1431 } 1432 1433 fn visit_i32_popcnt(&mut self) -> Self::Output { 1434 use OperandSize::*; 1435 self.masm.popcnt(&mut self.context, S32) 1436 } 1437 1438 fn visit_i64_popcnt(&mut self) -> Self::Output { 1439 use OperandSize::*; 1440 1441 self.masm.popcnt(&mut self.context, S64) 1442 } 1443 1444 fn visit_i32_wrap_i64(&mut self) -> Self::Output { 1445 self.context.unop(self.masm, |masm, reg| { 1446 masm.wrap(writable!(reg), reg)?; 1447 Ok(TypedReg::i32(reg)) 1448 }) 1449 } 1450 1451 fn visit_i64_extend_i32_s(&mut self) -> Self::Output { 1452 self.context.unop(self.masm, |masm, reg| { 1453 masm.extend(writable!(reg), reg, Extend::<Signed>::I64Extend32.into())?; 1454 Ok(TypedReg::i64(reg)) 1455 }) 1456 } 1457 1458 fn visit_i64_extend_i32_u(&mut self) -> Self::Output { 1459 self.context.unop(self.masm, |masm, reg| { 1460 masm.extend(writable!(reg), reg, Extend::<Zero>::I64Extend32.into())?; 1461 Ok(TypedReg::i64(reg)) 1462 }) 1463 } 1464 1465 fn visit_i32_extend8_s(&mut self) -> Self::Output { 1466 self.context.unop(self.masm, |masm, reg| { 1467 masm.extend(writable!(reg), reg, Extend::<Signed>::I32Extend8.into())?; 1468 Ok(TypedReg::i32(reg)) 1469 }) 1470 } 1471 1472 fn visit_i32_extend16_s(&mut self) -> Self::Output { 1473 self.context.unop(self.masm, |masm, reg| { 1474 masm.extend(writable!(reg), reg, Extend::<Signed>::I32Extend16.into())?; 1475 Ok(TypedReg::i32(reg)) 1476 }) 1477 } 1478 1479 fn visit_i64_extend8_s(&mut self) -> Self::Output { 1480 self.context.unop(self.masm, |masm, reg| { 1481 masm.extend(writable!(reg), reg, Extend::<Signed>::I64Extend8.into())?; 1482 Ok(TypedReg::i64(reg)) 1483 }) 1484 } 1485 1486 fn visit_i64_extend16_s(&mut self) -> Self::Output { 1487 self.context.unop(self.masm, |masm, reg| { 1488 masm.extend(writable!(reg), reg, Extend::<Signed>::I64Extend16.into())?; 1489 Ok(TypedReg::i64(reg)) 1490 }) 1491 } 1492 1493 fn visit_i64_extend32_s(&mut self) -> Self::Output { 1494 self.context.unop(self.masm, |masm, reg| { 1495 masm.extend(writable!(reg), reg, Extend::<Signed>::I64Extend32.into())?; 1496 Ok(TypedReg::i64(reg)) 1497 }) 1498 } 1499 1500 fn visit_i32_trunc_f32_s(&mut self) -> Self::Output { 1501 use OperandSize::*; 1502 1503 self.context 1504 .convert_op(self.masm, WasmValType::I32, |masm, dst, src, dst_size| { 1505 masm.signed_truncate(writable!(dst), src, S32, dst_size, TruncKind::Unchecked) 1506 }) 1507 } 1508 1509 fn visit_i32_trunc_f32_u(&mut self) -> Self::Output { 1510 use OperandSize::*; 1511 1512 self.masm 1513 .unsigned_truncate(&mut self.context, S32, S32, TruncKind::Unchecked) 1514 } 1515 1516 fn visit_i32_trunc_f64_s(&mut self) -> Self::Output { 1517 use OperandSize::*; 1518 1519 self.context 1520 .convert_op(self.masm, WasmValType::I32, |masm, dst, src, dst_size| { 1521 masm.signed_truncate(writable!(dst), src, S64, dst_size, TruncKind::Unchecked) 1522 }) 1523 } 1524 1525 fn visit_i32_trunc_f64_u(&mut self) -> Self::Output { 1526 use OperandSize::*; 1527 self.masm 1528 .unsigned_truncate(&mut self.context, S64, S32, TruncKind::Unchecked) 1529 } 1530 1531 fn visit_i64_trunc_f32_s(&mut self) -> Self::Output { 1532 use OperandSize::*; 1533 1534 self.context 1535 .convert_op(self.masm, WasmValType::I64, |masm, dst, src, dst_size| { 1536 masm.signed_truncate(writable!(dst), src, S32, dst_size, TruncKind::Unchecked) 1537 }) 1538 } 1539 1540 fn visit_i64_trunc_f32_u(&mut self) -> Self::Output { 1541 use OperandSize::*; 1542 1543 self.masm 1544 .unsigned_truncate(&mut self.context, S32, S64, TruncKind::Unchecked) 1545 } 1546 1547 fn visit_i64_trunc_f64_s(&mut self) -> Self::Output { 1548 use OperandSize::*; 1549 1550 self.context 1551 .convert_op(self.masm, WasmValType::I64, |masm, dst, src, dst_size| { 1552 masm.signed_truncate(writable!(dst), src, S64, dst_size, TruncKind::Unchecked) 1553 }) 1554 } 1555 1556 fn visit_i64_trunc_f64_u(&mut self) -> Self::Output { 1557 use OperandSize::*; 1558 1559 self.masm 1560 .unsigned_truncate(&mut self.context, S64, S64, TruncKind::Unchecked) 1561 } 1562 1563 fn visit_i32_reinterpret_f32(&mut self) -> Self::Output { 1564 self.context 1565 .convert_op(self.masm, WasmValType::I32, |masm, dst, src, size| { 1566 masm.reinterpret_float_as_int(writable!(dst), src.into(), size) 1567 }) 1568 } 1569 1570 fn visit_i64_reinterpret_f64(&mut self) -> Self::Output { 1571 self.context 1572 .convert_op(self.masm, WasmValType::I64, |masm, dst, src, size| { 1573 masm.reinterpret_float_as_int(writable!(dst), src.into(), size) 1574 }) 1575 } 1576 1577 fn visit_local_get(&mut self, index: u32) -> Self::Output { 1578 use WasmValType::*; 1579 let context = &mut self.context; 1580 let slot = context.frame.get_wasm_local(index); 1581 match slot.ty { 1582 I32 | I64 | F32 | F64 | V128 => context.stack.push(Val::local(index, slot.ty)), 1583 Ref(rt) => match rt.heap_type { 1584 WasmHeapType::Func => context.stack.push(Val::local(index, slot.ty)), 1585 _ => bail!(CodeGenError::unsupported_wasm_type()), 1586 }, 1587 } 1588 1589 Ok(()) 1590 } 1591 1592 fn visit_local_set(&mut self, index: u32) -> Self::Output { 1593 let src = self.emit_set_local(index)?; 1594 self.context.free_reg(src); 1595 Ok(()) 1596 } 1597 1598 fn visit_call(&mut self, index: u32) -> Self::Output { 1599 let callee = self.env.callee_from_index(FuncIndex::from_u32(index)); 1600 FnCall::emit::<M>(&mut self.env, self.masm, &mut self.context, callee)?; 1601 Ok(()) 1602 } 1603 1604 fn visit_call_indirect(&mut self, type_index: u32, table_index: u32) -> Self::Output { 1605 // Spill now because `emit_lazy_init_funcref` and the `FnCall::emit` 1606 // invocations will both trigger spills since they both call functions. 1607 // However, the machine instructions for the spill emitted by 1608 // `emit_lazy_funcref` will be jumped over if the funcref was previously 1609 // initialized which may result in the machine stack becoming 1610 // unbalanced. 1611 self.context.spill(self.masm)?; 1612 1613 let type_index = TypeIndex::from_u32(type_index); 1614 let table_index = TableIndex::from_u32(table_index); 1615 1616 self.emit_lazy_init_funcref(table_index)?; 1617 1618 // Perform the indirect call. 1619 // This code assumes that [`Self::emit_lazy_init_funcref`] will 1620 // push the funcref to the value stack. 1621 let funcref_ptr = self 1622 .context 1623 .stack 1624 .peek() 1625 .map(|v| v.unwrap_reg()) 1626 .ok_or_else(|| CodeGenError::missing_values_in_stack())?; 1627 self.masm 1628 .trapz(funcref_ptr.into(), TRAP_INDIRECT_CALL_TO_NULL)?; 1629 self.emit_typecheck_funcref(funcref_ptr.into(), type_index)?; 1630 1631 let callee = self.env.funcref(type_index); 1632 FnCall::emit::<M>(&mut self.env, self.masm, &mut self.context, callee)?; 1633 Ok(()) 1634 } 1635 1636 fn visit_table_init(&mut self, elem: u32, table: u32) -> Self::Output { 1637 let at = self.context.stack.ensure_index_at(3)?; 1638 1639 self.context 1640 .stack 1641 .insert_many(at, &[table.try_into()?, elem.try_into()?]); 1642 1643 let builtin = self.env.builtins.table_init::<M::ABI, M::Ptr>()?; 1644 FnCall::emit::<M>( 1645 &mut self.env, 1646 self.masm, 1647 &mut self.context, 1648 Callee::Builtin(builtin.clone()), 1649 )?; 1650 self.context.pop_and_free(self.masm) 1651 } 1652 1653 fn visit_table_copy(&mut self, dst: u32, src: u32) -> Self::Output { 1654 let at = self.context.stack.ensure_index_at(3)?; 1655 self.context 1656 .stack 1657 .insert_many(at, &[dst.try_into()?, src.try_into()?]); 1658 1659 let builtin = self.env.builtins.table_copy::<M::ABI, M::Ptr>()?; 1660 FnCall::emit::<M>( 1661 &mut self.env, 1662 self.masm, 1663 &mut self.context, 1664 Callee::Builtin(builtin), 1665 )?; 1666 self.context.pop_and_free(self.masm) 1667 } 1668 1669 fn visit_table_get(&mut self, table: u32) -> Self::Output { 1670 let table_index = TableIndex::from_u32(table); 1671 let table = self.env.table(table_index); 1672 let heap_type = table.ref_type.heap_type; 1673 1674 match heap_type { 1675 WasmHeapType::Func => self.emit_lazy_init_funcref(table_index), 1676 _ => Err(anyhow!(CodeGenError::unsupported_wasm_type())), 1677 } 1678 } 1679 1680 fn visit_table_grow(&mut self, table: u32) -> Self::Output { 1681 let table_index = TableIndex::from_u32(table); 1682 let table_ty = self.env.table(table_index); 1683 let builtin = match table_ty.ref_type.heap_type { 1684 WasmHeapType::Func => self.env.builtins.table_grow_func_ref::<M::ABI, M::Ptr>()?, 1685 _ => bail!(CodeGenError::unsupported_wasm_type()), 1686 }; 1687 1688 let len = self.context.stack.len(); 1689 // table.grow` requires at least 2 elements on the value stack. 1690 let at = self.context.stack.ensure_index_at(2)?; 1691 1692 // The table_grow builtin expects the parameters in a different 1693 // order. 1694 // The value stack at this point should contain: 1695 // [ init_value | delta ] (stack top) 1696 // but the builtin function expects the init value as the last 1697 // argument. 1698 self.context.stack.inner_mut().swap(len - 1, len - 2); 1699 self.context.stack.insert_many(at, &[table.try_into()?]); 1700 1701 FnCall::emit::<M>( 1702 &mut self.env, 1703 self.masm, 1704 &mut self.context, 1705 Callee::Builtin(builtin.clone()), 1706 )?; 1707 1708 Ok(()) 1709 } 1710 1711 fn visit_table_size(&mut self, table: u32) -> Self::Output { 1712 let table_index = TableIndex::from_u32(table); 1713 let table_data = self.env.resolve_table_data(table_index); 1714 self.emit_compute_table_size(&table_data) 1715 } 1716 1717 fn visit_table_fill(&mut self, table: u32) -> Self::Output { 1718 let table_index = TableIndex::from_u32(table); 1719 let table_ty = self.env.table(table_index); 1720 1721 ensure!( 1722 table_ty.ref_type.heap_type == WasmHeapType::Func, 1723 CodeGenError::unsupported_wasm_type() 1724 ); 1725 1726 let builtin = self.env.builtins.table_fill_func_ref::<M::ABI, M::Ptr>()?; 1727 1728 let at = self.context.stack.ensure_index_at(3)?; 1729 1730 self.context.stack.insert_many(at, &[table.try_into()?]); 1731 FnCall::emit::<M>( 1732 &mut self.env, 1733 self.masm, 1734 &mut self.context, 1735 Callee::Builtin(builtin.clone()), 1736 )?; 1737 self.context.pop_and_free(self.masm) 1738 } 1739 1740 fn visit_table_set(&mut self, table: u32) -> Self::Output { 1741 let ptr_type = self.env.ptr_type(); 1742 let table_index = TableIndex::from_u32(table); 1743 let table_data = self.env.resolve_table_data(table_index); 1744 let table = self.env.table(table_index); 1745 match table.ref_type.heap_type { 1746 WasmHeapType::Func => { 1747 ensure!( 1748 self.tunables.table_lazy_init, 1749 CodeGenError::unsupported_table_eager_init() 1750 ); 1751 let value = self.context.pop_to_reg(self.masm, None)?; 1752 let index = self.context.pop_to_reg(self.masm, None)?; 1753 let base = self.context.any_gpr(self.masm)?; 1754 let elem_addr = 1755 self.emit_compute_table_elem_addr(index.into(), base, &table_data)?; 1756 // Set the initialized bit. 1757 self.masm.or( 1758 writable!(value.into()), 1759 value.into(), 1760 RegImm::i64(FUNCREF_INIT_BIT as i64), 1761 ptr_type.try_into()?, 1762 )?; 1763 1764 self.masm.store_ptr(value.into(), elem_addr)?; 1765 1766 self.context.free_reg(value); 1767 self.context.free_reg(index); 1768 self.context.free_reg(base); 1769 Ok(()) 1770 } 1771 _ => Err(anyhow!(CodeGenError::unsupported_wasm_type())), 1772 } 1773 } 1774 1775 fn visit_elem_drop(&mut self, index: u32) -> Self::Output { 1776 let elem_drop = self.env.builtins.elem_drop::<M::ABI, M::Ptr>()?; 1777 self.context.stack.extend([index.try_into()?]); 1778 FnCall::emit::<M>( 1779 &mut self.env, 1780 self.masm, 1781 &mut self.context, 1782 Callee::Builtin(elem_drop), 1783 )?; 1784 Ok(()) 1785 } 1786 1787 fn visit_memory_init(&mut self, data_index: u32, mem: u32) -> Self::Output { 1788 let at = self.context.stack.ensure_index_at(3)?; 1789 self.context 1790 .stack 1791 .insert_many(at, &[mem.try_into()?, data_index.try_into()?]); 1792 let builtin = self.env.builtins.memory_init::<M::ABI, M::Ptr>()?; 1793 FnCall::emit::<M>( 1794 &mut self.env, 1795 self.masm, 1796 &mut self.context, 1797 Callee::Builtin(builtin), 1798 )?; 1799 self.context.pop_and_free(self.masm) 1800 } 1801 1802 fn visit_memory_copy(&mut self, dst_mem: u32, src_mem: u32) -> Self::Output { 1803 // At this point, the stack is expected to contain: 1804 // [ dst_offset, src_offset, len ] 1805 // The following code inserts the missing params, so that stack contains: 1806 // [ vmctx, dst_mem, dst_offset, src_mem, src_offset, len ] 1807 // Which is the order expected by the builtin function. 1808 let _ = self.context.stack.ensure_index_at(3)?; 1809 let at = self.context.stack.ensure_index_at(2)?; 1810 self.context.stack.insert_many(at, &[src_mem.try_into()?]); 1811 1812 // One element was inserted above, so instead of 3, we use 4. 1813 let at = self.context.stack.ensure_index_at(4)?; 1814 self.context.stack.insert_many(at, &[dst_mem.try_into()?]); 1815 1816 let builtin = self.env.builtins.memory_copy::<M::ABI, M::Ptr>()?; 1817 1818 FnCall::emit::<M>( 1819 &mut self.env, 1820 self.masm, 1821 &mut self.context, 1822 Callee::Builtin(builtin), 1823 )?; 1824 self.context.pop_and_free(self.masm) 1825 } 1826 1827 fn visit_memory_fill(&mut self, mem: u32) -> Self::Output { 1828 let at = self.context.stack.ensure_index_at(3)?; 1829 1830 self.context.stack.insert_many(at, &[mem.try_into()?]); 1831 1832 let builtin = self.env.builtins.memory_fill::<M::ABI, M::Ptr>()?; 1833 FnCall::emit::<M>( 1834 &mut self.env, 1835 self.masm, 1836 &mut self.context, 1837 Callee::Builtin(builtin), 1838 )?; 1839 self.context.pop_and_free(self.masm) 1840 } 1841 1842 fn visit_memory_size(&mut self, mem: u32) -> Self::Output { 1843 let heap = self.env.resolve_heap(MemoryIndex::from_u32(mem)); 1844 self.emit_compute_memory_size(&heap) 1845 } 1846 1847 fn visit_memory_grow(&mut self, mem: u32) -> Self::Output { 1848 let _ = self.context.stack.ensure_index_at(1)?; 1849 // The stack at this point contains: [ delta ] 1850 // The desired state is 1851 // [ vmctx, delta, index ] 1852 self.context.stack.extend([mem.try_into()?]); 1853 1854 let heap = self.env.resolve_heap(MemoryIndex::from_u32(mem)); 1855 let builtin = self.env.builtins.memory32_grow::<M::ABI, M::Ptr>()?; 1856 FnCall::emit::<M>( 1857 &mut self.env, 1858 self.masm, 1859 &mut self.context, 1860 Callee::Builtin(builtin), 1861 )?; 1862 1863 // The memory32_grow builtin returns a pointer type, therefore we must 1864 // ensure that the return type is representative of the address space of 1865 // the heap type. 1866 match (self.env.ptr_type(), heap.index_type()) { 1867 (WasmValType::I64, WasmValType::I64) => Ok(()), 1868 // When the heap type is smaller than the pointer type, we adjust 1869 // the result of the memory32_grow builtin. 1870 (WasmValType::I64, WasmValType::I32) => { 1871 let top: Reg = self.context.pop_to_reg(self.masm, None)?.into(); 1872 self.masm.wrap(writable!(top.into()), top.into())?; 1873 self.context.stack.push(TypedReg::i32(top).into()); 1874 Ok(()) 1875 } 1876 _ => Err(anyhow!(CodeGenError::unsupported_32_bit_platform())), 1877 } 1878 } 1879 1880 fn visit_data_drop(&mut self, data_index: u32) -> Self::Output { 1881 self.context.stack.extend([data_index.try_into()?]); 1882 1883 let builtin = self.env.builtins.data_drop::<M::ABI, M::Ptr>()?; 1884 FnCall::emit::<M>( 1885 &mut self.env, 1886 self.masm, 1887 &mut self.context, 1888 Callee::Builtin(builtin), 1889 ) 1890 } 1891 1892 fn visit_nop(&mut self) -> Self::Output { 1893 Ok(()) 1894 } 1895 1896 fn visit_if(&mut self, blockty: BlockType) -> Self::Output { 1897 self.control_frames.push(ControlStackFrame::r#if( 1898 self.env.resolve_block_sig(blockty), 1899 self.masm, 1900 &mut self.context, 1901 )?); 1902 1903 Ok(()) 1904 } 1905 1906 fn visit_else(&mut self) -> Self::Output { 1907 if !self.context.reachable { 1908 self.handle_unreachable_else() 1909 } else { 1910 let control = self 1911 .control_frames 1912 .last_mut() 1913 .ok_or_else(|| CodeGenError::control_frame_expected())?; 1914 control.emit_else(self.masm, &mut self.context) 1915 } 1916 } 1917 1918 fn visit_block(&mut self, blockty: BlockType) -> Self::Output { 1919 self.control_frames.push(ControlStackFrame::block( 1920 self.env.resolve_block_sig(blockty), 1921 self.masm, 1922 &mut self.context, 1923 )?); 1924 1925 Ok(()) 1926 } 1927 1928 fn visit_loop(&mut self, blockty: BlockType) -> Self::Output { 1929 self.control_frames.push(ControlStackFrame::r#loop( 1930 self.env.resolve_block_sig(blockty), 1931 self.masm, 1932 &mut self.context, 1933 )?); 1934 1935 self.maybe_emit_epoch_check()?; 1936 self.maybe_emit_fuel_check() 1937 } 1938 1939 fn visit_br(&mut self, depth: u32) -> Self::Output { 1940 let index = control_index(depth, self.control_frames.len())?; 1941 let frame = &mut self.control_frames[index]; 1942 self.context 1943 .unconditional_jump(frame, self.masm, |masm, cx, frame| { 1944 frame.pop_abi_results::<M, _>(cx, masm, |results, _, _| { 1945 Ok(results.ret_area().copied()) 1946 }) 1947 }) 1948 } 1949 1950 fn visit_br_if(&mut self, depth: u32) -> Self::Output { 1951 let index = control_index(depth, self.control_frames.len())?; 1952 let frame = &mut self.control_frames[index]; 1953 frame.set_as_target(); 1954 1955 let top = { 1956 let top = self.context.without::<Result<TypedReg>, M, _>( 1957 frame.results::<M>()?.regs(), 1958 self.masm, 1959 |ctx, masm| ctx.pop_to_reg(masm, None), 1960 )??; 1961 // Explicitly save any live registers and locals before setting up 1962 // the branch state. 1963 // In some cases, calculating the `top` value above, will result in 1964 // a spill, thus the following one will result in a no-op. 1965 self.context.spill(self.masm)?; 1966 frame.top_abi_results::<M, _>( 1967 &mut self.context, 1968 self.masm, 1969 |results, context, masm| { 1970 // In the case of `br_if` there's a possibility that we'll 1971 // exit early from the block or fallthrough, for 1972 // a fallthrough, we cannot rely on the pre-computed return area; 1973 // it must be recalculated so that any values that are 1974 // generated are correctly placed near the current stack 1975 // pointer. 1976 if results.on_stack() { 1977 let stack_consumed = context.stack.sizeof(results.stack_operands_len()); 1978 let base = masm.sp_offset()?.as_u32() - stack_consumed; 1979 let offs = base + results.size(); 1980 Ok(Some(RetArea::sp(SPOffset::from_u32(offs)))) 1981 } else { 1982 Ok(None) 1983 } 1984 }, 1985 )?; 1986 top 1987 }; 1988 1989 // Emit instructions to balance the machine stack if the frame has 1990 // a different offset. 1991 let current_sp_offset = self.masm.sp_offset()?; 1992 let results_size = frame.results::<M>()?.size(); 1993 let state = frame.stack_state(); 1994 let (label, cmp, needs_cleanup) = if current_sp_offset > state.target_offset { 1995 (self.masm.get_label()?, IntCmpKind::Eq, true) 1996 } else { 1997 (*frame.label(), IntCmpKind::Ne, false) 1998 }; 1999 2000 self.masm 2001 .branch(cmp, top.reg.into(), top.reg.into(), label, OperandSize::S32)?; 2002 self.context.free_reg(top); 2003 2004 if needs_cleanup { 2005 // Emit instructions to balance the stack and jump if not falling 2006 // through. 2007 self.masm.memmove( 2008 current_sp_offset, 2009 state.target_offset, 2010 results_size, 2011 MemMoveDirection::LowToHigh, 2012 )?; 2013 self.masm.ensure_sp_for_jump(state.target_offset)?; 2014 self.masm.jmp(*frame.label())?; 2015 2016 // Restore sp_offset to what it was for falling through and emit 2017 // fallthrough label. 2018 self.masm.reset_stack_pointer(current_sp_offset)?; 2019 self.masm.bind(label)?; 2020 } 2021 2022 Ok(()) 2023 } 2024 2025 fn visit_br_table(&mut self, targets: BrTable<'a>) -> Self::Output { 2026 // +1 to account for the default target. 2027 let len = targets.len() + 1; 2028 // SmallVec<[_; 5]> to match the binary emission layer (e.g 2029 // see `JmpTableSeq'), but here we use 5 instead since we 2030 // bundle the default target as the last element in the array. 2031 let mut labels: SmallVec<[_; 5]> = smallvec![]; 2032 for _ in 0..len { 2033 labels.push(self.masm.get_label()?); 2034 } 2035 2036 let default_index = control_index(targets.default(), self.control_frames.len())?; 2037 let default_frame = &mut self.control_frames[default_index]; 2038 let default_result = default_frame.results::<M>()?; 2039 2040 let (index, tmp) = { 2041 let index_and_tmp = self.context.without::<Result<(TypedReg, _)>, M, _>( 2042 default_result.regs(), 2043 self.masm, 2044 |cx, masm| Ok((cx.pop_to_reg(masm, None)?, cx.any_gpr(masm)?)), 2045 )??; 2046 2047 // Materialize any constants or locals into their result representation, 2048 // so that when reachability is restored, they are correctly located. 2049 default_frame.top_abi_results::<M, _>( 2050 &mut self.context, 2051 self.masm, 2052 |results, _, _| Ok(results.ret_area().copied()), 2053 )?; 2054 index_and_tmp 2055 }; 2056 2057 self.masm.jmp_table(&labels, index.into(), tmp)?; 2058 // Save the original stack pointer offset; we will reset the stack 2059 // pointer to this offset after jumping to each of the targets. Each 2060 // jump might adjust the stack according to the base offset of the 2061 // target. 2062 let current_sp = self.masm.sp_offset()?; 2063 2064 for (t, l) in targets 2065 .targets() 2066 .into_iter() 2067 .chain(std::iter::once(Ok(targets.default()))) 2068 .zip(labels.iter()) 2069 { 2070 let control_index = control_index(t?, self.control_frames.len())?; 2071 let frame = &mut self.control_frames[control_index]; 2072 // Reset the stack pointer to its original offset. This is needed 2073 // because each jump will potentially adjust the stack pointer 2074 // according to the base offset of the target. 2075 self.masm.reset_stack_pointer(current_sp)?; 2076 2077 // NB: We don't perform any result handling as it was 2078 // already taken care of above before jumping to the 2079 // jump table. 2080 self.masm.bind(*l)?; 2081 // Ensure that the stack pointer is correctly positioned before 2082 // jumping to the jump table code. 2083 let state = frame.stack_state(); 2084 self.masm.ensure_sp_for_jump(state.target_offset)?; 2085 self.masm.jmp(*frame.label())?; 2086 frame.set_as_target(); 2087 } 2088 // Finally reset the stack pointer to the original location. 2089 // The reachability analysis, will ensure it's correctly located 2090 // once reachability is restored. 2091 self.masm.reset_stack_pointer(current_sp)?; 2092 self.context.reachable = false; 2093 self.context.free_reg(index.reg); 2094 self.context.free_reg(tmp); 2095 2096 Ok(()) 2097 } 2098 2099 fn visit_return(&mut self) -> Self::Output { 2100 // Grab the outermost frame, which is the function's body 2101 // frame. We don't rely on [`codegen::control_index`] since 2102 // this frame is implicit and we know that it should exist at 2103 // index 0. 2104 let outermost = &mut self.control_frames[0]; 2105 self.context 2106 .unconditional_jump(outermost, self.masm, |masm, cx, frame| { 2107 frame.pop_abi_results::<M, _>(cx, masm, |results, _, _| { 2108 Ok(results.ret_area().copied()) 2109 }) 2110 }) 2111 } 2112 2113 fn visit_unreachable(&mut self) -> Self::Output { 2114 self.masm.unreachable()?; 2115 self.context.reachable = false; 2116 // Set the implicit outermost frame as target to perform the necessary 2117 // stack clean up. 2118 let outermost = &mut self.control_frames[0]; 2119 outermost.set_as_target(); 2120 2121 Ok(()) 2122 } 2123 2124 fn visit_local_tee(&mut self, index: u32) -> Self::Output { 2125 let typed_reg = self.emit_set_local(index)?; 2126 self.context.stack.push(typed_reg.into()); 2127 2128 Ok(()) 2129 } 2130 2131 fn visit_global_get(&mut self, global_index: u32) -> Self::Output { 2132 let index = GlobalIndex::from_u32(global_index); 2133 let (ty, base, offset) = self.emit_get_global_addr(index)?; 2134 let addr = self.masm.address_at_reg(base, offset)?; 2135 let dst = self.context.reg_for_type(ty, self.masm)?; 2136 self.masm.load(addr, writable!(dst), ty.try_into()?)?; 2137 self.context.stack.push(Val::reg(dst, ty)); 2138 2139 self.context.free_reg(base); 2140 2141 Ok(()) 2142 } 2143 2144 fn visit_global_set(&mut self, global_index: u32) -> Self::Output { 2145 let index = GlobalIndex::from_u32(global_index); 2146 let (ty, base, offset) = self.emit_get_global_addr(index)?; 2147 let addr = self.masm.address_at_reg(base, offset)?; 2148 2149 let typed_reg = self.context.pop_to_reg(self.masm, None)?; 2150 self.masm 2151 .store(typed_reg.reg.into(), addr, ty.try_into()?)?; 2152 self.context.free_reg(typed_reg.reg); 2153 self.context.free_reg(base); 2154 2155 Ok(()) 2156 } 2157 2158 fn visit_drop(&mut self) -> Self::Output { 2159 self.context.drop_last(1, |regalloc, val| match val { 2160 Val::Reg(tr) => Ok(regalloc.free(tr.reg.into())), 2161 Val::Memory(m) => self.masm.free_stack(m.slot.size), 2162 _ => Ok(()), 2163 }) 2164 } 2165 2166 fn visit_select(&mut self) -> Self::Output { 2167 let cond = self.context.pop_to_reg(self.masm, None)?; 2168 let val2 = self.context.pop_to_reg(self.masm, None)?; 2169 let val1 = self.context.pop_to_reg(self.masm, None)?; 2170 self.masm 2171 .cmp(cond.reg.into(), RegImm::i32(0), OperandSize::S32)?; 2172 // Conditionally move val1 to val2 if the comparison is 2173 // not zero. 2174 self.masm.cmov( 2175 writable!(val2.into()), 2176 val1.into(), 2177 IntCmpKind::Ne, 2178 val1.ty.try_into()?, 2179 )?; 2180 self.context.stack.push(val2.into()); 2181 self.context.free_reg(val1.reg); 2182 self.context.free_reg(cond); 2183 2184 Ok(()) 2185 } 2186 2187 fn visit_i32_load(&mut self, memarg: MemArg) -> Self::Output { 2188 self.emit_wasm_load( 2189 &memarg, 2190 WasmValType::I32, 2191 LoadKind::Operand(OperandSize::S32), 2192 ) 2193 } 2194 2195 fn visit_i32_load8_s(&mut self, memarg: MemArg) -> Self::Output { 2196 self.emit_wasm_load( 2197 &memarg, 2198 WasmValType::I32, 2199 LoadKind::ScalarExtend(Extend::<Signed>::I32Extend8.into()), 2200 ) 2201 } 2202 2203 fn visit_i32_load8_u(&mut self, memarg: MemArg) -> Self::Output { 2204 self.emit_wasm_load( 2205 &memarg, 2206 WasmValType::I32, 2207 LoadKind::ScalarExtend(Extend::<Zero>::I32Extend8.into()), 2208 ) 2209 } 2210 2211 fn visit_i32_load16_s(&mut self, memarg: MemArg) -> Self::Output { 2212 self.emit_wasm_load( 2213 &memarg, 2214 WasmValType::I32, 2215 LoadKind::ScalarExtend(Extend::<Signed>::I32Extend16.into()), 2216 ) 2217 } 2218 2219 fn visit_i32_load16_u(&mut self, memarg: MemArg) -> Self::Output { 2220 self.emit_wasm_load( 2221 &memarg, 2222 WasmValType::I32, 2223 LoadKind::ScalarExtend(Extend::<Zero>::I32Extend16.into()), 2224 ) 2225 } 2226 2227 fn visit_i32_store(&mut self, memarg: MemArg) -> Self::Output { 2228 self.emit_wasm_store(&memarg, StoreKind::Operand(OperandSize::S32)) 2229 } 2230 2231 fn visit_i32_store8(&mut self, memarg: MemArg) -> Self::Output { 2232 self.emit_wasm_store(&memarg, StoreKind::Operand(OperandSize::S8)) 2233 } 2234 2235 fn visit_i32_store16(&mut self, memarg: MemArg) -> Self::Output { 2236 self.emit_wasm_store(&memarg, StoreKind::Operand(OperandSize::S16)) 2237 } 2238 2239 fn visit_i64_load8_s(&mut self, memarg: MemArg) -> Self::Output { 2240 self.emit_wasm_load( 2241 &memarg, 2242 WasmValType::I64, 2243 LoadKind::ScalarExtend(Extend::<Signed>::I64Extend8.into()), 2244 ) 2245 } 2246 2247 fn visit_i64_load8_u(&mut self, memarg: MemArg) -> Self::Output { 2248 self.emit_wasm_load( 2249 &memarg, 2250 WasmValType::I64, 2251 LoadKind::ScalarExtend(Extend::<Zero>::I64Extend8.into()), 2252 ) 2253 } 2254 2255 fn visit_i64_load16_u(&mut self, memarg: MemArg) -> Self::Output { 2256 self.emit_wasm_load( 2257 &memarg, 2258 WasmValType::I64, 2259 LoadKind::ScalarExtend(Extend::<Zero>::I64Extend16.into()), 2260 ) 2261 } 2262 2263 fn visit_i64_load16_s(&mut self, memarg: MemArg) -> Self::Output { 2264 self.emit_wasm_load( 2265 &memarg, 2266 WasmValType::I64, 2267 LoadKind::ScalarExtend(Extend::<Signed>::I64Extend16.into()), 2268 ) 2269 } 2270 2271 fn visit_i64_load32_u(&mut self, memarg: MemArg) -> Self::Output { 2272 self.emit_wasm_load( 2273 &memarg, 2274 WasmValType::I64, 2275 LoadKind::ScalarExtend(Extend::<Zero>::I64Extend32.into()), 2276 ) 2277 } 2278 2279 fn visit_i64_load32_s(&mut self, memarg: MemArg) -> Self::Output { 2280 self.emit_wasm_load( 2281 &memarg, 2282 WasmValType::I64, 2283 LoadKind::ScalarExtend(Extend::<Signed>::I64Extend32.into()), 2284 ) 2285 } 2286 2287 fn visit_i64_load(&mut self, memarg: MemArg) -> Self::Output { 2288 self.emit_wasm_load( 2289 &memarg, 2290 WasmValType::I64, 2291 LoadKind::Operand(OperandSize::S64), 2292 ) 2293 } 2294 2295 fn visit_i64_store(&mut self, memarg: MemArg) -> Self::Output { 2296 self.emit_wasm_store(&memarg, StoreKind::Operand(OperandSize::S64)) 2297 } 2298 2299 fn visit_i64_store8(&mut self, memarg: MemArg) -> Self::Output { 2300 self.emit_wasm_store(&memarg, StoreKind::Operand(OperandSize::S8)) 2301 } 2302 2303 fn visit_i64_store16(&mut self, memarg: MemArg) -> Self::Output { 2304 self.emit_wasm_store(&memarg, StoreKind::Operand(OperandSize::S16)) 2305 } 2306 2307 fn visit_i64_store32(&mut self, memarg: MemArg) -> Self::Output { 2308 self.emit_wasm_store(&memarg, StoreKind::Operand(OperandSize::S32)) 2309 } 2310 2311 fn visit_f32_load(&mut self, memarg: MemArg) -> Self::Output { 2312 self.emit_wasm_load( 2313 &memarg, 2314 WasmValType::F32, 2315 LoadKind::Operand(OperandSize::S32), 2316 ) 2317 } 2318 2319 fn visit_f32_store(&mut self, memarg: MemArg) -> Self::Output { 2320 self.emit_wasm_store(&memarg, StoreKind::Operand(OperandSize::S32)) 2321 } 2322 2323 fn visit_f64_load(&mut self, memarg: MemArg) -> Self::Output { 2324 self.emit_wasm_load( 2325 &memarg, 2326 WasmValType::F64, 2327 LoadKind::Operand(OperandSize::S64), 2328 ) 2329 } 2330 2331 fn visit_f64_store(&mut self, memarg: MemArg) -> Self::Output { 2332 self.emit_wasm_store(&memarg, StoreKind::Operand(OperandSize::S64)) 2333 } 2334 2335 fn visit_i32_trunc_sat_f32_s(&mut self) -> Self::Output { 2336 use OperandSize::*; 2337 2338 self.context 2339 .convert_op(self.masm, WasmValType::I32, |masm, dst, src, dst_size| { 2340 masm.signed_truncate(writable!(dst), src, S32, dst_size, TruncKind::Checked) 2341 }) 2342 } 2343 2344 fn visit_i32_trunc_sat_f32_u(&mut self) -> Self::Output { 2345 use OperandSize::*; 2346 2347 self.masm 2348 .unsigned_truncate(&mut self.context, S32, S32, TruncKind::Checked) 2349 } 2350 2351 fn visit_i32_trunc_sat_f64_s(&mut self) -> Self::Output { 2352 use OperandSize::*; 2353 2354 self.context 2355 .convert_op(self.masm, WasmValType::I32, |masm, dst, src, dst_size| { 2356 masm.signed_truncate(writable!(dst), src, S64, dst_size, TruncKind::Checked) 2357 }) 2358 } 2359 2360 fn visit_i32_trunc_sat_f64_u(&mut self) -> Self::Output { 2361 use OperandSize::*; 2362 2363 self.masm 2364 .unsigned_truncate(&mut self.context, S64, S32, TruncKind::Checked) 2365 } 2366 2367 fn visit_i64_trunc_sat_f32_s(&mut self) -> Self::Output { 2368 use OperandSize::*; 2369 2370 self.context 2371 .convert_op(self.masm, WasmValType::I64, |masm, dst, src, dst_size| { 2372 masm.signed_truncate(writable!(dst), src, S32, dst_size, TruncKind::Checked) 2373 }) 2374 } 2375 2376 fn visit_i64_trunc_sat_f32_u(&mut self) -> Self::Output { 2377 use OperandSize::*; 2378 2379 self.masm 2380 .unsigned_truncate(&mut self.context, S32, S64, TruncKind::Checked) 2381 } 2382 2383 fn visit_i64_trunc_sat_f64_s(&mut self) -> Self::Output { 2384 use OperandSize::*; 2385 2386 self.context 2387 .convert_op(self.masm, WasmValType::I64, |masm, dst, src, dst_size| { 2388 masm.signed_truncate(writable!(dst), src, S64, dst_size, TruncKind::Checked) 2389 }) 2390 } 2391 2392 fn visit_i64_trunc_sat_f64_u(&mut self) -> Self::Output { 2393 use OperandSize::*; 2394 2395 self.masm 2396 .unsigned_truncate(&mut self.context, S64, S64, TruncKind::Checked) 2397 } 2398 2399 fn visit_i64_add128(&mut self) -> Self::Output { 2400 self.context 2401 .binop128(self.masm, |masm, lhs_lo, lhs_hi, rhs_lo, rhs_hi| { 2402 masm.add128( 2403 writable!(lhs_lo), 2404 writable!(lhs_hi), 2405 lhs_lo, 2406 lhs_hi, 2407 rhs_lo, 2408 rhs_hi, 2409 )?; 2410 Ok((TypedReg::i64(lhs_lo), TypedReg::i64(lhs_hi))) 2411 }) 2412 } 2413 2414 fn visit_i64_sub128(&mut self) -> Self::Output { 2415 self.context 2416 .binop128(self.masm, |masm, lhs_lo, lhs_hi, rhs_lo, rhs_hi| { 2417 masm.sub128( 2418 writable!(lhs_lo), 2419 writable!(lhs_hi), 2420 lhs_lo, 2421 lhs_hi, 2422 rhs_lo, 2423 rhs_hi, 2424 )?; 2425 Ok((TypedReg::i64(lhs_lo), TypedReg::i64(lhs_hi))) 2426 }) 2427 } 2428 2429 fn visit_i64_mul_wide_s(&mut self) -> Self::Output { 2430 self.masm.mul_wide(&mut self.context, MulWideKind::Signed) 2431 } 2432 2433 fn visit_i64_mul_wide_u(&mut self) -> Self::Output { 2434 self.masm.mul_wide(&mut self.context, MulWideKind::Unsigned) 2435 } 2436 2437 fn visit_i32_atomic_load8_u(&mut self, memarg: MemArg) -> Self::Output { 2438 self.emit_wasm_load( 2439 &memarg, 2440 WasmValType::I32, 2441 LoadKind::Atomic(OperandSize::S8, Some(Extend::<Zero>::I32Extend8.into())), 2442 ) 2443 } 2444 2445 fn visit_i32_atomic_load16_u(&mut self, memarg: MemArg) -> Self::Output { 2446 self.emit_wasm_load( 2447 &memarg, 2448 WasmValType::I32, 2449 LoadKind::Atomic(OperandSize::S16, Some(Extend::<Zero>::I32Extend16.into())), 2450 ) 2451 } 2452 2453 fn visit_i32_atomic_load(&mut self, memarg: MemArg) -> Self::Output { 2454 self.emit_wasm_load( 2455 &memarg, 2456 WasmValType::I32, 2457 LoadKind::Atomic(OperandSize::S32, None), 2458 ) 2459 } 2460 2461 fn visit_i64_atomic_load8_u(&mut self, memarg: MemArg) -> Self::Output { 2462 self.emit_wasm_load( 2463 &memarg, 2464 WasmValType::I64, 2465 LoadKind::Atomic(OperandSize::S8, Some(Extend::<Zero>::I64Extend8.into())), 2466 ) 2467 } 2468 2469 fn visit_i64_atomic_load16_u(&mut self, memarg: MemArg) -> Self::Output { 2470 self.emit_wasm_load( 2471 &memarg, 2472 WasmValType::I64, 2473 LoadKind::Atomic(OperandSize::S16, Some(Extend::<Zero>::I64Extend16.into())), 2474 ) 2475 } 2476 2477 fn visit_i64_atomic_load32_u(&mut self, memarg: MemArg) -> Self::Output { 2478 self.emit_wasm_load( 2479 &memarg, 2480 WasmValType::I64, 2481 LoadKind::Atomic(OperandSize::S32, Some(Extend::<Zero>::I64Extend32.into())), 2482 ) 2483 } 2484 2485 fn visit_i64_atomic_load(&mut self, memarg: MemArg) -> Self::Output { 2486 self.emit_wasm_load( 2487 &memarg, 2488 WasmValType::I64, 2489 LoadKind::Atomic(OperandSize::S64, None), 2490 ) 2491 } 2492 2493 fn visit_i32_atomic_store(&mut self, memarg: MemArg) -> Self::Output { 2494 self.emit_wasm_store(&memarg, StoreKind::Atomic(OperandSize::S32)) 2495 } 2496 2497 fn visit_i64_atomic_store(&mut self, memarg: MemArg) -> Self::Output { 2498 self.emit_wasm_store(&memarg, StoreKind::Atomic(OperandSize::S64)) 2499 } 2500 2501 fn visit_i32_atomic_store8(&mut self, memarg: MemArg) -> Self::Output { 2502 self.emit_wasm_store(&memarg, StoreKind::Atomic(OperandSize::S8)) 2503 } 2504 2505 fn visit_i32_atomic_store16(&mut self, memarg: MemArg) -> Self::Output { 2506 self.emit_wasm_store(&memarg, StoreKind::Atomic(OperandSize::S16)) 2507 } 2508 2509 fn visit_i64_atomic_store8(&mut self, memarg: MemArg) -> Self::Output { 2510 self.emit_wasm_store(&memarg, StoreKind::Atomic(OperandSize::S8)) 2511 } 2512 2513 fn visit_i64_atomic_store16(&mut self, memarg: MemArg) -> Self::Output { 2514 self.emit_wasm_store(&memarg, StoreKind::Atomic(OperandSize::S16)) 2515 } 2516 2517 fn visit_i64_atomic_store32(&mut self, memarg: MemArg) -> Self::Output { 2518 self.emit_wasm_store(&memarg, StoreKind::Atomic(OperandSize::S32)) 2519 } 2520 2521 fn visit_i32_atomic_rmw8_add_u(&mut self, arg: MemArg) -> Self::Output { 2522 self.emit_atomic_rmw( 2523 &arg, 2524 RmwOp::Add, 2525 OperandSize::S8, 2526 Some(Extend::<Zero>::I32Extend8), 2527 ) 2528 } 2529 2530 fn visit_i32_atomic_rmw16_add_u(&mut self, arg: MemArg) -> Self::Output { 2531 self.emit_atomic_rmw( 2532 &arg, 2533 RmwOp::Add, 2534 OperandSize::S16, 2535 Some(Extend::<Zero>::I32Extend16), 2536 ) 2537 } 2538 2539 fn visit_i32_atomic_rmw_add(&mut self, arg: MemArg) -> Self::Output { 2540 self.emit_atomic_rmw(&arg, RmwOp::Add, OperandSize::S32, None) 2541 } 2542 2543 fn visit_i64_atomic_rmw8_add_u(&mut self, arg: MemArg) -> Self::Output { 2544 self.emit_atomic_rmw( 2545 &arg, 2546 RmwOp::Add, 2547 OperandSize::S8, 2548 Some(Extend::<Zero>::I64Extend8), 2549 ) 2550 } 2551 2552 fn visit_i64_atomic_rmw16_add_u(&mut self, arg: MemArg) -> Self::Output { 2553 self.emit_atomic_rmw( 2554 &arg, 2555 RmwOp::Add, 2556 OperandSize::S16, 2557 Some(Extend::<Zero>::I64Extend16), 2558 ) 2559 } 2560 2561 fn visit_i64_atomic_rmw32_add_u(&mut self, arg: MemArg) -> Self::Output { 2562 self.emit_atomic_rmw( 2563 &arg, 2564 RmwOp::Add, 2565 OperandSize::S32, 2566 Some(Extend::<Zero>::I64Extend32), 2567 ) 2568 } 2569 2570 fn visit_i64_atomic_rmw_add(&mut self, arg: MemArg) -> Self::Output { 2571 self.emit_atomic_rmw(&arg, RmwOp::Add, OperandSize::S64, None) 2572 } 2573 2574 fn visit_i32_atomic_rmw8_sub_u(&mut self, arg: MemArg) -> Self::Output { 2575 self.emit_atomic_rmw( 2576 &arg, 2577 RmwOp::Sub, 2578 OperandSize::S8, 2579 Some(Extend::<Zero>::I32Extend8), 2580 ) 2581 } 2582 fn visit_i32_atomic_rmw16_sub_u(&mut self, arg: MemArg) -> Self::Output { 2583 self.emit_atomic_rmw( 2584 &arg, 2585 RmwOp::Sub, 2586 OperandSize::S16, 2587 Some(Extend::<Zero>::I32Extend16), 2588 ) 2589 } 2590 2591 fn visit_i32_atomic_rmw_sub(&mut self, arg: MemArg) -> Self::Output { 2592 self.emit_atomic_rmw(&arg, RmwOp::Sub, OperandSize::S32, None) 2593 } 2594 2595 fn visit_i64_atomic_rmw8_sub_u(&mut self, arg: MemArg) -> Self::Output { 2596 self.emit_atomic_rmw( 2597 &arg, 2598 RmwOp::Sub, 2599 OperandSize::S8, 2600 Some(Extend::<Zero>::I64Extend8), 2601 ) 2602 } 2603 2604 fn visit_i64_atomic_rmw16_sub_u(&mut self, arg: MemArg) -> Self::Output { 2605 self.emit_atomic_rmw( 2606 &arg, 2607 RmwOp::Sub, 2608 OperandSize::S16, 2609 Some(Extend::<Zero>::I64Extend16), 2610 ) 2611 } 2612 2613 fn visit_i64_atomic_rmw32_sub_u(&mut self, arg: MemArg) -> Self::Output { 2614 self.emit_atomic_rmw( 2615 &arg, 2616 RmwOp::Sub, 2617 OperandSize::S32, 2618 Some(Extend::<Zero>::I64Extend32), 2619 ) 2620 } 2621 2622 fn visit_i64_atomic_rmw_sub(&mut self, arg: MemArg) -> Self::Output { 2623 self.emit_atomic_rmw(&arg, RmwOp::Sub, OperandSize::S64, None) 2624 } 2625 2626 fn visit_i32_atomic_rmw8_xchg_u(&mut self, arg: MemArg) -> Self::Output { 2627 self.emit_atomic_rmw( 2628 &arg, 2629 RmwOp::Xchg, 2630 OperandSize::S8, 2631 Some(Extend::<Zero>::I32Extend8), 2632 ) 2633 } 2634 2635 fn visit_i32_atomic_rmw16_xchg_u(&mut self, arg: MemArg) -> Self::Output { 2636 self.emit_atomic_rmw( 2637 &arg, 2638 RmwOp::Xchg, 2639 OperandSize::S16, 2640 Some(Extend::<Zero>::I32Extend16), 2641 ) 2642 } 2643 2644 fn visit_i32_atomic_rmw_xchg(&mut self, arg: MemArg) -> Self::Output { 2645 self.emit_atomic_rmw(&arg, RmwOp::Xchg, OperandSize::S32, None) 2646 } 2647 2648 fn visit_i64_atomic_rmw8_xchg_u(&mut self, arg: MemArg) -> Self::Output { 2649 self.emit_atomic_rmw( 2650 &arg, 2651 RmwOp::Xchg, 2652 OperandSize::S8, 2653 Some(Extend::<Zero>::I64Extend8), 2654 ) 2655 } 2656 2657 fn visit_i64_atomic_rmw16_xchg_u(&mut self, arg: MemArg) -> Self::Output { 2658 self.emit_atomic_rmw( 2659 &arg, 2660 RmwOp::Xchg, 2661 OperandSize::S16, 2662 Some(Extend::<Zero>::I64Extend16), 2663 ) 2664 } 2665 2666 fn visit_i64_atomic_rmw32_xchg_u(&mut self, arg: MemArg) -> Self::Output { 2667 self.emit_atomic_rmw( 2668 &arg, 2669 RmwOp::Xchg, 2670 OperandSize::S32, 2671 Some(Extend::<Zero>::I64Extend32), 2672 ) 2673 } 2674 2675 fn visit_i64_atomic_rmw_xchg(&mut self, arg: MemArg) -> Self::Output { 2676 self.emit_atomic_rmw(&arg, RmwOp::Xchg, OperandSize::S64, None) 2677 } 2678 2679 fn visit_i32_atomic_rmw8_and_u(&mut self, arg: MemArg) -> Self::Output { 2680 self.emit_atomic_rmw( 2681 &arg, 2682 RmwOp::And, 2683 OperandSize::S8, 2684 Some(Extend::<Zero>::I32Extend8), 2685 ) 2686 } 2687 2688 fn visit_i32_atomic_rmw16_and_u(&mut self, arg: MemArg) -> Self::Output { 2689 self.emit_atomic_rmw( 2690 &arg, 2691 RmwOp::And, 2692 OperandSize::S16, 2693 Some(Extend::<Zero>::I32Extend16), 2694 ) 2695 } 2696 2697 fn visit_i32_atomic_rmw_and(&mut self, arg: MemArg) -> Self::Output { 2698 self.emit_atomic_rmw(&arg, RmwOp::And, OperandSize::S32, None) 2699 } 2700 2701 fn visit_i64_atomic_rmw8_and_u(&mut self, arg: MemArg) -> Self::Output { 2702 self.emit_atomic_rmw( 2703 &arg, 2704 RmwOp::And, 2705 OperandSize::S8, 2706 Some(Extend::<Zero>::I64Extend8), 2707 ) 2708 } 2709 2710 fn visit_i64_atomic_rmw16_and_u(&mut self, arg: MemArg) -> Self::Output { 2711 self.emit_atomic_rmw( 2712 &arg, 2713 RmwOp::And, 2714 OperandSize::S16, 2715 Some(Extend::<Zero>::I64Extend16), 2716 ) 2717 } 2718 2719 fn visit_i64_atomic_rmw32_and_u(&mut self, arg: MemArg) -> Self::Output { 2720 self.emit_atomic_rmw( 2721 &arg, 2722 RmwOp::And, 2723 OperandSize::S32, 2724 Some(Extend::<Zero>::I64Extend32), 2725 ) 2726 } 2727 2728 fn visit_i64_atomic_rmw_and(&mut self, arg: MemArg) -> Self::Output { 2729 self.emit_atomic_rmw(&arg, RmwOp::And, OperandSize::S64, None) 2730 } 2731 2732 fn visit_i32_atomic_rmw8_or_u(&mut self, arg: MemArg) -> Self::Output { 2733 self.emit_atomic_rmw( 2734 &arg, 2735 RmwOp::Or, 2736 OperandSize::S8, 2737 Some(Extend::<Zero>::I32Extend8), 2738 ) 2739 } 2740 2741 fn visit_i32_atomic_rmw16_or_u(&mut self, arg: MemArg) -> Self::Output { 2742 self.emit_atomic_rmw( 2743 &arg, 2744 RmwOp::Or, 2745 OperandSize::S16, 2746 Some(Extend::<Zero>::I32Extend16), 2747 ) 2748 } 2749 2750 fn visit_i32_atomic_rmw_or(&mut self, arg: MemArg) -> Self::Output { 2751 self.emit_atomic_rmw(&arg, RmwOp::Or, OperandSize::S32, None) 2752 } 2753 2754 fn visit_i64_atomic_rmw8_or_u(&mut self, arg: MemArg) -> Self::Output { 2755 self.emit_atomic_rmw( 2756 &arg, 2757 RmwOp::Or, 2758 OperandSize::S8, 2759 Some(Extend::<Zero>::I64Extend8), 2760 ) 2761 } 2762 2763 fn visit_i64_atomic_rmw16_or_u(&mut self, arg: MemArg) -> Self::Output { 2764 self.emit_atomic_rmw( 2765 &arg, 2766 RmwOp::Or, 2767 OperandSize::S16, 2768 Some(Extend::<Zero>::I64Extend16), 2769 ) 2770 } 2771 2772 fn visit_i64_atomic_rmw32_or_u(&mut self, arg: MemArg) -> Self::Output { 2773 self.emit_atomic_rmw( 2774 &arg, 2775 RmwOp::Or, 2776 OperandSize::S32, 2777 Some(Extend::<Zero>::I64Extend32), 2778 ) 2779 } 2780 2781 fn visit_i64_atomic_rmw_or(&mut self, arg: MemArg) -> Self::Output { 2782 self.emit_atomic_rmw(&arg, RmwOp::Or, OperandSize::S64, None) 2783 } 2784 2785 fn visit_i32_atomic_rmw8_xor_u(&mut self, arg: MemArg) -> Self::Output { 2786 self.emit_atomic_rmw( 2787 &arg, 2788 RmwOp::Xor, 2789 OperandSize::S8, 2790 Some(Extend::<Zero>::I32Extend8), 2791 ) 2792 } 2793 2794 fn visit_i32_atomic_rmw16_xor_u(&mut self, arg: MemArg) -> Self::Output { 2795 self.emit_atomic_rmw( 2796 &arg, 2797 RmwOp::Xor, 2798 OperandSize::S16, 2799 Some(Extend::<Zero>::I32Extend16), 2800 ) 2801 } 2802 2803 fn visit_i32_atomic_rmw_xor(&mut self, arg: MemArg) -> Self::Output { 2804 self.emit_atomic_rmw(&arg, RmwOp::Xor, OperandSize::S32, None) 2805 } 2806 2807 fn visit_i64_atomic_rmw8_xor_u(&mut self, arg: MemArg) -> Self::Output { 2808 self.emit_atomic_rmw( 2809 &arg, 2810 RmwOp::Xor, 2811 OperandSize::S8, 2812 Some(Extend::<Zero>::I64Extend8), 2813 ) 2814 } 2815 2816 fn visit_i64_atomic_rmw16_xor_u(&mut self, arg: MemArg) -> Self::Output { 2817 self.emit_atomic_rmw( 2818 &arg, 2819 RmwOp::Xor, 2820 OperandSize::S16, 2821 Some(Extend::<Zero>::I64Extend16), 2822 ) 2823 } 2824 2825 fn visit_i64_atomic_rmw32_xor_u(&mut self, arg: MemArg) -> Self::Output { 2826 self.emit_atomic_rmw( 2827 &arg, 2828 RmwOp::Xor, 2829 OperandSize::S32, 2830 Some(Extend::<Zero>::I64Extend32), 2831 ) 2832 } 2833 2834 fn visit_i64_atomic_rmw_xor(&mut self, arg: MemArg) -> Self::Output { 2835 self.emit_atomic_rmw(&arg, RmwOp::Xor, OperandSize::S64, None) 2836 } 2837 2838 fn visit_i32_atomic_rmw8_cmpxchg_u(&mut self, arg: MemArg) -> Self::Output { 2839 self.emit_atomic_cmpxchg(&arg, OperandSize::S8, Some(Extend::I32Extend8)) 2840 } 2841 2842 fn visit_i32_atomic_rmw16_cmpxchg_u(&mut self, arg: MemArg) -> Self::Output { 2843 self.emit_atomic_cmpxchg(&arg, OperandSize::S16, Some(Extend::I32Extend16)) 2844 } 2845 2846 fn visit_i32_atomic_rmw_cmpxchg(&mut self, arg: MemArg) -> Self::Output { 2847 self.emit_atomic_cmpxchg(&arg, OperandSize::S32, None) 2848 } 2849 2850 fn visit_i64_atomic_rmw8_cmpxchg_u(&mut self, arg: MemArg) -> Self::Output { 2851 self.emit_atomic_cmpxchg(&arg, OperandSize::S8, Some(Extend::I64Extend8)) 2852 } 2853 2854 fn visit_i64_atomic_rmw16_cmpxchg_u(&mut self, arg: MemArg) -> Self::Output { 2855 self.emit_atomic_cmpxchg(&arg, OperandSize::S16, Some(Extend::I64Extend16)) 2856 } 2857 2858 fn visit_i64_atomic_rmw32_cmpxchg_u(&mut self, arg: MemArg) -> Self::Output { 2859 self.emit_atomic_cmpxchg(&arg, OperandSize::S32, Some(Extend::I64Extend32)) 2860 } 2861 2862 fn visit_i64_atomic_rmw_cmpxchg(&mut self, arg: MemArg) -> Self::Output { 2863 self.emit_atomic_cmpxchg(&arg, OperandSize::S64, None) 2864 } 2865 2866 fn visit_memory_atomic_wait32(&mut self, arg: MemArg) -> Self::Output { 2867 self.emit_atomic_wait(&arg, AtomicWaitKind::Wait32) 2868 } 2869 2870 fn visit_memory_atomic_wait64(&mut self, arg: MemArg) -> Self::Output { 2871 self.emit_atomic_wait(&arg, AtomicWaitKind::Wait64) 2872 } 2873 2874 fn visit_memory_atomic_notify(&mut self, arg: MemArg) -> Self::Output { 2875 self.emit_atomic_notify(&arg) 2876 } 2877 2878 fn visit_atomic_fence(&mut self) -> Self::Output { 2879 self.masm.fence() 2880 } 2881 2882 wasmparser::for_each_visit_operator!(def_unsupported); 2883 } 2884 2885 impl<'a, 'translation, 'data, M> VisitSimdOperator<'a> 2886 for CodeGen<'a, 'translation, 'data, M, Emission> 2887 where 2888 M: MacroAssembler, 2889 { 2890 fn visit_v128_const(&mut self, val: V128) -> Self::Output { 2891 self.context.stack.push(Val::v128(val.i128())); 2892 Ok(()) 2893 } 2894 2895 fn visit_v128_load(&mut self, memarg: MemArg) -> Self::Output { 2896 self.emit_wasm_load( 2897 &memarg, 2898 WasmValType::V128, 2899 LoadKind::Operand(OperandSize::S128), 2900 ) 2901 } 2902 2903 fn visit_v128_store(&mut self, memarg: MemArg) -> Self::Output { 2904 self.emit_wasm_store(&memarg, StoreKind::Operand(OperandSize::S128)) 2905 } 2906 2907 fn visit_v128_load8x8_s(&mut self, memarg: MemArg) -> Self::Output { 2908 self.emit_wasm_load( 2909 &memarg, 2910 WasmValType::V128, 2911 LoadKind::VectorExtend(V128LoadExtendKind::E8x8S), 2912 ) 2913 } 2914 2915 fn visit_v128_load8x8_u(&mut self, memarg: MemArg) -> Self::Output { 2916 self.emit_wasm_load( 2917 &memarg, 2918 WasmValType::V128, 2919 LoadKind::VectorExtend(V128LoadExtendKind::E8x8U), 2920 ) 2921 } 2922 2923 fn visit_v128_load16x4_s(&mut self, memarg: MemArg) -> Self::Output { 2924 self.emit_wasm_load( 2925 &memarg, 2926 WasmValType::V128, 2927 LoadKind::VectorExtend(V128LoadExtendKind::E16x4S), 2928 ) 2929 } 2930 2931 fn visit_v128_load16x4_u(&mut self, memarg: MemArg) -> Self::Output { 2932 self.emit_wasm_load( 2933 &memarg, 2934 WasmValType::V128, 2935 LoadKind::VectorExtend(V128LoadExtendKind::E16x4U), 2936 ) 2937 } 2938 2939 fn visit_v128_load32x2_s(&mut self, memarg: MemArg) -> Self::Output { 2940 self.emit_wasm_load( 2941 &memarg, 2942 WasmValType::V128, 2943 LoadKind::VectorExtend(V128LoadExtendKind::E32x2S), 2944 ) 2945 } 2946 2947 fn visit_v128_load32x2_u(&mut self, memarg: MemArg) -> Self::Output { 2948 self.emit_wasm_load( 2949 &memarg, 2950 WasmValType::V128, 2951 LoadKind::VectorExtend(V128LoadExtendKind::E32x2U), 2952 ) 2953 } 2954 2955 fn visit_v128_load8_splat(&mut self, memarg: MemArg) -> Self::Output { 2956 self.emit_wasm_load( 2957 &memarg, 2958 WasmValType::V128, 2959 LoadKind::Splat(SplatLoadKind::S8), 2960 ) 2961 } 2962 2963 fn visit_v128_load16_splat(&mut self, memarg: MemArg) -> Self::Output { 2964 self.emit_wasm_load( 2965 &memarg, 2966 WasmValType::V128, 2967 LoadKind::Splat(SplatLoadKind::S16), 2968 ) 2969 } 2970 2971 fn visit_v128_load32_splat(&mut self, memarg: MemArg) -> Self::Output { 2972 self.emit_wasm_load( 2973 &memarg, 2974 WasmValType::V128, 2975 LoadKind::Splat(SplatLoadKind::S32), 2976 ) 2977 } 2978 2979 fn visit_v128_load64_splat(&mut self, memarg: MemArg) -> Self::Output { 2980 self.emit_wasm_load( 2981 &memarg, 2982 WasmValType::V128, 2983 LoadKind::Splat(SplatLoadKind::S64), 2984 ) 2985 } 2986 2987 fn visit_i8x16_splat(&mut self) -> Self::Output { 2988 self.masm.splat(&mut self.context, SplatKind::I8x16) 2989 } 2990 2991 fn visit_i16x8_splat(&mut self) -> Self::Output { 2992 self.masm.splat(&mut self.context, SplatKind::I16x8) 2993 } 2994 2995 fn visit_i32x4_splat(&mut self) -> Self::Output { 2996 self.masm.splat(&mut self.context, SplatKind::I32x4) 2997 } 2998 2999 fn visit_i64x2_splat(&mut self) -> Self::Output { 3000 self.masm.splat(&mut self.context, SplatKind::I64x2) 3001 } 3002 3003 fn visit_f32x4_splat(&mut self) -> Self::Output { 3004 self.masm.splat(&mut self.context, SplatKind::F32x4) 3005 } 3006 3007 fn visit_f64x2_splat(&mut self) -> Self::Output { 3008 self.masm.splat(&mut self.context, SplatKind::F64x2) 3009 } 3010 3011 fn visit_i8x16_shuffle(&mut self, lanes: [u8; 16]) -> Self::Output { 3012 let rhs = self.context.pop_to_reg(self.masm, None)?; 3013 let lhs = self.context.pop_to_reg(self.masm, None)?; 3014 self.masm 3015 .shuffle(writable!(lhs.into()), lhs.into(), rhs.into(), lanes)?; 3016 self.context.stack.push(TypedReg::v128(lhs.into()).into()); 3017 self.context.free_reg(rhs); 3018 Ok(()) 3019 } 3020 3021 fn visit_i8x16_swizzle(&mut self) -> Self::Output { 3022 let rhs = self.context.pop_to_reg(self.masm, None)?; 3023 let lhs = self.context.pop_to_reg(self.masm, None)?; 3024 self.masm 3025 .swizzle(writable!(lhs.into()), lhs.into(), rhs.into())?; 3026 self.context.stack.push(TypedReg::v128(lhs.into()).into()); 3027 self.context.free_reg(rhs); 3028 Ok(()) 3029 } 3030 3031 fn visit_i8x16_extract_lane_s(&mut self, lane: u8) -> Self::Output { 3032 self.context.extract_lane_op( 3033 self.masm, 3034 ExtractLaneKind::I8x16S, 3035 |masm, src, dst, kind| masm.extract_lane(src, dst, lane, kind), 3036 ) 3037 } 3038 3039 fn visit_i8x16_extract_lane_u(&mut self, lane: u8) -> Self::Output { 3040 self.context.extract_lane_op( 3041 self.masm, 3042 ExtractLaneKind::I8x16U, 3043 |masm, src, dst, kind| masm.extract_lane(src, dst, lane, kind), 3044 ) 3045 } 3046 3047 fn visit_i16x8_extract_lane_s(&mut self, lane: u8) -> Self::Output { 3048 self.context.extract_lane_op( 3049 self.masm, 3050 ExtractLaneKind::I16x8S, 3051 |masm, src, dst, kind| masm.extract_lane(src, dst, lane, kind), 3052 ) 3053 } 3054 3055 fn visit_i16x8_extract_lane_u(&mut self, lane: u8) -> Self::Output { 3056 self.context.extract_lane_op( 3057 self.masm, 3058 ExtractLaneKind::I16x8U, 3059 |masm, src, dst, kind| masm.extract_lane(src, dst, lane, kind), 3060 ) 3061 } 3062 3063 fn visit_i32x4_extract_lane(&mut self, lane: u8) -> Self::Output { 3064 self.context 3065 .extract_lane_op(self.masm, ExtractLaneKind::I32x4, |masm, src, dst, kind| { 3066 masm.extract_lane(src, dst, lane, kind) 3067 }) 3068 } 3069 3070 fn visit_i64x2_extract_lane(&mut self, lane: u8) -> Self::Output { 3071 self.context 3072 .extract_lane_op(self.masm, ExtractLaneKind::I64x2, |masm, src, dst, kind| { 3073 masm.extract_lane(src, dst, lane, kind) 3074 }) 3075 } 3076 3077 fn visit_f32x4_extract_lane(&mut self, lane: u8) -> Self::Output { 3078 self.context 3079 .extract_lane_op(self.masm, ExtractLaneKind::F32x4, |masm, src, dst, kind| { 3080 masm.extract_lane(src, dst, lane, kind) 3081 }) 3082 } 3083 3084 fn visit_f64x2_extract_lane(&mut self, lane: u8) -> Self::Output { 3085 self.context 3086 .extract_lane_op(self.masm, ExtractLaneKind::F64x2, |masm, src, dst, kind| { 3087 masm.extract_lane(src, dst, lane, kind) 3088 }) 3089 } 3090 3091 fn visit_i8x16_eq(&mut self) -> Self::Output { 3092 self.context 3093 .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| { 3094 masm.v128_eq(writable!(dst), dst, src, VectorEqualityKind::I8x16)?; 3095 Ok(TypedReg::v128(dst)) 3096 }) 3097 } 3098 3099 fn visit_i16x8_eq(&mut self) -> Self::Output { 3100 self.context 3101 .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| { 3102 masm.v128_eq(writable!(dst), dst, src, VectorEqualityKind::I16x8)?; 3103 Ok(TypedReg::v128(dst)) 3104 }) 3105 } 3106 3107 fn visit_i32x4_eq(&mut self) -> Self::Output { 3108 self.context 3109 .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| { 3110 masm.v128_eq(writable!(dst), dst, src, VectorEqualityKind::I32x4)?; 3111 Ok(TypedReg::v128(dst)) 3112 }) 3113 } 3114 3115 fn visit_i64x2_eq(&mut self) -> Self::Output { 3116 self.context 3117 .binop(self.masm, OperandSize::S64, |masm, dst, src, _size| { 3118 masm.v128_eq(writable!(dst), dst, src, VectorEqualityKind::I64x2)?; 3119 Ok(TypedReg::v128(dst)) 3120 }) 3121 } 3122 3123 fn visit_f32x4_eq(&mut self) -> Self::Output { 3124 self.context 3125 .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| { 3126 masm.v128_eq(writable!(dst), dst, src, VectorEqualityKind::F32x4)?; 3127 Ok(TypedReg::v128(dst)) 3128 }) 3129 } 3130 3131 fn visit_f64x2_eq(&mut self) -> Self::Output { 3132 self.context 3133 .binop(self.masm, OperandSize::S64, |masm, dst, src, _size| { 3134 masm.v128_eq(writable!(dst), dst, src, VectorEqualityKind::F64x2)?; 3135 Ok(TypedReg::v128(dst)) 3136 }) 3137 } 3138 3139 fn visit_i8x16_ne(&mut self) -> Self::Output { 3140 self.context 3141 .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| { 3142 masm.v128_ne(writable!(dst), dst, src, VectorEqualityKind::I8x16)?; 3143 Ok(TypedReg::v128(dst)) 3144 }) 3145 } 3146 3147 fn visit_i16x8_ne(&mut self) -> Self::Output { 3148 self.context 3149 .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| { 3150 masm.v128_ne(writable!(dst), dst, src, VectorEqualityKind::I16x8)?; 3151 Ok(TypedReg::v128(dst)) 3152 }) 3153 } 3154 3155 fn visit_i32x4_ne(&mut self) -> Self::Output { 3156 self.context 3157 .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| { 3158 masm.v128_ne(writable!(dst), dst, src, VectorEqualityKind::I32x4)?; 3159 Ok(TypedReg::v128(dst)) 3160 }) 3161 } 3162 3163 fn visit_i64x2_ne(&mut self) -> Self::Output { 3164 self.context 3165 .binop(self.masm, OperandSize::S64, |masm, dst, src, _size| { 3166 masm.v128_ne(writable!(dst), dst, src, VectorEqualityKind::I64x2)?; 3167 Ok(TypedReg::v128(dst)) 3168 }) 3169 } 3170 3171 fn visit_f32x4_ne(&mut self) -> Self::Output { 3172 self.context 3173 .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| { 3174 masm.v128_ne(writable!(dst), dst, src, VectorEqualityKind::F32x4)?; 3175 Ok(TypedReg::v128(dst)) 3176 }) 3177 } 3178 3179 fn visit_f64x2_ne(&mut self) -> Self::Output { 3180 self.context 3181 .binop(self.masm, OperandSize::S64, |masm, dst, src, _size| { 3182 masm.v128_ne(writable!(dst), dst, src, VectorEqualityKind::F64x2)?; 3183 Ok(TypedReg::v128(dst)) 3184 }) 3185 } 3186 3187 fn visit_i8x16_lt_s(&mut self) -> Self::Output { 3188 self.context 3189 .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| { 3190 masm.v128_lt(writable!(dst), dst, src, VectorCompareKind::I8x16S)?; 3191 Ok(TypedReg::v128(dst)) 3192 }) 3193 } 3194 3195 fn visit_i8x16_lt_u(&mut self) -> Self::Output { 3196 self.context 3197 .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| { 3198 masm.v128_lt(writable!(dst), dst, src, VectorCompareKind::I8x16U)?; 3199 Ok(TypedReg::v128(dst)) 3200 }) 3201 } 3202 3203 fn visit_i16x8_lt_s(&mut self) -> Self::Output { 3204 self.context 3205 .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| { 3206 masm.v128_lt(writable!(dst), dst, src, VectorCompareKind::I16x8S)?; 3207 Ok(TypedReg::v128(dst)) 3208 }) 3209 } 3210 3211 fn visit_i16x8_lt_u(&mut self) -> Self::Output { 3212 self.context 3213 .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| { 3214 masm.v128_lt(writable!(dst), dst, src, VectorCompareKind::I16x8U)?; 3215 Ok(TypedReg::v128(dst)) 3216 }) 3217 } 3218 3219 fn visit_i32x4_lt_s(&mut self) -> Self::Output { 3220 self.context 3221 .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| { 3222 masm.v128_lt(writable!(dst), dst, src, VectorCompareKind::I32x4S)?; 3223 Ok(TypedReg::v128(dst)) 3224 }) 3225 } 3226 3227 fn visit_i32x4_lt_u(&mut self) -> Self::Output { 3228 self.context 3229 .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| { 3230 masm.v128_lt(writable!(dst), dst, src, VectorCompareKind::I32x4U)?; 3231 Ok(TypedReg::v128(dst)) 3232 }) 3233 } 3234 3235 fn visit_i64x2_lt_s(&mut self) -> Self::Output { 3236 self.context 3237 .binop(self.masm, OperandSize::S64, |masm, dst, src, _size| { 3238 masm.v128_lt(writable!(dst), dst, src, VectorCompareKind::I64x2S)?; 3239 Ok(TypedReg::v128(dst)) 3240 }) 3241 } 3242 3243 fn visit_f32x4_lt(&mut self) -> Self::Output { 3244 self.context 3245 .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| { 3246 masm.v128_lt(writable!(dst), dst, src, VectorCompareKind::F32x4)?; 3247 Ok(TypedReg::v128(dst)) 3248 }) 3249 } 3250 3251 fn visit_f64x2_lt(&mut self) -> Self::Output { 3252 self.context 3253 .binop(self.masm, OperandSize::S64, |masm, dst, src, _size| { 3254 masm.v128_lt(writable!(dst), dst, src, VectorCompareKind::F64x2)?; 3255 Ok(TypedReg::v128(dst)) 3256 }) 3257 } 3258 3259 fn visit_i8x16_le_s(&mut self) -> Self::Output { 3260 self.context 3261 .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| { 3262 masm.v128_le(writable!(dst), dst, src, VectorCompareKind::I8x16S)?; 3263 Ok(TypedReg::v128(dst)) 3264 }) 3265 } 3266 3267 fn visit_i8x16_le_u(&mut self) -> Self::Output { 3268 self.context 3269 .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| { 3270 masm.v128_le(writable!(dst), dst, src, VectorCompareKind::I8x16U)?; 3271 Ok(TypedReg::v128(dst)) 3272 }) 3273 } 3274 3275 fn visit_i16x8_le_s(&mut self) -> Self::Output { 3276 self.context 3277 .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| { 3278 masm.v128_le(writable!(dst), dst, src, VectorCompareKind::I16x8S)?; 3279 Ok(TypedReg::v128(dst)) 3280 }) 3281 } 3282 3283 fn visit_i16x8_le_u(&mut self) -> Self::Output { 3284 self.context 3285 .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| { 3286 masm.v128_le(writable!(dst), dst, src, VectorCompareKind::I16x8U)?; 3287 Ok(TypedReg::v128(dst)) 3288 }) 3289 } 3290 3291 fn visit_i32x4_le_s(&mut self) -> Self::Output { 3292 self.context 3293 .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| { 3294 masm.v128_le(writable!(dst), dst, src, VectorCompareKind::I32x4S)?; 3295 Ok(TypedReg::v128(dst)) 3296 }) 3297 } 3298 3299 fn visit_i32x4_le_u(&mut self) -> Self::Output { 3300 self.context 3301 .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| { 3302 masm.v128_le(writable!(dst), dst, src, VectorCompareKind::I32x4U)?; 3303 Ok(TypedReg::v128(dst)) 3304 }) 3305 } 3306 3307 fn visit_i64x2_le_s(&mut self) -> Self::Output { 3308 self.context 3309 .binop(self.masm, OperandSize::S64, |masm, dst, src, _size| { 3310 masm.v128_le(writable!(dst), dst, src, VectorCompareKind::I64x2S)?; 3311 Ok(TypedReg::v128(dst)) 3312 }) 3313 } 3314 3315 fn visit_f32x4_le(&mut self) -> Self::Output { 3316 self.context 3317 .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| { 3318 masm.v128_le(writable!(dst), dst, src, VectorCompareKind::F32x4)?; 3319 Ok(TypedReg::v128(dst)) 3320 }) 3321 } 3322 3323 fn visit_f64x2_le(&mut self) -> Self::Output { 3324 self.context 3325 .binop(self.masm, OperandSize::S64, |masm, dst, src, _size| { 3326 masm.v128_le(writable!(dst), dst, src, VectorCompareKind::F64x2)?; 3327 Ok(TypedReg::v128(dst)) 3328 }) 3329 } 3330 3331 fn visit_i8x16_gt_s(&mut self) -> Self::Output { 3332 self.context 3333 .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| { 3334 masm.v128_gt(writable!(dst), dst, src, VectorCompareKind::I8x16S)?; 3335 Ok(TypedReg::v128(dst)) 3336 }) 3337 } 3338 3339 fn visit_i8x16_gt_u(&mut self) -> Self::Output { 3340 self.context 3341 .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| { 3342 masm.v128_gt(writable!(dst), dst, src, VectorCompareKind::I8x16U)?; 3343 Ok(TypedReg::v128(dst)) 3344 }) 3345 } 3346 3347 fn visit_i16x8_gt_s(&mut self) -> Self::Output { 3348 self.context 3349 .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| { 3350 masm.v128_gt(writable!(dst), dst, src, VectorCompareKind::I16x8S)?; 3351 Ok(TypedReg::v128(dst)) 3352 }) 3353 } 3354 3355 fn visit_i16x8_gt_u(&mut self) -> Self::Output { 3356 self.context 3357 .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| { 3358 masm.v128_gt(writable!(dst), dst, src, VectorCompareKind::I16x8U)?; 3359 Ok(TypedReg::v128(dst)) 3360 }) 3361 } 3362 3363 fn visit_i32x4_gt_s(&mut self) -> Self::Output { 3364 self.context 3365 .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| { 3366 masm.v128_gt(writable!(dst), dst, src, VectorCompareKind::I32x4S)?; 3367 Ok(TypedReg::v128(dst)) 3368 }) 3369 } 3370 3371 fn visit_i32x4_gt_u(&mut self) -> Self::Output { 3372 self.context 3373 .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| { 3374 masm.v128_gt(writable!(dst), dst, src, VectorCompareKind::I32x4U)?; 3375 Ok(TypedReg::v128(dst)) 3376 }) 3377 } 3378 3379 fn visit_i64x2_gt_s(&mut self) -> Self::Output { 3380 self.context 3381 .binop(self.masm, OperandSize::S64, |masm, dst, src, _size| { 3382 masm.v128_gt(writable!(dst), dst, src, VectorCompareKind::I64x2S)?; 3383 Ok(TypedReg::v128(dst)) 3384 }) 3385 } 3386 3387 fn visit_f32x4_gt(&mut self) -> Self::Output { 3388 self.context 3389 .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| { 3390 masm.v128_gt(writable!(dst), dst, src, VectorCompareKind::F32x4)?; 3391 Ok(TypedReg::v128(dst)) 3392 }) 3393 } 3394 3395 fn visit_f64x2_gt(&mut self) -> Self::Output { 3396 self.context 3397 .binop(self.masm, OperandSize::S64, |masm, dst, src, _size| { 3398 masm.v128_gt(writable!(dst), dst, src, VectorCompareKind::F64x2)?; 3399 Ok(TypedReg::v128(dst)) 3400 }) 3401 } 3402 3403 fn visit_i8x16_ge_s(&mut self) -> Self::Output { 3404 self.context 3405 .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| { 3406 masm.v128_ge(writable!(dst), dst, src, VectorCompareKind::I8x16S)?; 3407 Ok(TypedReg::v128(dst)) 3408 }) 3409 } 3410 3411 fn visit_i8x16_ge_u(&mut self) -> Self::Output { 3412 self.context 3413 .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| { 3414 masm.v128_ge(writable!(dst), dst, src, VectorCompareKind::I8x16U)?; 3415 Ok(TypedReg::v128(dst)) 3416 }) 3417 } 3418 3419 fn visit_i16x8_ge_s(&mut self) -> Self::Output { 3420 self.context 3421 .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| { 3422 masm.v128_ge(writable!(dst), dst, src, VectorCompareKind::I16x8S)?; 3423 Ok(TypedReg::v128(dst)) 3424 }) 3425 } 3426 3427 fn visit_i16x8_ge_u(&mut self) -> Self::Output { 3428 self.context 3429 .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| { 3430 masm.v128_ge(writable!(dst), dst, src, VectorCompareKind::I16x8U)?; 3431 Ok(TypedReg::v128(dst)) 3432 }) 3433 } 3434 3435 fn visit_i32x4_ge_s(&mut self) -> Self::Output { 3436 self.context 3437 .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| { 3438 masm.v128_ge(writable!(dst), dst, src, VectorCompareKind::I32x4S)?; 3439 Ok(TypedReg::v128(dst)) 3440 }) 3441 } 3442 3443 fn visit_i32x4_ge_u(&mut self) -> Self::Output { 3444 self.context 3445 .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| { 3446 masm.v128_ge(writable!(dst), dst, src, VectorCompareKind::I32x4U)?; 3447 Ok(TypedReg::v128(dst)) 3448 }) 3449 } 3450 3451 fn visit_i64x2_ge_s(&mut self) -> Self::Output { 3452 self.context 3453 .binop(self.masm, OperandSize::S64, |masm, dst, src, _size| { 3454 masm.v128_ge(writable!(dst), dst, src, VectorCompareKind::I64x2S)?; 3455 Ok(TypedReg::v128(dst)) 3456 }) 3457 } 3458 3459 fn visit_f32x4_ge(&mut self) -> Self::Output { 3460 self.context 3461 .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| { 3462 masm.v128_ge(writable!(dst), dst, src, VectorCompareKind::F32x4)?; 3463 Ok(TypedReg::v128(dst)) 3464 }) 3465 } 3466 3467 fn visit_f64x2_ge(&mut self) -> Self::Output { 3468 self.context 3469 .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| { 3470 masm.v128_ge(writable!(dst), dst, src, VectorCompareKind::F64x2)?; 3471 Ok(TypedReg::v128(dst)) 3472 }) 3473 } 3474 3475 fn visit_i8x16_replace_lane(&mut self, lane: u8) -> Self::Output { 3476 self.context 3477 .replace_lane_op(self.masm, ReplaceLaneKind::I8x16, |masm, src, dst, kind| { 3478 masm.replace_lane(src, dst, lane, kind) 3479 }) 3480 } 3481 3482 fn visit_i16x8_replace_lane(&mut self, lane: u8) -> Self::Output { 3483 self.context 3484 .replace_lane_op(self.masm, ReplaceLaneKind::I16x8, |masm, src, dst, kind| { 3485 masm.replace_lane(src, dst, lane, kind) 3486 }) 3487 } 3488 3489 fn visit_i32x4_replace_lane(&mut self, lane: u8) -> Self::Output { 3490 self.context 3491 .replace_lane_op(self.masm, ReplaceLaneKind::I32x4, |masm, src, dst, kind| { 3492 masm.replace_lane(src, dst, lane, kind) 3493 }) 3494 } 3495 3496 fn visit_i64x2_replace_lane(&mut self, lane: u8) -> Self::Output { 3497 self.context 3498 .replace_lane_op(self.masm, ReplaceLaneKind::I64x2, |masm, src, dst, kind| { 3499 masm.replace_lane(src, dst, lane, kind) 3500 }) 3501 } 3502 3503 fn visit_f32x4_replace_lane(&mut self, lane: u8) -> Self::Output { 3504 self.context 3505 .replace_lane_op(self.masm, ReplaceLaneKind::F32x4, |masm, src, dst, kind| { 3506 masm.replace_lane(src, dst, lane, kind) 3507 }) 3508 } 3509 3510 fn visit_f64x2_replace_lane(&mut self, lane: u8) -> Self::Output { 3511 self.context 3512 .replace_lane_op(self.masm, ReplaceLaneKind::F64x2, |masm, src, dst, kind| { 3513 masm.replace_lane(src, dst, lane, kind) 3514 }) 3515 } 3516 3517 fn visit_v128_not(&mut self) -> Self::Output { 3518 self.context.unop(self.masm, |masm, reg| { 3519 masm.v128_not(writable!(reg))?; 3520 Ok(TypedReg::new(WasmValType::V128, reg)) 3521 }) 3522 } 3523 3524 fn visit_v128_and(&mut self) -> Self::Output { 3525 self.context 3526 .binop(self.masm, OperandSize::S128, |masm, dst, src, _size| { 3527 masm.v128_and(dst, src, writable!(dst))?; 3528 Ok(TypedReg::new(WasmValType::V128, dst)) 3529 }) 3530 } 3531 3532 fn visit_v128_andnot(&mut self) -> Self::Output { 3533 self.context 3534 .binop(self.masm, OperandSize::S128, |masm, dst, src, _size| { 3535 // careful here: and_not is *not* commutative: dst = !src1 & src2 3536 masm.v128_and_not(src, dst, writable!(dst))?; 3537 Ok(TypedReg::new(WasmValType::V128, dst)) 3538 }) 3539 } 3540 3541 fn visit_v128_or(&mut self) -> Self::Output { 3542 self.context 3543 .binop(self.masm, OperandSize::S128, |masm, dst, src, _size| { 3544 // careful here: and_not is *not* commutative: dst = !src1 & src2 3545 masm.v128_or(src, dst, writable!(dst))?; 3546 Ok(TypedReg::new(WasmValType::V128, dst)) 3547 }) 3548 } 3549 3550 fn visit_v128_xor(&mut self) -> Self::Output { 3551 self.context 3552 .binop(self.masm, OperandSize::S128, |masm, dst, src, _size| { 3553 // careful here: and_not is *not* commutative: dst = !src1 & src2 3554 masm.v128_xor(src, dst, writable!(dst))?; 3555 Ok(TypedReg::new(WasmValType::V128, dst)) 3556 }) 3557 } 3558 3559 fn visit_v128_bitselect(&mut self) -> Self::Output { 3560 let mask = self.context.pop_to_reg(self.masm, None)?; 3561 let op2 = self.context.pop_to_reg(self.masm, None)?; 3562 let op1 = self.context.pop_to_reg(self.masm, None)?; 3563 let dst = self.context.any_fpr(self.masm)?; 3564 3565 // careful here: bitselect is *not* commutative. 3566 self.masm 3567 .v128_bitselect(op1.reg, op2.reg, mask.reg, writable!(dst))?; 3568 3569 self.context 3570 .stack 3571 .push(TypedReg::new(WasmValType::V128, dst).into()); 3572 self.context.free_reg(op1); 3573 self.context.free_reg(op2); 3574 self.context.free_reg(mask); 3575 3576 Ok(()) 3577 } 3578 3579 fn visit_v128_any_true(&mut self) -> Self::Output { 3580 let src = self.context.pop_to_reg(self.masm, None)?; 3581 let dst = self.context.any_gpr(self.masm)?; 3582 3583 self.masm.v128_any_true(src.reg, writable!(dst))?; 3584 3585 self.context 3586 .stack 3587 .push(TypedReg::new(WasmValType::I32, dst).into()); 3588 self.context.free_reg(src); 3589 3590 Ok(()) 3591 } 3592 3593 fn visit_v128_load8_lane(&mut self, arg: MemArg, lane: u8) -> Self::Output { 3594 self.emit_wasm_load( 3595 &arg, 3596 WasmValType::V128, 3597 LoadKind::vector_lane(lane, OperandSize::S8), 3598 ) 3599 } 3600 3601 fn visit_v128_load16_lane(&mut self, arg: MemArg, lane: u8) -> Self::Output { 3602 self.emit_wasm_load( 3603 &arg, 3604 WasmValType::V128, 3605 LoadKind::vector_lane(lane, OperandSize::S16), 3606 ) 3607 } 3608 3609 fn visit_v128_load32_lane(&mut self, arg: MemArg, lane: u8) -> Self::Output { 3610 self.emit_wasm_load( 3611 &arg, 3612 WasmValType::V128, 3613 LoadKind::vector_lane(lane, OperandSize::S32), 3614 ) 3615 } 3616 3617 fn visit_v128_load64_lane(&mut self, arg: MemArg, lane: u8) -> Self::Output { 3618 self.emit_wasm_load( 3619 &arg, 3620 WasmValType::V128, 3621 LoadKind::vector_lane(lane, OperandSize::S64), 3622 ) 3623 } 3624 3625 fn visit_v128_store8_lane(&mut self, arg: MemArg, lane: u8) -> Self::Output { 3626 self.emit_wasm_store(&arg, StoreKind::vector_lane(lane, OperandSize::S8)) 3627 } 3628 3629 fn visit_v128_store16_lane(&mut self, arg: MemArg, lane: u8) -> Self::Output { 3630 self.emit_wasm_store(&arg, StoreKind::vector_lane(lane, OperandSize::S16)) 3631 } 3632 3633 fn visit_v128_store32_lane(&mut self, arg: MemArg, lane: u8) -> Self::Output { 3634 self.emit_wasm_store(&arg, StoreKind::vector_lane(lane, OperandSize::S32)) 3635 } 3636 3637 fn visit_v128_store64_lane(&mut self, arg: MemArg, lane: u8) -> Self::Output { 3638 self.emit_wasm_store(&arg, StoreKind::vector_lane(lane, OperandSize::S64)) 3639 } 3640 3641 fn visit_f32x4_convert_i32x4_s(&mut self) -> Self::Output { 3642 self.context.unop(self.masm, |masm, reg| { 3643 masm.v128_convert(reg, writable!(reg), V128ConvertKind::I32x4S)?; 3644 Ok(TypedReg::v128(reg)) 3645 }) 3646 } 3647 3648 fn visit_f32x4_convert_i32x4_u(&mut self) -> Self::Output { 3649 self.context.unop(self.masm, |masm, reg| { 3650 masm.v128_convert(reg, writable!(reg), V128ConvertKind::I32x4U)?; 3651 Ok(TypedReg::v128(reg)) 3652 }) 3653 } 3654 3655 fn visit_f64x2_convert_low_i32x4_s(&mut self) -> Self::Output { 3656 self.context.unop(self.masm, |masm, reg| { 3657 masm.v128_convert(reg, writable!(reg), V128ConvertKind::I32x4LowS)?; 3658 Ok(TypedReg::v128(reg)) 3659 }) 3660 } 3661 3662 fn visit_f64x2_convert_low_i32x4_u(&mut self) -> Self::Output { 3663 self.context.unop(self.masm, |masm, reg| { 3664 masm.v128_convert(reg, writable!(reg), V128ConvertKind::I32x4LowU)?; 3665 Ok(TypedReg::v128(reg)) 3666 }) 3667 } 3668 3669 fn visit_i8x16_narrow_i16x8_s(&mut self) -> Self::Output { 3670 self.context 3671 .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| { 3672 masm.v128_narrow(dst, src, writable!(dst), V128NarrowKind::I16x8S)?; 3673 Ok(TypedReg::v128(dst)) 3674 }) 3675 } 3676 3677 fn visit_i8x16_narrow_i16x8_u(&mut self) -> Self::Output { 3678 self.context 3679 .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| { 3680 masm.v128_narrow(dst, src, writable!(dst), V128NarrowKind::I16x8U)?; 3681 Ok(TypedReg::v128(dst)) 3682 }) 3683 } 3684 3685 fn visit_i16x8_narrow_i32x4_s(&mut self) -> Self::Output { 3686 self.context 3687 .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| { 3688 masm.v128_narrow(dst, src, writable!(dst), V128NarrowKind::I32x4S)?; 3689 Ok(TypedReg::v128(dst)) 3690 }) 3691 } 3692 3693 fn visit_i16x8_narrow_i32x4_u(&mut self) -> Self::Output { 3694 self.context 3695 .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| { 3696 masm.v128_narrow(dst, src, writable!(dst), V128NarrowKind::I32x4U)?; 3697 Ok(TypedReg::v128(dst)) 3698 }) 3699 } 3700 3701 fn visit_f32x4_demote_f64x2_zero(&mut self) -> Self::Output { 3702 self.context.unop(self.masm, |masm, reg| { 3703 masm.v128_demote(reg, writable!(reg))?; 3704 Ok(TypedReg::v128(reg)) 3705 }) 3706 } 3707 3708 fn visit_f64x2_promote_low_f32x4(&mut self) -> Self::Output { 3709 self.context.unop(self.masm, |masm, reg| { 3710 masm.v128_promote(reg, writable!(reg))?; 3711 Ok(TypedReg::v128(reg)) 3712 }) 3713 } 3714 3715 fn visit_i16x8_extend_low_i8x16_s(&mut self) -> Self::Output { 3716 self.context.unop(self.masm, |masm, reg| { 3717 masm.v128_extend(reg, writable!(reg), V128ExtendKind::LowI8x16S)?; 3718 Ok(TypedReg::v128(reg)) 3719 }) 3720 } 3721 3722 fn visit_i16x8_extend_high_i8x16_s(&mut self) -> Self::Output { 3723 self.context.unop(self.masm, |masm, reg| { 3724 masm.v128_extend(reg, writable!(reg), V128ExtendKind::HighI8x16S)?; 3725 Ok(TypedReg::v128(reg)) 3726 }) 3727 } 3728 3729 fn visit_i16x8_extend_low_i8x16_u(&mut self) -> Self::Output { 3730 self.context.unop(self.masm, |masm, reg| { 3731 masm.v128_extend(reg, writable!(reg), V128ExtendKind::LowI8x16U)?; 3732 Ok(TypedReg::v128(reg)) 3733 }) 3734 } 3735 3736 fn visit_i16x8_extend_high_i8x16_u(&mut self) -> Self::Output { 3737 self.context.unop(self.masm, |masm, reg| { 3738 masm.v128_extend(reg, writable!(reg), V128ExtendKind::HighI8x16U)?; 3739 Ok(TypedReg::v128(reg)) 3740 }) 3741 } 3742 3743 fn visit_i32x4_extend_low_i16x8_s(&mut self) -> Self::Output { 3744 self.context.unop(self.masm, |masm, reg| { 3745 masm.v128_extend(reg, writable!(reg), V128ExtendKind::LowI16x8S)?; 3746 Ok(TypedReg::v128(reg)) 3747 }) 3748 } 3749 3750 fn visit_i32x4_extend_high_i16x8_s(&mut self) -> Self::Output { 3751 self.context.unop(self.masm, |masm, reg| { 3752 masm.v128_extend(reg, writable!(reg), V128ExtendKind::HighI16x8S)?; 3753 Ok(TypedReg::v128(reg)) 3754 }) 3755 } 3756 3757 fn visit_i32x4_extend_low_i16x8_u(&mut self) -> Self::Output { 3758 self.context.unop(self.masm, |masm, reg| { 3759 masm.v128_extend(reg, writable!(reg), V128ExtendKind::LowI16x8U)?; 3760 Ok(TypedReg::v128(reg)) 3761 }) 3762 } 3763 3764 fn visit_i32x4_extend_high_i16x8_u(&mut self) -> Self::Output { 3765 self.context.unop(self.masm, |masm, reg| { 3766 masm.v128_extend(reg, writable!(reg), V128ExtendKind::HighI16x8U)?; 3767 Ok(TypedReg::v128(reg)) 3768 }) 3769 } 3770 3771 fn visit_i64x2_extend_low_i32x4_s(&mut self) -> Self::Output { 3772 self.context.unop(self.masm, |masm, reg| { 3773 masm.v128_extend(reg, writable!(reg), V128ExtendKind::LowI32x4S)?; 3774 Ok(TypedReg::v128(reg)) 3775 }) 3776 } 3777 3778 fn visit_i64x2_extend_high_i32x4_s(&mut self) -> Self::Output { 3779 self.context.unop(self.masm, |masm, reg| { 3780 masm.v128_extend(reg, writable!(reg), V128ExtendKind::HighI32x4S)?; 3781 Ok(TypedReg::v128(reg)) 3782 }) 3783 } 3784 3785 fn visit_i64x2_extend_low_i32x4_u(&mut self) -> Self::Output { 3786 self.context.unop(self.masm, |masm, reg| { 3787 masm.v128_extend(reg, writable!(reg), V128ExtendKind::LowI32x4U)?; 3788 Ok(TypedReg::v128(reg)) 3789 }) 3790 } 3791 3792 fn visit_i64x2_extend_high_i32x4_u(&mut self) -> Self::Output { 3793 self.context.unop(self.masm, |masm, reg| { 3794 masm.v128_extend(reg, writable!(reg), V128ExtendKind::HighI32x4U)?; 3795 Ok(TypedReg::v128(reg)) 3796 }) 3797 } 3798 3799 fn visit_i8x16_add(&mut self) -> Self::Output { 3800 self.context 3801 .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| { 3802 masm.v128_add(dst, src, writable!(dst), V128AddKind::I8x16)?; 3803 Ok(TypedReg::new(WasmValType::V128, dst)) 3804 }) 3805 } 3806 3807 fn visit_i16x8_add(&mut self) -> Self::Output { 3808 self.context 3809 .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| { 3810 masm.v128_add(dst, src, writable!(dst), V128AddKind::I16x8)?; 3811 Ok(TypedReg::new(WasmValType::V128, dst)) 3812 }) 3813 } 3814 3815 fn visit_i32x4_add(&mut self) -> Self::Output { 3816 self.context 3817 .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| { 3818 masm.v128_add(dst, src, writable!(dst), V128AddKind::I32x4)?; 3819 Ok(TypedReg::new(WasmValType::V128, dst)) 3820 }) 3821 } 3822 3823 fn visit_i64x2_add(&mut self) -> Self::Output { 3824 self.context 3825 .binop(self.masm, OperandSize::S64, |masm, dst, src, _size| { 3826 masm.v128_add(dst, src, writable!(dst), V128AddKind::I64x2)?; 3827 Ok(TypedReg::new(WasmValType::V128, dst)) 3828 }) 3829 } 3830 3831 fn visit_i8x16_sub(&mut self) -> Self::Output { 3832 self.context 3833 .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| { 3834 masm.v128_sub(dst, src, writable!(dst), V128SubKind::I8x16)?; 3835 Ok(TypedReg::new(WasmValType::V128, dst)) 3836 }) 3837 } 3838 3839 fn visit_i16x8_sub(&mut self) -> Self::Output { 3840 self.context 3841 .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| { 3842 masm.v128_sub(dst, src, writable!(dst), V128SubKind::I16x8)?; 3843 Ok(TypedReg::new(WasmValType::V128, dst)) 3844 }) 3845 } 3846 3847 fn visit_i32x4_sub(&mut self) -> Self::Output { 3848 self.context 3849 .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| { 3850 masm.v128_sub(dst, src, writable!(dst), V128SubKind::I32x4)?; 3851 Ok(TypedReg::new(WasmValType::V128, dst)) 3852 }) 3853 } 3854 3855 fn visit_i64x2_sub(&mut self) -> Self::Output { 3856 self.context 3857 .binop(self.masm, OperandSize::S64, |masm, dst, src, _size| { 3858 masm.v128_sub(dst, src, writable!(dst), V128SubKind::I64x2)?; 3859 Ok(TypedReg::new(WasmValType::V128, dst)) 3860 }) 3861 } 3862 3863 fn visit_i16x8_mul(&mut self) -> Self::Output { 3864 self.masm.v128_mul(&mut self.context, V128MulKind::I16x8) 3865 } 3866 3867 fn visit_i32x4_mul(&mut self) -> Self::Output { 3868 self.masm.v128_mul(&mut self.context, V128MulKind::I32x4) 3869 } 3870 3871 fn visit_i64x2_mul(&mut self) -> Self::Output { 3872 self.masm.v128_mul(&mut self.context, V128MulKind::I64x2) 3873 } 3874 3875 fn visit_i8x16_add_sat_s(&mut self) -> Self::Output { 3876 self.context 3877 .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| { 3878 masm.v128_add(dst, src, writable!(dst), V128AddKind::I8x16SatS)?; 3879 Ok(TypedReg::new(WasmValType::V128, dst)) 3880 }) 3881 } 3882 3883 fn visit_i16x8_add_sat_s(&mut self) -> Self::Output { 3884 self.context 3885 .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| { 3886 masm.v128_add(dst, src, writable!(dst), V128AddKind::I16x8SatS)?; 3887 Ok(TypedReg::new(WasmValType::V128, dst)) 3888 }) 3889 } 3890 3891 fn visit_i8x16_add_sat_u(&mut self) -> Self::Output { 3892 self.context 3893 .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| { 3894 masm.v128_add(dst, src, writable!(dst), V128AddKind::I8x16SatU)?; 3895 Ok(TypedReg::new(WasmValType::V128, dst)) 3896 }) 3897 } 3898 3899 fn visit_i16x8_add_sat_u(&mut self) -> Self::Output { 3900 self.context 3901 .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| { 3902 masm.v128_add(dst, src, writable!(dst), V128AddKind::I16x8SatU)?; 3903 Ok(TypedReg::new(WasmValType::V128, dst)) 3904 }) 3905 } 3906 3907 fn visit_i8x16_sub_sat_s(&mut self) -> Self::Output { 3908 self.context 3909 .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| { 3910 masm.v128_sub(dst, src, writable!(dst), V128SubKind::I8x16SatS)?; 3911 Ok(TypedReg::new(WasmValType::V128, dst)) 3912 }) 3913 } 3914 3915 fn visit_i16x8_sub_sat_s(&mut self) -> Self::Output { 3916 self.context 3917 .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| { 3918 masm.v128_sub(dst, src, writable!(dst), V128SubKind::I16x8SatS)?; 3919 Ok(TypedReg::new(WasmValType::V128, dst)) 3920 }) 3921 } 3922 3923 fn visit_i8x16_sub_sat_u(&mut self) -> Self::Output { 3924 self.context 3925 .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| { 3926 masm.v128_sub(dst, src, writable!(dst), V128SubKind::I8x16SatU)?; 3927 Ok(TypedReg::new(WasmValType::V128, dst)) 3928 }) 3929 } 3930 3931 fn visit_i16x8_sub_sat_u(&mut self) -> Self::Output { 3932 self.context 3933 .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| { 3934 masm.v128_sub(dst, src, writable!(dst), V128SubKind::I16x8SatU)?; 3935 Ok(TypedReg::new(WasmValType::V128, dst)) 3936 }) 3937 } 3938 3939 fn visit_i8x16_abs(&mut self) -> Self::Output { 3940 self.context.unop(self.masm, |masm, reg| { 3941 masm.v128_abs(reg, writable!(reg), V128AbsKind::I8x16)?; 3942 Ok(TypedReg::new(WasmValType::V128, reg)) 3943 }) 3944 } 3945 3946 fn visit_i16x8_abs(&mut self) -> Self::Output { 3947 self.context.unop(self.masm, |masm, reg| { 3948 masm.v128_abs(reg, writable!(reg), V128AbsKind::I16x8)?; 3949 Ok(TypedReg::new(WasmValType::V128, reg)) 3950 }) 3951 } 3952 3953 fn visit_i32x4_abs(&mut self) -> Self::Output { 3954 self.context.unop(self.masm, |masm, reg| { 3955 masm.v128_abs(reg, writable!(reg), V128AbsKind::I32x4)?; 3956 Ok(TypedReg::new(WasmValType::V128, reg)) 3957 }) 3958 } 3959 3960 fn visit_i64x2_abs(&mut self) -> Self::Output { 3961 self.context.unop(self.masm, |masm, reg| { 3962 masm.v128_abs(reg, writable!(reg), V128AbsKind::I64x2)?; 3963 Ok(TypedReg::new(WasmValType::V128, reg)) 3964 }) 3965 } 3966 3967 fn visit_f32x4_abs(&mut self) -> Self::Output { 3968 self.context.unop(self.masm, |masm, reg| { 3969 masm.v128_abs(reg, writable!(reg), V128AbsKind::F32x4)?; 3970 Ok(TypedReg::new(WasmValType::V128, reg)) 3971 }) 3972 } 3973 3974 fn visit_f64x2_abs(&mut self) -> Self::Output { 3975 self.context.unop(self.masm, |masm, reg| { 3976 masm.v128_abs(reg, writable!(reg), V128AbsKind::F64x2)?; 3977 Ok(TypedReg::new(WasmValType::V128, reg)) 3978 }) 3979 } 3980 3981 fn visit_i8x16_neg(&mut self) -> Self::Output { 3982 self.context.unop(self.masm, |masm, op| { 3983 masm.v128_neg(writable!(op), V128NegKind::I8x16)?; 3984 Ok(TypedReg::new(WasmValType::V128, op)) 3985 }) 3986 } 3987 3988 fn visit_i16x8_neg(&mut self) -> Self::Output { 3989 self.context.unop(self.masm, |masm, op| { 3990 masm.v128_neg(writable!(op), V128NegKind::I16x8)?; 3991 Ok(TypedReg::new(WasmValType::V128, op)) 3992 }) 3993 } 3994 3995 fn visit_i32x4_neg(&mut self) -> Self::Output { 3996 self.context.unop(self.masm, |masm, op| { 3997 masm.v128_neg(writable!(op), V128NegKind::I32x4)?; 3998 Ok(TypedReg::new(WasmValType::V128, op)) 3999 }) 4000 } 4001 4002 fn visit_i64x2_neg(&mut self) -> Self::Output { 4003 self.context.unop(self.masm, |masm, op| { 4004 masm.v128_neg(writable!(op), V128NegKind::I64x2)?; 4005 Ok(TypedReg::new(WasmValType::V128, op)) 4006 }) 4007 } 4008 4009 fn visit_i8x16_shl(&mut self) -> Self::Output { 4010 self.masm 4011 .v128_shift(&mut self.context, OperandSize::S8, ShiftKind::Shl) 4012 } 4013 4014 fn visit_i16x8_shl(&mut self) -> Self::Output { 4015 self.masm 4016 .v128_shift(&mut self.context, OperandSize::S16, ShiftKind::Shl) 4017 } 4018 4019 fn visit_i32x4_shl(&mut self) -> Self::Output { 4020 self.masm 4021 .v128_shift(&mut self.context, OperandSize::S32, ShiftKind::Shl) 4022 } 4023 4024 fn visit_i64x2_shl(&mut self) -> Self::Output { 4025 self.masm 4026 .v128_shift(&mut self.context, OperandSize::S64, ShiftKind::Shl) 4027 } 4028 4029 fn visit_i8x16_shr_u(&mut self) -> Self::Output { 4030 self.masm 4031 .v128_shift(&mut self.context, OperandSize::S8, ShiftKind::ShrU) 4032 } 4033 4034 fn visit_i16x8_shr_u(&mut self) -> Self::Output { 4035 self.masm 4036 .v128_shift(&mut self.context, OperandSize::S16, ShiftKind::ShrU) 4037 } 4038 4039 fn visit_i32x4_shr_u(&mut self) -> Self::Output { 4040 self.masm 4041 .v128_shift(&mut self.context, OperandSize::S32, ShiftKind::ShrU) 4042 } 4043 4044 fn visit_i64x2_shr_u(&mut self) -> Self::Output { 4045 self.masm 4046 .v128_shift(&mut self.context, OperandSize::S64, ShiftKind::ShrU) 4047 } 4048 4049 fn visit_i8x16_shr_s(&mut self) -> Self::Output { 4050 self.masm 4051 .v128_shift(&mut self.context, OperandSize::S8, ShiftKind::ShrS) 4052 } 4053 4054 fn visit_i16x8_shr_s(&mut self) -> Self::Output { 4055 self.masm 4056 .v128_shift(&mut self.context, OperandSize::S16, ShiftKind::ShrS) 4057 } 4058 4059 fn visit_i32x4_shr_s(&mut self) -> Self::Output { 4060 self.masm 4061 .v128_shift(&mut self.context, OperandSize::S32, ShiftKind::ShrS) 4062 } 4063 4064 fn visit_i64x2_shr_s(&mut self) -> Self::Output { 4065 self.masm 4066 .v128_shift(&mut self.context, OperandSize::S64, ShiftKind::ShrS) 4067 } 4068 4069 fn visit_i16x8_q15mulr_sat_s(&mut self) -> Self::Output { 4070 self.context 4071 .binop(self.masm, OperandSize::S16, |masm, dst, src, size| { 4072 masm.v128_q15mulr_sat_s(dst, src, writable!(dst), size)?; 4073 Ok(TypedReg::v128(dst)) 4074 }) 4075 } 4076 4077 fn visit_i8x16_min_s(&mut self) -> Self::Output { 4078 self.context 4079 .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| { 4080 masm.v128_min(src, dst, writable!(dst), V128MinKind::I8x16S)?; 4081 Ok(TypedReg::v128(dst)) 4082 }) 4083 } 4084 4085 fn visit_i8x16_all_true(&mut self) -> Self::Output { 4086 self.context.v128_all_true_op(self.masm, |masm, src, dst| { 4087 masm.v128_all_true(src, writable!(dst), OperandSize::S8) 4088 }) 4089 } 4090 4091 fn visit_i16x8_all_true(&mut self) -> Self::Output { 4092 self.context.v128_all_true_op(self.masm, |masm, src, dst| { 4093 masm.v128_all_true(src, writable!(dst), OperandSize::S16) 4094 }) 4095 } 4096 4097 fn visit_i32x4_all_true(&mut self) -> Self::Output { 4098 self.context.v128_all_true_op(self.masm, |masm, src, dst| { 4099 masm.v128_all_true(src, writable!(dst), OperandSize::S32) 4100 }) 4101 } 4102 4103 fn visit_i64x2_all_true(&mut self) -> Self::Output { 4104 self.context.v128_all_true_op(self.masm, |masm, src, dst| { 4105 masm.v128_all_true(src, writable!(dst), OperandSize::S64) 4106 }) 4107 } 4108 4109 fn visit_i8x16_bitmask(&mut self) -> Self::Output { 4110 self.context.v128_bitmask_op(self.masm, |masm, src, dst| { 4111 masm.v128_bitmask(src, writable!(dst), OperandSize::S8) 4112 }) 4113 } 4114 4115 fn visit_i16x8_bitmask(&mut self) -> Self::Output { 4116 self.context.v128_bitmask_op(self.masm, |masm, src, dst| { 4117 masm.v128_bitmask(src, writable!(dst), OperandSize::S16) 4118 }) 4119 } 4120 4121 fn visit_i32x4_bitmask(&mut self) -> Self::Output { 4122 self.context.v128_bitmask_op(self.masm, |masm, src, dst| { 4123 masm.v128_bitmask(src, writable!(dst), OperandSize::S32) 4124 }) 4125 } 4126 4127 fn visit_i64x2_bitmask(&mut self) -> Self::Output { 4128 self.context.v128_bitmask_op(self.masm, |masm, src, dst| { 4129 masm.v128_bitmask(src, writable!(dst), OperandSize::S64) 4130 }) 4131 } 4132 4133 fn visit_i32x4_trunc_sat_f32x4_s(&mut self) -> Self::Output { 4134 self.masm 4135 .v128_trunc(&mut self.context, V128TruncKind::I32x4FromF32x4S) 4136 } 4137 4138 fn visit_i32x4_trunc_sat_f32x4_u(&mut self) -> Self::Output { 4139 self.masm 4140 .v128_trunc(&mut self.context, V128TruncKind::I32x4FromF32x4U) 4141 } 4142 4143 fn visit_i32x4_trunc_sat_f64x2_s_zero(&mut self) -> Self::Output { 4144 self.masm 4145 .v128_trunc(&mut self.context, V128TruncKind::I32x4FromF64x2SZero) 4146 } 4147 4148 fn visit_i32x4_trunc_sat_f64x2_u_zero(&mut self) -> Self::Output { 4149 self.masm 4150 .v128_trunc(&mut self.context, V128TruncKind::I32x4FromF64x2UZero) 4151 } 4152 4153 fn visit_i16x8_min_s(&mut self) -> Self::Output { 4154 self.context 4155 .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| { 4156 masm.v128_min(src, dst, writable!(dst), V128MinKind::I16x8S)?; 4157 Ok(TypedReg::v128(dst)) 4158 }) 4159 } 4160 4161 fn visit_i32x4_dot_i16x8_s(&mut self) -> Self::Output { 4162 self.context 4163 .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| { 4164 masm.v128_dot(dst, src, writable!(dst))?; 4165 Ok(TypedReg::v128(dst)) 4166 }) 4167 } 4168 4169 fn visit_i8x16_popcnt(&mut self) -> Self::Output { 4170 self.masm.v128_popcnt(&mut self.context) 4171 } 4172 4173 fn visit_i8x16_avgr_u(&mut self) -> Self::Output { 4174 self.context 4175 .binop(self.masm, OperandSize::S8, |masm, dst, src, size| { 4176 masm.v128_avgr(dst, src, writable!(dst), size)?; 4177 Ok(TypedReg::v128(dst)) 4178 }) 4179 } 4180 4181 fn visit_i32x4_min_s(&mut self) -> Self::Output { 4182 self.context 4183 .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| { 4184 masm.v128_min(src, dst, writable!(dst), V128MinKind::I32x4S)?; 4185 Ok(TypedReg::v128(dst)) 4186 }) 4187 } 4188 4189 fn visit_i8x16_min_u(&mut self) -> Self::Output { 4190 self.context 4191 .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| { 4192 masm.v128_min(src, dst, writable!(dst), V128MinKind::I8x16U)?; 4193 Ok(TypedReg::v128(dst)) 4194 }) 4195 } 4196 4197 fn visit_i16x8_avgr_u(&mut self) -> Self::Output { 4198 self.context 4199 .binop(self.masm, OperandSize::S16, |masm, dst, src, size| { 4200 masm.v128_avgr(dst, src, writable!(dst), size)?; 4201 Ok(TypedReg::v128(dst)) 4202 }) 4203 } 4204 4205 fn visit_i16x8_min_u(&mut self) -> Self::Output { 4206 self.context 4207 .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| { 4208 masm.v128_min(src, dst, writable!(dst), V128MinKind::I16x8U)?; 4209 Ok(TypedReg::v128(dst)) 4210 }) 4211 } 4212 4213 fn visit_i32x4_min_u(&mut self) -> Self::Output { 4214 self.context 4215 .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| { 4216 masm.v128_min(src, dst, writable!(dst), V128MinKind::I32x4U)?; 4217 Ok(TypedReg::v128(dst)) 4218 }) 4219 } 4220 4221 fn visit_i8x16_max_s(&mut self) -> Self::Output { 4222 self.context 4223 .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| { 4224 masm.v128_max(src, dst, writable!(dst), V128MaxKind::I8x16S)?; 4225 Ok(TypedReg::v128(dst)) 4226 }) 4227 } 4228 4229 fn visit_i16x8_max_s(&mut self) -> Self::Output { 4230 self.context 4231 .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| { 4232 masm.v128_max(src, dst, writable!(dst), V128MaxKind::I16x8S)?; 4233 Ok(TypedReg::v128(dst)) 4234 }) 4235 } 4236 4237 fn visit_i32x4_max_s(&mut self) -> Self::Output { 4238 self.context 4239 .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| { 4240 masm.v128_max(src, dst, writable!(dst), V128MaxKind::I32x4S)?; 4241 Ok(TypedReg::v128(dst)) 4242 }) 4243 } 4244 4245 fn visit_i8x16_max_u(&mut self) -> Self::Output { 4246 self.context 4247 .binop(self.masm, OperandSize::S8, |masm, dst, src, _size| { 4248 masm.v128_max(src, dst, writable!(dst), V128MaxKind::I8x16U)?; 4249 Ok(TypedReg::v128(dst)) 4250 }) 4251 } 4252 4253 fn visit_i16x8_max_u(&mut self) -> Self::Output { 4254 self.context 4255 .binop(self.masm, OperandSize::S16, |masm, dst, src, _size| { 4256 masm.v128_max(src, dst, writable!(dst), V128MaxKind::I16x8U)?; 4257 Ok(TypedReg::v128(dst)) 4258 }) 4259 } 4260 4261 fn visit_i32x4_max_u(&mut self) -> Self::Output { 4262 self.context 4263 .binop(self.masm, OperandSize::S32, |masm, dst, src, _size| { 4264 masm.v128_max(src, dst, writable!(dst), V128MaxKind::I32x4U)?; 4265 Ok(TypedReg::v128(dst)) 4266 }) 4267 } 4268 4269 fn visit_i16x8_extmul_low_i8x16_s(&mut self) -> Self::Output { 4270 self.masm 4271 .v128_extmul(&mut self.context, V128ExtMulKind::LowI8x16S) 4272 } 4273 4274 fn visit_i32x4_extmul_low_i16x8_s(&mut self) -> Self::Output { 4275 self.masm 4276 .v128_extmul(&mut self.context, V128ExtMulKind::LowI16x8S) 4277 } 4278 4279 fn visit_i64x2_extmul_low_i32x4_s(&mut self) -> Self::Output { 4280 self.masm 4281 .v128_extmul(&mut self.context, V128ExtMulKind::LowI32x4S) 4282 } 4283 4284 fn visit_i16x8_extmul_low_i8x16_u(&mut self) -> Self::Output { 4285 self.masm 4286 .v128_extmul(&mut self.context, V128ExtMulKind::LowI8x16U) 4287 } 4288 4289 fn visit_i32x4_extmul_low_i16x8_u(&mut self) -> Self::Output { 4290 self.masm 4291 .v128_extmul(&mut self.context, V128ExtMulKind::LowI16x8U) 4292 } 4293 4294 fn visit_i64x2_extmul_low_i32x4_u(&mut self) -> Self::Output { 4295 self.masm 4296 .v128_extmul(&mut self.context, V128ExtMulKind::LowI32x4U) 4297 } 4298 4299 fn visit_i16x8_extmul_high_i8x16_u(&mut self) -> Self::Output { 4300 self.masm 4301 .v128_extmul(&mut self.context, V128ExtMulKind::HighI8x16U) 4302 } 4303 4304 fn visit_i32x4_extmul_high_i16x8_u(&mut self) -> Self::Output { 4305 self.masm 4306 .v128_extmul(&mut self.context, V128ExtMulKind::HighI16x8U) 4307 } 4308 4309 fn visit_i64x2_extmul_high_i32x4_u(&mut self) -> Self::Output { 4310 self.masm 4311 .v128_extmul(&mut self.context, V128ExtMulKind::HighI32x4U) 4312 } 4313 4314 fn visit_i16x8_extmul_high_i8x16_s(&mut self) -> Self::Output { 4315 self.masm 4316 .v128_extmul(&mut self.context, V128ExtMulKind::HighI8x16S) 4317 } 4318 4319 fn visit_i32x4_extmul_high_i16x8_s(&mut self) -> Self::Output { 4320 self.masm 4321 .v128_extmul(&mut self.context, V128ExtMulKind::HighI16x8S) 4322 } 4323 4324 fn visit_i64x2_extmul_high_i32x4_s(&mut self) -> Self::Output { 4325 self.masm 4326 .v128_extmul(&mut self.context, V128ExtMulKind::HighI32x4S) 4327 } 4328 4329 fn visit_i16x8_extadd_pairwise_i8x16_s(&mut self) -> Self::Output { 4330 self.context.unop(self.masm, |masm, op| { 4331 masm.v128_extadd_pairwise(op, writable!(op), V128ExtAddKind::I8x16S)?; 4332 Ok(TypedReg::v128(op)) 4333 }) 4334 } 4335 4336 fn visit_i16x8_extadd_pairwise_i8x16_u(&mut self) -> Self::Output { 4337 self.context.unop(self.masm, |masm, op| { 4338 masm.v128_extadd_pairwise(op, writable!(op), V128ExtAddKind::I8x16U)?; 4339 Ok(TypedReg::v128(op)) 4340 }) 4341 } 4342 4343 fn visit_i32x4_extadd_pairwise_i16x8_s(&mut self) -> Self::Output { 4344 self.context.unop(self.masm, |masm, op| { 4345 masm.v128_extadd_pairwise(op, writable!(op), V128ExtAddKind::I16x8S)?; 4346 Ok(TypedReg::v128(op)) 4347 }) 4348 } 4349 4350 fn visit_i32x4_extadd_pairwise_i16x8_u(&mut self) -> Self::Output { 4351 self.context.unop(self.masm, |masm, op| { 4352 masm.v128_extadd_pairwise(op, writable!(op), V128ExtAddKind::I16x8U)?; 4353 Ok(TypedReg::v128(op)) 4354 }) 4355 } 4356 4357 fn visit_f32x4_ceil(&mut self) -> Self::Output { 4358 self.context.unop(self.masm, |masm, reg| { 4359 masm.v128_ceil(reg, writable!(reg), OperandSize::S32)?; 4360 Ok(TypedReg::v128(reg)) 4361 }) 4362 } 4363 4364 fn visit_f64x2_ceil(&mut self) -> Self::Output { 4365 self.context.unop(self.masm, |masm, reg| { 4366 masm.v128_ceil(reg, writable!(reg), OperandSize::S64)?; 4367 Ok(TypedReg::v128(reg)) 4368 }) 4369 } 4370 4371 fn visit_f32x4_floor(&mut self) -> Self::Output { 4372 self.context.unop(self.masm, |masm, reg| { 4373 masm.v128_floor(reg, writable!(reg), OperandSize::S32)?; 4374 Ok(TypedReg::v128(reg)) 4375 }) 4376 } 4377 4378 fn visit_f64x2_floor(&mut self) -> Self::Output { 4379 self.context.unop(self.masm, |masm, reg| { 4380 masm.v128_floor(reg, writable!(reg), OperandSize::S64)?; 4381 Ok(TypedReg::v128(reg)) 4382 }) 4383 } 4384 4385 fn visit_f32x4_nearest(&mut self) -> Self::Output { 4386 self.context.unop(self.masm, |masm, reg| { 4387 masm.v128_nearest(reg, writable!(reg), OperandSize::S32)?; 4388 Ok(TypedReg::v128(reg)) 4389 }) 4390 } 4391 4392 fn visit_f64x2_nearest(&mut self) -> Self::Output { 4393 self.context.unop(self.masm, |masm, reg| { 4394 masm.v128_nearest(reg, writable!(reg), OperandSize::S64)?; 4395 Ok(TypedReg::v128(reg)) 4396 }) 4397 } 4398 4399 fn visit_f32x4_trunc(&mut self) -> Self::Output { 4400 self.masm 4401 .v128_trunc(&mut self.context, V128TruncKind::F32x4) 4402 } 4403 4404 fn visit_f64x2_trunc(&mut self) -> Self::Output { 4405 self.masm 4406 .v128_trunc(&mut self.context, V128TruncKind::F64x2) 4407 } 4408 4409 wasmparser::for_each_visit_simd_operator!(def_unsupported); 4410 } 4411 4412 impl<'a, 'translation, 'data, M> CodeGen<'a, 'translation, 'data, M, Emission> 4413 where 4414 M: MacroAssembler, 4415 { 4416 fn cmp_i32s(&mut self, kind: IntCmpKind) -> Result<()> { 4417 self.context.i32_binop(self.masm, |masm, dst, src, size| { 4418 masm.cmp_with_set(writable!(dst), src, kind, size)?; 4419 Ok(TypedReg::i32(dst)) 4420 }) 4421 } 4422 4423 fn cmp_i64s(&mut self, kind: IntCmpKind) -> Result<()> { 4424 self.context 4425 .i64_binop(self.masm, move |masm, dst, src, size| { 4426 masm.cmp_with_set(writable!(dst), src, kind, size)?; 4427 Ok(TypedReg::i32(dst)) // Return value for comparisons is an `i32`. 4428 }) 4429 } 4430 } 4431 4432 impl TryFrom<WasmValType> for OperandSize { 4433 type Error = anyhow::Error; 4434 fn try_from(ty: WasmValType) -> Result<OperandSize> { 4435 let ty = match ty { 4436 WasmValType::I32 | WasmValType::F32 => OperandSize::S32, 4437 WasmValType::I64 | WasmValType::F64 => OperandSize::S64, 4438 WasmValType::V128 => OperandSize::S128, 4439 WasmValType::Ref(rt) => { 4440 match rt.heap_type { 4441 // TODO: Hardcoded size, assuming 64-bit support only. Once 4442 // Wasmtime supports 32-bit architectures, this will need 4443 // to be updated in such a way that the calculation of the 4444 // OperandSize will depend on the target's pointer size. 4445 WasmHeapType::Func => OperandSize::S64, 4446 WasmHeapType::Extern => OperandSize::S64, 4447 _ => bail!(CodeGenError::unsupported_wasm_type()), 4448 } 4449 } 4450 }; 4451 Ok(ty) 4452 } 4453 } 4454