diff options
Diffstat (limited to 'src/passes/param-utils.cpp')
-rw-r--r-- | src/passes/param-utils.cpp | 30 |
1 files changed, 25 insertions, 5 deletions
diff --git a/src/passes/param-utils.cpp b/src/passes/param-utils.cpp index cf7873dc0..3b0721173 100644 --- a/src/passes/param-utils.cpp +++ b/src/passes/param-utils.cpp @@ -62,20 +62,40 @@ bool removeParameter(const std::vector<Function*>& funcs, // Check if none of the calls has a param with side effects that we cannot // remove (as if we can remove them, we will simply do that when we remove the // parameter). Note: flattening the IR beforehand can help here. - auto hasBadEffects = [&](ExpressionList& operands) { - return EffectAnalyzer(runner->options, *module, operands[index]) - .hasUnremovableSideEffects(); + // + // It would also be bad if we remove a parameter that causes the type of the + // call to change, like this: + // + // (call $foo + // (unreachable)) + // + // After removing the parameter the type should change from unreachable to + // something concrete. We could handle this by updating the type and then + // propagating that out, or by appending an unreachable after the call, but + // for simplicity just ignore such cases; if we are called again later then + // if DCE ran meanwhile then we could optimize. + auto hasBadEffects = [&](auto* call) { + auto& operands = call->operands; + bool hasUnremovable = + EffectAnalyzer(runner->options, *module, operands[index]) + .hasUnremovableSideEffects(); + bool wouldChangeType = + call->type == Type::unreachable && !call->isReturn && + std::any_of(operands.begin(), operands.end(), [](Expression* operand) { + return operand->type == Type::unreachable; + }); + return hasUnremovable || wouldChangeType; }; bool callParamsAreValid = std::none_of(calls.begin(), calls.end(), [&](Call* call) { - return hasBadEffects(call->operands); + return hasBadEffects(call); }); if (!callParamsAreValid) { return false; } bool callRefParamsAreValid = std::none_of(callRefs.begin(), callRefs.end(), [&](CallRef* call) { - return hasBadEffects(call->operands); + return hasBadEffects(call); }); if (!callRefParamsAreValid) { return false; |