summaryrefslogtreecommitdiff
path: root/compiler/optimizing/instruction_simplifier.cc
diff options
context:
space:
mode:
author Roman Artemev <roman.artemev@syntacore.com> 2024-08-13 12:52:00 +0000
committer VladimĂ­r Marko <vmarko@google.com> 2024-08-14 12:26:57 +0000
commit4910586af2f208262dd1f8225f42fa6f6e95d355 (patch)
tree895c5c570d089d2bd9d219c0b7e5fa995443db5e /compiler/optimizing/instruction_simplifier.cc
parentb9075fca15c21ce4ea599e5379463c4fda82660a (diff)
Revert^2 "Implement transform from signed to unsigned compare"
This reverts commit 275cf7423efdb36e441b7bceb2e678944f8fa34b. Reason for revert: Fix HEquals and HNotEquals cases Change-Id: I47559e0b0d6625370e392119fd005bc10167aa87
Diffstat (limited to 'compiler/optimizing/instruction_simplifier.cc')
-rw-r--r--compiler/optimizing/instruction_simplifier.cc205
1 files changed, 198 insertions, 7 deletions
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index cafa83bece..4bee9c0711 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -89,6 +89,7 @@ class InstructionSimplifierVisitor final : public HGraphDelegateVisitor {
void VisitAbs(HAbs* instruction) override;
void VisitAdd(HAdd* instruction) override;
void VisitAnd(HAnd* instruction) override;
+ void VisitCompare(HCompare* instruction) override;
void VisitCondition(HCondition* instruction) override;
void VisitGreaterThan(HGreaterThan* condition) override;
void VisitGreaterThanOrEqual(HGreaterThanOrEqual* condition) override;
@@ -878,7 +879,7 @@ void InstructionSimplifierVisitor::VisitStaticFieldSet(HStaticFieldSet* instruct
}
}
-static HCondition* GetOppositeConditionSwapOps(ArenaAllocator* allocator, HInstruction* cond) {
+static HCondition* CreateOppositeConditionSwapOps(ArenaAllocator* allocator, HInstruction* cond) {
HInstruction *lhs = cond->InputAt(0);
HInstruction *rhs = cond->InputAt(1);
switch (cond->GetKind()) {
@@ -1794,6 +1795,56 @@ static bool RecognizeAndSimplifyClassCheck(HCondition* condition) {
}
}
+static HInstruction* CreateUnsignedConditionReplacement(ArenaAllocator* allocator,
+ HCondition* cond,
+ HCompare* compare) {
+ DCHECK(cond->InputAt(1)->IsIntConstant());
+ DCHECK_EQ(cond->InputAt(1)->AsIntConstant()->GetValue(), 0);
+ DCHECK(cond->InputAt(0) == compare);
+
+ HBasicBlock* block = cond->GetBlock();
+ HInstruction* lhs = compare->InputAt(0);
+ HInstruction* rhs = compare->InputAt(1);
+
+ switch (cond->GetKind()) {
+ case HInstruction::kLessThan:
+ return new (allocator) HBelow(lhs, rhs, cond->GetDexPc());
+ case HInstruction::kLessThanOrEqual:
+ return new (allocator) HBelowOrEqual(lhs, rhs, cond->GetDexPc());
+ case HInstruction::kGreaterThan:
+ return new (allocator) HAbove(lhs, rhs, cond->GetDexPc());
+ case HInstruction::kGreaterThanOrEqual:
+ return new (allocator) HAboveOrEqual(lhs, rhs, cond->GetDexPc());
+ case HInstruction::kBelow:
+ // Below(Compare(x, y), 0) always False since
+ // unsigned(-1) < 0 -> False
+ // 0 < 0 -> False
+ // 1 < 0 -> False
+ return block->GetGraph()->GetConstant(DataType::Type::kBool, 0, cond->GetDexPc());
+ case HInstruction::kBelowOrEqual:
+ // BelowOrEqual(Compare(x, y), 0) transforms into Equal(x, y)
+ // unsigned(-1) <= 0 -> False
+ // 0 <= 0 -> True
+ // 1 <= 0 -> False
+ return new (allocator) HEqual(lhs, rhs, cond->GetDexPc());
+ case HInstruction::kAbove:
+ // Above(Compare(x, y), 0) transforms into NotEqual(x, y)
+ // unsigned(-1) > 0 -> True
+ // 0 > 0 -> False
+ // 1 > 0 -> True
+ return new (allocator) HNotEqual(lhs, rhs, cond->GetDexPc());
+ case HInstruction::kAboveOrEqual:
+ // AboveOrEqual(Compare(x, y), 0) always True since
+ // unsigned(-1) >= 0 -> True
+ // 0 >= 0 -> True
+ // 1 >= 0 -> True
+ return block->GetGraph()->GetConstant(DataType::Type::kBool, 1, cond->GetDexPc());
+ default:
+ LOG(FATAL) << "Unknown ConditionType " << cond->GetKind();
+ UNREACHABLE();
+ }
+}
+
void InstructionSimplifierVisitor::VisitCondition(HCondition* condition) {
if (condition->IsEqual() || condition->IsNotEqual()) {
if (RecognizeAndSimplifyClassCheck(condition)) {
@@ -1803,10 +1854,10 @@ void InstructionSimplifierVisitor::VisitCondition(HCondition* condition) {
// Reverse condition if left is constant. Our code generators prefer constant
// on the right hand side.
+ HBasicBlock* block = condition->GetBlock();
if (condition->GetLeft()->IsConstant() && !condition->GetRight()->IsConstant()) {
- HBasicBlock* block = condition->GetBlock();
HCondition* replacement =
- GetOppositeConditionSwapOps(block->GetGraph()->GetAllocator(), condition);
+ CreateOppositeConditionSwapOps(block->GetGraph()->GetAllocator(), condition);
// If it is a fp we must set the opposite bias.
if (replacement != nullptr) {
if (condition->IsLtBias()) {
@@ -1814,6 +1865,7 @@ void InstructionSimplifierVisitor::VisitCondition(HCondition* condition) {
} else if (condition->IsGtBias()) {
replacement->SetBias(ComparisonBias::kLtBias);
}
+
block->ReplaceAndRemoveInstructionWith(condition, replacement);
RecordSimplification();
@@ -1856,11 +1908,26 @@ void InstructionSimplifierVisitor::VisitCondition(HCondition* condition) {
left->RemoveEnvironmentUsers();
// We have decided to fold the HCompare into the HCondition. Transfer the information.
- condition->SetBias(left->AsCompare()->GetBias());
+ if (DataType::IsUnsignedType(left->AsCompare()->GetComparisonType()) &&
+ !condition->IsEqual() &&
+ !condition->IsNotEqual()) {
+ DCHECK_EQ(condition->GetBias(), ComparisonBias::kNoBias);
+ HInstruction* replacement = CreateUnsignedConditionReplacement(
+ block->GetGraph()->GetAllocator(), condition, left->AsCompare());
+
+ if (replacement->IsConstant()) {
+ condition->ReplaceWith(replacement);
+ block->RemoveInstruction(condition);
+ } else {
+ block->ReplaceAndRemoveInstructionWith(condition, replacement);
+ }
+ } else {
+ condition->SetBias(left->AsCompare()->GetBias());
- // Replace the operands of the HCondition.
- condition->ReplaceInput(left->InputAt(0), 0);
- condition->ReplaceInput(left->InputAt(1), 1);
+ // Replace the operands of the HCondition.
+ condition->ReplaceInput(left->InputAt(0), 0);
+ condition->ReplaceInput(left->InputAt(1), 1);
+ }
// Remove the HCompare.
left->GetBlock()->RemoveInstruction(left);
@@ -1868,6 +1935,130 @@ void InstructionSimplifierVisitor::VisitCondition(HCondition* condition) {
RecordSimplification();
}
+static HInstruction* CheckSignedToUnsignedCompareConversion(HInstruction* operand,
+ HCompare* compare) {
+ // Check if operand looks like `ADD op, MIN_INTEGRAL`
+ if (operand->IsConstant()) {
+ // CONSTANT #x -> CONSTANT #(x - MIN_INTEGRAL)
+ HConstant* constant = operand->AsConstant();
+ if (constant->IsIntConstant()) {
+ HIntConstant* int_constant = constant->AsIntConstant();
+ int32_t old_value = int_constant->GetValue();
+ int32_t new_value = old_value - std::numeric_limits<int32_t>::min();
+ return operand->GetBlock()->GetGraph()->GetIntConstant(new_value, constant->GetDexPc());
+ } else if (constant->IsLongConstant()) {
+ HLongConstant* long_constant = constant->AsLongConstant();
+ int64_t old_value = long_constant->GetValue();
+ int64_t new_value = old_value - std::numeric_limits<int64_t>::min();
+ return operand->GetBlock()->GetGraph()->GetLongConstant(new_value, constant->GetDexPc());
+ } else {
+ return nullptr;
+ }
+ }
+
+ if (!operand->IsAdd() && !operand->IsXor()) {
+ return nullptr;
+ }
+
+ if (!operand->GetEnvUses().empty()) {
+ // There is a reference to the compare result in an environment. Do we really need it?
+ if (operand->GetBlock()->GetGraph()->IsDebuggable()) {
+ return nullptr;
+ }
+
+ // We have to ensure that there are no deopt points in the sequence.
+ if (operand->HasAnyEnvironmentUseBefore(compare)) {
+ return nullptr;
+ }
+ }
+
+ HBinaryOperation* additive_operand = operand->AsBinaryOperation();
+
+ HInstruction* left = additive_operand->GetLeft();
+ HInstruction* right = additive_operand->GetRight();
+
+ HConstant* constant = nullptr;
+ HInstruction* value = nullptr;
+
+ if (left->IsConstant() && !right->IsConstant()) {
+ constant = left->AsConstant();
+ value = right;
+ } else if (!left->IsConstant() && right->IsConstant()) {
+ value = left;
+ constant = right->AsConstant();
+ } else {
+ return nullptr;
+ }
+
+ if (constant->IsIntConstant()) {
+ HIntConstant* int_constant = constant->AsIntConstant();
+ if (int_constant->GetValue() != std::numeric_limits<int32_t>::min()) {
+ return nullptr;
+ }
+ } else if (constant->IsLongConstant()) {
+ HLongConstant* long_constant = constant->AsLongConstant();
+ if (long_constant->GetValue() != std::numeric_limits<int64_t>::min()) {
+ return nullptr;
+ }
+ } else {
+ return nullptr;
+ }
+
+ return value;
+}
+
+static DataType::Type GetOpositeSignType(DataType::Type type) {
+ return DataType::IsUnsignedType(type) ? DataType::ToSigned(type) : DataType::ToUnsigned(type);
+}
+
+void InstructionSimplifierVisitor::VisitCompare(HCompare* compare) {
+ // Transform signed compare into unsigned if possible
+ // Replace code looking like
+ // ADD normalizedLeft, left, MIN_INTEGRAL
+ // ADD normalizedRight, right, MIN_INTEGRAL
+ // COMPARE normalizedLeft, normalizedRight, sign
+ // with
+ // COMPARE left, right, !sign
+
+ if (!DataType::IsIntegralType(compare->GetComparisonType())) {
+ return;
+ }
+
+ HInstruction* compare_left = compare->GetLeft();
+ HInstruction* compare_right = compare->GetRight();
+
+ if (compare_left->IsConstant() && compare_right->IsConstant()) {
+ // Do not simplify, let it be folded.
+ return;
+ }
+
+ HInstruction* left = CheckSignedToUnsignedCompareConversion(compare_left, compare);
+ if (left == nullptr) {
+ return;
+ }
+
+ HInstruction* right = CheckSignedToUnsignedCompareConversion(compare_right, compare);
+ if (right == nullptr) {
+ return;
+ }
+
+ compare->SetComparisonType(GetOpositeSignType(compare->GetComparisonType()));
+ compare->ReplaceInput(left, 0);
+ compare->ReplaceInput(right, 1);
+
+ RecordSimplification();
+
+ if (compare_left->GetUses().empty()) {
+ compare_left->RemoveEnvironmentUsers();
+ compare_left->GetBlock()->RemoveInstruction(compare_left);
+ }
+
+ if (compare_right->GetUses().empty()) {
+ compare_right->RemoveEnvironmentUsers();
+ compare_right->GetBlock()->RemoveInstruction(compare_right);
+ }
+}
+
// Return whether x / divisor == x * (1.0f / divisor), for every float x.
static constexpr bool CanDivideByReciprocalMultiplyFloat(int32_t divisor) {
// True, if the most significant bits of divisor are 0.