summaryrefslogtreecommitdiff
path: root/src/tools/fuzzing.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/fuzzing.h')
-rw-r--r--src/tools/fuzzing.h1554
1 files changed, 1042 insertions, 512 deletions
diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h
index b7056f964..f5b548ec6 100644
--- a/src/tools/fuzzing.h
+++ b/src/tools/fuzzing.h
@@ -25,12 +25,14 @@ high chance for set at start of loop
high chance of a tee in that case => loop var
*/
-#include <wasm-builder.h>
+#include "ir/memory-utils.h"
#include <ir/find_all.h>
#include <ir/literal-utils.h>
#include <ir/manipulation.h>
-#include "ir/memory-utils.h"
#include <ir/utils.h>
+#include <support/file.h>
+#include <tools/optimization-options.h>
+#include <wasm-builder.h>
namespace wasm {
@@ -38,32 +40,35 @@ namespace wasm {
// evaluation, avoiding UB
struct ThreeArgs {
- Expression *a;
- Expression *b;
- Expression *c;
+ Expression* a;
+ Expression* b;
+ Expression* c;
};
struct UnaryArgs {
UnaryOp a;
- Expression *b;
+ Expression* b;
};
struct BinaryArgs {
BinaryOp a;
- Expression *b;
- Expression *c;
+ Expression* b;
+ Expression* c;
};
// main reader
class TranslateToFuzzReader {
public:
- TranslateToFuzzReader(Module& wasm, std::string& filename) : wasm(wasm), builder(wasm) {
- auto input(read_file<std::vector<char>>(filename, Flags::Binary, Flags::Release));
+ TranslateToFuzzReader(Module& wasm, std::string& filename)
+ : wasm(wasm), builder(wasm) {
+ auto input(
+ read_file<std::vector<char>>(filename, Flags::Binary, Flags::Release));
readData(input);
}
- TranslateToFuzzReader(Module& wasm, std::vector<char> input) : wasm(wasm), builder(wasm) {
+ TranslateToFuzzReader(Module& wasm, std::vector<char> input)
+ : wasm(wasm), builder(wasm) {
readData(input);
}
@@ -80,38 +85,91 @@ public:
options.passOptions.shrinkLevel = upTo(4);
break;
}
- case 5: options.passes.push_back("coalesce-locals"); break;
- case 6: options.passes.push_back("code-pushing"); break;
- case 7: options.passes.push_back("code-folding"); break;
- case 8: options.passes.push_back("dce"); break;
- case 9: options.passes.push_back("duplicate-function-elimination"); break;
- case 10: options.passes.push_back("flatten"); break;
- case 11: options.passes.push_back("inlining"); break;
- case 12: options.passes.push_back("inlining-optimizing"); break;
- case 13: options.passes.push_back("local-cse"); break;
- case 14: options.passes.push_back("memory-packing"); break;
- case 15: options.passes.push_back("merge-blocks"); break;
- case 16: options.passes.push_back("optimize-instructions"); break;
- case 17: options.passes.push_back("pick-load-signs"); break;
- case 18: options.passes.push_back("precompute"); break;
- case 19: options.passes.push_back("precompute-propagate"); break;
- case 20: options.passes.push_back("remove-unused-brs"); break;
- case 21: options.passes.push_back("remove-unused-module-elements"); break;
- case 22: options.passes.push_back("remove-unused-names"); break;
- case 23: options.passes.push_back("reorder-functions"); break;
- case 24: options.passes.push_back("reorder-locals"); break;
+ case 5:
+ options.passes.push_back("coalesce-locals");
+ break;
+ case 6:
+ options.passes.push_back("code-pushing");
+ break;
+ case 7:
+ options.passes.push_back("code-folding");
+ break;
+ case 8:
+ options.passes.push_back("dce");
+ break;
+ case 9:
+ options.passes.push_back("duplicate-function-elimination");
+ break;
+ case 10:
+ options.passes.push_back("flatten");
+ break;
+ case 11:
+ options.passes.push_back("inlining");
+ break;
+ case 12:
+ options.passes.push_back("inlining-optimizing");
+ break;
+ case 13:
+ options.passes.push_back("local-cse");
+ break;
+ case 14:
+ options.passes.push_back("memory-packing");
+ break;
+ case 15:
+ options.passes.push_back("merge-blocks");
+ break;
+ case 16:
+ options.passes.push_back("optimize-instructions");
+ break;
+ case 17:
+ options.passes.push_back("pick-load-signs");
+ break;
+ case 18:
+ options.passes.push_back("precompute");
+ break;
+ case 19:
+ options.passes.push_back("precompute-propagate");
+ break;
+ case 20:
+ options.passes.push_back("remove-unused-brs");
+ break;
+ case 21:
+ options.passes.push_back("remove-unused-module-elements");
+ break;
+ case 22:
+ options.passes.push_back("remove-unused-names");
+ break;
+ case 23:
+ options.passes.push_back("reorder-functions");
+ break;
+ case 24:
+ options.passes.push_back("reorder-locals");
+ break;
case 25: {
options.passes.push_back("flatten");
options.passes.push_back("rereloop");
break;
}
- case 26: options.passes.push_back("simplify-locals"); break;
- case 27: options.passes.push_back("simplify-locals-notee"); break;
- case 28: options.passes.push_back("simplify-locals-nostructure"); break;
- case 29: options.passes.push_back("simplify-locals-notee-nostructure"); break;
- case 30: options.passes.push_back("ssa"); break;
- case 31: options.passes.push_back("vacuum"); break;
- default: WASM_UNREACHABLE();
+ case 26:
+ options.passes.push_back("simplify-locals");
+ break;
+ case 27:
+ options.passes.push_back("simplify-locals-notee");
+ break;
+ case 28:
+ options.passes.push_back("simplify-locals-nostructure");
+ break;
+ case 29:
+ options.passes.push_back("simplify-locals-notee-nostructure");
+ break;
+ case 30:
+ options.passes.push_back("ssa");
+ break;
+ case 31:
+ options.passes.push_back("vacuum");
+ break;
+ default:
+ WASM_UNREACHABLE();
}
}
if (oneIn(2)) {
@@ -124,13 +182,9 @@ public:
std::cout << "shrink level: " << options.passOptions.shrinkLevel << '\n';
}
- void setAllowNaNs(bool allowNaNs_) {
- allowNaNs = allowNaNs_;
- }
+ void setAllowNaNs(bool allowNaNs_) { allowNaNs = allowNaNs_; }
- void setAllowMemory(bool allowMemory_) {
- allowMemory = allowMemory_;
- }
+ void setAllowMemory(bool allowMemory_) { allowMemory = allowMemory_; }
void build() {
if (allowMemory) {
@@ -157,8 +211,10 @@ private:
Module& wasm;
Builder builder;
std::vector<char> bytes; // the input bytes
- size_t pos; // the position in the input
- bool finishedInput; // whether we already cycled through all the input (if so, we should try to finish things off)
+ size_t pos; // the position in the input
+ // whether we already cycled through all the input (if so, we should try to
+ // finish things off)
+ bool finishedInput;
// The maximum amount of params to each function.
static const int MAX_PARAMS = 10;
@@ -176,8 +232,8 @@ private:
static const int BLOCK_FACTOR = 5;
// the memory that we use, a small portion so that we have a good chance of
- // looking at writes (we also look outside of this region with small probability)
- // this should be a power of 2
+ // looking at writes (we also look outside of this region with small
+ // probability) this should be a power of 2
static const int USABLE_MEMORY = 16;
// the number of runtime iterations (function calls, loop backbranches) we
@@ -239,13 +295,9 @@ private:
return temp | uint64_t(get32());
}
- float getFloat() {
- return Literal(get32()).reinterpretf32();
- }
+ float getFloat() { return Literal(get32()).reinterpretf32(); }
- double getDouble() {
- return Literal(get64()).reinterpretf64();
- }
+ double getDouble() { return Literal(get64()).reinterpretf64(); }
void setupMemory() {
// Add memory itself
@@ -274,10 +326,12 @@ private:
auto num = upTo(USABLE_MEMORY * 2);
for (size_t i = 0; i < num; i++) {
auto value = upTo(512);
- wasm.memory.segments[0].data.push_back(value >= 256 ? 0 : (value & 0xff));
+ wasm.memory.segments[0].data.push_back(value >= 256 ? 0
+ : (value & 0xff));
}
}
- // Add memory hasher helper (for the hash, see hash.h). The function looks like:
+ // Add memory hasher helper (for the hash, see hash.h). The function looks
+ // like:
// function hashMemory() {
// hash = 5381;
// hash = ((hash << 5) + hash) ^ mem[0];
@@ -287,31 +341,28 @@ private:
// }
std::vector<Expression*> contents;
contents.push_back(
- builder.makeSetLocal(0, builder.makeConst(Literal(uint32_t(5381))))
- );
+ builder.makeSetLocal(0, builder.makeConst(Literal(uint32_t(5381)))));
for (Index i = 0; i < USABLE_MEMORY; i++) {
- contents.push_back(
- builder.makeSetLocal(0,
- builder.makeBinary(XorInt32,
- builder.makeBinary(AddInt32,
- builder.makeBinary(ShlInt32,
- builder.makeGetLocal(0, i32),
- builder.makeConst(Literal(uint32_t(5)))
- ),
- builder.makeGetLocal(0, i32)
- ),
- builder.makeLoad(1, false, i, 1, builder.makeConst(Literal(uint32_t(0))), i32)
- )
- )
- );
- }
- contents.push_back(
- builder.makeGetLocal(0, i32)
- );
+ contents.push_back(builder.makeSetLocal(
+ 0,
+ builder.makeBinary(
+ XorInt32,
+ builder.makeBinary(
+ AddInt32,
+ builder.makeBinary(ShlInt32,
+ builder.makeGetLocal(0, i32),
+ builder.makeConst(Literal(uint32_t(5)))),
+ builder.makeGetLocal(0, i32)),
+ builder.makeLoad(
+ 1, false, i, 1, builder.makeConst(Literal(uint32_t(0))), i32))));
+ }
+ contents.push_back(builder.makeGetLocal(0, i32));
auto* body = builder.makeBlock(contents);
- auto* hasher = wasm.addFunction(builder.makeFunction("hashMemory", std::vector<Type>{}, i32, { i32 }, body));
+ auto* hasher = wasm.addFunction(builder.makeFunction(
+ "hashMemory", std::vector<Type>{}, i32, {i32}, body));
hasher->type = ensureFunctionType(getSig(hasher), &wasm)->name;
- wasm.addExport(builder.makeExport(hasher->name, hasher->name, ExternalKind::Function));
+ wasm.addExport(
+ builder.makeExport(hasher->name, hasher->name, ExternalKind::Function));
}
void setupTable() {
@@ -323,15 +374,14 @@ private:
void setupGlobals() {
size_t index = 0;
- for (auto type : { i32, i64, f32, f64 }) {
+ for (auto type : {i32, i64, f32, f64}) {
auto num = upTo(3);
for (size_t i = 0; i < num; i++) {
- auto* glob = builder.makeGlobal(
- std::string("global$") + std::to_string(index++),
- type,
- makeConst(type),
- Builder::Mutable
- );
+ auto* glob =
+ builder.makeGlobal(std::string("global$") + std::to_string(index++),
+ type,
+ makeConst(type),
+ Builder::Mutable);
wasm.addGlobal(glob);
globalsByType[type].push_back(glob->name);
}
@@ -340,26 +390,25 @@ private:
void finalizeTable() {
wasm.table.initial = wasm.table.segments[0].data.size();
- wasm.table.max = oneIn(2) ? Address(Table::kUnlimitedSize) : wasm.table.initial;
+ wasm.table.max =
+ oneIn(2) ? Address(Table::kUnlimitedSize) : wasm.table.initial;
}
const Name HANG_LIMIT_GLOBAL = "hangLimit";
void addHangLimitSupport() {
- auto* glob = builder.makeGlobal(
- HANG_LIMIT_GLOBAL,
- i32,
- builder.makeConst(Literal(int32_t(HANG_LIMIT))),
- Builder::Mutable
- );
+ auto* glob =
+ builder.makeGlobal(HANG_LIMIT_GLOBAL,
+ i32,
+ builder.makeConst(Literal(int32_t(HANG_LIMIT))),
+ Builder::Mutable);
wasm.addGlobal(glob);
auto* func = new Function;
func->name = "hangLimitInitializer";
func->result = none;
- func->body = builder.makeSetGlobal(glob->name,
- builder.makeConst(Literal(int32_t(HANG_LIMIT)))
- );
+ func->body = builder.makeSetGlobal(
+ glob->name, builder.makeConst(Literal(int32_t(HANG_LIMIT))));
wasm.addFunction(func);
auto* export_ = new Export;
@@ -370,7 +419,7 @@ private:
}
void addImportLoggingSupport() {
- for (auto type : { i32, i64, f32, f64 }) {
+ for (auto type : {i32, i64, f32, f64}) {
auto* func = new Function;
Name name = std::string("log-") + printType(type);
func->name = name;
@@ -386,21 +435,14 @@ private:
Expression* makeHangLimitCheck() {
return builder.makeSequence(
builder.makeIf(
- builder.makeUnary(
- UnaryOp::EqZInt32,
- builder.makeGetGlobal(HANG_LIMIT_GLOBAL, i32)
- ),
- makeTrivial(unreachable)
- ),
+ builder.makeUnary(UnaryOp::EqZInt32,
+ builder.makeGetGlobal(HANG_LIMIT_GLOBAL, i32)),
+ makeTrivial(unreachable)),
builder.makeSetGlobal(
HANG_LIMIT_GLOBAL,
- builder.makeBinary(
- BinaryOp::SubInt32,
- builder.makeGetGlobal(HANG_LIMIT_GLOBAL, i32),
- builder.makeConst(Literal(int32_t(1)))
- )
- )
- );
+ builder.makeBinary(BinaryOp::SubInt32,
+ builder.makeGetGlobal(HANG_LIMIT_GLOBAL, i32),
+ builder.makeConst(Literal(int32_t(1))))));
}
void addDeNanSupport() {
@@ -411,13 +453,9 @@ private:
func->result = type;
func->body = builder.makeIf(
builder.makeBinary(
- op,
- builder.makeGetLocal(0, type),
- builder.makeGetLocal(0, type)
- ),
+ op, builder.makeGetLocal(0, type), builder.makeGetLocal(0, type)),
builder.makeGetLocal(0, type),
- builder.makeConst(literal)
- );
+ builder.makeConst(literal));
wasm.addFunction(func);
};
add("deNan32", f32, Literal(float(0)), EqFloat32);
@@ -425,11 +463,12 @@ private:
}
Expression* makeDeNanOp(Expression* expr) {
- if (allowNaNs) return expr;
+ if (allowNaNs)
+ return expr;
if (expr->type == f32) {
- return builder.makeCall("deNan32", { expr }, f32);
+ return builder.makeCall("deNan32", {expr}, f32);
} else if (expr->type == f64) {
- return builder.makeCall("deNan64", { expr }, f64);
+ return builder.makeCall("deNan64", {expr}, f64);
}
return expr; // unreachable etc. is fine
}
@@ -444,7 +483,8 @@ private:
// which we try to minimize the risk of
std::vector<Expression*> hangStack;
- std::map<Type, std::vector<Index>> typeLocals; // type => list of locals with that type
+ std::map<Type, std::vector<Index>>
+ typeLocals; // type => list of locals with that type
Function* addFunction() {
LOGGING_PERCENT = upToSquared(100);
@@ -518,23 +558,19 @@ private:
// loop limit
FindAll<Loop> loops(func->body);
for (auto* loop : loops.list) {
- loop->body = builder.makeSequence(
- makeHangLimitCheck(),
- loop->body
- );
+ loop->body = builder.makeSequence(makeHangLimitCheck(), loop->body);
}
// recursion limit
- func->body = builder.makeSequence(
- makeHangLimitCheck(),
- func->body
- );
+ func->body = builder.makeSequence(makeHangLimitCheck(), func->body);
}
void recombine(Function* func) {
// Don't always do this.
- if (oneIn(2)) return;
+ if (oneIn(2))
+ return;
// First, scan and group all expressions by type.
- struct Scanner : public PostWalker<Scanner, UnifiedExpressionVisitor<Scanner>> {
+ struct Scanner
+ : public PostWalker<Scanner, UnifiedExpressionVisitor<Scanner>> {
// A map of all expressions, categorized by type.
std::map<Type, std::vector<Expression*>> exprsByType;
@@ -544,10 +580,11 @@ private:
};
Scanner scanner;
scanner.walk(func->body);
- // Potentially trim the list of possible picks, so replacements are more likely
- // to collide.
+ // Potentially trim the list of possible picks, so replacements are more
+ // likely to collide.
for (auto& pair : scanner.exprsByType) {
- if (oneIn(2)) continue;
+ if (oneIn(2))
+ continue;
auto& list = pair.second;
std::vector<Expression*> trimmed;
size_t num = upToSquared(list.size());
@@ -568,19 +605,22 @@ private:
// Second, with some probability replace an item with another item having
// the same type. (This is not always valid due to nesting of labels, but
// we'll fix that up later.)
- struct Modder : public PostWalker<Modder, UnifiedExpressionVisitor<Modder>> {
+ struct Modder
+ : public PostWalker<Modder, UnifiedExpressionVisitor<Modder>> {
Module& wasm;
Scanner& scanner;
TranslateToFuzzReader& parent;
- Modder(Module& wasm, Scanner& scanner, TranslateToFuzzReader& parent) : wasm(wasm), scanner(scanner), parent(parent) {}
+ Modder(Module& wasm, Scanner& scanner, TranslateToFuzzReader& parent)
+ : wasm(wasm), scanner(scanner), parent(parent) {}
void visitExpression(Expression* curr) {
if (parent.oneIn(10)) {
// Replace it!
auto& candidates = scanner.exprsByType[curr->type];
assert(!candidates.empty()); // this expression itself must be there
- replaceCurrent(ExpressionManipulator::copy(parent.vectorPick(candidates), wasm));
+ replaceCurrent(
+ ExpressionManipulator::copy(parent.vectorPick(candidates), wasm));
}
}
};
@@ -590,12 +630,15 @@ private:
void mutate(Function* func) {
// Don't always do this.
- if (oneIn(2)) return;
- struct Modder : public PostWalker<Modder, UnifiedExpressionVisitor<Modder>> {
+ if (oneIn(2))
+ return;
+ struct Modder
+ : public PostWalker<Modder, UnifiedExpressionVisitor<Modder>> {
Module& wasm;
TranslateToFuzzReader& parent;
- Modder(Module& wasm, TranslateToFuzzReader& parent) : wasm(wasm), parent(parent) {}
+ Modder(Module& wasm, TranslateToFuzzReader& parent)
+ : wasm(wasm), parent(parent) {}
void visitExpression(Expression* curr) {
if (parent.oneIn(10)) {
@@ -617,7 +660,8 @@ private:
Module& wasm;
TranslateToFuzzReader& parent;
- Fixer(Module& wasm, TranslateToFuzzReader& parent) : wasm(wasm), parent(parent) {}
+ Fixer(Module& wasm, TranslateToFuzzReader& parent)
+ : wasm(wasm), parent(parent) {}
// Track seen names to find duplication, which is invalid.
std::set<Name> seen;
@@ -644,14 +688,13 @@ private:
void visitSwitch(Switch* curr) {
for (auto name : curr->targets) {
- if (replaceIfInvalid(name)) return;
+ if (replaceIfInvalid(name))
+ return;
}
replaceIfInvalid(curr->default_);
}
- void visitBreak(Break* curr) {
- replaceIfInvalid(curr->name);
- }
+ void visitBreak(Break* curr) { replaceIfInvalid(curr->name); }
bool replaceIfInvalid(Name target) {
if (!hasBreakTarget(target)) {
@@ -662,24 +705,26 @@ private:
return false;
}
- void replace() {
- replaceCurrent(parent.makeTrivial(getCurrent()->type));
- }
+ void replace() { replaceCurrent(parent.makeTrivial(getCurrent()->type)); }
bool hasBreakTarget(Name name) {
- if (controlFlowStack.empty()) return false;
+ if (controlFlowStack.empty())
+ return false;
Index i = controlFlowStack.size() - 1;
while (1) {
auto* curr = controlFlowStack[i];
if (Block* block = curr->template dynCast<Block>()) {
- if (name == block->name) return true;
+ if (name == block->name)
+ return true;
} else if (Loop* loop = curr->template dynCast<Loop>()) {
- if (name == loop->name) return true;
+ if (name == loop->name)
+ return true;
} else {
// an if, ignorable
assert(curr->template is<If>());
}
- if (i == 0) return false;
+ if (i == 0)
+ return false;
i--;
}
}
@@ -709,7 +754,8 @@ private:
invocations.push_back(makeMemoryHashLogging());
}
}
- if (invocations.empty()) return;
+ if (invocations.empty())
+ return;
auto* invoker = new Function;
invoker->name = func->name.str + std::string("_invoker");
invoker->result = none;
@@ -733,8 +779,7 @@ private:
Expression* make(Type type) {
// when we should stop, emit something small (but not necessarily trivial)
- if (finishedInput ||
- nesting >= 5 * NESTING_LIMIT || // hard limit
+ if (finishedInput || nesting >= 5 * NESTING_LIMIT || // hard limit
(nesting >= NESTING_LIMIT && !oneIn(3))) {
if (isConcreteType(type)) {
if (oneIn(2)) {
@@ -759,9 +804,15 @@ private:
case i64:
case f32:
case f64:
- case v128: ret = _makeConcrete(type); break;
- case none: ret = _makenone(); break;
- case unreachable: ret = _makeunreachable(); break;
+ case v128:
+ ret = _makeConcrete(type);
+ break;
+ case none:
+ ret = _makenone();
+ break;
+ case unreachable:
+ ret = _makeunreachable();
+ break;
}
assert(ret->type == type); // we should create the right type of thing
nesting--;
@@ -770,31 +821,38 @@ private:
Expression* _makeConcrete(Type type) {
auto choice = upTo(100);
- if (choice < 10) return makeConst(type);
- if (choice < 30) return makeSetLocal(type);
- if (choice < 50) return makeGetLocal(type);
- if (choice < 60) return makeBlock(type);
- if (choice < 70) return makeIf(type);
- if (choice < 80) return makeLoop(type);
- if (choice < 90) return makeBreak(type);
+ if (choice < 10)
+ return makeConst(type);
+ if (choice < 30)
+ return makeSetLocal(type);
+ if (choice < 50)
+ return makeGetLocal(type);
+ if (choice < 60)
+ return makeBlock(type);
+ if (choice < 70)
+ return makeIf(type);
+ if (choice < 80)
+ return makeLoop(type);
+ if (choice < 90)
+ return makeBreak(type);
using Self = TranslateToFuzzReader;
auto options = FeatureOptions<Expression* (Self::*)(Type)>()
- .add(FeatureSet::MVP,
- &Self::makeBlock,
- &Self::makeIf,
- &Self::makeLoop,
- &Self::makeBreak,
- &Self::makeCall,
- &Self::makeCallIndirect,
- &Self::makeGetLocal,
- &Self::makeSetLocal,
- &Self::makeLoad,
- &Self::makeConst,
- &Self::makeUnary,
- &Self::makeBinary,
- &Self::makeSelect,
- &Self::makeGetGlobal)
- .add(FeatureSet::SIMD, &Self::makeSIMD);
+ .add(FeatureSet::MVP,
+ &Self::makeBlock,
+ &Self::makeIf,
+ &Self::makeLoop,
+ &Self::makeBreak,
+ &Self::makeCall,
+ &Self::makeCallIndirect,
+ &Self::makeGetLocal,
+ &Self::makeSetLocal,
+ &Self::makeLoad,
+ &Self::makeConst,
+ &Self::makeUnary,
+ &Self::makeBinary,
+ &Self::makeSelect,
+ &Self::makeGetGlobal)
+ .add(FeatureSet::SIMD, &Self::makeSIMD);
if (type == i32 || type == i64) {
options.add(FeatureSet::Atomics, &Self::makeAtomic);
}
@@ -811,46 +869,66 @@ private:
}
}
choice = upTo(100);
- if (choice < 50) return makeSetLocal(none);
- if (choice < 60) return makeBlock(none);
- if (choice < 70) return makeIf(none);
- if (choice < 80) return makeLoop(none);
- if (choice < 90) return makeBreak(none);
+ if (choice < 50)
+ return makeSetLocal(none);
+ if (choice < 60)
+ return makeBlock(none);
+ if (choice < 70)
+ return makeIf(none);
+ if (choice < 80)
+ return makeLoop(none);
+ if (choice < 90)
+ return makeBreak(none);
using Self = TranslateToFuzzReader;
auto options = FeatureOptions<Expression* (Self::*)(Type)>()
- .add(FeatureSet::MVP,
- &Self::makeBlock,
- &Self::makeIf,
- &Self::makeLoop,
- &Self::makeBreak,
- &Self::makeCall,
- &Self::makeCallIndirect,
- &Self::makeSetLocal,
- &Self::makeStore,
- &Self::makeDrop,
- &Self::makeNop,
- &Self::makeSetGlobal)
- .add(FeatureSet::BulkMemory, &Self::makeBulkMemory);
+ .add(FeatureSet::MVP,
+ &Self::makeBlock,
+ &Self::makeIf,
+ &Self::makeLoop,
+ &Self::makeBreak,
+ &Self::makeCall,
+ &Self::makeCallIndirect,
+ &Self::makeSetLocal,
+ &Self::makeStore,
+ &Self::makeDrop,
+ &Self::makeNop,
+ &Self::makeSetGlobal)
+ .add(FeatureSet::BulkMemory, &Self::makeBulkMemory);
return (this->*pick(options))(none);
}
Expression* _makeunreachable() {
switch (upTo(15)) {
- case 0: return makeBlock(unreachable);
- case 1: return makeIf(unreachable);
- case 2: return makeLoop(unreachable);
- case 3: return makeBreak(unreachable);
- case 4: return makeCall(unreachable);
- case 5: return makeCallIndirect(unreachable);
- case 6: return makeSetLocal(unreachable);
- case 7: return makeStore(unreachable);
- case 8: return makeUnary(unreachable);
- case 9: return makeBinary(unreachable);
- case 10: return makeSelect(unreachable);
- case 11: return makeSwitch(unreachable);
- case 12: return makeDrop(unreachable);
- case 13: return makeReturn(unreachable);
- case 14: return makeUnreachable(unreachable);
+ case 0:
+ return makeBlock(unreachable);
+ case 1:
+ return makeIf(unreachable);
+ case 2:
+ return makeLoop(unreachable);
+ case 3:
+ return makeBreak(unreachable);
+ case 4:
+ return makeCall(unreachable);
+ case 5:
+ return makeCallIndirect(unreachable);
+ case 6:
+ return makeSetLocal(unreachable);
+ case 7:
+ return makeStore(unreachable);
+ case 8:
+ return makeUnary(unreachable);
+ case 9:
+ return makeBinary(unreachable);
+ case 10:
+ return makeSelect(unreachable);
+ case 11:
+ return makeSwitch(unreachable);
+ case 12:
+ return makeDrop(unreachable);
+ case 13:
+ return makeReturn(unreachable);
+ case 14:
+ return makeUnreachable(unreachable);
}
WASM_UNREACHABLE();
}
@@ -932,7 +1010,8 @@ private:
// ensure a branch back. also optionally create some loop vars
std::vector<Expression*> list;
list.push_back(makeMaybeBlock(none)); // primary contents
- list.push_back(builder.makeBreak(ret->name, nullptr, makeCondition())); // possible branch back
+ // possible branch back
+ list.push_back(builder.makeBreak(ret->name, nullptr, makeCondition()));
list.push_back(make(type)); // final element, so we have the right type
ret->body = builder.makeBlock(list);
}
@@ -970,13 +1049,15 @@ private:
Expression* makeIf(Type type) {
auto* condition = makeCondition();
hangStack.push_back(nullptr);
- auto* ret = buildIf({ condition, makeMaybeBlock(type), makeMaybeBlock(type) });
+ auto* ret =
+ buildIf({condition, makeMaybeBlock(type), makeMaybeBlock(type)});
hangStack.pop_back();
return ret;
}
Expression* makeBreak(Type type) {
- if (breakableStack.empty()) return makeTrivial(type);
+ if (breakableStack.empty())
+ return makeTrivial(type);
Expression* condition = nullptr;
if (type != unreachable) {
hangStack.push_back(nullptr);
@@ -1029,15 +1110,18 @@ private:
}
switch (conditions) {
case 0: {
- if (!oneIn(4)) continue;
+ if (!oneIn(4))
+ continue;
break;
}
case 1: {
- if (!oneIn(2)) continue;
+ if (!oneIn(2))
+ continue;
break;
}
default: {
- if (oneIn(conditions + 1)) continue;
+ if (oneIn(conditions + 1))
+ continue;
}
}
return builder.makeBreak(name);
@@ -1058,7 +1142,8 @@ private:
if (!wasm.functions.empty() && !oneIn(wasm.functions.size())) {
target = vectorPick(wasm.functions).get();
}
- if (target->result != type) continue;
+ if (target->result != type)
+ continue;
// we found one!
std::vector<Expression*> args;
for (auto argType : target->params) {
@@ -1072,7 +1157,8 @@ private:
Expression* makeCallIndirect(Type type) {
auto& data = wasm.table.segments[0].data;
- if (data.empty()) return make(type);
+ if (data.empty())
+ return make(type);
// look for a call target with the right type
Index start = upTo(data.size());
Index i = start;
@@ -1084,8 +1170,10 @@ private:
break;
}
i++;
- if (i == data.size()) i = 0;
- if (i == start) return make(type);
+ if (i == data.size())
+ i = 0;
+ if (i == start)
+ return make(type);
}
// with high probability, make sure the type is valid otherwise, most are
// going to trap
@@ -1100,17 +1188,13 @@ private:
args.push_back(make(type));
}
func->type = ensureFunctionType(getSig(func), &wasm)->name;
- return builder.makeCallIndirect(
- func->type,
- target,
- args,
- func->result
- );
+ return builder.makeCallIndirect(func->type, target, args, func->result);
}
Expression* makeGetLocal(Type type) {
auto& locals = typeLocals[type];
- if (locals.empty()) return makeConst(type);
+ if (locals.empty())
+ return makeConst(type);
return builder.makeGetLocal(vectorPick(locals), type);
}
@@ -1123,7 +1207,8 @@ private:
valueType = getConcreteType();
}
auto& locals = typeLocals[valueType];
- if (locals.empty()) return makeTrivial(type);
+ if (locals.empty())
+ return makeTrivial(type);
auto* value = make(valueType);
if (tee) {
return builder.makeTeeLocal(vectorPick(locals), value);
@@ -1134,7 +1219,8 @@ private:
Expression* makeGetGlobal(Type type) {
auto& globals = globalsByType[type];
- if (globals.empty()) return makeConst(type);
+ if (globals.empty())
+ return makeConst(type);
return builder.makeGetGlobal(vectorPick(globals), type);
}
@@ -1142,7 +1228,8 @@ private:
assert(type == none);
type = getConcreteType();
auto& globals = globalsByType[type];
- if (globals.empty()) return makeTrivial(none);
+ if (globals.empty())
+ return makeTrivial(none);
auto* value = make(type);
return builder.makeSetGlobal(vectorPick(globals), value);
}
@@ -1153,10 +1240,8 @@ private:
// range. otherwise, most pointers are going to be out of range and
// most memory ops will just trap
if (!oneIn(10)) {
- ret = builder.makeBinary(AndInt32,
- ret,
- builder.makeConst(Literal(int32_t(USABLE_MEMORY - 1)))
- );
+ ret = builder.makeBinary(
+ AndInt32, ret, builder.makeConst(Literal(int32_t(USABLE_MEMORY - 1))));
}
return ret;
}
@@ -1168,19 +1253,29 @@ private:
case i32: {
bool signed_ = get() & 1;
switch (upTo(3)) {
- case 0: return builder.makeLoad(1, signed_, offset, 1, ptr, type);
- case 1: return builder.makeLoad(2, signed_, offset, pick(1, 2), ptr, type);
- case 2: return builder.makeLoad(4, signed_, offset, pick(1, 2, 4), ptr, type);
+ case 0:
+ return builder.makeLoad(1, signed_, offset, 1, ptr, type);
+ case 1:
+ return builder.makeLoad(2, signed_, offset, pick(1, 2), ptr, type);
+ case 2:
+ return builder.makeLoad(
+ 4, signed_, offset, pick(1, 2, 4), ptr, type);
}
WASM_UNREACHABLE();
}
case i64: {
bool signed_ = get() & 1;
switch (upTo(4)) {
- case 0: return builder.makeLoad(1, signed_, offset, 1, ptr, type);
- case 1: return builder.makeLoad(2, signed_, offset, pick(1, 2), ptr, type);
- case 2: return builder.makeLoad(4, signed_, offset, pick(1, 2, 4), ptr, type);
- case 3: return builder.makeLoad(8, signed_, offset, pick(1, 2, 4, 8), ptr, type);
+ case 0:
+ return builder.makeLoad(1, signed_, offset, 1, ptr, type);
+ case 1:
+ return builder.makeLoad(2, signed_, offset, pick(1, 2), ptr, type);
+ case 2:
+ return builder.makeLoad(
+ 4, signed_, offset, pick(1, 2, 4), ptr, type);
+ case 3:
+ return builder.makeLoad(
+ 8, signed_, offset, pick(1, 2, 4, 8), ptr, type);
}
WASM_UNREACHABLE();
}
@@ -1194,19 +1289,24 @@ private:
if (!wasm.features.hasSIMD()) {
return makeTrivial(type);
}
- return builder.makeLoad(16, false, offset, pick(1, 2, 4, 8, 16), ptr, type);
+ return builder.makeLoad(
+ 16, false, offset, pick(1, 2, 4, 8, 16), ptr, type);
}
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
WASM_UNREACHABLE();
}
Expression* makeLoad(Type type) {
- if (!allowMemory) return makeTrivial(type);
+ if (!allowMemory)
+ return makeTrivial(type);
auto* ret = makeNonAtomicLoad(type);
- if (type != i32 && type != i64) return ret;
- if (!wasm.features.hasAtomics() || oneIn(2)) return ret;
+ if (type != i32 && type != i64)
+ return ret;
+ if (!wasm.features.hasAtomics() || oneIn(2))
+ return ret;
// make it atomic
auto* load = ret->cast<Load>();
wasm.memory.shared = true;
@@ -1221,11 +1321,19 @@ private:
// make a normal store, then make it unreachable
auto* ret = makeNonAtomicStore(getConcreteType());
auto* store = ret->dynCast<Store>();
- if (!store) return ret;
+ if (!store)
+ return ret;
switch (upTo(3)) {
- case 0: store->ptr = make(unreachable); break;
- case 1: store->value = make(unreachable); break;
- case 2: store->ptr = make(unreachable); store->value = make(unreachable); break;
+ case 0:
+ store->ptr = make(unreachable);
+ break;
+ case 1:
+ store->value = make(unreachable);
+ break;
+ case 2:
+ store->ptr = make(unreachable);
+ store->value = make(unreachable);
+ break;
}
store->finalize();
return store;
@@ -1241,18 +1349,28 @@ private:
switch (type) {
case i32: {
switch (upTo(3)) {
- case 0: return builder.makeStore(1, offset, 1, ptr, value, type);
- case 1: return builder.makeStore(2, offset, pick(1, 2), ptr, value, type);
- case 2: return builder.makeStore(4, offset, pick(1, 2, 4), ptr, value, type);
+ case 0:
+ return builder.makeStore(1, offset, 1, ptr, value, type);
+ case 1:
+ return builder.makeStore(2, offset, pick(1, 2), ptr, value, type);
+ case 2:
+ return builder.makeStore(
+ 4, offset, pick(1, 2, 4), ptr, value, type);
}
WASM_UNREACHABLE();
}
case i64: {
switch (upTo(4)) {
- case 0: return builder.makeStore(1, offset, 1, ptr, value, type);
- case 1: return builder.makeStore(2, offset, pick(1, 2), ptr, value, type);
- case 2: return builder.makeStore(4, offset, pick(1, 2, 4), ptr, value, type);
- case 3: return builder.makeStore(8, offset, pick(1, 2, 4, 8), ptr, value, type);
+ case 0:
+ return builder.makeStore(1, offset, 1, ptr, value, type);
+ case 1:
+ return builder.makeStore(2, offset, pick(1, 2), ptr, value, type);
+ case 2:
+ return builder.makeStore(
+ 4, offset, pick(1, 2, 4), ptr, value, type);
+ case 3:
+ return builder.makeStore(
+ 8, offset, pick(1, 2, 4, 8), ptr, value, type);
}
WASM_UNREACHABLE();
}
@@ -1266,21 +1384,27 @@ private:
if (!wasm.features.hasSIMD()) {
return makeTrivial(type);
}
- return builder.makeStore(16, offset, pick(1, 2, 4, 8, 16), ptr, value, type);
+ return builder.makeStore(
+ 16, offset, pick(1, 2, 4, 8, 16), ptr, value, type);
}
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
WASM_UNREACHABLE();
}
Expression* makeStore(Type type) {
- if (!allowMemory) return makeTrivial(type);
+ if (!allowMemory)
+ return makeTrivial(type);
auto* ret = makeNonAtomicStore(type);
auto* store = ret->dynCast<Store>();
- if (!store) return ret;
- if (store->value->type != i32 && store->value->type != i64) return store;
- if (!wasm.features.hasAtomics() || oneIn(2)) return store;
+ if (!store)
+ return ret;
+ if (store->value->type != i32 && store->value->type != i64)
+ return store;
+ if (!wasm.features.hasAtomics() || oneIn(2))
+ return store;
// make it atomic
wasm.memory.shared = true;
store->isAtomic = true;
@@ -1292,25 +1416,50 @@ private:
if (type == v128) {
// generate each lane individually for random lane interpretation
switch (upTo(6)) {
- case 0: return Literal(
- std::array<Literal, 16>{{
- makeLiteral(i32), makeLiteral(i32), makeLiteral(i32), makeLiteral(i32),
- makeLiteral(i32), makeLiteral(i32), makeLiteral(i32), makeLiteral(i32),
- makeLiteral(i32), makeLiteral(i32), makeLiteral(i32), makeLiteral(i32),
- makeLiteral(i32), makeLiteral(i32), makeLiteral(i32), makeLiteral(i32)
- }}
- );
- case 1: return Literal(
- std::array<Literal, 8>{{
- makeLiteral(i32), makeLiteral(i32), makeLiteral(i32), makeLiteral(i32),
- makeLiteral(i32), makeLiteral(i32), makeLiteral(i32), makeLiteral(i32)
- }}
- );
- case 2: return Literal(std::array<Literal, 4>{{makeLiteral(i32), makeLiteral(i32), makeLiteral(i32), makeLiteral(i32)}});
- case 3: return Literal(std::array<Literal, 2>{{makeLiteral(i64), makeLiteral(i64)}});
- case 4: return Literal(std::array<Literal, 4>{{makeLiteral(f32), makeLiteral(f32), makeLiteral(f32), makeLiteral(f32)}});
- case 5: return Literal(std::array<Literal, 2>{{makeLiteral(f64), makeLiteral(f64)}});
- default: WASM_UNREACHABLE();
+ case 0:
+ return Literal(std::array<Literal, 16>{{makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32)}});
+ case 1:
+ return Literal(std::array<Literal, 8>{{makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32)}});
+ case 2:
+ return Literal(std::array<Literal, 4>{{makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32),
+ makeLiteral(i32)}});
+ case 3:
+ return Literal(
+ std::array<Literal, 2>{{makeLiteral(i64), makeLiteral(i64)}});
+ case 4:
+ return Literal(std::array<Literal, 4>{{makeLiteral(f32),
+ makeLiteral(f32),
+ makeLiteral(f32),
+ makeLiteral(f32)}});
+ case 5:
+ return Literal(
+ std::array<Literal, 2>{{makeLiteral(f64), makeLiteral(f64)}});
+ default:
+ WASM_UNREACHABLE();
}
}
@@ -1318,13 +1467,18 @@ private:
case 0: {
// totally random, entire range
switch (type) {
- case i32: return Literal(get32());
- case i64: return Literal(get64());
- case f32: return Literal(getFloat());
- case f64: return Literal(getDouble());
+ case i32:
+ return Literal(get32());
+ case i64:
+ return Literal(get64());
+ case f32:
+ return Literal(getFloat());
+ case f64:
+ return Literal(getDouble());
case v128:
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
break;
}
@@ -1332,22 +1486,40 @@ private:
// small range
int64_t small;
switch (upTo(6)) {
- case 0: small = int8_t(get()); break;
- case 1: small = uint8_t(get()); break;
- case 2: small = int16_t(get16()); break;
- case 3: small = uint16_t(get16()); break;
- case 4: small = int32_t(get32()); break;
- case 5: small = uint32_t(get32()); break;
- default: WASM_UNREACHABLE();
+ case 0:
+ small = int8_t(get());
+ break;
+ case 1:
+ small = uint8_t(get());
+ break;
+ case 2:
+ small = int16_t(get16());
+ break;
+ case 3:
+ small = uint16_t(get16());
+ break;
+ case 4:
+ small = int32_t(get32());
+ break;
+ case 5:
+ small = uint32_t(get32());
+ break;
+ default:
+ WASM_UNREACHABLE();
}
switch (type) {
- case i32: return Literal(int32_t(small));
- case i64: return Literal(int64_t(small));
- case f32: return Literal(float(small));
- case f64: return Literal(double(small));
+ case i32:
+ return Literal(int32_t(small));
+ case i64:
+ return Literal(int64_t(small));
+ case f32:
+ return Literal(float(small));
+ case f64:
+ return Literal(double(small));
case v128:
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
break;
}
@@ -1355,38 +1527,63 @@ private:
// special values
Literal value;
switch (type) {
- case i32: value = Literal(pick<int32_t>(0,
- std::numeric_limits<int8_t>::min(), std::numeric_limits<int8_t>::max(),
- std::numeric_limits<int16_t>::min(), std::numeric_limits<int16_t>::max(),
- std::numeric_limits<int32_t>::min(), std::numeric_limits<int32_t>::max(),
- std::numeric_limits<uint8_t>::max(),
- std::numeric_limits<uint16_t>::max(),
- std::numeric_limits<uint32_t>::max())); break;
- case i64: value = Literal(pick<int64_t>(0,
- std::numeric_limits<int8_t>::min(), std::numeric_limits<int8_t>::max(),
- std::numeric_limits<int16_t>::min(), std::numeric_limits<int16_t>::max(),
- std::numeric_limits<int32_t>::min(), std::numeric_limits<int32_t>::max(),
- std::numeric_limits<int64_t>::min(), std::numeric_limits<int64_t>::max(),
- std::numeric_limits<uint8_t>::max(),
- std::numeric_limits<uint16_t>::max(),
- std::numeric_limits<uint32_t>::max(),
- std::numeric_limits<uint64_t>::max())); break;
- case f32: value = Literal(pick<float>(0,
- std::numeric_limits<float>::min(), std::numeric_limits<float>::max(),
- std::numeric_limits<int32_t>::min(), std::numeric_limits<int32_t>::max(),
- std::numeric_limits<int64_t>::min(), std::numeric_limits<int64_t>::max(),
- std::numeric_limits<uint32_t>::max(),
- std::numeric_limits<uint64_t>::max())); break;
- case f64: value = Literal(pick<double>(0,
- std::numeric_limits<float>::min(), std::numeric_limits<float>::max(),
- std::numeric_limits<double>::min(), std::numeric_limits<double>::max(),
- std::numeric_limits<int32_t>::min(), std::numeric_limits<int32_t>::max(),
- std::numeric_limits<int64_t>::min(), std::numeric_limits<int64_t>::max(),
- std::numeric_limits<uint32_t>::max(),
- std::numeric_limits<uint64_t>::max())); break;
+ case i32:
+ value =
+ Literal(pick<int32_t>(0,
+ std::numeric_limits<int8_t>::min(),
+ std::numeric_limits<int8_t>::max(),
+ std::numeric_limits<int16_t>::min(),
+ std::numeric_limits<int16_t>::max(),
+ std::numeric_limits<int32_t>::min(),
+ std::numeric_limits<int32_t>::max(),
+ std::numeric_limits<uint8_t>::max(),
+ std::numeric_limits<uint16_t>::max(),
+ std::numeric_limits<uint32_t>::max()));
+ break;
+ case i64:
+ value =
+ Literal(pick<int64_t>(0,
+ std::numeric_limits<int8_t>::min(),
+ std::numeric_limits<int8_t>::max(),
+ std::numeric_limits<int16_t>::min(),
+ std::numeric_limits<int16_t>::max(),
+ std::numeric_limits<int32_t>::min(),
+ std::numeric_limits<int32_t>::max(),
+ std::numeric_limits<int64_t>::min(),
+ std::numeric_limits<int64_t>::max(),
+ std::numeric_limits<uint8_t>::max(),
+ std::numeric_limits<uint16_t>::max(),
+ std::numeric_limits<uint32_t>::max(),
+ std::numeric_limits<uint64_t>::max()));
+ break;
+ case f32:
+ value = Literal(pick<float>(0,
+ std::numeric_limits<float>::min(),
+ std::numeric_limits<float>::max(),
+ std::numeric_limits<int32_t>::min(),
+ std::numeric_limits<int32_t>::max(),
+ std::numeric_limits<int64_t>::min(),
+ std::numeric_limits<int64_t>::max(),
+ std::numeric_limits<uint32_t>::max(),
+ std::numeric_limits<uint64_t>::max()));
+ break;
+ case f64:
+ value = Literal(pick<double>(0,
+ std::numeric_limits<float>::min(),
+ std::numeric_limits<float>::max(),
+ std::numeric_limits<double>::min(),
+ std::numeric_limits<double>::max(),
+ std::numeric_limits<int32_t>::min(),
+ std::numeric_limits<int32_t>::max(),
+ std::numeric_limits<int64_t>::min(),
+ std::numeric_limits<int64_t>::max(),
+ std::numeric_limits<uint32_t>::max(),
+ std::numeric_limits<uint64_t>::max()));
+ break;
case v128:
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
// tweak around special values
if (oneIn(3)) { // +- 1
@@ -1401,13 +1598,22 @@ private:
// powers of 2
Literal value;
switch (type) {
- case i32: value = Literal(int32_t(1) << upTo(32)); break;
- case i64: value = Literal(int64_t(1) << upTo(64)); break;
- case f32: value = Literal(float(int64_t(1) << upTo(64))); break;
- case f64: value = Literal(double(int64_t(1) << upTo(64))); break;
+ case i32:
+ value = Literal(int32_t(1) << upTo(32));
+ break;
+ case i64:
+ value = Literal(int64_t(1) << upTo(64));
+ break;
+ case f32:
+ value = Literal(float(int64_t(1) << upTo(64)));
+ break;
+ case f64:
+ value = Literal(double(int64_t(1) << upTo(64)));
+ break;
case v128:
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
// maybe negative
if (oneIn(2)) {
@@ -1452,105 +1658,178 @@ private:
case i32: {
auto op = pick(
FeatureOptions<UnaryOp>()
- .add(FeatureSet::MVP, EqZInt32, ClzInt32, CtzInt32, PopcntInt32)
- .add(FeatureSet::Atomics, ExtendS8Int32, ExtendS16Int32)
- );
- return buildUnary({ op, make(i32) });
+ .add(FeatureSet::MVP, EqZInt32, ClzInt32, CtzInt32, PopcntInt32)
+ .add(FeatureSet::Atomics, ExtendS8Int32, ExtendS16Int32));
+ return buildUnary({op, make(i32)});
}
- case i64: return buildUnary({ pick(EqZInt64, WrapInt64), make(i64) });
+ case i64:
+ return buildUnary({pick(EqZInt64, WrapInt64), make(i64)});
case f32: {
- auto op = pick(
- FeatureOptions<UnaryOp>()
- .add(FeatureSet::MVP, TruncSFloat32ToInt32, TruncUFloat32ToInt32, ReinterpretFloat32)
- .add(FeatureSet::TruncSat, TruncSatSFloat32ToInt32, TruncSatUFloat32ToInt32)
- );
- return buildUnary({ op, make(f32) });
+ auto op = pick(FeatureOptions<UnaryOp>()
+ .add(FeatureSet::MVP,
+ TruncSFloat32ToInt32,
+ TruncUFloat32ToInt32,
+ ReinterpretFloat32)
+ .add(FeatureSet::TruncSat,
+ TruncSatSFloat32ToInt32,
+ TruncSatUFloat32ToInt32));
+ return buildUnary({op, make(f32)});
}
case f64: {
- auto op = pick(
- FeatureOptions<UnaryOp>()
- .add(FeatureSet::MVP, TruncSFloat64ToInt32, TruncUFloat64ToInt32)
- .add(FeatureSet::TruncSat, TruncSatSFloat64ToInt32, TruncSatUFloat64ToInt32)
- );
- return buildUnary({ op, make(f64) });
+ auto op = pick(FeatureOptions<UnaryOp>()
+ .add(FeatureSet::MVP,
+ TruncSFloat64ToInt32,
+ TruncUFloat64ToInt32)
+ .add(FeatureSet::TruncSat,
+ TruncSatSFloat64ToInt32,
+ TruncSatUFloat64ToInt32));
+ return buildUnary({op, make(f64)});
}
case v128: {
assert(wasm.features.hasSIMD());
- return buildUnary({ pick(AnyTrueVecI8x16, AllTrueVecI8x16, AnyTrueVecI16x8, AllTrueVecI16x8,
- AnyTrueVecI32x4, AllTrueVecI32x4, AnyTrueVecI64x2, AllTrueVecI64x2),
- make(v128) });
+ return buildUnary({pick(AnyTrueVecI8x16,
+ AllTrueVecI8x16,
+ AnyTrueVecI16x8,
+ AllTrueVecI16x8,
+ AnyTrueVecI32x4,
+ AllTrueVecI32x4,
+ AnyTrueVecI64x2,
+ AllTrueVecI64x2),
+ make(v128)});
}
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
WASM_UNREACHABLE();
}
case i64: {
switch (upTo(4)) {
case 0: {
- auto op = pick(
- FeatureOptions<UnaryOp>()
- .add(FeatureSet::MVP, ClzInt64, CtzInt64, PopcntInt64)
- .add(FeatureSet::Atomics, ExtendS8Int64, ExtendS16Int64, ExtendS32Int64)
- );
- return buildUnary({ op, make(i64) });
+ auto op =
+ pick(FeatureOptions<UnaryOp>()
+ .add(FeatureSet::MVP, ClzInt64, CtzInt64, PopcntInt64)
+ .add(FeatureSet::Atomics,
+ ExtendS8Int64,
+ ExtendS16Int64,
+ ExtendS32Int64));
+ return buildUnary({op, make(i64)});
}
- case 1: return buildUnary({ pick(ExtendSInt32, ExtendUInt32), make(i32) });
+ case 1:
+ return buildUnary({pick(ExtendSInt32, ExtendUInt32), make(i32)});
case 2: {
- auto op = pick(
- FeatureOptions<UnaryOp>()
- .add(FeatureSet::MVP, TruncSFloat32ToInt64, TruncUFloat32ToInt64)
- .add(FeatureSet::TruncSat, TruncSatSFloat32ToInt64, TruncSatUFloat32ToInt64)
- );
- return buildUnary({ op, make(f32) });
+ auto op = pick(FeatureOptions<UnaryOp>()
+ .add(FeatureSet::MVP,
+ TruncSFloat32ToInt64,
+ TruncUFloat32ToInt64)
+ .add(FeatureSet::TruncSat,
+ TruncSatSFloat32ToInt64,
+ TruncSatUFloat32ToInt64));
+ return buildUnary({op, make(f32)});
}
case 3: {
- auto op = pick(
- FeatureOptions<UnaryOp>()
- .add(FeatureSet::MVP, TruncSFloat64ToInt64, TruncUFloat64ToInt64, ReinterpretFloat64)
- .add(FeatureSet::TruncSat, TruncSatSFloat64ToInt64, TruncSatUFloat64ToInt64)
- );
- return buildUnary({ op, make(f64) });
+ auto op = pick(FeatureOptions<UnaryOp>()
+ .add(FeatureSet::MVP,
+ TruncSFloat64ToInt64,
+ TruncUFloat64ToInt64,
+ ReinterpretFloat64)
+ .add(FeatureSet::TruncSat,
+ TruncSatSFloat64ToInt64,
+ TruncSatUFloat64ToInt64));
+ return buildUnary({op, make(f64)});
}
}
WASM_UNREACHABLE();
}
case f32: {
switch (upTo(4)) {
- case 0: return makeDeNanOp(buildUnary({ pick(NegFloat32, AbsFloat32, CeilFloat32, FloorFloat32, TruncFloat32, NearestFloat32, SqrtFloat32), make(f32) }));
- case 1: return makeDeNanOp(buildUnary({ pick(ConvertUInt32ToFloat32, ConvertSInt32ToFloat32, ReinterpretInt32), make(i32) }));
- case 2: return makeDeNanOp(buildUnary({ pick(ConvertUInt64ToFloat32, ConvertSInt64ToFloat32), make(i64) }));
- case 3: return makeDeNanOp(buildUnary({ DemoteFloat64, make(f64) }));
+ case 0:
+ return makeDeNanOp(buildUnary({pick(NegFloat32,
+ AbsFloat32,
+ CeilFloat32,
+ FloorFloat32,
+ TruncFloat32,
+ NearestFloat32,
+ SqrtFloat32),
+ make(f32)}));
+ case 1:
+ return makeDeNanOp(buildUnary({pick(ConvertUInt32ToFloat32,
+ ConvertSInt32ToFloat32,
+ ReinterpretInt32),
+ make(i32)}));
+ case 2:
+ return makeDeNanOp(
+ buildUnary({pick(ConvertUInt64ToFloat32, ConvertSInt64ToFloat32),
+ make(i64)}));
+ case 3:
+ return makeDeNanOp(buildUnary({DemoteFloat64, make(f64)}));
}
WASM_UNREACHABLE();
}
case f64: {
switch (upTo(4)) {
- case 0: return makeDeNanOp(buildUnary({ pick(NegFloat64, AbsFloat64, CeilFloat64, FloorFloat64, TruncFloat64, NearestFloat64, SqrtFloat64), make(f64) }));
- case 1: return makeDeNanOp(buildUnary({ pick(ConvertUInt32ToFloat64, ConvertSInt32ToFloat64), make(i32) }));
- case 2: return makeDeNanOp(buildUnary({ pick(ConvertUInt64ToFloat64, ConvertSInt64ToFloat64, ReinterpretInt64), make(i64) }));
- case 3: return makeDeNanOp(buildUnary({ PromoteFloat32, make(f32) }));
+ case 0:
+ return makeDeNanOp(buildUnary({pick(NegFloat64,
+ AbsFloat64,
+ CeilFloat64,
+ FloorFloat64,
+ TruncFloat64,
+ NearestFloat64,
+ SqrtFloat64),
+ make(f64)}));
+ case 1:
+ return makeDeNanOp(
+ buildUnary({pick(ConvertUInt32ToFloat64, ConvertSInt32ToFloat64),
+ make(i32)}));
+ case 2:
+ return makeDeNanOp(buildUnary({pick(ConvertUInt64ToFloat64,
+ ConvertSInt64ToFloat64,
+ ReinterpretInt64),
+ make(i64)}));
+ case 3:
+ return makeDeNanOp(buildUnary({PromoteFloat32, make(f32)}));
}
WASM_UNREACHABLE();
}
case v128: {
assert(wasm.features.hasSIMD());
switch (upTo(5)) {
- case 0: return buildUnary({ pick(SplatVecI8x16, SplatVecI16x8, SplatVecI32x4), make(i32) });
- case 1: return buildUnary({ SplatVecI64x2, make(i64) });
- case 2: return buildUnary({ SplatVecF32x4, make(f32) });
- case 3: return buildUnary({ SplatVecF64x2, make(f64) });
- case 4: return buildUnary({
- pick(NotVec128, NegVecI8x16, NegVecI16x8, NegVecI32x4, NegVecI64x2,
- AbsVecF32x4, NegVecF32x4, SqrtVecF32x4, AbsVecF64x2, NegVecF64x2, SqrtVecF64x2,
- TruncSatSVecF32x4ToVecI32x4, TruncSatUVecF32x4ToVecI32x4, TruncSatSVecF64x2ToVecI64x2, TruncSatUVecF64x2ToVecI64x2,
- ConvertSVecI32x4ToVecF32x4, ConvertUVecI32x4ToVecF32x4, ConvertSVecI64x2ToVecF64x2, ConvertUVecI64x2ToVecF64x2),
- make(v128) });
+ case 0:
+ return buildUnary(
+ {pick(SplatVecI8x16, SplatVecI16x8, SplatVecI32x4), make(i32)});
+ case 1:
+ return buildUnary({SplatVecI64x2, make(i64)});
+ case 2:
+ return buildUnary({SplatVecF32x4, make(f32)});
+ case 3:
+ return buildUnary({SplatVecF64x2, make(f64)});
+ case 4:
+ return buildUnary({pick(NotVec128,
+ NegVecI8x16,
+ NegVecI16x8,
+ NegVecI32x4,
+ NegVecI64x2,
+ AbsVecF32x4,
+ NegVecF32x4,
+ SqrtVecF32x4,
+ AbsVecF64x2,
+ NegVecF64x2,
+ SqrtVecF64x2,
+ TruncSatSVecF32x4ToVecI32x4,
+ TruncSatUVecF32x4ToVecI32x4,
+ TruncSatSVecF64x2ToVecI64x2,
+ TruncSatUVecF64x2ToVecI64x2,
+ ConvertSVecI32x4ToVecF32x4,
+ ConvertUVecI32x4ToVecF32x4,
+ ConvertSVecI64x2ToVecF64x2,
+ ConvertUVecI64x2ToVecF64x2),
+ make(v128)});
}
WASM_UNREACHABLE();
}
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
WASM_UNREACHABLE();
}
@@ -1562,7 +1841,8 @@ private:
Expression* makeBinary(Type type) {
if (type == unreachable) {
if (auto* binary = makeBinary(getConcreteType())->dynCast<Binary>()) {
- return makeDeNanOp(buildBinary({ binary->op, make(unreachable), make(unreachable) }));
+ return makeDeNanOp(
+ buildBinary({binary->op, make(unreachable), make(unreachable)}));
}
// give up
return makeTrivial(type);
@@ -1570,37 +1850,193 @@ private:
switch (type) {
case i32: {
switch (upTo(4)) {
- case 0: return buildBinary({ pick(AddInt32, SubInt32, MulInt32, DivSInt32, DivUInt32, RemSInt32, RemUInt32, AndInt32, OrInt32, XorInt32, ShlInt32, ShrUInt32, ShrSInt32, RotLInt32, RotRInt32, EqInt32, NeInt32, LtSInt32, LtUInt32, LeSInt32, LeUInt32, GtSInt32, GtUInt32, GeSInt32, GeUInt32), make(i32), make(i32) });
- case 1: return buildBinary({ pick(EqInt64, NeInt64, LtSInt64, LtUInt64, LeSInt64, LeUInt64, GtSInt64, GtUInt64, GeSInt64, GeUInt64), make(i64), make(i64) });
- case 2: return buildBinary({ pick(EqFloat32, NeFloat32, LtFloat32, LeFloat32, GtFloat32, GeFloat32), make(f32), make(f32) });
- case 3: return buildBinary({ pick(EqFloat64, NeFloat64, LtFloat64, LeFloat64, GtFloat64, GeFloat64), make(f64), make(f64) });
+ case 0:
+ return buildBinary({pick(AddInt32,
+ SubInt32,
+ MulInt32,
+ DivSInt32,
+ DivUInt32,
+ RemSInt32,
+ RemUInt32,
+ AndInt32,
+ OrInt32,
+ XorInt32,
+ ShlInt32,
+ ShrUInt32,
+ ShrSInt32,
+ RotLInt32,
+ RotRInt32,
+ EqInt32,
+ NeInt32,
+ LtSInt32,
+ LtUInt32,
+ LeSInt32,
+ LeUInt32,
+ GtSInt32,
+ GtUInt32,
+ GeSInt32,
+ GeUInt32),
+ make(i32),
+ make(i32)});
+ case 1:
+ return buildBinary({pick(EqInt64,
+ NeInt64,
+ LtSInt64,
+ LtUInt64,
+ LeSInt64,
+ LeUInt64,
+ GtSInt64,
+ GtUInt64,
+ GeSInt64,
+ GeUInt64),
+ make(i64),
+ make(i64)});
+ case 2:
+ return buildBinary({pick(EqFloat32,
+ NeFloat32,
+ LtFloat32,
+ LeFloat32,
+ GtFloat32,
+ GeFloat32),
+ make(f32),
+ make(f32)});
+ case 3:
+ return buildBinary({pick(EqFloat64,
+ NeFloat64,
+ LtFloat64,
+ LeFloat64,
+ GtFloat64,
+ GeFloat64),
+ make(f64),
+ make(f64)});
}
WASM_UNREACHABLE();
}
case i64: {
- return buildBinary({ pick(AddInt64, SubInt64, MulInt64, DivSInt64, DivUInt64, RemSInt64, RemUInt64, AndInt64, OrInt64, XorInt64, ShlInt64, ShrUInt64, ShrSInt64, RotLInt64, RotRInt64), make(i64), make(i64) });
+ return buildBinary({pick(AddInt64,
+ SubInt64,
+ MulInt64,
+ DivSInt64,
+ DivUInt64,
+ RemSInt64,
+ RemUInt64,
+ AndInt64,
+ OrInt64,
+ XorInt64,
+ ShlInt64,
+ ShrUInt64,
+ ShrSInt64,
+ RotLInt64,
+ RotRInt64),
+ make(i64),
+ make(i64)});
}
case f32: {
- return makeDeNanOp(buildBinary({ pick(AddFloat32, SubFloat32, MulFloat32, DivFloat32, CopySignFloat32, MinFloat32, MaxFloat32), make(f32), make(f32) }));
+ return makeDeNanOp(buildBinary({pick(AddFloat32,
+ SubFloat32,
+ MulFloat32,
+ DivFloat32,
+ CopySignFloat32,
+ MinFloat32,
+ MaxFloat32),
+ make(f32),
+ make(f32)}));
}
case f64: {
- return makeDeNanOp(buildBinary({ pick(AddFloat64, SubFloat64, MulFloat64, DivFloat64, CopySignFloat64, MinFloat64, MaxFloat64), make(f64), make(f64) }));
+ return makeDeNanOp(buildBinary({pick(AddFloat64,
+ SubFloat64,
+ MulFloat64,
+ DivFloat64,
+ CopySignFloat64,
+ MinFloat64,
+ MaxFloat64),
+ make(f64),
+ make(f64)}));
}
case v128: {
assert(wasm.features.hasSIMD());
- return buildBinary({
- pick(EqVecI8x16, NeVecI8x16, LtSVecI8x16, LtUVecI8x16, GtSVecI8x16, GtUVecI8x16, LeSVecI8x16, LeUVecI8x16, GeSVecI8x16, GeUVecI8x16,
- EqVecI16x8, NeVecI16x8, LtSVecI16x8, LtUVecI16x8, GtSVecI16x8, GtUVecI16x8, LeSVecI16x8, LeUVecI16x8, GeSVecI16x8, GeUVecI16x8,
- EqVecI32x4, NeVecI32x4, LtSVecI32x4, LtUVecI32x4, GtSVecI32x4, GtUVecI32x4, LeSVecI32x4, LeUVecI32x4, GeSVecI32x4, GeUVecI32x4,
- EqVecF32x4, NeVecF32x4, LtVecF32x4, GtVecF32x4, LeVecF32x4, GeVecF32x4, EqVecF64x2, NeVecF64x2, LtVecF64x2, GtVecF64x2, LeVecF64x2, GeVecF64x2,
- AndVec128, OrVec128, XorVec128, AddVecI8x16, AddSatSVecI8x16, AddSatUVecI8x16, SubVecI8x16, SubSatSVecI8x16, SubSatUVecI8x16, MulVecI8x16,
- AddVecI16x8, AddSatSVecI16x8, AddSatUVecI16x8, SubVecI16x8, SubSatSVecI16x8, SubSatUVecI16x8, MulVecI16x8, AddVecI32x4, SubVecI32x4, MulVecI32x4,
- AddVecI64x2, SubVecI64x2, AddVecF32x4, SubVecF32x4, MulVecF32x4, DivVecF32x4, MinVecF32x4, MaxVecF32x4,
- AddVecF64x2, SubVecF64x2, MulVecF64x2, DivVecF64x2, MinVecF64x2, MaxVecF64x2),
- make(v128), make(v128) });
+ return buildBinary({pick(EqVecI8x16,
+ NeVecI8x16,
+ LtSVecI8x16,
+ LtUVecI8x16,
+ GtSVecI8x16,
+ GtUVecI8x16,
+ LeSVecI8x16,
+ LeUVecI8x16,
+ GeSVecI8x16,
+ GeUVecI8x16,
+ EqVecI16x8,
+ NeVecI16x8,
+ LtSVecI16x8,
+ LtUVecI16x8,
+ GtSVecI16x8,
+ GtUVecI16x8,
+ LeSVecI16x8,
+ LeUVecI16x8,
+ GeSVecI16x8,
+ GeUVecI16x8,
+ EqVecI32x4,
+ NeVecI32x4,
+ LtSVecI32x4,
+ LtUVecI32x4,
+ GtSVecI32x4,
+ GtUVecI32x4,
+ LeSVecI32x4,
+ LeUVecI32x4,
+ GeSVecI32x4,
+ GeUVecI32x4,
+ EqVecF32x4,
+ NeVecF32x4,
+ LtVecF32x4,
+ GtVecF32x4,
+ LeVecF32x4,
+ GeVecF32x4,
+ EqVecF64x2,
+ NeVecF64x2,
+ LtVecF64x2,
+ GtVecF64x2,
+ LeVecF64x2,
+ GeVecF64x2,
+ AndVec128,
+ OrVec128,
+ XorVec128,
+ AddVecI8x16,
+ AddSatSVecI8x16,
+ AddSatUVecI8x16,
+ SubVecI8x16,
+ SubSatSVecI8x16,
+ SubSatUVecI8x16,
+ MulVecI8x16,
+ AddVecI16x8,
+ AddSatSVecI16x8,
+ AddSatUVecI16x8,
+ SubVecI16x8,
+ SubSatSVecI16x8,
+ SubSatUVecI16x8,
+ MulVecI16x8,
+ AddVecI32x4,
+ SubVecI32x4,
+ MulVecI32x4,
+ AddVecI64x2,
+ SubVecI64x2,
+ AddVecF32x4,
+ SubVecF32x4,
+ MulVecF32x4,
+ DivVecF32x4,
+ MinVecF32x4,
+ MaxVecF32x4,
+ AddVecF64x2,
+ SubVecF64x2,
+ MulVecF64x2,
+ DivVecF64x2,
+ MinVecF64x2,
+ MaxVecF64x2),
+ make(v128),
+ make(v128)});
}
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
WASM_UNREACHABLE();
}
@@ -1610,12 +2046,13 @@ private:
}
Expression* makeSelect(Type type) {
- return makeDeNanOp(buildSelect({ make(i32), make(type), make(type) }));
+ return makeDeNanOp(buildSelect({make(i32), make(type), make(type)}));
}
Expression* makeSwitch(Type type) {
assert(type == unreachable);
- if (breakableStack.empty()) return make(type);
+ if (breakableStack.empty())
+ return make(type);
// we need to find proper targets to break to; try a bunch
int tries = TRIES;
std::vector<Name> names;
@@ -1639,16 +2076,19 @@ private:
}
auto default_ = names.back();
names.pop_back();
- auto temp1 = make(i32), temp2 = isConcreteType(valueType) ? make(valueType) : nullptr;
+ auto temp1 = make(i32),
+ temp2 = isConcreteType(valueType) ? make(valueType) : nullptr;
return builder.makeSwitch(names, default_, temp1, temp2);
}
Expression* makeDrop(Type type) {
- return builder.makeDrop(make(type == unreachable ? type : getConcreteType()));
+ return builder.makeDrop(
+ make(type == unreachable ? type : getConcreteType()));
}
Expression* makeReturn(Type type) {
- return builder.makeReturn(isConcreteType(func->result) ? make(func->result) : nullptr);
+ return builder.makeReturn(isConcreteType(func->result) ? make(func->result)
+ : nullptr);
}
Expression* makeNop(Type type) {
@@ -1663,7 +2103,8 @@ private:
Expression* makeAtomic(Type type) {
assert(wasm.features.hasAtomics());
- if (!allowMemory) return makeTrivial(type);
+ if (!allowMemory)
+ return makeTrivial(type);
wasm.memory.shared = true;
if (type == i32 && oneIn(2)) {
if (ATOMIC_WAITS && oneIn(2)) {
@@ -1671,7 +2112,8 @@ private:
auto expectedType = pick(i32, i64);
auto* expected = make(expectedType);
auto* timeout = make(i64);
- return builder.makeAtomicWait(ptr, expected, timeout, expectedType, logify(get()));
+ return builder.makeAtomicWait(
+ ptr, expected, timeout, expectedType, logify(get()));
} else {
auto* ptr = makePointer();
auto* count = make(i32);
@@ -1682,35 +2124,62 @@ private:
switch (type) {
case i32: {
switch (upTo(3)) {
- case 0: bytes = 1; break;
- case 1: bytes = pick(1, 2); break;
- case 2: bytes = pick(1, 2, 4); break;
- default: WASM_UNREACHABLE();
+ case 0:
+ bytes = 1;
+ break;
+ case 1:
+ bytes = pick(1, 2);
+ break;
+ case 2:
+ bytes = pick(1, 2, 4);
+ break;
+ default:
+ WASM_UNREACHABLE();
}
break;
}
case i64: {
switch (upTo(4)) {
- case 0: bytes = 1; break;
- case 1: bytes = pick(1, 2); break;
- case 2: bytes = pick(1, 2, 4); break;
- case 3: bytes = pick(1, 2, 4, 8); break;
- default: WASM_UNREACHABLE();
+ case 0:
+ bytes = 1;
+ break;
+ case 1:
+ bytes = pick(1, 2);
+ break;
+ case 2:
+ bytes = pick(1, 2, 4);
+ break;
+ case 3:
+ bytes = pick(1, 2, 4, 8);
+ break;
+ default:
+ WASM_UNREACHABLE();
}
break;
}
- default: WASM_UNREACHABLE();
+ default:
+ WASM_UNREACHABLE();
}
auto offset = logify(get());
auto* ptr = makePointer();
if (oneIn(2)) {
auto* value = make(type);
- return builder.makeAtomicRMW(pick(AtomicRMWOp::Add, AtomicRMWOp::Sub, AtomicRMWOp::And, AtomicRMWOp::Or, AtomicRMWOp::Xor, AtomicRMWOp::Xchg),
- bytes, offset, ptr, value, type);
+ return builder.makeAtomicRMW(pick(AtomicRMWOp::Add,
+ AtomicRMWOp::Sub,
+ AtomicRMWOp::And,
+ AtomicRMWOp::Or,
+ AtomicRMWOp::Xor,
+ AtomicRMWOp::Xchg),
+ bytes,
+ offset,
+ ptr,
+ value,
+ type);
} else {
auto* expected = make(type);
auto* replacement = make(type);
- return builder.makeAtomicCmpxchg(bytes, offset, ptr, expected, replacement, type);
+ return builder.makeAtomicCmpxchg(
+ bytes, offset, ptr, expected, replacement, type);
}
}
@@ -1720,12 +2189,18 @@ private:
return makeSIMDExtract(type);
}
switch (upTo(6)) {
- case 0: return makeUnary(v128);
- case 1: return makeBinary(v128);
- case 2: return makeSIMDReplace();
- case 3: return makeSIMDShuffle();
- case 4: return makeSIMDBitselect();
- case 5: return makeSIMDShift();
+ case 0:
+ return makeUnary(v128);
+ case 1:
+ return makeBinary(v128);
+ case 2:
+ return makeSIMDReplace();
+ case 3:
+ return makeSIMDShuffle();
+ case 4:
+ return makeSIMDBitselect();
+ case 5:
+ return makeSIMDShift();
}
WASM_UNREACHABLE();
}
@@ -1733,43 +2208,87 @@ private:
Expression* makeSIMDExtract(Type type) {
auto op = static_cast<SIMDExtractOp>(0);
switch (type) {
- case i32: op = pick(ExtractLaneSVecI8x16, ExtractLaneUVecI8x16, ExtractLaneSVecI16x8, ExtractLaneUVecI16x8, ExtractLaneVecI32x4); break;
- case i64: op = ExtractLaneVecI64x2; break;
- case f32: op = ExtractLaneVecF32x4; break;
- case f64: op = ExtractLaneVecF64x2; break;
+ case i32:
+ op = pick(ExtractLaneSVecI8x16,
+ ExtractLaneUVecI8x16,
+ ExtractLaneSVecI16x8,
+ ExtractLaneUVecI16x8,
+ ExtractLaneVecI32x4);
+ break;
+ case i64:
+ op = ExtractLaneVecI64x2;
+ break;
+ case f32:
+ op = ExtractLaneVecF32x4;
+ break;
+ case f64:
+ op = ExtractLaneVecF64x2;
+ break;
case v128:
case none:
- case unreachable: WASM_UNREACHABLE();
+ case unreachable:
+ WASM_UNREACHABLE();
}
Expression* vec = make(v128);
uint8_t index = 0;
switch (op) {
case ExtractLaneSVecI8x16:
- case ExtractLaneUVecI8x16: index = upTo(16); break;
+ case ExtractLaneUVecI8x16:
+ index = upTo(16);
+ break;
case ExtractLaneSVecI16x8:
- case ExtractLaneUVecI16x8: index = upTo(8); break;
+ case ExtractLaneUVecI16x8:
+ index = upTo(8);
+ break;
case ExtractLaneVecI32x4:
- case ExtractLaneVecF32x4: index = upTo(4); break;
+ case ExtractLaneVecF32x4:
+ index = upTo(4);
+ break;
case ExtractLaneVecI64x2:
- case ExtractLaneVecF64x2: index = upTo(2); break;
+ case ExtractLaneVecF64x2:
+ index = upTo(2);
+ break;
}
return builder.makeSIMDExtract(op, vec, index);
}
Expression* makeSIMDReplace() {
- SIMDReplaceOp op = pick(ReplaceLaneVecI8x16, ReplaceLaneVecI16x8, ReplaceLaneVecI32x4,
- ReplaceLaneVecI64x2, ReplaceLaneVecF32x4, ReplaceLaneVecF64x2);
+ SIMDReplaceOp op = pick(ReplaceLaneVecI8x16,
+ ReplaceLaneVecI16x8,
+ ReplaceLaneVecI32x4,
+ ReplaceLaneVecI64x2,
+ ReplaceLaneVecF32x4,
+ ReplaceLaneVecF64x2);
Expression* vec = make(v128);
uint8_t index;
Type lane_t;
switch (op) {
- case ReplaceLaneVecI8x16: index = upTo(16); lane_t = i32; break;
- case ReplaceLaneVecI16x8: index = upTo(8); lane_t = i32; break;
- case ReplaceLaneVecI32x4: index = upTo(4); lane_t = i32; break;
- case ReplaceLaneVecI64x2: index = upTo(2); lane_t = i64; break;
- case ReplaceLaneVecF32x4: index = upTo(4); lane_t = f32; break;
- case ReplaceLaneVecF64x2: index = upTo(2); lane_t = f64; break;
- default: WASM_UNREACHABLE();
+ case ReplaceLaneVecI8x16:
+ index = upTo(16);
+ lane_t = i32;
+ break;
+ case ReplaceLaneVecI16x8:
+ index = upTo(8);
+ lane_t = i32;
+ break;
+ case ReplaceLaneVecI32x4:
+ index = upTo(4);
+ lane_t = i32;
+ break;
+ case ReplaceLaneVecI64x2:
+ index = upTo(2);
+ lane_t = i64;
+ break;
+ case ReplaceLaneVecF32x4:
+ index = upTo(4);
+ lane_t = f32;
+ break;
+ case ReplaceLaneVecF64x2:
+ index = upTo(2);
+ lane_t = f64;
+ break;
+ default:
+ WASM_UNREACHABLE();
}
Expression* value = make(lane_t);
return builder.makeSIMDReplace(op, vec, index, value);
@@ -1793,28 +2312,44 @@ private:
}
Expression* makeSIMDShift() {
- SIMDShiftOp op = pick(ShlVecI8x16, ShrSVecI8x16, ShrUVecI8x16, ShlVecI16x8, ShrSVecI16x8, ShrUVecI16x8,
- ShlVecI32x4, ShrSVecI32x4, ShrUVecI32x4, ShlVecI64x2, ShrSVecI64x2, ShrUVecI64x2);
+ SIMDShiftOp op = pick(ShlVecI8x16,
+ ShrSVecI8x16,
+ ShrUVecI8x16,
+ ShlVecI16x8,
+ ShrSVecI16x8,
+ ShrUVecI16x8,
+ ShlVecI32x4,
+ ShrSVecI32x4,
+ ShrUVecI32x4,
+ ShlVecI64x2,
+ ShrSVecI64x2,
+ ShrUVecI64x2);
Expression* vec = make(v128);
Expression* shift = make(i32);
return builder.makeSIMDShift(op, vec, shift);
}
Expression* makeBulkMemory(Type type) {
- if (!allowMemory) return makeTrivial(type);
+ if (!allowMemory)
+ return makeTrivial(type);
assert(wasm.features.hasBulkMemory());
assert(type == none);
switch (upTo(4)) {
- case 0: return makeMemoryInit();
- case 1: return makeDataDrop();
- case 2: return makeMemoryCopy();
- case 3: return makeMemoryFill();
+ case 0:
+ return makeMemoryInit();
+ case 1:
+ return makeDataDrop();
+ case 2:
+ return makeMemoryCopy();
+ case 3:
+ return makeMemoryFill();
}
WASM_UNREACHABLE();
}
Expression* makeMemoryInit() {
- if (!allowMemory) return makeTrivial(none);
+ if (!allowMemory)
+ return makeTrivial(none);
uint32_t segment = upTo(wasm.memory.segments.size());
size_t totalSize = wasm.memory.segments[segment].data.size();
size_t offsetVal = upTo(totalSize);
@@ -1826,12 +2361,14 @@ private:
}
Expression* makeDataDrop() {
- if (!allowMemory) return makeTrivial(none);
+ if (!allowMemory)
+ return makeTrivial(none);
return builder.makeDataDrop(upTo(wasm.memory.segments.size()));
}
Expression* makeMemoryCopy() {
- if (!allowMemory) return makeTrivial(none);
+ if (!allowMemory)
+ return makeTrivial(none);
Expression* dest = makePointer();
Expression* source = makePointer();
Expression* size = make(i32);
@@ -1839,7 +2376,8 @@ private:
}
Expression* makeMemoryFill() {
- if (!allowMemory) return makeTrivial(none);
+ if (!allowMemory)
+ return makeTrivial(none);
Expression* dest = makePointer();
Expression* value = makePointer();
Expression* size = make(i32);
@@ -1850,32 +2388,33 @@ private:
Expression* makeLogging() {
auto type = pick(i32, i64, f32, f64);
- return builder.makeCall(std::string("log-") + printType(type), { make(type) }, none);
+ return builder.makeCall(
+ std::string("log-") + printType(type), {make(type)}, none);
}
Expression* makeMemoryHashLogging() {
auto* hash = builder.makeCall(std::string("hashMemory"), {}, i32);
- return builder.makeCall(std::string("log-i32"), { hash }, none);
+ return builder.makeCall(std::string("log-i32"), {hash}, none);
}
// special getters
Type getType() {
return pick(FeatureOptions<Type>()
- .add(FeatureSet::MVP, i32, i64, f32, f64, none, unreachable)
- .add(FeatureSet::SIMD, v128));
+ .add(FeatureSet::MVP, i32, i64, f32, f64, none, unreachable)
+ .add(FeatureSet::SIMD, v128));
}
Type getReachableType() {
return pick(FeatureOptions<Type>()
- .add(FeatureSet::MVP, i32, i64, f32, f64, none)
- .add(FeatureSet::SIMD, v128));
+ .add(FeatureSet::MVP, i32, i64, f32, f64, none)
+ .add(FeatureSet::SIMD, v128));
}
Type getConcreteType() {
return pick(FeatureOptions<Type>()
- .add(FeatureSet::MVP, i32, i64, f32, f64)
- .add(FeatureSet::SIMD, v128));
+ .add(FeatureSet::MVP, i32, i64, f32, f64)
+ .add(FeatureSet::SIMD, v128));
}
// statistical distributions
@@ -1889,7 +2428,8 @@ private:
// this isn't a perfectly uniform distribution, but it's fast
// and reasonable
Index upTo(Index x) {
- if (x == 0) return 0;
+ if (x == 0)
+ return 0;
Index raw;
if (x <= 255) {
raw = get();
@@ -1904,9 +2444,7 @@ private:
return ret;
}
- bool oneIn(Index x) {
- return upTo(x) == 0;
- }
+ bool oneIn(Index x) { return upTo(x) == 0; }
bool onceEvery(Index x) {
static int counter = 0;
@@ -1916,69 +2454,60 @@ private:
// apply upTo twice, generating a skewed distribution towards
// low values
- Index upToSquared(Index x) {
- return upTo(upTo(x));
- }
+ Index upToSquared(Index x) { return upTo(upTo(x)); }
// pick from a vector
- template<typename T>
- const T& vectorPick(const std::vector<T>& vec) {
+ template<typename T> const T& vectorPick(const std::vector<T>& vec) {
assert(!vec.empty());
auto index = upTo(vec.size());
return vec[index];
}
// pick from a fixed list
- template<typename T, typename... Args>
- T pick(T first, Args... args) {
+ template<typename T, typename... Args> T pick(T first, Args... args) {
auto num = sizeof...(Args) + 1;
auto temp = upTo(num);
return pickGivenNum<T>(temp, first, args...);
}
- template<typename T>
- T pickGivenNum(size_t num, T first) {
+ template<typename T> T pickGivenNum(size_t num, T first) {
assert(num == 0);
return first;
}
- // Trick to avoid a bug in GCC 7.x.
- // Upstream bug report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82800
- #define GCC_VERSION (__GNUC__ * 10000 \
- + __GNUC_MINOR__ * 100 \
- + __GNUC_PATCHLEVEL__)
- #if GCC_VERSION > 70000 && GCC_VERSION < 70300
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
- #endif
+// Trick to avoid a bug in GCC 7.x.
+// Upstream bug report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82800
+#define GCC_VERSION \
+ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
+#if GCC_VERSION > 70000 && GCC_VERSION < 70300
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#endif
template<typename T, typename... Args>
T pickGivenNum(size_t num, T first, Args... args) {
- if (num == 0) return first;
+ if (num == 0)
+ return first;
return pickGivenNum<T>(num - 1, args...);
}
- #if GCC_VERSION > 70000 && GCC_VERSION < 70300
- #pragma GCC diagnostic pop
- #endif
+#if GCC_VERSION > 70000 && GCC_VERSION < 70300
+#pragma GCC diagnostic pop
+#endif
- template<typename T>
- struct FeatureOptions {
- template<typename ...Ts>
+ template<typename T> struct FeatureOptions {
+ template<typename... Ts>
FeatureOptions<T>& add(FeatureSet::Feature feature, T option, Ts... rest) {
options[feature].push_back(option);
return add(feature, rest...);
}
- FeatureOptions<T>& add(FeatureSet::Feature feature) {
- return *this;
- }
+ FeatureOptions<T>& add(FeatureSet::Feature feature) { return *this; }
std::map<FeatureSet::Feature, std::vector<T>> options;
};
- template<typename T>
- const T pick(FeatureOptions<T>& picker) {
+ template<typename T> const T pick(FeatureOptions<T>& picker) {
std::vector<T> matches;
for (const auto& item : picker.options) {
if (wasm.features.has(item.first)) {
@@ -2012,6 +2541,7 @@ private:
} // namespace wasm
-// XXX Switch class has a condition?! is it real? should the node type be the value type if it exists?!
+// XXX Switch class has a condition?! is it real? should the node type be the
+// value type if it exists?!
// TODO copy an existing function and replace just one node in it