Files
wazero/internal/engine/wazevo/frontend/frontend_test.go
Takeshi Yoneda f4324b17cd wazevo: passes ref_func spectest (#1751)
Signed-off-by: Takeshi Yoneda <t.y.mathetake@gmail.com>
2023-10-04 08:16:22 +09:00

1929 lines
48 KiB
Go

package frontend
import (
"fmt"
"testing"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/internal/engine/wazevo/ssa"
"github.com/tetratelabs/wazero/internal/engine/wazevo/testcases"
"github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi"
"github.com/tetratelabs/wazero/internal/testing/require"
"github.com/tetratelabs/wazero/internal/wasm"
)
func TestCompiler_LowerToSSA(t *testing.T) {
// Most of the logic should look similar to Cranelift's Wasm frontend, so when you want to see
// what output should look like, you can run:
// `~/wasmtime/target/debug/clif-util wasm --target aarch64-apple-darwin testcase.wat -p -t`
for _, tc := range []struct {
name string
ensureTermination bool
needListener bool
// m is the *wasm.Module to be compiled in this test.
m *wasm.Module
// targetIndex is the index of a local function to be compiled in this test.
targetIndex wasm.Index
// exp is the *unoptimized* expected SSA IR for the function m.FunctionSection[targetIndex].
exp string
// expAfterOpt is not empty when we want to check the result after optimization passes.
expAfterOpt string
}{
{
name: "empty", m: testcases.Empty.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64)
Jump blk_ret
`,
},
{
name: "unreachable", m: testcases.Unreachable.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64)
Exit exec_ctx, unreachable
`,
},
{
name: testcases.OnlyReturn.Name, m: testcases.OnlyReturn.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64)
Return
`,
},
{
name: "params", m: testcases.Params.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:f32, v4:f64)
Return
`,
},
{
name: "add/sub params return", m: testcases.AddSubParamsReturn.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i32)
v4:i32 = Iadd v2, v3
v5:i32 = Isub v4, v2
Jump blk_ret, v5
`,
},
{
name: "add/sub params return / listener", m: testcases.AddSubParamsReturn.Module,
needListener: true,
exp: `
signatures:
sig1: i64i32i32i32_v
sig2: i64i32i32_v
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i32)
Store module_ctx, exec_ctx, 0x8
v4:i64 = Load module_ctx, 0x8
v5:i64 = Load v4, 0x0
v6:i32 = Iconst_32 0x0
CallIndirect v5:sig1, exec_ctx, v6, v2, v3
v7:i32 = Iadd v2, v3
v8:i32 = Isub v7, v2
Store module_ctx, exec_ctx, 0x8
v9:i64 = Load module_ctx, 0x10
v10:i64 = Load v9, 0x0
v11:i32 = Iconst_32 0x0
CallIndirect v10:sig2, exec_ctx, v11, v8
Jump blk_ret, v8
`,
},
{
name: "locals", m: testcases.Locals.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64)
v2:i32 = Iconst_32 0x0
v3:i64 = Iconst_64 0x0
v4:f32 = F32const 0.000000
v5:f64 = F64const 0.000000
Jump blk_ret
`,
expAfterOpt: `
blk0: (exec_ctx:i64, module_ctx:i64)
Jump blk_ret
`,
},
{
name: "selects", m: testcases.Selects.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i32, v4:i64, v5:i64, v6:f32, v7:f32, v8:f64, v9:f64)
v10:i32 = Icmp eq, v4, v5
v11:i32 = Select v10, v2, v3
v12:i64 = Select v3, v4, v5
v13:i32 = Fcmp gt, v8, v9
v14:f32 = Select v13, v6, v7
v15:i32 = Fcmp neq, v6, v7
v16:f64 = Select v15, v8, v9
Jump blk_ret, v11, v12, v14, v16
`,
},
{
name: "local param tee return", m: testcases.LocalParamTeeReturn.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32)
v3:i32 = Iconst_32 0x0
Jump blk_ret, v2, v2
`,
expAfterOpt: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32)
Jump blk_ret, v2, v2
`,
},
{
name: "locals + params", m: testcases.LocalsParams.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i64, v3:f32, v4:f64)
v5:i32 = Iconst_32 0x0
v6:i64 = Iconst_64 0x0
v7:f32 = F32const 0.000000
v8:f64 = F64const 0.000000
v9:i64 = Iadd v2, v2
v10:i64 = Isub v9, v2
v11:f32 = Fadd v3, v3
v12:f32 = Fsub v11, v3
v13:f32 = Fmul v12, v3
v14:f32 = Fdiv v13, v3
v15:f32 = Fmax v14, v3
v16:f32 = Fmin v15, v3
v17:f64 = Fadd v4, v4
v18:f64 = Fsub v17, v4
v19:f64 = Fmul v18, v4
v20:f64 = Fdiv v19, v4
v21:f64 = Fmax v20, v4
v22:f64 = Fmin v21, v4
Jump blk_ret, v10, v16, v22
`,
expAfterOpt: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i64, v3:f32, v4:f64)
v9:i64 = Iadd v2, v2
v10:i64 = Isub v9, v2
v11:f32 = Fadd v3, v3
v12:f32 = Fsub v11, v3
v13:f32 = Fmul v12, v3
v14:f32 = Fdiv v13, v3
v15:f32 = Fmax v14, v3
v16:f32 = Fmin v15, v3
v17:f64 = Fadd v4, v4
v18:f64 = Fsub v17, v4
v19:f64 = Fmul v18, v4
v20:f64 = Fdiv v19, v4
v21:f64 = Fmax v20, v4
v22:f64 = Fmin v21, v4
Jump blk_ret, v10, v16, v22
`,
},
{
name: "locals + params + return", m: testcases.LocalParamReturn.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32)
v3:i32 = Iconst_32 0x0
Jump blk_ret, v2, v3
`,
},
{
name: "swap param and return", m: testcases.SwapParamAndReturn.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i32)
Jump blk_ret, v3, v2
`,
},
{
name: "swap params and return", m: testcases.SwapParamsAndReturn.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i32)
Jump blk1
blk1: () <-- (blk0)
Jump blk_ret, v3, v2
`,
},
{
name: "block - br", m: testcases.BlockBr.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64)
v2:i32 = Iconst_32 0x0
v3:i64 = Iconst_64 0x0
v4:f32 = F32const 0.000000
v5:f64 = F64const 0.000000
Jump blk1
blk1: () <-- (blk0)
Jump blk_ret
`,
},
{
name: "block - br_if", m: testcases.BlockBrIf.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64)
v2:i32 = Iconst_32 0x0
Brnz v2, blk1
Jump blk2
blk1: () <-- (blk0)
Jump blk_ret
blk2: () <-- (blk0)
Exit exec_ctx, unreachable
`,
},
{
name: "loop - br", m: testcases.LoopBr.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64)
Jump blk1
blk1: () <-- (blk0,blk1)
Jump blk1
blk2: ()
`,
expAfterOpt: `
blk0: (exec_ctx:i64, module_ctx:i64)
Jump blk1
blk1: () <-- (blk0,blk1)
Jump blk1
`,
},
{
name: "loop - br / ensure termination", m: testcases.LoopBr.Module,
ensureTermination: true,
exp: `
signatures:
sig2: i64_v
blk0: (exec_ctx:i64, module_ctx:i64)
Jump blk1
blk1: () <-- (blk0,blk1)
v2:i64 = Load exec_ctx, 0x58
CallIndirect v2:sig2, exec_ctx
Jump blk1
blk2: ()
`,
expAfterOpt: `
signatures:
sig2: i64_v
blk0: (exec_ctx:i64, module_ctx:i64)
Jump blk1
blk1: () <-- (blk0,blk1)
v2:i64 = Load exec_ctx, 0x58
CallIndirect v2:sig2, exec_ctx
Jump blk1
`,
},
{
name: "loop - br_if", m: testcases.LoopBrIf.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64)
Jump blk1
blk1: () <-- (blk0,blk1)
v2:i32 = Iconst_32 0x1
Brnz v2, blk1
Jump blk3
blk2: ()
blk3: () <-- (blk1)
Return
`,
expAfterOpt: `
blk0: (exec_ctx:i64, module_ctx:i64)
Jump blk1
blk1: () <-- (blk0,blk1)
v2:i32 = Iconst_32 0x1
Brnz v2, blk1
Jump blk3
blk3: () <-- (blk1)
Return
`,
},
{
name: "block - block - br", m: testcases.BlockBlockBr.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64)
v2:i32 = Iconst_32 0x0
v3:i64 = Iconst_64 0x0
v4:f32 = F32const 0.000000
v5:f64 = F64const 0.000000
Jump blk1
blk1: () <-- (blk0)
Jump blk_ret
blk2: ()
`,
expAfterOpt: `
blk0: (exec_ctx:i64, module_ctx:i64)
Jump blk1
blk1: () <-- (blk0)
Jump blk_ret
`,
},
{
name: "if without else", m: testcases.IfWithoutElse.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64)
v2:i32 = Iconst_32 0x0
Brz v2, blk2
Jump blk1
blk1: () <-- (blk0)
Jump blk3
blk2: () <-- (blk0)
Jump blk3
blk3: () <-- (blk1,blk2)
Jump blk_ret
`,
},
{
name: "if-else", m: testcases.IfElse.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64)
v2:i32 = Iconst_32 0x0
Brz v2, blk2
Jump blk1
blk1: () <-- (blk0)
Jump blk3
blk2: () <-- (blk0)
Jump blk_ret
blk3: () <-- (blk1)
Jump blk_ret
`,
},
{
name: "single predecessor local refs", m: testcases.SinglePredecessorLocalRefs.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64)
v2:i32 = Iconst_32 0x0
v3:i32 = Iconst_32 0x0
v4:i32 = Iconst_32 0x0
Brz v2, blk2
Jump blk1
blk1: () <-- (blk0)
Return v4
blk2: () <-- (blk0)
Jump blk3
blk3: () <-- (blk2)
Jump blk_ret, v2
`,
expAfterOpt: `
blk0: (exec_ctx:i64, module_ctx:i64)
v2:i32 = Iconst_32 0x0
v4:i32 = Iconst_32 0x0
Brz v2, blk2
Jump blk1
blk1: () <-- (blk0)
Return v4
blk2: () <-- (blk0)
Jump blk3
blk3: () <-- (blk2)
Jump blk_ret, v2
`,
},
{
name: "multi predecessors local ref",
m: testcases.MultiPredecessorLocalRef.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i32)
v4:i32 = Iconst_32 0x0
Brz v2, blk2
Jump blk1
blk1: () <-- (blk0)
Jump blk3, v2
blk2: () <-- (blk0)
Jump blk3, v3
blk3: (v5:i32) <-- (blk1,blk2)
Jump blk_ret, v5
`,
expAfterOpt: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i32)
Brz v2, blk2
Jump blk1
blk1: () <-- (blk0)
Jump blk3, v2
blk2: () <-- (blk0)
Jump blk3, v3
blk3: (v5:i32) <-- (blk1,blk2)
Jump blk_ret, v5
`,
},
{
name: "reference value from unsealed block",
m: testcases.ReferenceValueFromUnsealedBlock.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32)
v3:i32 = Iconst_32 0x0
Jump blk1, v2
blk1: (v4:i32) <-- (blk0)
Return v4
blk2: ()
`,
expAfterOpt: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32)
Jump blk1
blk1: () <-- (blk0)
Return v2
`,
},
{
name: "reference value from unsealed block - #2",
m: testcases.ReferenceValueFromUnsealedBlock2.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32)
Jump blk1, v2
blk1: (v3:i32) <-- (blk0,blk1)
Brnz v3, blk1, v3
Jump blk4
blk2: () <-- (blk3)
v4:i32 = Iconst_32 0x0
Jump blk_ret, v4
blk3: () <-- (blk4)
Jump blk2
blk4: () <-- (blk1)
Jump blk3
`,
expAfterOpt: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32)
Jump blk1
blk1: () <-- (blk0,blk1)
Brnz v2, blk1
Jump blk4
blk2: () <-- (blk3)
v4:i32 = Iconst_32 0x0
Jump blk_ret, v4
blk3: () <-- (blk4)
Jump blk2
blk4: () <-- (blk1)
Jump blk3
`,
},
{
name: "reference value from unsealed block - #3",
m: testcases.ReferenceValueFromUnsealedBlock3.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32)
Jump blk1, v2
blk1: (v3:i32) <-- (blk0,blk3)
Brnz v3, blk_ret
Jump blk4
blk2: ()
blk3: () <-- (blk4)
v4:i32 = Iconst_32 0x1
Jump blk1, v4
blk4: () <-- (blk1)
Jump blk3
`,
expAfterOpt: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32)
Jump blk1, v2
blk1: (v3:i32) <-- (blk0,blk3)
Brnz v3, blk_ret
Jump blk4
blk3: () <-- (blk4)
v4:i32 = Iconst_32 0x1
Jump blk1, v4
blk4: () <-- (blk1)
Jump blk3
`,
},
{
name: "call",
m: testcases.Call.Module,
exp: `
signatures:
sig1: i64i64_i32
sig2: i64i64i32i32_i32
sig3: i64i64i32_i32i32
blk0: (exec_ctx:i64, module_ctx:i64)
Store module_ctx, exec_ctx, 0x8
v2:i32 = Call f1:sig1, exec_ctx, module_ctx
v3:i32 = Iconst_32 0x5
Store module_ctx, exec_ctx, 0x8
v4:i32 = Call f2:sig2, exec_ctx, module_ctx, v2, v3
Store module_ctx, exec_ctx, 0x8
v5:i32, v6:i32 = Call f3:sig3, exec_ctx, module_ctx, v4
Jump blk_ret, v5, v6
`,
},
{
name: "call_many_params",
m: testcases.CallManyParams.Module,
exp: `
signatures:
sig1: i64i64i32i64f32f64i32i64f32f64i32i64f32f64i32i64f32f64i32i64f32f64i32i64f32f64i32i64f32f64i32i64f32f64i32i64f32f64i32i64f32f64_v
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i64, v4:f32, v5:f64)
Store module_ctx, exec_ctx, 0x8
Call f1:sig1, exec_ctx, module_ctx, v2, v3, v4, v5, v2, v3, v4, v5, v2, v3, v4, v5, v2, v3, v4, v5, v2, v3, v4, v5, v2, v3, v4, v5, v2, v3, v4, v5, v2, v3, v4, v5, v2, v3, v4, v5, v2, v3, v4, v5
Jump blk_ret
`,
},
{
name: "call_many_returns",
m: testcases.CallManyReturns.Module,
exp: `
signatures:
sig0: i64i64i32i64f32f64_i32i64f32f64i32i64f32f64i32i64f32f64i32i64f32f64i32i64f32f64i32i64f32f64i32i64f32f64i32i64f32f64i32i64f32f64i32i64f32f64
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i64, v4:f32, v5:f64)
Store module_ctx, exec_ctx, 0x8
v6:i32, v7:i64, v8:f32, v9:f64, v10:i32, v11:i64, v12:f32, v13:f64, v14:i32, v15:i64, v16:f32, v17:f64, v18:i32, v19:i64, v20:f32, v21:f64, v22:i32, v23:i64, v24:f32, v25:f64, v26:i32, v27:i64, v28:f32, v29:f64, v30:i32, v31:i64, v32:f32, v33:f64, v34:i32, v35:i64, v36:f32, v37:f64, v38:i32, v39:i64, v40:f32, v41:f64, v42:i32, v43:i64, v44:f32, v45:f64 = Call f1:sig0, exec_ctx, module_ctx, v2, v3, v4, v5
Jump blk_ret, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45
`,
},
{
name: "integer comparisons", m: testcases.IntegerComparisons.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i32, v4:i64, v5:i64)
v6:i32 = Icmp eq, v2, v3
v7:i32 = Icmp eq, v4, v5
v8:i32 = Icmp neq, v2, v3
v9:i32 = Icmp neq, v4, v5
v10:i32 = Icmp lt_s, v2, v3
v11:i32 = Icmp lt_s, v4, v5
v12:i32 = Icmp lt_u, v2, v3
v13:i32 = Icmp lt_u, v4, v5
v14:i32 = Icmp gt_s, v2, v3
v15:i32 = Icmp gt_s, v4, v5
v16:i32 = Icmp gt_u, v2, v3
v17:i32 = Icmp gt_u, v4, v5
v18:i32 = Icmp le_s, v2, v3
v19:i32 = Icmp le_s, v4, v5
v20:i32 = Icmp le_u, v2, v3
v21:i32 = Icmp le_u, v4, v5
v22:i32 = Icmp ge_s, v2, v3
v23:i32 = Icmp ge_s, v4, v5
v24:i32 = Icmp ge_u, v2, v3
v25:i32 = Icmp ge_u, v4, v5
Jump blk_ret, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25
`,
expAfterOpt: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i32, v4:i64, v5:i64)
v6:i32 = Icmp eq, v2, v3
v7:i32 = Icmp eq, v4, v5
v8:i32 = Icmp neq, v2, v3
v9:i32 = Icmp neq, v4, v5
v10:i32 = Icmp lt_s, v2, v3
v11:i32 = Icmp lt_s, v4, v5
v12:i32 = Icmp lt_u, v2, v3
v13:i32 = Icmp lt_u, v4, v5
v14:i32 = Icmp gt_s, v2, v3
v15:i32 = Icmp gt_s, v4, v5
v16:i32 = Icmp gt_u, v2, v3
v17:i32 = Icmp gt_u, v4, v5
v18:i32 = Icmp le_s, v2, v3
v19:i32 = Icmp le_s, v4, v5
v20:i32 = Icmp le_u, v2, v3
v21:i32 = Icmp le_u, v4, v5
v22:i32 = Icmp ge_s, v2, v3
v23:i32 = Icmp ge_s, v4, v5
v24:i32 = Icmp ge_u, v2, v3
v25:i32 = Icmp ge_u, v4, v5
Jump blk_ret, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25
`,
},
{
name: "integer bitwise", m: testcases.IntegerBitwise.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i32, v4:i64, v5:i64)
v6:i32 = Band v2, v3
v7:i32 = Bor v2, v3
v8:i32 = Bxor v2, v3
v9:i32 = Rotr v2, v3
v10:i64 = Band v4, v5
v11:i64 = Bor v4, v5
v12:i64 = Bxor v4, v5
v13:i64 = Iconst_64 0x8
v14:i64 = Ishl v5, v13
v15:i64 = Bxor v4, v14
v16:i64 = Rotl v4, v5
v17:i64 = Rotr v4, v5
Jump blk_ret, v6, v7, v8, v9, v10, v11, v12, v15, v16, v17
`,
},
{
name: "integer shift", m: testcases.IntegerShift.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i32, v4:i64, v5:i64)
v6:i32 = Ishl v2, v3
v7:i32 = Iconst_32 0x1f
v8:i32 = Ishl v2, v7
v9:i64 = Ishl v4, v5
v10:i64 = Iconst_64 0x20
v11:i64 = Ishl v4, v10
v12:i32 = Ushr v2, v3
v13:i32 = Iconst_32 0x1f
v14:i32 = Ushr v2, v13
v15:i64 = Ushr v4, v5
v16:i64 = Iconst_64 0x20
v17:i64 = Ushr v4, v16
v18:i32 = Sshr v2, v3
v19:i32 = Iconst_32 0x1f
v20:i32 = Sshr v2, v19
v21:i64 = Sshr v4, v5
v22:i64 = Iconst_64 0x20
v23:i64 = Sshr v4, v22
Jump blk_ret, v6, v8, v9, v11, v12, v14, v15, v17, v18, v20, v21, v23
`,
},
{
name: "integer extension", m: testcases.IntegerExtensions.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i64)
v4:i64 = SExtend v2, 32->64
v5:i64 = UExtend v2, 32->64
v6:i64 = SExtend v3, 8->64
v7:i64 = SExtend v3, 16->64
v8:i64 = SExtend v3, 32->64
v9:i32 = SExtend v2, 8->32
v10:i32 = SExtend v2, 16->32
Jump blk_ret, v4, v5, v6, v7, v8, v9, v10
`,
},
{
name: "integer bit counts", m: testcases.IntegerBitCounts.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i64)
v4:i32 = Clz v2
v5:i32 = Ctz v2
v6:i32 = Popcnt v2
v7:i64 = Clz v3
v8:i64 = Ctz v3
v9:i64 = Popcnt v3
Jump blk_ret, v4, v5, v6, v7, v8, v9
`,
},
{
name: "float comparisons", m: testcases.FloatComparisons.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:f32, v3:f32, v4:f64, v5:f64)
v6:i32 = Fcmp eq, v2, v3
v7:i32 = Fcmp neq, v2, v3
v8:i32 = Fcmp lt, v2, v3
v9:i32 = Fcmp gt, v2, v3
v10:i32 = Fcmp le, v2, v3
v11:i32 = Fcmp ge, v2, v3
v12:i32 = Fcmp eq, v4, v5
v13:i32 = Fcmp neq, v4, v5
v14:i32 = Fcmp lt, v4, v5
v15:i32 = Fcmp gt, v4, v5
v16:i32 = Fcmp le, v4, v5
v17:i32 = Fcmp ge, v4, v5
Jump blk_ret, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17
`,
},
{
name: "float conversions", m: testcases.FloatConversions.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:f64, v3:f32)
v4:i64 = FcvtToSint v2
v5:i64 = FcvtToSint v3
v6:i32 = FcvtToSint v2
v7:i32 = FcvtToSint v3
v8:i64 = FcvtToUint v2
v9:i64 = FcvtToUint v3
v10:i32 = FcvtToUint v2
v11:i32 = FcvtToUint v3
v12:f32 = Fdemote v2
v13:f64 = Fpromote v3
Jump blk_ret, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13
`,
},
{
name: "non-trapping float conversions", m: testcases.NonTrappingFloatConversions.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:f64, v3:f32)
v4:i64 = FcvtToSintSat v2
v5:i64 = FcvtToSintSat v3
v6:i32 = FcvtToSintSat v2
v7:i32 = FcvtToSintSat v3
v8:i64 = FcvtToUintSat v2
v9:i64 = FcvtToUintSat v3
v10:i32 = FcvtToUintSat v2
v11:i32 = FcvtToUintSat v3
Jump blk_ret, v4, v5, v6, v7, v8, v9, v10, v11
`,
},
{
name: "loop with param and results", m: testcases.LoopBrWithParamResults.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i32)
Jump blk1, v2, v3
blk1: (v4:i32,v5:i32) <-- (blk0,blk1)
v7:i32 = Iconst_32 0x1
Brnz v7, blk1, v4, v5
Jump blk3
blk2: (v6:i32) <-- (blk3)
Jump blk_ret, v6
blk3: () <-- (blk1)
Jump blk2, v4
`,
expAfterOpt: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i32)
Jump blk1
blk1: () <-- (blk0,blk1)
v7:i32 = Iconst_32 0x1
Brnz v7, blk1
Jump blk3
blk2: () <-- (blk3)
Jump blk_ret, v2
blk3: () <-- (blk1)
Jump blk2
`,
},
{
name: "many_params_small_results",
m: testcases.ManyParamsSmallResults.Module,
targetIndex: 0,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i64, v4:f32, v5:f64, v6:i32, v7:i64, v8:f32, v9:f64, v10:i32, v11:i64, v12:f32, v13:f64, v14:i32, v15:i64, v16:f32, v17:f64, v18:i32, v19:i64, v20:f32, v21:f64, v22:i32, v23:i64, v24:f32, v25:f64, v26:i32, v27:i64, v28:f32, v29:f64, v30:i32, v31:i64, v32:f32, v33:f64, v34:i32, v35:i64, v36:f32, v37:f64, v38:i32, v39:i64, v40:f32, v41:f64)
Jump blk_ret, v2, v11, v20, v29
`,
expAfterOpt: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i64, v4:f32, v5:f64, v6:i32, v7:i64, v8:f32, v9:f64, v10:i32, v11:i64, v12:f32, v13:f64, v14:i32, v15:i64, v16:f32, v17:f64, v18:i32, v19:i64, v20:f32, v21:f64, v22:i32, v23:i64, v24:f32, v25:f64, v26:i32, v27:i64, v28:f32, v29:f64, v30:i32, v31:i64, v32:f32, v33:f64, v34:i32, v35:i64, v36:f32, v37:f64, v38:i32, v39:i64, v40:f32, v41:f64)
Jump blk_ret, v2, v11, v20, v29
`,
},
{
name: "small_params_many_results",
m: testcases.SmallParamsManyResults.Module,
targetIndex: 0,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i64, v4:f32, v5:f64)
Jump blk_ret, v2, v3, v4, v5, v2, v3, v4, v5, v2, v3, v4, v5, v2, v3, v4, v5, v2, v3, v4, v5, v2, v3, v4, v5, v2, v3, v4, v5, v2, v3, v4, v5, v2, v3, v4, v5, v2, v3, v4, v5
`,
expAfterOpt: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i64, v4:f32, v5:f64)
Jump blk_ret, v2, v3, v4, v5, v2, v3, v4, v5, v2, v3, v4, v5, v2, v3, v4, v5, v2, v3, v4, v5, v2, v3, v4, v5, v2, v3, v4, v5, v2, v3, v4, v5, v2, v3, v4, v5, v2, v3, v4, v5
`,
},
{
name: "many_params_many_results",
m: testcases.ManyParamsManyResults.Module,
targetIndex: 0,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i64, v4:f32, v5:f64, v6:i32, v7:i64, v8:f32, v9:f64, v10:i32, v11:i64, v12:f32, v13:f64, v14:i32, v15:i64, v16:f32, v17:f64, v18:i32, v19:i64, v20:f32, v21:f64, v22:i32, v23:i64, v24:f32, v25:f64, v26:i32, v27:i64, v28:f32, v29:f64, v30:i32, v31:i64, v32:f32, v33:f64, v34:i32, v35:i64, v36:f32, v37:f64, v38:i32, v39:i64, v40:f32, v41:f64)
Jump blk_ret, v41, v40, v39, v38, v37, v36, v35, v34, v33, v32, v31, v30, v29, v28, v27, v26, v25, v24, v23, v22, v21, v20, v19, v18, v17, v16, v15, v14, v13, v12, v11, v10, v9, v8, v7, v6, v5, v4, v3, v2
`,
expAfterOpt: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i64, v4:f32, v5:f64, v6:i32, v7:i64, v8:f32, v9:f64, v10:i32, v11:i64, v12:f32, v13:f64, v14:i32, v15:i64, v16:f32, v17:f64, v18:i32, v19:i64, v20:f32, v21:f64, v22:i32, v23:i64, v24:f32, v25:f64, v26:i32, v27:i64, v28:f32, v29:f64, v30:i32, v31:i64, v32:f32, v33:f64, v34:i32, v35:i64, v36:f32, v37:f64, v38:i32, v39:i64, v40:f32, v41:f64)
Jump blk_ret, v41, v40, v39, v38, v37, v36, v35, v34, v33, v32, v31, v30, v29, v28, v27, v26, v25, v24, v23, v22, v21, v20, v19, v18, v17, v16, v15, v14, v13, v12, v11, v10, v9, v8, v7, v6, v5, v4, v3, v2
`,
},
{
name: "many_middle_values",
m: testcases.ManyMiddleValues.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:f32)
v4:i32 = Iconst_32 0x1
v5:i32 = Imul v2, v4
v6:i32 = Iconst_32 0x2
v7:i32 = Imul v2, v6
v8:i32 = Iconst_32 0x3
v9:i32 = Imul v2, v8
v10:i32 = Iconst_32 0x4
v11:i32 = Imul v2, v10
v12:i32 = Iconst_32 0x5
v13:i32 = Imul v2, v12
v14:i32 = Iconst_32 0x6
v15:i32 = Imul v2, v14
v16:i32 = Iconst_32 0x7
v17:i32 = Imul v2, v16
v18:i32 = Iconst_32 0x8
v19:i32 = Imul v2, v18
v20:i32 = Iconst_32 0x9
v21:i32 = Imul v2, v20
v22:i32 = Iconst_32 0xa
v23:i32 = Imul v2, v22
v24:i32 = Iconst_32 0xb
v25:i32 = Imul v2, v24
v26:i32 = Iconst_32 0xc
v27:i32 = Imul v2, v26
v28:i32 = Iconst_32 0xd
v29:i32 = Imul v2, v28
v30:i32 = Iconst_32 0xe
v31:i32 = Imul v2, v30
v32:i32 = Iconst_32 0xf
v33:i32 = Imul v2, v32
v34:i32 = Iconst_32 0x10
v35:i32 = Imul v2, v34
v36:i32 = Iconst_32 0x11
v37:i32 = Imul v2, v36
v38:i32 = Iconst_32 0x12
v39:i32 = Imul v2, v38
v40:i32 = Iconst_32 0x13
v41:i32 = Imul v2, v40
v42:i32 = Iconst_32 0x14
v43:i32 = Imul v2, v42
v44:i32 = Iadd v41, v43
v45:i32 = Iadd v39, v44
v46:i32 = Iadd v37, v45
v47:i32 = Iadd v35, v46
v48:i32 = Iadd v33, v47
v49:i32 = Iadd v31, v48
v50:i32 = Iadd v29, v49
v51:i32 = Iadd v27, v50
v52:i32 = Iadd v25, v51
v53:i32 = Iadd v23, v52
v54:i32 = Iadd v21, v53
v55:i32 = Iadd v19, v54
v56:i32 = Iadd v17, v55
v57:i32 = Iadd v15, v56
v58:i32 = Iadd v13, v57
v59:i32 = Iadd v11, v58
v60:i32 = Iadd v9, v59
v61:i32 = Iadd v7, v60
v62:i32 = Iadd v5, v61
v63:f32 = F32const 1.000000
v64:f32 = Fmul v3, v63
v65:f32 = F32const 2.000000
v66:f32 = Fmul v3, v65
v67:f32 = F32const 3.000000
v68:f32 = Fmul v3, v67
v69:f32 = F32const 4.000000
v70:f32 = Fmul v3, v69
v71:f32 = F32const 5.000000
v72:f32 = Fmul v3, v71
v73:f32 = F32const 6.000000
v74:f32 = Fmul v3, v73
v75:f32 = F32const 7.000000
v76:f32 = Fmul v3, v75
v77:f32 = F32const 8.000000
v78:f32 = Fmul v3, v77
v79:f32 = F32const 9.000000
v80:f32 = Fmul v3, v79
v81:f32 = F32const 10.000000
v82:f32 = Fmul v3, v81
v83:f32 = F32const 11.000000
v84:f32 = Fmul v3, v83
v85:f32 = F32const 12.000000
v86:f32 = Fmul v3, v85
v87:f32 = F32const 13.000000
v88:f32 = Fmul v3, v87
v89:f32 = F32const 14.000000
v90:f32 = Fmul v3, v89
v91:f32 = F32const 15.000000
v92:f32 = Fmul v3, v91
v93:f32 = F32const 16.000000
v94:f32 = Fmul v3, v93
v95:f32 = F32const 17.000000
v96:f32 = Fmul v3, v95
v97:f32 = F32const 18.000000
v98:f32 = Fmul v3, v97
v99:f32 = F32const 19.000000
v100:f32 = Fmul v3, v99
v101:f32 = F32const 20.000000
v102:f32 = Fmul v3, v101
v103:f32 = Fadd v100, v102
v104:f32 = Fadd v98, v103
v105:f32 = Fadd v96, v104
v106:f32 = Fadd v94, v105
v107:f32 = Fadd v92, v106
v108:f32 = Fadd v90, v107
v109:f32 = Fadd v88, v108
v110:f32 = Fadd v86, v109
v111:f32 = Fadd v84, v110
v112:f32 = Fadd v82, v111
v113:f32 = Fadd v80, v112
v114:f32 = Fadd v78, v113
v115:f32 = Fadd v76, v114
v116:f32 = Fadd v74, v115
v117:f32 = Fadd v72, v116
v118:f32 = Fadd v70, v117
v119:f32 = Fadd v68, v118
v120:f32 = Fadd v66, v119
v121:f32 = Fadd v64, v120
Jump blk_ret, v62, v121
`,
},
{
name: "recursive_fibonacci", m: testcases.FibonacciRecursive.Module,
exp: `
signatures:
sig0: i64i64i32_i32
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32)
v3:i32 = Iconst_32 0x2
v4:i32 = Icmp lt_s, v2, v3
Brz v4, blk2
Jump blk1
blk1: () <-- (blk0)
Return v2
blk2: () <-- (blk0)
Jump blk3
blk3: () <-- (blk2)
v5:i32 = Iconst_32 0x1
v6:i32 = Isub v2, v5
Store module_ctx, exec_ctx, 0x8
v7:i32 = Call f0:sig0, exec_ctx, module_ctx, v6
v8:i32 = Iconst_32 0x2
v9:i32 = Isub v2, v8
Store module_ctx, exec_ctx, 0x8
v10:i32 = Call f0:sig0, exec_ctx, module_ctx, v9
v11:i32 = Iadd v7, v10
Jump blk_ret, v11
`,
expAfterOpt: `
signatures:
sig0: i64i64i32_i32
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32)
v3:i32 = Iconst_32 0x2
v4:i32 = Icmp lt_s, v2, v3
Brz v4, blk2
Jump blk1
blk1: () <-- (blk0)
Return v2
blk2: () <-- (blk0)
Jump blk3
blk3: () <-- (blk2)
v5:i32 = Iconst_32 0x1
v6:i32 = Isub v2, v5
Store module_ctx, exec_ctx, 0x8
v7:i32 = Call f0:sig0, exec_ctx, module_ctx, v6
v8:i32 = Iconst_32 0x2
v9:i32 = Isub v2, v8
Store module_ctx, exec_ctx, 0x8
v10:i32 = Call f0:sig0, exec_ctx, module_ctx, v9
v11:i32 = Iadd v7, v10
Jump blk_ret, v11
`,
},
{
name: "memory_store_basic", m: testcases.MemoryStoreBasic.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i32)
v4:i64 = Iconst_64 0x4
v5:i64 = UExtend v2, 32->64
v6:i64 = Uload32 module_ctx, 0x10
v7:i64 = Iadd v5, v4
v8:i32 = Icmp lt_u, v6, v7
ExitIfTrue v8, exec_ctx, memory_out_of_bounds
v9:i64 = Load module_ctx, 0x8
v10:i64 = Iadd v9, v5
Store v3, v10, 0x0
v11:i64 = Iconst_64 0x4
v12:i64 = UExtend v2, 32->64
v13:i64 = Iadd v12, v11
v14:i32 = Icmp lt_u, v6, v13
ExitIfTrue v14, exec_ctx, memory_out_of_bounds
v15:i64 = Iadd v9, v12
v16:i32 = Load v15, 0x0
Jump blk_ret, v16
`,
},
{
name: "memory_load_basic", m: testcases.MemoryLoadBasic.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32)
v3:i64 = Iconst_64 0x4
v4:i64 = UExtend v2, 32->64
v5:i64 = Uload32 module_ctx, 0x10
v6:i64 = Iadd v4, v3
v7:i32 = Icmp lt_u, v5, v6
ExitIfTrue v7, exec_ctx, memory_out_of_bounds
v8:i64 = Load module_ctx, 0x8
v9:i64 = Iadd v8, v4
v10:i32 = Load v9, 0x0
Jump blk_ret, v10
`,
},
{
name: "memory_load_basic2", m: testcases.MemoryLoadBasic2.Module,
exp: `
signatures:
sig1: i64i64_v
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32)
v3:i32 = Iconst_32 0x0
v4:i32 = Icmp eq, v2, v3
Brz v4, blk2
Jump blk1
blk1: () <-- (blk0)
Store module_ctx, exec_ctx, 0x8
Call f1:sig1, exec_ctx, module_ctx
v5:i64 = Load module_ctx, 0x8
v6:i64 = Uload32 module_ctx, 0x10
Jump blk3, v2
blk2: () <-- (blk0)
Jump blk3, v2
blk3: (v7:i32) <-- (blk1,blk2)
v8:i64 = Iconst_64 0x4
v9:i64 = UExtend v7, 32->64
v10:i64 = Uload32 module_ctx, 0x10
v11:i64 = Iadd v9, v8
v12:i32 = Icmp lt_u, v10, v11
ExitIfTrue v12, exec_ctx, memory_out_of_bounds
v13:i64 = Load module_ctx, 0x8
v14:i64 = Iadd v13, v9
v15:i32 = Load v14, 0x0
Jump blk_ret, v15
`,
expAfterOpt: `
signatures:
sig1: i64i64_v
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32)
v3:i32 = Iconst_32 0x0
v4:i32 = Icmp eq, v2, v3
Brz v4, blk2
Jump blk1
blk1: () <-- (blk0)
Store module_ctx, exec_ctx, 0x8
Call f1:sig1, exec_ctx, module_ctx
Jump blk3
blk2: () <-- (blk0)
Jump blk3
blk3: () <-- (blk1,blk2)
v8:i64 = Iconst_64 0x4
v9:i64 = UExtend v2, 32->64
v10:i64 = Uload32 module_ctx, 0x10
v11:i64 = Iadd v9, v8
v12:i32 = Icmp lt_u, v10, v11
ExitIfTrue v12, exec_ctx, memory_out_of_bounds
v13:i64 = Load module_ctx, 0x8
v14:i64 = Iadd v13, v9
v15:i32 = Load v14, 0x0
Jump blk_ret, v15
`,
},
{
name: "imported_function_call", m: testcases.ImportedFunctionCall.Module,
exp: `
signatures:
sig1: i64i64i32i32_i32
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32)
Store module_ctx, exec_ctx, 0x8
v3:i64 = Load module_ctx, 0x8
v4:i64 = Load module_ctx, 0x10
v5:i32 = CallIndirect v3:sig1, exec_ctx, v4, v2, v2
Jump blk_ret, v5
`,
},
{
name: "memory_loads", m: testcases.MemoryLoads.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32)
v3:i64 = Iconst_64 0x4
v4:i64 = UExtend v2, 32->64
v5:i64 = Uload32 module_ctx, 0x10
v6:i64 = Iadd v4, v3
v7:i32 = Icmp lt_u, v5, v6
ExitIfTrue v7, exec_ctx, memory_out_of_bounds
v8:i64 = Load module_ctx, 0x8
v9:i64 = Iadd v8, v4
v10:i32 = Load v9, 0x0
v11:i64 = Iconst_64 0x8
v12:i64 = UExtend v2, 32->64
v13:i64 = Iadd v12, v11
v14:i32 = Icmp lt_u, v5, v13
ExitIfTrue v14, exec_ctx, memory_out_of_bounds
v15:i64 = Iadd v8, v12
v16:i64 = Load v15, 0x0
v17:i64 = Iconst_64 0x4
v18:i64 = UExtend v2, 32->64
v19:i64 = Iadd v18, v17
v20:i32 = Icmp lt_u, v5, v19
ExitIfTrue v20, exec_ctx, memory_out_of_bounds
v21:i64 = Iadd v8, v18
v22:f32 = Load v21, 0x0
v23:i64 = Iconst_64 0x8
v24:i64 = UExtend v2, 32->64
v25:i64 = Iadd v24, v23
v26:i32 = Icmp lt_u, v5, v25
ExitIfTrue v26, exec_ctx, memory_out_of_bounds
v27:i64 = Iadd v8, v24
v28:f64 = Load v27, 0x0
v29:i64 = Iconst_64 0x13
v30:i64 = UExtend v2, 32->64
v31:i64 = Iadd v30, v29
v32:i32 = Icmp lt_u, v5, v31
ExitIfTrue v32, exec_ctx, memory_out_of_bounds
v33:i64 = Iadd v8, v30
v34:i32 = Load v33, 0xf
v35:i64 = Iconst_64 0x17
v36:i64 = UExtend v2, 32->64
v37:i64 = Iadd v36, v35
v38:i32 = Icmp lt_u, v5, v37
ExitIfTrue v38, exec_ctx, memory_out_of_bounds
v39:i64 = Iadd v8, v36
v40:i64 = Load v39, 0xf
v41:i64 = Iconst_64 0x13
v42:i64 = UExtend v2, 32->64
v43:i64 = Iadd v42, v41
v44:i32 = Icmp lt_u, v5, v43
ExitIfTrue v44, exec_ctx, memory_out_of_bounds
v45:i64 = Iadd v8, v42
v46:f32 = Load v45, 0xf
v47:i64 = Iconst_64 0x17
v48:i64 = UExtend v2, 32->64
v49:i64 = Iadd v48, v47
v50:i32 = Icmp lt_u, v5, v49
ExitIfTrue v50, exec_ctx, memory_out_of_bounds
v51:i64 = Iadd v8, v48
v52:f64 = Load v51, 0xf
v53:i64 = Iconst_64 0x1
v54:i64 = UExtend v2, 32->64
v55:i64 = Iadd v54, v53
v56:i32 = Icmp lt_u, v5, v55
ExitIfTrue v56, exec_ctx, memory_out_of_bounds
v57:i64 = Iadd v8, v54
v58:i32 = Sload8 v57, 0x0
v59:i64 = Iconst_64 0x10
v60:i64 = UExtend v2, 32->64
v61:i64 = Iadd v60, v59
v62:i32 = Icmp lt_u, v5, v61
ExitIfTrue v62, exec_ctx, memory_out_of_bounds
v63:i64 = Iadd v8, v60
v64:i32 = Sload8 v63, 0xf
v65:i64 = Iconst_64 0x1
v66:i64 = UExtend v2, 32->64
v67:i64 = Iadd v66, v65
v68:i32 = Icmp lt_u, v5, v67
ExitIfTrue v68, exec_ctx, memory_out_of_bounds
v69:i64 = Iadd v8, v66
v70:i32 = Uload8 v69, 0x0
v71:i64 = Iconst_64 0x10
v72:i64 = UExtend v2, 32->64
v73:i64 = Iadd v72, v71
v74:i32 = Icmp lt_u, v5, v73
ExitIfTrue v74, exec_ctx, memory_out_of_bounds
v75:i64 = Iadd v8, v72
v76:i32 = Uload8 v75, 0xf
v77:i64 = Iconst_64 0x2
v78:i64 = UExtend v2, 32->64
v79:i64 = Iadd v78, v77
v80:i32 = Icmp lt_u, v5, v79
ExitIfTrue v80, exec_ctx, memory_out_of_bounds
v81:i64 = Iadd v8, v78
v82:i32 = Sload16 v81, 0x0
v83:i64 = Iconst_64 0x11
v84:i64 = UExtend v2, 32->64
v85:i64 = Iadd v84, v83
v86:i32 = Icmp lt_u, v5, v85
ExitIfTrue v86, exec_ctx, memory_out_of_bounds
v87:i64 = Iadd v8, v84
v88:i32 = Sload16 v87, 0xf
v89:i64 = Iconst_64 0x2
v90:i64 = UExtend v2, 32->64
v91:i64 = Iadd v90, v89
v92:i32 = Icmp lt_u, v5, v91
ExitIfTrue v92, exec_ctx, memory_out_of_bounds
v93:i64 = Iadd v8, v90
v94:i32 = Uload16 v93, 0x0
v95:i64 = Iconst_64 0x11
v96:i64 = UExtend v2, 32->64
v97:i64 = Iadd v96, v95
v98:i32 = Icmp lt_u, v5, v97
ExitIfTrue v98, exec_ctx, memory_out_of_bounds
v99:i64 = Iadd v8, v96
v100:i32 = Uload16 v99, 0xf
v101:i64 = Iconst_64 0x1
v102:i64 = UExtend v2, 32->64
v103:i64 = Iadd v102, v101
v104:i32 = Icmp lt_u, v5, v103
ExitIfTrue v104, exec_ctx, memory_out_of_bounds
v105:i64 = Iadd v8, v102
v106:i64 = Sload8 v105, 0x0
v107:i64 = Iconst_64 0x10
v108:i64 = UExtend v2, 32->64
v109:i64 = Iadd v108, v107
v110:i32 = Icmp lt_u, v5, v109
ExitIfTrue v110, exec_ctx, memory_out_of_bounds
v111:i64 = Iadd v8, v108
v112:i64 = Sload8 v111, 0xf
v113:i64 = Iconst_64 0x1
v114:i64 = UExtend v2, 32->64
v115:i64 = Iadd v114, v113
v116:i32 = Icmp lt_u, v5, v115
ExitIfTrue v116, exec_ctx, memory_out_of_bounds
v117:i64 = Iadd v8, v114
v118:i64 = Uload8 v117, 0x0
v119:i64 = Iconst_64 0x10
v120:i64 = UExtend v2, 32->64
v121:i64 = Iadd v120, v119
v122:i32 = Icmp lt_u, v5, v121
ExitIfTrue v122, exec_ctx, memory_out_of_bounds
v123:i64 = Iadd v8, v120
v124:i64 = Uload8 v123, 0xf
v125:i64 = Iconst_64 0x2
v126:i64 = UExtend v2, 32->64
v127:i64 = Iadd v126, v125
v128:i32 = Icmp lt_u, v5, v127
ExitIfTrue v128, exec_ctx, memory_out_of_bounds
v129:i64 = Iadd v8, v126
v130:i64 = Sload16 v129, 0x0
v131:i64 = Iconst_64 0x11
v132:i64 = UExtend v2, 32->64
v133:i64 = Iadd v132, v131
v134:i32 = Icmp lt_u, v5, v133
ExitIfTrue v134, exec_ctx, memory_out_of_bounds
v135:i64 = Iadd v8, v132
v136:i64 = Sload16 v135, 0xf
v137:i64 = Iconst_64 0x2
v138:i64 = UExtend v2, 32->64
v139:i64 = Iadd v138, v137
v140:i32 = Icmp lt_u, v5, v139
ExitIfTrue v140, exec_ctx, memory_out_of_bounds
v141:i64 = Iadd v8, v138
v142:i64 = Uload16 v141, 0x0
v143:i64 = Iconst_64 0x11
v144:i64 = UExtend v2, 32->64
v145:i64 = Iadd v144, v143
v146:i32 = Icmp lt_u, v5, v145
ExitIfTrue v146, exec_ctx, memory_out_of_bounds
v147:i64 = Iadd v8, v144
v148:i64 = Uload16 v147, 0xf
v149:i64 = Iconst_64 0x4
v150:i64 = UExtend v2, 32->64
v151:i64 = Iadd v150, v149
v152:i32 = Icmp lt_u, v5, v151
ExitIfTrue v152, exec_ctx, memory_out_of_bounds
v153:i64 = Iadd v8, v150
v154:i64 = Sload32 v153, 0x0
v155:i64 = Iconst_64 0x13
v156:i64 = UExtend v2, 32->64
v157:i64 = Iadd v156, v155
v158:i32 = Icmp lt_u, v5, v157
ExitIfTrue v158, exec_ctx, memory_out_of_bounds
v159:i64 = Iadd v8, v156
v160:i64 = Sload32 v159, 0xf
v161:i64 = Iconst_64 0x4
v162:i64 = UExtend v2, 32->64
v163:i64 = Iadd v162, v161
v164:i32 = Icmp lt_u, v5, v163
ExitIfTrue v164, exec_ctx, memory_out_of_bounds
v165:i64 = Iadd v8, v162
v166:i64 = Uload32 v165, 0x0
v167:i64 = Iconst_64 0x13
v168:i64 = UExtend v2, 32->64
v169:i64 = Iadd v168, v167
v170:i32 = Icmp lt_u, v5, v169
ExitIfTrue v170, exec_ctx, memory_out_of_bounds
v171:i64 = Iadd v8, v168
v172:i64 = Uload32 v171, 0xf
Jump blk_ret, v10, v16, v22, v28, v34, v40, v46, v52, v58, v64, v70, v76, v82, v88, v94, v100, v106, v112, v118, v124, v130, v136, v142, v148, v154, v160, v166, v172
`,
},
{
name: "globals_get",
m: testcases.GlobalsGet.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64)
v2:i64 = Load module_ctx, 0x8
v3:i32 = Load v2, 0x8
v4:i64 = Load module_ctx, 0x10
v5:i64 = Load v4, 0x8
v6:i64 = Load module_ctx, 0x18
v7:f32 = Load v6, 0x8
v8:i64 = Load module_ctx, 0x20
v9:f64 = Load v8, 0x8
Jump blk_ret, v3, v5, v7, v9
`,
},
{
name: "globals_set",
m: testcases.GlobalsSet.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64)
v2:i32 = Iconst_32 0x1
v3:i64 = Load module_ctx, 0x8
Store v2, v3, 0x8
v4:i64 = Iconst_64 0x2
v5:i64 = Load module_ctx, 0x10
Store v4, v5, 0x8
v6:f32 = F32const 3.000000
v7:i64 = Load module_ctx, 0x18
Store v6, v7, 0x8
v8:f64 = F64const 4.000000
v9:i64 = Load module_ctx, 0x20
Store v8, v9, 0x8
Jump blk_ret, v2, v4, v6, v8
`,
},
{
name: "globals_mutable",
m: testcases.GlobalsMutable.Module,
exp: `
signatures:
sig1: i64i64_v
blk0: (exec_ctx:i64, module_ctx:i64)
v2:i64 = Load module_ctx, 0x8
v3:i32 = Load v2, 0x8
v4:i64 = Load module_ctx, 0x10
v5:i64 = Load v4, 0x8
v6:i64 = Load module_ctx, 0x18
v7:f32 = Load v6, 0x8
v8:i64 = Load module_ctx, 0x20
v9:f64 = Load v8, 0x8
Store module_ctx, exec_ctx, 0x8
Call f1:sig1, exec_ctx, module_ctx
v10:i64 = Load module_ctx, 0x8
v11:i32 = Load v10, 0x8
v12:i64 = Load module_ctx, 0x10
v13:i64 = Load v12, 0x8
v14:i64 = Load module_ctx, 0x18
v15:f32 = Load v14, 0x8
v16:i64 = Load module_ctx, 0x20
v17:f64 = Load v16, 0x8
Jump blk_ret, v3, v5, v7, v9, v11, v13, v15, v17
`,
expAfterOpt: `
signatures:
sig1: i64i64_v
blk0: (exec_ctx:i64, module_ctx:i64)
v2:i64 = Load module_ctx, 0x8
v3:i32 = Load v2, 0x8
v4:i64 = Load module_ctx, 0x10
v5:i64 = Load v4, 0x8
v6:i64 = Load module_ctx, 0x18
v7:f32 = Load v6, 0x8
v8:i64 = Load module_ctx, 0x20
v9:f64 = Load v8, 0x8
Store module_ctx, exec_ctx, 0x8
Call f1:sig1, exec_ctx, module_ctx
v10:i64 = Load module_ctx, 0x8
v11:i32 = Load v10, 0x8
v12:i64 = Load module_ctx, 0x10
v13:i64 = Load v12, 0x8
v14:i64 = Load module_ctx, 0x18
v15:f32 = Load v14, 0x8
v16:i64 = Load module_ctx, 0x20
v17:f64 = Load v16, 0x8
Jump blk_ret, v3, v5, v7, v9, v11, v13, v15, v17
`,
},
{
name: "imported_memory_grow",
m: testcases.ImportedMemoryGrow.Module,
exp: `
signatures:
sig0: i64i64_i32
sig2: i64i32_i32
blk0: (exec_ctx:i64, module_ctx:i64)
Store module_ctx, exec_ctx, 0x8
v2:i64 = Load module_ctx, 0x18
v3:i64 = Load module_ctx, 0x20
v4:i32 = CallIndirect v2:sig0, exec_ctx, v3
v5:i64 = Load module_ctx, 0x8
v6:i64 = Load v5, 0x0
v7:i64 = Load module_ctx, 0x8
v8:i64 = Load v7, 0x8
v9:i64 = Load module_ctx, 0x8
v10:i32 = Load v9, 0x8
v11:i32 = Iconst_32 0x10
v12:i32 = Ushr v10, v11
v13:i32 = Iconst_32 0xa
Store module_ctx, exec_ctx, 0x8
v14:i64 = Load exec_ctx, 0x48
v15:i32 = CallIndirect v14:sig2, exec_ctx, v13
v16:i64 = Load module_ctx, 0x8
v17:i64 = Load v16, 0x0
v18:i64 = Load module_ctx, 0x8
v19:i64 = Load v18, 0x8
Store module_ctx, exec_ctx, 0x8
v20:i64 = Load module_ctx, 0x18
v21:i64 = Load module_ctx, 0x20
v22:i32 = CallIndirect v20:sig0, exec_ctx, v21
v23:i64 = Load module_ctx, 0x8
v24:i64 = Load v23, 0x0
v25:i64 = Load module_ctx, 0x8
v26:i64 = Load v25, 0x8
v27:i64 = Load module_ctx, 0x8
v28:i32 = Load v27, 0x8
v29:i32 = Iconst_32 0x10
v30:i32 = Ushr v28, v29
Jump blk_ret, v4, v12, v22, v30
`,
expAfterOpt: `
signatures:
sig0: i64i64_i32
sig2: i64i32_i32
blk0: (exec_ctx:i64, module_ctx:i64)
Store module_ctx, exec_ctx, 0x8
v2:i64 = Load module_ctx, 0x18
v3:i64 = Load module_ctx, 0x20
v4:i32 = CallIndirect v2:sig0, exec_ctx, v3
v9:i64 = Load module_ctx, 0x8
v10:i32 = Load v9, 0x8
v11:i32 = Iconst_32 0x10
v12:i32 = Ushr v10, v11
v13:i32 = Iconst_32 0xa
Store module_ctx, exec_ctx, 0x8
v14:i64 = Load exec_ctx, 0x48
v15:i32 = CallIndirect v14:sig2, exec_ctx, v13
Store module_ctx, exec_ctx, 0x8
v20:i64 = Load module_ctx, 0x18
v21:i64 = Load module_ctx, 0x20
v22:i32 = CallIndirect v20:sig0, exec_ctx, v21
v27:i64 = Load module_ctx, 0x8
v28:i32 = Load v27, 0x8
v29:i32 = Iconst_32 0x10
v30:i32 = Ushr v28, v29
Jump blk_ret, v4, v12, v22, v30
`,
},
{
name: "memory_size_grow",
m: testcases.MemorySizeGrow.Module,
exp: `
signatures:
sig1: i64i32_i32
blk0: (exec_ctx:i64, module_ctx:i64)
v2:i32 = Iconst_32 0x1
Store module_ctx, exec_ctx, 0x8
v3:i64 = Load exec_ctx, 0x48
v4:i32 = CallIndirect v3:sig1, exec_ctx, v2
v5:i64 = Load module_ctx, 0x8
v6:i64 = Uload32 module_ctx, 0x10
v7:i32 = Load module_ctx, 0x10
v8:i32 = Iconst_32 0x10
v9:i32 = Ushr v7, v8
v10:i32 = Iconst_32 0x1
Store module_ctx, exec_ctx, 0x8
v11:i64 = Load exec_ctx, 0x48
v12:i32 = CallIndirect v11:sig1, exec_ctx, v10
v13:i64 = Load module_ctx, 0x8
v14:i64 = Uload32 module_ctx, 0x10
Jump blk_ret, v4, v9, v12
`,
expAfterOpt: `
signatures:
sig1: i64i32_i32
blk0: (exec_ctx:i64, module_ctx:i64)
v2:i32 = Iconst_32 0x1
Store module_ctx, exec_ctx, 0x8
v3:i64 = Load exec_ctx, 0x48
v4:i32 = CallIndirect v3:sig1, exec_ctx, v2
v7:i32 = Load module_ctx, 0x10
v8:i32 = Iconst_32 0x10
v9:i32 = Ushr v7, v8
v10:i32 = Iconst_32 0x1
Store module_ctx, exec_ctx, 0x8
v11:i64 = Load exec_ctx, 0x48
v12:i32 = CallIndirect v11:sig1, exec_ctx, v10
Jump blk_ret, v4, v9, v12
`,
},
{
name: "call_indirect", m: testcases.CallIndirect.Module,
exp: `
signatures:
sig2: i64i64_i32
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32)
v3:i64 = Load module_ctx, 0x10
v4:i32 = Load v3, 0x8
v5:i32 = Icmp ge_u, v2, v4
ExitIfTrue v5, exec_ctx, table_out_of_bounds
v6:i64 = Load v3, 0x0
v7:i64 = Iconst_64 0x3
v8:i32 = Ishl v2, v7
v9:i64 = Iadd v6, v8
v10:i64 = Load v9, 0x0
v11:i64 = Iconst_64 0x0
v12:i32 = Icmp eq, v10, v11
ExitIfTrue v12, exec_ctx, indirect_call_null_pointer
v13:i32 = Load v10, 0x10
v14:i64 = Load module_ctx, 0x8
v15:i32 = Load v14, 0x8
v16:i32 = Icmp neq, v13, v15
ExitIfTrue v16, exec_ctx, indirect_call_type_mismatch
v17:i64 = Load v10, 0x0
v18:i64 = Load v10, 0x8
Store module_ctx, exec_ctx, 0x8
v19:i32 = CallIndirect v17:sig2, exec_ctx, v18
Jump blk_ret, v19
`,
},
{
name: "br_table", m: testcases.BrTable.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32)
BrTable v2, [blk7, blk8, blk9, blk10, blk11, blk12, blk13]
blk1: () <-- (blk12)
v8:i32 = Iconst_32 0x10
Return v8
blk2: () <-- (blk11)
v7:i32 = Iconst_32 0xf
Return v7
blk3: () <-- (blk10)
v6:i32 = Iconst_32 0xe
Return v6
blk4: () <-- (blk9)
v5:i32 = Iconst_32 0xd
Return v5
blk5: () <-- (blk8)
v4:i32 = Iconst_32 0xc
Return v4
blk6: () <-- (blk7,blk13)
v3:i32 = Iconst_32 0xb
Return v3
blk7: () <-- (blk0)
Jump blk6
blk8: () <-- (blk0)
Jump blk5
blk9: () <-- (blk0)
Jump blk4
blk10: () <-- (blk0)
Jump blk3
blk11: () <-- (blk0)
Jump blk2
blk12: () <-- (blk0)
Jump blk1
blk13: () <-- (blk0)
Jump blk6
`,
},
{
name: "br_table_with_arg", m: testcases.BrTableWithArg.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i32)
BrTable v2, [blk7, blk8, blk9, blk10, blk11, blk12, blk13]
blk1: (v4:i32) <-- (blk12)
v20:i32 = Iconst_32 0x10
v21:i32 = Iadd v4, v20
Return v21
blk2: (v5:i32) <-- (blk11)
v18:i32 = Iconst_32 0xf
v19:i32 = Iadd v5, v18
Return v19
blk3: (v6:i32) <-- (blk10)
v16:i32 = Iconst_32 0xe
v17:i32 = Iadd v6, v16
Return v17
blk4: (v7:i32) <-- (blk9)
v14:i32 = Iconst_32 0xd
v15:i32 = Iadd v7, v14
Return v15
blk5: (v8:i32) <-- (blk8)
v12:i32 = Iconst_32 0xc
v13:i32 = Iadd v8, v12
Return v13
blk6: (v9:i32) <-- (blk7,blk13)
v10:i32 = Iconst_32 0xb
v11:i32 = Iadd v9, v10
Return v11
blk7: () <-- (blk0)
Jump blk6, v3
blk8: () <-- (blk0)
Jump blk5, v3
blk9: () <-- (blk0)
Jump blk4, v3
blk10: () <-- (blk0)
Jump blk3, v3
blk11: () <-- (blk0)
Jump blk2, v3
blk12: () <-- (blk0)
Jump blk1, v3
blk13: () <-- (blk0)
Jump blk6, v3
`,
// TODO: these trivial two hop jumps should be optimized away.
expAfterOpt: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i32)
BrTable v2, [blk7, blk8, blk9, blk10, blk11, blk12, blk13]
blk1: () <-- (blk12)
v20:i32 = Iconst_32 0x10
v21:i32 = Iadd v3, v20
Return v21
blk2: () <-- (blk11)
v18:i32 = Iconst_32 0xf
v19:i32 = Iadd v3, v18
Return v19
blk3: () <-- (blk10)
v16:i32 = Iconst_32 0xe
v17:i32 = Iadd v3, v16
Return v17
blk4: () <-- (blk9)
v14:i32 = Iconst_32 0xd
v15:i32 = Iadd v3, v14
Return v15
blk5: () <-- (blk8)
v12:i32 = Iconst_32 0xc
v13:i32 = Iadd v3, v12
Return v13
blk6: () <-- (blk7,blk13)
v10:i32 = Iconst_32 0xb
v11:i32 = Iadd v3, v10
Return v11
blk7: () <-- (blk0)
Jump blk6
blk8: () <-- (blk0)
Jump blk5
blk9: () <-- (blk0)
Jump blk4
blk10: () <-- (blk0)
Jump blk3
blk11: () <-- (blk0)
Jump blk2
blk12: () <-- (blk0)
Jump blk1
blk13: () <-- (blk0)
Jump blk6
`,
},
{
name: "if_then_end_nesting_unreachable_if_then_else_end", m: testcases.IfThenEndNestingUnreachableIfThenElseEnd.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:f64, v3:f64, v4:f64)
v6:i32 = Load module_ctx, 0x10
v7:i32 = Iconst_32 0x10
v8:i32 = Ushr v6, v7
Brz v8, blk3
Jump blk2
blk1: (v5:i64) <-- (blk4)
Jump blk_ret
blk2: () <-- (blk0)
v9:i32 = Load module_ctx, 0x10
v10:i32 = Iconst_32 0x10
v11:i32 = Ushr v9, v10
Jump blk4
blk3: () <-- (blk0)
Jump blk4
blk4: () <-- (blk2,blk3)
v12:i64 = Iconst_64 0x0
Jump blk1, v12
`,
expAfterOpt: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:f64, v3:f64, v4:f64)
v6:i32 = Load module_ctx, 0x10
v7:i32 = Iconst_32 0x10
v8:i32 = Ushr v6, v7
Brz v8, blk3
Jump blk2
blk1: () <-- (blk4)
Jump blk_ret
blk2: () <-- (blk0)
Jump blk4
blk3: () <-- (blk0)
Jump blk4
blk4: () <-- (blk2,blk3)
Jump blk1
`,
},
} {
tc := tc
t.Run(tc.name, func(t *testing.T) {
// Just in case let's check the test module is valid.
err := tc.m.Validate(api.CoreFeaturesV2)
require.NoError(t, err, "invalid test case module!")
b := ssa.NewBuilder()
offset := wazevoapi.NewModuleContextOffsetData(tc.m, tc.needListener)
fc := NewFrontendCompiler(tc.m, b, &offset, tc.ensureTermination, tc.needListener, false)
typeIndex := tc.m.FunctionSection[tc.targetIndex]
code := &tc.m.CodeSection[tc.targetIndex]
fc.Init(tc.targetIndex, typeIndex, &tc.m.TypeSection[typeIndex], code.LocalTypes, code.Body, tc.needListener, 0)
fc.LowerToSSA()
actual := fc.formatBuilder()
fmt.Println(actual)
require.Equal(t, tc.exp, actual)
b.RunPasses()
if expAfterOpt := tc.expAfterOpt; expAfterOpt != "" {
actualAfterOpt := fc.formatBuilder()
fmt.Println(actualAfterOpt)
require.Equal(t, expAfterOpt, actualAfterOpt)
}
// Dry-run without checking the results of LayoutBlocks function.
b.LayoutBlocks()
})
}
}
func TestSignatureForListener(t *testing.T) {
for _, tc := range []struct {
name string
sig *wasm.FunctionType
before, after *ssa.Signature
}{
{
name: "empty",
sig: &wasm.FunctionType{},
before: &ssa.Signature{Params: []ssa.Type{ssa.TypeI64, ssa.TypeI32}},
after: &ssa.Signature{Params: []ssa.Type{ssa.TypeI64, ssa.TypeI32}},
},
{
name: "multi",
sig: &wasm.FunctionType{
Params: []wasm.ValueType{wasm.ValueTypeF64, wasm.ValueTypeI32},
Results: []wasm.ValueType{
wasm.ValueTypeI64, wasm.ValueTypeI32, wasm.ValueTypeF32, wasm.ValueTypeF64, wasm.ValueTypeV128,
},
},
before: &ssa.Signature{
Params: []ssa.Type{
ssa.TypeI64, ssa.TypeI32,
ssa.TypeF64, ssa.TypeI32,
},
},
after: &ssa.Signature{
Params: []ssa.Type{
ssa.TypeI64, ssa.TypeI32,
ssa.TypeI64, ssa.TypeI32, ssa.TypeF32, ssa.TypeF64, ssa.TypeV128,
},
},
},
} {
tc := tc
t.Run(tc.name, func(t *testing.T) {
before, after := SignatureForListener(tc.sig)
require.Equal(t, tc.before, before)
require.Equal(t, tc.after, after)
})
}
}
func TestCompiler_declareSignatures(t *testing.T) {
m := &wasm.Module{
TypeSection: []wasm.FunctionType{
{},
{Params: []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI32}},
{Params: []wasm.ValueType{wasm.ValueTypeF64, wasm.ValueTypeI32}},
{Results: []wasm.ValueType{wasm.ValueTypeI64, wasm.ValueTypeI32}},
},
}
t.Run("listener=false", func(t *testing.T) {
builder := ssa.NewBuilder()
c := &Compiler{m: m, ssaBuilder: builder}
c.declareSignatures(false)
declaredSigs := builder.Signatures()
expected := []*ssa.Signature{
{ID: 0, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI64}},
{ID: 1, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI64, ssa.TypeI64, ssa.TypeI32}},
{ID: 2, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI64, ssa.TypeF64, ssa.TypeI32}},
{ID: 3, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI64}, Results: []ssa.Type{ssa.TypeI64, ssa.TypeI32}},
{ID: 4, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI32}, Results: []ssa.Type{ssa.TypeI32}},
{ID: 5, Params: []ssa.Type{ssa.TypeI64}},
{ID: 6, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI32, ssa.TypeI32, ssa.TypeI64}, Results: []ssa.Type{ssa.TypeI32}},
{ID: 7, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI32}, Results: []ssa.Type{ssa.TypeI64}},
}
require.Equal(t, len(expected), len(declaredSigs))
for i := 0; i < len(expected); i++ {
require.Equal(t, expected[i].String(), declaredSigs[i].String(), i)
}
})
t.Run("listener=false", func(t *testing.T) {
builder := ssa.NewBuilder()
c := &Compiler{m: m, ssaBuilder: builder}
c.declareSignatures(true)
declaredSigs := builder.Signatures()
expected := []*ssa.Signature{
{ID: 0, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI64}},
{ID: 1, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI64, ssa.TypeI64, ssa.TypeI32}},
{ID: 2, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI64, ssa.TypeF64, ssa.TypeI32}},
{ID: 3, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI64}, Results: []ssa.Type{ssa.TypeI64, ssa.TypeI32}},
// Before.
{ID: 4, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI32}},
{ID: 5, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI32, ssa.TypeI64, ssa.TypeI32}},
{ID: 6, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI32, ssa.TypeF64, ssa.TypeI32}},
{ID: 7, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI32}},
// After.
{ID: 8, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI32}},
{ID: 9, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI32}},
{ID: 10, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI32}},
{ID: 11, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI32, ssa.TypeI64, ssa.TypeI32}},
// Misc.
{ID: 12, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI32}, Results: []ssa.Type{ssa.TypeI32}},
{ID: 13, Params: []ssa.Type{ssa.TypeI64}},
{ID: 14, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI32, ssa.TypeI32, ssa.TypeI64}, Results: []ssa.Type{ssa.TypeI32}},
{ID: 15, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI32}, Results: []ssa.Type{ssa.TypeI64}},
}
require.Equal(t, len(expected), len(declaredSigs))
for i := 0; i < len(declaredSigs); i++ {
require.Equal(t, expected[i].String(), declaredSigs[i].String(), i)
}
})
}