github.com/tetratelabs/wazero@v1.7.3-0.20240513003603-48f702e154b5/internal/engine/interpreter/compiler_test.go (about) 1 package interpreter 2 3 import ( 4 "fmt" 5 "math" 6 "testing" 7 8 "github.com/tetratelabs/wazero/api" 9 "github.com/tetratelabs/wazero/internal/leb128" 10 "github.com/tetratelabs/wazero/internal/testing/require" 11 "github.com/tetratelabs/wazero/internal/wasm" 12 ) 13 14 var ( 15 wf32, wf64, i32 = wasm.ValueTypeF32, wasm.ValueTypeF64, wasm.ValueTypeI32 16 f32_i32 = wasm.FunctionType{ 17 Params: []wasm.ValueType{wf32}, Results: []wasm.ValueType{i32}, 18 ParamNumInUint64: 1, 19 ResultNumInUint64: 1, 20 } 21 i32_i32 = wasm.FunctionType{ 22 Params: []wasm.ValueType{i32}, Results: []wasm.ValueType{i32}, 23 ParamNumInUint64: 1, 24 ResultNumInUint64: 1, 25 } 26 i32i32_i32 = wasm.FunctionType{ 27 Params: []wasm.ValueType{i32, i32}, Results: []wasm.ValueType{i32}, 28 ParamNumInUint64: 2, 29 ResultNumInUint64: 1, 30 } 31 v_v = wasm.FunctionType{} 32 v_f64f64 = wasm.FunctionType{Results: []wasm.ValueType{wf64, wf64}, ResultNumInUint64: 2} 33 ) 34 35 func TestCompile(t *testing.T) { 36 tests := []struct { 37 name string 38 module *wasm.Module 39 expected *compilationResult 40 enabledFeatures api.CoreFeatures 41 }{ 42 { 43 name: "nullary", 44 module: &wasm.Module{ 45 TypeSection: []wasm.FunctionType{v_v}, 46 FunctionSection: []wasm.Index{0}, 47 CodeSection: []wasm.Code{{Body: []byte{wasm.OpcodeEnd}}}, 48 }, 49 expected: &compilationResult{ 50 Operations: []unionOperation{ // begin with params: [] 51 newOperationBr(newLabel(labelKindReturn, 0)), // return! 52 }, 53 LabelCallers: map[label]uint32{}, 54 Functions: []uint32{0}, 55 Types: []wasm.FunctionType{v_v}, 56 }, 57 }, 58 { 59 name: "host wasm nullary", 60 module: &wasm.Module{ 61 TypeSection: []wasm.FunctionType{v_v}, 62 FunctionSection: []wasm.Index{0}, 63 CodeSection: []wasm.Code{{Body: []byte{wasm.OpcodeEnd}}}, 64 }, 65 expected: &compilationResult{ 66 Operations: []unionOperation{ // begin with params: [] 67 newOperationBr(newLabel(labelKindReturn, 0)), // return! 68 }, 69 LabelCallers: map[label]uint32{}, 70 Functions: []uint32{0}, 71 Types: []wasm.FunctionType{v_v}, 72 }, 73 }, 74 { 75 name: "identity", 76 module: &wasm.Module{ 77 TypeSection: []wasm.FunctionType{i32_i32}, 78 FunctionSection: []wasm.Index{0}, 79 CodeSection: []wasm.Code{{Body: []byte{wasm.OpcodeLocalGet, 0, wasm.OpcodeEnd}}}, 80 }, 81 expected: &compilationResult{ 82 Operations: []unionOperation{ // begin with params: [$x] 83 newOperationPick(0, false), // [$x, $x] 84 newOperationDrop(inclusiveRange{Start: 1, End: 1}), // [$x] 85 newOperationBr(newLabel(labelKindReturn, 0)), // return! 86 }, 87 LabelCallers: map[label]uint32{}, 88 Types: []wasm.FunctionType{ 89 { 90 Params: []wasm.ValueType{i32}, Results: []wasm.ValueType{i32}, 91 ParamNumInUint64: 1, 92 ResultNumInUint64: 1, 93 }, 94 }, 95 Functions: []uint32{0}, 96 }, 97 }, 98 { 99 name: "uses memory", 100 module: &wasm.Module{ 101 TypeSection: []wasm.FunctionType{v_v}, 102 FunctionSection: []wasm.Index{0}, 103 CodeSection: []wasm.Code{{Body: []byte{ 104 wasm.OpcodeI32Const, 8, // memory offset to load 105 wasm.OpcodeI32Load, 0x2, 0x0, // load alignment=2 (natural alignment) staticOffset=0 106 wasm.OpcodeDrop, 107 wasm.OpcodeEnd, 108 }}}, 109 }, 110 expected: &compilationResult{ 111 Operations: []unionOperation{ // begin with params: [] 112 newOperationConstI32(8), // [8] 113 newOperationLoad(unsignedTypeI32, memoryArg{Alignment: 2, Offset: 0}), // [x] 114 newOperationDrop(inclusiveRange{}), // [] 115 newOperationBr(newLabel(labelKindReturn, 0)), // return! 116 }, 117 LabelCallers: map[label]uint32{}, 118 Types: []wasm.FunctionType{v_v}, 119 Functions: []uint32{0}, 120 UsesMemory: true, 121 }, 122 }, 123 { 124 name: "host uses memory", 125 module: &wasm.Module{ 126 TypeSection: []wasm.FunctionType{v_v}, 127 FunctionSection: []wasm.Index{0}, 128 CodeSection: []wasm.Code{{Body: []byte{ 129 wasm.OpcodeI32Const, 8, // memory offset to load 130 wasm.OpcodeI32Load, 0x2, 0x0, // load alignment=2 (natural alignment) staticOffset=0 131 wasm.OpcodeDrop, 132 wasm.OpcodeEnd, 133 }}}, 134 }, 135 expected: &compilationResult{ 136 Operations: []unionOperation{ // begin with params: [] 137 newOperationConstI32(8), // [8] 138 newOperationLoad(unsignedTypeI32, memoryArg{Alignment: 2, Offset: 0}), // [x] 139 newOperationDrop(inclusiveRange{}), // [] 140 newOperationBr(newLabel(labelKindReturn, 0)), // return! 141 }, 142 LabelCallers: map[label]uint32{}, 143 Types: []wasm.FunctionType{v_v}, 144 Functions: []uint32{0}, 145 UsesMemory: true, 146 }, 147 }, 148 { 149 name: "memory.grow", // Ex to expose ops to grow memory 150 module: &wasm.Module{ 151 TypeSection: []wasm.FunctionType{i32_i32}, 152 FunctionSection: []wasm.Index{0}, 153 CodeSection: []wasm.Code{{Body: []byte{ 154 wasm.OpcodeLocalGet, 0, wasm.OpcodeMemoryGrow, 0, wasm.OpcodeEnd, 155 }}}, 156 }, 157 expected: &compilationResult{ 158 Operations: []unionOperation{ // begin with params: [$delta] 159 newOperationPick(0, false), // [$delta, $delta] 160 newOperationMemoryGrow(), // [$delta, $old_size] 161 newOperationDrop(inclusiveRange{Start: 1, End: 1}), // [$old_size] 162 newOperationBr(newLabel(labelKindReturn, 0)), // return! 163 }, 164 LabelCallers: map[label]uint32{}, 165 Types: []wasm.FunctionType{{ 166 Params: []wasm.ValueType{i32}, Results: []wasm.ValueType{i32}, 167 ParamNumInUint64: 1, 168 ResultNumInUint64: 1, 169 }}, 170 Functions: []uint32{0}, 171 UsesMemory: true, 172 }, 173 }, 174 } 175 176 for _, tt := range tests { 177 tc := tt 178 179 t.Run(tc.name, func(t *testing.T) { 180 enabledFeatures := tc.enabledFeatures 181 if enabledFeatures == 0 { 182 enabledFeatures = api.CoreFeaturesV2 183 } 184 for _, tp := range tc.module.TypeSection { 185 tp.CacheNumInUint64() 186 } 187 c, err := newCompiler(enabledFeatures, 0, tc.module, false) 188 require.NoError(t, err) 189 190 fn, err := c.Next() 191 require.NoError(t, err) 192 require.Equal(t, tc.expected, fn) 193 }) 194 } 195 } 196 197 func TestCompile_Block(t *testing.T) { 198 tests := []struct { 199 name string 200 module *wasm.Module 201 expected *compilationResult 202 enabledFeatures api.CoreFeatures 203 }{ 204 { 205 name: "type-i32-i32", 206 module: &wasm.Module{ 207 TypeSection: []wasm.FunctionType{v_v}, 208 FunctionSection: []wasm.Index{0}, 209 CodeSection: []wasm.Code{{Body: []byte{ 210 wasm.OpcodeBlock, 0x40, 211 wasm.OpcodeBr, 0, 212 wasm.OpcodeI32Add, 213 wasm.OpcodeDrop, 214 wasm.OpcodeEnd, 215 wasm.OpcodeEnd, 216 }}}, 217 }, 218 // Above set manually until the text compiler supports this: 219 // (func (export "type-i32-i32") (block (drop (i32.add (br 0))))) 220 expected: &compilationResult{ 221 Operations: []unionOperation{ // begin with params: [] 222 newOperationBr(newLabel(labelKindContinuation, 2)), // arbitrary FrameID 223 newOperationLabel(newLabel(labelKindContinuation, 2)), // arbitrary FrameID 224 newOperationBr(newLabel(labelKindReturn, 0)), 225 }, 226 // Note: i32.add comes after br 0 so is unreachable. Compilation succeeds when it feels like it 227 // shouldn't because the br instruction is stack-polymorphic. In other words, (br 0) substitutes for the 228 // two i32 parameters to add. 229 LabelCallers: map[label]uint32{newLabel(labelKindContinuation, 2): 1}, 230 Functions: []uint32{0}, 231 Types: []wasm.FunctionType{v_v}, 232 }, 233 }, 234 } 235 236 for _, tt := range tests { 237 tc := tt 238 239 t.Run(tc.name, func(t *testing.T) { 240 requireCompilationResult(t, tc.enabledFeatures, tc.expected, tc.module) 241 }) 242 } 243 } 244 245 // TestCompile_BulkMemoryOperations uses the example from the "bulk-memory-operations" overview. 246 func TestCompile_BulkMemoryOperations(t *testing.T) { 247 // Set manually until the text compiler supports this: 248 // (module 249 // (memory 1) 250 // (data (i32.const 0) "hello") ;; data segment 0, is active so always copied 251 // (data "goodbye") ;; data segment 1, is passive 252 // 253 // (func $start 254 // ;; copy data segment 1 into memory 0 (the 0 is implicit) 255 // (memory.init 1 256 // (i32.const 16) ;; target offset 257 // (i32.const 0) ;; source offset 258 // (i32.const 7)) ;; length 259 // 260 // ;; The memory used by this segment is no longer needed, so this segment can 261 // ;; be dropped. 262 // (data.drop 1) 263 // ) 264 // (start $start) 265 // ) 266 two := uint32(2) 267 module := &wasm.Module{ 268 TypeSection: []wasm.FunctionType{v_v}, 269 FunctionSection: []wasm.Index{0}, 270 MemorySection: &wasm.Memory{Min: 1}, 271 DataSection: []wasm.DataSegment{ 272 { 273 OffsetExpression: wasm.ConstantExpression{ 274 Opcode: wasm.OpcodeI32Const, 275 Data: []byte{0x00}, 276 }, 277 Init: []byte("hello"), 278 }, 279 { 280 Passive: true, 281 Init: []byte("goodbye"), 282 }, 283 }, 284 DataCountSection: &two, 285 CodeSection: []wasm.Code{{Body: []byte{ 286 wasm.OpcodeI32Const, 16, 287 wasm.OpcodeI32Const, 0, 288 wasm.OpcodeI32Const, 7, 289 wasm.OpcodeMiscPrefix, wasm.OpcodeMiscMemoryInit, 1, 0, // segment 1, memory 0 290 wasm.OpcodeMiscPrefix, wasm.OpcodeMiscDataDrop, 1, 291 wasm.OpcodeEnd, 292 }}}, 293 } 294 295 expected := &compilationResult{ 296 Operations: []unionOperation{ // begin with params: [] 297 newOperationConstI32(16), // [16] 298 newOperationConstI32(0), // [16, 0] 299 newOperationConstI32(7), // [16, 0, 7] 300 newOperationMemoryInit(1), // [] 301 newOperationDataDrop(1), // [] 302 newOperationBr(newLabel(labelKindReturn, 0)), // return! 303 }, 304 Memory: memoryTypeStandard, 305 UsesMemory: true, 306 HasDataInstances: true, 307 LabelCallers: map[label]uint32{}, 308 Functions: []wasm.Index{0}, 309 Types: []wasm.FunctionType{v_v}, 310 } 311 312 c, err := newCompiler(api.CoreFeatureBulkMemoryOperations, 0, module, false) 313 require.NoError(t, err) 314 315 actual, err := c.Next() 316 require.NoError(t, err) 317 require.Equal(t, expected, actual) 318 } 319 320 func TestCompile_MultiValue(t *testing.T) { 321 i32i32_i32i32 := wasm.FunctionType{ 322 Params: []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, 323 Results: []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32}, 324 ParamNumInUint64: 2, 325 ResultNumInUint64: 2, 326 } 327 _i32i64 := wasm.FunctionType{ 328 Results: []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI64}, 329 ParamNumInUint64: 0, 330 ResultNumInUint64: 2, 331 } 332 333 tests := []struct { 334 name string 335 module *wasm.Module 336 expected *compilationResult 337 enabledFeatures api.CoreFeatures 338 }{ 339 { 340 name: "swap", 341 module: &wasm.Module{ 342 TypeSection: []wasm.FunctionType{i32i32_i32i32}, 343 FunctionSection: []wasm.Index{0}, 344 CodeSection: []wasm.Code{{Body: []byte{ 345 // (func (param $x i32) (param $y i32) (result i32 i32) local.get 1 local.get 0) 346 wasm.OpcodeLocalGet, 1, wasm.OpcodeLocalGet, 0, wasm.OpcodeEnd, 347 }}}, 348 }, 349 expected: &compilationResult{ 350 Operations: []unionOperation{ // begin with params: [$x, $y] 351 newOperationPick(0, false), // [$x, $y, $y] 352 newOperationPick(2, false), // [$x, $y, $y, $x] 353 newOperationDrop(inclusiveRange{Start: 2, End: 3}), // [$y, $x] 354 newOperationBr(newLabel(labelKindReturn, 0)), // return! 355 }, 356 LabelCallers: map[label]uint32{}, 357 Functions: []wasm.Index{0}, 358 Types: []wasm.FunctionType{i32i32_i32i32}, 359 }, 360 }, 361 { 362 name: "br.wast - type-f64-f64-value", 363 module: &wasm.Module{ 364 TypeSection: []wasm.FunctionType{v_f64f64}, 365 FunctionSection: []wasm.Index{0}, 366 CodeSection: []wasm.Code{{Body: []byte{ 367 wasm.OpcodeBlock, 0, // (block (result f64 f64) 368 wasm.OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0x10, 0x40, // (f64.const 4) 369 wasm.OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0x14, 0x40, // (f64.const 5) 370 wasm.OpcodeBr, 0, 371 wasm.OpcodeF64Add, 372 wasm.OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0x18, 0x40, // (f64.const 6) 373 wasm.OpcodeEnd, 374 wasm.OpcodeEnd, 375 }}}, 376 }, 377 // Above set manually until the text compiler supports this: 378 // (func $type-f64-f64-value (result f64 f64) 379 // (block (result f64 f64) 380 // (f64.add (br 0 (f64.const 4) (f64.const 5))) (f64.const 6) 381 // ) 382 // ) 383 expected: &compilationResult{ 384 Operations: []unionOperation{ // begin with params: [] 385 newOperationConstF64(4), // [4] 386 newOperationConstF64(5), // [4, 5] 387 newOperationBr(newLabel(labelKindContinuation, 2)), // arbitrary FrameID 388 newOperationLabel(newLabel(labelKindContinuation, 2)), // arbitrary FrameID 389 newOperationBr(newLabel(labelKindReturn, 0)), // return! 390 }, 391 // Note: f64.add comes after br 0 so is unreachable. This is why neither the add, nor its other operand 392 // are in the above compilation result. 393 LabelCallers: map[label]uint32{newLabel(labelKindContinuation, 2): 1}, // arbitrary label 394 Functions: []wasm.Index{0}, 395 Types: []wasm.FunctionType{v_f64f64}, 396 }, 397 }, 398 { 399 name: "call.wast - $const-i32-i64", 400 module: &wasm.Module{ 401 TypeSection: []wasm.FunctionType{_i32i64}, 402 FunctionSection: []wasm.Index{0}, 403 CodeSection: []wasm.Code{{Body: []byte{ 404 // (func $const-i32-i64 (result i32 i64) i32.const 306 i64.const 356) 405 wasm.OpcodeI32Const, 0xb2, 0x2, wasm.OpcodeI64Const, 0xe4, 0x2, wasm.OpcodeEnd, 406 }}}, 407 }, 408 expected: &compilationResult{ 409 Operations: []unionOperation{ // begin with params: [] 410 newOperationConstI32(306), // [306] 411 newOperationConstI64(356), // [306, 356] 412 newOperationBr(newLabel(labelKindReturn, 0)), // return! 413 }, 414 LabelCallers: map[label]uint32{}, 415 Functions: []wasm.Index{0}, 416 Types: []wasm.FunctionType{_i32i64}, 417 }, 418 }, 419 { 420 name: "if.wast - param", 421 module: &wasm.Module{ 422 TypeSection: []wasm.FunctionType{i32_i32}, // (func (param i32) (result i32) 423 FunctionSection: []wasm.Index{0}, 424 CodeSection: []wasm.Code{{Body: []byte{ 425 wasm.OpcodeI32Const, 1, // (i32.const 1) 426 wasm.OpcodeLocalGet, 0, wasm.OpcodeIf, 0, // (if (param i32) (result i32) (local.get 0) 427 wasm.OpcodeI32Const, 2, wasm.OpcodeI32Add, // (then (i32.const 2) (i32.add)) 428 wasm.OpcodeElse, wasm.OpcodeI32Const, 0x7e, wasm.OpcodeI32Add, // (else (i32.const -2) (i32.add)) 429 wasm.OpcodeEnd, // ) 430 wasm.OpcodeEnd, // ) 431 }}}, 432 }, 433 // Above set manually until the text compiler supports this: 434 // (func (export "param") (param i32) (result i32) 435 // (i32.const 1) 436 // (if (param i32) (result i32) (local.get 0) 437 // (then (i32.const 2) (i32.add)) 438 // (else (i32.const -2) (i32.add)) 439 // ) 440 // ) 441 expected: &compilationResult{ 442 Operations: []unionOperation{ // begin with params: [$0] 443 newOperationConstI32(1), // [$0, 1] 444 newOperationPick(1, false), // [$0, 1, $0] 445 newOperationBrIf( // [$0, 1] 446 newLabel(labelKindHeader, 2), 447 newLabel(labelKindElse, 2), 448 nopinclusiveRange, 449 ), 450 newOperationLabel(newLabel(labelKindHeader, 2)), 451 newOperationConstI32(2), // [$0, 1, 2] 452 newOperationAdd(unsignedTypeI32), // [$0, 3] 453 newOperationBr(newLabel(labelKindContinuation, 2)), 454 newOperationLabel(newLabel(labelKindElse, 2)), 455 newOperationConstI32(uint32(api.EncodeI32(-2))), // [$0, 1, -2] 456 newOperationAdd(unsignedTypeI32), // [$0, -1] 457 newOperationBr(newLabel(labelKindContinuation, 2)), 458 newOperationLabel(newLabel(labelKindContinuation, 2)), 459 newOperationDrop(inclusiveRange{Start: 1, End: 1}), // .L2 = [3], .L2_else = [-1] 460 newOperationBr(newLabel(labelKindReturn, 0)), 461 }, 462 LabelCallers: map[label]uint32{ 463 newLabel(labelKindHeader, 2): 1, 464 newLabel(labelKindContinuation, 2): 2, 465 newLabel(labelKindElse, 2): 1, 466 }, 467 Functions: []wasm.Index{0}, 468 Types: []wasm.FunctionType{i32_i32}, 469 }, 470 }, 471 { 472 name: "if.wast - params", 473 module: &wasm.Module{ 474 TypeSection: []wasm.FunctionType{ 475 i32_i32, // (func (param i32) (result i32) 476 i32i32_i32, // (if (param i32 i32) (result i32) 477 }, 478 FunctionSection: []wasm.Index{0}, 479 CodeSection: []wasm.Code{{Body: []byte{ 480 wasm.OpcodeI32Const, 1, // (i32.const 1) 481 wasm.OpcodeI32Const, 2, // (i32.const 2) 482 wasm.OpcodeLocalGet, 0, wasm.OpcodeIf, 1, // (if (param i32) (result i32) (local.get 0) 483 wasm.OpcodeI32Add, // (then (i32.add)) 484 wasm.OpcodeElse, wasm.OpcodeI32Sub, // (else (i32.sub)) 485 wasm.OpcodeEnd, // ) 486 wasm.OpcodeEnd, // ) 487 }}}, 488 }, 489 // Above set manually until the text compiler supports this: 490 // (func (export "params") (param i32) (result i32) 491 // (i32.const 1) 492 // (i32.const 2) 493 // (if (param i32 i32) (result i32) (local.get 0) 494 // (then (i32.add)) 495 // (else (i32.sub)) 496 // ) 497 // ) 498 expected: &compilationResult{ 499 Operations: []unionOperation{ // begin with params: [$0] 500 newOperationConstI32(1), // [$0, 1] 501 newOperationConstI32(2), // [$0, 1, 2] 502 newOperationPick(2, false), // [$0, 1, 2, $0] 503 newOperationBrIf( // [$0, 1, 2] 504 newLabel(labelKindHeader, 2), 505 newLabel(labelKindElse, 2), 506 nopinclusiveRange, 507 ), 508 newOperationLabel(newLabel(labelKindHeader, 2)), 509 newOperationAdd(unsignedTypeI32), // [$0, 3] 510 newOperationBr(newLabel(labelKindContinuation, 2)), 511 newOperationLabel(newLabel(labelKindElse, 2)), 512 newOperationSub(unsignedTypeI32), // [$0, -1] 513 newOperationBr(newLabel(labelKindContinuation, 2)), 514 newOperationLabel(newLabel(labelKindContinuation, 2)), 515 newOperationDrop(inclusiveRange{Start: 1, End: 1}), // .L2 = [3], .L2_else = [-1] 516 newOperationBr(newLabel(labelKindReturn, 0)), 517 }, 518 LabelCallers: map[label]uint32{ 519 newLabel(labelKindHeader, 2): 1, 520 newLabel(labelKindContinuation, 2): 2, 521 newLabel(labelKindElse, 2): 1, 522 }, 523 Functions: []wasm.Index{0}, 524 Types: []wasm.FunctionType{i32_i32, i32i32_i32}, 525 }, 526 }, 527 { 528 name: "if.wast - params-break", 529 module: &wasm.Module{ 530 TypeSection: []wasm.FunctionType{ 531 i32_i32, // (func (param i32) (result i32) 532 i32i32_i32, // (if (param i32 i32) (result i32) 533 }, 534 FunctionSection: []wasm.Index{0}, 535 CodeSection: []wasm.Code{{Body: []byte{ 536 wasm.OpcodeI32Const, 1, // (i32.const 1) 537 wasm.OpcodeI32Const, 2, // (i32.const 2) 538 wasm.OpcodeLocalGet, 0, wasm.OpcodeIf, 1, // (if (param i32) (result i32) (local.get 0) 539 wasm.OpcodeI32Add, wasm.OpcodeBr, 0, // (then (i32.add) (br 0)) 540 wasm.OpcodeElse, wasm.OpcodeI32Sub, wasm.OpcodeBr, 0, // (else (i32.sub) (br 0)) 541 wasm.OpcodeEnd, // ) 542 wasm.OpcodeEnd, // ) 543 }}}, 544 }, 545 // Above set manually until the text compiler supports this: 546 // (func (export "params-break") (param i32) (result i32) 547 // (i32.const 1) 548 // (i32.const 2) 549 // (if (param i32 i32) (result i32) (local.get 0) 550 // (then (i32.add) (br 0)) 551 // (else (i32.sub) (br 0)) 552 // ) 553 // ) 554 expected: &compilationResult{ 555 Operations: []unionOperation{ // begin with params: [$0] 556 newOperationConstI32(1), // [$0, 1] 557 newOperationConstI32(2), // [$0, 1, 2] 558 newOperationPick(2, false), // [$0, 1, 2, $0] 559 newOperationBrIf( // [$0, 1, 2] 560 newLabel(labelKindHeader, 2), 561 newLabel(labelKindElse, 2), 562 nopinclusiveRange, 563 ), 564 newOperationLabel(newLabel(labelKindHeader, 2)), 565 newOperationAdd(unsignedTypeI32), // [$0, 3] 566 newOperationBr(newLabel(labelKindContinuation, 2)), 567 newOperationLabel(newLabel(labelKindElse, 2)), 568 newOperationSub(unsignedTypeI32), // [$0, -1] 569 newOperationBr(newLabel(labelKindContinuation, 2)), 570 newOperationLabel(newLabel(labelKindContinuation, 2)), 571 newOperationDrop(inclusiveRange{Start: 1, End: 1}), // .L2 = [3], .L2_else = [-1] 572 newOperationBr(newLabel(labelKindReturn, 0)), 573 }, 574 LabelCallers: map[label]uint32{ 575 newLabel(labelKindHeader, 2): 1, 576 newLabel(labelKindContinuation, 2): 2, 577 newLabel(labelKindElse, 2): 1, 578 }, 579 Functions: []wasm.Index{0}, 580 Types: []wasm.FunctionType{i32_i32, i32i32_i32}, 581 }, 582 }, 583 } 584 585 for _, tt := range tests { 586 tc := tt 587 588 t.Run(tc.name, func(t *testing.T) { 589 enabledFeatures := tc.enabledFeatures 590 if enabledFeatures == 0 { 591 enabledFeatures = api.CoreFeaturesV2 592 } 593 for _, tp := range tc.module.TypeSection { 594 tp.CacheNumInUint64() 595 } 596 c, err := newCompiler(enabledFeatures, 0, tc.module, false) 597 require.NoError(t, err) 598 599 actual, err := c.Next() 600 require.NoError(t, err) 601 require.Equal(t, tc.expected, actual) 602 }) 603 } 604 } 605 606 // TestCompile_NonTrappingFloatToIntConversion picks an arbitrary operator from "nontrapping-float-to-int-conversion". 607 func TestCompile_NonTrappingFloatToIntConversion(t *testing.T) { 608 module := &wasm.Module{ 609 TypeSection: []wasm.FunctionType{f32_i32}, 610 FunctionSection: []wasm.Index{0}, 611 // (func (param f32) (result i32) local.get 0 i32.trunc_sat_f32_s) 612 CodeSection: []wasm.Code{{Body: []byte{ 613 wasm.OpcodeLocalGet, 0, wasm.OpcodeMiscPrefix, wasm.OpcodeMiscI32TruncSatF32S, wasm.OpcodeEnd, 614 }}}, 615 } 616 617 expected := &compilationResult{ 618 Operations: []unionOperation{ // begin with params: [$0] 619 newOperationPick(0, false), // [$0, $0] 620 newOperationITruncFromF( // [$0, i32.trunc_sat_f32_s($0)] 621 f32, 622 signedInt32, 623 true, 624 ), 625 newOperationDrop(inclusiveRange{Start: 1, End: 1}), // [i32.trunc_sat_f32_s($0)] 626 newOperationBr(newLabel(labelKindReturn, 0)), // return! 627 }, 628 LabelCallers: map[label]uint32{}, 629 Functions: []wasm.Index{0}, 630 Types: []wasm.FunctionType{f32_i32}, 631 } 632 c, err := newCompiler(api.CoreFeatureNonTrappingFloatToIntConversion, 0, module, false) 633 require.NoError(t, err) 634 635 actual, err := c.Next() 636 require.NoError(t, err) 637 require.Equal(t, expected, actual) 638 } 639 640 // TestCompile_SignExtensionOps picks an arbitrary operator from "sign-extension-ops". 641 func TestCompile_SignExtensionOps(t *testing.T) { 642 module := &wasm.Module{ 643 TypeSection: []wasm.FunctionType{i32_i32}, 644 FunctionSection: []wasm.Index{0}, 645 CodeSection: []wasm.Code{{Body: []byte{ 646 wasm.OpcodeLocalGet, 0, wasm.OpcodeI32Extend8S, wasm.OpcodeEnd, 647 }}}, 648 } 649 650 expected := &compilationResult{ 651 Operations: []unionOperation{ // begin with params: [$0] 652 newOperationPick(0, false), // [$0, $0] 653 newOperationSignExtend32From8(), // [$0, i32.extend8_s($0)] 654 newOperationDrop(inclusiveRange{Start: 1, End: 1}), // [i32.extend8_s($0)] 655 newOperationBr(newLabel(labelKindReturn, 0)), // return! 656 }, 657 LabelCallers: map[label]uint32{}, 658 Functions: []wasm.Index{0}, 659 Types: []wasm.FunctionType{i32_i32}, 660 } 661 c, err := newCompiler(api.CoreFeatureSignExtensionOps, 0, module, false) 662 require.NoError(t, err) 663 664 actual, err := c.Next() 665 require.NoError(t, err) 666 require.Equal(t, expected, actual) 667 } 668 669 func requireCompilationResult(t *testing.T, enabledFeatures api.CoreFeatures, expected *compilationResult, module *wasm.Module) { 670 if enabledFeatures == 0 { 671 enabledFeatures = api.CoreFeaturesV2 672 } 673 c, err := newCompiler(enabledFeatures, 0, module, false) 674 require.NoError(t, err) 675 676 actual, err := c.Next() 677 require.NoError(t, err) 678 679 require.NoError(t, err) 680 require.Equal(t, expected, actual) 681 } 682 683 func TestCompile_CallIndirectNonZeroTableIndex(t *testing.T) { 684 module := &wasm.Module{ 685 TypeSection: []wasm.FunctionType{v_v, v_v, v_v}, 686 FunctionSection: []wasm.Index{0}, 687 CodeSection: []wasm.Code{{Body: []byte{ 688 wasm.OpcodeI32Const, 0, // call indirect offset 689 wasm.OpcodeCallIndirect, 690 2, // Type index for call_indirect. 691 5, // Non-zero table index for call_indirect. 692 wasm.OpcodeEnd, 693 }}}, 694 TableSection: []wasm.Table{ 695 {Type: wasm.RefTypeExternref}, 696 {Type: wasm.RefTypeFuncref}, 697 {Type: wasm.RefTypeFuncref}, 698 {Type: wasm.RefTypeFuncref}, 699 {Type: wasm.RefTypeFuncref}, 700 {Type: wasm.RefTypeFuncref, Min: 100}, 701 }, 702 } 703 704 expected := &compilationResult{ 705 Operations: []unionOperation{ // begin with params: [] 706 newOperationConstI32(0), 707 newOperationCallIndirect(2, 5), 708 newOperationBr(newLabel(labelKindReturn, 0)), // return! 709 }, 710 HasTable: true, 711 LabelCallers: map[label]uint32{}, 712 Functions: []wasm.Index{0}, 713 Types: []wasm.FunctionType{v_v, v_v, v_v}, 714 } 715 716 c, err := newCompiler(api.CoreFeatureBulkMemoryOperations, 0, module, false) 717 require.NoError(t, err) 718 719 actual, err := c.Next() 720 require.NoError(t, err) 721 require.Equal(t, expected, actual) 722 } 723 724 func TestCompile_Refs(t *testing.T) { 725 tests := []struct { 726 name string 727 body []byte 728 expected []unionOperation 729 }{ 730 { 731 name: "ref.func", 732 body: []byte{ 733 wasm.OpcodeRefFunc, 100, 734 wasm.OpcodeDrop, 735 wasm.OpcodeEnd, 736 }, 737 expected: []unionOperation{ 738 newOperationRefFunc(100), 739 newOperationDrop(inclusiveRange{Start: 0, End: 0}), 740 newOperationBr(newLabel(labelKindReturn, 0)), // return! 741 }, 742 }, 743 { 744 name: "ref.null (externref)", 745 body: []byte{ 746 wasm.OpcodeRefNull, wasm.ValueTypeExternref, 747 wasm.OpcodeDrop, 748 wasm.OpcodeEnd, 749 }, 750 expected: []unionOperation{ 751 newOperationConstI64(0), 752 newOperationDrop(inclusiveRange{Start: 0, End: 0}), 753 newOperationBr(newLabel(labelKindReturn, 0)), // return! 754 }, 755 }, 756 { 757 name: "ref.null (funcref)", 758 body: []byte{ 759 wasm.OpcodeRefNull, wasm.ValueTypeFuncref, 760 wasm.OpcodeDrop, 761 wasm.OpcodeEnd, 762 }, 763 expected: []unionOperation{ 764 newOperationConstI64(0), 765 newOperationDrop(inclusiveRange{Start: 0, End: 0}), 766 newOperationBr(newLabel(labelKindReturn, 0)), // return! 767 }, 768 }, 769 { 770 name: "ref.is_null", 771 body: []byte{ 772 wasm.OpcodeRefFunc, 100, 773 wasm.OpcodeRefIsNull, 774 wasm.OpcodeDrop, 775 wasm.OpcodeEnd, 776 }, 777 expected: []unionOperation{ 778 newOperationRefFunc(100), 779 newOperationEqz(unsignedInt64), 780 newOperationDrop(inclusiveRange{Start: 0, End: 0}), 781 newOperationBr(newLabel(labelKindReturn, 0)), // return! 782 }, 783 }, 784 { 785 name: "ref.is_null (externref)", 786 body: []byte{ 787 wasm.OpcodeRefNull, wasm.ValueTypeExternref, 788 wasm.OpcodeRefIsNull, 789 wasm.OpcodeDrop, 790 wasm.OpcodeEnd, 791 }, 792 expected: []unionOperation{ 793 newOperationConstI64(0), 794 newOperationEqz(unsignedInt64), 795 newOperationDrop(inclusiveRange{Start: 0, End: 0}), 796 newOperationBr(newLabel(labelKindReturn, 0)), // return! 797 }, 798 }, 799 } 800 801 for _, tt := range tests { 802 tc := tt 803 t.Run(tc.name, func(t *testing.T) { 804 module := &wasm.Module{ 805 TypeSection: []wasm.FunctionType{v_v}, 806 FunctionSection: []wasm.Index{0}, 807 CodeSection: []wasm.Code{{Body: tc.body}}, 808 } 809 c, err := newCompiler(api.CoreFeaturesV2, 0, module, false) 810 require.NoError(t, err) 811 812 actual, err := c.Next() 813 require.NoError(t, err) 814 require.Equal(t, tc.expected, actual.Operations) 815 }) 816 } 817 } 818 819 func TestCompile_TableGetOrSet(t *testing.T) { 820 tests := []struct { 821 name string 822 body []byte 823 expected []unionOperation 824 }{ 825 { 826 name: "table.get", 827 body: []byte{ 828 wasm.OpcodeI32Const, 10, 829 wasm.OpcodeTableGet, 0, 830 wasm.OpcodeDrop, 831 wasm.OpcodeEnd, 832 }, 833 expected: []unionOperation{ 834 newOperationConstI32(10), 835 newOperationTableGet(0), 836 newOperationDrop(inclusiveRange{Start: 0, End: 0}), 837 newOperationBr(newLabel(labelKindReturn, 0)), // return! 838 }, 839 }, 840 { 841 name: "table.set (externref)", 842 body: []byte{ 843 wasm.OpcodeI32Const, 10, 844 wasm.OpcodeRefNull, wasm.ValueTypeExternref, 845 wasm.OpcodeTableSet, 0, 846 wasm.OpcodeEnd, 847 }, 848 expected: []unionOperation{ 849 newOperationConstI32(10), 850 newOperationConstI64(0), 851 newOperationTableSet(0), 852 newOperationBr(newLabel(labelKindReturn, 0)), // return! 853 }, 854 }, 855 { 856 name: "table.set (funcref)", 857 body: []byte{ 858 wasm.OpcodeI32Const, 10, 859 wasm.OpcodeRefFunc, 1, 860 wasm.OpcodeTableSet, 0, 861 wasm.OpcodeEnd, 862 }, 863 expected: []unionOperation{ 864 newOperationConstI32(10), 865 newOperationRefFunc(1), 866 newOperationTableSet(0), 867 newOperationBr(newLabel(labelKindReturn, 0)), // return! 868 }, 869 }, 870 } 871 872 for _, tt := range tests { 873 tc := tt 874 t.Run(tc.name, func(t *testing.T) { 875 module := &wasm.Module{ 876 TypeSection: []wasm.FunctionType{v_v}, 877 FunctionSection: []wasm.Index{0}, 878 CodeSection: []wasm.Code{{Body: tc.body}}, 879 TableSection: []wasm.Table{{}}, 880 } 881 c, err := newCompiler(api.CoreFeaturesV2, 0, module, false) 882 require.NoError(t, err) 883 884 actual, err := c.Next() 885 require.NoError(t, err) 886 require.Equal(t, tc.expected, actual.Operations) 887 }) 888 } 889 } 890 891 func TestCompile_TableGrowFillSize(t *testing.T) { 892 tests := []struct { 893 name string 894 body []byte 895 expected []unionOperation 896 }{ 897 { 898 name: "table.grow", 899 body: []byte{ 900 wasm.OpcodeRefNull, wasm.RefTypeFuncref, 901 wasm.OpcodeI32Const, 1, 902 wasm.OpcodeMiscPrefix, wasm.OpcodeMiscTableGrow, 1, 903 wasm.OpcodeEnd, 904 }, 905 expected: []unionOperation{ 906 newOperationConstI64(0), // Null ref. 907 newOperationConstI32(1), 908 newOperationTableGrow(1), 909 newOperationDrop(inclusiveRange{Start: 0, End: 0}), 910 newOperationBr(newLabel(labelKindReturn, 0)), // return! 911 }, 912 }, 913 { 914 name: "table.fill", 915 body: []byte{ 916 wasm.OpcodeI32Const, 10, 917 wasm.OpcodeRefNull, wasm.RefTypeFuncref, 918 wasm.OpcodeI32Const, 1, 919 wasm.OpcodeMiscPrefix, wasm.OpcodeMiscTableFill, 1, 920 wasm.OpcodeEnd, 921 }, 922 expected: []unionOperation{ 923 newOperationConstI32(10), 924 newOperationConstI64(0), // Null ref. 925 newOperationConstI32(1), 926 newOperationTableFill(1), 927 newOperationBr(newLabel(labelKindReturn, 0)), // return! 928 }, 929 }, 930 { 931 name: "table.size", 932 body: []byte{ 933 wasm.OpcodeMiscPrefix, wasm.OpcodeMiscTableSize, 1, 934 wasm.OpcodeEnd, 935 }, 936 expected: []unionOperation{ 937 newOperationTableSize(1), 938 newOperationDrop(inclusiveRange{Start: 0, End: 0}), 939 newOperationBr(newLabel(labelKindReturn, 0)), // return! 940 }, 941 }, 942 } 943 944 for _, tt := range tests { 945 tc := tt 946 t.Run(tc.name, func(t *testing.T) { 947 module := &wasm.Module{ 948 TypeSection: []wasm.FunctionType{v_v}, 949 FunctionSection: []wasm.Index{0}, 950 CodeSection: []wasm.Code{{Body: tc.body}}, 951 TableSection: []wasm.Table{{}}, 952 } 953 c, err := newCompiler(api.CoreFeaturesV2, 0, module, false) 954 require.NoError(t, err) 955 956 actual, err := c.Next() 957 require.NoError(t, err) 958 require.Equal(t, tc.expected, actual.Operations) 959 require.True(t, actual.HasTable) 960 }) 961 } 962 } 963 964 func TestCompile_Locals(t *testing.T) { 965 tests := []struct { 966 name string 967 mod *wasm.Module 968 expected []unionOperation 969 }{ 970 { 971 name: "local.get - func param - v128", 972 mod: &wasm.Module{ 973 TypeSection: []wasm.FunctionType{{Params: []wasm.ValueType{wasm.ValueTypeV128}}}, 974 FunctionSection: []wasm.Index{0}, 975 CodeSection: []wasm.Code{{Body: []byte{ 976 wasm.OpcodeLocalGet, 0, 977 wasm.OpcodeEnd, 978 }}}, 979 }, 980 expected: []unionOperation{ 981 newOperationPick(1, true), // [param[0].low, param[0].high] -> [param[0].low, param[0].high, param[0].low, param[0].high] 982 newOperationDrop(inclusiveRange{Start: 0, End: 3}), 983 newOperationBr(newLabel(labelKindReturn, 0)), // return! 984 }, 985 }, 986 { 987 name: "local.get - func param - i64", 988 mod: &wasm.Module{ 989 TypeSection: []wasm.FunctionType{{Params: []wasm.ValueType{wasm.ValueTypeI64}}}, 990 FunctionSection: []wasm.Index{0}, 991 CodeSection: []wasm.Code{{Body: []byte{ 992 wasm.OpcodeLocalGet, 0, 993 wasm.OpcodeEnd, 994 }}}, 995 }, 996 expected: []unionOperation{ 997 newOperationPick(0, false), // [param[0]] -> [param[0], param[0]] 998 newOperationDrop(inclusiveRange{Start: 0, End: 1}), 999 newOperationBr(newLabel(labelKindReturn, 0)), // return! 1000 }, 1001 }, 1002 { 1003 name: "local.get - non func param - v128", 1004 mod: &wasm.Module{ 1005 TypeSection: []wasm.FunctionType{v_v}, 1006 FunctionSection: []wasm.Index{0}, 1007 CodeSection: []wasm.Code{{ 1008 Body: []byte{ 1009 wasm.OpcodeLocalGet, 0, 1010 wasm.OpcodeEnd, 1011 }, 1012 LocalTypes: []wasm.ValueType{wasm.ValueTypeV128}, 1013 }}, 1014 }, 1015 expected: []unionOperation{ 1016 newOperationV128Const(0, 0), 1017 newOperationPick(1, true), // [p[0].low, p[0].high] -> [p[0].low, p[0].high, p[0].low, p[0].high] 1018 newOperationDrop(inclusiveRange{Start: 0, End: 3}), 1019 newOperationBr(newLabel(labelKindReturn, 0)), // return! 1020 }, 1021 }, 1022 { 1023 name: "local.set - func param - v128", 1024 mod: &wasm.Module{ 1025 TypeSection: []wasm.FunctionType{{Params: []wasm.ValueType{wasm.ValueTypeV128}}}, 1026 FunctionSection: []wasm.Index{0}, 1027 CodeSection: []wasm.Code{{Body: []byte{ 1028 wasm.OpcodeVecPrefix, wasm.OpcodeVecV128Const, // [] -> [0x01, 0x02] 1029 1, 0, 0, 0, 0, 0, 0, 0, 1030 2, 0, 0, 0, 0, 0, 0, 0, 1031 wasm.OpcodeLocalSet, 0, // [0x01, 0x02] -> [] 1032 wasm.OpcodeEnd, 1033 }}}, 1034 }, 1035 expected: []unionOperation{ 1036 // [p[0].lo, p[1].hi] -> [p[0].lo, p[1].hi, 0x01, 0x02] 1037 newOperationV128Const(0x01, 0x02), 1038 // [p[0].lo, p[1].hi, 0x01, 0x02] -> [0x01, 0x02] 1039 newOperationSet(3, true), 1040 newOperationDrop(inclusiveRange{Start: 0, End: 1}), 1041 newOperationBr(newLabel(labelKindReturn, 0)), // return! 1042 }, 1043 }, 1044 { 1045 name: "local.set - func param - i32", 1046 mod: &wasm.Module{ 1047 TypeSection: []wasm.FunctionType{{Params: []wasm.ValueType{wasm.ValueTypeI32}}}, 1048 FunctionSection: []wasm.Index{0}, 1049 CodeSection: []wasm.Code{{Body: []byte{ 1050 wasm.OpcodeI32Const, 0x1, // [] -> [0x01] 1051 wasm.OpcodeLocalSet, 0, // [0x01] -> [] 1052 wasm.OpcodeEnd, 1053 }}}, 1054 }, 1055 expected: []unionOperation{ 1056 newOperationConstI32(0x1), 1057 newOperationSet(1, false), 1058 newOperationDrop(inclusiveRange{Start: 0, End: 0}), 1059 newOperationBr(newLabel(labelKindReturn, 0)), // return! 1060 }, 1061 }, 1062 { 1063 name: "local.set - non func param - v128", 1064 mod: &wasm.Module{ 1065 TypeSection: []wasm.FunctionType{v_v}, 1066 FunctionSection: []wasm.Index{0}, 1067 CodeSection: []wasm.Code{{ 1068 Body: []byte{ 1069 wasm.OpcodeVecPrefix, wasm.OpcodeVecV128Const, // [] -> [0x01, 0x02] 1070 1, 0, 0, 0, 0, 0, 0, 0, 1071 2, 0, 0, 0, 0, 0, 0, 0, 1072 wasm.OpcodeLocalSet, 0, // [0x01, 0x02] -> [] 1073 wasm.OpcodeEnd, 1074 }, 1075 LocalTypes: []wasm.ValueType{wasm.ValueTypeV128}, 1076 }}, 1077 }, 1078 expected: []unionOperation{ 1079 newOperationV128Const(0, 0), 1080 // [p[0].lo, p[1].hi] -> [p[0].lo, p[1].hi, 0x01, 0x02] 1081 newOperationV128Const(0x01, 0x02), 1082 // [p[0].lo, p[1].hi, 0x01, 0x02] -> [0x01, 0x02] 1083 newOperationSet(3, true), 1084 newOperationDrop(inclusiveRange{Start: 0, End: 1}), 1085 newOperationBr(newLabel(labelKindReturn, 0)), // return! 1086 }, 1087 }, 1088 { 1089 name: "local.tee - func param - v128", 1090 mod: &wasm.Module{ 1091 TypeSection: []wasm.FunctionType{{Params: []wasm.ValueType{wasm.ValueTypeV128}}}, 1092 FunctionSection: []wasm.Index{0}, 1093 CodeSection: []wasm.Code{{Body: []byte{ 1094 wasm.OpcodeVecPrefix, wasm.OpcodeVecV128Const, // [] -> [0x01, 0x02] 1095 1, 0, 0, 0, 0, 0, 0, 0, 1096 2, 0, 0, 0, 0, 0, 0, 0, 1097 wasm.OpcodeLocalTee, 0, // [0x01, 0x02] -> [0x01, 0x02] 1098 wasm.OpcodeEnd, 1099 }}}, 1100 }, 1101 expected: []unionOperation{ 1102 // [p[0].lo, p[1].hi] -> [p[0].lo, p[1].hi, 0x01, 0x02] 1103 newOperationV128Const(0x01, 0x02), 1104 // [p[0].lo, p[1].hi, 0x01, 0x02] -> [p[0].lo, p[1].hi, 0x01, 0x02, 0x01, 0x02] 1105 newOperationPick(1, true), 1106 // [p[0].lo, p[1].hi, 0x01, 0x02, 0x01, 0x02] -> [0x01, 0x02, 0x01, 0x02] 1107 newOperationSet(5, true), 1108 newOperationDrop(inclusiveRange{Start: 0, End: 3}), 1109 newOperationBr(newLabel(labelKindReturn, 0)), // return! 1110 }, 1111 }, 1112 { 1113 name: "local.tee - func param - f32", 1114 mod: &wasm.Module{ 1115 TypeSection: []wasm.FunctionType{{Params: []wasm.ValueType{wasm.ValueTypeF32}}}, 1116 FunctionSection: []wasm.Index{0}, 1117 CodeSection: []wasm.Code{{Body: []byte{ 1118 wasm.OpcodeF32Const, 1, 0, 0, 0, 1119 wasm.OpcodeLocalTee, 0, // [0x01, 0x02] -> [0x01, 0x02] 1120 wasm.OpcodeEnd, 1121 }}}, 1122 }, 1123 expected: []unionOperation{ 1124 newOperationConstF32(math.Float32frombits(1)), 1125 newOperationPick(0, false), 1126 newOperationSet(2, false), 1127 newOperationDrop(inclusiveRange{Start: 0, End: 1}), 1128 newOperationBr(newLabel(labelKindReturn, 0)), // return! 1129 }, 1130 }, 1131 { 1132 name: "local.tee - non func param", 1133 mod: &wasm.Module{ 1134 TypeSection: []wasm.FunctionType{v_v}, 1135 FunctionSection: []wasm.Index{0}, 1136 CodeSection: []wasm.Code{{ 1137 Body: []byte{ 1138 wasm.OpcodeVecPrefix, wasm.OpcodeVecV128Const, // [] -> [0x01, 0x02] 1139 1, 0, 0, 0, 0, 0, 0, 0, 1140 2, 0, 0, 0, 0, 0, 0, 0, 1141 wasm.OpcodeLocalTee, 0, // [0x01, 0x02] -> [0x01, 0x02] 1142 wasm.OpcodeEnd, 1143 }, 1144 LocalTypes: []wasm.ValueType{wasm.ValueTypeV128}, 1145 }}, 1146 }, 1147 expected: []unionOperation{ 1148 newOperationV128Const(0, 0), 1149 // [p[0].lo, p[1].hi] -> [p[0].lo, p[1].hi, 0x01, 0x02] 1150 newOperationV128Const(0x01, 0x02), 1151 // [p[0].lo, p[1].hi, 0x01, 0x02] -> [p[0].lo, p[1].hi, 0x01, 0x02, 0x01, 0x02] 1152 newOperationPick(1, true), 1153 // [p[0].lo, p[1].hi, 0x01, 0x02, 0x01, 0x2] -> [0x01, 0x02, 0x01, 0x02] 1154 newOperationSet(5, true), 1155 newOperationDrop(inclusiveRange{Start: 0, End: 3}), 1156 newOperationBr(newLabel(labelKindReturn, 0)), // return! 1157 }, 1158 }, 1159 } 1160 1161 for _, tt := range tests { 1162 tc := tt 1163 t.Run(tc.name, func(t *testing.T) { 1164 c, err := newCompiler(api.CoreFeaturesV2, 0, tc.mod, false) 1165 require.NoError(t, err) 1166 1167 actual, err := c.Next() 1168 require.NoError(t, err) 1169 msg := fmt.Sprintf("\nhave:\n\t%s\nwant:\n\t%s", format(actual.Operations), format(tc.expected)) 1170 require.Equal(t, tc.expected, actual.Operations, msg) 1171 }) 1172 } 1173 } 1174 1175 func TestCompile_Vec(t *testing.T) { 1176 addV128Const := func(in []byte) []byte { 1177 return append(in, wasm.OpcodeVecPrefix, 1178 wasm.OpcodeVecV128Const, 1179 1, 1, 1, 1, 1, 1, 1, 1, 1180 1, 1, 1, 1, 1, 1, 1, 1) 1181 } 1182 1183 vvv2v := func(vec wasm.OpcodeVec) (ret []byte) { 1184 ret = addV128Const(ret) 1185 ret = addV128Const(ret) 1186 ret = addV128Const(ret) 1187 return append(ret, wasm.OpcodeVecPrefix, vec, wasm.OpcodeDrop, wasm.OpcodeEnd) 1188 } 1189 1190 vv2v := func(vec wasm.OpcodeVec) (ret []byte) { 1191 ret = addV128Const(ret) 1192 ret = addV128Const(ret) 1193 return append(ret, wasm.OpcodeVecPrefix, vec, wasm.OpcodeDrop, wasm.OpcodeEnd) 1194 } 1195 1196 vi2v := func(vec wasm.OpcodeVec) (ret []byte) { 1197 ret = addV128Const(ret) 1198 return append(ret, wasm.OpcodeI32Const, 1, 1199 wasm.OpcodeVecPrefix, vec, 1200 wasm.OpcodeDrop, wasm.OpcodeEnd) 1201 } 1202 1203 v2v := func(vec wasm.OpcodeVec) (ret []byte) { 1204 ret = addV128Const(ret) 1205 return append(ret, wasm.OpcodeVecPrefix, vec, wasm.OpcodeDrop, wasm.OpcodeEnd) 1206 } 1207 1208 load := func(vec wasm.OpcodeVec, offset, align uint32) (ret []byte) { 1209 ret = []byte{wasm.OpcodeI32Const, 1, 1, 1, 1, wasm.OpcodeVecPrefix, vec} 1210 ret = append(ret, leb128.EncodeUint32(align)...) 1211 ret = append(ret, leb128.EncodeUint32(offset)...) 1212 ret = append(ret, wasm.OpcodeDrop, wasm.OpcodeEnd) 1213 return 1214 } 1215 1216 loadLane := func(vec wasm.OpcodeVec, offset, align uint32, lane byte) (ret []byte) { 1217 ret = addV128Const([]byte{wasm.OpcodeI32Const, 1, 1, 1, 1}) 1218 ret = append(ret, wasm.OpcodeVecPrefix, vec) 1219 ret = append(ret, leb128.EncodeUint32(align)...) 1220 ret = append(ret, leb128.EncodeUint32(offset)...) 1221 ret = append(ret, lane, wasm.OpcodeDrop, wasm.OpcodeEnd) 1222 return 1223 } 1224 1225 storeLane := func(vec wasm.OpcodeVec, offset, align uint32, lane byte) (ret []byte) { 1226 ret = addV128Const([]byte{wasm.OpcodeI32Const, 0}) 1227 ret = append(ret, wasm.OpcodeVecPrefix, vec) 1228 ret = append(ret, leb128.EncodeUint32(align)...) 1229 ret = append(ret, leb128.EncodeUint32(offset)...) 1230 ret = append(ret, lane, wasm.OpcodeEnd) 1231 return 1232 } 1233 1234 extractLane := func(vec wasm.OpcodeVec, lane byte) (ret []byte) { 1235 ret = addV128Const(ret) 1236 ret = append(ret, wasm.OpcodeVecPrefix, vec, lane, wasm.OpcodeDrop, wasm.OpcodeEnd) 1237 return 1238 } 1239 1240 replaceLane := func(vec wasm.OpcodeVec, lane byte) (ret []byte) { 1241 ret = addV128Const(ret) 1242 1243 switch vec { 1244 case wasm.OpcodeVecI8x16ReplaceLane, wasm.OpcodeVecI16x8ReplaceLane, wasm.OpcodeVecI32x4ReplaceLane: 1245 ret = append(ret, wasm.OpcodeI32Const, 0) 1246 case wasm.OpcodeVecI64x2ReplaceLane: 1247 ret = append(ret, wasm.OpcodeI64Const, 0) 1248 case wasm.OpcodeVecF32x4ReplaceLane: 1249 ret = append(ret, wasm.OpcodeF32Const, 0, 0, 0, 0) 1250 case wasm.OpcodeVecF64x2ReplaceLane: 1251 ret = append(ret, wasm.OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0, 0) 1252 } 1253 1254 ret = append(ret, wasm.OpcodeVecPrefix, vec, lane, wasm.OpcodeDrop, wasm.OpcodeEnd) 1255 return 1256 } 1257 1258 splat := func(vec wasm.OpcodeVec) (ret []byte) { 1259 switch vec { 1260 case wasm.OpcodeVecI8x16Splat, wasm.OpcodeVecI16x8Splat, wasm.OpcodeVecI32x4Splat: 1261 ret = append(ret, wasm.OpcodeI32Const, 0) 1262 case wasm.OpcodeVecI64x2Splat: 1263 ret = append(ret, wasm.OpcodeI64Const, 0) 1264 case wasm.OpcodeVecF32x4Splat: 1265 ret = append(ret, wasm.OpcodeF32Const, 0, 0, 0, 0) 1266 case wasm.OpcodeVecF64x2Splat: 1267 ret = append(ret, wasm.OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0, 0) 1268 } 1269 ret = append(ret, wasm.OpcodeVecPrefix, vec, wasm.OpcodeDrop, wasm.OpcodeEnd) 1270 return 1271 } 1272 1273 tests := []struct { 1274 name string 1275 body []byte 1276 expected unionOperation 1277 needDropBeforeReturn bool 1278 }{ 1279 { 1280 name: "i8x16 add", 1281 needDropBeforeReturn: true, 1282 body: vv2v(wasm.OpcodeVecI8x16Add), 1283 expected: newOperationV128Add(shapeI8x16), 1284 }, 1285 { 1286 name: "i8x16 add", 1287 needDropBeforeReturn: true, 1288 body: vv2v(wasm.OpcodeVecI16x8Add), 1289 expected: newOperationV128Add(shapeI16x8), 1290 }, 1291 { 1292 name: "i32x2 add", 1293 needDropBeforeReturn: true, 1294 body: vv2v(wasm.OpcodeVecI64x2Add), 1295 expected: newOperationV128Add(shapeI64x2), 1296 }, 1297 { 1298 name: "i64x2 add", 1299 needDropBeforeReturn: true, 1300 body: vv2v(wasm.OpcodeVecI64x2Add), 1301 expected: newOperationV128Add(shapeI64x2), 1302 }, 1303 { 1304 name: "i8x16 sub", 1305 needDropBeforeReturn: true, 1306 body: vv2v(wasm.OpcodeVecI8x16Sub), 1307 expected: newOperationV128Sub(shapeI8x16), 1308 }, 1309 { 1310 name: "i16x8 sub", 1311 needDropBeforeReturn: true, 1312 body: vv2v(wasm.OpcodeVecI16x8Sub), 1313 expected: newOperationV128Sub(shapeI16x8), 1314 }, 1315 { 1316 name: "i32x2 sub", 1317 needDropBeforeReturn: true, 1318 body: vv2v(wasm.OpcodeVecI64x2Sub), 1319 expected: newOperationV128Sub(shapeI64x2), 1320 }, 1321 { 1322 name: "i64x2 sub", 1323 needDropBeforeReturn: true, 1324 body: vv2v(wasm.OpcodeVecI64x2Sub), 1325 expected: newOperationV128Sub(shapeI64x2), 1326 }, 1327 { 1328 name: wasm.OpcodeVecV128LoadName, body: load(wasm.OpcodeVecV128Load, 0, 0), 1329 needDropBeforeReturn: true, 1330 expected: newOperationV128Load(v128LoadType128, memoryArg{Alignment: 0, Offset: 0}), 1331 }, 1332 { 1333 name: wasm.OpcodeVecV128LoadName + "/align=4", body: load(wasm.OpcodeVecV128Load, 0, 4), 1334 needDropBeforeReturn: true, 1335 expected: newOperationV128Load(v128LoadType128, memoryArg{Alignment: 4, Offset: 0}), 1336 }, 1337 { 1338 name: wasm.OpcodeVecV128Load8x8SName, body: load(wasm.OpcodeVecV128Load8x8s, 1, 0), 1339 needDropBeforeReturn: true, 1340 expected: newOperationV128Load(v128LoadType8x8s, memoryArg{Alignment: 0, Offset: 1}), 1341 }, 1342 { 1343 name: wasm.OpcodeVecV128Load8x8SName + "/align=1", body: load(wasm.OpcodeVecV128Load8x8s, 0, 1), 1344 needDropBeforeReturn: true, 1345 expected: newOperationV128Load(v128LoadType8x8s, memoryArg{Alignment: 1, Offset: 0}), 1346 }, 1347 { 1348 name: wasm.OpcodeVecV128Load8x8UName, body: load(wasm.OpcodeVecV128Load8x8u, 0, 0), 1349 needDropBeforeReturn: true, 1350 expected: newOperationV128Load(v128LoadType8x8u, memoryArg{Alignment: 0, Offset: 0}), 1351 }, 1352 { 1353 name: wasm.OpcodeVecV128Load8x8UName + "/align=1", body: load(wasm.OpcodeVecV128Load8x8u, 0, 1), 1354 needDropBeforeReturn: true, 1355 expected: newOperationV128Load(v128LoadType8x8u, memoryArg{Alignment: 1, Offset: 0}), 1356 }, 1357 { 1358 name: wasm.OpcodeVecV128Load16x4SName, body: load(wasm.OpcodeVecV128Load16x4s, 1, 0), 1359 needDropBeforeReturn: true, 1360 expected: newOperationV128Load(v128LoadType16x4s, memoryArg{Alignment: 0, Offset: 1}), 1361 }, 1362 { 1363 name: wasm.OpcodeVecV128Load16x4SName + "/align=2", body: load(wasm.OpcodeVecV128Load16x4s, 0, 2), 1364 needDropBeforeReturn: true, 1365 expected: newOperationV128Load(v128LoadType16x4s, memoryArg{Alignment: 2, Offset: 0}), 1366 }, 1367 { 1368 name: wasm.OpcodeVecV128Load16x4UName, body: load(wasm.OpcodeVecV128Load16x4u, 0, 0), 1369 needDropBeforeReturn: true, 1370 expected: newOperationV128Load(v128LoadType16x4u, memoryArg{Alignment: 0, Offset: 0}), 1371 }, 1372 { 1373 name: wasm.OpcodeVecV128Load16x4UName + "/align=2", body: load(wasm.OpcodeVecV128Load16x4u, 0, 2), 1374 needDropBeforeReturn: true, 1375 expected: newOperationV128Load(v128LoadType16x4u, memoryArg{Alignment: 2, Offset: 0}), 1376 }, 1377 { 1378 name: wasm.OpcodeVecV128Load32x2SName, body: load(wasm.OpcodeVecV128Load32x2s, 1, 0), 1379 needDropBeforeReturn: true, 1380 expected: newOperationV128Load(v128LoadType32x2s, memoryArg{Alignment: 0, Offset: 1}), 1381 }, 1382 { 1383 name: wasm.OpcodeVecV128Load32x2SName + "/align=3", body: load(wasm.OpcodeVecV128Load32x2s, 0, 3), 1384 needDropBeforeReturn: true, 1385 expected: newOperationV128Load(v128LoadType32x2s, memoryArg{Alignment: 3, Offset: 0}), 1386 }, 1387 { 1388 name: wasm.OpcodeVecV128Load32x2UName, body: load(wasm.OpcodeVecV128Load32x2u, 0, 0), 1389 needDropBeforeReturn: true, 1390 expected: newOperationV128Load(v128LoadType32x2u, memoryArg{Alignment: 0, Offset: 0}), 1391 }, 1392 { 1393 name: wasm.OpcodeVecV128Load32x2UName + "/align=3", body: load(wasm.OpcodeVecV128Load32x2u, 0, 3), 1394 needDropBeforeReturn: true, 1395 expected: newOperationV128Load(v128LoadType32x2u, memoryArg{Alignment: 3, Offset: 0}), 1396 }, 1397 { 1398 name: wasm.OpcodeVecV128Load8SplatName, body: load(wasm.OpcodeVecV128Load8Splat, 2, 0), 1399 needDropBeforeReturn: true, 1400 expected: newOperationV128Load(v128LoadType8Splat, memoryArg{Alignment: 0, Offset: 2}), 1401 }, 1402 { 1403 name: wasm.OpcodeVecV128Load16SplatName, body: load(wasm.OpcodeVecV128Load16Splat, 0, 1), 1404 needDropBeforeReturn: true, 1405 expected: newOperationV128Load(v128LoadType16Splat, memoryArg{Alignment: 1, Offset: 0}), 1406 }, 1407 { 1408 name: wasm.OpcodeVecV128Load32SplatName, body: load(wasm.OpcodeVecV128Load32Splat, 3, 2), 1409 needDropBeforeReturn: true, 1410 expected: newOperationV128Load(v128LoadType32Splat, memoryArg{Alignment: 2, Offset: 3}), 1411 }, 1412 { 1413 name: wasm.OpcodeVecV128Load64SplatName, body: load(wasm.OpcodeVecV128Load64Splat, 0, 3), 1414 needDropBeforeReturn: true, 1415 expected: newOperationV128Load(v128LoadType64Splat, memoryArg{Alignment: 3, Offset: 0}), 1416 }, 1417 { 1418 name: wasm.OpcodeVecV128Load32zeroName, body: load(wasm.OpcodeVecV128Load32zero, 0, 2), 1419 needDropBeforeReturn: true, 1420 expected: newOperationV128Load(v128LoadType32zero, memoryArg{Alignment: 2, Offset: 0}), 1421 }, 1422 { 1423 name: wasm.OpcodeVecV128Load64zeroName, body: load(wasm.OpcodeVecV128Load64zero, 5, 3), 1424 needDropBeforeReturn: true, 1425 expected: newOperationV128Load(v128LoadType64zero, memoryArg{Alignment: 3, Offset: 5}), 1426 }, 1427 { 1428 name: wasm.OpcodeVecV128Load8LaneName, needDropBeforeReturn: true, 1429 body: loadLane(wasm.OpcodeVecV128Load8Lane, 5, 0, 10), 1430 expected: newOperationV128LoadLane(10, 8, memoryArg{Alignment: 0, Offset: 5}), 1431 }, 1432 { 1433 name: wasm.OpcodeVecV128Load16LaneName, needDropBeforeReturn: true, 1434 body: loadLane(wasm.OpcodeVecV128Load16Lane, 100, 1, 7), 1435 expected: newOperationV128LoadLane(7, 16, memoryArg{Alignment: 1, Offset: 100}), 1436 }, 1437 { 1438 name: wasm.OpcodeVecV128Load32LaneName, needDropBeforeReturn: true, 1439 body: loadLane(wasm.OpcodeVecV128Load32Lane, 0, 2, 3), 1440 expected: newOperationV128LoadLane(3, 32, memoryArg{Alignment: 2, Offset: 0}), 1441 }, 1442 { 1443 name: wasm.OpcodeVecV128Load64LaneName, needDropBeforeReturn: true, 1444 body: loadLane(wasm.OpcodeVecV128Load64Lane, 0, 3, 1), 1445 expected: newOperationV128LoadLane(1, 64, memoryArg{Alignment: 3, Offset: 0}), 1446 }, 1447 { 1448 name: wasm.OpcodeVecV128StoreName, body: []byte{ 1449 wasm.OpcodeI32Const, 1450 1, 1, 1, 1, 1451 wasm.OpcodeVecPrefix, 1452 wasm.OpcodeVecV128Const, 1453 1, 1, 1, 1, 1, 1, 1, 1, 1454 1, 1, 1, 1, 1, 1, 1, 1, 1455 wasm.OpcodeVecPrefix, 1456 wasm.OpcodeVecV128Store, 1457 4, // alignment 1458 10, // offset 1459 wasm.OpcodeEnd, 1460 }, 1461 expected: newOperationV128Store(memoryArg{Alignment: 4, Offset: 10}), 1462 }, 1463 { 1464 name: wasm.OpcodeVecV128Store8LaneName, 1465 body: storeLane(wasm.OpcodeVecV128Store8Lane, 0, 0, 0), 1466 expected: newOperationV128StoreLane(0, 8, memoryArg{Alignment: 0, Offset: 0}), 1467 }, 1468 { 1469 name: wasm.OpcodeVecV128Store8LaneName + "/lane=15", 1470 body: storeLane(wasm.OpcodeVecV128Store8Lane, 100, 0, 15), 1471 expected: newOperationV128StoreLane(15, 8, memoryArg{Alignment: 0, Offset: 100}), 1472 }, 1473 { 1474 name: wasm.OpcodeVecV128Store16LaneName, 1475 body: storeLane(wasm.OpcodeVecV128Store16Lane, 0, 0, 0), 1476 expected: newOperationV128StoreLane(0, 16, memoryArg{Alignment: 0, Offset: 0}), 1477 }, 1478 { 1479 name: wasm.OpcodeVecV128Store16LaneName + "/lane=7/align=1", 1480 body: storeLane(wasm.OpcodeVecV128Store16Lane, 100, 1, 7), 1481 expected: newOperationV128StoreLane(7, 16, memoryArg{Alignment: 1, Offset: 100}), 1482 }, 1483 { 1484 name: wasm.OpcodeVecV128Store32LaneName, 1485 body: storeLane(wasm.OpcodeVecV128Store32Lane, 0, 0, 0), 1486 expected: newOperationV128StoreLane(0, 32, memoryArg{Alignment: 0, Offset: 0}), 1487 }, 1488 { 1489 name: wasm.OpcodeVecV128Store32LaneName + "/lane=3/align=2", 1490 body: storeLane(wasm.OpcodeVecV128Store32Lane, 100, 2, 3), 1491 expected: newOperationV128StoreLane(3, 32, memoryArg{Alignment: 2, Offset: 100}), 1492 }, 1493 { 1494 name: wasm.OpcodeVecV128Store64LaneName, 1495 body: storeLane(wasm.OpcodeVecV128Store64Lane, 0, 0, 0), 1496 expected: newOperationV128StoreLane(0, 64, memoryArg{Alignment: 0, Offset: 0}), 1497 }, 1498 { 1499 name: wasm.OpcodeVecV128Store64LaneName + "/lane=1/align=3", 1500 body: storeLane(wasm.OpcodeVecV128Store64Lane, 50, 3, 1), 1501 expected: newOperationV128StoreLane(1, 64, memoryArg{Alignment: 3, Offset: 50}), 1502 }, 1503 { 1504 name: wasm.OpcodeVecI8x16ExtractLaneSName, 1505 body: extractLane(wasm.OpcodeVecI8x16ExtractLaneS, 0), 1506 expected: newOperationV128ExtractLane(0, true, shapeI8x16), 1507 needDropBeforeReturn: true, 1508 }, 1509 { 1510 name: wasm.OpcodeVecI8x16ExtractLaneSName + "/lane=15", 1511 body: extractLane(wasm.OpcodeVecI8x16ExtractLaneS, 15), 1512 expected: newOperationV128ExtractLane(15, true, shapeI8x16), 1513 needDropBeforeReturn: true, 1514 }, 1515 { 1516 name: wasm.OpcodeVecI8x16ExtractLaneUName, 1517 body: extractLane(wasm.OpcodeVecI8x16ExtractLaneU, 0), 1518 expected: newOperationV128ExtractLane(0, false, shapeI8x16), 1519 needDropBeforeReturn: true, 1520 }, 1521 { 1522 name: wasm.OpcodeVecI8x16ExtractLaneUName + "/lane=15", 1523 body: extractLane(wasm.OpcodeVecI8x16ExtractLaneU, 15), 1524 expected: newOperationV128ExtractLane(15, false, shapeI8x16), 1525 needDropBeforeReturn: true, 1526 }, 1527 { 1528 name: wasm.OpcodeVecI16x8ExtractLaneSName, 1529 body: extractLane(wasm.OpcodeVecI16x8ExtractLaneS, 0), 1530 expected: newOperationV128ExtractLane(0, true, shapeI16x8), 1531 needDropBeforeReturn: true, 1532 }, 1533 { 1534 name: wasm.OpcodeVecI16x8ExtractLaneSName + "/lane=7", 1535 body: extractLane(wasm.OpcodeVecI16x8ExtractLaneS, 7), 1536 expected: newOperationV128ExtractLane(7, true, shapeI16x8), 1537 needDropBeforeReturn: true, 1538 }, 1539 { 1540 name: wasm.OpcodeVecI16x8ExtractLaneUName, 1541 body: extractLane(wasm.OpcodeVecI16x8ExtractLaneU, 0), 1542 expected: newOperationV128ExtractLane(0, false, shapeI16x8), 1543 needDropBeforeReturn: true, 1544 }, 1545 { 1546 name: wasm.OpcodeVecI16x8ExtractLaneUName + "/lane=7", 1547 body: extractLane(wasm.OpcodeVecI16x8ExtractLaneU, 7), 1548 expected: newOperationV128ExtractLane(7, false, shapeI16x8), 1549 needDropBeforeReturn: true, 1550 }, 1551 { 1552 name: wasm.OpcodeVecI32x4ExtractLaneName, 1553 body: extractLane(wasm.OpcodeVecI32x4ExtractLane, 0), 1554 expected: newOperationV128ExtractLane(0, false, shapeI32x4), 1555 needDropBeforeReturn: true, 1556 }, 1557 { 1558 name: wasm.OpcodeVecI32x4ExtractLaneName + "/lane=3", 1559 body: extractLane(wasm.OpcodeVecI32x4ExtractLane, 3), 1560 expected: newOperationV128ExtractLane(3, false, shapeI32x4), 1561 needDropBeforeReturn: true, 1562 }, 1563 { 1564 name: wasm.OpcodeVecI64x2ExtractLaneName, 1565 body: extractLane(wasm.OpcodeVecI64x2ExtractLane, 0), 1566 expected: newOperationV128ExtractLane(0, false, shapeI64x2), 1567 needDropBeforeReturn: true, 1568 }, 1569 { 1570 name: wasm.OpcodeVecI64x2ExtractLaneName + "/lane=1", 1571 body: extractLane(wasm.OpcodeVecI64x2ExtractLane, 1), 1572 expected: newOperationV128ExtractLane(1, false, shapeI64x2), 1573 needDropBeforeReturn: true, 1574 }, 1575 { 1576 name: wasm.OpcodeVecF32x4ExtractLaneName, 1577 body: extractLane(wasm.OpcodeVecF32x4ExtractLane, 0), 1578 expected: newOperationV128ExtractLane(0, false, shapeF32x4), 1579 needDropBeforeReturn: true, 1580 }, 1581 { 1582 name: wasm.OpcodeVecF32x4ExtractLaneName + "/lane=3", 1583 body: extractLane(wasm.OpcodeVecF32x4ExtractLane, 3), 1584 expected: newOperationV128ExtractLane(3, false, shapeF32x4), 1585 needDropBeforeReturn: true, 1586 }, 1587 { 1588 name: wasm.OpcodeVecF64x2ExtractLaneName, 1589 body: extractLane(wasm.OpcodeVecF64x2ExtractLane, 0), 1590 expected: newOperationV128ExtractLane(0, false, shapeF64x2), 1591 needDropBeforeReturn: true, 1592 }, 1593 { 1594 name: wasm.OpcodeVecF64x2ExtractLaneName + "/lane=1", 1595 body: extractLane(wasm.OpcodeVecF64x2ExtractLane, 1), 1596 expected: newOperationV128ExtractLane(1, false, shapeF64x2), 1597 needDropBeforeReturn: true, 1598 }, 1599 1600 { 1601 name: wasm.OpcodeVecI8x16ReplaceLaneName, 1602 body: replaceLane(wasm.OpcodeVecI8x16ReplaceLane, 0), 1603 expected: newOperationV128ReplaceLane(0, shapeI8x16), 1604 needDropBeforeReturn: true, 1605 }, 1606 { 1607 name: wasm.OpcodeVecI8x16ReplaceLaneName + "/lane=15", 1608 body: replaceLane(wasm.OpcodeVecI8x16ReplaceLane, 15), 1609 expected: newOperationV128ReplaceLane(15, shapeI8x16), 1610 needDropBeforeReturn: true, 1611 }, 1612 { 1613 name: wasm.OpcodeVecI16x8ReplaceLaneName, 1614 body: replaceLane(wasm.OpcodeVecI16x8ReplaceLane, 0), 1615 expected: newOperationV128ReplaceLane(0, shapeI16x8), 1616 needDropBeforeReturn: true, 1617 }, 1618 { 1619 name: wasm.OpcodeVecI16x8ReplaceLaneName + "/lane=7", 1620 body: replaceLane(wasm.OpcodeVecI16x8ReplaceLane, 7), 1621 expected: newOperationV128ReplaceLane(7, shapeI16x8), 1622 needDropBeforeReturn: true, 1623 }, 1624 { 1625 name: wasm.OpcodeVecI32x4ReplaceLaneName, 1626 body: replaceLane(wasm.OpcodeVecI32x4ReplaceLane, 0), 1627 expected: newOperationV128ReplaceLane(0, shapeI32x4), 1628 needDropBeforeReturn: true, 1629 }, 1630 { 1631 name: wasm.OpcodeVecI32x4ReplaceLaneName + "/lane=3", 1632 body: replaceLane(wasm.OpcodeVecI32x4ReplaceLane, 3), 1633 expected: newOperationV128ReplaceLane(3, shapeI32x4), 1634 needDropBeforeReturn: true, 1635 }, 1636 { 1637 name: wasm.OpcodeVecI64x2ReplaceLaneName, 1638 body: replaceLane(wasm.OpcodeVecI64x2ReplaceLane, 0), 1639 expected: newOperationV128ReplaceLane(0, shapeI64x2), 1640 needDropBeforeReturn: true, 1641 }, 1642 { 1643 name: wasm.OpcodeVecI64x2ReplaceLaneName + "/lane=1", 1644 body: replaceLane(wasm.OpcodeVecI64x2ReplaceLane, 1), 1645 expected: newOperationV128ReplaceLane(1, shapeI64x2), 1646 needDropBeforeReturn: true, 1647 }, 1648 { 1649 name: wasm.OpcodeVecF32x4ReplaceLaneName, 1650 body: replaceLane(wasm.OpcodeVecF32x4ReplaceLane, 0), 1651 expected: newOperationV128ReplaceLane(0, shapeF32x4), 1652 needDropBeforeReturn: true, 1653 }, 1654 { 1655 name: wasm.OpcodeVecF32x4ReplaceLaneName + "/lane=3", 1656 body: replaceLane(wasm.OpcodeVecF32x4ReplaceLane, 3), 1657 expected: newOperationV128ReplaceLane(3, shapeF32x4), 1658 needDropBeforeReturn: true, 1659 }, 1660 { 1661 name: wasm.OpcodeVecF64x2ReplaceLaneName, 1662 body: replaceLane(wasm.OpcodeVecF64x2ReplaceLane, 0), 1663 expected: newOperationV128ReplaceLane(0, shapeF64x2), 1664 needDropBeforeReturn: true, 1665 }, 1666 { 1667 name: wasm.OpcodeVecF64x2ReplaceLaneName + "/lane=1", 1668 body: replaceLane(wasm.OpcodeVecF64x2ReplaceLane, 1), 1669 expected: newOperationV128ReplaceLane(1, shapeF64x2), 1670 needDropBeforeReturn: true, 1671 }, 1672 { 1673 name: wasm.OpcodeVecI8x16SplatName, body: splat(wasm.OpcodeVecI8x16Splat), 1674 expected: newOperationV128Splat(shapeI8x16), 1675 needDropBeforeReturn: true, 1676 }, 1677 { 1678 name: wasm.OpcodeVecI16x8SplatName, body: splat(wasm.OpcodeVecI16x8Splat), 1679 expected: newOperationV128Splat(shapeI16x8), 1680 needDropBeforeReturn: true, 1681 }, 1682 { 1683 name: wasm.OpcodeVecI32x4SplatName, body: splat(wasm.OpcodeVecI32x4Splat), 1684 expected: newOperationV128Splat(shapeI32x4), 1685 needDropBeforeReturn: true, 1686 }, 1687 { 1688 name: wasm.OpcodeVecI64x2SplatName, body: splat(wasm.OpcodeVecI64x2Splat), 1689 expected: newOperationV128Splat(shapeI64x2), 1690 needDropBeforeReturn: true, 1691 }, 1692 { 1693 name: wasm.OpcodeVecF32x4SplatName, body: splat(wasm.OpcodeVecF32x4Splat), 1694 expected: newOperationV128Splat(shapeF32x4), 1695 needDropBeforeReturn: true, 1696 }, 1697 { 1698 name: wasm.OpcodeVecF64x2SplatName, body: splat(wasm.OpcodeVecF64x2Splat), 1699 expected: newOperationV128Splat(shapeF64x2), 1700 needDropBeforeReturn: true, 1701 }, 1702 { 1703 name: wasm.OpcodeVecI8x16SwizzleName, body: vv2v(wasm.OpcodeVecI8x16Swizzle), 1704 expected: newOperationV128Swizzle(), 1705 needDropBeforeReturn: true, 1706 }, 1707 { 1708 name: wasm.OpcodeVecV128i8x16ShuffleName, body: []byte{ 1709 wasm.OpcodeVecPrefix, 1710 wasm.OpcodeVecV128Const, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1711 wasm.OpcodeVecPrefix, 1712 wasm.OpcodeVecV128Const, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1713 wasm.OpcodeVecPrefix, 1714 wasm.OpcodeVecV128i8x16Shuffle, 1715 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1716 wasm.OpcodeDrop, 1717 wasm.OpcodeEnd, 1718 }, 1719 expected: newOperationV128Shuffle([]uint64{ 1720 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1721 }), 1722 needDropBeforeReturn: true, 1723 }, 1724 { 1725 name: wasm.OpcodeVecV128NotName, body: v2v(wasm.OpcodeVecV128Not), 1726 needDropBeforeReturn: true, 1727 expected: newOperationV128Not(), 1728 }, 1729 { 1730 name: wasm.OpcodeVecV128AndName, body: vv2v(wasm.OpcodeVecV128And), 1731 needDropBeforeReturn: true, 1732 expected: newOperationV128And(), 1733 }, 1734 { 1735 name: wasm.OpcodeVecV128AndNotName, body: vv2v(wasm.OpcodeVecV128AndNot), 1736 needDropBeforeReturn: true, 1737 expected: newOperationV128AndNot(), 1738 }, 1739 { 1740 name: wasm.OpcodeVecV128OrName, body: vv2v(wasm.OpcodeVecV128Or), 1741 needDropBeforeReturn: true, 1742 expected: newOperationV128Or(), 1743 }, 1744 { 1745 name: wasm.OpcodeVecV128XorName, body: vv2v(wasm.OpcodeVecV128Xor), 1746 needDropBeforeReturn: true, 1747 expected: newOperationV128Xor(), 1748 }, 1749 { 1750 name: wasm.OpcodeVecV128BitselectName, body: vvv2v(wasm.OpcodeVecV128Bitselect), 1751 needDropBeforeReturn: true, 1752 expected: newOperationV128Bitselect(), 1753 }, 1754 { 1755 name: wasm.OpcodeVecI8x16ShlName, body: vi2v(wasm.OpcodeVecI8x16Shl), 1756 needDropBeforeReturn: true, 1757 expected: newOperationV128Shl(shapeI8x16), 1758 }, 1759 { 1760 name: wasm.OpcodeVecI8x16ShrSName, body: vi2v(wasm.OpcodeVecI8x16ShrS), 1761 needDropBeforeReturn: true, 1762 expected: newOperationV128Shr(shapeI8x16, true), 1763 }, 1764 { 1765 name: wasm.OpcodeVecI8x16ShrUName, body: vi2v(wasm.OpcodeVecI8x16ShrU), 1766 needDropBeforeReturn: true, 1767 expected: newOperationV128Shr(shapeI8x16, false), 1768 }, 1769 { 1770 name: wasm.OpcodeVecI16x8ShlName, body: vi2v(wasm.OpcodeVecI16x8Shl), 1771 needDropBeforeReturn: true, 1772 expected: newOperationV128Shl(shapeI16x8), 1773 }, 1774 { 1775 name: wasm.OpcodeVecI16x8ShrSName, body: vi2v(wasm.OpcodeVecI16x8ShrS), 1776 needDropBeforeReturn: true, 1777 expected: newOperationV128Shr(shapeI16x8, true), 1778 }, 1779 { 1780 name: wasm.OpcodeVecI16x8ShrUName, body: vi2v(wasm.OpcodeVecI16x8ShrU), 1781 needDropBeforeReturn: true, 1782 expected: newOperationV128Shr(shapeI16x8, false), 1783 }, 1784 { 1785 name: wasm.OpcodeVecI32x4ShlName, body: vi2v(wasm.OpcodeVecI32x4Shl), 1786 needDropBeforeReturn: true, 1787 expected: newOperationV128Shl(shapeI32x4), 1788 }, 1789 { 1790 name: wasm.OpcodeVecI32x4ShrSName, body: vi2v(wasm.OpcodeVecI32x4ShrS), 1791 needDropBeforeReturn: true, 1792 expected: newOperationV128Shr(shapeI32x4, true), 1793 }, 1794 { 1795 name: wasm.OpcodeVecI32x4ShrUName, body: vi2v(wasm.OpcodeVecI32x4ShrU), 1796 needDropBeforeReturn: true, 1797 expected: newOperationV128Shr(shapeI32x4, false), 1798 }, 1799 { 1800 name: wasm.OpcodeVecI64x2ShlName, body: vi2v(wasm.OpcodeVecI64x2Shl), 1801 needDropBeforeReturn: true, 1802 expected: newOperationV128Shl(shapeI64x2), 1803 }, 1804 { 1805 name: wasm.OpcodeVecI64x2ShrSName, body: vi2v(wasm.OpcodeVecI64x2ShrS), 1806 needDropBeforeReturn: true, 1807 expected: newOperationV128Shr(shapeI64x2, true), 1808 }, 1809 { 1810 name: wasm.OpcodeVecI64x2ShrUName, body: vi2v(wasm.OpcodeVecI64x2ShrU), 1811 needDropBeforeReturn: true, 1812 expected: newOperationV128Shr(shapeI64x2, false), 1813 }, 1814 { 1815 name: wasm.OpcodeVecI8x16EqName, body: vv2v(wasm.OpcodeVecI8x16Eq), 1816 needDropBeforeReturn: true, 1817 expected: newOperationV128Cmp(v128CmpTypeI8x16Eq), 1818 }, 1819 { 1820 name: wasm.OpcodeVecI8x16NeName, body: vv2v(wasm.OpcodeVecI8x16Ne), 1821 needDropBeforeReturn: true, 1822 expected: newOperationV128Cmp(v128CmpTypeI8x16Ne), 1823 }, 1824 { 1825 name: wasm.OpcodeVecI8x16LtSName, body: vv2v(wasm.OpcodeVecI8x16LtS), 1826 needDropBeforeReturn: true, 1827 expected: newOperationV128Cmp(v128CmpTypeI8x16LtS), 1828 }, 1829 { 1830 name: wasm.OpcodeVecI8x16LtUName, body: vv2v(wasm.OpcodeVecI8x16LtU), 1831 needDropBeforeReturn: true, 1832 expected: newOperationV128Cmp(v128CmpTypeI8x16LtU), 1833 }, 1834 { 1835 name: wasm.OpcodeVecI8x16GtSName, body: vv2v(wasm.OpcodeVecI8x16GtS), 1836 needDropBeforeReturn: true, 1837 expected: newOperationV128Cmp(v128CmpTypeI8x16GtS), 1838 }, 1839 { 1840 name: wasm.OpcodeVecI8x16GtUName, body: vv2v(wasm.OpcodeVecI8x16GtU), 1841 needDropBeforeReturn: true, 1842 expected: newOperationV128Cmp(v128CmpTypeI8x16GtU), 1843 }, 1844 { 1845 name: wasm.OpcodeVecI8x16LeSName, body: vv2v(wasm.OpcodeVecI8x16LeS), 1846 needDropBeforeReturn: true, 1847 expected: newOperationV128Cmp(v128CmpTypeI8x16LeS), 1848 }, 1849 { 1850 name: wasm.OpcodeVecI8x16LeUName, body: vv2v(wasm.OpcodeVecI8x16LeU), 1851 needDropBeforeReturn: true, 1852 expected: newOperationV128Cmp(v128CmpTypeI8x16LeU), 1853 }, 1854 { 1855 name: wasm.OpcodeVecI8x16GeSName, body: vv2v(wasm.OpcodeVecI8x16GeS), 1856 needDropBeforeReturn: true, 1857 expected: newOperationV128Cmp(v128CmpTypeI8x16GeS), 1858 }, 1859 { 1860 name: wasm.OpcodeVecI8x16GeUName, body: vv2v(wasm.OpcodeVecI8x16GeU), 1861 needDropBeforeReturn: true, 1862 expected: newOperationV128Cmp(v128CmpTypeI8x16GeU), 1863 }, 1864 { 1865 name: wasm.OpcodeVecI16x8EqName, body: vv2v(wasm.OpcodeVecI16x8Eq), 1866 needDropBeforeReturn: true, 1867 expected: newOperationV128Cmp(v128CmpTypeI16x8Eq), 1868 }, 1869 { 1870 name: wasm.OpcodeVecI16x8NeName, body: vv2v(wasm.OpcodeVecI16x8Ne), 1871 needDropBeforeReturn: true, 1872 expected: newOperationV128Cmp(v128CmpTypeI16x8Ne), 1873 }, 1874 { 1875 name: wasm.OpcodeVecI16x8LtSName, body: vv2v(wasm.OpcodeVecI16x8LtS), 1876 needDropBeforeReturn: true, 1877 expected: newOperationV128Cmp(v128CmpTypeI16x8LtS), 1878 }, 1879 { 1880 name: wasm.OpcodeVecI16x8LtUName, body: vv2v(wasm.OpcodeVecI16x8LtU), 1881 needDropBeforeReturn: true, 1882 expected: newOperationV128Cmp(v128CmpTypeI16x8LtU), 1883 }, 1884 { 1885 name: wasm.OpcodeVecI16x8GtSName, body: vv2v(wasm.OpcodeVecI16x8GtS), 1886 needDropBeforeReturn: true, 1887 expected: newOperationV128Cmp(v128CmpTypeI16x8GtS), 1888 }, 1889 { 1890 name: wasm.OpcodeVecI16x8GtUName, body: vv2v(wasm.OpcodeVecI16x8GtU), 1891 needDropBeforeReturn: true, 1892 expected: newOperationV128Cmp(v128CmpTypeI16x8GtU), 1893 }, 1894 { 1895 name: wasm.OpcodeVecI16x8LeSName, body: vv2v(wasm.OpcodeVecI16x8LeS), 1896 needDropBeforeReturn: true, 1897 expected: newOperationV128Cmp(v128CmpTypeI16x8LeS), 1898 }, 1899 { 1900 name: wasm.OpcodeVecI16x8LeUName, body: vv2v(wasm.OpcodeVecI16x8LeU), 1901 needDropBeforeReturn: true, 1902 expected: newOperationV128Cmp(v128CmpTypeI16x8LeU), 1903 }, 1904 { 1905 name: wasm.OpcodeVecI16x8GeSName, body: vv2v(wasm.OpcodeVecI16x8GeS), 1906 needDropBeforeReturn: true, 1907 expected: newOperationV128Cmp(v128CmpTypeI16x8GeS), 1908 }, 1909 { 1910 name: wasm.OpcodeVecI16x8GeUName, body: vv2v(wasm.OpcodeVecI16x8GeU), 1911 needDropBeforeReturn: true, 1912 expected: newOperationV128Cmp(v128CmpTypeI16x8GeU), 1913 }, 1914 { 1915 name: wasm.OpcodeVecI32x4EqName, body: vv2v(wasm.OpcodeVecI32x4Eq), 1916 needDropBeforeReturn: true, 1917 expected: newOperationV128Cmp(v128CmpTypeI32x4Eq), 1918 }, 1919 { 1920 name: wasm.OpcodeVecI32x4NeName, body: vv2v(wasm.OpcodeVecI32x4Ne), 1921 needDropBeforeReturn: true, 1922 expected: newOperationV128Cmp(v128CmpTypeI32x4Ne), 1923 }, 1924 { 1925 name: wasm.OpcodeVecI32x4LtSName, body: vv2v(wasm.OpcodeVecI32x4LtS), 1926 needDropBeforeReturn: true, 1927 expected: newOperationV128Cmp(v128CmpTypeI32x4LtS), 1928 }, 1929 { 1930 name: wasm.OpcodeVecI32x4LtUName, body: vv2v(wasm.OpcodeVecI32x4LtU), 1931 needDropBeforeReturn: true, 1932 expected: newOperationV128Cmp(v128CmpTypeI32x4LtU), 1933 }, 1934 { 1935 name: wasm.OpcodeVecI32x4GtSName, body: vv2v(wasm.OpcodeVecI32x4GtS), 1936 needDropBeforeReturn: true, 1937 expected: newOperationV128Cmp(v128CmpTypeI32x4GtS), 1938 }, 1939 { 1940 name: wasm.OpcodeVecI32x4GtUName, body: vv2v(wasm.OpcodeVecI32x4GtU), 1941 needDropBeforeReturn: true, 1942 expected: newOperationV128Cmp(v128CmpTypeI32x4GtU), 1943 }, 1944 { 1945 name: wasm.OpcodeVecI32x4LeSName, body: vv2v(wasm.OpcodeVecI32x4LeS), 1946 needDropBeforeReturn: true, 1947 expected: newOperationV128Cmp(v128CmpTypeI32x4LeS), 1948 }, 1949 { 1950 name: wasm.OpcodeVecI32x4LeUName, body: vv2v(wasm.OpcodeVecI32x4LeU), 1951 needDropBeforeReturn: true, 1952 expected: newOperationV128Cmp(v128CmpTypeI32x4LeU), 1953 }, 1954 { 1955 name: wasm.OpcodeVecI32x4GeSName, body: vv2v(wasm.OpcodeVecI32x4GeS), 1956 needDropBeforeReturn: true, 1957 expected: newOperationV128Cmp(v128CmpTypeI32x4GeS), 1958 }, 1959 { 1960 name: wasm.OpcodeVecI32x4GeUName, body: vv2v(wasm.OpcodeVecI32x4GeU), 1961 needDropBeforeReturn: true, 1962 expected: newOperationV128Cmp(v128CmpTypeI32x4GeU), 1963 }, 1964 { 1965 name: wasm.OpcodeVecI64x2EqName, body: vv2v(wasm.OpcodeVecI64x2Eq), 1966 needDropBeforeReturn: true, 1967 expected: newOperationV128Cmp(v128CmpTypeI64x2Eq), 1968 }, 1969 { 1970 name: wasm.OpcodeVecI64x2NeName, body: vv2v(wasm.OpcodeVecI64x2Ne), 1971 needDropBeforeReturn: true, 1972 expected: newOperationV128Cmp(v128CmpTypeI64x2Ne), 1973 }, 1974 { 1975 name: wasm.OpcodeVecI64x2LtSName, body: vv2v(wasm.OpcodeVecI64x2LtS), 1976 needDropBeforeReturn: true, 1977 expected: newOperationV128Cmp(v128CmpTypeI64x2LtS), 1978 }, 1979 { 1980 name: wasm.OpcodeVecI64x2GtSName, body: vv2v(wasm.OpcodeVecI64x2GtS), 1981 needDropBeforeReturn: true, 1982 expected: newOperationV128Cmp(v128CmpTypeI64x2GtS), 1983 }, 1984 { 1985 name: wasm.OpcodeVecI64x2LeSName, body: vv2v(wasm.OpcodeVecI64x2LeS), 1986 needDropBeforeReturn: true, 1987 expected: newOperationV128Cmp(v128CmpTypeI64x2LeS), 1988 }, 1989 { 1990 name: wasm.OpcodeVecI64x2GeSName, body: vv2v(wasm.OpcodeVecI64x2GeS), 1991 needDropBeforeReturn: true, 1992 expected: newOperationV128Cmp(v128CmpTypeI64x2GeS), 1993 }, 1994 { 1995 name: wasm.OpcodeVecF32x4EqName, body: vv2v(wasm.OpcodeVecF32x4Eq), 1996 needDropBeforeReturn: true, 1997 expected: newOperationV128Cmp(v128CmpTypeF32x4Eq), 1998 }, 1999 { 2000 name: wasm.OpcodeVecF32x4NeName, body: vv2v(wasm.OpcodeVecF32x4Ne), 2001 needDropBeforeReturn: true, 2002 expected: newOperationV128Cmp(v128CmpTypeF32x4Ne), 2003 }, 2004 { 2005 name: wasm.OpcodeVecF32x4LtName, body: vv2v(wasm.OpcodeVecF32x4Lt), 2006 needDropBeforeReturn: true, 2007 expected: newOperationV128Cmp(v128CmpTypeF32x4Lt), 2008 }, 2009 { 2010 name: wasm.OpcodeVecF32x4GtName, body: vv2v(wasm.OpcodeVecF32x4Gt), 2011 needDropBeforeReturn: true, 2012 expected: newOperationV128Cmp(v128CmpTypeF32x4Gt), 2013 }, 2014 { 2015 name: wasm.OpcodeVecF32x4LeName, body: vv2v(wasm.OpcodeVecF32x4Le), 2016 needDropBeforeReturn: true, 2017 expected: newOperationV128Cmp(v128CmpTypeF32x4Le), 2018 }, 2019 { 2020 name: wasm.OpcodeVecF32x4GeName, body: vv2v(wasm.OpcodeVecF32x4Ge), 2021 needDropBeforeReturn: true, 2022 expected: newOperationV128Cmp(v128CmpTypeF32x4Ge), 2023 }, 2024 { 2025 name: wasm.OpcodeVecF64x2EqName, body: vv2v(wasm.OpcodeVecF64x2Eq), 2026 needDropBeforeReturn: true, 2027 expected: newOperationV128Cmp(v128CmpTypeF64x2Eq), 2028 }, 2029 { 2030 name: wasm.OpcodeVecF64x2NeName, body: vv2v(wasm.OpcodeVecF64x2Ne), 2031 needDropBeforeReturn: true, 2032 expected: newOperationV128Cmp(v128CmpTypeF64x2Ne), 2033 }, 2034 { 2035 name: wasm.OpcodeVecF64x2LtName, body: vv2v(wasm.OpcodeVecF64x2Lt), 2036 needDropBeforeReturn: true, 2037 expected: newOperationV128Cmp(v128CmpTypeF64x2Lt), 2038 }, 2039 { 2040 name: wasm.OpcodeVecF64x2GtName, body: vv2v(wasm.OpcodeVecF64x2Gt), 2041 needDropBeforeReturn: true, 2042 expected: newOperationV128Cmp(v128CmpTypeF64x2Gt), 2043 }, 2044 { 2045 name: wasm.OpcodeVecF64x2LeName, body: vv2v(wasm.OpcodeVecF64x2Le), 2046 needDropBeforeReturn: true, 2047 expected: newOperationV128Cmp(v128CmpTypeF64x2Le), 2048 }, 2049 { 2050 name: wasm.OpcodeVecF64x2GeName, body: vv2v(wasm.OpcodeVecF64x2Ge), 2051 needDropBeforeReturn: true, 2052 expected: newOperationV128Cmp(v128CmpTypeF64x2Ge), 2053 }, 2054 { 2055 name: wasm.OpcodeVecI8x16AllTrueName, body: v2v(wasm.OpcodeVecI8x16AllTrue), 2056 needDropBeforeReturn: true, 2057 expected: newOperationV128AllTrue(shapeI8x16), 2058 }, 2059 { 2060 name: wasm.OpcodeVecI16x8AllTrueName, body: v2v(wasm.OpcodeVecI16x8AllTrue), 2061 needDropBeforeReturn: true, 2062 expected: newOperationV128AllTrue(shapeI16x8), 2063 }, 2064 { 2065 name: wasm.OpcodeVecI32x4AllTrueName, body: v2v(wasm.OpcodeVecI32x4AllTrue), 2066 needDropBeforeReturn: true, 2067 expected: newOperationV128AllTrue(shapeI32x4), 2068 }, 2069 { 2070 name: wasm.OpcodeVecI64x2AllTrueName, body: v2v(wasm.OpcodeVecI64x2AllTrue), 2071 needDropBeforeReturn: true, 2072 expected: newOperationV128AllTrue(shapeI64x2), 2073 }, 2074 { 2075 name: wasm.OpcodeVecI8x16BitMaskName, body: v2v(wasm.OpcodeVecI8x16BitMask), 2076 needDropBeforeReturn: true, expected: newOperationV128BitMask(shapeI8x16), 2077 }, 2078 { 2079 name: wasm.OpcodeVecI16x8BitMaskName, body: v2v(wasm.OpcodeVecI16x8BitMask), 2080 needDropBeforeReturn: true, expected: newOperationV128BitMask(shapeI16x8), 2081 }, 2082 { 2083 name: wasm.OpcodeVecI32x4BitMaskName, body: v2v(wasm.OpcodeVecI32x4BitMask), 2084 needDropBeforeReturn: true, expected: newOperationV128BitMask(shapeI32x4), 2085 }, 2086 { 2087 name: wasm.OpcodeVecI64x2BitMaskName, body: v2v(wasm.OpcodeVecI64x2BitMask), 2088 needDropBeforeReturn: true, expected: newOperationV128BitMask(shapeI64x2), 2089 }, 2090 { 2091 name: wasm.OpcodeVecV128AnyTrueName, body: v2v(wasm.OpcodeVecV128AnyTrue), 2092 needDropBeforeReturn: true, 2093 expected: newOperationV128AnyTrue(), 2094 }, 2095 { 2096 name: wasm.OpcodeVecI8x16AddName, body: vv2v(wasm.OpcodeVecI8x16Add), 2097 needDropBeforeReturn: true, 2098 expected: newOperationV128Add(shapeI8x16), 2099 }, 2100 { 2101 name: wasm.OpcodeVecI8x16AddSatSName, body: vv2v(wasm.OpcodeVecI8x16AddSatS), 2102 needDropBeforeReturn: true, 2103 expected: newOperationV128AddSat(shapeI8x16, true), 2104 }, 2105 { 2106 name: wasm.OpcodeVecI8x16AddSatUName, body: vv2v(wasm.OpcodeVecI8x16AddSatU), 2107 needDropBeforeReturn: true, 2108 expected: newOperationV128AddSat(shapeI8x16, false), 2109 }, 2110 { 2111 name: wasm.OpcodeVecI8x16SubName, body: vv2v(wasm.OpcodeVecI8x16Sub), 2112 needDropBeforeReturn: true, 2113 expected: newOperationV128Sub(shapeI8x16), 2114 }, 2115 { 2116 name: wasm.OpcodeVecI8x16SubSatSName, body: vv2v(wasm.OpcodeVecI8x16SubSatS), 2117 needDropBeforeReturn: true, 2118 expected: newOperationV128SubSat(shapeI8x16, true), 2119 }, 2120 { 2121 name: wasm.OpcodeVecI8x16SubSatUName, body: vv2v(wasm.OpcodeVecI8x16SubSatU), 2122 needDropBeforeReturn: true, 2123 expected: newOperationV128SubSat(shapeI8x16, false), 2124 }, 2125 { 2126 name: wasm.OpcodeVecI16x8AddName, body: vv2v(wasm.OpcodeVecI16x8Add), 2127 needDropBeforeReturn: true, 2128 expected: newOperationV128Add(shapeI16x8), 2129 }, 2130 { 2131 name: wasm.OpcodeVecI16x8AddSatSName, body: vv2v(wasm.OpcodeVecI16x8AddSatS), 2132 needDropBeforeReturn: true, 2133 expected: newOperationV128AddSat(shapeI16x8, true), 2134 }, 2135 { 2136 name: wasm.OpcodeVecI16x8AddSatUName, body: vv2v(wasm.OpcodeVecI16x8AddSatU), 2137 needDropBeforeReturn: true, 2138 expected: newOperationV128AddSat(shapeI16x8, false), 2139 }, 2140 { 2141 name: wasm.OpcodeVecI16x8SubName, body: vv2v(wasm.OpcodeVecI16x8Sub), 2142 needDropBeforeReturn: true, 2143 expected: newOperationV128Sub(shapeI16x8), 2144 }, 2145 { 2146 name: wasm.OpcodeVecI16x8SubSatSName, body: vv2v(wasm.OpcodeVecI16x8SubSatS), 2147 needDropBeforeReturn: true, 2148 expected: newOperationV128SubSat(shapeI16x8, true), 2149 }, 2150 { 2151 name: wasm.OpcodeVecI16x8SubSatUName, body: vv2v(wasm.OpcodeVecI16x8SubSatU), 2152 needDropBeforeReturn: true, 2153 expected: newOperationV128SubSat(shapeI16x8, false), 2154 }, 2155 { 2156 name: wasm.OpcodeVecI16x8MulName, body: vv2v(wasm.OpcodeVecI16x8Mul), 2157 needDropBeforeReturn: true, 2158 expected: newOperationV128Mul(shapeI16x8), 2159 }, 2160 { 2161 name: wasm.OpcodeVecI32x4AddName, body: vv2v(wasm.OpcodeVecI32x4Add), 2162 needDropBeforeReturn: true, 2163 expected: newOperationV128Add(shapeI32x4), 2164 }, 2165 { 2166 name: wasm.OpcodeVecI32x4SubName, body: vv2v(wasm.OpcodeVecI32x4Sub), 2167 needDropBeforeReturn: true, 2168 expected: newOperationV128Sub(shapeI32x4), 2169 }, 2170 { 2171 name: wasm.OpcodeVecI32x4MulName, body: vv2v(wasm.OpcodeVecI32x4Mul), 2172 needDropBeforeReturn: true, 2173 expected: newOperationV128Mul(shapeI32x4), 2174 }, 2175 { 2176 name: wasm.OpcodeVecI64x2AddName, body: vv2v(wasm.OpcodeVecI64x2Add), 2177 needDropBeforeReturn: true, 2178 expected: newOperationV128Add(shapeI64x2), 2179 }, 2180 { 2181 name: wasm.OpcodeVecI64x2SubName, body: vv2v(wasm.OpcodeVecI64x2Sub), 2182 needDropBeforeReturn: true, 2183 expected: newOperationV128Sub(shapeI64x2), 2184 }, 2185 { 2186 name: wasm.OpcodeVecI64x2MulName, body: vv2v(wasm.OpcodeVecI64x2Mul), 2187 needDropBeforeReturn: true, 2188 expected: newOperationV128Mul(shapeI64x2), 2189 }, 2190 { 2191 name: wasm.OpcodeVecF32x4AddName, body: vv2v(wasm.OpcodeVecF32x4Add), 2192 needDropBeforeReturn: true, 2193 expected: newOperationV128Add(shapeF32x4), 2194 }, 2195 { 2196 name: wasm.OpcodeVecF32x4SubName, body: vv2v(wasm.OpcodeVecF32x4Sub), 2197 needDropBeforeReturn: true, 2198 expected: newOperationV128Sub(shapeF32x4), 2199 }, 2200 { 2201 name: wasm.OpcodeVecF32x4MulName, body: vv2v(wasm.OpcodeVecF32x4Mul), 2202 needDropBeforeReturn: true, 2203 expected: newOperationV128Mul(shapeF32x4), 2204 }, 2205 { 2206 name: wasm.OpcodeVecF32x4DivName, body: vv2v(wasm.OpcodeVecF32x4Div), 2207 needDropBeforeReturn: true, 2208 expected: newOperationV128Div(shapeF32x4), 2209 }, 2210 { 2211 name: wasm.OpcodeVecF64x2AddName, body: vv2v(wasm.OpcodeVecF64x2Add), 2212 needDropBeforeReturn: true, 2213 expected: newOperationV128Add(shapeF64x2), 2214 }, 2215 { 2216 name: wasm.OpcodeVecF64x2SubName, body: vv2v(wasm.OpcodeVecF64x2Sub), 2217 needDropBeforeReturn: true, 2218 expected: newOperationV128Sub(shapeF64x2), 2219 }, 2220 { 2221 name: wasm.OpcodeVecF64x2MulName, body: vv2v(wasm.OpcodeVecF64x2Mul), 2222 needDropBeforeReturn: true, 2223 expected: newOperationV128Mul(shapeF64x2), 2224 }, 2225 { 2226 name: wasm.OpcodeVecF64x2DivName, body: vv2v(wasm.OpcodeVecF64x2Div), 2227 needDropBeforeReturn: true, 2228 expected: newOperationV128Div(shapeF64x2), 2229 }, 2230 { 2231 name: wasm.OpcodeVecI8x16MinSName, body: vv2v(wasm.OpcodeVecI8x16MinS), 2232 needDropBeforeReturn: true, 2233 expected: newOperationV128Min(shapeI8x16, true), 2234 }, 2235 { 2236 name: wasm.OpcodeVecI8x16MinUName, body: vv2v(wasm.OpcodeVecI8x16MinU), 2237 needDropBeforeReturn: true, 2238 expected: newOperationV128Min(shapeI8x16, false), 2239 }, 2240 { 2241 name: wasm.OpcodeVecI8x16MaxSName, body: vv2v(wasm.OpcodeVecI8x16MaxS), 2242 needDropBeforeReturn: true, 2243 expected: newOperationV128Max(shapeI8x16, true), 2244 }, 2245 { 2246 name: wasm.OpcodeVecI8x16MaxUName, body: vv2v(wasm.OpcodeVecI8x16MaxU), 2247 needDropBeforeReturn: true, 2248 expected: newOperationV128Max(shapeI8x16, false), 2249 }, 2250 { 2251 name: wasm.OpcodeVecI8x16AvgrUName, body: vv2v(wasm.OpcodeVecI8x16AvgrU), 2252 needDropBeforeReturn: true, 2253 expected: newOperationV128AvgrU(shapeI8x16), 2254 }, 2255 { 2256 name: wasm.OpcodeVecI16x8MinSName, body: vv2v(wasm.OpcodeVecI16x8MinS), 2257 needDropBeforeReturn: true, 2258 expected: newOperationV128Min(shapeI16x8, true), 2259 }, 2260 { 2261 name: wasm.OpcodeVecI16x8MinUName, body: vv2v(wasm.OpcodeVecI16x8MinU), 2262 needDropBeforeReturn: true, 2263 expected: newOperationV128Min(shapeI16x8, false), 2264 }, 2265 { 2266 name: wasm.OpcodeVecI16x8MaxSName, body: vv2v(wasm.OpcodeVecI16x8MaxS), 2267 needDropBeforeReturn: true, 2268 expected: newOperationV128Max(shapeI16x8, true), 2269 }, 2270 { 2271 name: wasm.OpcodeVecI16x8MaxUName, body: vv2v(wasm.OpcodeVecI16x8MaxU), 2272 needDropBeforeReturn: true, 2273 expected: newOperationV128Max(shapeI16x8, false), 2274 }, 2275 { 2276 name: wasm.OpcodeVecI16x8AvgrUName, body: vv2v(wasm.OpcodeVecI16x8AvgrU), 2277 needDropBeforeReturn: true, 2278 expected: newOperationV128AvgrU(shapeI16x8), 2279 }, 2280 { 2281 name: wasm.OpcodeVecI32x4MinSName, body: vv2v(wasm.OpcodeVecI32x4MinS), 2282 needDropBeforeReturn: true, 2283 expected: newOperationV128Min(shapeI32x4, true), 2284 }, 2285 { 2286 name: wasm.OpcodeVecI32x4MinUName, body: vv2v(wasm.OpcodeVecI32x4MinU), 2287 needDropBeforeReturn: true, 2288 expected: newOperationV128Min(shapeI32x4, false), 2289 }, 2290 { 2291 name: wasm.OpcodeVecI32x4MaxSName, body: vv2v(wasm.OpcodeVecI32x4MaxS), 2292 needDropBeforeReturn: true, 2293 expected: newOperationV128Max(shapeI32x4, true), 2294 }, 2295 { 2296 name: wasm.OpcodeVecI32x4MaxUName, body: vv2v(wasm.OpcodeVecI32x4MaxU), 2297 needDropBeforeReturn: true, 2298 expected: newOperationV128Max(shapeI32x4, false), 2299 }, 2300 { 2301 name: wasm.OpcodeVecF32x4MinName, body: vv2v(wasm.OpcodeVecF32x4Min), 2302 needDropBeforeReturn: true, 2303 expected: newOperationV128Min(shapeF32x4, false), 2304 }, 2305 { 2306 name: wasm.OpcodeVecF32x4MaxName, body: vv2v(wasm.OpcodeVecF32x4Max), 2307 needDropBeforeReturn: true, 2308 expected: newOperationV128Max(shapeF32x4, false), 2309 }, 2310 { 2311 name: wasm.OpcodeVecF64x2MinName, body: vv2v(wasm.OpcodeVecF64x2Min), 2312 needDropBeforeReturn: true, 2313 expected: newOperationV128Min(shapeF64x2, false), 2314 }, 2315 { 2316 name: wasm.OpcodeVecF64x2MaxName, body: vv2v(wasm.OpcodeVecF64x2Max), 2317 needDropBeforeReturn: true, 2318 expected: newOperationV128Max(shapeF64x2, false), 2319 }, 2320 { 2321 name: wasm.OpcodeVecI8x16AbsName, body: v2v(wasm.OpcodeVecI8x16Abs), 2322 needDropBeforeReturn: true, 2323 expected: newOperationV128Abs(shapeI8x16), 2324 }, 2325 { 2326 name: wasm.OpcodeVecI8x16PopcntName, body: v2v(wasm.OpcodeVecI8x16Popcnt), 2327 needDropBeforeReturn: true, 2328 expected: newOperationV128Popcnt(shapeI8x16), 2329 }, 2330 { 2331 name: wasm.OpcodeVecI16x8AbsName, body: v2v(wasm.OpcodeVecI16x8Abs), 2332 needDropBeforeReturn: true, 2333 expected: newOperationV128Abs(shapeI16x8), 2334 }, 2335 { 2336 name: wasm.OpcodeVecI32x4AbsName, body: v2v(wasm.OpcodeVecI32x4Abs), 2337 needDropBeforeReturn: true, 2338 expected: newOperationV128Abs(shapeI32x4), 2339 }, 2340 { 2341 name: wasm.OpcodeVecI64x2AbsName, body: v2v(wasm.OpcodeVecI64x2Abs), 2342 needDropBeforeReturn: true, 2343 expected: newOperationV128Abs(shapeI64x2), 2344 }, 2345 { 2346 name: wasm.OpcodeVecF32x4AbsName, body: v2v(wasm.OpcodeVecF32x4Abs), 2347 needDropBeforeReturn: true, 2348 expected: newOperationV128Abs(shapeF32x4), 2349 }, 2350 { 2351 name: wasm.OpcodeVecF64x2AbsName, body: v2v(wasm.OpcodeVecF64x2Abs), 2352 needDropBeforeReturn: true, 2353 expected: newOperationV128Abs(shapeF64x2), 2354 }, 2355 { 2356 name: wasm.OpcodeVecF32x4CeilName, body: v2v(wasm.OpcodeVecF32x4Ceil), 2357 needDropBeforeReturn: true, 2358 expected: newOperationV128Ceil(shapeF32x4), 2359 }, 2360 { 2361 name: wasm.OpcodeVecF32x4FloorName, body: v2v(wasm.OpcodeVecF32x4Floor), 2362 needDropBeforeReturn: true, 2363 expected: newOperationV128Floor(shapeF32x4), 2364 }, 2365 { 2366 name: wasm.OpcodeVecF32x4TruncName, body: v2v(wasm.OpcodeVecF32x4Trunc), 2367 needDropBeforeReturn: true, 2368 expected: newOperationV128Trunc(shapeF32x4), 2369 }, 2370 { 2371 name: wasm.OpcodeVecF32x4NearestName, body: v2v(wasm.OpcodeVecF32x4Nearest), 2372 needDropBeforeReturn: true, 2373 expected: newOperationV128Nearest(shapeF32x4), 2374 }, 2375 { 2376 name: wasm.OpcodeVecF64x2CeilName, body: v2v(wasm.OpcodeVecF64x2Ceil), 2377 needDropBeforeReturn: true, 2378 expected: newOperationV128Ceil(shapeF64x2), 2379 }, 2380 { 2381 name: wasm.OpcodeVecF64x2FloorName, body: v2v(wasm.OpcodeVecF64x2Floor), 2382 needDropBeforeReturn: true, 2383 expected: newOperationV128Floor(shapeF64x2), 2384 }, 2385 { 2386 name: wasm.OpcodeVecF64x2TruncName, body: v2v(wasm.OpcodeVecF64x2Trunc), 2387 needDropBeforeReturn: true, 2388 expected: newOperationV128Trunc(shapeF64x2), 2389 }, 2390 { 2391 name: wasm.OpcodeVecF64x2NearestName, body: v2v(wasm.OpcodeVecF64x2Nearest), 2392 needDropBeforeReturn: true, 2393 expected: newOperationV128Nearest(shapeF64x2), 2394 }, 2395 { 2396 name: wasm.OpcodeVecF32x4PminName, body: vv2v(wasm.OpcodeVecF32x4Pmin), 2397 needDropBeforeReturn: true, 2398 expected: newOperationV128Pmin(shapeF32x4), 2399 }, 2400 { 2401 name: wasm.OpcodeVecF32x4PmaxName, body: vv2v(wasm.OpcodeVecF32x4Pmax), 2402 needDropBeforeReturn: true, 2403 expected: newOperationV128Pmax(shapeF32x4), 2404 }, 2405 { 2406 name: wasm.OpcodeVecF64x2PminName, body: vv2v(wasm.OpcodeVecF64x2Pmin), 2407 needDropBeforeReturn: true, 2408 expected: newOperationV128Pmin(shapeF64x2), 2409 }, 2410 { 2411 name: wasm.OpcodeVecF64x2PmaxName, body: vv2v(wasm.OpcodeVecF64x2Pmax), 2412 needDropBeforeReturn: true, 2413 expected: newOperationV128Pmax(shapeF64x2), 2414 }, 2415 { 2416 name: wasm.OpcodeVecI16x8Q15mulrSatSName, body: vv2v(wasm.OpcodeVecI16x8Q15mulrSatS), 2417 needDropBeforeReturn: true, 2418 expected: newOperationV128Q15mulrSatS(), 2419 }, 2420 { 2421 name: wasm.OpcodeVecI16x8ExtMulLowI8x16SName, body: vv2v(wasm.OpcodeVecI16x8ExtMulLowI8x16S), 2422 needDropBeforeReturn: true, 2423 expected: newOperationV128ExtMul(shapeI8x16, true, true), 2424 }, 2425 { 2426 name: wasm.OpcodeVecI16x8ExtMulHighI8x16SName, body: vv2v(wasm.OpcodeVecI16x8ExtMulHighI8x16S), 2427 needDropBeforeReturn: true, 2428 expected: newOperationV128ExtMul(shapeI8x16, true, false), 2429 }, 2430 { 2431 name: wasm.OpcodeVecI16x8ExtMulLowI8x16UName, body: vv2v(wasm.OpcodeVecI16x8ExtMulLowI8x16U), 2432 needDropBeforeReturn: true, 2433 expected: newOperationV128ExtMul(shapeI8x16, false, true), 2434 }, 2435 { 2436 name: wasm.OpcodeVecI16x8ExtMulHighI8x16UName, body: vv2v(wasm.OpcodeVecI16x8ExtMulHighI8x16U), 2437 needDropBeforeReturn: true, 2438 expected: newOperationV128ExtMul(shapeI8x16, false, false), 2439 }, 2440 { 2441 name: wasm.OpcodeVecI32x4ExtMulLowI16x8SName, body: vv2v(wasm.OpcodeVecI32x4ExtMulLowI16x8S), 2442 needDropBeforeReturn: true, 2443 expected: newOperationV128ExtMul(shapeI16x8, true, true), 2444 }, 2445 { 2446 name: wasm.OpcodeVecI32x4ExtMulHighI16x8SName, body: vv2v(wasm.OpcodeVecI32x4ExtMulHighI16x8S), 2447 needDropBeforeReturn: true, 2448 expected: newOperationV128ExtMul(shapeI16x8, true, false), 2449 }, 2450 { 2451 name: wasm.OpcodeVecI32x4ExtMulLowI16x8UName, body: vv2v(wasm.OpcodeVecI32x4ExtMulLowI16x8U), 2452 needDropBeforeReturn: true, 2453 expected: newOperationV128ExtMul(shapeI16x8, false, true), 2454 }, 2455 { 2456 name: wasm.OpcodeVecI32x4ExtMulHighI16x8UName, body: vv2v(wasm.OpcodeVecI32x4ExtMulHighI16x8U), 2457 needDropBeforeReturn: true, 2458 expected: newOperationV128ExtMul(shapeI16x8, false, false), 2459 }, 2460 { 2461 name: wasm.OpcodeVecI64x2ExtMulLowI32x4SName, body: vv2v(wasm.OpcodeVecI64x2ExtMulLowI32x4S), 2462 needDropBeforeReturn: true, 2463 expected: newOperationV128ExtMul(shapeI32x4, true, true), 2464 }, 2465 { 2466 name: wasm.OpcodeVecI64x2ExtMulHighI32x4SName, body: vv2v(wasm.OpcodeVecI64x2ExtMulHighI32x4S), 2467 needDropBeforeReturn: true, 2468 expected: newOperationV128ExtMul(shapeI32x4, true, false), 2469 }, 2470 { 2471 name: wasm.OpcodeVecI64x2ExtMulLowI32x4UName, body: vv2v(wasm.OpcodeVecI64x2ExtMulLowI32x4U), 2472 needDropBeforeReturn: true, 2473 expected: newOperationV128ExtMul(shapeI32x4, false, true), 2474 }, 2475 { 2476 name: wasm.OpcodeVecI64x2ExtMulHighI32x4UName, body: vv2v(wasm.OpcodeVecI64x2ExtMulHighI32x4U), 2477 needDropBeforeReturn: true, 2478 expected: newOperationV128ExtMul(shapeI32x4, false, false), 2479 }, 2480 { 2481 name: wasm.OpcodeVecI16x8ExtendLowI8x16SName, body: v2v(wasm.OpcodeVecI16x8ExtendLowI8x16S), 2482 needDropBeforeReturn: true, 2483 expected: newOperationV128Extend(shapeI8x16, true, true), 2484 }, 2485 { 2486 name: wasm.OpcodeVecI16x8ExtendHighI8x16SName, body: v2v(wasm.OpcodeVecI16x8ExtendHighI8x16S), 2487 needDropBeforeReturn: true, 2488 expected: newOperationV128Extend(shapeI8x16, true, false), 2489 }, 2490 { 2491 name: wasm.OpcodeVecI16x8ExtendLowI8x16UName, body: v2v(wasm.OpcodeVecI16x8ExtendLowI8x16U), 2492 needDropBeforeReturn: true, 2493 expected: newOperationV128Extend(shapeI8x16, false, true), 2494 }, 2495 { 2496 name: wasm.OpcodeVecI16x8ExtendHighI8x16UName, body: v2v(wasm.OpcodeVecI16x8ExtendHighI8x16U), 2497 needDropBeforeReturn: true, 2498 expected: newOperationV128Extend(shapeI8x16, false, false), 2499 }, 2500 { 2501 name: wasm.OpcodeVecI32x4ExtendLowI16x8SName, body: v2v(wasm.OpcodeVecI32x4ExtendLowI16x8S), 2502 needDropBeforeReturn: true, 2503 expected: newOperationV128Extend(shapeI16x8, true, true), 2504 }, 2505 { 2506 name: wasm.OpcodeVecI32x4ExtendHighI16x8SName, body: v2v(wasm.OpcodeVecI32x4ExtendHighI16x8S), 2507 needDropBeforeReturn: true, 2508 expected: newOperationV128Extend(shapeI16x8, true, false), 2509 }, 2510 { 2511 name: wasm.OpcodeVecI32x4ExtendLowI16x8UName, body: v2v(wasm.OpcodeVecI32x4ExtendLowI16x8U), 2512 needDropBeforeReturn: true, 2513 expected: newOperationV128Extend(shapeI16x8, false, true), 2514 }, 2515 { 2516 name: wasm.OpcodeVecI32x4ExtendHighI16x8UName, body: v2v(wasm.OpcodeVecI32x4ExtendHighI16x8U), 2517 needDropBeforeReturn: true, 2518 expected: newOperationV128Extend(shapeI16x8, false, false), 2519 }, 2520 { 2521 name: wasm.OpcodeVecI64x2ExtendLowI32x4SName, body: v2v(wasm.OpcodeVecI64x2ExtendLowI32x4S), 2522 needDropBeforeReturn: true, 2523 expected: newOperationV128Extend(shapeI32x4, true, true), 2524 }, 2525 { 2526 name: wasm.OpcodeVecI64x2ExtendHighI32x4SName, body: v2v(wasm.OpcodeVecI64x2ExtendHighI32x4S), 2527 needDropBeforeReturn: true, 2528 expected: newOperationV128Extend(shapeI32x4, true, false), 2529 }, 2530 { 2531 name: wasm.OpcodeVecI64x2ExtendLowI32x4UName, body: v2v(wasm.OpcodeVecI64x2ExtendLowI32x4U), 2532 needDropBeforeReturn: true, 2533 expected: newOperationV128Extend(shapeI32x4, false, true), 2534 }, 2535 { 2536 name: wasm.OpcodeVecI64x2ExtendHighI32x4UName, body: v2v(wasm.OpcodeVecI64x2ExtendHighI32x4U), 2537 needDropBeforeReturn: true, 2538 expected: newOperationV128Extend(shapeI32x4, false, false), 2539 }, 2540 2541 { 2542 name: wasm.OpcodeVecI16x8ExtaddPairwiseI8x16SName, body: v2v(wasm.OpcodeVecI16x8ExtaddPairwiseI8x16S), 2543 needDropBeforeReturn: true, 2544 expected: newOperationV128ExtAddPairwise(shapeI8x16, true), 2545 }, 2546 { 2547 name: wasm.OpcodeVecI16x8ExtaddPairwiseI8x16UName, body: v2v(wasm.OpcodeVecI16x8ExtaddPairwiseI8x16U), 2548 needDropBeforeReturn: true, 2549 expected: newOperationV128ExtAddPairwise(shapeI8x16, false), 2550 }, 2551 { 2552 name: wasm.OpcodeVecI32x4ExtaddPairwiseI16x8SName, body: v2v(wasm.OpcodeVecI32x4ExtaddPairwiseI16x8S), 2553 needDropBeforeReturn: true, 2554 expected: newOperationV128ExtAddPairwise(shapeI16x8, true), 2555 }, 2556 { 2557 name: wasm.OpcodeVecI32x4ExtaddPairwiseI16x8UName, body: v2v(wasm.OpcodeVecI32x4ExtaddPairwiseI16x8U), 2558 needDropBeforeReturn: true, 2559 expected: newOperationV128ExtAddPairwise(shapeI16x8, false), 2560 }, 2561 { 2562 name: wasm.OpcodeVecF64x2PromoteLowF32x4ZeroName, body: v2v(wasm.OpcodeVecF64x2PromoteLowF32x4Zero), 2563 needDropBeforeReturn: true, 2564 expected: newOperationV128FloatPromote(), 2565 }, 2566 { 2567 name: wasm.OpcodeVecF32x4DemoteF64x2ZeroName, body: v2v(wasm.OpcodeVecF32x4DemoteF64x2Zero), 2568 needDropBeforeReturn: true, 2569 expected: newOperationV128FloatDemote(), 2570 }, 2571 { 2572 name: wasm.OpcodeVecF32x4ConvertI32x4SName, body: v2v(wasm.OpcodeVecF32x4ConvertI32x4S), 2573 needDropBeforeReturn: true, 2574 expected: newOperationV128FConvertFromI(shapeF32x4, true), 2575 }, 2576 { 2577 name: wasm.OpcodeVecF32x4ConvertI32x4UName, body: v2v(wasm.OpcodeVecF32x4ConvertI32x4U), 2578 needDropBeforeReturn: true, 2579 expected: newOperationV128FConvertFromI(shapeF32x4, false), 2580 }, 2581 { 2582 name: wasm.OpcodeVecF64x2ConvertLowI32x4SName, body: v2v(wasm.OpcodeVecF64x2ConvertLowI32x4S), 2583 needDropBeforeReturn: true, 2584 expected: newOperationV128FConvertFromI(shapeF64x2, true), 2585 }, 2586 { 2587 name: wasm.OpcodeVecF64x2ConvertLowI32x4UName, body: v2v(wasm.OpcodeVecF64x2ConvertLowI32x4U), 2588 needDropBeforeReturn: true, 2589 expected: newOperationV128FConvertFromI(shapeF64x2, false), 2590 }, 2591 { 2592 name: wasm.OpcodeVecI32x4DotI16x8SName, body: vv2v(wasm.OpcodeVecI32x4DotI16x8S), 2593 needDropBeforeReturn: true, 2594 expected: newOperationV128Dot(), 2595 }, 2596 { 2597 name: wasm.OpcodeVecI8x16NarrowI16x8SName, body: vv2v(wasm.OpcodeVecI8x16NarrowI16x8S), 2598 needDropBeforeReturn: true, 2599 expected: newOperationV128Narrow(shapeI16x8, true), 2600 }, 2601 { 2602 name: wasm.OpcodeVecI8x16NarrowI16x8UName, body: vv2v(wasm.OpcodeVecI8x16NarrowI16x8U), 2603 needDropBeforeReturn: true, 2604 expected: newOperationV128Narrow(shapeI16x8, false), 2605 }, 2606 { 2607 name: wasm.OpcodeVecI16x8NarrowI32x4SName, body: vv2v(wasm.OpcodeVecI16x8NarrowI32x4S), 2608 needDropBeforeReturn: true, 2609 expected: newOperationV128Narrow(shapeI32x4, true), 2610 }, 2611 { 2612 name: wasm.OpcodeVecI16x8NarrowI32x4UName, body: vv2v(wasm.OpcodeVecI16x8NarrowI32x4U), 2613 needDropBeforeReturn: true, 2614 expected: newOperationV128Narrow(shapeI32x4, false), 2615 }, 2616 { 2617 name: wasm.OpcodeVecI32x4TruncSatF32x4SName, body: v2v(wasm.OpcodeVecI32x4TruncSatF32x4S), 2618 needDropBeforeReturn: true, 2619 expected: newOperationV128ITruncSatFromF(shapeF32x4, true), 2620 }, 2621 { 2622 name: wasm.OpcodeVecI32x4TruncSatF32x4UName, body: v2v(wasm.OpcodeVecI32x4TruncSatF32x4U), 2623 needDropBeforeReturn: true, 2624 expected: newOperationV128ITruncSatFromF(shapeF32x4, false), 2625 }, 2626 { 2627 name: wasm.OpcodeVecI32x4TruncSatF64x2SZeroName, body: v2v(wasm.OpcodeVecI32x4TruncSatF64x2SZero), 2628 needDropBeforeReturn: true, 2629 expected: newOperationV128ITruncSatFromF(shapeF64x2, true), 2630 }, 2631 { 2632 name: wasm.OpcodeVecI32x4TruncSatF64x2UZeroName, body: v2v(wasm.OpcodeVecI32x4TruncSatF64x2UZero), 2633 needDropBeforeReturn: true, 2634 expected: newOperationV128ITruncSatFromF(shapeF64x2, false), 2635 }, 2636 } 2637 2638 for _, tt := range tests { 2639 tc := tt 2640 t.Run(tc.name, func(t *testing.T) { 2641 module := &wasm.Module{ 2642 TypeSection: []wasm.FunctionType{v_v}, 2643 FunctionSection: []wasm.Index{0}, 2644 MemorySection: &wasm.Memory{}, 2645 CodeSection: []wasm.Code{{Body: tc.body}}, 2646 } 2647 c, err := newCompiler(api.CoreFeaturesV2, 0, module, false) 2648 require.NoError(t, err) 2649 2650 res, err := c.Next() 2651 require.NoError(t, err) 2652 2653 var actual unionOperation 2654 if tc.needDropBeforeReturn { 2655 // If the drop operation is inserted, the target op exits at -3 2656 // as the operations looks like: [... target, drop, br(to return)]. 2657 actual = res.Operations[len(res.Operations)-3] 2658 } else { 2659 // If the drop operation is not inserted, the target op exits at -2 2660 // as the operations looks like: [... target, br(to return)]. 2661 actual = res.Operations[len(res.Operations)-2] 2662 } 2663 2664 require.Equal(t, tc.expected, actual) 2665 }) 2666 } 2667 } 2668 2669 // TestCompile_unreachable_Br_BrIf_BrTable ensures that unreachable br/br_if/br_table instructions are correctly ignored. 2670 func TestCompile_unreachable_Br_BrIf_BrTable(t *testing.T) { 2671 tests := []struct { 2672 name string 2673 mod *wasm.Module 2674 expected []unionOperation 2675 }{ 2676 { 2677 name: "br", 2678 mod: &wasm.Module{ 2679 TypeSection: []wasm.FunctionType{v_v}, 2680 FunctionSection: []wasm.Index{0}, 2681 CodeSection: []wasm.Code{{Body: []byte{ 2682 wasm.OpcodeBr, 0, // Return the function -> the followings are unreachable. 2683 wasm.OpcodeBlock, 0, 2684 wasm.OpcodeBr, 1, 2685 wasm.OpcodeEnd, // End the block. 2686 wasm.OpcodeEnd, // End the function. 2687 }}}, 2688 }, 2689 expected: []unionOperation{newOperationBr(newLabel(labelKindReturn, 0))}, 2690 }, 2691 { 2692 name: "br_if", 2693 mod: &wasm.Module{ 2694 TypeSection: []wasm.FunctionType{v_v}, 2695 FunctionSection: []wasm.Index{0}, 2696 CodeSection: []wasm.Code{{Body: []byte{ 2697 wasm.OpcodeBr, 0, // Return the function -> the followings are unreachable. 2698 wasm.OpcodeBlock, 0, 2699 wasm.OpcodeI32Const, 1, 2700 wasm.OpcodeBrIf, 1, 2701 wasm.OpcodeEnd, // End the block. 2702 wasm.OpcodeEnd, // End the function. 2703 }}}, 2704 }, 2705 expected: []unionOperation{newOperationBr(newLabel(labelKindReturn, 0))}, 2706 }, 2707 { 2708 name: "br_table", 2709 mod: &wasm.Module{ 2710 TypeSection: []wasm.FunctionType{v_v}, 2711 FunctionSection: []wasm.Index{0}, 2712 CodeSection: []wasm.Code{{Body: []byte{ 2713 wasm.OpcodeBr, 0, // Return the function -> the followings are unreachable. 2714 wasm.OpcodeBlock, 0, 2715 wasm.OpcodeBrTable, 2, 2, 3, 2716 wasm.OpcodeEnd, // End the block. 2717 wasm.OpcodeEnd, // End the function. 2718 }}}, 2719 }, 2720 expected: []unionOperation{newOperationBr(newLabel(labelKindReturn, 0))}, 2721 }, 2722 } 2723 2724 for _, tt := range tests { 2725 tc := tt 2726 t.Run(tc.name, func(t *testing.T) { 2727 c, err := newCompiler(api.CoreFeaturesV2, 0, tc.mod, false) 2728 require.NoError(t, err) 2729 2730 actual, err := c.Next() 2731 require.NoError(t, err) 2732 require.Equal(t, tc.expected, actual.Operations) 2733 }) 2734 } 2735 } 2736 2737 // TestCompile_drop_vectors ensures that wasm.OpcodeDrop on vector values is correctly compiled, 2738 // which is not covered by spectest. 2739 func TestCompile_drop_vectors(t *testing.T) { 2740 tests := []struct { 2741 name string 2742 mod *wasm.Module 2743 expected []unionOperation 2744 }{ 2745 { 2746 name: "basic", 2747 mod: &wasm.Module{ 2748 TypeSection: []wasm.FunctionType{v_v}, 2749 FunctionSection: []wasm.Index{0}, 2750 CodeSection: []wasm.Code{{Body: []byte{ 2751 wasm.OpcodeVecPrefix, 2752 wasm.OpcodeVecV128Const, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2753 wasm.OpcodeDrop, 2754 wasm.OpcodeEnd, 2755 }}}, 2756 }, 2757 expected: []unionOperation{ 2758 newOperationV128Const(0x1, 0x2), 2759 // inclusiveRange is the range in uint64 representation, so dropping a vector value on top 2760 // should be translated as drop [0..1] inclusively. 2761 newOperationDrop(inclusiveRange{Start: 0, End: 1}), 2762 newOperationBr(newLabel(labelKindReturn, 0)), 2763 }, 2764 }, 2765 } 2766 2767 for _, tt := range tests { 2768 tc := tt 2769 t.Run(tc.name, func(t *testing.T) { 2770 c, err := newCompiler(api.CoreFeaturesV2, 0, tc.mod, false) 2771 require.NoError(t, err) 2772 2773 actual, err := c.Next() 2774 require.NoError(t, err) 2775 require.Equal(t, tc.expected, actual.Operations) 2776 }) 2777 } 2778 } 2779 2780 func TestCompile_select_vectors(t *testing.T) { 2781 tests := []struct { 2782 name string 2783 mod *wasm.Module 2784 expected []unionOperation 2785 }{ 2786 { 2787 name: "non typed", 2788 mod: &wasm.Module{ 2789 TypeSection: []wasm.FunctionType{v_v}, 2790 FunctionSection: []wasm.Index{0}, 2791 CodeSection: []wasm.Code{{Body: []byte{ 2792 wasm.OpcodeVecPrefix, 2793 wasm.OpcodeVecV128Const, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2794 wasm.OpcodeVecPrefix, 2795 wasm.OpcodeVecV128Const, 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 2796 wasm.OpcodeI32Const, 0, 2797 wasm.OpcodeSelect, 2798 wasm.OpcodeDrop, 2799 wasm.OpcodeEnd, 2800 }}}, 2801 FunctionDefinitionSection: []wasm.FunctionDefinition{{}}, 2802 }, 2803 expected: []unionOperation{ 2804 newOperationV128Const(0x1, 0x2), 2805 newOperationV128Const(0x3, 0x4), 2806 newOperationConstI32(0), 2807 newOperationSelect(true), 2808 newOperationDrop(inclusiveRange{Start: 0, End: 1}), 2809 newOperationBr(newLabel(labelKindReturn, 0)), 2810 }, 2811 }, 2812 { 2813 name: "typed", 2814 mod: &wasm.Module{ 2815 TypeSection: []wasm.FunctionType{v_v}, 2816 FunctionSection: []wasm.Index{0}, 2817 CodeSection: []wasm.Code{{Body: []byte{ 2818 wasm.OpcodeVecPrefix, 2819 wasm.OpcodeVecV128Const, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2820 wasm.OpcodeVecPrefix, 2821 wasm.OpcodeVecV128Const, 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 2822 wasm.OpcodeI32Const, 0, 2823 wasm.OpcodeTypedSelect, 0x1, wasm.ValueTypeV128, 2824 wasm.OpcodeDrop, 2825 wasm.OpcodeEnd, 2826 }}}, 2827 FunctionDefinitionSection: []wasm.FunctionDefinition{{}}, 2828 }, 2829 expected: []unionOperation{ 2830 newOperationV128Const(0x1, 0x2), 2831 newOperationV128Const(0x3, 0x4), 2832 newOperationConstI32(0), 2833 newOperationSelect(true), 2834 newOperationDrop(inclusiveRange{Start: 0, End: 1}), 2835 newOperationBr(newLabel(labelKindReturn, 0)), 2836 }, 2837 }, 2838 } 2839 2840 for _, tt := range tests { 2841 tc := tt 2842 t.Run(tc.name, func(t *testing.T) { 2843 c, err := newCompiler(api.CoreFeaturesV2, 0, tc.mod, false) 2844 require.NoError(t, err) 2845 2846 actual, err := c.Next() 2847 require.NoError(t, err) 2848 require.Equal(t, tc.expected, actual.Operations) 2849 }) 2850 } 2851 } 2852 2853 func TestCompiler_initializeStack(t *testing.T) { 2854 const v128 = wasm.ValueTypeV128 2855 tests := []struct { 2856 name string 2857 sig *wasm.FunctionType 2858 functionLocalTypes []wasm.ValueType 2859 callFrameStackSizeInUint64 int 2860 expLocalIndexToStackHeightInUint64 []int 2861 }{ 2862 { 2863 name: "no function local, args>results", 2864 sig: &wasm.FunctionType{ 2865 Params: []wasm.ValueType{i32, wf32}, 2866 Results: []wasm.ValueType{i32}, 2867 ParamNumInUint64: 2, 2868 ResultNumInUint64: 1, 2869 }, 2870 expLocalIndexToStackHeightInUint64: []int{0, 1}, 2871 }, 2872 { 2873 name: "no function local, args=results", 2874 sig: &wasm.FunctionType{ 2875 Params: []wasm.ValueType{i32}, 2876 Results: []wasm.ValueType{i32}, 2877 ParamNumInUint64: 1, 2878 ResultNumInUint64: 1, 2879 }, 2880 expLocalIndexToStackHeightInUint64: []int{0}, 2881 }, 2882 { 2883 name: "no function local, args>results, with vector", 2884 sig: &wasm.FunctionType{ 2885 Params: []wasm.ValueType{i32, v128, wf32}, 2886 Results: []wasm.ValueType{i32}, 2887 ParamNumInUint64: 4, 2888 ResultNumInUint64: 1, 2889 }, 2890 expLocalIndexToStackHeightInUint64: []int{0, 1, 3}, 2891 }, 2892 { 2893 name: "no function local, args<results", 2894 sig: &wasm.FunctionType{ 2895 Params: []wasm.ValueType{}, 2896 Results: []wasm.ValueType{i32}, 2897 ParamNumInUint64: 0, 2898 ResultNumInUint64: 1, 2899 }, 2900 callFrameStackSizeInUint64: 4, 2901 expLocalIndexToStackHeightInUint64: nil, 2902 }, 2903 { 2904 name: "no function local, args<results", 2905 sig: &wasm.FunctionType{ 2906 Params: []wasm.ValueType{i32}, 2907 Results: []wasm.ValueType{i32, wf32}, 2908 ParamNumInUint64: 1, 2909 ResultNumInUint64: 2, 2910 }, 2911 callFrameStackSizeInUint64: 4, 2912 expLocalIndexToStackHeightInUint64: []int{0}, 2913 }, 2914 { 2915 name: "no function local, args<results, with vector", 2916 sig: &wasm.FunctionType{ 2917 Params: []wasm.ValueType{i32}, 2918 Results: []wasm.ValueType{i32, v128, wf32}, 2919 ParamNumInUint64: 1, 2920 ResultNumInUint64: 4, 2921 }, 2922 callFrameStackSizeInUint64: 4, 2923 expLocalIndexToStackHeightInUint64: []int{0}, 2924 }, 2925 2926 // With function locals 2927 { 2928 name: "function locals, args>results", 2929 sig: &wasm.FunctionType{ 2930 Params: []wasm.ValueType{i32, wf32}, 2931 Results: []wasm.ValueType{i32}, 2932 ParamNumInUint64: 2, 2933 ResultNumInUint64: 1, 2934 }, 2935 functionLocalTypes: []wasm.ValueType{wf64}, 2936 callFrameStackSizeInUint64: 4, 2937 // [i32, f32, callframe.0, callframe.1, callframe.2, callframe.3, f64] 2938 expLocalIndexToStackHeightInUint64: []int{ 2939 0, 2940 1, 2941 // Function local comes after call frame. 2942 6, 2943 }, 2944 }, 2945 { 2946 name: "function locals, args>results, with vector", 2947 sig: &wasm.FunctionType{ 2948 Params: []wasm.ValueType{i32, v128, wf32}, 2949 Results: []wasm.ValueType{i32}, 2950 ParamNumInUint64: 4, 2951 ResultNumInUint64: 1, 2952 }, 2953 functionLocalTypes: []wasm.ValueType{v128, v128}, 2954 callFrameStackSizeInUint64: 4, 2955 // [i32, v128.lo, v128.hi, f32, callframe.0, callframe.1, callframe.2, callframe.3, v128.lo, v128.hi, v128.lo, v128.hi] 2956 expLocalIndexToStackHeightInUint64: []int{ 2957 0, 2958 1, 2959 3, 2960 // Function local comes after call frame. 2961 8, 2962 10, 2963 }, 2964 }, 2965 { 2966 name: "function locals, args<results", 2967 sig: &wasm.FunctionType{ 2968 Params: []wasm.ValueType{i32}, 2969 Results: []wasm.ValueType{i32, i32, i32, i32}, 2970 ParamNumInUint64: 1, 2971 ResultNumInUint64: 4, 2972 }, 2973 functionLocalTypes: []wasm.ValueType{wf64}, 2974 callFrameStackSizeInUint64: 4, 2975 // [i32, _, _, _, callframe.0, callframe.1, callframe.2, callframe.3, f64] 2976 expLocalIndexToStackHeightInUint64: []int{0, 8}, 2977 }, 2978 { 2979 name: "function locals, args<results with vector", 2980 sig: &wasm.FunctionType{ 2981 Params: []wasm.ValueType{v128, wf64}, 2982 Results: []wasm.ValueType{v128, i32, i32, v128}, 2983 ParamNumInUint64: 3, 2984 ResultNumInUint64: 6, 2985 }, 2986 functionLocalTypes: []wasm.ValueType{wf64}, 2987 callFrameStackSizeInUint64: 4, 2988 // [v128.lo, v128.hi, f64, _, _, _, callframe.0, callframe.1, callframe.2, callframe.3, f64] 2989 expLocalIndexToStackHeightInUint64: []int{0, 2, 10}, 2990 }, 2991 } 2992 2993 for _, tc := range tests { 2994 tc := tc 2995 t.Run(tc.name, func(t *testing.T) { 2996 c := &compiler{ 2997 sig: tc.sig, localTypes: tc.functionLocalTypes, 2998 callFrameStackSizeInUint64: tc.callFrameStackSizeInUint64, 2999 } 3000 3001 c.initializeStack() 3002 require.Equal(t, tc.expLocalIndexToStackHeightInUint64, c.localIndexToStackHeightInUint64) 3003 }) 3004 } 3005 } 3006 3007 func Test_ensureTermination(t *testing.T) { 3008 for _, tc := range []struct { 3009 ensureTermination bool 3010 exp string 3011 }{ 3012 { 3013 ensureTermination: true, 3014 exp: `.entrypoint 3015 ConstI32 0x0 3016 Br .L2 3017 .L2 3018 BuiltinFunctionCheckExitCode 3019 ConstI32 0x1 3020 BrIf .L2, .L3 3021 .L3 3022 ConstI32 0x1 3023 Br .L4 3024 .L4 3025 BuiltinFunctionCheckExitCode 3026 i32.Add 3027 Drop 0..0 3028 Br .return 3029 `, 3030 }, 3031 { 3032 ensureTermination: false, 3033 exp: `.entrypoint 3034 ConstI32 0x0 3035 Br .L2 3036 .L2 3037 ConstI32 0x1 3038 BrIf .L2, .L3 3039 .L3 3040 ConstI32 0x1 3041 Br .L4 3042 .L4 3043 i32.Add 3044 Drop 0..0 3045 Br .return 3046 `, 3047 }, 3048 } { 3049 t.Run(fmt.Sprintf("%v", tc.ensureTermination), func(t *testing.T) { 3050 mod := &wasm.Module{ 3051 TypeSection: []wasm.FunctionType{v_v}, 3052 FunctionSection: []wasm.Index{0}, 3053 CodeSection: []wasm.Code{{ 3054 Body: []byte{ 3055 wasm.OpcodeI32Const, 0, 3056 wasm.OpcodeLoop, 0, wasm.OpcodeI32Const, 1, wasm.OpcodeBrIf, 0, wasm.OpcodeEnd, 3057 wasm.OpcodeI32Const, 1, 3058 wasm.OpcodeLoop, 0, wasm.OpcodeEnd, 3059 wasm.OpcodeI32Add, 3060 wasm.OpcodeDrop, 3061 wasm.OpcodeEnd, 3062 }, 3063 }}, 3064 } 3065 c, err := newCompiler(api.CoreFeaturesV2, 0, mod, tc.ensureTermination) 3066 require.NoError(t, err) 3067 3068 actual, err := c.Next() 3069 require.NoError(t, err) 3070 require.Equal(t, tc.exp, format(actual.Operations)) 3071 }) 3072 } 3073 } 3074 3075 func TestCompiler_threads(t *testing.T) { 3076 tests := []struct { 3077 name string 3078 body []byte 3079 noDropBeforeReturn bool 3080 expected unionOperation 3081 }{ 3082 { 3083 name: "i32.atomic.load8_u", 3084 body: []byte{ 3085 wasm.OpcodeI32Const, 0x0, 3086 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI32Load8U, 0x1, 0x8, // alignment=2^1, offset=8 3087 }, 3088 expected: newOperationAtomicLoad8(unsignedTypeI32, memoryArg{Alignment: 0x1, Offset: 0x8}), 3089 }, 3090 { 3091 name: "i32.atomic.load16_u", 3092 body: []byte{ 3093 wasm.OpcodeI32Const, 0x0, 3094 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI32Load16U, 0x2, 0x8, // alignment=2^(2-1), offset=8 3095 }, 3096 expected: newOperationAtomicLoad16(unsignedTypeI32, memoryArg{Alignment: 0x2, Offset: 0x8}), 3097 }, 3098 { 3099 name: "i32.atomic.load", 3100 body: []byte{ 3101 wasm.OpcodeI32Const, 0x0, 3102 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI32Load, 0x3, 0x8, // alignment=2^(3-1), offset=8 3103 }, 3104 expected: newOperationAtomicLoad(unsignedTypeI32, memoryArg{Alignment: 0x3, Offset: 0x8}), 3105 }, 3106 { 3107 name: "i64.atomic.load8_u", 3108 body: []byte{ 3109 wasm.OpcodeI32Const, 0x0, 3110 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64Load8U, 0x1, 0x8, // alignment=2^1, offset=8 3111 }, 3112 expected: newOperationAtomicLoad8(unsignedTypeI64, memoryArg{Alignment: 0x1, Offset: 0x8}), 3113 }, 3114 { 3115 name: "i64.atomic.load16_u", 3116 body: []byte{ 3117 wasm.OpcodeI32Const, 0x0, 3118 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64Load16U, 0x2, 0x8, // alignment=2^(2-1), offset=8 3119 }, 3120 expected: newOperationAtomicLoad16(unsignedTypeI64, memoryArg{Alignment: 0x2, Offset: 0x8}), 3121 }, 3122 { 3123 name: "i64.atomic.load32_u", 3124 body: []byte{ 3125 wasm.OpcodeI32Const, 0x0, 3126 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64Load32U, 0x3, 0x8, // alignment=2^(3-1), offset=8 3127 }, 3128 expected: newOperationAtomicLoad(unsignedTypeI32, memoryArg{Alignment: 0x3, Offset: 0x8}), 3129 }, 3130 { 3131 name: "i64.atomic.load", 3132 body: []byte{ 3133 wasm.OpcodeI32Const, 0x0, 3134 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64Load, 0x4, 0x8, // alignment=2^(4-1), offset=8 3135 }, 3136 expected: newOperationAtomicLoad(unsignedTypeI64, memoryArg{Alignment: 0x4, Offset: 0x8}), 3137 }, 3138 { 3139 name: "i32.atomic.store8", 3140 body: []byte{ 3141 wasm.OpcodeI32Const, 0x1, 3142 wasm.OpcodeI32Const, 0x0, 3143 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI32Store8, 0x1, 0x8, // alignment=2^1, offset=8 3144 }, 3145 noDropBeforeReturn: true, 3146 expected: newOperationAtomicStore8(unsignedTypeI32, memoryArg{Alignment: 0x1, Offset: 0x8}), 3147 }, 3148 { 3149 name: "i32.atomic.store16", 3150 body: []byte{ 3151 wasm.OpcodeI32Const, 0x1, 3152 wasm.OpcodeI32Const, 0x0, 3153 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI32Store16, 0x2, 0x8, // alignment=2^(2-1), offset=8 3154 }, 3155 noDropBeforeReturn: true, 3156 expected: newOperationAtomicStore16(unsignedTypeI32, memoryArg{Alignment: 0x2, Offset: 0x8}), 3157 }, 3158 { 3159 name: "i32.atomic.store", 3160 body: []byte{ 3161 wasm.OpcodeI32Const, 0x1, 3162 wasm.OpcodeI32Const, 0x0, 3163 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI32Store, 0x3, 0x8, // alignment=2^(3-1), offset=8 3164 }, 3165 noDropBeforeReturn: true, 3166 expected: newOperationAtomicStore(unsignedTypeI32, memoryArg{Alignment: 0x3, Offset: 0x8}), 3167 }, 3168 { 3169 name: "i64.atomic.store8", 3170 body: []byte{ 3171 wasm.OpcodeI32Const, 0x0, 3172 wasm.OpcodeI64Const, 0x1, 3173 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64Store8, 0x1, 0x8, // alignment=2^1, offset=8 3174 }, 3175 noDropBeforeReturn: true, 3176 expected: newOperationAtomicStore8(unsignedTypeI64, memoryArg{Alignment: 0x1, Offset: 0x8}), 3177 }, 3178 { 3179 name: "i64.atomic.store16", 3180 body: []byte{ 3181 wasm.OpcodeI32Const, 0x0, 3182 wasm.OpcodeI64Const, 0x1, 3183 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64Store16, 0x2, 0x8, // alignment=2^(2-1), offset=8 3184 }, 3185 noDropBeforeReturn: true, 3186 expected: newOperationAtomicStore16(unsignedTypeI64, memoryArg{Alignment: 0x2, Offset: 0x8}), 3187 }, 3188 { 3189 name: "i64.atomic.store32", 3190 body: []byte{ 3191 wasm.OpcodeI32Const, 0x0, 3192 wasm.OpcodeI64Const, 0x1, 3193 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64Store32, 0x3, 0x8, // alignment=2^(3-1), offset=8 3194 }, 3195 noDropBeforeReturn: true, 3196 expected: newOperationAtomicStore(unsignedTypeI32, memoryArg{Alignment: 0x3, Offset: 0x8}), 3197 }, 3198 { 3199 name: "i64.atomic.store", 3200 body: []byte{ 3201 wasm.OpcodeI32Const, 0x0, 3202 wasm.OpcodeI64Const, 0x1, 3203 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64Store, 0x4, 0x8, // alignment=2^(4-1), offset=8 3204 }, 3205 noDropBeforeReturn: true, 3206 expected: newOperationAtomicStore(unsignedTypeI64, memoryArg{Alignment: 0x4, Offset: 0x8}), 3207 }, 3208 { 3209 name: "i32.atomic.rmw8.add_u", 3210 body: []byte{ 3211 wasm.OpcodeI32Const, 0x0, 3212 wasm.OpcodeI32Const, 0x1, 3213 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI32Rmw8AddU, 0x1, 0x8, // alignment=2^1, offset=8 3214 }, 3215 expected: newOperationAtomicRMW8(unsignedTypeI32, memoryArg{Alignment: 0x1, Offset: 0x8}, atomicArithmeticOpAdd), 3216 }, 3217 { 3218 name: "i32.atomic.rmw16.add_u", 3219 body: []byte{ 3220 wasm.OpcodeI32Const, 0x0, 3221 wasm.OpcodeI32Const, 0x1, 3222 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI32Rmw16AddU, 0x2, 0x8, // alignment=2^(2-1), offset=8 3223 }, 3224 expected: newOperationAtomicRMW16(unsignedTypeI32, memoryArg{Alignment: 0x2, Offset: 0x8}, atomicArithmeticOpAdd), 3225 }, 3226 { 3227 name: "i32.atomic.rmw.add", 3228 body: []byte{ 3229 wasm.OpcodeI32Const, 0x0, 3230 wasm.OpcodeI32Const, 0x1, 3231 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI32RmwAdd, 0x3, 0x8, // alignment=2^(3-1), offset=8 3232 }, 3233 expected: newOperationAtomicRMW(unsignedTypeI32, memoryArg{Alignment: 0x3, Offset: 0x8}, atomicArithmeticOpAdd), 3234 }, 3235 { 3236 name: "i64.atomic.rmw8.add_u", 3237 body: []byte{ 3238 wasm.OpcodeI32Const, 0x0, 3239 wasm.OpcodeI64Const, 0x1, 3240 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64Rmw8AddU, 0x1, 0x8, // alignment=2^1, offset=8 3241 }, 3242 expected: newOperationAtomicRMW8(unsignedTypeI64, memoryArg{Alignment: 0x1, Offset: 0x8}, atomicArithmeticOpAdd), 3243 }, 3244 { 3245 name: "i64.atomic.rmw16.add_u", 3246 body: []byte{ 3247 wasm.OpcodeI32Const, 0x0, 3248 wasm.OpcodeI64Const, 0x1, 3249 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64Rmw16AddU, 0x2, 0x8, // alignment=2^(2-1), offset=8 3250 }, 3251 expected: newOperationAtomicRMW16(unsignedTypeI64, memoryArg{Alignment: 0x2, Offset: 0x8}, atomicArithmeticOpAdd), 3252 }, 3253 { 3254 name: "i64.atomic.rmw32.add_u", 3255 body: []byte{ 3256 wasm.OpcodeI32Const, 0x0, 3257 wasm.OpcodeI64Const, 0x1, 3258 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64Rmw32AddU, 0x3, 0x8, // alignment=2^(3-1), offset=8 3259 }, 3260 expected: newOperationAtomicRMW(unsignedTypeI32, memoryArg{Alignment: 0x3, Offset: 0x8}, atomicArithmeticOpAdd), 3261 }, 3262 { 3263 name: "i64.atomic.rmw.add", 3264 body: []byte{ 3265 wasm.OpcodeI32Const, 0x0, 3266 wasm.OpcodeI64Const, 0x1, 3267 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64RmwAdd, 0x4, 0x8, // alignment=2^(4-1), offset=8 3268 }, 3269 expected: newOperationAtomicRMW(unsignedTypeI64, memoryArg{Alignment: 0x4, Offset: 0x8}, atomicArithmeticOpAdd), 3270 }, 3271 { 3272 name: "i32.atomic.rmw8.sub_u", 3273 body: []byte{ 3274 wasm.OpcodeI32Const, 0x0, 3275 wasm.OpcodeI32Const, 0x1, 3276 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI32Rmw8SubU, 0x1, 0x8, // alignment=2^1, offset=8 3277 }, 3278 expected: newOperationAtomicRMW8(unsignedTypeI32, memoryArg{Alignment: 0x1, Offset: 0x8}, atomicArithmeticOpSub), 3279 }, 3280 { 3281 name: "i32.atomic.rmw16.sub_u", 3282 body: []byte{ 3283 wasm.OpcodeI32Const, 0x0, 3284 wasm.OpcodeI32Const, 0x1, 3285 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI32Rmw16SubU, 0x2, 0x8, // alignment=2^(2-1), offset=8 3286 }, 3287 expected: newOperationAtomicRMW16(unsignedTypeI32, memoryArg{Alignment: 0x2, Offset: 0x8}, atomicArithmeticOpSub), 3288 }, 3289 { 3290 name: "i32.atomic.rmw.sub", 3291 body: []byte{ 3292 wasm.OpcodeI32Const, 0x0, 3293 wasm.OpcodeI32Const, 0x1, 3294 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI32RmwSub, 0x3, 0x8, // alignment=2^(3-1), offset=8 3295 }, 3296 expected: newOperationAtomicRMW(unsignedTypeI32, memoryArg{Alignment: 0x3, Offset: 0x8}, atomicArithmeticOpSub), 3297 }, 3298 { 3299 name: "i64.atomic.rmw8.sub_u", 3300 body: []byte{ 3301 wasm.OpcodeI32Const, 0x0, 3302 wasm.OpcodeI64Const, 0x1, 3303 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64Rmw8SubU, 0x1, 0x8, // alignment=2^1, offset=8 3304 }, 3305 expected: newOperationAtomicRMW8(unsignedTypeI64, memoryArg{Alignment: 0x1, Offset: 0x8}, atomicArithmeticOpSub), 3306 }, 3307 { 3308 name: "i64.atomic.rmw16.sub_u", 3309 body: []byte{ 3310 wasm.OpcodeI32Const, 0x0, 3311 wasm.OpcodeI64Const, 0x1, 3312 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64Rmw16SubU, 0x2, 0x8, // alignment=2^(2-1), offset=8 3313 }, 3314 expected: newOperationAtomicRMW16(unsignedTypeI64, memoryArg{Alignment: 0x2, Offset: 0x8}, atomicArithmeticOpSub), 3315 }, 3316 { 3317 name: "i64.atomic.rmw32.sub_u", 3318 body: []byte{ 3319 wasm.OpcodeI32Const, 0x0, 3320 wasm.OpcodeI64Const, 0x1, 3321 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64Rmw32SubU, 0x3, 0x8, // alignment=2^(3-1), offset=8 3322 }, 3323 expected: newOperationAtomicRMW(unsignedTypeI32, memoryArg{Alignment: 0x3, Offset: 0x8}, atomicArithmeticOpSub), 3324 }, 3325 { 3326 name: "i64.atomic.rmw.sub", 3327 body: []byte{ 3328 wasm.OpcodeI32Const, 0x0, 3329 wasm.OpcodeI64Const, 0x1, 3330 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64RmwSub, 0x4, 0x8, // alignment=2^(4-1), offset=8 3331 }, 3332 expected: newOperationAtomicRMW(unsignedTypeI64, memoryArg{Alignment: 0x4, Offset: 0x8}, atomicArithmeticOpSub), 3333 }, 3334 { 3335 name: "i32.atomic.rmw8.and_u", 3336 body: []byte{ 3337 wasm.OpcodeI32Const, 0x0, 3338 wasm.OpcodeI32Const, 0x1, 3339 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI32Rmw8AndU, 0x1, 0x8, // alignment=2^1, offset=8 3340 }, 3341 expected: newOperationAtomicRMW8(unsignedTypeI32, memoryArg{Alignment: 0x1, Offset: 0x8}, atomicArithmeticOpAnd), 3342 }, 3343 { 3344 name: "i32.atomic.rmw16.and_u", 3345 body: []byte{ 3346 wasm.OpcodeI32Const, 0x0, 3347 wasm.OpcodeI32Const, 0x1, 3348 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI32Rmw16AndU, 0x2, 0x8, // alignment=2^(2-1), offset=8 3349 }, 3350 expected: newOperationAtomicRMW16(unsignedTypeI32, memoryArg{Alignment: 0x2, Offset: 0x8}, atomicArithmeticOpAnd), 3351 }, 3352 { 3353 name: "i32.atomic.rmw.and", 3354 body: []byte{ 3355 wasm.OpcodeI32Const, 0x0, 3356 wasm.OpcodeI32Const, 0x1, 3357 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI32RmwAnd, 0x3, 0x8, // alignment=2^(3-1), offset=8 3358 }, 3359 expected: newOperationAtomicRMW(unsignedTypeI32, memoryArg{Alignment: 0x3, Offset: 0x8}, atomicArithmeticOpAnd), 3360 }, 3361 { 3362 name: "i64.atomic.rmw8.and_u", 3363 body: []byte{ 3364 wasm.OpcodeI32Const, 0x0, 3365 wasm.OpcodeI64Const, 0x1, 3366 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64Rmw8AndU, 0x1, 0x8, // alignment=2^1, offset=8 3367 }, 3368 expected: newOperationAtomicRMW8(unsignedTypeI64, memoryArg{Alignment: 0x1, Offset: 0x8}, atomicArithmeticOpAnd), 3369 }, 3370 { 3371 name: "i64.atomic.rmw16.and_u", 3372 body: []byte{ 3373 wasm.OpcodeI32Const, 0x0, 3374 wasm.OpcodeI64Const, 0x1, 3375 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64Rmw16AndU, 0x2, 0x8, // alignment=2^(2-1), offset=8 3376 }, 3377 expected: newOperationAtomicRMW16(unsignedTypeI64, memoryArg{Alignment: 0x2, Offset: 0x8}, atomicArithmeticOpAnd), 3378 }, 3379 { 3380 name: "i64.atomic.rmw32.and_u", 3381 body: []byte{ 3382 wasm.OpcodeI32Const, 0x0, 3383 wasm.OpcodeI64Const, 0x1, 3384 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64Rmw32AndU, 0x3, 0x8, // alignment=2^(3-1), offset=8 3385 }, 3386 expected: newOperationAtomicRMW(unsignedTypeI32, memoryArg{Alignment: 0x3, Offset: 0x8}, atomicArithmeticOpAnd), 3387 }, 3388 { 3389 name: "i64.atomic.rmw.and", 3390 body: []byte{ 3391 wasm.OpcodeI32Const, 0x0, 3392 wasm.OpcodeI64Const, 0x1, 3393 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64RmwAnd, 0x4, 0x8, // alignment=2^(4-1), offset=8 3394 }, 3395 expected: newOperationAtomicRMW(unsignedTypeI64, memoryArg{Alignment: 0x4, Offset: 0x8}, atomicArithmeticOpAnd), 3396 }, 3397 { 3398 name: "i32.atomic.rmw8.or", 3399 body: []byte{ 3400 wasm.OpcodeI32Const, 0x0, 3401 wasm.OpcodeI32Const, 0x1, 3402 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI32Rmw8OrU, 0x1, 0x8, // alignment=2^1, offset=8 3403 }, 3404 expected: newOperationAtomicRMW8(unsignedTypeI32, memoryArg{Alignment: 0x1, Offset: 0x8}, atomicArithmeticOpOr), 3405 }, 3406 { 3407 name: "i32.atomic.rmw16.or_u", 3408 body: []byte{ 3409 wasm.OpcodeI32Const, 0x0, 3410 wasm.OpcodeI32Const, 0x1, 3411 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI32Rmw16OrU, 0x2, 0x8, // alignment=2^(2-1), offset=8 3412 }, 3413 expected: newOperationAtomicRMW16(unsignedTypeI32, memoryArg{Alignment: 0x2, Offset: 0x8}, atomicArithmeticOpOr), 3414 }, 3415 { 3416 name: "i32.atomic.rmw.or", 3417 body: []byte{ 3418 wasm.OpcodeI32Const, 0x0, 3419 wasm.OpcodeI32Const, 0x1, 3420 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI32RmwOr, 0x3, 0x8, // alignment=2^(3-1), offset=8 3421 }, 3422 expected: newOperationAtomicRMW(unsignedTypeI32, memoryArg{Alignment: 0x3, Offset: 0x8}, atomicArithmeticOpOr), 3423 }, 3424 { 3425 name: "i64.atomic.rmw8.or_u", 3426 body: []byte{ 3427 wasm.OpcodeI32Const, 0x0, 3428 wasm.OpcodeI64Const, 0x1, 3429 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64Rmw8OrU, 0x1, 0x8, // alignment=2^1, offset=8 3430 }, 3431 expected: newOperationAtomicRMW8(unsignedTypeI64, memoryArg{Alignment: 0x1, Offset: 0x8}, atomicArithmeticOpOr), 3432 }, 3433 { 3434 name: "i64.atomic.rmw16.or_u", 3435 body: []byte{ 3436 wasm.OpcodeI32Const, 0x0, 3437 wasm.OpcodeI64Const, 0x1, 3438 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64Rmw16OrU, 0x2, 0x8, // alignment=2^(2-1), offset=8 3439 }, 3440 expected: newOperationAtomicRMW16(unsignedTypeI64, memoryArg{Alignment: 0x2, Offset: 0x8}, atomicArithmeticOpOr), 3441 }, 3442 { 3443 name: "i64.atomic.rmw32.or_u", 3444 body: []byte{ 3445 wasm.OpcodeI32Const, 0x0, 3446 wasm.OpcodeI64Const, 0x1, 3447 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64Rmw32OrU, 0x3, 0x8, // alignment=2^(3-1), offset=8 3448 }, 3449 expected: newOperationAtomicRMW(unsignedTypeI32, memoryArg{Alignment: 0x3, Offset: 0x8}, atomicArithmeticOpOr), 3450 }, 3451 { 3452 name: "i64.atomic.rmw.or", 3453 body: []byte{ 3454 wasm.OpcodeI32Const, 0x0, 3455 wasm.OpcodeI64Const, 0x1, 3456 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64RmwOr, 0x4, 0x8, // alignment=2^(4-1), offset=8 3457 }, 3458 expected: newOperationAtomicRMW(unsignedTypeI64, memoryArg{Alignment: 0x4, Offset: 0x8}, atomicArithmeticOpOr), 3459 }, 3460 { 3461 name: "i32.atomic.rmw8.xor_u", 3462 body: []byte{ 3463 wasm.OpcodeI32Const, 0x0, 3464 wasm.OpcodeI32Const, 0x1, 3465 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI32Rmw8XorU, 0x1, 0x8, // alignment=2^1, offset=8 3466 }, 3467 expected: newOperationAtomicRMW8(unsignedTypeI32, memoryArg{Alignment: 0x1, Offset: 0x8}, atomicArithmeticOpXor), 3468 }, 3469 { 3470 name: "i32.atomic.rmw16.xor_u", 3471 body: []byte{ 3472 wasm.OpcodeI32Const, 0x0, 3473 wasm.OpcodeI32Const, 0x1, 3474 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI32Rmw16XorU, 0x2, 0x8, // alignment=2^(2-1), offset=8 3475 }, 3476 expected: newOperationAtomicRMW16(unsignedTypeI32, memoryArg{Alignment: 0x2, Offset: 0x8}, atomicArithmeticOpXor), 3477 }, 3478 { 3479 name: "i32.atomic.rmw.xor", 3480 body: []byte{ 3481 wasm.OpcodeI32Const, 0x0, 3482 wasm.OpcodeI32Const, 0x1, 3483 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI32RmwXor, 0x3, 0x8, // alignment=2^(3-1), offset=8 3484 }, 3485 expected: newOperationAtomicRMW(unsignedTypeI32, memoryArg{Alignment: 0x3, Offset: 0x8}, atomicArithmeticOpXor), 3486 }, 3487 { 3488 name: "i64.atomic.rmw8.xor_u", 3489 body: []byte{ 3490 wasm.OpcodeI32Const, 0x0, 3491 wasm.OpcodeI64Const, 0x1, 3492 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64Rmw8XorU, 0x1, 0x8, // alignment=2^1, offset=8 3493 }, 3494 expected: newOperationAtomicRMW8(unsignedTypeI64, memoryArg{Alignment: 0x1, Offset: 0x8}, atomicArithmeticOpXor), 3495 }, 3496 { 3497 name: "i64.atomic.rmw16.xor_u", 3498 body: []byte{ 3499 wasm.OpcodeI32Const, 0x0, 3500 wasm.OpcodeI64Const, 0x1, 3501 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64Rmw16XorU, 0x2, 0x8, // alignment=2^(2-1), offset=8 3502 }, 3503 expected: newOperationAtomicRMW16(unsignedTypeI64, memoryArg{Alignment: 0x2, Offset: 0x8}, atomicArithmeticOpXor), 3504 }, 3505 { 3506 name: "i64.atomic.rmw32.xor_u", 3507 body: []byte{ 3508 wasm.OpcodeI32Const, 0x0, 3509 wasm.OpcodeI64Const, 0x1, 3510 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64Rmw32XorU, 0x3, 0x8, // alignment=2^(3-1), offset=8 3511 }, 3512 expected: newOperationAtomicRMW(unsignedTypeI32, memoryArg{Alignment: 0x3, Offset: 0x8}, atomicArithmeticOpXor), 3513 }, 3514 { 3515 name: "i64.atomic.rmw.xor", 3516 body: []byte{ 3517 wasm.OpcodeI32Const, 0x0, 3518 wasm.OpcodeI64Const, 0x1, 3519 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64RmwXor, 0x4, 0x8, // alignment=2^(4-1), offset=8 3520 }, 3521 expected: newOperationAtomicRMW(unsignedTypeI64, memoryArg{Alignment: 0x4, Offset: 0x8}, atomicArithmeticOpXor), 3522 }, 3523 { 3524 name: "i32.atomic.rmw8.xchg_u", 3525 body: []byte{ 3526 wasm.OpcodeI32Const, 0x0, 3527 wasm.OpcodeI32Const, 0x1, 3528 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI32Rmw8XchgU, 0x1, 0x8, // alignment=2^1, offset=8 3529 }, 3530 expected: newOperationAtomicRMW8(unsignedTypeI32, memoryArg{Alignment: 0x1, Offset: 0x8}, atomicArithmeticOpNop), 3531 }, 3532 { 3533 name: "i32.atomic.rmw16.xchg_u", 3534 body: []byte{ 3535 wasm.OpcodeI32Const, 0x0, 3536 wasm.OpcodeI32Const, 0x1, 3537 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI32Rmw16XchgU, 0x2, 0x8, // alignment=2^(2-1), offset=8 3538 }, 3539 expected: newOperationAtomicRMW16(unsignedTypeI32, memoryArg{Alignment: 0x2, Offset: 0x8}, atomicArithmeticOpNop), 3540 }, 3541 { 3542 name: "i32.atomic.rmw.xchg", 3543 body: []byte{ 3544 wasm.OpcodeI32Const, 0x0, 3545 wasm.OpcodeI32Const, 0x1, 3546 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI32RmwXchg, 0x3, 0x8, // alignment=2^(3-1), offset=8 3547 }, 3548 expected: newOperationAtomicRMW(unsignedTypeI32, memoryArg{Alignment: 0x3, Offset: 0x8}, atomicArithmeticOpNop), 3549 }, 3550 { 3551 name: "i64.atomic.rmw8.xchg_u", 3552 body: []byte{ 3553 wasm.OpcodeI32Const, 0x0, 3554 wasm.OpcodeI64Const, 0x1, 3555 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64Rmw8XchgU, 0x1, 0x8, // alignment=2^1, offset=8 3556 }, 3557 expected: newOperationAtomicRMW8(unsignedTypeI64, memoryArg{Alignment: 0x1, Offset: 0x8}, atomicArithmeticOpNop), 3558 }, 3559 { 3560 name: "i64.atomic.rmw16.xchg_u", 3561 body: []byte{ 3562 wasm.OpcodeI32Const, 0x0, 3563 wasm.OpcodeI64Const, 0x1, 3564 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64Rmw16XchgU, 0x2, 0x8, // alignment=2^(2-1), offset=8 3565 }, 3566 expected: newOperationAtomicRMW16(unsignedTypeI64, memoryArg{Alignment: 0x2, Offset: 0x8}, atomicArithmeticOpNop), 3567 }, 3568 { 3569 name: "i64.atomic.rmw32.xchg_u", 3570 body: []byte{ 3571 wasm.OpcodeI32Const, 0x0, 3572 wasm.OpcodeI64Const, 0x1, 3573 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64Rmw32XchgU, 0x3, 0x8, // alignment=2^(3-1), offset=8 3574 }, 3575 expected: newOperationAtomicRMW(unsignedTypeI32, memoryArg{Alignment: 0x3, Offset: 0x8}, atomicArithmeticOpNop), 3576 }, 3577 { 3578 name: "i64.atomic.rmw.xchg", 3579 body: []byte{ 3580 wasm.OpcodeI32Const, 0x0, 3581 wasm.OpcodeI64Const, 0x1, 3582 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64RmwXchg, 0x4, 0x8, // alignment=2^(4-1), offset=8 3583 }, 3584 expected: newOperationAtomicRMW(unsignedTypeI64, memoryArg{Alignment: 0x4, Offset: 0x8}, atomicArithmeticOpNop), 3585 }, 3586 { 3587 name: "i32.atomic.rmw8.cmpxchg_u", 3588 body: []byte{ 3589 wasm.OpcodeI32Const, 0x0, 3590 wasm.OpcodeI32Const, 0x1, 3591 wasm.OpcodeI32Const, 0x2, 3592 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI32Rmw8CmpxchgU, 0x1, 0x8, // alignment=2^1, offset=8 3593 }, 3594 expected: newOperationAtomicRMW8Cmpxchg(unsignedTypeI32, memoryArg{Alignment: 0x1, Offset: 0x8}), 3595 }, 3596 { 3597 name: "i32.atomic.rmw16.cmpxchg_u", 3598 body: []byte{ 3599 wasm.OpcodeI32Const, 0x0, 3600 wasm.OpcodeI32Const, 0x1, 3601 wasm.OpcodeI32Const, 0x2, 3602 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI32Rmw16CmpxchgU, 0x2, 0x8, // alignment=2^(2-1), offset=8 3603 }, 3604 expected: newOperationAtomicRMW16Cmpxchg(unsignedTypeI32, memoryArg{Alignment: 0x2, Offset: 0x8}), 3605 }, 3606 { 3607 name: "i32.atomic.rmw.cmpxchg", 3608 body: []byte{ 3609 wasm.OpcodeI32Const, 0x0, 3610 wasm.OpcodeI32Const, 0x1, 3611 wasm.OpcodeI32Const, 0x2, 3612 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI32RmwCmpxchg, 0x3, 0x8, // alignment=2^(3-1), offset=8 3613 }, 3614 expected: newOperationAtomicRMWCmpxchg(unsignedTypeI32, memoryArg{Alignment: 0x3, Offset: 0x8}), 3615 }, 3616 { 3617 name: "i64.atomic.rmw8.xchg_u", 3618 body: []byte{ 3619 wasm.OpcodeI32Const, 0x0, 3620 wasm.OpcodeI64Const, 0x1, 3621 wasm.OpcodeI64Const, 0x2, 3622 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64Rmw8CmpxchgU, 0x1, 0x8, // alignment=2^1, offset=8 3623 }, 3624 expected: newOperationAtomicRMW8Cmpxchg(unsignedTypeI64, memoryArg{Alignment: 0x1, Offset: 0x8}), 3625 }, 3626 { 3627 name: "i64.atomic.rmw16.cmpxchg_u", 3628 body: []byte{ 3629 wasm.OpcodeI32Const, 0x0, 3630 wasm.OpcodeI64Const, 0x1, 3631 wasm.OpcodeI64Const, 0x2, 3632 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64Rmw16CmpxchgU, 0x2, 0x8, // alignment=2^(2-1), offset=8 3633 }, 3634 expected: newOperationAtomicRMW16Cmpxchg(unsignedTypeI64, memoryArg{Alignment: 0x2, Offset: 0x8}), 3635 }, 3636 { 3637 name: "i64.atomic.rmw32.cmpxchg_u", 3638 body: []byte{ 3639 wasm.OpcodeI32Const, 0x0, 3640 wasm.OpcodeI64Const, 0x1, 3641 wasm.OpcodeI64Const, 0x1, 3642 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64Rmw32CmpxchgU, 0x3, 0x8, // alignment=2^(3-1), offset=8 3643 }, 3644 expected: newOperationAtomicRMWCmpxchg(unsignedTypeI32, memoryArg{Alignment: 0x3, Offset: 0x8}), 3645 }, 3646 { 3647 name: "i64.atomic.rmw.cmpxchg", 3648 body: []byte{ 3649 wasm.OpcodeI32Const, 0x0, 3650 wasm.OpcodeI64Const, 0x1, 3651 wasm.OpcodeI64Const, 0x2, 3652 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicI64RmwCmpxchg, 0x4, 0x8, // alignment=2^(4-1), offset=8 3653 }, 3654 expected: newOperationAtomicRMWCmpxchg(unsignedTypeI64, memoryArg{Alignment: 0x4, Offset: 0x8}), 3655 }, 3656 { 3657 name: "memory.atomic.wait32", 3658 body: []byte{ 3659 wasm.OpcodeI32Const, 0x0, 3660 wasm.OpcodeI32Const, 0x1, 3661 wasm.OpcodeI64Const, 0x2, 3662 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicMemoryWait32, 0x3, 0x8, // alignment=2^(3-1), offset=8 3663 }, 3664 expected: newOperationAtomicMemoryWait(unsignedTypeI32, memoryArg{Alignment: 0x3, Offset: 0x8}), 3665 }, 3666 { 3667 name: "memory.atomic.wait64", 3668 body: []byte{ 3669 wasm.OpcodeI32Const, 0x0, 3670 wasm.OpcodeI64Const, 0x1, 3671 wasm.OpcodeI64Const, 0x2, 3672 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicMemoryWait64, 0x4, 0x8, // alignment=2^(4-1), offset=8 3673 }, 3674 expected: newOperationAtomicMemoryWait(unsignedTypeI64, memoryArg{Alignment: 0x4, Offset: 0x8}), 3675 }, 3676 { 3677 name: "memory.atomic.notify", 3678 body: []byte{ 3679 wasm.OpcodeI32Const, 0x0, 3680 wasm.OpcodeI32Const, 0x1, 3681 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicMemoryNotify, 0x3, 0x8, // alignment=2^(3-1), offset=8 3682 }, 3683 expected: newOperationAtomicMemoryNotify(memoryArg{Alignment: 0x3, Offset: 0x8}), 3684 }, 3685 { 3686 name: "memory.atomic.fence", 3687 body: []byte{ 3688 wasm.OpcodeAtomicPrefix, wasm.OpcodeAtomicFence, 0x0, // consistency=0 3689 }, 3690 noDropBeforeReturn: true, 3691 expected: newOperationAtomicFence(), 3692 }, 3693 } 3694 3695 for _, tc := range tests { 3696 tt := tc 3697 t.Run(tt.name, func(t *testing.T) { 3698 body := append([]byte{}, tt.body...) 3699 if !tt.noDropBeforeReturn { 3700 body = append(body, wasm.OpcodeDrop) 3701 } 3702 body = append(body, wasm.OpcodeEnd) 3703 module := &wasm.Module{ 3704 TypeSection: []wasm.FunctionType{v_v}, 3705 FunctionSection: []wasm.Index{0}, 3706 MemorySection: &wasm.Memory{}, 3707 CodeSection: []wasm.Code{{Body: body}}, 3708 } 3709 c, err := newCompiler(api.CoreFeaturesV2, 0, module, false) 3710 require.NoError(t, err) 3711 3712 res, err := c.Next() 3713 require.NoError(t, err) 3714 if tt.noDropBeforeReturn { 3715 require.Equal(t, tc.expected, res.Operations[len(res.Operations)-2]) 3716 } else { 3717 require.Equal(t, tc.expected, res.Operations[len(res.Operations)-3]) 3718 } 3719 }) 3720 } 3721 }