diff options
Diffstat (limited to 'compiler/optimizing')
-rw-r--r-- | compiler/optimizing/constant_folding.cc | 88 | ||||
-rw-r--r-- | compiler/optimizing/nodes.cc | 72 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 15 |
3 files changed, 143 insertions, 32 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); } } diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index 2b7e384f34..5795ea7ca9 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -1816,10 +1816,12 @@ void HGraphVisitor::VisitBasicBlock(HBasicBlock* block) { } } -HConstant* HTypeConversion::TryStaticEvaluation() const { - HGraph* graph = GetBlock()->GetGraph(); - if (GetInput()->IsIntConstant()) { - int32_t value = GetInput()->AsIntConstant()->GetValue(); +HConstant* HTypeConversion::TryStaticEvaluation() const { return TryStaticEvaluation(GetInput()); } + +HConstant* HTypeConversion::TryStaticEvaluation(HInstruction* input) const { + HGraph* graph = input->GetBlock()->GetGraph(); + if (input->IsIntConstant()) { + int32_t value = input->AsIntConstant()->GetValue(); switch (GetResultType()) { case DataType::Type::kInt8: return graph->GetIntConstant(static_cast<int8_t>(value), GetDexPc()); @@ -1838,8 +1840,8 @@ HConstant* HTypeConversion::TryStaticEvaluation() const { default: return nullptr; } - } else if (GetInput()->IsLongConstant()) { - int64_t value = GetInput()->AsLongConstant()->GetValue(); + } else if (input->IsLongConstant()) { + int64_t value = input->AsLongConstant()->GetValue(); switch (GetResultType()) { case DataType::Type::kInt8: return graph->GetIntConstant(static_cast<int8_t>(value), GetDexPc()); @@ -1858,8 +1860,8 @@ HConstant* HTypeConversion::TryStaticEvaluation() const { default: return nullptr; } - } else if (GetInput()->IsFloatConstant()) { - float value = GetInput()->AsFloatConstant()->GetValue(); + } else if (input->IsFloatConstant()) { + float value = input->AsFloatConstant()->GetValue(); switch (GetResultType()) { case DataType::Type::kInt32: if (std::isnan(value)) @@ -1882,8 +1884,8 @@ HConstant* HTypeConversion::TryStaticEvaluation() const { default: return nullptr; } - } else if (GetInput()->IsDoubleConstant()) { - double value = GetInput()->AsDoubleConstant()->GetValue(); + } else if (input->IsDoubleConstant()) { + double value = input->AsDoubleConstant()->GetValue(); switch (GetResultType()) { case DataType::Type::kInt32: if (std::isnan(value)) @@ -1910,41 +1912,47 @@ HConstant* HTypeConversion::TryStaticEvaluation() const { return nullptr; } -HConstant* HUnaryOperation::TryStaticEvaluation() const { - if (GetInput()->IsIntConstant()) { - return Evaluate(GetInput()->AsIntConstant()); - } else if (GetInput()->IsLongConstant()) { - return Evaluate(GetInput()->AsLongConstant()); +HConstant* HUnaryOperation::TryStaticEvaluation() const { return TryStaticEvaluation(GetInput()); } + +HConstant* HUnaryOperation::TryStaticEvaluation(HInstruction* input) const { + if (input->IsIntConstant()) { + return Evaluate(input->AsIntConstant()); + } else if (input->IsLongConstant()) { + return Evaluate(input->AsLongConstant()); } else if (kEnableFloatingPointStaticEvaluation) { - if (GetInput()->IsFloatConstant()) { - return Evaluate(GetInput()->AsFloatConstant()); - } else if (GetInput()->IsDoubleConstant()) { - return Evaluate(GetInput()->AsDoubleConstant()); + if (input->IsFloatConstant()) { + return Evaluate(input->AsFloatConstant()); + } else if (input->IsDoubleConstant()) { + return Evaluate(input->AsDoubleConstant()); } } return nullptr; } HConstant* HBinaryOperation::TryStaticEvaluation() const { - if (GetLeft()->IsIntConstant() && GetRight()->IsIntConstant()) { - return Evaluate(GetLeft()->AsIntConstant(), GetRight()->AsIntConstant()); - } else if (GetLeft()->IsLongConstant()) { - if (GetRight()->IsIntConstant()) { + return TryStaticEvaluation(GetLeft(), GetRight()); +} + +HConstant* HBinaryOperation::TryStaticEvaluation(HInstruction* left, HInstruction* right) const { + if (left->IsIntConstant() && right->IsIntConstant()) { + return Evaluate(left->AsIntConstant(), right->AsIntConstant()); + } else if (left->IsLongConstant()) { + if (right->IsIntConstant()) { // The binop(long, int) case is only valid for shifts and rotations. DCHECK(IsShl() || IsShr() || IsUShr() || IsRor()) << DebugName(); - return Evaluate(GetLeft()->AsLongConstant(), GetRight()->AsIntConstant()); - } else if (GetRight()->IsLongConstant()) { - return Evaluate(GetLeft()->AsLongConstant(), GetRight()->AsLongConstant()); + return Evaluate(left->AsLongConstant(), right->AsIntConstant()); + } else if (right->IsLongConstant()) { + return Evaluate(left->AsLongConstant(), right->AsLongConstant()); } - } else if (GetLeft()->IsNullConstant() && GetRight()->IsNullConstant()) { + } else if (left->IsNullConstant() && right->IsNullConstant()) { // The binop(null, null) case is only valid for equal and not-equal conditions. DCHECK(IsEqual() || IsNotEqual()) << DebugName(); - return Evaluate(GetLeft()->AsNullConstant(), GetRight()->AsNullConstant()); + return Evaluate(left->AsNullConstant(), right->AsNullConstant()); } else if (kEnableFloatingPointStaticEvaluation) { - if (GetLeft()->IsFloatConstant() && GetRight()->IsFloatConstant()) { - return Evaluate(GetLeft()->AsFloatConstant(), GetRight()->AsFloatConstant()); - } else if (GetLeft()->IsDoubleConstant() && GetRight()->IsDoubleConstant()) { - return Evaluate(GetLeft()->AsDoubleConstant(), GetRight()->AsDoubleConstant()); + if (left->IsFloatConstant() && right->IsFloatConstant()) { + return Evaluate(left->AsFloatConstant(), right->AsFloatConstant()); + } else if (left->IsDoubleConstant() && right->IsDoubleConstant()) { + return Evaluate(left->AsDoubleConstant(), right->AsDoubleConstant()); } } return nullptr; diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 3f60ec5241..9cf52183b8 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -3858,6 +3858,9 @@ class HUnaryOperation : public HExpression<1> { // be evaluated as a constant, return null. HConstant* TryStaticEvaluation() const; + // Same but for `input` instead of GetInput(). + HConstant* TryStaticEvaluation(HInstruction* input) const; + // Apply this operation to `x`. virtual HConstant* Evaluate(HIntConstant* x) const = 0; virtual HConstant* Evaluate(HLongConstant* x) const = 0; @@ -3934,6 +3937,9 @@ class HBinaryOperation : public HExpression<2> { // be evaluated as a constant, return null. HConstant* TryStaticEvaluation() const; + // Same but for `left` and `right` instead of GetLeft() and GetRight(). + HConstant* TryStaticEvaluation(HInstruction* left, HInstruction* right) const; + // Apply this operation to `x` and `y`. virtual HConstant* Evaluate([[maybe_unused]] HNullConstant* x, [[maybe_unused]] HNullConstant* y) const { @@ -6188,6 +6194,9 @@ class HTypeConversion final : public HExpression<1> { // containing the result. If the input cannot be converted, return nullptr. HConstant* TryStaticEvaluation() const; + // Same but for `input` instead of GetInput(). + HConstant* TryStaticEvaluation(HInstruction* input) const; + DECLARE_INSTRUCTION(TypeConversion); protected: @@ -8377,6 +8386,12 @@ class HSelect final : public HExpression<3> { return GetTrueValue()->CanBeNull() || GetFalseValue()->CanBeNull(); } + void UpdateType() { + DCHECK_EQ(HPhi::ToPhiType(GetTrueValue()->GetType()), + HPhi::ToPhiType(GetFalseValue()->GetType())); + SetPackedField<TypeField>(HPhi::ToPhiType(GetTrueValue()->GetType())); + } + DECLARE_INSTRUCTION(Select); protected: |