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