Commit 29acb575 by Eric Holk

Subzero - WASM: Codegen fixes, better test infrastructure

Fixes several bugs in code generation, including handling of booleans, comparisons and shifts. The tests that get through code generation now run successfully (except for the tests that are known to fail on https://wasm-stat.us/). This change also includes improvements to the test infrastructure. The wasm test runner has a list of expected failures to skip. The tests now run in parallel, which significantly cuts down the time to run the whole test suite. Finally, there are some minor improvements to the WASM runtime, including an implementation of syscall20, i.e. getpid(). BUG= https://bugs.chromium.org/p/nativeclient/issues/detail?id=4369 R=kschimpf@google.com, stichnot@chromium.org Review URL: https://codereview.chromium.org/1900213002 .
parent cd261e91
...@@ -4,8 +4,9 @@ ...@@ -4,8 +4,9 @@
# that should be removed. # that should be removed.
./wasm-install/bin/emscripten/emcc "$1" -s BINARYEN=1 \ ./wasm-install/bin/emscripten/emcc "$1" -s BINARYEN=1 \
-s 'BINARYEN_METHOD="native-wasm"' -O2 \ -s 'BINARYEN_METHOD="native-wasm"' \
--em-config wasm-install/emscripten_config_vanilla && \ --em-config wasm-install/emscripten_config_vanilla && \
./wasm-install/bin/sexpr-wasm a.out.wast -o a.out.wasm && \ ./wasm-install/bin/sexpr-wasm a.out.wast -o a.out.wasm && \
./pnacl-sz a.out.wasm -o a.out.o -filetype=obj -O2 && \ ./pnacl-sz a.out.wasm -o a.out.o -filetype=obj -O2 && \
clang -m32 a.out.o runtime/wasm-runtime.c -g clang -m32 a.out.o ./runtime/szrt.c \
./runtime/wasm-runtime.cpp -lm -g
...@@ -9,45 +9,131 @@ ...@@ -9,45 +9,131 @@
# #
#===-----------------------------------------------------------------------===// #===-----------------------------------------------------------------------===//
from __future__ import print_function
import argparse
import glob import glob
import multiprocessing
import os import os
import Queue
import shutil import shutil
import StringIO
import sys import sys
import threading
IGNORED_TESTS = [ IGNORED_TESTS = set([
'loop-2f.c.wasm', # mmap not in MVP 'loop-2f.c.wasm', # mmap not in MVP
'loop-2g.c.wasm', # mmap not in MVP 'loop-2g.c.wasm', # mmap not in MVP
'960521-1.c.wasm', # sbrk not in MVP '960521-1.c.wasm', # sbrk
'ipa-sra-2.c.wasm', # sbrk
'pr36765.c.wasm', # __builtin_malloc not allowed 'pr41463.c.wasm', # sbrk
'20051113-1.c.wasm', # sbrk
'pr24716.c.wasm', # infinite loop '990628-1.c.wasm', # sbrk
'vla-dealloc-1.c.wasm', # infinite loop 'pr41395-2.c.wasm', # sbrk
'20040811-1.c.wasm', # infinite loop 'pr42614.c.wasm', # sbrk
'961125-1.c.wasm', # infinite loop 'pr41395-1.c.wasm', # sbrk
'980506-1.c.wasm', # infinite loop '920810-1.c.wasm', # sbrk
'20070824-1.c.wasm', # infinite loop '20000914-1.c.wasm', # sbrk
'20140212-1.c.wasm', # infinite loop 'pr15262-1.c.wasm', # sbrk
'pr59014.c.wasm', # infinite loop '941014-2.c.wasm', # sbrk
'pr58277-2.c.wasm', # infinite loop 'va-arg-21.c.wasm', # sbrk
'pr43560.c.wasm', # infinite loop '20020406-1.c.wasm', # sbrk
'20000818-1.c.wasm', # infinite loop
'20010409-1.c.wasm', # infinite loop # waterfall known failures
'loop-7.c.wasm', # infinite loop '20010122-1.c.wasm',
'pr34415.c.wasm', # infinite loop '20031003-1.c.wasm',
'20011126-2.c.wasm', # infinite loop '20071018-1.c.wasm',
'postmod-1.c.wasm', # infinite loop '20071120-1.c.wasm',
'pr17133.c.wasm', # infinite loop '20071220-1.c.wasm',
'20021024-1.c.wasm', # infinite loop '20071220-2.c.wasm',
'pr15296.c.wasm', # infinite loop '20101011-1.c.wasm',
'990524-1.c.wasm', # infinite loop 'alloca-1.c.wasm',
'loop-12.c.wasm', # infinite loop 'bitfld-3.c.wasm',
'961125-1.c.wasm', # infinite loop 'bitfld-5.c.wasm',
] 'builtin-bitops-1.c.wasm',
'conversion.c.wasm',
'eeprof-1.c.wasm',
'frame-address.c.wasm',
'pr17377.c.wasm',
'pr32244-1.c.wasm',
'pr34971.c.wasm',
'pr36765.c.wasm',
'pr39228.c.wasm',
'pr43008.c.wasm',
'pr47237.c.wasm',
'pr60960.c.wasm',
'va-arg-pack-1.c.wasm',
'20000717-5.c.wasm', # abort() (also works without emcc)
'20001203-2.c.wasm', # assert fail (works without emcc)
'20040811-1.c.wasm', # OOB trap
'20070824-1.c.wasm', # abort() (also works without emcc)
'arith-rand-ll.c.wasm', # abort() (works without emcc)
'arith-rand.c.wasm', # abort() (works without emcc)
'pr23135.c.wasm', # OOB trap (works without emcc)
'pr34415.c.wasm', # (empty output?)
'pr36339.c.wasm', # abort() (works without emcc)
'pr38048-2.c.wasm', # abort() (works without emcc)
'pr42691.c.wasm', # abort() (works without emcc)
'pr43220.c.wasm', # OOB trap (works without emcc)
'pr43269.c.wasm', # abort() (works without emcc)
'vla-dealloc-1.c.wasm', # OOB trap (works without emcc)
'20051012-1.c.wasm', # error reading binary
'921208-2.c.wasm', # error reading binary
'920501-1.c.wasm', # error reading binary
'call-trap-1.c.wasm', # error reading binary
'pr44942.c.wasm', # error reading binary
'920625-1.c.wasm', # abort() (also fails without emcc)
'931004-10.c.wasm', # abort() (also fails without emcc)
'931004-12.c.wasm', # abort() (also fails without emcc)
'931004-14.c.wasm', # abort() (also fails without emcc)
'931004-6.c.wasm', # abort() (also fails without emcc)
'pr38051.c.wasm', # (empty output?) (fails without emcc)
'pr38151.c.wasm', # abort() (fails without emcc)
'pr44575.c.wasm', # abort() (fails without emcc)
'strct-stdarg-1.c.wasm', # abort() (fails without emcc)
'strct-varg-1.c.wasm', # abort() (fails without emcc)
'va-arg-22.c.wasm', # abort() (fails without emcc)
'stdarg-3.c.wasm', # abort() (fails without emcc)
'pr56982.c.wasm', # missing setjmp (wasm.js check did not catch)
'20010605-2.c.wasm', # missing __netf2
'20020413-1.c.wasm', # missing __lttf2
'20030914-1.c.wasm', # missing __floatsitf
'20040709-1.c.wasm', # missing __netf2
'20040709-2.c.wasm', # missing __netf2
'20050121-1.c.wasm', # missing __floatsitf
'20080502-1.c.wasm', # missing __eqtf2
'920501-8.c.wasm', # missing __extenddftf2
'930513-1.c.wasm', # missing __extenddftf2
'930622-2.c.wasm', # missing __floatditf
'960215-1.c.wasm', # missing __addtf3
'960405-1.c.wasm', # missing __eqtf2
'960513-1.c.wasm', # missing __subtf3
'align-2.c.wasm', # missing __eqtf2
'complex-6.c.wasm', # missing __subtf3
'complex-7.c.wasm', # missing __netf2
'pr49218.c.wasm', # missing __fixsfti
'pr54471.c.wasm', # missing __multi3
'regstack-1.c.wasm', # missing __addtf3
'stdarg-1.c.wasm', # missing __netf2
'stdarg-2.c.wasm', # missing __floatsitf
'va-arg-5.c.wasm', # missing __eqtf2
'va-arg-6.c.wasm', # missing __eqtf2
'struct-ret-1.c.wasm', # missing __extenddftf2
])
parser = argparse.ArgumentParser()
parser.add_argument('-v', '--verbose', action='store_true')
parser.add_argument('--translate-only', action='store_true')
parser.add_argument('tests', nargs='*')
args = parser.parse_args()
OUT_DIR = "./build/wasm-torture" OUT_DIR = "./build/wasm-torture"
results_lock = threading.Lock()
compile_count = 0 compile_count = 0
compile_failures = [] compile_failures = []
...@@ -55,13 +141,17 @@ run_count = 0 ...@@ -55,13 +141,17 @@ run_count = 0
run_failures = [] run_failures = []
def run_test(test_file, verbose=False): def run_test(test_file, verbose=False):
global args
global compile_count global compile_count
global compile_failures global compile_failures
global results_lock
global run_count global run_count
global run_failures global run_failures
global OUT_DIR global OUT_DIR
global IGNORED_TESTS global IGNORED_TESTS
run_test = not args.translate_only
test_name = os.path.basename(test_file) test_name = os.path.basename(test_file)
obj_file = os.path.join(OUT_DIR, test_name + ".o") obj_file = os.path.join(OUT_DIR, test_name + ".o")
exe_file = os.path.join(OUT_DIR, test_name + ".exe") exe_file = os.path.join(OUT_DIR, test_name + ".exe")
...@@ -77,33 +167,42 @@ def run_test(test_file, verbose=False): ...@@ -77,33 +167,42 @@ def run_test(test_file, verbose=False):
if not verbose: if not verbose:
cmd += " &> /dev/null" cmd += " &> /dev/null"
sys.stdout.write(test_file + " ..."); out = StringIO.StringIO()
out.write(test_file + " ...");
status = os.system(cmd); status = os.system(cmd);
if status != 0: if status != 0:
print('\033[1;31m[compile fail]\033[1;m') print('\033[1;31m[compile fail]\033[1;m', file=out)
with results_lock:
compile_failures.append(test_file) compile_failures.append(test_file)
else: else:
compile_count += 1 compile_count += 1
# Try to link and run the program. # Try to link and run the program.
cmd = "clang -g -m32 {} -o {} ./runtime/wasm-runtime.c".format(obj_file, cmd = "clang -g -m32 {} -o {} " + \
exe_file) "./runtime/szrt.c ./runtime/wasm-runtime.cpp -lm"
if os.system(cmd) == 0: cmd = cmd.format(obj_file, exe_file)
if os.system(exe_file) == 0:
if not run_test or os.system(cmd) == 0:
if not run_test or os.system(exe_file) == 0:
with results_lock:
run_count += 1 run_count += 1
print('\033[1;32m[ok]\033[1;m') print('\033[1;32m[ok]\033[1;m', file=out)
else: else:
with results_lock:
run_failures.append(test_file) run_failures.append(test_file)
print('\033[1;33m[run fail]\033[1;m') print('\033[1;33m[run fail]\033[1;m', file=out)
else: else:
with results_lock:
run_failures.append(test_file) run_failures.append(test_file)
print('\033[1;33m[run fail]\033[1;m') print('\033[1;33m[run fail]\033[1;m', file=out)
sys.stdout.write(out.getvalue())
verbose = False verbose = args.verbose
if len(sys.argv) > 1: if len(args.tests) > 0:
test_files = sys.argv[1:] test_files = args.tests
verbose = True
else: else:
test_files = glob.glob("./emwasm-torture-out/*.wasm") test_files = glob.glob("./emwasm-torture-out/*.wasm")
...@@ -111,18 +210,32 @@ if os.path.exists(OUT_DIR): ...@@ -111,18 +210,32 @@ if os.path.exists(OUT_DIR):
shutil.rmtree(OUT_DIR) shutil.rmtree(OUT_DIR)
os.mkdir(OUT_DIR) os.mkdir(OUT_DIR)
tasks = Queue.Queue()
def worker():
while True:
run_test(tasks.get(), verbose)
tasks.task_done()
for i in range(multiprocessing.cpu_count()):
t = threading.Thread(target=worker)
t.daemon = True
t.start()
for test_file in test_files: for test_file in test_files:
run_test(test_file, verbose) tasks.put(test_file)
tasks.join()
if len(compile_failures) > 0: if len(compile_failures) > 0:
print print()
print("Compilation failures:") print("Compilation failures:")
print("=====================\n") print("=====================\n")
for f in compile_failures: for f in compile_failures:
print(" \033[1;31m" + f + "\033[1;m") print(" \033[1;31m" + f + "\033[1;m")
if len(run_failures) > 0: if len(run_failures) > 0:
print print()
print("Run failures:") print("Run failures:")
print("=============\n") print("=============\n")
for f in run_failures: for f in run_failures:
......
//===- subzero/runtime/wasm-runtime.c - Subzero WASM runtime source -------===// //===- subzero/runtime/wasm-runtime.cpp - Subzero WASM runtime source -----===//
// //
// The Subzero Code Generator // The Subzero Code Generator
// //
...@@ -12,8 +12,19 @@ ...@@ -12,8 +12,19 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include <cmath>
namespace env {
double floor(double X) { return std::floor(X); }
float floor(float X) { return std::floor(X); }
}
// TODO (eholk): move the C parts outside and use C++ name mangling.
extern "C" {
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <math.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
...@@ -30,6 +41,9 @@ void env$$abort() { ...@@ -30,6 +41,9 @@ void env$$abort() {
void env$$_abort() { env$$abort(); } void env$$_abort() { env$$abort(); }
double env$$floor_f(float X) { return env::floor(X); }
double env$$floor_d(double X) { return env::floor(X); }
void env$$exit(int Status) { exit(Status); } void env$$exit(int Status) { exit(Status); }
void env$$_exit(int Status) { env$$exit(Status); } void env$$_exit(int Status) { env$$exit(Status); }
...@@ -44,12 +58,13 @@ UNIMPLEMENTED(setjmp) ...@@ -44,12 +58,13 @@ UNIMPLEMENTED(setjmp)
UNIMPLEMENTED(longjmp) UNIMPLEMENTED(longjmp)
UNIMPLEMENTED(__assert_fail) UNIMPLEMENTED(__assert_fail)
UNIMPLEMENTED(__builtin_malloc) UNIMPLEMENTED(__builtin_malloc)
UNIMPLEMENTED(__builtin_isinff)
UNIMPLEMENTED(__builtin_isinfl)
UNIMPLEMENTED(__builtin_apply) UNIMPLEMENTED(__builtin_apply)
UNIMPLEMENTED(__builtin_apply_args) UNIMPLEMENTED(__builtin_apply_args)
UNIMPLEMENTED(pthread_cleanup_push) UNIMPLEMENTED(pthread_cleanup_push)
UNIMPLEMENTED(pthread_cleanup_pop) UNIMPLEMENTED(pthread_cleanup_pop)
UNIMPLEMENTED(pthread_self) UNIMPLEMENTED(pthread_self)
UNIMPLEMENTED(abs)
UNIMPLEMENTED(__floatditf) UNIMPLEMENTED(__floatditf)
UNIMPLEMENTED(__floatsitf) UNIMPLEMENTED(__floatsitf)
UNIMPLEMENTED(__fixtfdi) UNIMPLEMENTED(__fixtfdi)
...@@ -66,14 +81,17 @@ UNIMPLEMENTED(__multf3) ...@@ -66,14 +81,17 @@ UNIMPLEMENTED(__multf3)
UNIMPLEMENTED(__multi3) UNIMPLEMENTED(__multi3)
UNIMPLEMENTED(__lock) UNIMPLEMENTED(__lock)
UNIMPLEMENTED(__unlock) UNIMPLEMENTED(__unlock)
UNIMPLEMENTED(__syscall6) UNIMPLEMENTED(__syscall6) // sys_close
UNIMPLEMENTED(__syscall20) UNIMPLEMENTED(__syscall140) // sys_llseek
UNIMPLEMENTED(__syscall140) UNIMPLEMENTED(__syscall192) // sys_mmap?
UNIMPLEMENTED(__syscall192) UNIMPLEMENTED(__unordtf2)
UNIMPLEMENTED(__fixunstfsi)
UNIMPLEMENTED(__floatunsitf)
UNIMPLEMENTED(__extenddftf2)
void *wasmPtr(int Index) { void *wasmPtr(int Index) {
// TODO (eholk): get the mask from the WASM file. // TODO (eholk): get the mask from the WASM file.
const int MASK = 0x3fffff; const int MASK = 0xffffff;
Index &= MASK; Index &= MASK;
return WASM_MEMORY + Index; return WASM_MEMORY + Index;
...@@ -86,6 +104,10 @@ extern int __szwasm_main(int, const char **); ...@@ -86,6 +104,10 @@ extern int __szwasm_main(int, const char **);
int main(int argc, const char **argv) { return __szwasm_main(argc, argv); } int main(int argc, const char **argv) { return __szwasm_main(argc, argv); }
int env$$abs(int a) { return abs(a); }
double env$$pow(double x, double y) { return pow(x, y); }
/// sys_write /// sys_write
int env$$__syscall4(int Which, int VarArgs) { int env$$__syscall4(int Which, int VarArgs) {
int Fd = WASM_DEREF(int, VarArgs + 0 * sizeof(int)); int Fd = WASM_DEREF(int, VarArgs + 0 * sizeof(int));
...@@ -107,6 +129,14 @@ int env$$__syscall5(int Which, int VarArgs) { ...@@ -107,6 +129,14 @@ int env$$__syscall5(int Which, int VarArgs) {
return open(Path, Flags, Mode); return open(Path, Flags, Mode);
} }
/// sys_getpid
int env$$__syscall20(int Which, int VarArgs) {
(void)Which;
(void)VarArgs;
return getpid();
}
/// sys_ioctl /// sys_ioctl
int env$$__syscall54(int A, int B) { int env$$__syscall54(int A, int B) {
int Fd = WASM_DEREF(int, B + 0 * sizeof(int)); int Fd = WASM_DEREF(int, B + 0 * sizeof(int));
...@@ -116,32 +146,26 @@ int env$$__syscall54(int A, int B) { ...@@ -116,32 +146,26 @@ int env$$__syscall54(int A, int B) {
return -ENOTTY; return -ENOTTY;
} }
/// sys_write
int env$$__syscall146(int Which, int VarArgs) { int env$$__syscall146(int Which, int VarArgs) {
fprintf(stderr, "syscall146\n");
int Fd = WASM_DEREF(int, VarArgs); int Fd = WASM_DEREF(int, VarArgs);
int Iov = WASM_DEREF(int, VarArgs + sizeof(int)); int Iov = WASM_DEREF(int, VarArgs + sizeof(int));
int Iovcnt = WASM_DEREF(int, VarArgs + 2 * sizeof(int)); int Iovcnt = WASM_DEREF(int, VarArgs + 2 * sizeof(int));
fprintf(stderr, " Fd=%d, Iov=%d (%p), Iovcnt=%d\n", Fd, Iov, wasmPtr(Iov),
Iovcnt);
int Count = 0; int Count = 0;
for (int I = 0; I < Iovcnt; ++I) { for (int I = 0; I < Iovcnt; ++I) {
void *Ptr = WASM_REF(void, WASM_DEREF(int, Iov + I * 8)); void *Ptr = WASM_REF(void, WASM_DEREF(int, Iov + I * 8));
int Length = WASM_DEREF(int, Iov + I * 8 + 4); int Length = WASM_DEREF(int, Iov + I * 8 + 4);
fprintf(stderr, " [%d] write(%d, %p, %d) = ", I, Fd, Ptr, Length);
int Curr = write(Fd, Ptr, Length); int Curr = write(Fd, Ptr, Length);
fprintf(stderr, "%d\n", Curr);
if (Curr < 0) { if (Curr < 0) {
return -1; return -1;
} }
Count += Curr; Count += Curr;
} }
fprintf(stderr, " Count = %d\n", Count);
return Count; return Count;
} }
} // end of extern "C"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment