summaryrefslogtreecommitdiff
path: root/compiler/optimizing/constant_folding.cc
diff options
context:
space:
mode:
author Santiago Aboy Solanes <solanes@google.com> 2023-03-10 15:58:17 +0000
committer Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> 2023-10-10 12:51:37 +0000
commitd003e7530ed0b00df5504cf57f0dd6479629c67a (patch)
tree205938c02bfb914f007fc4e7e30f78b9b50b63e4 /compiler/optimizing/constant_folding.cc
parent472f6bced8e088fe8f97213587933e0c4420238f (diff)
Add optimization to simplify Select+Binary/Unary ops
We can simplify a Select + Binary/Unary Op if: * Both inputs to the Select instruction are constant, and * The Select instruction is not used in another instruction to avoid duplicating Selects. * In the case of Binary ops, both inputs can't be Select. Test: art/test/testrunner/testrunner.py --host --64 --optimizing -b Change-Id: Ic716155e9a8515126c2867bb1d54593fa63011ae
Diffstat (limited to 'compiler/optimizing/constant_folding.cc')
-rw-r--r--compiler/optimizing/constant_folding.cc88
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);
}
}