Expect tests
This commit is contained in:
parent
f093e23f9e
commit
e6af9f3d7f
3
.travis-run-expect.sh
Executable file
3
.travis-run-expect.sh
Executable file
|
@ -0,0 +1,3 @@
|
|||
#!/usr/bin/env bash
|
||||
set -e
|
||||
make expect-tests
|
|
@ -17,3 +17,4 @@ env:
|
|||
- TEST_SUITE=codegen
|
||||
- TEST_SUITE=jshint
|
||||
- TEST_SUITE=jit-paging
|
||||
- TEST_SUITE=expect
|
||||
|
|
4
Makefile
4
Makefile
|
@ -296,6 +296,10 @@ kvm-unit-test: build/libv86-debug.js build/v86-debug.wasm
|
|||
codegen-test: build/codegen-test.wasm
|
||||
./tests/codegen/codegen.js
|
||||
|
||||
expect-tests: build/libv86-debug.js build/libwabt.js
|
||||
make -C tests/expect/tests
|
||||
./tests/expect/run.js
|
||||
|
||||
covreport:
|
||||
mkdir -p $(COVERAGE_DIR)/build/
|
||||
$(COVERAGE_DIR)/gen_report.js
|
||||
|
|
|
@ -311,6 +311,8 @@ CPU.prototype.wasm_patch = function(wm)
|
|||
|
||||
this.clear_tlb = this.wm.exports["_clear_tlb"];
|
||||
this.full_clear_tlb = this.wm.exports["_full_clear_tlb"];
|
||||
|
||||
this.jit_force_generate_unsafe = this.wm.exports["_jit_force_generate_unsafe"];
|
||||
};
|
||||
|
||||
CPU.prototype.jit_clear_func = function(index)
|
||||
|
@ -1278,6 +1280,11 @@ CPU.prototype.codegen_finalize = function(wasm_table_index, start, end, first_op
|
|||
}
|
||||
|
||||
seen_code[start] = (seen_code[start] || 0) + 1;
|
||||
|
||||
if(this.test_hook_did_generate_wasm)
|
||||
{
|
||||
this.test_hook_did_generate_wasm(code);
|
||||
}
|
||||
}
|
||||
|
||||
// Make a copy of jit_imports, since some imports change and
|
||||
|
|
|
@ -1375,6 +1375,13 @@ static void jit_generate(uint32_t phys_addr, uint32_t page_dirtiness)
|
|||
*instruction_pointer = start;
|
||||
}
|
||||
|
||||
// for testing
|
||||
void jit_force_generate_unsafe(uint32_t phys_addr)
|
||||
{
|
||||
*instruction_pointer = phys_addr;
|
||||
jit_generate(phys_addr, 0);
|
||||
}
|
||||
|
||||
void cycle_internal()
|
||||
{
|
||||
#if ENABLE_JIT
|
||||
|
|
21
tests/expect/readme.md
Normal file
21
tests/expect/readme.md
Normal file
|
@ -0,0 +1,21 @@
|
|||
Expect tests
|
||||
------------
|
||||
|
||||
These so-called "expect tests" test the code generation, i.e. the translation
|
||||
of x86 assembly to Web Assembly. Use the following workflow:
|
||||
|
||||
1. Hack on the code generator
|
||||
2. Run make `expect-tests`
|
||||
3. For each failing test:
|
||||
- Manually verify that the generated code changes are as expected by the diff
|
||||
- If so, accept the new code by copying the .actual.wast file over the .wast file
|
||||
and checking the new .wast file into git
|
||||
|
||||
In order to add a new expect test:
|
||||
|
||||
1. Create a new .asm file in tests/
|
||||
2. Run make `expect-tests`
|
||||
3. Verify the generated code and use the printed cp command to accept the test
|
||||
|
||||
|
||||
For more information, see https://blog.janestreet.com/testing-with-expectations/
|
151
tests/expect/run.js
Executable file
151
tests/expect/run.js
Executable file
|
@ -0,0 +1,151 @@
|
|||
#!/usr/bin/env node
|
||||
"use strict";
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const { spawnSync } = require("child_process");
|
||||
|
||||
const libwabt = require("../../build/libwabt.js");
|
||||
|
||||
try {
|
||||
var V86 = require("../../build/libv86-debug.js").V86;
|
||||
}
|
||||
catch(e) {
|
||||
console.error(e);
|
||||
console.error("Failed to import build/libv86-debug.js. Run " +
|
||||
"`make build/libv86-debug.js` first.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const LOG_LEVEL = 0;
|
||||
|
||||
const GIT_DIFF_FLAGS = [ "--no-index", "--patience", "--color=always"];
|
||||
|
||||
const TEST_DIR = path.join(__dirname, "tests");
|
||||
const BUILD_DIR = path.join(TEST_DIR, "build");
|
||||
|
||||
function run_all()
|
||||
{
|
||||
const asm_files = fs.readdirSync(TEST_DIR).filter(filename => filename.endsWith(".asm"));
|
||||
|
||||
const files = asm_files.map(asm_file => {
|
||||
const name = asm_file.slice(0, -4);
|
||||
return {
|
||||
name,
|
||||
expect_file: path.relative(".", path.join(TEST_DIR, name + ".wast")),
|
||||
actual_file: path.relative(".", path.join(BUILD_DIR, name + ".actual.wast")),
|
||||
asm_file: path.join(TEST_DIR, name + ".asm"),
|
||||
executable_file: path.join(BUILD_DIR, name + ".bin"),
|
||||
};
|
||||
});
|
||||
|
||||
files.forEach(run_test);
|
||||
}
|
||||
|
||||
function run_test({ name, executable_file, expect_file, actual_file, asm_file })
|
||||
{
|
||||
const emulator = new V86({
|
||||
autostart: false,
|
||||
memory_size: 2 * 1024 * 1024,
|
||||
log_level: LOG_LEVEL,
|
||||
});
|
||||
|
||||
const executable = fs.readFileSync(executable_file);
|
||||
const asm = fs.readFileSync(asm_file);
|
||||
|
||||
const is_32 = asm.includes("BITS 32");
|
||||
|
||||
emulator.add_listener("emulator-loaded", function()
|
||||
{
|
||||
const cpu = emulator.v86.cpu;
|
||||
|
||||
const hook_not_called_timeout = setTimeout(() => {
|
||||
throw new Error("Hook for code generation not called");
|
||||
}, 1000);
|
||||
|
||||
cpu.test_hook_did_generate_wasm = function(wasm)
|
||||
{
|
||||
const wast = disassemble_wasm(wasm);
|
||||
|
||||
clearTimeout(hook_not_called_timeout);
|
||||
fs.writeFileSync(actual_file, wast);
|
||||
|
||||
cpu.test_hook_did_generate_wasm = function()
|
||||
{
|
||||
cpu.test_hook_did_generate_wasm = function() {};
|
||||
throw new Error("Hook for wasm generation called multiple times");
|
||||
};
|
||||
|
||||
if(!fs.existsSync(expect_file))
|
||||
{
|
||||
// enhanced workflow: If file doesn't exist yet print full diff
|
||||
var expect_file_for_diff = "/dev/null";
|
||||
}
|
||||
else
|
||||
{
|
||||
expect_file_for_diff = expect_file;
|
||||
}
|
||||
|
||||
const result = spawnSync("git",
|
||||
[].concat(
|
||||
"diff",
|
||||
GIT_DIFF_FLAGS,
|
||||
expect_file_for_diff,
|
||||
actual_file
|
||||
),
|
||||
{ encoding: "utf8" });
|
||||
|
||||
if(result.status)
|
||||
{
|
||||
console.log(result.stdout);
|
||||
console.log(result.stderr);
|
||||
|
||||
console.log(
|
||||
"%s.asm failed:\n" +
|
||||
"The code generator produced different code. If you believe this change is intentional,\n" +
|
||||
"verify the diff above and run the following command to accept the change:\n\n" +
|
||||
" cp %s %s", name, actual_file, expect_file);
|
||||
|
||||
process.exit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
console.log("%s ok", name);
|
||||
console.assert(!result.stdout);
|
||||
console.assert(!result.stderr);
|
||||
}
|
||||
};
|
||||
|
||||
if(is_32)
|
||||
{
|
||||
cpu.is_32[0] = true;
|
||||
cpu.stack_size_32[0] = true;
|
||||
}
|
||||
|
||||
const START_ADDRESS = 0x1000;
|
||||
|
||||
cpu.mem8.set(executable, START_ADDRESS);
|
||||
cpu.jit_force_generate_unsafe(START_ADDRESS);
|
||||
});
|
||||
}
|
||||
|
||||
function disassemble_wasm(wasm)
|
||||
{
|
||||
// Need to make a small copy otherwise libwabt goes nuts trying to copy
|
||||
// the whole underlying buffer
|
||||
wasm = wasm.slice();
|
||||
|
||||
try
|
||||
{
|
||||
var module = libwabt.readWasm(wasm, { readDebugNames: false });
|
||||
module.generateNames();
|
||||
module.applyNames();
|
||||
return module.toText({ foldExprs: true, inlineExport: true });
|
||||
}
|
||||
finally
|
||||
{
|
||||
module && module.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
run_all();
|
9
tests/expect/tests/Makefile
Normal file
9
tests/expect/tests/Makefile
Normal file
|
@ -0,0 +1,9 @@
|
|||
|
||||
source_files := $(wildcard *.asm)
|
||||
executable_files := $(patsubst %.asm,build/%.bin,$(source_files))
|
||||
|
||||
all: $(executable_files)
|
||||
mkdir -p build
|
||||
|
||||
build/%.bin: %.asm
|
||||
nasm $< -o $@
|
8
tests/expect/tests/call.asm
Normal file
8
tests/expect/tests/call.asm
Normal file
|
@ -0,0 +1,8 @@
|
|||
BITS 32
|
||||
|
||||
call test
|
||||
hlt
|
||||
|
||||
test:
|
||||
inc eax
|
||||
ret
|
51
tests/expect/tests/call.wast
Normal file
51
tests/expect/tests/call.wast
Normal file
|
@ -0,0 +1,51 @@
|
|||
(module
|
||||
(type $t0 (func))
|
||||
(type $t1 (func (param i32)))
|
||||
(type $t2 (func (param i32 i32)))
|
||||
(type $t3 (func (param i32 i32 i32)))
|
||||
(type $t4 (func (result i32)))
|
||||
(type $t5 (func (param i32) (result i32)))
|
||||
(type $t6 (func (param i32 i32) (result i32)))
|
||||
(import "e" "get_seg" (func $e.get_seg (type $t5)))
|
||||
(import "e" "instr32_E8" (func $e.instr32_E8 (type $t1)))
|
||||
(import "e" "m" (memory $e.m 256))
|
||||
(func $f (export "f") (type $t0)
|
||||
(local $l0 i32) (local $l1 i32)
|
||||
(set_local $l0
|
||||
(i32.const 0))
|
||||
(set_local $l1
|
||||
(i32.const 10000))
|
||||
(loop $L0
|
||||
(set_local $l1
|
||||
(i32.add
|
||||
(get_local $l1)
|
||||
(i32.const -1)))
|
||||
(if $I1
|
||||
(i32.eqz
|
||||
(get_local $l1))
|
||||
(then
|
||||
(return)))
|
||||
(block $B2
|
||||
(block $B3
|
||||
(br_table $B3 $B2
|
||||
(get_local $l0)))
|
||||
(i32.store
|
||||
(i32.const 560)
|
||||
(i32.load
|
||||
(i32.const 556)))
|
||||
(i32.store
|
||||
(i32.const 556)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 556))
|
||||
(i32.const 5)))
|
||||
(call $e.instr32_E8
|
||||
(i32.const 1))
|
||||
(i32.store
|
||||
(i32.const 664)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 664))
|
||||
(i32.const 1)))
|
||||
(return))
|
||||
(unreachable))))
|
8
tests/expect/tests/do-while.asm
Normal file
8
tests/expect/tests/do-while.asm
Normal file
|
@ -0,0 +1,8 @@
|
|||
BITS 32
|
||||
|
||||
start:
|
||||
inc ebx
|
||||
cmp eax, 10
|
||||
jnz start
|
||||
|
||||
hlt
|
91
tests/expect/tests/do-while.wast
Normal file
91
tests/expect/tests/do-while.wast
Normal file
|
@ -0,0 +1,91 @@
|
|||
(module
|
||||
(type $t0 (func))
|
||||
(type $t1 (func (param i32)))
|
||||
(type $t2 (func (param i32 i32)))
|
||||
(type $t3 (func (param i32 i32 i32)))
|
||||
(type $t4 (func (result i32)))
|
||||
(type $t5 (func (param i32) (result i32)))
|
||||
(type $t6 (func (param i32 i32) (result i32)))
|
||||
(import "e" "get_seg" (func $e.get_seg (type $t5)))
|
||||
(import "e" "instr32_43" (func $e.instr32_43 (type $t0)))
|
||||
(import "e" "instr32_83_7_reg" (func $e.instr32_83_7_reg (type $t2)))
|
||||
(import "e" "test_nz" (func $e.test_nz (type $t4)))
|
||||
(import "e" "instr_F4" (func $e.instr_F4 (type $t0)))
|
||||
(import "e" "m" (memory $e.m 256))
|
||||
(func $f (export "f") (type $t0)
|
||||
(local $l0 i32) (local $l1 i32)
|
||||
(set_local $l0
|
||||
(i32.const 0))
|
||||
(set_local $l1
|
||||
(i32.const 10000))
|
||||
(loop $L0
|
||||
(set_local $l1
|
||||
(i32.add
|
||||
(get_local $l1)
|
||||
(i32.const -1)))
|
||||
(if $I1
|
||||
(i32.eqz
|
||||
(get_local $l1))
|
||||
(then
|
||||
(return)))
|
||||
(block $B2
|
||||
(block $B3
|
||||
(block $B4
|
||||
(br_table $B4 $B3 $B2
|
||||
(get_local $l0)))
|
||||
(i32.store
|
||||
(i32.const 560)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 556))
|
||||
(i32.const 4)))
|
||||
(i32.store
|
||||
(i32.const 556)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 556))
|
||||
(i32.const 6)))
|
||||
(call $e.instr32_43)
|
||||
(call $e.instr32_83_7_reg
|
||||
(i32.const 0)
|
||||
(i32.const 10))
|
||||
(i32.store
|
||||
(i32.const 664)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 664))
|
||||
(i32.const 3)))
|
||||
(if $I5
|
||||
(call $e.test_nz)
|
||||
(then
|
||||
(i32.store
|
||||
(i32.const 556)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 556))
|
||||
(i32.const -6)))
|
||||
(set_local $l0
|
||||
(i32.const 0)))
|
||||
(else
|
||||
(set_local $l0
|
||||
(i32.const 1))))
|
||||
(br $L0))
|
||||
(i32.store
|
||||
(i32.const 560)
|
||||
(i32.load
|
||||
(i32.const 556)))
|
||||
(i32.store
|
||||
(i32.const 556)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 556))
|
||||
(i32.const 1)))
|
||||
(call $e.instr_F4)
|
||||
(i32.store
|
||||
(i32.const 664)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 664))
|
||||
(i32.const 1)))
|
||||
(return))
|
||||
(unreachable))))
|
8
tests/expect/tests/if.asm
Normal file
8
tests/expect/tests/if.asm
Normal file
|
@ -0,0 +1,8 @@
|
|||
BITS 32
|
||||
|
||||
cmp eax, 5
|
||||
jg else
|
||||
inc ecx
|
||||
else:
|
||||
inc ebx
|
||||
hlt
|
111
tests/expect/tests/if.wast
Normal file
111
tests/expect/tests/if.wast
Normal file
|
@ -0,0 +1,111 @@
|
|||
(module
|
||||
(type $t0 (func))
|
||||
(type $t1 (func (param i32)))
|
||||
(type $t2 (func (param i32 i32)))
|
||||
(type $t3 (func (param i32 i32 i32)))
|
||||
(type $t4 (func (result i32)))
|
||||
(type $t5 (func (param i32) (result i32)))
|
||||
(type $t6 (func (param i32 i32) (result i32)))
|
||||
(import "e" "get_seg" (func $e.get_seg (type $t5)))
|
||||
(import "e" "instr32_83_7_reg" (func $e.instr32_83_7_reg (type $t2)))
|
||||
(import "e" "test_nle" (func $e.test_nle (type $t4)))
|
||||
(import "e" "instr32_41" (func $e.instr32_41 (type $t0)))
|
||||
(import "e" "instr32_43" (func $e.instr32_43 (type $t0)))
|
||||
(import "e" "instr_F4" (func $e.instr_F4 (type $t0)))
|
||||
(import "e" "m" (memory $e.m 256))
|
||||
(func $f (export "f") (type $t0)
|
||||
(local $l0 i32) (local $l1 i32)
|
||||
(set_local $l0
|
||||
(i32.const 0))
|
||||
(set_local $l1
|
||||
(i32.const 10000))
|
||||
(loop $L0
|
||||
(set_local $l1
|
||||
(i32.add
|
||||
(get_local $l1)
|
||||
(i32.const -1)))
|
||||
(if $I1
|
||||
(i32.eqz
|
||||
(get_local $l1))
|
||||
(then
|
||||
(return)))
|
||||
(block $B2
|
||||
(block $B3
|
||||
(block $B4
|
||||
(block $B5
|
||||
(br_table $B5 $B4 $B3 $B2
|
||||
(get_local $l0)))
|
||||
(i32.store
|
||||
(i32.const 560)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 556))
|
||||
(i32.const 3)))
|
||||
(i32.store
|
||||
(i32.const 556)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 556))
|
||||
(i32.const 5)))
|
||||
(call $e.instr32_83_7_reg
|
||||
(i32.const 0)
|
||||
(i32.const 5))
|
||||
(i32.store
|
||||
(i32.const 664)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 664))
|
||||
(i32.const 2)))
|
||||
(if $I6
|
||||
(call $e.test_nle)
|
||||
(then
|
||||
(i32.store
|
||||
(i32.const 556)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 556))
|
||||
(i32.const 1)))
|
||||
(set_local $l0
|
||||
(i32.const 2)))
|
||||
(else
|
||||
(set_local $l0
|
||||
(i32.const 1))))
|
||||
(br $L0))
|
||||
(call $e.instr32_41)
|
||||
(i32.store
|
||||
(i32.const 556)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 556))
|
||||
(i32.const 1)))
|
||||
(i32.store
|
||||
(i32.const 664)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 664))
|
||||
(i32.const 1)))
|
||||
(set_local $l0
|
||||
(i32.const 2))
|
||||
(br $L0))
|
||||
(i32.store
|
||||
(i32.const 560)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 556))
|
||||
(i32.const 1)))
|
||||
(i32.store
|
||||
(i32.const 556)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 556))
|
||||
(i32.const 2)))
|
||||
(call $e.instr32_43)
|
||||
(call $e.instr_F4)
|
||||
(i32.store
|
||||
(i32.const 664)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 664))
|
||||
(i32.const 2)))
|
||||
(return))
|
||||
(unreachable))))
|
4
tests/expect/tests/indirect-call.asm
Normal file
4
tests/expect/tests/indirect-call.asm
Normal file
|
@ -0,0 +1,4 @@
|
|||
BITS 32
|
||||
|
||||
call [eax]
|
||||
hlt
|
55
tests/expect/tests/indirect-call.wast
Normal file
55
tests/expect/tests/indirect-call.wast
Normal file
|
@ -0,0 +1,55 @@
|
|||
(module
|
||||
(type $t0 (func))
|
||||
(type $t1 (func (param i32)))
|
||||
(type $t2 (func (param i32 i32)))
|
||||
(type $t3 (func (param i32 i32 i32)))
|
||||
(type $t4 (func (result i32)))
|
||||
(type $t5 (func (param i32) (result i32)))
|
||||
(type $t6 (func (param i32 i32) (result i32)))
|
||||
(import "e" "get_seg" (func $e.get_seg (type $t5)))
|
||||
(import "e" "instr32_FF_2_mem" (func $e.instr32_FF_2_mem (type $t1)))
|
||||
(import "e" "m" (memory $e.m 256))
|
||||
(func $f (export "f") (type $t0)
|
||||
(local $l0 i32) (local $l1 i32)
|
||||
(set_local $l0
|
||||
(i32.const 0))
|
||||
(set_local $l1
|
||||
(i32.const 10000))
|
||||
(loop $L0
|
||||
(set_local $l1
|
||||
(i32.add
|
||||
(get_local $l1)
|
||||
(i32.const -1)))
|
||||
(if $I1
|
||||
(i32.eqz
|
||||
(get_local $l1))
|
||||
(then
|
||||
(return)))
|
||||
(block $B2
|
||||
(block $B3
|
||||
(br_table $B3 $B2
|
||||
(get_local $l0)))
|
||||
(i32.store
|
||||
(i32.const 560)
|
||||
(i32.load
|
||||
(i32.const 556)))
|
||||
(i32.store
|
||||
(i32.const 556)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 556))
|
||||
(i32.const 2)))
|
||||
(call $e.instr32_FF_2_mem
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 4))
|
||||
(call $e.get_seg
|
||||
(i32.const 3))))
|
||||
(i32.store
|
||||
(i32.const 664)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 664))
|
||||
(i32.const 1)))
|
||||
(return))
|
||||
(unreachable))))
|
4
tests/expect/tests/pop.asm
Normal file
4
tests/expect/tests/pop.asm
Normal file
|
@ -0,0 +1,4 @@
|
|||
BITS 32
|
||||
|
||||
pop eax
|
||||
hlt
|
60
tests/expect/tests/pop.wast
Normal file
60
tests/expect/tests/pop.wast
Normal file
|
@ -0,0 +1,60 @@
|
|||
(module
|
||||
(type $t0 (func))
|
||||
(type $t1 (func (param i32)))
|
||||
(type $t2 (func (param i32 i32)))
|
||||
(type $t3 (func (param i32 i32 i32)))
|
||||
(type $t4 (func (result i32)))
|
||||
(type $t5 (func (param i32) (result i32)))
|
||||
(type $t6 (func (param i32 i32) (result i32)))
|
||||
(import "e" "get_seg" (func $e.get_seg (type $t5)))
|
||||
(import "e" "pop32s_ss32" (func $e.pop32s_ss32 (type $t4)))
|
||||
(import "e" "instr_F4" (func $e.instr_F4 (type $t0)))
|
||||
(import "e" "m" (memory $e.m 256))
|
||||
(func $f (export "f") (type $t0)
|
||||
(local $l0 i32) (local $l1 i32)
|
||||
(set_local $l0
|
||||
(i32.const 0))
|
||||
(set_local $l1
|
||||
(i32.const 10000))
|
||||
(loop $L0
|
||||
(set_local $l1
|
||||
(i32.add
|
||||
(get_local $l1)
|
||||
(i32.const -1)))
|
||||
(if $I1
|
||||
(i32.eqz
|
||||
(get_local $l1))
|
||||
(then
|
||||
(return)))
|
||||
(block $B2
|
||||
(block $B3
|
||||
(br_table $B3 $B2
|
||||
(get_local $l0)))
|
||||
(i32.store
|
||||
(i32.const 560)
|
||||
(i32.load
|
||||
(i32.const 556)))
|
||||
(i32.store
|
||||
(i32.const 4)
|
||||
(call $e.pop32s_ss32))
|
||||
(i32.store
|
||||
(i32.const 560)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 556))
|
||||
(i32.const 1)))
|
||||
(i32.store
|
||||
(i32.const 556)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 556))
|
||||
(i32.const 2)))
|
||||
(call $e.instr_F4)
|
||||
(i32.store
|
||||
(i32.const 664)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 664))
|
||||
(i32.const 2)))
|
||||
(return))
|
||||
(unreachable))))
|
4
tests/expect/tests/push.asm
Normal file
4
tests/expect/tests/push.asm
Normal file
|
@ -0,0 +1,4 @@
|
|||
BITS 32
|
||||
|
||||
push eax
|
||||
hlt
|
60
tests/expect/tests/push.wast
Normal file
60
tests/expect/tests/push.wast
Normal file
|
@ -0,0 +1,60 @@
|
|||
(module
|
||||
(type $t0 (func))
|
||||
(type $t1 (func (param i32)))
|
||||
(type $t2 (func (param i32 i32)))
|
||||
(type $t3 (func (param i32 i32 i32)))
|
||||
(type $t4 (func (result i32)))
|
||||
(type $t5 (func (param i32) (result i32)))
|
||||
(type $t6 (func (param i32 i32) (result i32)))
|
||||
(import "e" "get_seg" (func $e.get_seg (type $t5)))
|
||||
(import "e" "push32_ss32" (func $e.push32_ss32 (type $t1)))
|
||||
(import "e" "instr_F4" (func $e.instr_F4 (type $t0)))
|
||||
(import "e" "m" (memory $e.m 256))
|
||||
(func $f (export "f") (type $t0)
|
||||
(local $l0 i32) (local $l1 i32)
|
||||
(set_local $l0
|
||||
(i32.const 0))
|
||||
(set_local $l1
|
||||
(i32.const 10000))
|
||||
(loop $L0
|
||||
(set_local $l1
|
||||
(i32.add
|
||||
(get_local $l1)
|
||||
(i32.const -1)))
|
||||
(if $I1
|
||||
(i32.eqz
|
||||
(get_local $l1))
|
||||
(then
|
||||
(return)))
|
||||
(block $B2
|
||||
(block $B3
|
||||
(br_table $B3 $B2
|
||||
(get_local $l0)))
|
||||
(i32.store
|
||||
(i32.const 560)
|
||||
(i32.load
|
||||
(i32.const 556)))
|
||||
(call $e.push32_ss32
|
||||
(i32.load
|
||||
(i32.const 4)))
|
||||
(i32.store
|
||||
(i32.const 560)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 556))
|
||||
(i32.const 1)))
|
||||
(i32.store
|
||||
(i32.const 556)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 556))
|
||||
(i32.const 2)))
|
||||
(call $e.instr_F4)
|
||||
(i32.store
|
||||
(i32.const 664)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 664))
|
||||
(i32.const 2)))
|
||||
(return))
|
||||
(unreachable))))
|
10
tests/expect/tests/while-do.asm
Normal file
10
tests/expect/tests/while-do.asm
Normal file
|
@ -0,0 +1,10 @@
|
|||
BITS 32
|
||||
|
||||
start:
|
||||
cmp eax, 10
|
||||
jz end
|
||||
inc ebx
|
||||
jmp start
|
||||
|
||||
end:
|
||||
hlt
|
116
tests/expect/tests/while-do.wast
Normal file
116
tests/expect/tests/while-do.wast
Normal file
|
@ -0,0 +1,116 @@
|
|||
(module
|
||||
(type $t0 (func))
|
||||
(type $t1 (func (param i32)))
|
||||
(type $t2 (func (param i32 i32)))
|
||||
(type $t3 (func (param i32 i32 i32)))
|
||||
(type $t4 (func (result i32)))
|
||||
(type $t5 (func (param i32) (result i32)))
|
||||
(type $t6 (func (param i32 i32) (result i32)))
|
||||
(import "e" "get_seg" (func $e.get_seg (type $t5)))
|
||||
(import "e" "instr32_83_7_reg" (func $e.instr32_83_7_reg (type $t2)))
|
||||
(import "e" "test_z" (func $e.test_z (type $t4)))
|
||||
(import "e" "instr32_43" (func $e.instr32_43 (type $t0)))
|
||||
(import "e" "instr_EB" (func $e.instr_EB (type $t1)))
|
||||
(import "e" "instr_F4" (func $e.instr_F4 (type $t0)))
|
||||
(import "e" "m" (memory $e.m 256))
|
||||
(func $f (export "f") (type $t0)
|
||||
(local $l0 i32) (local $l1 i32)
|
||||
(set_local $l0
|
||||
(i32.const 0))
|
||||
(set_local $l1
|
||||
(i32.const 10000))
|
||||
(loop $L0
|
||||
(set_local $l1
|
||||
(i32.add
|
||||
(get_local $l1)
|
||||
(i32.const -1)))
|
||||
(if $I1
|
||||
(i32.eqz
|
||||
(get_local $l1))
|
||||
(then
|
||||
(return)))
|
||||
(block $B2
|
||||
(block $B3
|
||||
(block $B4
|
||||
(block $B5
|
||||
(br_table $B5 $B4 $B3 $B2
|
||||
(get_local $l0)))
|
||||
(i32.store
|
||||
(i32.const 560)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 556))
|
||||
(i32.const 3)))
|
||||
(i32.store
|
||||
(i32.const 556)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 556))
|
||||
(i32.const 5)))
|
||||
(call $e.instr32_83_7_reg
|
||||
(i32.const 0)
|
||||
(i32.const 10))
|
||||
(i32.store
|
||||
(i32.const 664)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 664))
|
||||
(i32.const 2)))
|
||||
(if $I6
|
||||
(call $e.test_z)
|
||||
(then
|
||||
(i32.store
|
||||
(i32.const 556)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 556))
|
||||
(i32.const 3)))
|
||||
(set_local $l0
|
||||
(i32.const 2)))
|
||||
(else
|
||||
(set_local $l0
|
||||
(i32.const 1))))
|
||||
(br $L0))
|
||||
(i32.store
|
||||
(i32.const 560)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 556))
|
||||
(i32.const 1)))
|
||||
(i32.store
|
||||
(i32.const 556)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 556))
|
||||
(i32.const 3)))
|
||||
(call $e.instr32_43)
|
||||
(call $e.instr_EB
|
||||
(i32.const -8))
|
||||
(i32.store
|
||||
(i32.const 664)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 664))
|
||||
(i32.const 2)))
|
||||
(set_local $l0
|
||||
(i32.const 0))
|
||||
(br $L0))
|
||||
(i32.store
|
||||
(i32.const 560)
|
||||
(i32.load
|
||||
(i32.const 556)))
|
||||
(i32.store
|
||||
(i32.const 556)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 556))
|
||||
(i32.const 1)))
|
||||
(call $e.instr_F4)
|
||||
(i32.store
|
||||
(i32.const 664)
|
||||
(i32.add
|
||||
(i32.load
|
||||
(i32.const 664))
|
||||
(i32.const 1)))
|
||||
(return))
|
||||
(unreachable))))
|
Loading…
Reference in a new issue