summaryrefslogtreecommitdiff
path: root/compiler/optimizing
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing')
-rw-r--r--compiler/optimizing/constant_folding.cc88
-rw-r--r--compiler/optimizing/nodes.cc72
-rw-r--r--compiler/optimizing/nodes.h15
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: