diff options
Diffstat (limited to 'compiler/optimizing/constant_folding.cc')
-rw-r--r-- | compiler/optimizing/constant_folding.cc | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/compiler/optimizing/constant_folding.cc b/compiler/optimizing/constant_folding.cc index 2163c007e6..e20d9e83e6 100644 --- a/compiler/optimizing/constant_folding.cc +++ b/compiler/optimizing/constant_folding.cc @@ -37,6 +37,13 @@ class HConstantFoldingVisitor final : public HGraphDelegateVisitor { void VisitUnaryOperation(HUnaryOperation* inst) override; void VisitBinaryOperation(HBinaryOperation* inst) override; + // Tries to replace constants in binary operations like: + // * BinaryOp(Select(false_constant, true_constant, condition), other_constant), or + // * BinaryOp(other_constant, Select(false_constant, true_constant, condition)) + // with consolidated constants. For example, Add(Select(10, 20, condition), 5) can be replaced + // with Select(15, 25, condition). + bool TryRemoveBinaryOperationViaSelect(HBinaryOperation* inst); + void VisitArrayLength(HArrayLength* inst) override; void VisitDivZeroCheck(HDivZeroCheck* inst) override; void VisitIf(HIf* inst) override; @@ -113,9 +120,69 @@ void HConstantFoldingVisitor::VisitUnaryOperation(HUnaryOperation* inst) { if (constant != nullptr) { inst->ReplaceWith(constant); inst->GetBlock()->RemoveInstruction(inst); + } else if (inst->InputAt(0)->IsSelect() && inst->InputAt(0)->HasOnlyOneNonEnvironmentUse()) { + // Try to replace the select's inputs in Select+UnaryOperation cases. We can do this if both + // inputs to the select are constants, and this is the only use of the select. + HSelect* select = inst->InputAt(0)->AsSelect(); + HConstant* false_constant = inst->TryStaticEvaluation(select->GetFalseValue()); + if (false_constant == nullptr) { + return; + } + HConstant* true_constant = inst->TryStaticEvaluation(select->GetTrueValue()); + if (true_constant == nullptr) { + return; + } + DCHECK_EQ(select->InputAt(0), select->GetFalseValue()); + DCHECK_EQ(select->InputAt(1), select->GetTrueValue()); + select->ReplaceInput(false_constant, 0); + select->ReplaceInput(true_constant, 1); + select->UpdateType(); + inst->ReplaceWith(select); + inst->GetBlock()->RemoveInstruction(inst); } } +bool HConstantFoldingVisitor::TryRemoveBinaryOperationViaSelect(HBinaryOperation* inst) { + if (inst->GetLeft()->IsSelect() == inst->GetRight()->IsSelect()) { + // If both of them are constants, VisitBinaryOperation already tried the static evaluation. If + // both of them are selects, then we can't simplify. + // TODO(solanes): Technically, if both of them are selects we could simplify iff both select's + // conditions are equal e.g. Add(Select(1, 2, cond), Select(3, 4, cond)) could be replaced with + // Select(4, 6, cond). This seems very unlikely to happen so we don't implement it. + return false; + } + + const bool left_is_select = inst->GetLeft()->IsSelect(); + HSelect* select = left_is_select ? inst->GetLeft()->AsSelect() : inst->GetRight()->AsSelect(); + HInstruction* maybe_constant = left_is_select ? inst->GetRight() : inst->GetLeft(); + + if (select->HasOnlyOneNonEnvironmentUse()) { + // Try to replace the select's inputs in Select+BinaryOperation. We can do this if both + // inputs to the select are constants, and this is the only use of the select. + HConstant* false_constant = + inst->TryStaticEvaluation(left_is_select ? select->GetFalseValue() : maybe_constant, + left_is_select ? maybe_constant : select->GetFalseValue()); + if (false_constant == nullptr) { + return false; + } + HConstant* true_constant = + inst->TryStaticEvaluation(left_is_select ? select->GetTrueValue() : maybe_constant, + left_is_select ? maybe_constant : select->GetTrueValue()); + if (true_constant == nullptr) { + return false; + } + DCHECK_EQ(select->InputAt(0), select->GetFalseValue()); + DCHECK_EQ(select->InputAt(1), select->GetTrueValue()); + select->ReplaceInput(false_constant, 0); + select->ReplaceInput(true_constant, 1); + select->UpdateType(); + inst->ReplaceWith(select); + inst->GetBlock()->RemoveInstruction(inst); + return true; + } + return false; +} + void HConstantFoldingVisitor::VisitBinaryOperation(HBinaryOperation* inst) { // Constant folding: replace `op(a, b)' with a constant at // compile time if `a' and `b' are both constants. @@ -123,6 +190,8 @@ void HConstantFoldingVisitor::VisitBinaryOperation(HBinaryOperation* inst) { if (constant != nullptr) { inst->ReplaceWith(constant); inst->GetBlock()->RemoveInstruction(inst); + } else if (TryRemoveBinaryOperationViaSelect(inst)) { + // Already replaced inside TryRemoveBinaryOperationViaSelect. } else { InstructionWithAbsorbingInputSimplifier simplifier(GetGraph()); inst->Accept(&simplifier); @@ -299,6 +368,25 @@ void HConstantFoldingVisitor::VisitTypeConversion(HTypeConversion* inst) { if (constant != nullptr) { inst->ReplaceWith(constant); inst->GetBlock()->RemoveInstruction(inst); + } else if (inst->InputAt(0)->IsSelect() && inst->InputAt(0)->HasOnlyOneNonEnvironmentUse()) { + // Try to replace the select's inputs in Select+TypeConversion. We can do this if both + // inputs to the select are constants, and this is the only use of the select. + HSelect* select = inst->InputAt(0)->AsSelect(); + HConstant* false_constant = inst->TryStaticEvaluation(select->GetFalseValue()); + if (false_constant == nullptr) { + return; + } + HConstant* true_constant = inst->TryStaticEvaluation(select->GetTrueValue()); + if (true_constant == nullptr) { + return; + } + DCHECK_EQ(select->InputAt(0), select->GetFalseValue()); + DCHECK_EQ(select->InputAt(1), select->GetTrueValue()); + select->ReplaceInput(false_constant, 0); + select->ReplaceInput(true_constant, 1); + select->UpdateType(); + inst->ReplaceWith(select); + inst->GetBlock()->RemoveInstruction(inst); } } |