Files
wazero-wazero/internal/engine/wazevo/frontend/frontend_test.go
T
Edoardo Vacchi bfb20e0ba7 feat: exception handling spec (#2489)
Add experimental support to the Exception Handling spec.

Exception handling adds structured error propagation to WebAssembly
through `tags` (typed exception signatures), `throw/throw_ref` (raising
exceptions), and `try_table` (catching exceptions with typed `catch`
clauses). A new value type, `exnref`, represents a reference to a caught
exception.

Excluding tests and spec suites, the entire feature amounts to a little
less than 2000 lines of code.

Feature flag: `experimental.CoreFeaturesExceptionHandling`


## What's the use for this?

In the spirit of always having a real use case for the specs we
implement, I did check this implementation against the one large Wasm
C++ codebase I am aware about, i.e.
https://github.com/klippa-app/go-pdfium, and I verified that the entire
suite, compiled with `emcc+wasm-opt` does work; incidentally, much of
the existing support code, based on Emscripten's longjmp/setjmp, can be
dropped (thx @jerbob92 for the help!)

Broadly speaking, I don't know how much EH-enabled Wasm code you will
find in the wild. For instance, code compiled using Clang's C++ backend
does not really throw new-style exceptions, unless you compile WASI-SDK
with some flags, or you build with `emcc` and translate old-style
exceptions using `wasm-opt` (see exceptions_test.go)

In short, this spec should be really seen as a step towards supporting
the GC spec. The design decisions (esp. regarding the test suite) follow
from this reasoning.


## Spec Suite

`wast2json` **does not** support the EH suite, but `wasm-tools` does,
albeit with a tiny quirk in the way negative numbers are rendered. In
this PR _I am not_ moving the other suites to `wasm-tools` though.

The spec test suite passes entirely, except for two tests that are
intentionally skipped.

These tests assume **a very small subset** of typed references is
implemented; specifically, the distinction between nullable and
non-nullable function references (`(ref null $t)` vs `(ref $t)`). I have
decided to just flatten all non-nullable refs to nullable refs at decode
time, so we cannot detect the type mismatch the spec expects in these
cases.

Passing the **full suite is actually straightforward** because it only
requires introducing a non-nullable variant for each ref type: strictly
speaking the 2 failing tests are only for related nullable vs
non-nullable **func refs** -- so I can special-case these and/or add
non-nullable types for each known value; however, we will **need** to
rethink the representation of Values for the GC proposal anyway (because
this will introduce custom type indices, and these won't fit our
currently byte-sized `ValueType` enum).

The subtype-checking functions (`isRefSubtypeOf`,
`isStrictRefSubtypeOf`) are kept as abstraction points but currently
they are just equalities.

Nevertheless, as proven by the CPP example and
https://github.com/klippa-app/go-pdfium this PR provides a starting
point that is already useful (even if it is for limited cases).


## Interpreter

Exception handling in the interpreter:

**Within a frame**, `try_table` blocks are compiled into a static
exception table with PC ranges. When `throw` or `throw_ref` executes,
`searchExceptionTable` scans backwards (inner handlers first) for a
catch clause whose PC range covers the current instruction. If a match
is found, `applyExceptionHandler` adjusts the operand stack depth and
jumps to the catch target PC directly.

**Across frames**, if no handler is found in the current frame,
`panic(&thrownException{...})` propagates up the Go call stack. Each
cross-function call goes through `callWithUnwind()`, which uses
`defer/recover` to intercept the panic. Its `canRestore` method unwinds
`ce.frames` to the caller's depth and searches that frame's exception
table. If a handler is found, `doRestore` applies it and
`callWithUnwind` returns `true` (frame unwound -- caller refreshes
locals and continues). If not, the panic re-propagates to the next outer
`callWithUnwind`.

Note on the implementation: this mechanism is unified with the existing
`snapshot/restore` API through the `restorable` interface: both
`*thrownException` and `*snapshot` implement `canRestore`/`doRestore`,
so `callWithUnwind` handles both with a single defer/recover path. The
short-circuit check (`len(exceptionTable) == 0 && no snapshotter`) skips
the defer/recover overhead entirely for frames that don't need it.


## Compiler

The compiler could not reuse the snapshot/restore mechanism directly,
but it follows a similar pattern. One cool thing is that exception
handling could be implemented entirely as an SSA-level lowering with new
exit codes; there is no backend-specific code.

Throwing uses a two-phase ABI:

1. `ExitCodeThrowAlloc`: exits to the Go runtime to allocate an
`Exception` struct on the heap and writes a pointer to its params array
into the execution context. Then we return control to compiled code,
which stores the tag parameters directly into the struct.
2. `ExitCodeThrow`: exits to the Go runtime again to search for a
matching handler, restore the stack checkpoint, and branch to the catch
target.

The idea is that we NEED to allocate the parameter slice dynamically, so
we delegate to the Go runtime. Incidentally, this also allows us to
unify `throw` and `throwRef`; in the latter case, we skip the `alloc`
phase, and we exit straight to `ExitCodeThrow`.

### Trampolines

The compiler uses four trampolines to return to host to manage exception
state:

| Trampoline | Exit Code | Purpose |
|---|---|---|
| **ThrowAlloc** | `ExitCodeThrowAlloc` | Allocates an `Exception`
struct on the Go heap, writes `&exn.Params[0]` into `execCtx` so
compiled code can store tag parameters directly. |
| **Throw** | `ExitCodeThrow` | Searches `tryHandlers` for a matching
catch clause, restores the stack checkpoint on match, sets
`caughtExceptionClauseIdx` for the compiled dispatch. Used for both
`throw` (after ThrowAlloc) and `throw_ref` (directly). |
| **TryTableEnter** | `ExitCodeTryTableEnter` | Clones the current stack
as a checkpoint, pushes a `tryHandler` with the catch clause table and
saved module instance. Sets `caughtExceptionClauseIdx = -1` (no
exception). |
| **TryTableLeave** | `ExitCodeTryTableLeave` | Pops the most recent
`tryHandler`. Emitted at `try_table` block ends, and before any branch
or return that exits a `try_table` scope. |

### Lowering

As mentioned earlier, this entirely resolved at the SSA-level. In
particular:

- **Entry**: when a `try_table` is encountered, the compiler emits a
call to the TryTableEnter trampoline. Control returns to compiled code,
which reads `caughtExceptionClauseIdx` from the execution context — if
it's -1 (no exception), execution continues into the `try_table` body.

- **Normal exit**: when execution reaches the `End` opcode of the
`try_table` block, a TryTableLeave trampoline call is emitted.

However, every TryTableEnter must have a matching TryTableLeave on every
control flow path that doesn't throw; so we also "TryTableLeaves" also
for the following:

- **Early exit (branch)**: a `br`, `br_if`, or `br_table` can jump to a
label outside the `try_table`, skipping its `End`.
`emitTryTableLeaves(depth)` walks the control frame stack and emits one
TryTableLeave for each `try_table` frame the branch crosses. For
`br_if`, this happens in a trampoline basic block that only executes on
the taken path.

- **Early exit (return)**: `return`, `return_call`, and
`return_call_indirect` call `emitTryTableLeaves` with the full control
stack depth, popping all active handlers before leaving the frame.

- **Throw**: on `throw`/`throw_ref`, compiled code exits to the dispatch
loop via ExitCodeThrow. `doHandleException` searches `tryHandlers`
innermost-to-outermost. On match, it restores the cloned stack
checkpoint, sets `caughtExceptionClauseIdx`, and re-enters compiled code
at the handler's return address. The compiled dispatch branches to the
matching catch clause's handler block.


### Caveats

- As described above, we are skipping 2 spec tests (will be addressed
when we implement typed references)
- Because of that, I am _not_ enabling by default the fuzzer: I would
have to special-case for typed references and/or TODOs I have left
behind; I did run the fuzzer with some special-casing while debugging
the issue with pdfium (#2488) and did not find issues (the fuzzer did go
frequently OOM though); in fact, the pdfium issue was actually unrelated
(!)

---------

Signed-off-by: Edoardo Vacchi <evacchi@users.noreply.github.com>
2026-04-26 09:12:51 -07:00

3372 lines
92 KiB
Go

package frontend
import (
"fmt"
"testing"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/experimental"
"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
// expAfterPasses is not empty when we want to check the result after SSA passes.
expAfterPasses string
features api.CoreFeatures
}{
{
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
`,
expAfterPasses: `
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
`,
expAfterPasses: `
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
`,
expAfterPasses: `
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: ()
`,
expAfterPasses: `
blk0: (exec_ctx:i64, module_ctx:i64)
Jump fallthrough
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: ()
`,
expAfterPasses: `
signatures:
sig2: i64_v
blk0: (exec_ctx:i64, module_ctx:i64)
Jump fallthrough
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
`,
expAfterPasses: `
blk0: (exec_ctx:i64, module_ctx:i64)
Jump fallthrough
blk1: () <-- (blk0,blk4)
v2:i32 = Iconst_32 0x1
Brz v2, blk3
Jump fallthrough
blk4: () <-- (blk1)
Jump blk1
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: ()
`,
expAfterPasses: `
blk0: (exec_ctx:i64, module_ctx:i64)
Jump fallthrough
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
Brz v2, blk2
Jump blk1
blk1: () <-- (blk0)
Return v2
blk2: () <-- (blk0)
Jump blk3
blk3: () <-- (blk2)
Jump blk_ret, v2
`,
expAfterPasses: `
blk0: (exec_ctx:i64, module_ctx:i64)
v2:i32 = Iconst_32 0x0
Brz v2, blk2
Jump fallthrough
blk1: () <-- (blk0)
Return v2
blk2: () <-- (blk0)
Jump fallthrough
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
`,
expAfterPasses: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i32)
Brz v2, blk2
Jump fallthrough
blk1: () <-- (blk0)
Jump blk3, v2
blk2: () <-- (blk0)
Jump fallthrough, 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: ()
`,
expAfterPasses: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32)
Jump fallthrough
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
`,
expAfterPasses: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32)
Jump fallthrough
blk1: () <-- (blk0,blk5)
Brz v2, blk4
Jump fallthrough
blk5: () <-- (blk1)
Jump blk1
blk4: () <-- (blk1)
Jump fallthrough
blk3: () <-- (blk4)
Jump fallthrough
blk2: () <-- (blk3)
v4:i32 = Iconst_32 0x0
Jump blk_ret, v4
`,
},
{
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
`,
expAfterPasses: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32)
Jump fallthrough, v2
blk1: (v3:i32) <-- (blk0,blk3)
Brnz v3, blk5
Jump blk4
blk5: () <-- (blk1)
Jump blk_ret
blk4: () <-- (blk1)
Jump fallthrough
blk3: () <-- (blk4)
v4:i32 = Iconst_32 0x1
Jump blk1, v4
`,
},
{
name: "call",
m: testcases.Call.Module,
exp: `
signatures:
sig1: i64i64_i32
sig2: i64i64i32i32_i32
sig3: i64i64i32_i32i32
blk0: (exec_ctx:i64, module_ctx:i64)
v2:i32 = Call f1:sig1, exec_ctx, module_ctx
v3:i32 = Iconst_32 0x5
v4:i32 = Call f2:sig2, exec_ctx, module_ctx, v2, v3
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)
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)
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
`,
expAfterPasses: `
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
`,
expAfterPasses: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i32)
Jump fallthrough
blk1: () <-- (blk0,blk4)
v7:i32 = Iconst_32 0x1
Brz v7, blk3
Jump fallthrough
blk4: () <-- (blk1)
Jump blk1
blk3: () <-- (blk1)
Jump fallthrough
blk2: () <-- (blk3)
Jump blk_ret, v2
`,
},
{
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
`,
expAfterPasses: `
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
`,
expAfterPasses: `
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
`,
expAfterPasses: `
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
v7:i32 = Call f0:sig0, exec_ctx, module_ctx, v6
v8:i32 = Iconst_32 0x2
v9:i32 = Isub v2, v8
v10:i32 = Call f0:sig0, exec_ctx, module_ctx, v9
v11:i32 = Iadd v7, v10
Jump blk_ret, v11
`,
expAfterPasses: `
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 fallthrough
blk1: () <-- (blk0)
Return v2
blk2: () <-- (blk0)
Jump fallthrough
blk3: () <-- (blk2)
v5:i32 = Iconst_32 0x1
v6:i32 = Isub v2, v5
v7:i32 = Call f0:sig0, exec_ctx, module_ctx, v6
v8:i32 = Iconst_32 0x2
v9:i32 = Isub v2, v8
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:i32 = Load v10, 0x0
Jump blk_ret, v11
`,
},
{
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)
Call f1:sig1, exec_ctx, module_ctx
v5:i64 = Load module_ctx, 0x8
v6:i64 = Uload32 module_ctx, 0x10
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
`,
expAfterPasses: `
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 fallthrough
blk1: () <-- (blk0)
Call f1:sig1, exec_ctx, module_ctx
Jump blk3
blk2: () <-- (blk0)
Jump fallthrough
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 = Load v9, 0x0
v16:f32 = Load v9, 0x0
v17:f64 = Load v9, 0x0
v18:i64 = Iconst_64 0x13
v19:i64 = UExtend v2, 32->64
v20:i64 = Iadd v19, v18
v21:i32 = Icmp lt_u, v5, v20
ExitIfTrue v21, exec_ctx, memory_out_of_bounds
v22:i32 = Load v9, 0xf
v23:i64 = Iconst_64 0x17
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 = Load v9, 0xf
v28:f32 = Load v9, 0xf
v29:f64 = Load v9, 0xf
v30:i32 = Sload8 v9, 0x0
v31:i32 = Sload8 v9, 0xf
v32:i32 = Uload8 v9, 0x0
v33:i32 = Uload8 v9, 0xf
v34:i32 = Sload16 v9, 0x0
v35:i32 = Sload16 v9, 0xf
v36:i32 = Uload16 v9, 0x0
v37:i32 = Uload16 v9, 0xf
v38:i64 = Sload8 v9, 0x0
v39:i64 = Sload8 v9, 0xf
v40:i64 = Uload8 v9, 0x0
v41:i64 = Uload8 v9, 0xf
v42:i64 = Sload16 v9, 0x0
v43:i64 = Sload16 v9, 0xf
v44:i64 = Uload16 v9, 0x0
v45:i64 = Uload16 v9, 0xf
v46:i64 = Sload32 v9, 0x0
v47:i64 = Sload32 v9, 0xf
v48:i64 = Uload32 v9, 0x0
v49:i64 = Uload32 v9, 0xf
Jump blk_ret, v10, v15, v16, v17, v22, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49
`,
},
{
name: "globals_get",
m: testcases.GlobalsGet.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64)
v2:i32 = Load module_ctx, 0x10
v3:i64 = Load module_ctx, 0x20
v4:f32 = Load module_ctx, 0x30
v5:f64 = Load module_ctx, 0x40
v6:v128 = Load module_ctx, 0x50
Jump blk_ret, v2, v3, v4, v5, v6
`,
},
{
name: "globals_set",
m: testcases.GlobalsSet.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64)
v2:i32 = Iconst_32 0x1
Store v2, module_ctx, 0x10
v3:i64 = Iconst_64 0x2
Store v3, module_ctx, 0x20
v4:f32 = F32const 3.000000
Store v4, module_ctx, 0x30
v5:f64 = F64const 4.000000
Store v5, module_ctx, 0x40
v6:v128 = Vconst 000000000000000a 0000000000000014
Store v6, module_ctx, 0x50
Jump blk_ret, v2, v3, v4, v5, v6
`,
},
{
name: "globals_mutable",
m: testcases.GlobalsMutable.Module,
exp: `
signatures:
sig1: i64i64_v
blk0: (exec_ctx:i64, module_ctx:i64)
v2:i32 = Load module_ctx, 0x10
v3:i64 = Load module_ctx, 0x20
v4:f32 = Load module_ctx, 0x30
v5:f64 = Load module_ctx, 0x40
Call f1:sig1, exec_ctx, module_ctx
v6:i32 = Load module_ctx, 0x10
v7:i64 = Load module_ctx, 0x20
v8:f32 = Load module_ctx, 0x30
v9:f64 = Load module_ctx, 0x40
Jump blk_ret, v2, v3, v4, v5, v6, v7, v8, v9
`,
expAfterPasses: `
signatures:
sig1: i64i64_v
blk0: (exec_ctx:i64, module_ctx:i64)
v2:i32 = Load module_ctx, 0x10
v3:i64 = Load module_ctx, 0x20
v4:f32 = Load module_ctx, 0x30
v5:f64 = Load module_ctx, 0x40
Call f1:sig1, exec_ctx, module_ctx
v6:i32 = Load module_ctx, 0x10
v7:i64 = Load module_ctx, 0x20
v8:f32 = Load module_ctx, 0x30
v9:f64 = Load module_ctx, 0x40
Jump blk_ret, v2, v3, v4, v5, v6, v7, v8, v9
`,
},
{
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
`,
expAfterPasses: `
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
`,
expAfterPasses: `
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
`,
expAfterPasses: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i32)
BrTable v2, [blk7, blk8, blk9, blk10, blk11, blk12, blk13]
blk7: () <-- (blk0)
Jump blk6
blk8: () <-- (blk0)
Jump fallthrough
blk5: () <-- (blk8)
v12:i32 = Iconst_32 0xc
v13:i32 = Iadd v3, v12
Return v13
blk9: () <-- (blk0)
Jump fallthrough
blk4: () <-- (blk9)
v14:i32 = Iconst_32 0xd
v15:i32 = Iadd v3, v14
Return v15
blk10: () <-- (blk0)
Jump fallthrough
blk3: () <-- (blk10)
v16:i32 = Iconst_32 0xe
v17:i32 = Iadd v3, v16
Return v17
blk11: () <-- (blk0)
Jump fallthrough
blk2: () <-- (blk11)
v18:i32 = Iconst_32 0xf
v19:i32 = Iadd v3, v18
Return v19
blk12: () <-- (blk0)
Jump fallthrough
blk1: () <-- (blk12)
v20:i32 = Iconst_32 0x10
v21:i32 = Iadd v3, v20
Return v21
blk13: () <-- (blk0)
Jump fallthrough
blk6: () <-- (blk7,blk13)
v10:i32 = Iconst_32 0xb
v11:i32 = Iadd v3, v10
Return v11
`,
},
{
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
`,
expAfterPasses: `
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 fallthrough
blk2: () <-- (blk0)
Jump blk4
blk3: () <-- (blk0)
Jump fallthrough
blk4: () <-- (blk2,blk3)
Jump fallthrough
blk1: () <-- (blk4)
Jump blk_ret
`,
},
{
name: "VecShuffle",
m: testcases.VecShuffle.Module,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:v128, v3:v128)
v4:v128 = Shuffle.[0 1 2 3 4 5 6 7 24 25 26 27 28 29 30 31] v2, v3
Jump blk_ret, v4
`,
},
{
name: "MemoryWait32",
m: testcases.MemoryWait32.Module,
features: api.CoreFeaturesV2 | experimental.CoreFeaturesThreads,
exp: `
signatures:
sig6: i64i64i32i64_i32
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i32, v4:i64)
Store module_ctx, exec_ctx, 0x8
v5:i64 = Iconst_64 0xc
v6:i64 = UExtend v2, 32->64
v7:i64 = Iconst_64 0x10
v8:i64 = Iadd module_ctx, v7
v9:i64 = AtomicLoad_64, v8
v10:i64 = Iadd v6, v5
v11:i32 = Icmp lt_u, v9, v10
ExitIfTrue v11, exec_ctx, memory_out_of_bounds
v12:i64 = Load module_ctx, 0x8
v13:i64 = Iadd v12, v6
v14:i64 = Iconst_64 0x8
v15:i64 = Iadd v13, v14
v16:i64 = Iconst_64 0x3
v17:i64 = Band v15, v16
v18:i64 = Iconst_64 0x0
v19:i32 = Icmp neq, v17, v18
ExitIfTrue v19, exec_ctx, unaligned_atomic
v20:i64 = Load exec_ctx, 0x488
v21:i32 = CallIndirect v20:sig6, exec_ctx, v4, v3, v15
Jump blk_ret, v21
`,
},
{
name: "MemoryWait64",
m: testcases.MemoryWait64.Module,
features: api.CoreFeaturesV2 | experimental.CoreFeaturesThreads,
exp: `
signatures:
sig7: i64i64i64i64_i32
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i64, v4:i64)
Store module_ctx, exec_ctx, 0x8
v5:i64 = Iconst_64 0x10
v6:i64 = UExtend v2, 32->64
v7:i64 = Iconst_64 0x10
v8:i64 = Iadd module_ctx, v7
v9:i64 = AtomicLoad_64, v8
v10:i64 = Iadd v6, v5
v11:i32 = Icmp lt_u, v9, v10
ExitIfTrue v11, exec_ctx, memory_out_of_bounds
v12:i64 = Load module_ctx, 0x8
v13:i64 = Iadd v12, v6
v14:i64 = Iconst_64 0x8
v15:i64 = Iadd v13, v14
v16:i64 = Iconst_64 0x7
v17:i64 = Band v15, v16
v18:i64 = Iconst_64 0x0
v19:i32 = Icmp neq, v17, v18
ExitIfTrue v19, exec_ctx, unaligned_atomic
v20:i64 = Load exec_ctx, 0x490
v21:i32 = CallIndirect v20:sig7, exec_ctx, v4, v3, v15
Jump blk_ret, v21
`,
},
{
name: "MemoryNotify",
m: testcases.MemoryNotify.Module,
features: api.CoreFeaturesV2 | experimental.CoreFeaturesThreads,
exp: `
signatures:
sig8: i64i32i64_i32
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i32)
Store module_ctx, exec_ctx, 0x8
v4:i64 = Iconst_64 0xc
v5:i64 = UExtend v2, 32->64
v6:i64 = Iconst_64 0x10
v7:i64 = Iadd module_ctx, v6
v8:i64 = AtomicLoad_64, v7
v9:i64 = Iadd v5, v4
v10:i32 = Icmp lt_u, v8, v9
ExitIfTrue v10, exec_ctx, memory_out_of_bounds
v11:i64 = Load module_ctx, 0x8
v12:i64 = Iadd v11, v5
v13:i64 = Iconst_64 0x8
v14:i64 = Iadd v12, v13
v15:i64 = Iconst_64 0x3
v16:i64 = Band v14, v15
v17:i64 = Iconst_64 0x0
v18:i32 = Icmp neq, v16, v17
ExitIfTrue v18, exec_ctx, unaligned_atomic
v19:i64 = Load exec_ctx, 0x498
v20:i32 = CallIndirect v19:sig8, exec_ctx, v3, v14
Jump blk_ret, v20
`,
},
{
name: "AtomicRMWAdd",
m: testcases.AtomicRmwAdd.Module,
features: api.CoreFeaturesV2 | experimental.CoreFeaturesThreads,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i32, v4:i32, v5:i64, v6:i64, v7:i64, v8:i64)
v9:i32 = Iconst_32 0x0
v10:i64 = Iconst_64 0x1
v11:i64 = UExtend v9, 32->64
v12:i64 = Iconst_64 0x10
v13:i64 = Iadd module_ctx, v12
v14:i64 = AtomicLoad_64, v13
v15:i64 = Iadd v11, v10
v16:i32 = Icmp lt_u, v14, v15
ExitIfTrue v16, exec_ctx, memory_out_of_bounds
v17:i64 = Load module_ctx, 0x8
v18:i64 = Iadd v17, v11
v19:i32 = AtomicRmw add_8, v18, v2
v20:i32 = Iconst_32 0x8
v21:i64 = Iconst_64 0x2
v22:i64 = UExtend v20, 32->64
v23:i64 = Iconst_64 0x10
v24:i64 = Iadd module_ctx, v23
v25:i64 = AtomicLoad_64, v24
v26:i64 = Iadd v22, v21
v27:i32 = Icmp lt_u, v25, v26
ExitIfTrue v27, exec_ctx, memory_out_of_bounds
v28:i64 = Iadd v17, v22
v29:i64 = Iconst_64 0x1
v30:i64 = Band v28, v29
v31:i64 = Iconst_64 0x0
v32:i32 = Icmp neq, v30, v31
ExitIfTrue v32, exec_ctx, unaligned_atomic
v33:i32 = AtomicRmw add_16, v28, v3
v34:i32 = Iconst_32 0x10
v35:i64 = Iconst_64 0x4
v36:i64 = UExtend v34, 32->64
v37:i64 = Iconst_64 0x10
v38:i64 = Iadd module_ctx, v37
v39:i64 = AtomicLoad_64, v38
v40:i64 = Iadd v36, v35
v41:i32 = Icmp lt_u, v39, v40
ExitIfTrue v41, exec_ctx, memory_out_of_bounds
v42:i64 = Iadd v17, v36
v43:i64 = Iconst_64 0x3
v44:i64 = Band v42, v43
v45:i64 = Iconst_64 0x0
v46:i32 = Icmp neq, v44, v45
ExitIfTrue v46, exec_ctx, unaligned_atomic
v47:i32 = AtomicRmw add_32, v42, v4
v48:i32 = Iconst_32 0x18
v49:i64 = Iconst_64 0x1
v50:i64 = UExtend v48, 32->64
v51:i64 = Iconst_64 0x10
v52:i64 = Iadd module_ctx, v51
v53:i64 = AtomicLoad_64, v52
v54:i64 = Iadd v50, v49
v55:i32 = Icmp lt_u, v53, v54
ExitIfTrue v55, exec_ctx, memory_out_of_bounds
v56:i64 = Iadd v17, v50
v57:i64 = AtomicRmw add_8, v56, v5
v58:i32 = Iconst_32 0x20
v59:i64 = Iconst_64 0x2
v60:i64 = UExtend v58, 32->64
v61:i64 = Iconst_64 0x10
v62:i64 = Iadd module_ctx, v61
v63:i64 = AtomicLoad_64, v62
v64:i64 = Iadd v60, v59
v65:i32 = Icmp lt_u, v63, v64
ExitIfTrue v65, exec_ctx, memory_out_of_bounds
v66:i64 = Iadd v17, v60
v67:i64 = Iconst_64 0x1
v68:i64 = Band v66, v67
v69:i64 = Iconst_64 0x0
v70:i32 = Icmp neq, v68, v69
ExitIfTrue v70, exec_ctx, unaligned_atomic
v71:i64 = AtomicRmw add_16, v66, v6
v72:i32 = Iconst_32 0x28
v73:i64 = Iconst_64 0x4
v74:i64 = UExtend v72, 32->64
v75:i64 = Iconst_64 0x10
v76:i64 = Iadd module_ctx, v75
v77:i64 = AtomicLoad_64, v76
v78:i64 = Iadd v74, v73
v79:i32 = Icmp lt_u, v77, v78
ExitIfTrue v79, exec_ctx, memory_out_of_bounds
v80:i64 = Iadd v17, v74
v81:i64 = Iconst_64 0x3
v82:i64 = Band v80, v81
v83:i64 = Iconst_64 0x0
v84:i32 = Icmp neq, v82, v83
ExitIfTrue v84, exec_ctx, unaligned_atomic
v85:i64 = AtomicRmw add_32, v80, v7
v86:i32 = Iconst_32 0x30
v87:i64 = Iconst_64 0x8
v88:i64 = UExtend v86, 32->64
v89:i64 = Iconst_64 0x10
v90:i64 = Iadd module_ctx, v89
v91:i64 = AtomicLoad_64, v90
v92:i64 = Iadd v88, v87
v93:i32 = Icmp lt_u, v91, v92
ExitIfTrue v93, exec_ctx, memory_out_of_bounds
v94:i64 = Iadd v17, v88
v95:i64 = Iconst_64 0x7
v96:i64 = Band v94, v95
v97:i64 = Iconst_64 0x0
v98:i32 = Icmp neq, v96, v97
ExitIfTrue v98, exec_ctx, unaligned_atomic
v99:i64 = AtomicRmw add_64, v94, v8
Jump blk_ret, v19, v33, v47, v57, v71, v85, v99
`,
},
{
name: "AtomicRMWSub",
m: testcases.AtomicRmwSub.Module,
features: api.CoreFeaturesV2 | experimental.CoreFeaturesThreads,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i32, v4:i32, v5:i64, v6:i64, v7:i64, v8:i64)
v9:i32 = Iconst_32 0x0
v10:i64 = Iconst_64 0x1
v11:i64 = UExtend v9, 32->64
v12:i64 = Iconst_64 0x10
v13:i64 = Iadd module_ctx, v12
v14:i64 = AtomicLoad_64, v13
v15:i64 = Iadd v11, v10
v16:i32 = Icmp lt_u, v14, v15
ExitIfTrue v16, exec_ctx, memory_out_of_bounds
v17:i64 = Load module_ctx, 0x8
v18:i64 = Iadd v17, v11
v19:i32 = AtomicRmw sub_8, v18, v2
v20:i32 = Iconst_32 0x8
v21:i64 = Iconst_64 0x2
v22:i64 = UExtend v20, 32->64
v23:i64 = Iconst_64 0x10
v24:i64 = Iadd module_ctx, v23
v25:i64 = AtomicLoad_64, v24
v26:i64 = Iadd v22, v21
v27:i32 = Icmp lt_u, v25, v26
ExitIfTrue v27, exec_ctx, memory_out_of_bounds
v28:i64 = Iadd v17, v22
v29:i64 = Iconst_64 0x1
v30:i64 = Band v28, v29
v31:i64 = Iconst_64 0x0
v32:i32 = Icmp neq, v30, v31
ExitIfTrue v32, exec_ctx, unaligned_atomic
v33:i32 = AtomicRmw sub_16, v28, v3
v34:i32 = Iconst_32 0x10
v35:i64 = Iconst_64 0x4
v36:i64 = UExtend v34, 32->64
v37:i64 = Iconst_64 0x10
v38:i64 = Iadd module_ctx, v37
v39:i64 = AtomicLoad_64, v38
v40:i64 = Iadd v36, v35
v41:i32 = Icmp lt_u, v39, v40
ExitIfTrue v41, exec_ctx, memory_out_of_bounds
v42:i64 = Iadd v17, v36
v43:i64 = Iconst_64 0x3
v44:i64 = Band v42, v43
v45:i64 = Iconst_64 0x0
v46:i32 = Icmp neq, v44, v45
ExitIfTrue v46, exec_ctx, unaligned_atomic
v47:i32 = AtomicRmw sub_32, v42, v4
v48:i32 = Iconst_32 0x18
v49:i64 = Iconst_64 0x1
v50:i64 = UExtend v48, 32->64
v51:i64 = Iconst_64 0x10
v52:i64 = Iadd module_ctx, v51
v53:i64 = AtomicLoad_64, v52
v54:i64 = Iadd v50, v49
v55:i32 = Icmp lt_u, v53, v54
ExitIfTrue v55, exec_ctx, memory_out_of_bounds
v56:i64 = Iadd v17, v50
v57:i64 = AtomicRmw sub_8, v56, v5
v58:i32 = Iconst_32 0x20
v59:i64 = Iconst_64 0x2
v60:i64 = UExtend v58, 32->64
v61:i64 = Iconst_64 0x10
v62:i64 = Iadd module_ctx, v61
v63:i64 = AtomicLoad_64, v62
v64:i64 = Iadd v60, v59
v65:i32 = Icmp lt_u, v63, v64
ExitIfTrue v65, exec_ctx, memory_out_of_bounds
v66:i64 = Iadd v17, v60
v67:i64 = Iconst_64 0x1
v68:i64 = Band v66, v67
v69:i64 = Iconst_64 0x0
v70:i32 = Icmp neq, v68, v69
ExitIfTrue v70, exec_ctx, unaligned_atomic
v71:i64 = AtomicRmw sub_16, v66, v6
v72:i32 = Iconst_32 0x28
v73:i64 = Iconst_64 0x4
v74:i64 = UExtend v72, 32->64
v75:i64 = Iconst_64 0x10
v76:i64 = Iadd module_ctx, v75
v77:i64 = AtomicLoad_64, v76
v78:i64 = Iadd v74, v73
v79:i32 = Icmp lt_u, v77, v78
ExitIfTrue v79, exec_ctx, memory_out_of_bounds
v80:i64 = Iadd v17, v74
v81:i64 = Iconst_64 0x3
v82:i64 = Band v80, v81
v83:i64 = Iconst_64 0x0
v84:i32 = Icmp neq, v82, v83
ExitIfTrue v84, exec_ctx, unaligned_atomic
v85:i64 = AtomicRmw sub_32, v80, v7
v86:i32 = Iconst_32 0x30
v87:i64 = Iconst_64 0x8
v88:i64 = UExtend v86, 32->64
v89:i64 = Iconst_64 0x10
v90:i64 = Iadd module_ctx, v89
v91:i64 = AtomicLoad_64, v90
v92:i64 = Iadd v88, v87
v93:i32 = Icmp lt_u, v91, v92
ExitIfTrue v93, exec_ctx, memory_out_of_bounds
v94:i64 = Iadd v17, v88
v95:i64 = Iconst_64 0x7
v96:i64 = Band v94, v95
v97:i64 = Iconst_64 0x0
v98:i32 = Icmp neq, v96, v97
ExitIfTrue v98, exec_ctx, unaligned_atomic
v99:i64 = AtomicRmw sub_64, v94, v8
Jump blk_ret, v19, v33, v47, v57, v71, v85, v99
`,
},
{
name: "AtomicRMWAnd",
m: testcases.AtomicRmwAnd.Module,
features: api.CoreFeaturesV2 | experimental.CoreFeaturesThreads,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i32, v4:i32, v5:i64, v6:i64, v7:i64, v8:i64)
v9:i32 = Iconst_32 0x0
v10:i64 = Iconst_64 0x1
v11:i64 = UExtend v9, 32->64
v12:i64 = Iconst_64 0x10
v13:i64 = Iadd module_ctx, v12
v14:i64 = AtomicLoad_64, v13
v15:i64 = Iadd v11, v10
v16:i32 = Icmp lt_u, v14, v15
ExitIfTrue v16, exec_ctx, memory_out_of_bounds
v17:i64 = Load module_ctx, 0x8
v18:i64 = Iadd v17, v11
v19:i32 = AtomicRmw and_8, v18, v2
v20:i32 = Iconst_32 0x0
v21:i64 = Iconst_64 0xa
v22:i64 = UExtend v20, 32->64
v23:i64 = Iconst_64 0x10
v24:i64 = Iadd module_ctx, v23
v25:i64 = AtomicLoad_64, v24
v26:i64 = Iadd v22, v21
v27:i32 = Icmp lt_u, v25, v26
ExitIfTrue v27, exec_ctx, memory_out_of_bounds
v28:i64 = Iadd v17, v22
v29:i64 = Iconst_64 0x8
v30:i64 = Iadd v28, v29
v31:i64 = Iconst_64 0x1
v32:i64 = Band v30, v31
v33:i64 = Iconst_64 0x0
v34:i32 = Icmp neq, v32, v33
ExitIfTrue v34, exec_ctx, unaligned_atomic
v35:i32 = AtomicRmw and_16, v30, v3
v36:i32 = Iconst_32 0x0
v37:i64 = Iconst_64 0x14
v38:i64 = UExtend v36, 32->64
v39:i64 = Iconst_64 0x10
v40:i64 = Iadd module_ctx, v39
v41:i64 = AtomicLoad_64, v40
v42:i64 = Iadd v38, v37
v43:i32 = Icmp lt_u, v41, v42
ExitIfTrue v43, exec_ctx, memory_out_of_bounds
v44:i64 = Iadd v17, v38
v45:i64 = Iconst_64 0x10
v46:i64 = Iadd v44, v45
v47:i64 = Iconst_64 0x3
v48:i64 = Band v46, v47
v49:i64 = Iconst_64 0x0
v50:i32 = Icmp neq, v48, v49
ExitIfTrue v50, exec_ctx, unaligned_atomic
v51:i32 = AtomicRmw and_32, v46, v4
v52:i32 = Iconst_32 0x0
v53:i64 = Iconst_64 0x19
v54:i64 = UExtend v52, 32->64
v55:i64 = Iconst_64 0x10
v56:i64 = Iadd module_ctx, v55
v57:i64 = AtomicLoad_64, v56
v58:i64 = Iadd v54, v53
v59:i32 = Icmp lt_u, v57, v58
ExitIfTrue v59, exec_ctx, memory_out_of_bounds
v60:i64 = Iadd v17, v54
v61:i64 = Iconst_64 0x18
v62:i64 = Iadd v60, v61
v63:i64 = AtomicRmw and_8, v62, v5
v64:i32 = Iconst_32 0x0
v65:i64 = Iconst_64 0x22
v66:i64 = UExtend v64, 32->64
v67:i64 = Iconst_64 0x10
v68:i64 = Iadd module_ctx, v67
v69:i64 = AtomicLoad_64, v68
v70:i64 = Iadd v66, v65
v71:i32 = Icmp lt_u, v69, v70
ExitIfTrue v71, exec_ctx, memory_out_of_bounds
v72:i64 = Iadd v17, v66
v73:i64 = Iconst_64 0x20
v74:i64 = Iadd v72, v73
v75:i64 = Iconst_64 0x1
v76:i64 = Band v74, v75
v77:i64 = Iconst_64 0x0
v78:i32 = Icmp neq, v76, v77
ExitIfTrue v78, exec_ctx, unaligned_atomic
v79:i64 = AtomicRmw and_16, v74, v6
v80:i32 = Iconst_32 0x0
v81:i64 = Iconst_64 0x2c
v82:i64 = UExtend v80, 32->64
v83:i64 = Iconst_64 0x10
v84:i64 = Iadd module_ctx, v83
v85:i64 = AtomicLoad_64, v84
v86:i64 = Iadd v82, v81
v87:i32 = Icmp lt_u, v85, v86
ExitIfTrue v87, exec_ctx, memory_out_of_bounds
v88:i64 = Iadd v17, v82
v89:i64 = Iconst_64 0x28
v90:i64 = Iadd v88, v89
v91:i64 = Iconst_64 0x3
v92:i64 = Band v90, v91
v93:i64 = Iconst_64 0x0
v94:i32 = Icmp neq, v92, v93
ExitIfTrue v94, exec_ctx, unaligned_atomic
v95:i64 = AtomicRmw and_32, v90, v7
v96:i32 = Iconst_32 0x0
v97:i64 = Iconst_64 0x38
v98:i64 = UExtend v96, 32->64
v99:i64 = Iconst_64 0x10
v100:i64 = Iadd module_ctx, v99
v101:i64 = AtomicLoad_64, v100
v102:i64 = Iadd v98, v97
v103:i32 = Icmp lt_u, v101, v102
ExitIfTrue v103, exec_ctx, memory_out_of_bounds
v104:i64 = Iadd v17, v98
v105:i64 = Iconst_64 0x30
v106:i64 = Iadd v104, v105
v107:i64 = Iconst_64 0x7
v108:i64 = Band v106, v107
v109:i64 = Iconst_64 0x0
v110:i32 = Icmp neq, v108, v109
ExitIfTrue v110, exec_ctx, unaligned_atomic
v111:i64 = AtomicRmw and_64, v106, v8
Jump blk_ret, v19, v35, v51, v63, v79, v95, v111
`,
},
{
name: "AtomicRMWOr",
m: testcases.AtomicRmwOr.Module,
features: api.CoreFeaturesV2 | experimental.CoreFeaturesThreads,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i32, v4:i32, v5:i64, v6:i64, v7:i64, v8:i64)
v9:i32 = Iconst_32 0x0
v10:i64 = Iconst_64 0x1
v11:i64 = UExtend v9, 32->64
v12:i64 = Iconst_64 0x10
v13:i64 = Iadd module_ctx, v12
v14:i64 = AtomicLoad_64, v13
v15:i64 = Iadd v11, v10
v16:i32 = Icmp lt_u, v14, v15
ExitIfTrue v16, exec_ctx, memory_out_of_bounds
v17:i64 = Load module_ctx, 0x8
v18:i64 = Iadd v17, v11
v19:i32 = AtomicRmw or_8, v18, v2
v20:i32 = Iconst_32 0x0
v21:i64 = Iconst_64 0xa
v22:i64 = UExtend v20, 32->64
v23:i64 = Iconst_64 0x10
v24:i64 = Iadd module_ctx, v23
v25:i64 = AtomicLoad_64, v24
v26:i64 = Iadd v22, v21
v27:i32 = Icmp lt_u, v25, v26
ExitIfTrue v27, exec_ctx, memory_out_of_bounds
v28:i64 = Iadd v17, v22
v29:i64 = Iconst_64 0x8
v30:i64 = Iadd v28, v29
v31:i64 = Iconst_64 0x1
v32:i64 = Band v30, v31
v33:i64 = Iconst_64 0x0
v34:i32 = Icmp neq, v32, v33
ExitIfTrue v34, exec_ctx, unaligned_atomic
v35:i32 = AtomicRmw or_16, v30, v3
v36:i32 = Iconst_32 0x0
v37:i64 = Iconst_64 0x14
v38:i64 = UExtend v36, 32->64
v39:i64 = Iconst_64 0x10
v40:i64 = Iadd module_ctx, v39
v41:i64 = AtomicLoad_64, v40
v42:i64 = Iadd v38, v37
v43:i32 = Icmp lt_u, v41, v42
ExitIfTrue v43, exec_ctx, memory_out_of_bounds
v44:i64 = Iadd v17, v38
v45:i64 = Iconst_64 0x10
v46:i64 = Iadd v44, v45
v47:i64 = Iconst_64 0x3
v48:i64 = Band v46, v47
v49:i64 = Iconst_64 0x0
v50:i32 = Icmp neq, v48, v49
ExitIfTrue v50, exec_ctx, unaligned_atomic
v51:i32 = AtomicRmw or_32, v46, v4
v52:i32 = Iconst_32 0x0
v53:i64 = Iconst_64 0x19
v54:i64 = UExtend v52, 32->64
v55:i64 = Iconst_64 0x10
v56:i64 = Iadd module_ctx, v55
v57:i64 = AtomicLoad_64, v56
v58:i64 = Iadd v54, v53
v59:i32 = Icmp lt_u, v57, v58
ExitIfTrue v59, exec_ctx, memory_out_of_bounds
v60:i64 = Iadd v17, v54
v61:i64 = Iconst_64 0x18
v62:i64 = Iadd v60, v61
v63:i64 = AtomicRmw or_8, v62, v5
v64:i32 = Iconst_32 0x0
v65:i64 = Iconst_64 0x22
v66:i64 = UExtend v64, 32->64
v67:i64 = Iconst_64 0x10
v68:i64 = Iadd module_ctx, v67
v69:i64 = AtomicLoad_64, v68
v70:i64 = Iadd v66, v65
v71:i32 = Icmp lt_u, v69, v70
ExitIfTrue v71, exec_ctx, memory_out_of_bounds
v72:i64 = Iadd v17, v66
v73:i64 = Iconst_64 0x20
v74:i64 = Iadd v72, v73
v75:i64 = Iconst_64 0x1
v76:i64 = Band v74, v75
v77:i64 = Iconst_64 0x0
v78:i32 = Icmp neq, v76, v77
ExitIfTrue v78, exec_ctx, unaligned_atomic
v79:i64 = AtomicRmw or_16, v74, v6
v80:i32 = Iconst_32 0x0
v81:i64 = Iconst_64 0x2c
v82:i64 = UExtend v80, 32->64
v83:i64 = Iconst_64 0x10
v84:i64 = Iadd module_ctx, v83
v85:i64 = AtomicLoad_64, v84
v86:i64 = Iadd v82, v81
v87:i32 = Icmp lt_u, v85, v86
ExitIfTrue v87, exec_ctx, memory_out_of_bounds
v88:i64 = Iadd v17, v82
v89:i64 = Iconst_64 0x28
v90:i64 = Iadd v88, v89
v91:i64 = Iconst_64 0x3
v92:i64 = Band v90, v91
v93:i64 = Iconst_64 0x0
v94:i32 = Icmp neq, v92, v93
ExitIfTrue v94, exec_ctx, unaligned_atomic
v95:i64 = AtomicRmw or_32, v90, v7
v96:i32 = Iconst_32 0x0
v97:i64 = Iconst_64 0x38
v98:i64 = UExtend v96, 32->64
v99:i64 = Iconst_64 0x10
v100:i64 = Iadd module_ctx, v99
v101:i64 = AtomicLoad_64, v100
v102:i64 = Iadd v98, v97
v103:i32 = Icmp lt_u, v101, v102
ExitIfTrue v103, exec_ctx, memory_out_of_bounds
v104:i64 = Iadd v17, v98
v105:i64 = Iconst_64 0x30
v106:i64 = Iadd v104, v105
v107:i64 = Iconst_64 0x7
v108:i64 = Band v106, v107
v109:i64 = Iconst_64 0x0
v110:i32 = Icmp neq, v108, v109
ExitIfTrue v110, exec_ctx, unaligned_atomic
v111:i64 = AtomicRmw or_64, v106, v8
Jump blk_ret, v19, v35, v51, v63, v79, v95, v111
`,
},
{
name: "AtomicRMWXor",
m: testcases.AtomicRmwXor.Module,
features: api.CoreFeaturesV2 | experimental.CoreFeaturesThreads,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i32, v4:i32, v5:i64, v6:i64, v7:i64, v8:i64)
v9:i32 = Iconst_32 0x0
v10:i64 = Iconst_64 0x1
v11:i64 = UExtend v9, 32->64
v12:i64 = Iconst_64 0x10
v13:i64 = Iadd module_ctx, v12
v14:i64 = AtomicLoad_64, v13
v15:i64 = Iadd v11, v10
v16:i32 = Icmp lt_u, v14, v15
ExitIfTrue v16, exec_ctx, memory_out_of_bounds
v17:i64 = Load module_ctx, 0x8
v18:i64 = Iadd v17, v11
v19:i32 = AtomicRmw xor_8, v18, v2
v20:i32 = Iconst_32 0x0
v21:i64 = Iconst_64 0xa
v22:i64 = UExtend v20, 32->64
v23:i64 = Iconst_64 0x10
v24:i64 = Iadd module_ctx, v23
v25:i64 = AtomicLoad_64, v24
v26:i64 = Iadd v22, v21
v27:i32 = Icmp lt_u, v25, v26
ExitIfTrue v27, exec_ctx, memory_out_of_bounds
v28:i64 = Iadd v17, v22
v29:i64 = Iconst_64 0x8
v30:i64 = Iadd v28, v29
v31:i64 = Iconst_64 0x1
v32:i64 = Band v30, v31
v33:i64 = Iconst_64 0x0
v34:i32 = Icmp neq, v32, v33
ExitIfTrue v34, exec_ctx, unaligned_atomic
v35:i32 = AtomicRmw xor_16, v30, v3
v36:i32 = Iconst_32 0x0
v37:i64 = Iconst_64 0x14
v38:i64 = UExtend v36, 32->64
v39:i64 = Iconst_64 0x10
v40:i64 = Iadd module_ctx, v39
v41:i64 = AtomicLoad_64, v40
v42:i64 = Iadd v38, v37
v43:i32 = Icmp lt_u, v41, v42
ExitIfTrue v43, exec_ctx, memory_out_of_bounds
v44:i64 = Iadd v17, v38
v45:i64 = Iconst_64 0x10
v46:i64 = Iadd v44, v45
v47:i64 = Iconst_64 0x3
v48:i64 = Band v46, v47
v49:i64 = Iconst_64 0x0
v50:i32 = Icmp neq, v48, v49
ExitIfTrue v50, exec_ctx, unaligned_atomic
v51:i32 = AtomicRmw xor_32, v46, v4
v52:i32 = Iconst_32 0x0
v53:i64 = Iconst_64 0x19
v54:i64 = UExtend v52, 32->64
v55:i64 = Iconst_64 0x10
v56:i64 = Iadd module_ctx, v55
v57:i64 = AtomicLoad_64, v56
v58:i64 = Iadd v54, v53
v59:i32 = Icmp lt_u, v57, v58
ExitIfTrue v59, exec_ctx, memory_out_of_bounds
v60:i64 = Iadd v17, v54
v61:i64 = Iconst_64 0x18
v62:i64 = Iadd v60, v61
v63:i64 = AtomicRmw xor_8, v62, v5
v64:i32 = Iconst_32 0x0
v65:i64 = Iconst_64 0x22
v66:i64 = UExtend v64, 32->64
v67:i64 = Iconst_64 0x10
v68:i64 = Iadd module_ctx, v67
v69:i64 = AtomicLoad_64, v68
v70:i64 = Iadd v66, v65
v71:i32 = Icmp lt_u, v69, v70
ExitIfTrue v71, exec_ctx, memory_out_of_bounds
v72:i64 = Iadd v17, v66
v73:i64 = Iconst_64 0x20
v74:i64 = Iadd v72, v73
v75:i64 = Iconst_64 0x1
v76:i64 = Band v74, v75
v77:i64 = Iconst_64 0x0
v78:i32 = Icmp neq, v76, v77
ExitIfTrue v78, exec_ctx, unaligned_atomic
v79:i64 = AtomicRmw xor_16, v74, v6
v80:i32 = Iconst_32 0x0
v81:i64 = Iconst_64 0x2c
v82:i64 = UExtend v80, 32->64
v83:i64 = Iconst_64 0x10
v84:i64 = Iadd module_ctx, v83
v85:i64 = AtomicLoad_64, v84
v86:i64 = Iadd v82, v81
v87:i32 = Icmp lt_u, v85, v86
ExitIfTrue v87, exec_ctx, memory_out_of_bounds
v88:i64 = Iadd v17, v82
v89:i64 = Iconst_64 0x28
v90:i64 = Iadd v88, v89
v91:i64 = Iconst_64 0x3
v92:i64 = Band v90, v91
v93:i64 = Iconst_64 0x0
v94:i32 = Icmp neq, v92, v93
ExitIfTrue v94, exec_ctx, unaligned_atomic
v95:i64 = AtomicRmw xor_32, v90, v7
v96:i32 = Iconst_32 0x0
v97:i64 = Iconst_64 0x38
v98:i64 = UExtend v96, 32->64
v99:i64 = Iconst_64 0x10
v100:i64 = Iadd module_ctx, v99
v101:i64 = AtomicLoad_64, v100
v102:i64 = Iadd v98, v97
v103:i32 = Icmp lt_u, v101, v102
ExitIfTrue v103, exec_ctx, memory_out_of_bounds
v104:i64 = Iadd v17, v98
v105:i64 = Iconst_64 0x30
v106:i64 = Iadd v104, v105
v107:i64 = Iconst_64 0x7
v108:i64 = Band v106, v107
v109:i64 = Iconst_64 0x0
v110:i32 = Icmp neq, v108, v109
ExitIfTrue v110, exec_ctx, unaligned_atomic
v111:i64 = AtomicRmw xor_64, v106, v8
Jump blk_ret, v19, v35, v51, v63, v79, v95, v111
`,
},
{
name: "AtomicRMWXchg",
m: testcases.AtomicRmwXchg.Module,
features: api.CoreFeaturesV2 | experimental.CoreFeaturesThreads,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i32, v4:i32, v5:i64, v6:i64, v7:i64, v8:i64)
v9:i32 = Iconst_32 0x0
v10:i64 = Iconst_64 0x1
v11:i64 = UExtend v9, 32->64
v12:i64 = Iconst_64 0x10
v13:i64 = Iadd module_ctx, v12
v14:i64 = AtomicLoad_64, v13
v15:i64 = Iadd v11, v10
v16:i32 = Icmp lt_u, v14, v15
ExitIfTrue v16, exec_ctx, memory_out_of_bounds
v17:i64 = Load module_ctx, 0x8
v18:i64 = Iadd v17, v11
v19:i32 = AtomicRmw xchg_8, v18, v2
v20:i32 = Iconst_32 0x0
v21:i64 = Iconst_64 0xa
v22:i64 = UExtend v20, 32->64
v23:i64 = Iconst_64 0x10
v24:i64 = Iadd module_ctx, v23
v25:i64 = AtomicLoad_64, v24
v26:i64 = Iadd v22, v21
v27:i32 = Icmp lt_u, v25, v26
ExitIfTrue v27, exec_ctx, memory_out_of_bounds
v28:i64 = Iadd v17, v22
v29:i64 = Iconst_64 0x8
v30:i64 = Iadd v28, v29
v31:i64 = Iconst_64 0x1
v32:i64 = Band v30, v31
v33:i64 = Iconst_64 0x0
v34:i32 = Icmp neq, v32, v33
ExitIfTrue v34, exec_ctx, unaligned_atomic
v35:i32 = AtomicRmw xchg_16, v30, v3
v36:i32 = Iconst_32 0x0
v37:i64 = Iconst_64 0x14
v38:i64 = UExtend v36, 32->64
v39:i64 = Iconst_64 0x10
v40:i64 = Iadd module_ctx, v39
v41:i64 = AtomicLoad_64, v40
v42:i64 = Iadd v38, v37
v43:i32 = Icmp lt_u, v41, v42
ExitIfTrue v43, exec_ctx, memory_out_of_bounds
v44:i64 = Iadd v17, v38
v45:i64 = Iconst_64 0x10
v46:i64 = Iadd v44, v45
v47:i64 = Iconst_64 0x3
v48:i64 = Band v46, v47
v49:i64 = Iconst_64 0x0
v50:i32 = Icmp neq, v48, v49
ExitIfTrue v50, exec_ctx, unaligned_atomic
v51:i32 = AtomicRmw xchg_32, v46, v4
v52:i32 = Iconst_32 0x0
v53:i64 = Iconst_64 0x19
v54:i64 = UExtend v52, 32->64
v55:i64 = Iconst_64 0x10
v56:i64 = Iadd module_ctx, v55
v57:i64 = AtomicLoad_64, v56
v58:i64 = Iadd v54, v53
v59:i32 = Icmp lt_u, v57, v58
ExitIfTrue v59, exec_ctx, memory_out_of_bounds
v60:i64 = Iadd v17, v54
v61:i64 = Iconst_64 0x18
v62:i64 = Iadd v60, v61
v63:i64 = AtomicRmw xchg_8, v62, v5
v64:i32 = Iconst_32 0x0
v65:i64 = Iconst_64 0x22
v66:i64 = UExtend v64, 32->64
v67:i64 = Iconst_64 0x10
v68:i64 = Iadd module_ctx, v67
v69:i64 = AtomicLoad_64, v68
v70:i64 = Iadd v66, v65
v71:i32 = Icmp lt_u, v69, v70
ExitIfTrue v71, exec_ctx, memory_out_of_bounds
v72:i64 = Iadd v17, v66
v73:i64 = Iconst_64 0x20
v74:i64 = Iadd v72, v73
v75:i64 = Iconst_64 0x1
v76:i64 = Band v74, v75
v77:i64 = Iconst_64 0x0
v78:i32 = Icmp neq, v76, v77
ExitIfTrue v78, exec_ctx, unaligned_atomic
v79:i64 = AtomicRmw xchg_16, v74, v6
v80:i32 = Iconst_32 0x0
v81:i64 = Iconst_64 0x2c
v82:i64 = UExtend v80, 32->64
v83:i64 = Iconst_64 0x10
v84:i64 = Iadd module_ctx, v83
v85:i64 = AtomicLoad_64, v84
v86:i64 = Iadd v82, v81
v87:i32 = Icmp lt_u, v85, v86
ExitIfTrue v87, exec_ctx, memory_out_of_bounds
v88:i64 = Iadd v17, v82
v89:i64 = Iconst_64 0x28
v90:i64 = Iadd v88, v89
v91:i64 = Iconst_64 0x3
v92:i64 = Band v90, v91
v93:i64 = Iconst_64 0x0
v94:i32 = Icmp neq, v92, v93
ExitIfTrue v94, exec_ctx, unaligned_atomic
v95:i64 = AtomicRmw xchg_32, v90, v7
v96:i32 = Iconst_32 0x0
v97:i64 = Iconst_64 0x38
v98:i64 = UExtend v96, 32->64
v99:i64 = Iconst_64 0x10
v100:i64 = Iadd module_ctx, v99
v101:i64 = AtomicLoad_64, v100
v102:i64 = Iadd v98, v97
v103:i32 = Icmp lt_u, v101, v102
ExitIfTrue v103, exec_ctx, memory_out_of_bounds
v104:i64 = Iadd v17, v98
v105:i64 = Iconst_64 0x30
v106:i64 = Iadd v104, v105
v107:i64 = Iconst_64 0x7
v108:i64 = Band v106, v107
v109:i64 = Iconst_64 0x0
v110:i32 = Icmp neq, v108, v109
ExitIfTrue v110, exec_ctx, unaligned_atomic
v111:i64 = AtomicRmw xchg_64, v106, v8
Jump blk_ret, v19, v35, v51, v63, v79, v95, v111
`,
},
{
name: "AtomicStoreLoad",
m: testcases.AtomicStoreLoad.Module,
features: api.CoreFeaturesV2 | experimental.CoreFeaturesThreads,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i32, v4:i32, v5:i64, v6:i64, v7:i64, v8:i64)
v9:i32 = Iconst_32 0x0
v10:i64 = Iconst_64 0x1
v11:i64 = UExtend v9, 32->64
v12:i64 = Iconst_64 0x10
v13:i64 = Iadd module_ctx, v12
v14:i64 = AtomicLoad_64, v13
v15:i64 = Iadd v11, v10
v16:i32 = Icmp lt_u, v14, v15
ExitIfTrue v16, exec_ctx, memory_out_of_bounds
v17:i64 = Load module_ctx, 0x8
v18:i64 = Iadd v17, v11
AtomicStore_8, v18, v2
v19:i32 = Iconst_32 0x0
v20:i64 = Iconst_64 0x1
v21:i64 = UExtend v19, 32->64
v22:i64 = Iconst_64 0x10
v23:i64 = Iadd module_ctx, v22
v24:i64 = AtomicLoad_64, v23
v25:i64 = Iadd v21, v20
v26:i32 = Icmp lt_u, v24, v25
ExitIfTrue v26, exec_ctx, memory_out_of_bounds
v27:i64 = Iadd v17, v21
v28:i32 = AtomicLoad_8, v27
v29:i32 = Iconst_32 0x0
v30:i64 = Iconst_64 0xa
v31:i64 = UExtend v29, 32->64
v32:i64 = Iconst_64 0x10
v33:i64 = Iadd module_ctx, v32
v34:i64 = AtomicLoad_64, v33
v35:i64 = Iadd v31, v30
v36:i32 = Icmp lt_u, v34, v35
ExitIfTrue v36, exec_ctx, memory_out_of_bounds
v37:i64 = Iadd v17, v31
v38:i64 = Iconst_64 0x8
v39:i64 = Iadd v37, v38
v40:i64 = Iconst_64 0x1
v41:i64 = Band v39, v40
v42:i64 = Iconst_64 0x0
v43:i32 = Icmp neq, v41, v42
ExitIfTrue v43, exec_ctx, unaligned_atomic
AtomicStore_16, v39, v3
v44:i32 = Iconst_32 0x0
v45:i64 = Iconst_64 0xa
v46:i64 = UExtend v44, 32->64
v47:i64 = Iconst_64 0x10
v48:i64 = Iadd module_ctx, v47
v49:i64 = AtomicLoad_64, v48
v50:i64 = Iadd v46, v45
v51:i32 = Icmp lt_u, v49, v50
ExitIfTrue v51, exec_ctx, memory_out_of_bounds
v52:i64 = Iadd v17, v46
v53:i64 = Iconst_64 0x8
v54:i64 = Iadd v52, v53
v55:i64 = Iconst_64 0x1
v56:i64 = Band v54, v55
v57:i64 = Iconst_64 0x0
v58:i32 = Icmp neq, v56, v57
ExitIfTrue v58, exec_ctx, unaligned_atomic
v59:i32 = AtomicLoad_16, v54
v60:i32 = Iconst_32 0x0
v61:i64 = Iconst_64 0x14
v62:i64 = UExtend v60, 32->64
v63:i64 = Iconst_64 0x10
v64:i64 = Iadd module_ctx, v63
v65:i64 = AtomicLoad_64, v64
v66:i64 = Iadd v62, v61
v67:i32 = Icmp lt_u, v65, v66
ExitIfTrue v67, exec_ctx, memory_out_of_bounds
v68:i64 = Iadd v17, v62
v69:i64 = Iconst_64 0x10
v70:i64 = Iadd v68, v69
v71:i64 = Iconst_64 0x3
v72:i64 = Band v70, v71
v73:i64 = Iconst_64 0x0
v74:i32 = Icmp neq, v72, v73
ExitIfTrue v74, exec_ctx, unaligned_atomic
AtomicStore_32, v70, v4
v75:i32 = Iconst_32 0x0
v76:i64 = Iconst_64 0x14
v77:i64 = UExtend v75, 32->64
v78:i64 = Iconst_64 0x10
v79:i64 = Iadd module_ctx, v78
v80:i64 = AtomicLoad_64, v79
v81:i64 = Iadd v77, v76
v82:i32 = Icmp lt_u, v80, v81
ExitIfTrue v82, exec_ctx, memory_out_of_bounds
v83:i64 = Iadd v17, v77
v84:i64 = Iconst_64 0x10
v85:i64 = Iadd v83, v84
v86:i64 = Iconst_64 0x3
v87:i64 = Band v85, v86
v88:i64 = Iconst_64 0x0
v89:i32 = Icmp neq, v87, v88
ExitIfTrue v89, exec_ctx, unaligned_atomic
v90:i32 = AtomicLoad_32, v85
v91:i32 = Iconst_32 0x0
v92:i64 = Iconst_64 0x19
v93:i64 = UExtend v91, 32->64
v94:i64 = Iconst_64 0x10
v95:i64 = Iadd module_ctx, v94
v96:i64 = AtomicLoad_64, v95
v97:i64 = Iadd v93, v92
v98:i32 = Icmp lt_u, v96, v97
ExitIfTrue v98, exec_ctx, memory_out_of_bounds
v99:i64 = Iadd v17, v93
v100:i64 = Iconst_64 0x18
v101:i64 = Iadd v99, v100
AtomicStore_8, v101, v5
v102:i32 = Iconst_32 0x0
v103:i64 = Iconst_64 0x19
v104:i64 = UExtend v102, 32->64
v105:i64 = Iconst_64 0x10
v106:i64 = Iadd module_ctx, v105
v107:i64 = AtomicLoad_64, v106
v108:i64 = Iadd v104, v103
v109:i32 = Icmp lt_u, v107, v108
ExitIfTrue v109, exec_ctx, memory_out_of_bounds
v110:i64 = Iadd v17, v104
v111:i64 = Iconst_64 0x18
v112:i64 = Iadd v110, v111
v113:i64 = AtomicLoad_8, v112
v114:i32 = Iconst_32 0x0
v115:i64 = Iconst_64 0x22
v116:i64 = UExtend v114, 32->64
v117:i64 = Iconst_64 0x10
v118:i64 = Iadd module_ctx, v117
v119:i64 = AtomicLoad_64, v118
v120:i64 = Iadd v116, v115
v121:i32 = Icmp lt_u, v119, v120
ExitIfTrue v121, exec_ctx, memory_out_of_bounds
v122:i64 = Iadd v17, v116
v123:i64 = Iconst_64 0x20
v124:i64 = Iadd v122, v123
v125:i64 = Iconst_64 0x1
v126:i64 = Band v124, v125
v127:i64 = Iconst_64 0x0
v128:i32 = Icmp neq, v126, v127
ExitIfTrue v128, exec_ctx, unaligned_atomic
AtomicStore_16, v124, v6
v129:i32 = Iconst_32 0x0
v130:i64 = Iconst_64 0x22
v131:i64 = UExtend v129, 32->64
v132:i64 = Iconst_64 0x10
v133:i64 = Iadd module_ctx, v132
v134:i64 = AtomicLoad_64, v133
v135:i64 = Iadd v131, v130
v136:i32 = Icmp lt_u, v134, v135
ExitIfTrue v136, exec_ctx, memory_out_of_bounds
v137:i64 = Iadd v17, v131
v138:i64 = Iconst_64 0x20
v139:i64 = Iadd v137, v138
v140:i64 = Iconst_64 0x1
v141:i64 = Band v139, v140
v142:i64 = Iconst_64 0x0
v143:i32 = Icmp neq, v141, v142
ExitIfTrue v143, exec_ctx, unaligned_atomic
v144:i64 = AtomicLoad_16, v139
v145:i32 = Iconst_32 0x0
v146:i64 = Iconst_64 0x2c
v147:i64 = UExtend v145, 32->64
v148:i64 = Iconst_64 0x10
v149:i64 = Iadd module_ctx, v148
v150:i64 = AtomicLoad_64, v149
v151:i64 = Iadd v147, v146
v152:i32 = Icmp lt_u, v150, v151
ExitIfTrue v152, exec_ctx, memory_out_of_bounds
v153:i64 = Iadd v17, v147
v154:i64 = Iconst_64 0x28
v155:i64 = Iadd v153, v154
v156:i64 = Iconst_64 0x3
v157:i64 = Band v155, v156
v158:i64 = Iconst_64 0x0
v159:i32 = Icmp neq, v157, v158
ExitIfTrue v159, exec_ctx, unaligned_atomic
AtomicStore_32, v155, v7
v160:i32 = Iconst_32 0x0
v161:i64 = Iconst_64 0x2c
v162:i64 = UExtend v160, 32->64
v163:i64 = Iconst_64 0x10
v164:i64 = Iadd module_ctx, v163
v165:i64 = AtomicLoad_64, v164
v166:i64 = Iadd v162, v161
v167:i32 = Icmp lt_u, v165, v166
ExitIfTrue v167, exec_ctx, memory_out_of_bounds
v168:i64 = Iadd v17, v162
v169:i64 = Iconst_64 0x28
v170:i64 = Iadd v168, v169
v171:i64 = Iconst_64 0x3
v172:i64 = Band v170, v171
v173:i64 = Iconst_64 0x0
v174:i32 = Icmp neq, v172, v173
ExitIfTrue v174, exec_ctx, unaligned_atomic
v175:i64 = AtomicLoad_32, v170
v176:i32 = Iconst_32 0x0
v177:i64 = Iconst_64 0x38
v178:i64 = UExtend v176, 32->64
v179:i64 = Iconst_64 0x10
v180:i64 = Iadd module_ctx, v179
v181:i64 = AtomicLoad_64, v180
v182:i64 = Iadd v178, v177
v183:i32 = Icmp lt_u, v181, v182
ExitIfTrue v183, exec_ctx, memory_out_of_bounds
v184:i64 = Iadd v17, v178
v185:i64 = Iconst_64 0x30
v186:i64 = Iadd v184, v185
v187:i64 = Iconst_64 0x7
v188:i64 = Band v186, v187
v189:i64 = Iconst_64 0x0
v190:i32 = Icmp neq, v188, v189
ExitIfTrue v190, exec_ctx, unaligned_atomic
AtomicStore_64, v186, v8
v191:i32 = Iconst_32 0x0
v192:i64 = Iconst_64 0x38
v193:i64 = UExtend v191, 32->64
v194:i64 = Iconst_64 0x10
v195:i64 = Iadd module_ctx, v194
v196:i64 = AtomicLoad_64, v195
v197:i64 = Iadd v193, v192
v198:i32 = Icmp lt_u, v196, v197
ExitIfTrue v198, exec_ctx, memory_out_of_bounds
v199:i64 = Iadd v17, v193
v200:i64 = Iconst_64 0x30
v201:i64 = Iadd v199, v200
v202:i64 = Iconst_64 0x7
v203:i64 = Band v201, v202
v204:i64 = Iconst_64 0x0
v205:i32 = Icmp neq, v203, v204
ExitIfTrue v205, exec_ctx, unaligned_atomic
v206:i64 = AtomicLoad_64, v201
Jump blk_ret, v28, v59, v90, v113, v144, v175, v206
`,
},
{
name: "AtomicCas",
m: testcases.AtomicCas.Module,
features: api.CoreFeaturesV2 | experimental.CoreFeaturesThreads,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32, v3:i32, v4:i32, v5:i32, v6:i32, v7:i32, v8:i64, v9:i64, v10:i64, v11:i64, v12:i64, v13:i64, v14:i64, v15:i64)
v16:i32 = Iconst_32 0x0
v17:i64 = Iconst_64 0x1
v18:i64 = UExtend v16, 32->64
v19:i64 = Iconst_64 0x10
v20:i64 = Iadd module_ctx, v19
v21:i64 = AtomicLoad_64, v20
v22:i64 = Iadd v18, v17
v23:i32 = Icmp lt_u, v21, v22
ExitIfTrue v23, exec_ctx, memory_out_of_bounds
v24:i64 = Load module_ctx, 0x8
v25:i64 = Iadd v24, v18
v26:i32 = AtomicCas_8, v25, v2, v3
v27:i32 = Iconst_32 0x0
v28:i64 = Iconst_64 0xa
v29:i64 = UExtend v27, 32->64
v30:i64 = Iconst_64 0x10
v31:i64 = Iadd module_ctx, v30
v32:i64 = AtomicLoad_64, v31
v33:i64 = Iadd v29, v28
v34:i32 = Icmp lt_u, v32, v33
ExitIfTrue v34, exec_ctx, memory_out_of_bounds
v35:i64 = Iadd v24, v29
v36:i64 = Iconst_64 0x8
v37:i64 = Iadd v35, v36
v38:i64 = Iconst_64 0x1
v39:i64 = Band v37, v38
v40:i64 = Iconst_64 0x0
v41:i32 = Icmp neq, v39, v40
ExitIfTrue v41, exec_ctx, unaligned_atomic
v42:i32 = AtomicCas_16, v37, v4, v5
v43:i32 = Iconst_32 0x0
v44:i64 = Iconst_64 0x14
v45:i64 = UExtend v43, 32->64
v46:i64 = Iconst_64 0x10
v47:i64 = Iadd module_ctx, v46
v48:i64 = AtomicLoad_64, v47
v49:i64 = Iadd v45, v44
v50:i32 = Icmp lt_u, v48, v49
ExitIfTrue v50, exec_ctx, memory_out_of_bounds
v51:i64 = Iadd v24, v45
v52:i64 = Iconst_64 0x10
v53:i64 = Iadd v51, v52
v54:i64 = Iconst_64 0x3
v55:i64 = Band v53, v54
v56:i64 = Iconst_64 0x0
v57:i32 = Icmp neq, v55, v56
ExitIfTrue v57, exec_ctx, unaligned_atomic
v58:i32 = AtomicCas_32, v53, v6, v7
v59:i32 = Iconst_32 0x0
v60:i64 = Iconst_64 0x19
v61:i64 = UExtend v59, 32->64
v62:i64 = Iconst_64 0x10
v63:i64 = Iadd module_ctx, v62
v64:i64 = AtomicLoad_64, v63
v65:i64 = Iadd v61, v60
v66:i32 = Icmp lt_u, v64, v65
ExitIfTrue v66, exec_ctx, memory_out_of_bounds
v67:i64 = Iadd v24, v61
v68:i64 = Iconst_64 0x18
v69:i64 = Iadd v67, v68
v70:i64 = AtomicCas_8, v69, v8, v9
v71:i32 = Iconst_32 0x0
v72:i64 = Iconst_64 0x22
v73:i64 = UExtend v71, 32->64
v74:i64 = Iconst_64 0x10
v75:i64 = Iadd module_ctx, v74
v76:i64 = AtomicLoad_64, v75
v77:i64 = Iadd v73, v72
v78:i32 = Icmp lt_u, v76, v77
ExitIfTrue v78, exec_ctx, memory_out_of_bounds
v79:i64 = Iadd v24, v73
v80:i64 = Iconst_64 0x20
v81:i64 = Iadd v79, v80
v82:i64 = Iconst_64 0x1
v83:i64 = Band v81, v82
v84:i64 = Iconst_64 0x0
v85:i32 = Icmp neq, v83, v84
ExitIfTrue v85, exec_ctx, unaligned_atomic
v86:i64 = AtomicCas_16, v81, v10, v11
v87:i32 = Iconst_32 0x0
v88:i64 = Iconst_64 0x2c
v89:i64 = UExtend v87, 32->64
v90:i64 = Iconst_64 0x10
v91:i64 = Iadd module_ctx, v90
v92:i64 = AtomicLoad_64, v91
v93:i64 = Iadd v89, v88
v94:i32 = Icmp lt_u, v92, v93
ExitIfTrue v94, exec_ctx, memory_out_of_bounds
v95:i64 = Iadd v24, v89
v96:i64 = Iconst_64 0x28
v97:i64 = Iadd v95, v96
v98:i64 = Iconst_64 0x3
v99:i64 = Band v97, v98
v100:i64 = Iconst_64 0x0
v101:i32 = Icmp neq, v99, v100
ExitIfTrue v101, exec_ctx, unaligned_atomic
v102:i64 = AtomicCas_32, v97, v12, v13
v103:i32 = Iconst_32 0x0
v104:i64 = Iconst_64 0x38
v105:i64 = UExtend v103, 32->64
v106:i64 = Iconst_64 0x10
v107:i64 = Iadd module_ctx, v106
v108:i64 = AtomicLoad_64, v107
v109:i64 = Iadd v105, v104
v110:i32 = Icmp lt_u, v108, v109
ExitIfTrue v110, exec_ctx, memory_out_of_bounds
v111:i64 = Iadd v24, v105
v112:i64 = Iconst_64 0x30
v113:i64 = Iadd v111, v112
v114:i64 = Iconst_64 0x7
v115:i64 = Band v113, v114
v116:i64 = Iconst_64 0x0
v117:i32 = Icmp neq, v115, v116
ExitIfTrue v117, exec_ctx, unaligned_atomic
v118:i64 = AtomicCas_64, v113, v14, v15
Jump blk_ret, v26, v42, v58, v70, v86, v102, v118
`,
},
{
name: "AtomicFence",
m: testcases.AtomicFence.Module,
features: api.CoreFeaturesV2 | experimental.CoreFeaturesThreads,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64)
Fence 0
Jump blk_ret
`,
},
{
name: "AtomicFenceNoMemory",
m: testcases.AtomicFenceNoMemory.Module,
features: api.CoreFeaturesV2 | experimental.CoreFeaturesThreads,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64)
Jump blk_ret
`,
},
{
name: "bounds check in if-else",
m: &wasm.Module{
TypeSection: []wasm.FunctionType{{Params: []wasm.ValueType{wasm.ValueTypeI32}}},
FunctionSection: []wasm.Index{0},
CodeSection: []wasm.Code{{
Body: []byte{
wasm.OpcodeLocalGet, 0,
wasm.OpcodeI32Load, 0x2, 0x20, // alignment=2 (natural alignment) staticOffset=0x20
wasm.OpcodeDrop,
wasm.OpcodeLocalGet, 0,
wasm.OpcodeIf, 0x40, // blockSignature:vv.
/* */ wasm.OpcodeLocalGet, 0,
/* */ // This bound check should be removed since it's known to be in bounds.
/* */ wasm.OpcodeI32Load, 0x2, 0x10, // alignment=2 (natural alignment) staticOffset=0x20
/* */ wasm.OpcodeDrop,
wasm.OpcodeElse,
/* */ wasm.OpcodeLocalGet, 0,
/* */ // This bound check should be removed since it's known to be in bounds.
/* */ wasm.OpcodeI32Load, 0x2, 0x10, // alignment=2 (natural alignment) staticOffset=0x20
/* */ wasm.OpcodeDrop,
/* */ // This shouldn't be removed since it's not known to be in bounds.
/* */ wasm.OpcodeLocalGet, 0,
/* */ wasm.OpcodeI32Load, 0x2, 0x30, // alignment=2 (natural alignment) staticOffset=0x20
/* */ wasm.OpcodeDrop,
/* */ // But this is known to be in bounds.
/* */ wasm.OpcodeLocalGet, 0,
/* */ wasm.OpcodeI32Load, 0x2, 0x25, // alignment=2 (natural alignment) staticOffset=0x20
/* */ wasm.OpcodeDrop,
wasm.OpcodeEnd,
// At this point, the known bound 0x20 should be retained.
wasm.OpcodeLocalGet, 0,
wasm.OpcodeI32Load, 0x2, 0x15, // alignment=2 (natural alignment) staticOffset=0x20
wasm.OpcodeDrop,
wasm.OpcodeEnd,
},
}},
MemorySection: &wasm.Memory{Min: 1},
},
features: api.CoreFeaturesV2,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32)
v3:i64 = Iconst_64 0x24
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, 0x20
Brz v2, blk2
Jump blk1
blk1: () <-- (blk0)
v11:i32 = Load v9, 0x10
Jump blk3
blk2: () <-- (blk0)
v12:i32 = Load v9, 0x10
v13:i64 = Iconst_64 0x34
v14:i64 = UExtend v2, 32->64
v15:i64 = Iadd v14, v13
v16:i32 = Icmp lt_u, v5, v15
ExitIfTrue v16, exec_ctx, memory_out_of_bounds
v17:i32 = Load v9, 0x30
v18:i32 = Load v9, 0x25
Jump blk3
blk3: () <-- (blk1,blk2)
v20:i64 = Load module_ctx, 0x8
v21:i64 = UExtend v2, 32->64
v22:i64 = Iadd v20, v21
v23:i32 = Load v22, 0x15
Jump blk_ret
`,
},
{
name: "bounds check in loop with if-else",
m: &wasm.Module{
TypeSection: []wasm.FunctionType{{Params: []wasm.ValueType{wasm.ValueTypeI32}}},
FunctionSection: []wasm.Index{0},
CodeSection: []wasm.Code{{
Body: []byte{
wasm.OpcodeLocalGet, 0,
wasm.OpcodeI32Load, 0x2, 0x10, // staticOffset=0x20
wasm.OpcodeDrop,
wasm.OpcodeLoop, 0x40, // blockSignature:vv.
/* */ wasm.OpcodeLocalGet, 0,
// This address must be always recomputed:
// v9 in `Load v9, 0x20` won't propagate from blk0 to blk1,
/* */ wasm.OpcodeI32Load, 0x2, 0x20, // staticOffset=0x30
/* */ wasm.OpcodeIf, 0x40, // blockSignature:vv.
/* */ /* */ wasm.OpcodeLoop, 0x40, // blockSignature:vv.
/* */ /* */ /* */ wasm.OpcodeLocalGet, 0,
/* */ /* */ /* */ wasm.OpcodeI32Load, 0x2, 0x50, // staticOffset=0x50
/* */ /* */ /* */ wasm.OpcodeBrIf, 2, // quit to the inner loop
/* */ /* */ wasm.OpcodeEnd,
/* */ wasm.OpcodeElse,
/* */ /* */ wasm.OpcodeLocalGet, 0,
/* */ /* */ wasm.OpcodeBrIf, 2, // quit to the outer loop
/* */ wasm.OpcodeEnd,
/* */ wasm.OpcodeBr, 1, // quit to the loop
wasm.OpcodeEnd, // end loop
wasm.OpcodeEnd,
},
}},
MemorySection: &wasm.Memory{Min: 1},
},
features: api.CoreFeaturesV2,
exp: `
blk0: (exec_ctx:i64, module_ctx:i64, v2:i32)
v3:i64 = Iconst_64 0x14
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, 0x10
Jump blk1, v2
blk1: (v11:i32) <-- (blk0,blk6)
v12:i64 = Iconst_64 0x24
v13:i64 = UExtend v11, 32->64
v14:i64 = Uload32 module_ctx, 0x10
v15:i64 = Iadd v13, v12
v16:i32 = Icmp lt_u, v14, v15
ExitIfTrue v16, exec_ctx, memory_out_of_bounds
v17:i64 = Load module_ctx, 0x8
v18:i64 = Iadd v17, v13
v19:i32 = Load v18, 0x20
Brz v19, blk4
Jump blk3
blk2: ()
blk3: () <-- (blk1)
Jump blk6, v11
blk4: () <-- (blk1)
Brnz v11, blk_ret
Jump blk9
blk5: () <-- (blk7,blk9)
Jump blk_ret
blk6: (v20:i32) <-- (blk3)
v21:i64 = Iconst_64 0x54
v22:i64 = UExtend v20, 32->64
v23:i64 = Uload32 module_ctx, 0x10
v24:i64 = Iadd v22, v21
v25:i32 = Icmp lt_u, v23, v24
ExitIfTrue v25, exec_ctx, memory_out_of_bounds
v26:i64 = Load module_ctx, 0x8
v27:i64 = Iadd v26, v22
v28:i32 = Load v27, 0x50
Brnz v28, blk1, v20
Jump blk8
blk7: () <-- (blk8)
Jump blk5
blk8: () <-- (blk6)
Jump blk7
blk9: () <-- (blk4)
Jump blk5
`,
},
} {
tc := tc
t.Run(tc.name, func(t *testing.T) {
// Just in case let's check the test module is valid.
features := tc.features
if features == 0 {
features = api.CoreFeaturesV2
}
err := tc.m.Validate(features)
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()
require.Equal(t, tc.exp, actual)
b.RunPasses()
if expAfterOpt := tc.expAfterPasses; expAfterOpt != "" {
actualAfterOpt := fc.formatBuilder()
require.Equal(t, expAfterOpt, actualAfterOpt)
}
})
}
}
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}},
{ID: 8, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI64, ssa.TypeI64}},
{ID: 9, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI64, ssa.TypeI32, ssa.TypeI64}, Results: []ssa.Type{ssa.TypeI32}},
{ID: 10, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI64, ssa.TypeI64, ssa.TypeI64}, Results: []ssa.Type{ssa.TypeI32}},
{ID: 11, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI32, ssa.TypeI64}, Results: []ssa.Type{ssa.TypeI32}},
// EH signatures.
{ID: 12, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI64}, Results: []ssa.Type{ssa.TypeI64}},
{ID: 13, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI64}},
{ID: 14, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI64}},
{ID: 15, Params: []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}},
{ID: 16, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI64, ssa.TypeI64}},
{ID: 17, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI64, ssa.TypeI32, ssa.TypeI64}, Results: []ssa.Type{ssa.TypeI32}},
{ID: 18, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI64, ssa.TypeI64, ssa.TypeI64}, Results: []ssa.Type{ssa.TypeI32}},
{ID: 19, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI32, ssa.TypeI64}, Results: []ssa.Type{ssa.TypeI32}},
// EH signatures.
{ID: 20, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI64}, Results: []ssa.Type{ssa.TypeI64}},
{ID: 21, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI64}},
{ID: 22, Params: []ssa.Type{ssa.TypeI64, ssa.TypeI64}},
{ID: 23, Params: []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)
}
})
}
func TestCompiler_recordKnownSafeBound(t *testing.T) {
c := &Compiler{}
c.recordKnownSafeBound(1, 99, 9999)
require.Equal(t, 1, len(c.knownSafeBoundsSet))
require.True(t, c.getKnownSafeBound(1).valid())
require.Equal(t, uint64(99), c.getKnownSafeBound(1).bound)
require.Equal(t, ssa.Value(9999), c.getKnownSafeBound(1).absoluteAddr)
c.recordKnownSafeBound(1, 150, 9999)
require.Equal(t, 1, len(c.knownSafeBoundsSet))
require.Equal(t, uint64(150), c.getKnownSafeBound(1).bound)
c.recordKnownSafeBound(5, 666, 54321)
require.Equal(t, 2, len(c.knownSafeBoundsSet))
require.Equal(t, uint64(666), c.getKnownSafeBound(5).bound)
require.Equal(t, ssa.Value(54321), c.getKnownSafeBound(5).absoluteAddr)
}
func TestCompiler_getKnownSafeBound(t *testing.T) {
c := &Compiler{
knownSafeBounds: []knownSafeBound{
{}, {bound: 2134},
},
}
require.Nil(t, c.getKnownSafeBound(5))
require.Nil(t, c.getKnownSafeBound(12345))
require.False(t, c.getKnownSafeBound(0).valid())
require.True(t, c.getKnownSafeBound(1).valid())
}
func TestCompiler_clearSafeBounds(t *testing.T) {
c := &Compiler{}
c.knownSafeBounds = []knownSafeBound{{bound: 1}, {}, {bound: 2}, {}, {}, {bound: 3}}
c.knownSafeBoundsSet = []ssa.ValueID{0, 2, 5}
c.clearSafeBounds()
require.Equal(t, 0, len(c.knownSafeBoundsSet))
require.Equal(t, []knownSafeBound{{absoluteAddr: ssa.ValueInvalid}, {}, {absoluteAddr: ssa.ValueInvalid}, {}, {}, {absoluteAddr: ssa.ValueInvalid}}, c.knownSafeBounds)
}
func TestCompiler_resetAbsoluteAddressInSafeBounds(t *testing.T) {
c := &Compiler{}
c.knownSafeBounds = []knownSafeBound{
{bound: 1, absoluteAddr: ssa.Value(1)},
{},
{bound: 2, absoluteAddr: ssa.Value(2)},
{},
{},
{bound: 3, absoluteAddr: ssa.Value(3)},
}
c.knownSafeBoundsSet = []ssa.ValueID{0, 2, 5}
c.resetAbsoluteAddressInSafeBounds()
require.Equal(t, 3, len(c.knownSafeBoundsSet))
require.Equal(t, []knownSafeBound{
{bound: 1, absoluteAddr: ssa.ValueInvalid},
{},
{bound: 2, absoluteAddr: ssa.ValueInvalid},
{},
{},
{bound: 3, absoluteAddr: ssa.ValueInvalid},
}, c.knownSafeBounds)
}
func TestKnownSafeBound_valid(t *testing.T) {
k := &knownSafeBound{bound: 10, absoluteAddr: 12345}
require.True(t, k.valid())
k.bound = 0
require.False(t, k.valid())
}
func TestCompiler_finalizeKnownSafeBoundsAtTheEndOoBlock(t *testing.T) {
c := NewFrontendCompiler(&wasm.Module{}, ssa.NewBuilder(), nil, false, false, false)
blk := c.ssaBuilder.AllocateBasicBlock()
require.True(t, len(c.getKnownSafeBoundsAtTheEndOfBlocks(blk.ID()).View()) == 0)
c.ssaBuilder.SetCurrentBlock(blk)
c.knownSafeBoundsSet = []ssa.ValueID{0, 2, 5}
c.knownSafeBounds = []knownSafeBound{
{bound: 1, absoluteAddr: ssa.Value(1)},
{},
{bound: 2, absoluteAddr: ssa.Value(2)},
{},
{},
{bound: 3, absoluteAddr: ssa.Value(3)},
}
c.finalizeKnownSafeBoundsAtTheEndOfBlock(blk.ID())
require.True(t, len(c.knownSafeBoundsSet) == 0)
finalized := c.getKnownSafeBoundsAtTheEndOfBlocks(blk.ID())
require.Equal(t, 3, len(finalized.View()))
}
func TestCompiler_initializeCurrentBlockKnownBounds(t *testing.T) {
t.Run("single (sealed)", func(t *testing.T) {
c := NewFrontendCompiler(&wasm.Module{}, ssa.NewBuilder(), nil, false, false, false)
builder := c.ssaBuilder
child := builder.AllocateBasicBlock()
{
parent := builder.AllocateBasicBlock()
builder.SetCurrentBlock(parent)
c.recordKnownSafeBound(1, 99, 9999)
c.recordKnownSafeBound(2, 150, 9999)
c.recordKnownSafeBound(5, 666, 54321)
builder.AllocateInstruction().AsJump(ssa.ValuesNil, child).Insert(builder)
c.finalizeKnownSafeBoundsAtTheEndOfBlock(parent.ID())
}
// Seal the child: the absolute addresses will be propagated.
builder.Seal(child)
builder.SetCurrentBlock(child)
c.initializeCurrentBlockKnownBounds()
kb := c.getKnownSafeBound(1)
require.True(t, kb.valid())
require.Equal(t, uint64(99), kb.bound)
require.Equal(t, ssa.Value(9999), kb.absoluteAddr)
kb = c.getKnownSafeBound(2)
require.True(t, kb.valid())
require.Equal(t, uint64(150), kb.bound)
require.Equal(t, ssa.Value(9999), kb.absoluteAddr)
kb = c.getKnownSafeBound(5)
require.True(t, kb.valid())
require.Equal(t, uint64(666), kb.bound)
require.Equal(t, ssa.Value(54321), kb.absoluteAddr)
})
t.Run("single (unsealed)", func(t *testing.T) {
c := NewFrontendCompiler(&wasm.Module{}, ssa.NewBuilder(), nil, false, false, false)
builder := c.ssaBuilder
child := builder.AllocateBasicBlock()
{
parent := builder.AllocateBasicBlock()
builder.SetCurrentBlock(parent)
c.recordKnownSafeBound(1, 99, 9999)
c.recordKnownSafeBound(2, 150, 9999)
c.recordKnownSafeBound(5, 666, 54321)
builder.AllocateInstruction().AsJump(ssa.ValuesNil, child).Insert(builder)
c.finalizeKnownSafeBoundsAtTheEndOfBlock(parent.ID())
}
// Do not seal the child: the absolute addresses will be recomputed.
builder.SetCurrentBlock(child)
c.initializeCurrentBlockKnownBounds()
kb := c.getKnownSafeBound(1)
require.True(t, kb.valid())
require.Equal(t, uint64(99), kb.bound)
require.NotEqual(t, ssa.Value(9999), kb.absoluteAddr)
kb = c.getKnownSafeBound(2)
require.True(t, kb.valid())
require.Equal(t, uint64(150), kb.bound)
require.NotEqual(t, ssa.Value(9999), kb.absoluteAddr)
kb = c.getKnownSafeBound(5)
require.True(t, kb.valid())
require.Equal(t, uint64(666), kb.bound)
require.NotEqual(t, ssa.Value(54321), kb.absoluteAddr)
})
t.Run("multiple predecessors", func(t *testing.T) {
c := NewFrontendCompiler(&wasm.Module{}, ssa.NewBuilder(), nil, false, false, false)
builder := c.ssaBuilder
child := builder.AllocateBasicBlock()
{
p1 := builder.AllocateBasicBlock()
builder.SetCurrentBlock(p1)
c.recordKnownSafeBound(1, 99, 9999)
c.recordKnownSafeBound(2, 150, 9999)
c.recordKnownSafeBound(5, 666, 54321)
c.recordKnownSafeBound(592131, 666, 54321)
builder.AllocateInstruction().AsJump(ssa.ValuesNil, child).Insert(builder)
c.finalizeKnownSafeBoundsAtTheEndOfBlock(p1.ID())
}
{
p2 := builder.AllocateBasicBlock()
builder.SetCurrentBlock(p2)
c.recordKnownSafeBound(1, 100, 999419)
c.recordKnownSafeBound(2, 4, 9991239)
c.recordKnownSafeBound(5, 555, 54341221)
c.recordKnownSafeBound(6, 666, 54321)
c.recordKnownSafeBound(7, 666, 54321)
builder.AllocateInstruction().AsJump(ssa.ValuesNil, child).Insert(builder)
c.finalizeKnownSafeBoundsAtTheEndOfBlock(p2.ID())
}
{
p3 := builder.AllocateBasicBlock()
builder.SetCurrentBlock(p3)
c.recordKnownSafeBound(1, 1, 999419)
c.recordKnownSafeBound(2, 11111, 9991239)
c.recordKnownSafeBound(5, 5551231, 54341221)
c.recordKnownSafeBound(7, 666, 54321)
c.recordKnownSafeBound(60, 666, 54321)
builder.AllocateInstruction().AsJump(ssa.ValuesNil, child).Insert(builder)
c.finalizeKnownSafeBoundsAtTheEndOfBlock(p3.ID())
}
builder.SetCurrentBlock(child)
c.initializeCurrentBlockKnownBounds()
for _, tc := range []struct {
id ssa.ValueID
valid bool
bound uint64
}{
{id: 0, valid: false},
{id: 1, valid: true, bound: 1},
{id: 2, valid: true, bound: 4},
{id: 3, valid: false},
{id: 4, valid: false},
{id: 5, valid: true, bound: 555},
{id: 6, valid: false},
{id: 7, valid: false},
{id: 60, valid: false},
{id: 592131, valid: false},
} {
t.Run(fmt.Sprintf("id=%d", tc.id), func(t *testing.T) {
kb := c.getKnownSafeBound(tc.id)
require.Equal(t, tc.valid, kb.valid())
if kb.valid() {
require.Equal(t, tc.bound, kb.bound)
require.Equal(t, ssa.ValueInvalid, kb.absoluteAddr)
}
})
}
})
}