diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bits.h | 107 | ||||
-rw-r--r-- | src/emscripten-optimizer/colors.h | 72 | ||||
-rw-r--r-- | src/s2wasm.h | 19 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 27 | ||||
-rw-r--r-- | src/wasm-validator.h | 30 | ||||
-rw-r--r-- | src/wasm.h | 1 |
6 files changed, 184 insertions, 72 deletions
diff --git a/src/bits.h b/src/bits.h new file mode 100644 index 000000000..0ae83db3f --- /dev/null +++ b/src/bits.h @@ -0,0 +1,107 @@ +/* + * Copyright 2015 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_bits_h +#define wasm_bits_h + +/* + * Portable bit functions. + * + * Not all platforms offer fast intrinsics for these functions, and some + * compilers require checking CPUID at runtime before using the intrinsic. + * + * We instead use portable and reasonably-fast implementations, while + * avoiding implementations with large lookup tables. + */ + +namespace wasm { + +// Only the specialized templates should be instantiated, getting +// a linker error with these functions means an unsupported type was used. + +template<typename T> inline int PopCount(T /* v */); +template<typename T> inline T BitReverse(T /* v */); +template<typename T> inline int CountTrailingZeroes(T /* v */); +template<typename T> inline int CountLeadingZeroes(T /* v */); + +// Implementations for the above templates. + +template<> inline int PopCount<uint8_t>(uint8_t v) { + // Small table lookup. + static const uint8_t tbl[32] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5 + }; + return tbl[v & 0xf] + tbl[v >> 4]; +} +template<> inline int PopCount<uint16_t>(uint16_t v) { + return PopCount<uint8_t>(v & 0xff) + PopCount<uint8_t>(v >> 8); +} +template<> inline int PopCount<uint32_t>(uint32_t v) { + // See Stanford bithacks, counting bits set in parallel, "best method": + // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel + v = v - ((v >> 1) & 0x55555555); + v = (v & 0x33333333) + ((v >> 2) & 0x33333333); + return (((v + (v >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; +} +template<> inline int PopCount<uint64_t>(uint64_t v) { + return PopCount<uint32_t>((uint32_t)v) + PopCount<uint32_t>(v >> 32); +} + +template<> inline uint32_t BitReverse<uint32_t>(uint32_t v) { + // See Hacker's Delight, first edition, figure 7-1. + v = ((v & 0x55555555) << 1) | ((v >> 1) & 0x55555555); + v = ((v & 0x33333333) << 2) | ((v >> 2) & 0x33333333); + v = ((v & 0x0F0F0F0F) << 4) | ((v >> 4) & 0x0F0F0F0F); + v = (v << 24) | ((v & 0xFF00) << 8) | + ((v >> 8) & 0xFF00) | (v >> 24); + return v; +} + +template<> inline int CountTrailingZeroes<uint32_t>(uint32_t v) { + // See Stanford bithacks, count the consecutive zero bits (trailing) on the + // right with multiply and lookup: + // http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightMultLookup + static const uint8_t tbl[32] = { + 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, + 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 + }; + return v ? + (int)tbl[((uint32_t)((v & -(int32_t)v) * 0x077CB531U)) >> 27] : + -1; +} + +template<> inline int CountLeadingZeroes<uint32_t>(uint32_t v) { + // See Stanford bithacks, find the log base 2 of an N-bit integer in + // O(lg(N)) operations with multiply and lookup: + // http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogDeBruijn + static const uint8_t tbl[32] = { + 31, 22, 30, 21, 18, 10, 29, 2, 20, 17, 15, 13, 9, 6, 28, 1, + 23, 19, 11, 3, 16, 14, 7, 24, 12, 4, 8, 25, 5, 26, 27, 0 + }; + v = v | (v >> 1); + v = v | (v >> 2); + v = v | (v >> 4); + v = v | (v >> 8); + v = v | (v >> 16); + return v ? + (int)tbl[((uint32_t)(v * 0x07C4ACDDU)) >> 27] : + -1; +} + +} // namespace wasm + +#endif // wasm_bits_h diff --git a/src/emscripten-optimizer/colors.h b/src/emscripten-optimizer/colors.h index c3f48113f..bd12f0c6b 100644 --- a/src/emscripten-optimizer/colors.h +++ b/src/emscripten-optimizer/colors.h @@ -17,64 +17,32 @@ #ifndef wasm_color_h #define wasm_color_h -#include <unistd.h> #include <cstdlib> #include <ostream> -namespace Colors { - inline bool use() { - return (getenv("COLORS") && getenv("COLORS")[0] == '1') || // forced - (isatty(STDOUT_FILENO) && (!getenv("COLORS") || getenv("COLORS")[0] != '0')); // implicit - } - - inline void normal(std::ostream& stream) { - if (!use()) return; -#if defined(__linux__) || defined(__apple__) - stream << "\033[0m"; -#endif - } - inline void red(std::ostream& stream) { - if (!use()) return; -#if defined(__linux__) || defined(__apple__) - stream << "\033[31m"; -#endif - } - inline void magenta(std::ostream& stream) { - if (!use()) return; -#if defined(__linux__) || defined(__apple__) - stream << "\033[35m"; -#endif - } - inline void orange(std::ostream& stream) { - if (!use()) return; -#if defined(__linux__) || defined(__apple__) - stream << "\033[33m"; -#endif - } - inline void grey(std::ostream& stream) { - if (!use()) return; -#if defined(__linux__) || defined(__apple__) - stream << "\033[37m"; -#endif - } - inline void green(std::ostream& stream) { - if (!use()) return; #if defined(__linux__) || defined(__apple__) - stream << "\033[32m"; -#endif - } - inline void blue(std::ostream& stream) { - if (!use()) return; -#if defined(__linux__) || defined(__apple__) - stream << "\033[34m"; -#endif +#include <unistd.h> + +namespace Colors { + inline void outputColorCode(std::ostream& stream,const char* colorCode) { + if((getenv("COLORS") && getenv("COLORS")[0] == '1') || // forced + (isatty(STDOUT_FILENO) && (!getenv("COLORS") || getenv("COLORS")[0] != '0'))) { // implicit + stream << colorCode; + } } - inline void bold(std::ostream& stream) { - if (!use()) return; -#if defined(__linux__) || defined(__apple__) - stream << "\033[1m"; +#else +namespace Colors { + inline void outputColorCode(std::ostream& stream,const char* colorCode) {} #endif - } + + inline void normal(std::ostream& stream) { outputColorCode(stream,"\033[0m"); } + inline void red(std::ostream& stream) { outputColorCode(stream,"\033[31m"); } + inline void magenta(std::ostream& stream) { outputColorCode(stream,"\033[35m"); } + inline void orange(std::ostream& stream) { outputColorCode(stream,"\033[33m"); } + inline void grey(std::ostream& stream) { outputColorCode(stream,"\033[37m"); } + inline void green(std::ostream& stream) { outputColorCode(stream,"\033[32m"); } + inline void blue(std::ostream& stream) { outputColorCode(stream,"\033[34m"); } + inline void bold(std::ostream& stream) { outputColorCode(stream,"\033[1m"); } }; #endif // wasm_color_h diff --git a/src/s2wasm.h b/src/s2wasm.h index 57d5768b8..74387859e 100644 --- a/src/s2wasm.h +++ b/src/s2wasm.h @@ -76,6 +76,8 @@ private: std::map<size_t, size_t> addressSegments; // address => segment index + std::map<Name, size_t> functionIndexes; + // utilities void skipWhitespace() { @@ -972,11 +974,20 @@ private: Name name = triple.name; size_t offset = triple.offset; const auto &symbolAddress = staticAddresses.find(name); - if (symbolAddress == staticAddresses.end()) { - std::cerr << "Unknown symbol: " << name << '\n'; - abort_on("Unknown symbol"); + if (symbolAddress != staticAddresses.end()) { + curr->value = Literal(symbolAddress->second + offset); + } else { + // must be a function address + if (wasm.functionsMap.count(name) == 0) { + std::cerr << "Unknown symbol: " << name << '\n'; + abort_on("Unknown symbol"); + } + if (functionIndexes.count(name) == 0) { + functionIndexes[name] = functionIndexes.size(); + wasm.table.names.push_back(name); + } + curr->value = Literal(functionIndexes[name] + offset); } - curr->value = Literal(symbolAddress->second + offset); assert(curr->value.i32 > 0); curr->type = i32; } diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 97958b041..76c3f66ba 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -35,6 +35,24 @@ using namespace cashew; IString WASM("wasm"); + +#ifdef WIN32 +#include <intrin.h> + +int32_t safe_clz(int32_t v) { + unsigned long result; + return _BitScanReverse(&result,v) ? result : 32; +} + +int32_t safe_ctz(int32_t v) { + unsigned long result; + return _BitScanForward(&result,v) ? result : 32; +} + +int32_t platform_popcount(int32_t v) { + return __popcnt(v); +} +#else int32_t safe_clz(int32_t v) { if (v == 0) return 32; return __builtin_clz(v); @@ -45,6 +63,11 @@ int32_t safe_ctz(int32_t v) { return __builtin_ctz(v); } +int32_t platform_popcount(int32_t v) { + return __buildin_popcount(v); +} +#endif + enum { pageSize = 64*1024, maxCallDepth = 250 @@ -374,7 +397,7 @@ private: if (v == 0) return Literal(32); return Literal((int32_t)safe_ctz(v)); } - case Popcnt: return Literal((int32_t)__builtin_popcount(v)); + case Popcnt: return Literal((int32_t)platform_popcount(v)); case ReinterpretInt: { float v = value.reinterpretf32(); if (isnan(v)) { @@ -403,7 +426,7 @@ private: if (low == 0) return Literal(32+(int64_t)safe_ctz(high)); return Literal((int64_t)safe_ctz(low)); } - case Popcnt: return Literal(int64_t(__builtin_popcount(low) + __builtin_popcount(high))); + case Popcnt: return Literal(int64_t(platform_popcount(low) + platform_popcount(high))); case WrapInt64: return Literal(int32_t(value.geti64())); case ReinterpretInt: { return Literal(value.reinterpretf64()); diff --git a/src/wasm-validator.h b/src/wasm-validator.h index af0c4ba9d..f0e73fb85 100644 --- a/src/wasm-validator.h +++ b/src/wasm-validator.h @@ -39,20 +39,7 @@ public: void visitLoop(Loop *curr) override { if (curr->in.is()) { - // the "in" label has a none type, since no one can receive its value. make sure no one breaks to it with a value. - struct ChildChecker : public WasmWalker { - Name in; - bool valid = true; - - ChildChecker(Name in) : in(in) {} - - void visitBreak(Break *curr) override { - if (curr->name == in && curr->value) { - valid = false; - } - } - }; - ChildChecker childChecker(curr->in); + LoopChildChecker childChecker(curr->in); childChecker.walk(curr->body); shouldBeTrue(childChecker.valid); } @@ -109,6 +96,21 @@ public: } private: + + // the "in" label has a none type, since no one can receive its value. make sure no one breaks to it with a value. + struct LoopChildChecker : public WasmWalker { + Name in; + bool valid = true; + + LoopChildChecker(Name in) : in(in) {} + + void visitBreak(Break *curr) override { + if (curr->name == in && curr->value) { + valid = false; + } + } + }; + // helpers void shouldBeTrue(bool result) { diff --git a/src/wasm.h b/src/wasm.h index df7731094..86aca1fd3 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -51,6 +51,7 @@ #include <fstream> #include <map> #include <vector> +#include <string> #include "compiler-support.h" #include "emscripten-optimizer/simple_ast.h" |