summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml43
-rw-r--r--CMakeLists.txt1
-rwxr-xr-xbuild.sh2
-rwxr-xr-xcheck.py11
-rw-r--r--src/asm2wasm.h12
-rw-r--r--src/emscripten-optimizer/optimizer-shared.cpp21
-rw-r--r--src/emscripten-optimizer/optimizer.h4
-rw-r--r--src/emscripten-optimizer/parser.h18
-rw-r--r--src/emscripten-optimizer/simple_ast.h29
-rw-r--r--src/s2wasm.h86
-rw-r--r--src/support/safe_integer.cpp75
-rw-r--r--src/support/safe_integer.h34
-rw-r--r--src/wasm-binary.h86
-rw-r--r--src/wasm.h5
-rw-r--r--src/wasm2asm.h4
-rw-r--r--test/dot_s/asm_const.s2
-rw-r--r--test/dot_s/basics.s2
-rw-r--r--test/dot_s/exit.s2
-rw-r--r--test/dot_s/memops.s4
-rw-r--r--test/emcc_hello_world.2asm.js2
-rw-r--r--test/emcc_hello_world.fromasm2
-rw-r--r--test/emcc_hello_world.wast2
-rw-r--r--test/llvm_autogenerated/call.s20
-rw-r--r--test/llvm_autogenerated/cfg-stackify.s14
-rw-r--r--test/llvm_autogenerated/f32.s2
-rw-r--r--test/llvm_autogenerated/f64.s2
-rw-r--r--test/llvm_autogenerated/frem.s4
-rw-r--r--test/llvm_autogenerated/global.s14
-rw-r--r--test/llvm_autogenerated/global.wast2
-rw-r--r--test/llvm_autogenerated/legalize.s128
-rw-r--r--test/llvm_autogenerated/offset-folding.s2
-rw-r--r--test/llvm_autogenerated/signext-zeroext.s4
-rw-r--r--test/llvm_autogenerated/store-results.s2
-rw-r--r--test/llvm_autogenerated/switch.s24
-rw-r--r--test/llvm_autogenerated/unreachable.s2
-rw-r--r--test/llvm_autogenerated/unused-argument.s2
-rw-r--r--test/llvm_autogenerated/userstack.s25
-rw-r--r--test/llvm_autogenerated/userstack.wast63
-rw-r--r--test/llvm_autogenerated/varargs.s2
-rw-r--r--test/passes/O.txt2
-rw-r--r--ubsan.blacklist3
41 files changed, 539 insertions, 225 deletions
diff --git a/.travis.yml b/.travis.yml
index 02b7efd86..861e1407d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,24 +2,41 @@ sudo: false
language: cpp
matrix:
include:
- - addons: &gcc5
+
+ - env: COMPILER_VERSION=3.6
+ compiler: clang
+ addons: &clang36
apt:
- sources: ['ubuntu-toolchain-r-test']
- packages: ['cmake', 'g++-5']
+ sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.6']
+ packages: ['cmake', 'clang-3.6']
+
+ - env: COMPILER_VERSION=3.6 COMPILER_FLAGS="-fsanitize=undefined -fsanitize-blacklist=`pwd`/ubsan.blacklist"
+ compiler: clang
+ addons: *clang36
+
+# - env: COMPILER_VERSION=3.6 COMPILER_FLAGS="-fsanitize=address"
+# compiler: clang
+# addons: *clang36
+#
+# - env: COMPILER_VERSION=3.6 COMPILER_FLAGS="-fsanitize=thread"
+# compiler: clang
+# addons: *clang36
+
+ - env: COMPILER_VERSION=5
compiler: gcc
- env: COMPILER_VERSION=5
- - addons: &clang37
+ addons: &gcc5
apt:
- sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.7']
- packages: ['cmake', 'clang-3.7']
- compiler: clang
- env: COMPILER_VERSION=3.7
-before_script:
- - git submodule update --init # Initialize the submodules recorded in the index.
+ sources: ['ubuntu-toolchain-r-test']
+ packages: ['cmake', 'g++-5']
+
+before_install:
- export CC="${CC}-${COMPILER_VERSION}"
- export CXX="${CXX}-${COMPILER_VERSION}"
- - $CC --version
+
script:
- - cmake .
+ - cmake . -DCMAKE_C_FLAGS="$COMPILER_FLAGS" -DCMAKE_CXX_FLAGS="$COMPILER_FLAGS"
- make -j2
- ./check.py
+
+notifications:
+ email: false
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3771f7090..bcd9eb917 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -27,6 +27,7 @@ SET(support_SOURCES
src/support/colors.cpp
src/support/command-line.cpp
src/support/file.cpp
+ src/support/safe_integer.cpp
)
ADD_LIBRARY(support STATIC ${support_SOURCES})
diff --git a/build.sh b/build.sh
index 894875cd0..bcf8bc399 100755
--- a/build.sh
+++ b/build.sh
@@ -11,6 +11,6 @@ make -j
#echo "building s2wasm"
#g++ -O2 -std=c++11 src/s2wasm-main.cpp src/support/command-line.cpp src/support/file.cpp src/support/colors.cpp -Isrc/ -o bin/s2wasm
echo "building interpreter/js"
-em++ -std=c++11 src/wasm-js.cpp src/pass.cpp src/passes/MergeBlocks.cpp src/passes/RemoveUnusedBrs.cpp src/passes/RemoveUnusedNames.cpp src/passes/SimplifyLocals.cpp src/emscripten-optimizer/parser.cpp src/emscripten-optimizer/simple_ast.cpp src/emscripten-optimizer/optimizer-shared.cpp src/support/colors.cpp -Isrc/ -o bin/wasm.js -s MODULARIZE=1 -s 'EXPORT_NAME="WasmJS"' --memory-init-file 0 -Oz -s ALLOW_MEMORY_GROWTH=1 -profiling -s DEMANGLE_SUPPORT=1 #-DWASM_JS_DEBUG -DWASM_INTERPRETER_DEBUG=2
+em++ -std=c++11 src/wasm-js.cpp src/pass.cpp src/passes/MergeBlocks.cpp src/passes/RemoveUnusedBrs.cpp src/passes/RemoveUnusedNames.cpp src/passes/SimplifyLocals.cpp src/emscripten-optimizer/parser.cpp src/emscripten-optimizer/simple_ast.cpp src/emscripten-optimizer/optimizer-shared.cpp src/support/colors.cpp src/support/safe_integer.cpp -Isrc/ -o bin/wasm.js -s MODULARIZE=1 -s 'EXPORT_NAME="WasmJS"' --memory-init-file 0 -Oz -s ALLOW_MEMORY_GROWTH=1 -profiling -s DEMANGLE_SUPPORT=1 #-DWASM_JS_DEBUG -DWASM_INTERPRETER_DEBUG=2
cat src/js/wasm.js-post.js >> bin/wasm.js
diff --git a/check.py b/check.py
index 1921c8b89..b8c136dfd 100755
--- a/check.py
+++ b/check.py
@@ -146,7 +146,9 @@ for t in tests:
if t.endswith('.wast') and not t.startswith('spec'):
print '..', t
t = os.path.join('test', t)
- actual, err = subprocess.Popen([os.path.join('bin', 'binaryen-shell'), t, '-print-before'], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
+ cmd = [os.path.join('bin', 'binaryen-shell'), t, '-print-before']
+ print ' ', ' '.join(cmd)
+ actual, err = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
assert err.replace('printing before:', '').strip() == '', 'bad err:' + err
actual = actual.replace('printing before:\n', '')
@@ -273,7 +275,12 @@ if unexpected_result_count:
print '\n[ checking example testcases... ]\n'
-subprocess.check_call([os.environ.get('CXX') or 'g++', '-std=c++11', os.path.join('test', 'example', 'find_div0s.cpp'), '-Isrc', '-g', '-lsupport', '-Llib/.'])
+cmd = [os.environ.get('CXX') or 'g++', '-std=c++11', os.path.join('test', 'example', 'find_div0s.cpp'), '-Isrc', '-g', '-lsupport', '-Llib/.']
+if os.environ.get('COMPILER_FLAGS'):
+ for f in os.environ.get('COMPILER_FLAGS').split(' '):
+ cmd.append(f)
+print ' '.join(cmd)
+subprocess.check_call(cmd)
actual = subprocess.Popen(['./a.out'], stdout=subprocess.PIPE).communicate()[0]
expected = open(os.path.join('test', 'example', 'find_div0s.txt')).read()
if actual != expected:
diff --git a/src/asm2wasm.h b/src/asm2wasm.h
index 11cb75b30..280624d9b 100644
--- a/src/asm2wasm.h
+++ b/src/asm2wasm.h
@@ -390,8 +390,9 @@ private:
}
if (ast[1] == MINUS && ast[2][0] == NUM) {
double num = -ast[2][1]->getNumber();
- assert(isInteger32(num));
- return Literal((int32_t)num);
+ if (isSInteger32(num)) return Literal((int32_t)num);
+ if (isUInteger32(num)) return Literal((uint32_t)num);
+ assert(false && "expected signed or unsigned int32");
}
if (ast[1] == PLUS && ast[2][0] == UNARY_PREFIX && ast[2][1] == MINUS && ast[2][2][0] == NUM) {
return Literal((double)-ast[2][2][1]->getNumber());
@@ -917,9 +918,12 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) {
} else if (what == NUM) {
auto ret = allocator.alloc<Const>();
double num = ast[1]->getNumber();
- if (isInteger32(num)) {
+ if (isSInteger32(num)) {
ret->value.type = WasmType::i32;
- ret->value.i32 = toInteger32(num);
+ ret->value.i32 = toSInteger32(num);
+ } else if (isUInteger32(num)) {
+ ret->value.type = WasmType::i32;
+ ret->value.i32 = toUInteger32(num);
} else {
ret->value.type = WasmType::f64;
ret->value.f64 = num;
diff --git a/src/emscripten-optimizer/optimizer-shared.cpp b/src/emscripten-optimizer/optimizer-shared.cpp
index 4466fb0e9..6831d81b0 100644
--- a/src/emscripten-optimizer/optimizer-shared.cpp
+++ b/src/emscripten-optimizer/optimizer-shared.cpp
@@ -14,7 +14,10 @@
* limitations under the License.
*/
+#include <limits>
+
#include "optimizer.h"
+#include "support/safe_integer.h"
using namespace cashew;
@@ -26,20 +29,6 @@ IString SIMD_INT8X16_CHECK("SIMD_Int8x16_check"),
SIMD_FLOAT32X4_CHECK("SIMD_Float32x4_check"),
SIMD_FLOAT64X2_CHECK("SIMD_Float64x2_check");
-bool isInteger(double x) {
- return fmod(x, 1) == 0;
-}
-
-bool isInteger32(double x) {
- return isInteger(x) && (x == (int32_t)x || x == (uint32_t)x);
-}
-
-int32_t toInteger32(double x) {
- if (x == (int32_t)x) return (int32_t)x;
- assert(x == (uint32_t)x);
- return (uint32_t)x;
-}
-
int parseInt(const char *str) {
int ret = *str - '0';
while (*(++str)) {
@@ -67,7 +56,7 @@ AsmType detectType(Ref node, AsmData *asmData, bool inVarDef, IString minifiedFr
switch (node[0]->getCString()[0]) {
case 'n': {
if (node[0] == NUM) {
- if (!isInteger(node[1]->getNumber())) return ASM_DOUBLE;
+ if (!wasm::isInteger(node[1]->getNumber())) return ASM_DOUBLE;
return ASM_INT;
} else if (node[0] == NAME) {
if (asmData) {
@@ -176,7 +165,7 @@ AsmSign detectSign(Ref node, IString minifiedFround) {
double value = node[1]->getNumber();
if (value < 0) return ASM_SIGNED;
if (value > uint32_t(-1) || fmod(value, 1) != 0) return ASM_NONSIGNED;
- if (value == int32_t(value)) return ASM_FLEXIBLE;
+ if (wasm::isSInteger32(value)) return ASM_FLEXIBLE;
return ASM_UNSIGNED;
} else if (type == NAME) {
return ASM_FLEXIBLE;
diff --git a/src/emscripten-optimizer/optimizer.h b/src/emscripten-optimizer/optimizer.h
index 451a9e286..684fc0164 100644
--- a/src/emscripten-optimizer/optimizer.h
+++ b/src/emscripten-optimizer/optimizer.h
@@ -116,10 +116,6 @@ struct AsmData {
}
};
-bool isInteger(double x);
-bool isInteger32(double x);
-int32_t toInteger32(double x);
-
extern cashew::IString ASM_FLOAT_ZERO;
extern cashew::IString SIMD_INT8X16_CHECK,
diff --git a/src/emscripten-optimizer/parser.h b/src/emscripten-optimizer/parser.h
index c805ca9f6..da3e6f5c7 100644
--- a/src/emscripten-optimizer/parser.h
+++ b/src/emscripten-optimizer/parser.h
@@ -22,13 +22,14 @@
#ifndef wasm_parser_h
#define wasm_parser_h
-#include <vector>
-#include <iostream>
#include <algorithm>
-
-#include <stdio.h>
+#include <cstdio>
+#include <iostream>
+#include <limits>
+#include <vector>
#include "istring.h"
+#include "support/safe_integer.h"
namespace cashew {
@@ -179,10 +180,6 @@ class Parser {
static bool hasChar(const char* list, char x) { while (*list) if (*list++ == x) return true; return false; }
- static bool is32Bit(double x) {
- return x == (int)x || x == (unsigned int)x;
- }
-
// An atomic fragment of something. Stops at a natural boundary.
enum FragType {
KEYWORD = 0,
@@ -249,7 +246,10 @@ class Parser {
// for valid asm.js input, the '.' should be enough, and for uglify
// in the emscripten optimizer pipeline, we use simple_ast where INT/DOUBLE
// is quite the same at this point anyhow
- type = (std::find(start, src, '.') == src && is32Bit(num)) ? INT : DOUBLE;
+ type = (std::find(start, src, '.') == src &&
+ (wasm::isSInteger32(num) || wasm::isUInteger32(num)))
+ ? INT
+ : DOUBLE;
assert(src > start);
} else if (hasChar(OPERATOR_INITS, *src)) {
switch (*src) {
diff --git a/src/emscripten-optimizer/simple_ast.h b/src/emscripten-optimizer/simple_ast.h
index 712845dea..73037815f 100644
--- a/src/emscripten-optimizer/simple_ast.h
+++ b/src/emscripten-optimizer/simple_ast.h
@@ -17,26 +17,25 @@
#ifndef wasm_simple_ast_h
#define wasm_simple_ast_h
-#include <assert.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-
-#include <vector>
-#include <ostream>
-#include <iostream>
+#include <algorithm>
+#include <cassert>
+#include <cmath>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <functional>
#include <iomanip>
+#include <iostream>
#include <limits>
-#include <functional>
-#include <algorithm>
+#include <ostream>
#include <set>
-#include <unordered_set>
#include <unordered_map>
+#include <unordered_set>
+#include <vector>
#include "parser.h"
-
#include "snprintf.h"
+#include "support/safe_integer.h"
#define err(str) fprintf(stderr, str "\n");
#define errv(str, ...) fprintf(stderr, str "\n", __VA_ARGS__);
@@ -870,8 +869,8 @@ struct JSPrinter {
} else {
// integer
assert(d >= 0);
- unsigned long long uu = (unsigned long long)d;
- if (uu == d) {
+ if (wasm::isUInteger64(d)) {
+ unsigned long long uu = wasm::toUInteger64(d);
bool asHex = e && !finalize;
snprintf(buffer, BUFFERSIZE-1, asHex ? "0x%llx" : "%llu", uu);
if (asHex) {
diff --git a/src/s2wasm.h b/src/s2wasm.h
index bd3f12e73..b99a71159 100644
--- a/src/s2wasm.h
+++ b/src/s2wasm.h
@@ -160,19 +160,36 @@ private:
}
int32_t getInt() {
- int32_t ret = 0;
+ const char* loc = s;
+ uint32_t value = 0;
bool neg = false;
- if (*s == '-') {
+ if (*loc == '-') {
neg = true;
- s++;
+ loc++;
}
- while (isdigit(*s)) {
- ret *= 10;
- ret += (*s - '0');
- s++;
+ while (isdigit(*loc)) {
+ uint32_t digit = *loc - '0';
+ if (value > std::numeric_limits<uint32_t>::max() / 10) {
+ abort_on("uint32_t overflow");
+ }
+ value *= 10;
+ if (value > std::numeric_limits<uint32_t>::max() - digit) {
+ abort_on("uint32_t overflow");
+ }
+ value += digit;
+ loc++;
}
- if (neg) ret = -ret;
- return ret;
+ if (neg) {
+ uint32_t positive_int_min =
+ (uint32_t) - (1 + std::numeric_limits<int32_t>::min()) + (uint32_t)1;
+ if (value > positive_int_min) {
+ abort_on("negative int32_t overflow");
+ }
+ s = loc;
+ return -value;
+ }
+ s = loc;
+ return value;
}
// gets a constant, which may be a relocation for later.
@@ -183,7 +200,7 @@ private:
return false;
} else {
// a global constant, we need to fix it up later
- Name name = getStrToSep();
+ Name name = cleanFunction(getStrToSep());
int offset = 0;
if (*s == '+') {
s++;
@@ -198,19 +215,36 @@ private:
}
int64_t getInt64() {
- int64_t ret = 0;
+ const char* loc = s;
+ uint64_t value = 0;
bool neg = false;
- if (*s == '-') {
+ if (*loc == '-') {
neg = true;
- s++;
+ loc++;
}
- while (isdigit(*s)) {
- ret *= 10;
- ret += (*s - '0');
- s++;
+ while (isdigit(*loc)) {
+ uint64_t digit = *loc - '0';
+ if (value > std::numeric_limits<uint64_t>::max() / 10) {
+ abort_on("uint64_t overflow");
+ }
+ value *= 10;
+ if (value > std::numeric_limits<uint64_t>::max() - digit) {
+ abort_on("uint64_t overflow");
+ }
+ value += digit;
+ loc++;
}
- if (neg) ret = -ret;
- return ret;
+ if (neg) {
+ uint64_t positive_int_min =
+ (uint64_t) - (1 + std::numeric_limits<int64_t>::min()) + (uint64_t)1;
+ if (value > positive_int_min) {
+ abort_on("negative int64_t overflow");
+ }
+ s = loc;
+ return -value;
+ }
+ s = loc;
+ return value;
}
Name getCommaSeparated() {
@@ -282,6 +316,16 @@ private:
abort_on("getType");
}
+ // The LLVM backend emits function names as name@FUNCTION. We can drop the @ and after it.
+ Name cleanFunction(Name name) {
+ if (!strchr(name.str, '@')) return name;
+ char *temp = strdup(name.str);
+ *strchr(temp, '@') = 0;
+ Name ret = cashew::IString(temp, false);
+ free(temp);
+ return ret;
+ }
+
// processors
void scan() {
@@ -543,7 +587,7 @@ private:
curr = specific;
} else {
assign = getAssign();
- Name target = getCommaSeparated();
+ Name target = cleanFunction(getCommaSeparated());
if (implementedFunctions.count(target) > 0) {
auto specific = allocator.alloc<Call>();
specific->target = target;
@@ -933,7 +977,7 @@ private:
} else if (match(".int64")) {
size_t size = raw->size();
raw->resize(size + 8);
- (*(int64_t*)(&(*raw)[size])) = getInt();
+ (*(int64_t*)(&(*raw)[size])) = getInt64();
zero = false;
} else {
break;
diff --git a/src/support/safe_integer.cpp b/src/support/safe_integer.cpp
new file mode 100644
index 000000000..dbe62ca52
--- /dev/null
+++ b/src/support/safe_integer.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2016 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cassert>
+#include <cmath>
+#include <limits>
+
+#include "support/safe_integer.h"
+
+using namespace wasm;
+
+bool wasm::isInteger(double x) { return fmod(x, 1) == 0; }
+
+bool wasm::isUInteger32(double x) {
+ return isInteger(x) && x >= 0 && x <= std::numeric_limits<uint32_t>::max();
+}
+
+bool wasm::isSInteger32(double x) {
+ return isInteger(x) && x >= std::numeric_limits<int32_t>::min() &&
+ x <= std::numeric_limits<int32_t>::max();
+}
+
+uint32_t wasm::toUInteger32(double x) {
+ assert(isUInteger32(x));
+ return x < std::numeric_limits<uint32_t>::max()
+ ? x
+ : std::numeric_limits<uint32_t>::max();
+}
+
+int32_t wasm::toSInteger32(double x) {
+ assert(isSInteger32(x));
+ return x > std::numeric_limits<int32_t>::min() &&
+ x < std::numeric_limits<int32_t>::max()
+ ? x
+ : (x < 0 ? std::numeric_limits<int32_t>::min()
+ : std::numeric_limits<int32_t>::max());
+}
+
+bool wasm::isUInteger64(double x) {
+ return isInteger(x) && x >= 0 && x <= std::numeric_limits<uint64_t>::max();
+}
+
+bool wasm::isSInteger64(double x) {
+ return isInteger(x) && x >= std::numeric_limits<int64_t>::min() &&
+ x <= std::numeric_limits<int64_t>::max();
+}
+
+uint64_t wasm::toUInteger64(double x) {
+ assert(isUInteger64(x));
+ return x < (double)std::numeric_limits<uint64_t>::max()
+ ? (uint64_t)x
+ : std::numeric_limits<uint64_t>::max();
+}
+
+int64_t wasm::toSInteger64(double x) {
+ assert(isSInteger64(x));
+ return x > (double)std::numeric_limits<int64_t>::min() &&
+ x < (double)std::numeric_limits<int64_t>::max()
+ ? (int64_t)x
+ : (x < 0 ? std::numeric_limits<int64_t>::min()
+ : std::numeric_limits<int64_t>::max());
+}
diff --git a/src/support/safe_integer.h b/src/support/safe_integer.h
new file mode 100644
index 000000000..f240644c8
--- /dev/null
+++ b/src/support/safe_integer.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2016 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef wasm_safe_integer_h
+#define wasm_safe_integer_h
+
+#include <cstdint>
+
+namespace wasm {
+bool isInteger(double x);
+bool isUInteger32(double x);
+bool isSInteger32(double x);
+uint32_t toUInteger32(double x);
+int32_t toSInteger32(double x);
+bool isUInteger64(double x);
+bool isSInteger64(double x);
+uint64_t toUInteger64(double x);
+int64_t toSInteger64(double x);
+} // namespace wasm
+
+#endif // wasm_safe_integer_h
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index 76a9b62be..d923b9ecb 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -30,13 +30,40 @@
namespace wasm {
struct LEB128 {
- int32_t value;
- LEB128(int32_t value) : value(value) {}
+ uint32_t value;
+
+ LEB128(uint32_t value) : value(value) {}
+
+ void write(std::vector<uint8_t>* out) {
+ uint32_t temp = value;
+ do {
+ uint8_t byte = value & 127;
+ temp >>= 7;
+ if (temp) {
+ byte = byte | 128;
+ }
+ out.push_back(byte);
+ } while (temp);
+ }
+
+ void read(std::function<uint8_t ()> get) {
+ value = 0;
+ uint32_t shift = 0;
+ while (1) {
+ uint8_t byte = get();
+ value |= ((byte & 127) << shift);
+ if (byte & 128) break;
+ shift += 7;
+ }
+ }
};
+//
// We mostly stream into a buffer as we create the binary format, however,
-// sometimes we need to backtrack and write to a location behind us.
-class BufferWithRandomAccess : public std::vector<unsigned char> {
+// sometimes we need to backtrack and write to a location behind us - wasm
+// is optimized for reading, not writing.
+//
+class BufferWithRandomAccess : public std::vector<uint8_t> {
public:
BufferWithRandomAccess& operator<<(int8_t x) {
push_back(x);
@@ -66,8 +93,7 @@ public:
return *this;
}
BufferWithRandomAccess& operator<<(LEB128 x) {
- // XXX TODO
- magic
+ x.write(this);
return *this;
}
@@ -285,6 +311,7 @@ public:
writeDataSegments();
writeFunctionTable();
writeEnd();
+ finishUp();
}
writeMemory() {
@@ -367,10 +394,10 @@ public:
}
o << getFunctionTypeIndex(type);
o << int8_t(FunctionEntry::Named |
- (FunctionEntry::Import * !!import) |
- (FunctionEntry::Locals * (function && function->locals.size() > 0) |
- (FunctionEntry::Export) * (wasm.exportsMap[name].count(name) > 0)));
- // TODO: name. how can we do an offset? into what section? and how do we know it now?
+ (FunctionEntry::Import * !!import) |
+ (FunctionEntry::Locals * (function && function->locals.size() > 0) |
+ (FunctionEntry::Export) * (wasm.exportsMap[name].count(name) > 0)));
+ emitString(Name.str);
if (function && function->locals.size() > 0) {
mapLocals(function);
o << uint16_t(numLocalsByType[i32])
@@ -389,10 +416,10 @@ public:
writeDataSegments() {
o << Section::DataSegments << LEB128(wasm.memory.segments.size());
for (auto& segment : wasm.memory.segments) {
- o << int32_t(segment.offset)
- << int32_t(XXX) // TODO: where/when do we emit this?
- << int32_t(segment.size)
- << int8_t(1); // load at program start
+ o << int32_t(segment.offset);
+ emitBuffer(segment.data, segment.size);
+ o << int32_t(segment.size);
+ o << int8_t(1); // load at program start
}
}
@@ -418,6 +445,37 @@ public:
o << Section::End;
}
+ // helpers
+
+ struct Buffer {
+ const char* data;
+ size_t size;
+ size_t pointerLocation;
+ Buffer(const char* data, size_t size, size_t pointerLocation) : data(data), size(size), pointerLocation(pointerLocation) {}
+ };
+
+ std::vector<Buffer> buffersToWrite;
+
+ void emitBuffer(const char* data, size_t size) {
+ assert(size > 0);
+ buffersToWrite.emplace_back(data, size, o.size());
+ o << uint32_t(0); // placeholder
+ }
+
+ void emitString(const char *str) {
+ emitBuffer(str, strlen(str) + 1);
+ }
+
+ void finishUp() {
+ // finish buffers
+ for (auto& buffer : buffersToWrite) {
+ o.writeAt(buffer.pointerLocation, (uint32_t)o.size());
+ for (size_t i = 0; i < buffer.size; i++) {
+ o << buffer.data[i];
+ }
+ }
+ }
+
// AST writing via visitors
std::vector<Name> breakStack;
diff --git a/src/wasm.h b/src/wasm.h
index b1b8d84d4..c4654580a 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -45,13 +45,14 @@
#define wasm_wasm_h
#include <cassert>
+#include <cmath>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <fstream>
#include <map>
-#include <vector>
#include <string>
+#include <vector>
#include "compiler-support.h"
#include "emscripten-optimizer/simple_ast.h"
@@ -200,7 +201,7 @@ struct Literal {
}
static void printDouble(std::ostream &o, double d) {
- if (d == 0 && 1/d < 0) {
+ if (d == 0 && std::signbit(d)) {
o << "-0";
return;
}
diff --git a/src/wasm2asm.h b/src/wasm2asm.h
index 53cb6df78..1a85bc177 100644
--- a/src/wasm2asm.h
+++ b/src/wasm2asm.h
@@ -22,6 +22,8 @@
#ifndef wasm_wasm2asm_h
#define wasm_wasm2asm_h
+#include <cmath>
+
#include "wasm.h"
#include "emscripten-optimizer/optimizer.h"
#include "mixed_arena.h"
@@ -914,7 +916,7 @@ Ref Wasm2AsmBuilder::processFunctionBody(Expression* curr, IString result) {
}
case f64: {
double d = curr->value.f64;
- if (d == 0 && 1/d < 0) { // negative zero
+ if (d == 0 && std::signbit(d)) { // negative zero
return ValueBuilder::makeUnary(PLUS, ValueBuilder::makeUnary(MINUS, ValueBuilder::makeDouble(0)));
}
return ValueBuilder::makeUnary(PLUS, ValueBuilder::makeDouble(curr->value.f64));
diff --git a/test/dot_s/asm_const.s b/test/dot_s/asm_const.s
index fc055579d..04c2c8630 100644
--- a/test/dot_s/asm_const.s
+++ b/test/dot_s/asm_const.s
@@ -6,7 +6,7 @@ main: # @main
.result i32
# BB#0:
i32.const $push0=, .str
- call emscripten_asm_const, $pop0
+ call emscripten_asm_const@FUNCTION, $pop0
i32.const $push1=, 0
return $pop1
.Lfunc_end0:
diff --git a/test/dot_s/basics.s b/test/dot_s/basics.s
index 1c6225738..a37678ff7 100644
--- a/test/dot_s/basics.s
+++ b/test/dot_s/basics.s
@@ -7,7 +7,7 @@ main: # @main
.result i32
# BB#0:
i32.const $push0=, .str
- call $discard=, puts, $pop0
+ call $discard=, puts@FUNCTION, $pop0
i32.const $push1=, 31
i32.shr_s $push2=, $0, $pop1
i32.const $push3=, 30
diff --git a/test/dot_s/exit.s b/test/dot_s/exit.s
index 12bf86bf3..2fad9277f 100644
--- a/test/dot_s/exit.s
+++ b/test/dot_s/exit.s
@@ -6,6 +6,6 @@ main:
.result i32
.local i32
i32.const $push0=, 0
- call exit, $pop0
+ call exit@FUNCTION, $pop0
.Lfunc_end0:
.size main, .Lfunc_end0-main
diff --git a/test/dot_s/memops.s b/test/dot_s/memops.s
index 893dc6b68..64c967a13 100644
--- a/test/dot_s/memops.s
+++ b/test/dot_s/memops.s
@@ -7,7 +7,7 @@ _Z6reporti: # @_Z6reporti
i32.const $push0=, 8
i32.store $discard=, 0($pop0), $0
i32.const $push1=, .str
- call emscripten_asm_const, $pop1
+ call emscripten_asm_const@FUNCTION, $pop1
return
.Lfunc_end0:
.size _Z6reporti, .Lfunc_end0-_Z6reporti
@@ -75,7 +75,7 @@ main: # @main
i32.ne $push16=, $0, $pop15
br_if $pop16, .LBB1_1
.LBB1_5:
- call _Z6reporti, $6
+ call _Z6reporti@FUNCTION, $6
i32.const $push17=, 0
i32.const $9=, 1048576
i32.add $12=, $12, $9
diff --git a/test/emcc_hello_world.2asm.js b/test/emcc_hello_world.2asm.js
index dbc002e3e..3dfeecd19 100644
--- a/test/emcc_hello_world.2asm.js
+++ b/test/emcc_hello_world.2asm.js
@@ -137,7 +137,7 @@ function asmFunc(global, env, buffer) {
block0 : {
$tobool1 = $x != 0.0;
if ($tobool1) block1 : {
- $mul = $x - 18446744073709551616.0;
+ $mul = $x - 18446744073709551615.0;
$call = +_frexp(+$mul, $e | 0);
$4 = HEAPU32[$e >> 2] | 0;
$sub = $4 + 4294967232 | 0;
diff --git a/test/emcc_hello_world.fromasm b/test/emcc_hello_world.fromasm
index 3b0331011..9dbe000df 100644
--- a/test/emcc_hello_world.fromasm
+++ b/test/emcc_hello_world.fromasm
@@ -430,7 +430,7 @@
(set_local $$mul
(f64.mul
(get_local $$x)
- (f64.const 18446744073709551616)
+ (f64.const 18446744073709551615)
)
)
(set_local $$call
diff --git a/test/emcc_hello_world.wast b/test/emcc_hello_world.wast
index bd0adc06f..01cd2f4c1 100644
--- a/test/emcc_hello_world.wast
+++ b/test/emcc_hello_world.wast
@@ -441,7 +441,7 @@
(set_local $$mul
(f64.mul
(get_local $$x)
- (f64.const 18446744073709551616)
+ (f64.const 18446744073709551615)
)
)
(set_local $$call
diff --git a/test/llvm_autogenerated/call.s b/test/llvm_autogenerated/call.s
index f406bbaaf..7081c43a8 100644
--- a/test/llvm_autogenerated/call.s
+++ b/test/llvm_autogenerated/call.s
@@ -4,7 +4,7 @@
.type call_i32_nullary,@function
call_i32_nullary:
.result i32
- i32.call $push0=, i32_nullary
+ i32.call $push0=, i32_nullary@FUNCTION
return $pop0
.Lfunc_end0:
.size call_i32_nullary, .Lfunc_end0-call_i32_nullary
@@ -13,7 +13,7 @@ call_i32_nullary:
.type call_i64_nullary,@function
call_i64_nullary:
.result i64
- i64.call $push0=, i64_nullary
+ i64.call $push0=, i64_nullary@FUNCTION
return $pop0
.Lfunc_end1:
.size call_i64_nullary, .Lfunc_end1-call_i64_nullary
@@ -22,7 +22,7 @@ call_i64_nullary:
.type call_float_nullary,@function
call_float_nullary:
.result f32
- f32.call $push0=, float_nullary
+ f32.call $push0=, float_nullary@FUNCTION
return $pop0
.Lfunc_end2:
.size call_float_nullary, .Lfunc_end2-call_float_nullary
@@ -31,7 +31,7 @@ call_float_nullary:
.type call_double_nullary,@function
call_double_nullary:
.result f64
- f64.call $push0=, double_nullary
+ f64.call $push0=, double_nullary@FUNCTION
return $pop0
.Lfunc_end3:
.size call_double_nullary, .Lfunc_end3-call_double_nullary
@@ -39,7 +39,7 @@ call_double_nullary:
.globl call_void_nullary
.type call_void_nullary,@function
call_void_nullary:
- call void_nullary
+ call void_nullary@FUNCTION
return
.Lfunc_end4:
.size call_void_nullary, .Lfunc_end4-call_void_nullary
@@ -49,7 +49,7 @@ call_void_nullary:
call_i32_unary:
.param i32
.result i32
- i32.call $push0=, i32_unary, $0
+ i32.call $push0=, i32_unary@FUNCTION, $0
return $pop0
.Lfunc_end5:
.size call_i32_unary, .Lfunc_end5-call_i32_unary
@@ -59,7 +59,7 @@ call_i32_unary:
call_i32_binary:
.param i32, i32
.result i32
- i32.call $push0=, i32_binary, $0, $1
+ i32.call $push0=, i32_binary@FUNCTION, $0, $1
return $pop0
.Lfunc_end6:
.size call_i32_binary, .Lfunc_end6-call_i32_binary
@@ -86,7 +86,7 @@ call_indirect_i32:
.globl tail_call_void_nullary
.type tail_call_void_nullary,@function
tail_call_void_nullary:
- call void_nullary
+ call void_nullary@FUNCTION
return
.Lfunc_end9:
.size tail_call_void_nullary, .Lfunc_end9-tail_call_void_nullary
@@ -94,7 +94,7 @@ tail_call_void_nullary:
.globl fastcc_tail_call_void_nullary
.type fastcc_tail_call_void_nullary,@function
fastcc_tail_call_void_nullary:
- call void_nullary
+ call void_nullary@FUNCTION
return
.Lfunc_end10:
.size fastcc_tail_call_void_nullary, .Lfunc_end10-fastcc_tail_call_void_nullary
@@ -102,7 +102,7 @@ fastcc_tail_call_void_nullary:
.globl coldcc_tail_call_void_nullary
.type coldcc_tail_call_void_nullary,@function
coldcc_tail_call_void_nullary:
- call void_nullary
+ call void_nullary@FUNCTION
return
.Lfunc_end11:
.size coldcc_tail_call_void_nullary, .Lfunc_end11-coldcc_tail_call_void_nullary
diff --git a/test/llvm_autogenerated/cfg-stackify.s b/test/llvm_autogenerated/cfg-stackify.s
index eec847fa1..121b7d55a 100644
--- a/test/llvm_autogenerated/cfg-stackify.s
+++ b/test/llvm_autogenerated/cfg-stackify.s
@@ -12,7 +12,7 @@ test0:
i32.add $1=, $1, $pop0
i32.ge_s $push1=, $1, $0
br_if $pop1, .LBB0_3
- call something
+ call something@FUNCTION
br .LBB0_1
.LBB0_3:
return
@@ -31,7 +31,7 @@ test1:
i32.add $1=, $1, $pop0
i32.ge_s $push1=, $1, $0
br_if $pop1, .LBB1_3
- call something
+ call something@FUNCTION
br .LBB1_1
.LBB1_3:
return
@@ -288,7 +288,7 @@ test3:
i32.ne $push1=, $0, $0
br_if $pop1, .LBB12_2
.LBB12_3:
- call bar
+ call bar@FUNCTION
br .LBB12_1
.LBB12_4:
unreachable
@@ -463,7 +463,7 @@ test9:
loop .LBB18_5
i32.const $push0=, 1
i32.store $1=, 0($0), $pop0
- i32.call $push1=, a
+ i32.call $push1=, a@FUNCTION
i32.and $push2=, $pop1, $1
i32.const $push13=, 0
i32.eq $push14=, $pop2, $pop13
@@ -473,21 +473,21 @@ test9:
block .LBB18_4
i32.const $push4=, 2
i32.store $discard=, 0($0), $pop4
- i32.call $push5=, a
+ i32.call $push5=, a@FUNCTION
i32.and $push6=, $pop5, $1
i32.const $push15=, 0
i32.eq $push16=, $pop6, $pop15
br_if $pop16, .LBB18_4
i32.const $push10=, 3
i32.store $discard=, 0($0), $pop10
- i32.call $push11=, a
+ i32.call $push11=, a@FUNCTION
i32.and $push12=, $pop11, $1
br_if $pop12, .LBB18_2
br .LBB18_1
.LBB18_4:
i32.const $push7=, 4
i32.store $discard=, 0($0), $pop7
- i32.call $push8=, a
+ i32.call $push8=, a@FUNCTION
i32.and $push9=, $pop8, $1
br_if $pop9, .LBB18_2
br .LBB18_1
diff --git a/test/llvm_autogenerated/f32.s b/test/llvm_autogenerated/f32.s
index 53ec18d7f..229f3f7dc 100644
--- a/test/llvm_autogenerated/f32.s
+++ b/test/llvm_autogenerated/f32.s
@@ -157,7 +157,7 @@ fmax32:
fma32:
.param f32, f32, f32
.result f32
- f32.call $push0=, fmaf, $0, $1, $2
+ f32.call $push0=, fmaf@FUNCTION, $0, $1, $2
return $pop0
.Lfunc_end15:
.size fma32, .Lfunc_end15-fma32
diff --git a/test/llvm_autogenerated/f64.s b/test/llvm_autogenerated/f64.s
index 423d7cb77..520a1a68d 100644
--- a/test/llvm_autogenerated/f64.s
+++ b/test/llvm_autogenerated/f64.s
@@ -157,7 +157,7 @@ fmax64:
fma64:
.param f64, f64, f64
.result f64
- f64.call $push0=, fma, $0, $1, $2
+ f64.call $push0=, fma@FUNCTION, $0, $1, $2
return $pop0
.Lfunc_end15:
.size fma64, .Lfunc_end15-fma64
diff --git a/test/llvm_autogenerated/frem.s b/test/llvm_autogenerated/frem.s
index 44d12adfd..af01a9c2b 100644
--- a/test/llvm_autogenerated/frem.s
+++ b/test/llvm_autogenerated/frem.s
@@ -5,7 +5,7 @@
frem32:
.param f32, f32
.result f32
- f32.call $push0=, fmodf, $0, $1
+ f32.call $push0=, fmodf@FUNCTION, $0, $1
return $pop0
.Lfunc_end0:
.size frem32, .Lfunc_end0-frem32
@@ -15,7 +15,7 @@ frem32:
frem64:
.param f64, f64
.result f64
- f64.call $push0=, fmod, $0, $1
+ f64.call $push0=, fmod@FUNCTION, $0, $1
return $pop0
.Lfunc_end1:
.size frem64, .Lfunc_end1-frem64
diff --git a/test/llvm_autogenerated/global.s b/test/llvm_autogenerated/global.s
index 82b1d75d1..3b2432998 100644
--- a/test/llvm_autogenerated/global.s
+++ b/test/llvm_autogenerated/global.s
@@ -15,7 +15,7 @@ foo:
call_memcpy:
.param i32, i32, i32
.result i32
- call memcpy, $0, $1, $2
+ call memcpy@FUNCTION, $0, $1, $2
return $0
.Lfunc_end1:
.size call_memcpy, .Lfunc_end1-call_memcpy
@@ -30,7 +30,7 @@ call_memcpy:
.type ud,@object
.align 2
ud:
- .zero 4
+ .skip 4
.size ud, 4
.type nil,@object
@@ -58,7 +58,7 @@ u32max:
.type ud64,@object
.align 3
ud64:
- .zero 8
+ .skip 8
.size ud64, 8
.type nil64,@object
@@ -80,7 +80,7 @@ u64max:
.type f32ud,@object
.align 2
f32ud:
- .zero 4
+ .skip 4
.size f32ud, 4
.type f32nil,@object
@@ -102,7 +102,7 @@ f32two:
.type f64ud,@object
.align 3
f64ud:
- .zero 8
+ .skip 8
.size f64ud, 8
.type f64nil,@object
@@ -126,7 +126,7 @@ f64two:
.globl arr
.align 4
arr:
- .zero 512
+ .skip 512
.size arr, 512
.type ptr,@object
@@ -142,7 +142,7 @@ ptr:
.globl rom
.align 4
rom:
- .zero 512
+ .skip 512
.size rom, 512
diff --git a/test/llvm_autogenerated/global.wast b/test/llvm_autogenerated/global.wast
index 09cf1a1a2..cc453456c 100644
--- a/test/llvm_autogenerated/global.wast
+++ b/test/llvm_autogenerated/global.wast
@@ -1,5 +1,5 @@
(module
- (memory 1184 4294967295 (segment 4 "9\05\00\00") (segment 20 "\01\00\00\00") (segment 24 "*\00\00\00") (segment 28 "\ff\ff\ff\ff") (segment 56 "\00\00\00\00\00\00\00\00") (segment 64 "\ff\ff\ff\ff\ff\ff\ff\ff") (segment 84 "\00\00\00\80") (segment 88 "\00\00\00@") (segment 120 "\00\00\00\00\00\00\00\00") (segment 128 "\00\00\00\00\00\00\00\00") (segment 656 "\e0\00\00\00"))
+ (memory 1184 4294967295 (segment 4 "9\05\00\00") (segment 20 "\01\00\00\00") (segment 24 "*\00\00\00") (segment 28 "\ff\ff\ff\ff") (segment 56 "\00\00\00\00\01\00\00\00") (segment 64 "\ff\ff\ff\ff\ff\ff\ff\ff") (segment 84 "\00\00\00\80") (segment 88 "\00\00\00@") (segment 120 "\00\00\00\00\00\00\00\80") (segment 128 "\00\00\00\00\00\00\00@") (segment 656 "\e0\00\00\00"))
(import $memcpy "env" "memcpy" (param i32 i32 i32))
(export "foo" $foo)
(export "call_memcpy" $call_memcpy)
diff --git a/test/llvm_autogenerated/legalize.s b/test/llvm_autogenerated/legalize.s
index f675652da..53bd6c1ed 100644
--- a/test/llvm_autogenerated/legalize.s
+++ b/test/llvm_autogenerated/legalize.s
@@ -74,228 +74,228 @@ bigshift:
i64.sub $push1=, $pop0, $17
i32.const $184=, 480
i32.add $184=, $279, $184
- call __lshrti3, $184, $1, $2, $pop1
+ call __lshrti3@FUNCTION, $184, $1, $2, $pop1
i64.const $push2=, -768
i64.add $33=, $17, $pop2
i32.const $185=, 464
i32.add $185=, $279, $185
- call __ashlti3, $185, $3, $4, $33
+ call __ashlti3@FUNCTION, $185, $3, $4, $33
i64.const $push3=, -896
i64.add $push4=, $17, $pop3
i32.const $186=, 496
i32.add $186=, $279, $186
- call __ashlti3, $186, $1, $2, $pop4
+ call __ashlti3@FUNCTION, $186, $1, $2, $pop4
i64.const $push5=, 640
i64.sub $34=, $pop5, $17
i32.const $187=, 352
i32.add $187=, $279, $187
- call __lshrti3, $187, $5, $6, $34
+ call __lshrti3@FUNCTION, $187, $5, $6, $34
i64.const $push6=, -512
i64.add $35=, $17, $pop6
i32.const $188=, 336
i32.add $188=, $279, $188
- call __ashlti3, $188, $7, $8, $35
+ call __ashlti3@FUNCTION, $188, $7, $8, $35
i64.const $push7=, -640
i64.add $36=, $17, $pop7
i32.const $189=, 368
i32.add $189=, $279, $189
- call __ashlti3, $189, $5, $6, $36
+ call __ashlti3@FUNCTION, $189, $5, $6, $36
i64.const $push8=, 768
i64.sub $37=, $pop8, $17
i32.const $190=, 432
i32.add $190=, $279, $190
- call __lshrti3, $190, $3, $4, $37
+ call __lshrti3@FUNCTION, $190, $3, $4, $37
i64.const $38=, 384
i64.sub $39=, $38, $17
i32.const $191=, 864
i32.add $191=, $279, $191
- call __lshrti3, $191, $9, $10, $39
+ call __lshrti3@FUNCTION, $191, $9, $10, $39
i64.const $push9=, -256
i64.add $40=, $17, $pop9
i32.const $192=, 848
i32.add $192=, $279, $192
- call __ashlti3, $192, $11, $12, $40
+ call __ashlti3@FUNCTION, $192, $11, $12, $40
i64.const $push10=, -384
i64.add $41=, $17, $pop10
i32.const $193=, 880
i32.add $193=, $279, $193
- call __ashlti3, $193, $9, $10, $41
+ call __ashlti3@FUNCTION, $193, $9, $10, $41
i32.const $194=, 1008
i32.add $194=, $279, $194
- call __ashlti3, $194, $15, $16, $17
+ call __ashlti3@FUNCTION, $194, $15, $16, $17
i64.const $42=, 128
i64.sub $51=, $42, $17
i32.const $195=, 960
i32.add $195=, $279, $195
- call __lshrti3, $195, $13, $14, $51
+ call __lshrti3@FUNCTION, $195, $13, $14, $51
i64.const $push11=, -128
i64.add $43=, $17, $pop11
i32.const $196=, 976
i32.add $196=, $279, $196
- call __ashlti3, $196, $13, $14, $43
+ call __ashlti3@FUNCTION, $196, $13, $14, $43
i64.const $44=, 256
i64.sub $45=, $44, $17
i32.const $197=, 816
i32.add $197=, $279, $197
- call __lshrti3, $197, $11, $12, $45
+ call __lshrti3@FUNCTION, $197, $11, $12, $45
i64.const $46=, 512
i64.sub $47=, $46, $17
i32.const $198=, 240
i32.add $198=, $279, $198
- call __lshrti3, $198, $7, $8, $47
+ call __lshrti3@FUNCTION, $198, $7, $8, $47
i32.const $199=, 912
i32.add $199=, $279, $199
- call __ashlti3, $199, $11, $12, $17
+ call __ashlti3@FUNCTION, $199, $11, $12, $17
i32.const $200=, 928
i32.add $200=, $279, $200
- call __lshrti3, $200, $9, $10, $51
+ call __lshrti3@FUNCTION, $200, $9, $10, $51
i32.const $201=, 944
i32.add $201=, $279, $201
- call __ashlti3, $201, $9, $10, $43
+ call __ashlti3@FUNCTION, $201, $9, $10, $43
i64.sub $48=, $44, $47
i32.const $202=, 80
i32.add $202=, $279, $202
- call __ashlti3, $202, $7, $8, $48
+ call __ashlti3@FUNCTION, $202, $7, $8, $48
i64.sub $push12=, $42, $48
i32.const $203=, 96
i32.add $203=, $279, $203
- call __lshrti3, $203, $5, $6, $pop12
+ call __lshrti3@FUNCTION, $203, $5, $6, $pop12
i64.sub $49=, $42, $47
i32.const $204=, 112
i32.add $204=, $279, $204
- call __ashlti3, $204, $5, $6, $49
+ call __ashlti3@FUNCTION, $204, $5, $6, $49
i32.const $205=, 48
i32.add $205=, $279, $205
- call __lshrti3, $205, $3, $4, $47
+ call __lshrti3@FUNCTION, $205, $3, $4, $47
i32.const $206=, 176
i32.add $206=, $279, $206
- call __lshrti3, $206, $7, $8, $45
+ call __lshrti3@FUNCTION, $206, $7, $8, $45
i32.const $207=, 288
i32.add $207=, $279, $207
- call __lshrti3, $207, $1, $2, $34
+ call __lshrti3@FUNCTION, $207, $1, $2, $34
i32.const $208=, 272
i32.add $208=, $279, $208
- call __ashlti3, $208, $3, $4, $35
+ call __ashlti3@FUNCTION, $208, $3, $4, $35
i32.const $209=, 304
i32.add $209=, $279, $209
- call __ashlti3, $209, $1, $2, $36
+ call __ashlti3@FUNCTION, $209, $1, $2, $36
i32.const $210=, 128
i32.add $210=, $279, $210
- call __lshrti3, $210, $5, $6, $45
+ call __lshrti3@FUNCTION, $210, $5, $6, $45
i64.sub $push13=, $38, $47
i32.const $211=, 144
i32.add $211=, $279, $211
- call __ashlti3, $211, $7, $8, $pop13
+ call __ashlti3@FUNCTION, $211, $7, $8, $pop13
i32.const $212=, 160
i32.add $212=, $279, $212
- call __lshrti3, $212, $7, $8, $51
+ call __lshrti3@FUNCTION, $212, $7, $8, $51
i32.const $213=, 0
i32.add $213=, $279, $213
- call __lshrti3, $213, $1, $2, $47
+ call __lshrti3@FUNCTION, $213, $1, $2, $47
i32.const $214=, 16
i32.add $214=, $279, $214
- call __ashlti3, $214, $3, $4, $49
+ call __ashlti3@FUNCTION, $214, $3, $4, $49
i32.const $215=, 32
i32.add $215=, $279, $215
- call __lshrti3, $215, $3, $4, $39
+ call __lshrti3@FUNCTION, $215, $3, $4, $39
i32.const $216=, 64
i32.add $216=, $279, $216
- call __ashlti3, $216, $5, $6, $48
+ call __ashlti3@FUNCTION, $216, $5, $6, $48
i32.const $217=, 896
i32.add $217=, $279, $217
- call __ashlti3, $217, $9, $10, $17
+ call __ashlti3@FUNCTION, $217, $9, $10, $17
i32.const $218=, 256
i32.add $218=, $279, $218
- call __ashlti3, $218, $1, $2, $35
+ call __ashlti3@FUNCTION, $218, $1, $2, $35
i32.const $219=, 192
i32.add $219=, $279, $219
- call __lshrti3, $219, $5, $6, $47
+ call __lshrti3@FUNCTION, $219, $5, $6, $47
i32.const $220=, 208
i32.add $220=, $279, $220
- call __ashlti3, $220, $7, $8, $49
+ call __ashlti3@FUNCTION, $220, $7, $8, $49
i32.const $221=, 224
i32.add $221=, $279, $221
- call __lshrti3, $221, $7, $8, $39
+ call __lshrti3@FUNCTION, $221, $7, $8, $39
i32.const $222=, 768
i32.add $222=, $279, $222
- call __lshrti3, $222, $9, $10, $45
+ call __lshrti3@FUNCTION, $222, $9, $10, $45
i64.sub $49=, $42, $45
i32.const $223=, 784
i32.add $223=, $279, $223
- call __ashlti3, $223, $11, $12, $49
+ call __ashlti3@FUNCTION, $223, $11, $12, $49
i32.const $224=, 800
i32.add $224=, $279, $224
- call __lshrti3, $224, $11, $12, $51
+ call __lshrti3@FUNCTION, $224, $11, $12, $51
i32.const $225=, 992
i32.add $225=, $279, $225
- call __ashlti3, $225, $13, $14, $17
+ call __ashlti3@FUNCTION, $225, $13, $14, $17
i32.const $226=, 832
i32.add $226=, $279, $226
- call __ashlti3, $226, $9, $10, $40
+ call __ashlti3@FUNCTION, $226, $9, $10, $40
i32.const $227=, 384
i32.add $227=, $279, $227
- call __lshrti3, $227, $1, $2, $37
+ call __lshrti3@FUNCTION, $227, $1, $2, $37
i64.sub $push14=, $42, $37
i32.const $228=, 400
i32.add $228=, $279, $228
- call __ashlti3, $228, $3, $4, $pop14
+ call __ashlti3@FUNCTION, $228, $3, $4, $pop14
i32.const $229=, 416
i32.add $229=, $279, $229
- call __lshrti3, $229, $3, $4, $34
+ call __lshrti3@FUNCTION, $229, $3, $4, $34
i32.const $230=, 320
i32.add $230=, $279, $230
- call __ashlti3, $230, $5, $6, $35
+ call __ashlti3@FUNCTION, $230, $5, $6, $35
i32.const $231=, 448
i32.add $231=, $279, $231
- call __ashlti3, $231, $1, $2, $33
+ call __ashlti3@FUNCTION, $231, $1, $2, $33
i32.const $232=, 736
i32.add $232=, $279, $232
- call __lshrti3, $232, $1, $2, $39
+ call __lshrti3@FUNCTION, $232, $1, $2, $39
i32.const $233=, 720
i32.add $233=, $279, $233
- call __ashlti3, $233, $3, $4, $40
+ call __ashlti3@FUNCTION, $233, $3, $4, $40
i32.const $234=, 752
i32.add $234=, $279, $234
- call __ashlti3, $234, $1, $2, $41
+ call __ashlti3@FUNCTION, $234, $1, $2, $41
i32.const $235=, 592
i32.add $235=, $279, $235
- call __ashlti3, $235, $7, $8, $17
+ call __ashlti3@FUNCTION, $235, $7, $8, $17
i32.const $236=, 608
i32.add $236=, $279, $236
- call __lshrti3, $236, $5, $6, $51
+ call __lshrti3@FUNCTION, $236, $5, $6, $51
i32.const $237=, 624
i32.add $237=, $279, $237
- call __ashlti3, $237, $5, $6, $43
+ call __ashlti3@FUNCTION, $237, $5, $6, $43
i32.const $238=, 688
i32.add $238=, $279, $238
- call __lshrti3, $238, $3, $4, $45
+ call __lshrti3@FUNCTION, $238, $3, $4, $45
i32.const $239=, 640
i32.add $239=, $279, $239
- call __lshrti3, $239, $1, $2, $45
+ call __lshrti3@FUNCTION, $239, $1, $2, $45
i32.const $240=, 656
i32.add $240=, $279, $240
- call __ashlti3, $240, $3, $4, $49
+ call __ashlti3@FUNCTION, $240, $3, $4, $49
i32.const $241=, 672
i32.add $241=, $279, $241
- call __lshrti3, $241, $3, $4, $51
+ call __lshrti3@FUNCTION, $241, $3, $4, $51
i32.const $242=, 576
i32.add $242=, $279, $242
- call __ashlti3, $242, $5, $6, $17
+ call __ashlti3@FUNCTION, $242, $5, $6, $17
i32.const $243=, 704
i32.add $243=, $279, $243
- call __ashlti3, $243, $1, $2, $40
+ call __ashlti3@FUNCTION, $243, $1, $2, $40
i32.const $244=, 528
i32.add $244=, $279, $244
- call __ashlti3, $244, $3, $4, $17
+ call __ashlti3@FUNCTION, $244, $3, $4, $17
i32.const $245=, 544
i32.add $245=, $279, $245
- call __lshrti3, $245, $1, $2, $51
+ call __lshrti3@FUNCTION, $245, $1, $2, $51
i32.const $246=, 560
i32.add $246=, $279, $246
- call __ashlti3, $246, $1, $2, $43
+ call __ashlti3@FUNCTION, $246, $1, $2, $43
i32.const $247=, 512
i32.add $247=, $279, $247
- call __ashlti3, $247, $1, $2, $17
+ call __ashlti3@FUNCTION, $247, $1, $2, $17
i32.const $78=, 8
i32.const $248=, 480
i32.add $248=, $279, $248
diff --git a/test/llvm_autogenerated/offset-folding.s b/test/llvm_autogenerated/offset-folding.s
index 6c03d5191..897b0d45a 100644
--- a/test/llvm_autogenerated/offset-folding.s
+++ b/test/llvm_autogenerated/offset-folding.s
@@ -47,7 +47,7 @@ x:
.globl y
.align 4
y:
- .zero 200
+ .skip 200
.size y, 200
diff --git a/test/llvm_autogenerated/signext-zeroext.s b/test/llvm_autogenerated/signext-zeroext.s
index eadac8294..395166900 100644
--- a/test/llvm_autogenerated/signext-zeroext.s
+++ b/test/llvm_autogenerated/signext-zeroext.s
@@ -31,7 +31,7 @@ z2s_call:
.result i32
i32.const $push0=, 255
i32.and $push1=, $0, $pop0
- i32.call $push2=, z2s_func, $pop1
+ i32.call $push2=, z2s_func@FUNCTION, $pop1
return $pop2
.Lfunc_end2:
.size z2s_call, .Lfunc_end2-z2s_call
@@ -45,7 +45,7 @@ s2z_call:
i32.const $1=, 24
i32.shl $push0=, $0, $1
i32.shr_s $push1=, $pop0, $1
- i32.call $push2=, s2z_func, $pop1
+ i32.call $push2=, s2z_func@FUNCTION, $pop1
i32.shl $push3=, $pop2, $1
i32.shr_s $push4=, $pop3, $1
return $pop4
diff --git a/test/llvm_autogenerated/store-results.s b/test/llvm_autogenerated/store-results.s
index 563ec01e1..6356d5d92 100644
--- a/test/llvm_autogenerated/store-results.s
+++ b/test/llvm_autogenerated/store-results.s
@@ -54,7 +54,7 @@ bar:
.globl pos
.align 2
pos:
- .zero 12
+ .skip 12
.size pos, 12
diff --git a/test/llvm_autogenerated/switch.s b/test/llvm_autogenerated/switch.s
index 635d453c5..35fda0849 100644
--- a/test/llvm_autogenerated/switch.s
+++ b/test/llvm_autogenerated/switch.s
@@ -16,22 +16,22 @@ bar32:
block .LBB0_2
tableswitch $0, .LBB0_2, .LBB0_2, .LBB0_2, .LBB0_2, .LBB0_2, .LBB0_2, .LBB0_2, .LBB0_2, .LBB0_3, .LBB0_3, .LBB0_3, .LBB0_3, .LBB0_3, .LBB0_3, .LBB0_3, .LBB0_3, .LBB0_4, .LBB0_4, .LBB0_4, .LBB0_4, .LBB0_4, .LBB0_4, .LBB0_5, .LBB0_6, .LBB0_7
.LBB0_2:
- call foo0
+ call foo0@FUNCTION
br .LBB0_8
.LBB0_3:
- call foo1
+ call foo1@FUNCTION
br .LBB0_8
.LBB0_4:
- call foo2
+ call foo2@FUNCTION
br .LBB0_8
.LBB0_5:
- call foo3
+ call foo3@FUNCTION
br .LBB0_8
.LBB0_6:
- call foo4
+ call foo4@FUNCTION
br .LBB0_8
.LBB0_7:
- call foo5
+ call foo5@FUNCTION
.LBB0_8:
return
.Lfunc_end0:
@@ -54,22 +54,22 @@ bar64:
i32.wrap/i64 $push0=, $0
tableswitch $pop0, .LBB1_2, .LBB1_2, .LBB1_2, .LBB1_2, .LBB1_2, .LBB1_2, .LBB1_2, .LBB1_2, .LBB1_3, .LBB1_3, .LBB1_3, .LBB1_3, .LBB1_3, .LBB1_3, .LBB1_3, .LBB1_3, .LBB1_4, .LBB1_4, .LBB1_4, .LBB1_4, .LBB1_4, .LBB1_4, .LBB1_5, .LBB1_6, .LBB1_7
.LBB1_2:
- call foo0
+ call foo0@FUNCTION
br .LBB1_8
.LBB1_3:
- call foo1
+ call foo1@FUNCTION
br .LBB1_8
.LBB1_4:
- call foo2
+ call foo2@FUNCTION
br .LBB1_8
.LBB1_5:
- call foo3
+ call foo3@FUNCTION
br .LBB1_8
.LBB1_6:
- call foo4
+ call foo4@FUNCTION
br .LBB1_8
.LBB1_7:
- call foo5
+ call foo5@FUNCTION
.LBB1_8:
return
.Lfunc_end1:
diff --git a/test/llvm_autogenerated/unreachable.s b/test/llvm_autogenerated/unreachable.s
index bd5f85df6..83ec5b4b1 100644
--- a/test/llvm_autogenerated/unreachable.s
+++ b/test/llvm_autogenerated/unreachable.s
@@ -4,7 +4,7 @@
.type f1,@function
f1:
.result i32
- call abort
+ call abort@FUNCTION
unreachable
.Lfunc_end0:
.size f1, .Lfunc_end0-f1
diff --git a/test/llvm_autogenerated/unused-argument.s b/test/llvm_autogenerated/unused-argument.s
index 97d72ee2c..48ab32e38 100644
--- a/test/llvm_autogenerated/unused-argument.s
+++ b/test/llvm_autogenerated/unused-argument.s
@@ -21,7 +21,7 @@ unused_second:
.globl call_something
.type call_something,@function
call_something:
- i32.call $discard=, return_something
+ i32.call $discard=, return_something@FUNCTION
return
.Lfunc_end2:
.size call_something, .Lfunc_end2-call_something
diff --git a/test/llvm_autogenerated/userstack.s b/test/llvm_autogenerated/userstack.s
index f3ae1cbca..d77c7bc81 100644
--- a/test/llvm_autogenerated/userstack.s
+++ b/test/llvm_autogenerated/userstack.s
@@ -67,13 +67,34 @@ allocarray:
.Lfunc_end2:
.size allocarray, .Lfunc_end2-allocarray
+ .globl allocarray_inbounds
+ .type allocarray_inbounds,@function
+allocarray_inbounds:
+ .local i32, i32, i32, i32
+ i32.const $0=, __stack_pointer
+ i32.load $0=, 0($0)
+ i32.const $1=, 32
+ i32.sub $3=, $0, $1
+ i32.const $1=, __stack_pointer
+ i32.store $3=, 0($1), $3
+ i32.const $push0=, 1
+ i32.store $push1=, 12($3), $pop0
+ i32.store $discard=, 16($3), $pop1
+ i32.const $2=, 32
+ i32.add $3=, $3, $2
+ i32.const $2=, __stack_pointer
+ i32.store $3=, 0($2), $3
+ return
+.Lfunc_end3:
+ .size allocarray_inbounds, .Lfunc_end3-allocarray_inbounds
+
.globl dynamic_alloca
.type dynamic_alloca,@function
dynamic_alloca:
.param i32
return
-.Lfunc_end3:
- .size dynamic_alloca, .Lfunc_end3-dynamic_alloca
+.Lfunc_end4:
+ .size dynamic_alloca, .Lfunc_end4-dynamic_alloca
.section ".note.GNU-stack","",@progbits
diff --git a/test/llvm_autogenerated/userstack.wast b/test/llvm_autogenerated/userstack.wast
index c2083ce2a..d412410f3 100644
--- a/test/llvm_autogenerated/userstack.wast
+++ b/test/llvm_autogenerated/userstack.wast
@@ -3,6 +3,7 @@
(export "alloca32" $alloca32)
(export "alloca3264" $alloca3264)
(export "allocarray" $allocarray)
+ (export "allocarray_inbounds" $allocarray_inbounds)
(export "dynamic_alloca" $dynamic_alloca)
(func $alloca32
(local $$0 i32)
@@ -205,6 +206,68 @@
)
)
)
+ (func $allocarray_inbounds
+ (local $$0 i32)
+ (local $$1 i32)
+ (local $$2 i32)
+ (local $$3 i32)
+ (block $fake_return_waka123
+ (block
+ (set_local $$0
+ (i32.const 0)
+ )
+ (set_local $$0
+ (i32.load align=4
+ (get_local $$0)
+ )
+ )
+ (set_local $$1
+ (i32.const 32)
+ )
+ (set_local $$3
+ (i32.sub
+ (get_local $$0)
+ (get_local $$1)
+ )
+ )
+ (set_local $$1
+ (i32.const 0)
+ )
+ (set_local $$3
+ (i32.store align=4
+ (get_local $$1)
+ (get_local $$3)
+ )
+ )
+ (i32.store offset=16 align=4
+ (get_local $$3)
+ (i32.store offset=12 align=4
+ (get_local $$3)
+ (i32.const 1)
+ )
+ )
+ (set_local $$2
+ (i32.const 32)
+ )
+ (set_local $$3
+ (i32.add
+ (get_local $$3)
+ (get_local $$2)
+ )
+ )
+ (set_local $$2
+ (i32.const 0)
+ )
+ (set_local $$3
+ (i32.store align=4
+ (get_local $$2)
+ (get_local $$3)
+ )
+ )
+ (br $fake_return_waka123)
+ )
+ )
+ )
(func $dynamic_alloca (param $$0 i32)
(block $fake_return_waka123
(block
diff --git a/test/llvm_autogenerated/varargs.s b/test/llvm_autogenerated/varargs.s
index 5159dadca..feb0a2659 100644
--- a/test/llvm_autogenerated/varargs.s
+++ b/test/llvm_autogenerated/varargs.s
@@ -80,7 +80,7 @@ arg_i128:
.globl caller_none
.type caller_none,@function
caller_none:
- call callee
+ call callee@FUNCTION
return
.Lfunc_end5:
.size caller_none, .Lfunc_end5-caller_none
diff --git a/test/passes/O.txt b/test/passes/O.txt
index dec081fd4..23b39e920 100644
--- a/test/passes/O.txt
+++ b/test/passes/O.txt
@@ -20203,7 +20203,7 @@
(call $_frexp
(f64.mul
(get_local $d1)
- (f64.const 18446744073709551616)
+ (f64.const 18446744073709551615)
)
(get_local $i5)
)
diff --git a/ubsan.blacklist b/ubsan.blacklist
new file mode 100644
index 000000000..cd23680dd
--- /dev/null
+++ b/ubsan.blacklist
@@ -0,0 +1,3 @@
+# Work around libstdc++ bug: https://llvm.org/bugs/show_bug.cgi?id=18156
+# Also see: http://lists.llvm.org/pipermail/cfe-dev/2015-January/040945.html
+src:*/ios_base.h