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