summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/passes/RemoveUnusedBrs.cpp36
-rw-r--r--src/tools/translate-to-fuzz.h18
-rw-r--r--src/tools/wasm-opt.cpp69
-rw-r--r--src/wasm-builder.h4
-rw-r--r--src/wasm/wasm.cpp4
5 files changed, 105 insertions, 26 deletions
diff --git a/src/passes/RemoveUnusedBrs.cpp b/src/passes/RemoveUnusedBrs.cpp
index 8994c7fe2..e627ce138 100644
--- a/src/passes/RemoveUnusedBrs.cpp
+++ b/src/passes/RemoveUnusedBrs.cpp
@@ -31,6 +31,8 @@ namespace wasm {
// condition and possible value, and the possible value must
// not have side effects (as they would run unconditionally)
static bool canTurnIfIntoBrIf(Expression* ifCondition, Expression* brValue, PassOptions& options) {
+ // if the if isn't even taken, this is all dead code anyhow
+ if (ifCondition->type == unreachable) return false;
if (!brValue) return true;
EffectAnalyzer value(options, brValue);
if (value.hasSideEffects()) return false;
@@ -72,7 +74,7 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
flows.push_back(currp);
self->valueCanFlow = true; // start optimistic
} else {
- self->valueCanFlow = false;
+ self->stopValueFlow();
}
} else if (curr->is<Return>()) {
flows.clear();
@@ -80,6 +82,11 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
self->valueCanFlow = true; // start optimistic
} else if (curr->is<If>()) {
auto* iff = curr->cast<If>();
+ if (iff->condition->type == unreachable) {
+ // avoid trying to optimize this, we never reach it anyhow
+ self->stopFlow();
+ return;
+ }
if (iff->ifFalse) {
assert(self->ifStack.size() > 0);
for (auto* flow : self->ifStack.back()) {
@@ -88,7 +95,7 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
self->ifStack.pop_back();
} else {
// if without else stops the flow of values
- self->valueCanFlow = false;
+ self->stopValueFlow();
}
} else if (curr->is<Block>()) {
// any breaks flowing to here are unnecessary, as we get here anyhow
@@ -126,16 +133,31 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
}
} else if (curr->is<Nop>()) {
// ignore (could be result of a previous cycle)
- self->valueCanFlow = false;
+ self->stopValueFlow();
} else if (curr->is<Loop>()) {
// do nothing - it's ok for values to flow out
} else {
// anything else stops the flow
- flows.clear();
- self->valueCanFlow = false;
+ self->stopFlow();
}
}
+ void stopFlow() {
+ flows.clear();
+ valueCanFlow = false;
+ }
+
+ void stopValueFlow() {
+ flows.erase(std::remove_if(flows.begin(), flows.end(), [&](Expression** currp) {
+ auto* curr = *currp;
+ if (auto* ret = curr->dynCast<Return>()) {
+ return ret->value;
+ }
+ return curr->cast<Break>()->value;
+ }), flows.end());
+ valueCanFlow = false;
+ }
+
static void clear(RemoveUnusedBrs* self, Expression** currp) {
self->flows.clear();
}
@@ -171,6 +193,10 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
auto* iff = (*currp)->dynCast<If>();
if (iff) {
+ if (iff->condition->type == unreachable) {
+ // avoid trying to optimize this, we never reach it anyhow
+ return;
+ }
self->pushTask(doVisitIf, currp);
if (iff->ifFalse) {
// we need to join up if-else control flow, and clear after the condition
diff --git a/src/tools/translate-to-fuzz.h b/src/tools/translate-to-fuzz.h
index a7f86af13..307604af6 100644
--- a/src/tools/translate-to-fuzz.h
+++ b/src/tools/translate-to-fuzz.h
@@ -87,7 +87,7 @@ private:
// the number of runtime iterations (function calls, loop backbranches) we
// allow before we stop execution with a trap, to prevent hangs. 0 means
// no hang protection.
- static const int HANG_LIMIT = 25;
+ static const int HANG_LIMIT = 100;
// Optionally remove NaNs, which are a source of nondeterminism (which makes
// cross-VM comparisons harder)
@@ -452,14 +452,20 @@ private:
// make something with no chance of infinite recursion
Expression* makeTrivial(WasmType type) {
if (isConcreteWasmType(type)) {
- return makeConst(type);
+ if (oneIn(2)) {
+ return makeGetLocal(type);
+ } else {
+ return makeConst(type);
+ }
} else if (type == none) {
return makeNop(type);
}
assert(type == unreachable);
- return builder.makeReturn(
- isConcreteWasmType(func->result) ? makeConst(func->result) : nullptr
- );
+ Expression* ret = nullptr;
+ if (isConcreteWasmType(func->result)) {
+ ret = makeTrivial(func->result);
+ }
+ return builder.makeReturn(ret);
}
// specific expression creators
@@ -650,7 +656,7 @@ private:
Expression* makeGetLocal(WasmType type) {
auto& locals = typeLocals[type];
- if (locals.empty()) return makeTrivial(type);
+ if (locals.empty()) return makeConst(type);
return builder.makeGetLocal(vectorPick(locals), type);
}
diff --git a/src/tools/wasm-opt.cpp b/src/tools/wasm-opt.cpp
index c34331366..a66bc612f 100644
--- a/src/tools/wasm-opt.cpp
+++ b/src/tools/wasm-opt.cpp
@@ -39,6 +39,23 @@
using namespace wasm;
+// runs a command and returns its output TODO: portability, return code checking
+std::string runCommand(std::string command) {
+#ifdef __linux__
+ std::string output;
+ const int MAX_BUFFER = 1024;
+ char buffer[MAX_BUFFER];
+ FILE *stream = popen(command.c_str(), "r");
+ while (fgets(buffer, MAX_BUFFER, stream) != NULL) {
+ output.append(buffer);
+ }
+ pclose(stream);
+ return output;
+#else
+ Fatal() << "TODO: portability for wasm-opt runCommand";
+#endif
+}
+
//
// main
//
@@ -50,6 +67,7 @@ int main(int argc, const char* argv[]) {
bool debugInfo = false;
bool fuzzExec = false;
bool fuzzBinary = false;
+ std::string extraFuzzCommand;
bool translateToFuzz = false;
std::string emitJSWrapper;
std::string emitSpecWrapper;
@@ -74,6 +92,9 @@ int main(int argc, const char* argv[]) {
.add("--fuzz-binary", "-fb", "Convert to binary and back after optimizations and before fuzz-exec, helping fuzzing find binary format bugs",
Options::Arguments::Zero,
[&](Options *o, const std::string &arguments) { fuzzBinary = true; })
+ .add("--extra-fuzz-command", "-efc", "An extra command to run on the output before and after optimizing. The output is compared between the two, and an error occurs if they are not equal",
+ Options::Arguments::One,
+ [&](Options *o, const std::string &arguments) { extraFuzzCommand = arguments; })
.add("--translate-to-fuzz", "-ttf", "Translate the input into a valid wasm module *somehow*, useful for fuzzing",
Options::Arguments::Zero,
[&](Options *o, const std::string &arguments) { translateToFuzz = true; })
@@ -123,6 +144,33 @@ int main(int argc, const char* argv[]) {
results.get(wasm);
}
+ if (emitJSWrapper.size() > 0) {
+ std::ofstream outfile;
+ outfile.open(emitJSWrapper, std::ofstream::out);
+ outfile << generateJSWrapper(wasm);
+ outfile.close();
+ }
+
+ if (emitSpecWrapper.size() > 0) {
+ std::ofstream outfile;
+ outfile.open(emitSpecWrapper, std::ofstream::out);
+ outfile << generateSpecWrapper(wasm);
+ outfile.close();
+ }
+
+ std::string firstOutput;
+
+ if (extraFuzzCommand.size() > 0 && options.extra.count("output") > 0) {
+ if (options.debug) std::cerr << "writing binary before opts, for extra fuzz command..." << std::endl;
+ ModuleWriter writer;
+ writer.setDebug(options.debug);
+ writer.setBinary(emitBinary);
+ writer.setDebugInfo(debugInfo);
+ writer.write(wasm, options.extra["output"]);
+ firstOutput = runCommand(extraFuzzCommand);
+ std::cout << "[extra-fuzz-command first output:]\n" << firstOutput << '\n';
+ }
+
if (options.runningPasses()) {
if (options.debug) std::cerr << "running passes...\n";
PassRunner passRunner = options.getPassRunner(wasm);
@@ -155,19 +203,14 @@ int main(int argc, const char* argv[]) {
writer.setBinary(emitBinary);
writer.setDebugInfo(debugInfo);
writer.write(wasm, options.extra["output"]);
- }
-
- if (emitJSWrapper.size() > 0) {
- std::ofstream outfile;
- outfile.open(emitJSWrapper, std::ofstream::out);
- outfile << generateJSWrapper(wasm);
- outfile.close();
- }
- if (emitSpecWrapper.size() > 0) {
- std::ofstream outfile;
- outfile.open(emitSpecWrapper, std::ofstream::out);
- outfile << generateSpecWrapper(wasm);
- outfile.close();
+ if (extraFuzzCommand.size() > 0) {
+ auto secondOutput = runCommand(extraFuzzCommand);
+ std::cout << "[extra-fuzz-command second output:]\n" << firstOutput << '\n';
+ if (firstOutput != secondOutput) {
+ std::cerr << "extra fuzz command output differs\n";
+ abort();
+ }
+ }
}
}
diff --git a/src/wasm-builder.h b/src/wasm-builder.h
index 4ef4b1e0b..7432562d1 100644
--- a/src/wasm-builder.h
+++ b/src/wasm-builder.h
@@ -164,14 +164,14 @@ public:
auto* ret = allocator.alloc<SetLocal>();
ret->index = index;
ret->value = value;
- ret->type = none;
+ ret->finalize();
return ret;
}
SetLocal* makeTeeLocal(Index index, Expression* value) {
auto* ret = allocator.alloc<SetLocal>();
ret->index = index;
ret->value = value;
- ret->type = value->type;
+ ret->setTee(true);
return ret;
}
GetGlobal* makeGetGlobal(Name name, WasmType type) {
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
index f82a06e68..ab2db6bd5 100644
--- a/src/wasm/wasm.cpp
+++ b/src/wasm/wasm.cpp
@@ -332,6 +332,10 @@ void SetLocal::setTee(bool is) {
void SetLocal::finalize() {
if (value->type == unreachable) {
type = unreachable;
+ } else if (isTee()) {
+ type = value->type;
+ } else {
+ type = none;
}
}