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