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