diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ast_utils.h | 66 | ||||
-rw-r--r-- | src/pass.h | 4 | ||||
-rw-r--r-- | src/passes/CodePushing.cpp | 19 | ||||
-rw-r--r-- | src/passes/MergeBlocks.cpp | 10 | ||||
-rw-r--r-- | src/passes/OptimizeInstructions.cpp | 8 | ||||
-rw-r--r-- | src/passes/RemoveUnusedBrs.cpp | 27 | ||||
-rw-r--r-- | src/passes/SimplifyLocals.cpp | 10 | ||||
-rw-r--r-- | src/passes/Vacuum.cpp | 24 | ||||
-rw-r--r-- | src/tools/optimization-options.h | 13 |
9 files changed, 121 insertions, 60 deletions
diff --git a/src/ast_utils.h b/src/ast_utils.h index 2a151d8f7..35ad96987 100644 --- a/src/ast_utils.h +++ b/src/ast_utils.h @@ -71,11 +71,13 @@ struct BreakSeeker : public PostWalker<BreakSeeker, Visitor<BreakSeeker>> { // TODO: optimize struct EffectAnalyzer : public PostWalker<EffectAnalyzer, Visitor<EffectAnalyzer>> { - EffectAnalyzer() {} - EffectAnalyzer(Expression *ast) { - analyze(ast); + EffectAnalyzer(PassOptions& passOptions, Expression *ast = nullptr) { + ignoreImplicitTraps = passOptions.ignoreImplicitTraps; + if (ast) analyze(ast); } + bool ignoreImplicitTraps; + void analyze(Expression *ast) { breakNames.clear(); walk(ast); @@ -91,12 +93,18 @@ struct EffectAnalyzer : public PostWalker<EffectAnalyzer, Visitor<EffectAnalyzer std::set<Name> globalsWritten; bool readsMemory = false; bool writesMemory = false; + bool implicitTrap = false; // a load or div/rem, which may trap. we ignore trap + // differences, so it is ok to reorder these, and we + // also allow reordering them with other effects + // (so a trap may occur later or earlier, if it is + // going to occur anyhow), but we can't remove them, + // they count as side effects bool accessesLocal() { return localsRead.size() + localsWritten.size() > 0; } bool accessesGlobal() { return globalsRead.size() + globalsWritten.size() > 0; } bool accessesMemory() { return calls || readsMemory || writesMemory; } - bool hasSideEffects() { return calls || localsWritten.size() > 0 || writesMemory || branches || globalsWritten.size() > 0; } - bool hasAnything() { return branches || calls || accessesLocal() || readsMemory || writesMemory || accessesGlobal(); } + bool hasSideEffects() { return calls || localsWritten.size() > 0 || writesMemory || branches || globalsWritten.size() > 0 || implicitTrap; } + bool hasAnything() { return branches || calls || accessesLocal() || readsMemory || writesMemory || accessesGlobal() || implicitTrap; } // checks if these effects would invalidate another set (e.g., if we write, we invalidate someone that reads, they can't be moved past us) bool invalidates(EffectAnalyzer& other) { @@ -124,6 +132,10 @@ struct EffectAnalyzer : public PostWalker<EffectAnalyzer, Visitor<EffectAnalyzer for (auto global : globalsRead) { if (other.globalsWritten.count(global)) return true; } + // we are ok to reorder implicit traps, but not conditionalize them + if ((implicitTrap && other.branches) || (other.implicitTrap && branches)) { + return true; + } return false; } @@ -189,8 +201,48 @@ struct EffectAnalyzer : public PostWalker<EffectAnalyzer, Visitor<EffectAnalyzer void visitSetGlobal(SetGlobal *curr) { globalsWritten.insert(curr->name); } - void visitLoad(Load *curr) { readsMemory = true; } - void visitStore(Store *curr) { writesMemory = true; } + void visitLoad(Load *curr) { + readsMemory = true; + if (!ignoreImplicitTraps) implicitTrap = true; + } + void visitStore(Store *curr) { + writesMemory = true; + if (!ignoreImplicitTraps) implicitTrap = true; + } + void visitUnary(Unary *curr) { + if (!ignoreImplicitTraps) { + switch (curr->op) { + case TruncSFloat32ToInt32: + case TruncSFloat32ToInt64: + case TruncUFloat32ToInt32: + case TruncUFloat32ToInt64: + case TruncSFloat64ToInt32: + case TruncSFloat64ToInt64: + case TruncUFloat64ToInt32: + case TruncUFloat64ToInt64: { + implicitTrap = true; + } + default: {} + } + } + } + void visitBinary(Binary *curr) { + if (!ignoreImplicitTraps) { + switch (curr->op) { + case DivSInt32: + case DivUInt32: + case RemSInt32: + case RemUInt32: + case DivSInt64: + case DivUInt64: + case RemSInt64: + case RemUInt64: { + implicitTrap = true; + } + default: {} + } + } + } void visitReturn(Return *curr) { branches = true; } void visitHost(Host *curr) { calls = true; } void visitUnreachable(Unreachable *curr) { branches = true; } diff --git a/src/pass.h b/src/pass.h index dc9159aa0..74579e162 100644 --- a/src/pass.h +++ b/src/pass.h @@ -200,6 +200,10 @@ public: return runner; } + PassOptions& getPassOptions() { + return runner->options; + } + void setPassRunner(PassRunner* runner_) { runner = runner_; } diff --git a/src/passes/CodePushing.cpp b/src/passes/CodePushing.cpp index f4beff1a8..55b15ac9d 100644 --- a/src/passes/CodePushing.cpp +++ b/src/passes/CodePushing.cpp @@ -83,9 +83,10 @@ class Pusher { ExpressionList& list; LocalAnalyzer& analyzer; std::vector<Index>& numGetsSoFar; + PassOptions& passOptions; public: - Pusher(Block* block, LocalAnalyzer& analyzer, std::vector<Index>& numGetsSoFar) : list(block->list), analyzer(analyzer), numGetsSoFar(numGetsSoFar) { + Pusher(Block* block, LocalAnalyzer& analyzer, std::vector<Index>& numGetsSoFar, PassOptions& passOptions) : list(block->list), analyzer(analyzer), numGetsSoFar(numGetsSoFar), passOptions(passOptions) { // Find an optimization segment: from the first pushable thing, to the first // point past which we want to push. We then push in that range before // continuing forward. @@ -119,7 +120,7 @@ private: // but also have no side effects, as it may not execute if pushed. if (analyzer.isSFA(index) && numGetsSoFar[index] == analyzer.getNumGets(index) && - !EffectAnalyzer(set->value).hasSideEffects()) { + !EffectAnalyzer(passOptions, set->value).hasSideEffects()) { return set; } return nullptr; @@ -146,8 +147,8 @@ private: // of earlier ones. Once we know all we can push, we push it all // in one pass, keeping the order of the pushables intact. assert(firstPushable != Index(-1) && pushPoint != Index(-1) && firstPushable < pushPoint); - EffectAnalyzer cumulativeEffects; // everything that matters if you want - // to be pushed past the pushPoint + EffectAnalyzer cumulativeEffects(passOptions); // everything that matters if you want + // to be pushed past the pushPoint cumulativeEffects.analyze(list[pushPoint]); cumulativeEffects.branches = false; // it is ok to ignore the branching here, // that is the crucial point of this opt @@ -158,9 +159,13 @@ private: if (pushable) { auto iter = pushableEffects.find(pushable); if (iter == pushableEffects.end()) { - pushableEffects.emplace(pushable, pushable); + iter = pushableEffects.emplace( + std::piecewise_construct, + std::forward_as_tuple(pushable), + std::forward_as_tuple(passOptions, pushable) + ).first; } - auto& effects = pushableEffects[pushable]; + auto& effects = iter->second; if (cumulativeEffects.invalidates(effects)) { // we can't push this, so further pushables must pass it cumulativeEffects.mergeIn(effects); @@ -248,7 +253,7 @@ struct CodePushing : public WalkerPass<PostWalker<CodePushing, Visitor<CodePushi // ordering invalidation issue, since if this isn't a loop, it's fine (we're not // used outside), and if it is, we hit the assign before any use (as we can't // push it past a use). - Pusher pusher(curr, analyzer, numGetsSoFar); + Pusher pusher(curr, analyzer, numGetsSoFar, getPassOptions()); } }; diff --git a/src/passes/MergeBlocks.cpp b/src/passes/MergeBlocks.cpp index 383837beb..f8d044212 100644 --- a/src/passes/MergeBlocks.cpp +++ b/src/passes/MergeBlocks.cpp @@ -216,9 +216,9 @@ struct MergeBlocks : public WalkerPass<PostWalker<MergeBlocks, Visitor<MergeBloc if (!child) return outer; if ((dependency1 && *dependency1) || (dependency2 && *dependency2)) { // there are dependencies, things we must be reordered through. make sure no problems there - EffectAnalyzer childEffects(child); - if (dependency1 && *dependency1 && EffectAnalyzer(*dependency1).invalidates(childEffects)) return outer; - if (dependency2 && *dependency2 && EffectAnalyzer(*dependency2).invalidates(childEffects)) return outer; + EffectAnalyzer childEffects(getPassOptions(), child); + if (dependency1 && *dependency1 && EffectAnalyzer(getPassOptions(), *dependency1).invalidates(childEffects)) return outer; + if (dependency2 && *dependency2 && EffectAnalyzer(getPassOptions(), *dependency2).invalidates(childEffects)) return outer; } if (auto* block = child->dynCast<Block>()) { if (!block->name.is() && block->list.size() >= 2) { @@ -278,7 +278,7 @@ struct MergeBlocks : public WalkerPass<PostWalker<MergeBlocks, Visitor<MergeBloc void handleCall(T* curr, Block* outer = nullptr) { for (Index i = 0; i < curr->operands.size(); i++) { outer = optimize(curr, curr->operands[i], outer); - if (EffectAnalyzer(curr->operands[i]).hasSideEffects()) return; + if (EffectAnalyzer(getPassOptions(), curr->operands[i]).hasSideEffects()) return; } } @@ -292,7 +292,7 @@ struct MergeBlocks : public WalkerPass<PostWalker<MergeBlocks, Visitor<MergeBloc void visitCallIndirect(CallIndirect* curr) { auto* outer = optimize(curr, curr->target); - if (EffectAnalyzer(curr->target).hasSideEffects()) return; + if (EffectAnalyzer(getPassOptions(), curr->target).hasSideEffects()) return; handleCall(curr, outer); } }; diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 5c1aa5fc3..f94285930 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -317,8 +317,8 @@ struct OptimizeInstructions : public WalkerPass<PostWalker<OptimizeInstructions, auto* condition = select->condition->dynCast<Unary>(); if (condition && condition->op == EqZInt32) { // flip select to remove eqz, if we can reorder - EffectAnalyzer ifTrue(select->ifTrue); - EffectAnalyzer ifFalse(select->ifFalse); + EffectAnalyzer ifTrue(getPassOptions(), select->ifTrue); + EffectAnalyzer ifFalse(getPassOptions(), select->ifFalse); if (!ifTrue.invalidates(ifFalse)) { select->condition = condition->value; std::swap(select->ifTrue, select->ifFalse); @@ -408,8 +408,8 @@ private: auto* left = binary->left; auto* right = binary->right; if (!Properties::emitsBoolean(left) || !Properties::emitsBoolean(right)) return nullptr; - auto leftEffects = EffectAnalyzer(left).hasSideEffects(); - auto rightEffects = EffectAnalyzer(right).hasSideEffects(); + auto leftEffects = EffectAnalyzer(getPassOptions(), left).hasSideEffects(); + auto rightEffects = EffectAnalyzer(getPassOptions(), right).hasSideEffects(); if (leftEffects && rightEffects) return nullptr; // both must execute // canonicalize with side effects, if any, happening on the left if (rightEffects) { diff --git a/src/passes/RemoveUnusedBrs.cpp b/src/passes/RemoveUnusedBrs.cpp index 69a7c4ff1..b4b188416 100644 --- a/src/passes/RemoveUnusedBrs.cpp +++ b/src/passes/RemoveUnusedBrs.cpp @@ -28,11 +28,11 @@ namespace wasm { // to turn an if into a br-if, we must be able to reorder the // 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) { +static bool canTurnIfIntoBrIf(Expression* ifCondition, Expression* brValue, PassOptions& options) { if (!brValue) return true; - EffectAnalyzer value(brValue); + EffectAnalyzer value(options, brValue); if (value.hasSideEffects()) return false; - return !EffectAnalyzer(ifCondition).invalidates(value); + return !EffectAnalyzer(options, ifCondition).invalidates(value); } struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs, Visitor<RemoveUnusedBrs>>> { @@ -146,7 +146,7 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs, Visitor<R // if without an else. try to reduce if (condition) br => br_if (condition) Break* br = curr->ifTrue->dynCast<Break>(); if (br && !br->condition) { // TODO: if there is a condition, join them - if (canTurnIfIntoBrIf(curr->condition, br->value)) { + if (canTurnIfIntoBrIf(curr->condition, br->value, getPassOptions())) { br->condition = curr->condition; br->finalize(); replaceCurrent(Builder(*getModule()).dropIfConcretelyTyped(br)); @@ -263,7 +263,7 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs, Visitor<R return false; } // if there is control flow, we must stop looking - if (EffectAnalyzer(curr).branches) { + if (EffectAnalyzer(getPassOptions(), curr).branches) { return false; } if (i == 0) return false; @@ -394,6 +394,9 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs, Visitor<R // perform some final optimizations struct FinalOptimizer : public PostWalker<FinalOptimizer, Visitor<FinalOptimizer>> { bool selectify; + PassOptions& passOptions; + + FinalOptimizer(PassOptions& passOptions) : passOptions(passOptions) {} void visitBlock(Block* curr) { // if a block has an if br else br, we can un-conditionalize the latter, allowing @@ -406,7 +409,7 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs, Visitor<R auto* iff = list[i]->dynCast<If>(); if (!iff || !iff->ifFalse || isConcreteWasmType(iff->type)) continue; // if it lacked an if-false, it would already be a br_if, as that's the easy case auto* ifTrueBreak = iff->ifTrue->dynCast<Break>(); - if (ifTrueBreak && !ifTrueBreak->condition && canTurnIfIntoBrIf(iff->condition, ifTrueBreak->value)) { + if (ifTrueBreak && !ifTrueBreak->condition && canTurnIfIntoBrIf(iff->condition, ifTrueBreak->value, passOptions)) { // we are an if-else where the ifTrue is a break without a condition, so we can do this ifTrueBreak->condition = iff->condition; ifTrueBreak->finalize(); @@ -416,7 +419,7 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs, Visitor<R } // otherwise, perhaps we can flip the if auto* ifFalseBreak = iff->ifFalse->dynCast<Break>(); - if (ifFalseBreak && !ifFalseBreak->condition && canTurnIfIntoBrIf(iff->condition, ifFalseBreak->value)) { + if (ifFalseBreak && !ifFalseBreak->condition && canTurnIfIntoBrIf(iff->condition, ifFalseBreak->value, passOptions)) { ifFalseBreak->condition = Builder(*getModule()).makeUnary(EqZInt32, iff->condition); ifFalseBreak->finalize(); list[i] = Builder(*getModule()).dropIfConcretelyTyped(ifFalseBreak); @@ -435,7 +438,7 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs, Visitor<R if (!br2 || !br2->condition) continue; if (br1->name == br2->name) { assert(!br1->value && !br2->value); - if (!EffectAnalyzer(br2->condition).hasSideEffects()) { + if (!EffectAnalyzer(passOptions, br2->condition).hasSideEffects()) { // it's ok to execute them both, do it Builder builder(*getModule()); br1->condition = builder.makeBinary(OrInt32, br1->condition, br2->condition); @@ -480,11 +483,11 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs, Visitor<R if (curr->ifFalse && isConcreteWasmType(curr->ifTrue->type) && isConcreteWasmType(curr->ifFalse->type)) { // if with else, consider turning it into a select if there is no control flow // TODO: estimate cost - EffectAnalyzer condition(curr->condition); + EffectAnalyzer condition(passOptions, curr->condition); if (!condition.hasSideEffects()) { - EffectAnalyzer ifTrue(curr->ifTrue); + EffectAnalyzer ifTrue(passOptions, curr->ifTrue); if (!ifTrue.hasSideEffects()) { - EffectAnalyzer ifFalse(curr->ifFalse); + EffectAnalyzer ifFalse(passOptions, curr->ifFalse); if (!ifFalse.hasSideEffects()) { auto* select = getModule()->allocator.alloc<Select>(); select->condition = curr->condition; @@ -498,7 +501,7 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs, Visitor<R } } }; - FinalOptimizer finalOptimizer; + FinalOptimizer finalOptimizer(getPassOptions()); finalOptimizer.setModule(getModule()); finalOptimizer.selectify = getPassRunner()->options.shrinkLevel > 0; finalOptimizer.walkFunction(func); diff --git a/src/passes/SimplifyLocals.cpp b/src/passes/SimplifyLocals.cpp index 6509c9da5..8590fbe96 100644 --- a/src/passes/SimplifyLocals.cpp +++ b/src/passes/SimplifyLocals.cpp @@ -84,9 +84,7 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals, Expression** item; EffectAnalyzer effects; - SinkableInfo(Expression** item) : item(item) { - effects.walk(*item); - } + SinkableInfo(Expression** item, PassOptions& passOptions) : item(item), effects(passOptions, *item) {} }; // a list of sinkables in a linear execution trace @@ -246,7 +244,7 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals, static void visitPre(SimplifyLocals* self, Expression** currp) { Expression* curr = *currp; - EffectAnalyzer effects; + EffectAnalyzer effects(self->getPassOptions()); if (effects.checkPre(curr)) { self->checkInvalidations(effects); } @@ -274,7 +272,7 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals, } } - EffectAnalyzer effects; + EffectAnalyzer effects(self->getPassOptions()); if (effects.checkPost(*currp)) { self->checkInvalidations(effects); } @@ -282,7 +280,7 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals, if (set && self->canSink(set)) { Index index = set->index; assert(self->sinkables.count(index) == 0); - self->sinkables.emplace(std::make_pair(index, SinkableInfo(currp))); + self->sinkables.emplace(std::make_pair(index, SinkableInfo(currp, self->getPassOptions()))); } self->expressionStack.pop_back(); diff --git a/src/passes/Vacuum.cpp b/src/passes/Vacuum.cpp index 8d9bb421c..38e607c24 100644 --- a/src/passes/Vacuum.cpp +++ b/src/passes/Vacuum.cpp @@ -74,22 +74,22 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum, Visitor<Vacuum>> } // for unary, binary, and select, we need to check their arguments for side effects if (auto* unary = curr->dynCast<Unary>()) { - if (EffectAnalyzer(unary->value).hasSideEffects()) { + if (EffectAnalyzer(getPassOptions(), unary->value).hasSideEffects()) { curr = unary->value; continue; } else { return nullptr; } } else if (auto* binary = curr->dynCast<Binary>()) { - if (EffectAnalyzer(binary->left).hasSideEffects()) { - if (EffectAnalyzer(binary->right).hasSideEffects()) { + if (EffectAnalyzer(getPassOptions(), binary->left).hasSideEffects()) { + if (EffectAnalyzer(getPassOptions(), binary->right).hasSideEffects()) { return curr; // leave them } else { curr = binary->left; continue; } } else { - if (EffectAnalyzer(binary->right).hasSideEffects()) { + if (EffectAnalyzer(getPassOptions(), binary->right).hasSideEffects()) { curr = binary->right; continue; } else { @@ -99,11 +99,11 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum, Visitor<Vacuum>> } else { // TODO: if two have side effects, we could replace the select with say an add? auto* select = curr->cast<Select>(); - if (EffectAnalyzer(select->ifTrue).hasSideEffects()) { - if (EffectAnalyzer(select->ifFalse).hasSideEffects()) { + if (EffectAnalyzer(getPassOptions(), select->ifTrue).hasSideEffects()) { + if (EffectAnalyzer(getPassOptions(), select->ifFalse).hasSideEffects()) { return curr; // leave them } else { - if (EffectAnalyzer(select->condition).hasSideEffects()) { + if (EffectAnalyzer(getPassOptions(), select->condition).hasSideEffects()) { return curr; // leave them } else { curr = select->ifTrue; @@ -111,15 +111,15 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum, Visitor<Vacuum>> } } } else { - if (EffectAnalyzer(select->ifFalse).hasSideEffects()) { - if (EffectAnalyzer(select->condition).hasSideEffects()) { + if (EffectAnalyzer(getPassOptions(), select->ifFalse).hasSideEffects()) { + if (EffectAnalyzer(getPassOptions(), select->condition).hasSideEffects()) { return curr; // leave them } else { curr = select->ifFalse; continue; } } else { - if (EffectAnalyzer(select->condition).hasSideEffects()) { + if (EffectAnalyzer(getPassOptions(), select->condition).hasSideEffects()) { curr = select->condition; continue; } else { @@ -174,7 +174,7 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum, Visitor<Vacuum>> if (!curr->name.is()) { if (list.size() == 1) { // just one element. replace the block, either with it or with a nop if it's not needed - if (isConcreteWasmType(curr->type) || EffectAnalyzer(list[0]).hasSideEffects()) { + if (isConcreteWasmType(curr->type) || EffectAnalyzer(getPassOptions(), list[0]).hasSideEffects()) { replaceCurrent(list[0]); } else { if (curr->type == unreachable) { @@ -307,7 +307,7 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum, Visitor<Vacuum>> } else { ExpressionManipulator::nop(curr->body); } - if (curr->result == none && !EffectAnalyzer(curr->body).hasSideEffects()) { + if (curr->result == none && !EffectAnalyzer(getPassOptions(), curr->body).hasSideEffects()) { ExpressionManipulator::nop(curr->body); } } diff --git a/src/tools/optimization-options.h b/src/tools/optimization-options.h index 7f3936d35..368e319a7 100644 --- a/src/tools/optimization-options.h +++ b/src/tools/optimization-options.h @@ -23,7 +23,6 @@ [&runOptimizationPasses, &passOptions](Options*, const std::string&) { passOptions.optimizeLevel = 2; passOptions.shrinkLevel = 1; - passOptions.ignoreImplicitTraps = true; runOptimizationPasses = true; }) .add("", "-O0", "execute no optimization passes", @@ -31,14 +30,12 @@ [&passOptions](Options*, const std::string&) { passOptions.optimizeLevel = 0; passOptions.shrinkLevel = 0; - passOptions.ignoreImplicitTraps = false; }) .add("", "-O1", "execute -O1 optimization passes", Options::Arguments::Zero, [&runOptimizationPasses, &passOptions](Options*, const std::string&) { passOptions.optimizeLevel = 1; passOptions.shrinkLevel = 0; - passOptions.ignoreImplicitTraps = true; runOptimizationPasses = true; }) .add("", "-O2", "execute -O2 optimization passes", @@ -46,7 +43,6 @@ [&runOptimizationPasses, &passOptions](Options*, const std::string&) { passOptions.optimizeLevel = 2; passOptions.shrinkLevel = 0; - passOptions.ignoreImplicitTraps = true; runOptimizationPasses = true; }) .add("", "-O3", "execute -O3 optimization passes", @@ -54,7 +50,6 @@ [&runOptimizationPasses, &passOptions](Options*, const std::string&) { passOptions.optimizeLevel = 3; passOptions.shrinkLevel = 0; - passOptions.ignoreImplicitTraps = true; runOptimizationPasses = true; }) .add("", "-Os", "execute default optimization passes, focusing on code size", @@ -62,7 +57,6 @@ [&runOptimizationPasses, &passOptions](Options*, const std::string&) { passOptions.optimizeLevel = 2; passOptions.shrinkLevel = 1; - passOptions.ignoreImplicitTraps = true; runOptimizationPasses = true; }) .add("", "-Oz", "execute default optimization passes, super-focusing on code size", @@ -70,7 +64,6 @@ [&runOptimizationPasses, &passOptions](Options*, const std::string&) { passOptions.optimizeLevel = 2; passOptions.shrinkLevel = 2; - passOptions.ignoreImplicitTraps = true; runOptimizationPasses = true; }) .add("--optimize-level", "-ol", "How much to focus on optimizing code", @@ -83,3 +76,9 @@ [&passOptions](Options* o, const std::string& argument) { passOptions.shrinkLevel = atoi(argument.c_str()); }) + .add("--ignore-implicit-traps", "-iit", "Optimize under the helpful assumption that no surprising traps occur (from load, div/mod, etc.)", + Options::Arguments::Zero, + [&runOptimizationPasses, &passOptions](Options*, const std::string&) { + passOptions.ignoreImplicitTraps = true; + }) + |