diff options
Diffstat (limited to 'compiler/optimizing')
-rw-r--r-- | compiler/optimizing/bounds_check_elimination.cc | 94 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 2 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 2 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 2 | ||||
-rw-r--r-- | compiler/optimizing/common_arm64.h | 10 | ||||
-rw-r--r-- | compiler/optimizing/gvn.cc | 9 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 50 |
7 files changed, 149 insertions, 20 deletions
diff --git a/compiler/optimizing/bounds_check_elimination.cc b/compiler/optimizing/bounds_check_elimination.cc index deaeb8ef47..4ca364867d 100644 --- a/compiler/optimizing/bounds_check_elimination.cc +++ b/compiler/optimizing/bounds_check_elimination.cc @@ -261,8 +261,8 @@ class ValueRange : public ArenaObject<kArenaAllocMisc> { virtual ~ValueRange() {} - virtual const MonotonicValueRange* AsMonotonicValueRange() const { return nullptr; } - bool IsMonotonicValueRange() const { + virtual MonotonicValueRange* AsMonotonicValueRange() { return nullptr; } + bool IsMonotonicValueRange() { return AsMonotonicValueRange() != nullptr; } @@ -345,7 +345,11 @@ class MonotonicValueRange : public ValueRange { virtual ~MonotonicValueRange() {} - const MonotonicValueRange* AsMonotonicValueRange() const OVERRIDE { return this; } + int32_t GetIncrement() const { return increment_; } + + ValueBound GetBound() const { return bound_; } + + MonotonicValueRange* AsMonotonicValueRange() OVERRIDE { return this; } // If it's certain that this value range fits in other_range. bool FitsIn(ValueRange* other_range) const OVERRIDE { @@ -494,6 +498,73 @@ class BCEVisitor : public HGraphVisitor { } } + // Special case that we may simultaneously narrow two MonotonicValueRange's to + // regular value ranges. + void HandleIfBetweenTwoMonotonicValueRanges(HIf* instruction, + HInstruction* left, + HInstruction* right, + IfCondition cond, + MonotonicValueRange* left_range, + MonotonicValueRange* right_range) { + DCHECK(left->IsLoopHeaderPhi()); + DCHECK(right->IsLoopHeaderPhi()); + if (instruction->GetBlock() != left->GetBlock()) { + // Comparison needs to be in loop header to make sure it's done after each + // increment/decrement. + return; + } + + // Handle common cases which also don't have overflow/underflow concerns. + if (left_range->GetIncrement() == 1 && + left_range->GetBound().IsConstant() && + right_range->GetIncrement() == -1 && + right_range->GetBound().IsRelatedToArrayLength() && + right_range->GetBound().GetConstant() < 0) { + HBasicBlock* successor = nullptr; + int32_t left_compensation = 0; + int32_t right_compensation = 0; + if (cond == kCondLT) { + left_compensation = -1; + right_compensation = 1; + successor = instruction->IfTrueSuccessor(); + } else if (cond == kCondLE) { + successor = instruction->IfTrueSuccessor(); + } else if (cond == kCondGT) { + successor = instruction->IfFalseSuccessor(); + } else if (cond == kCondGE) { + left_compensation = -1; + right_compensation = 1; + successor = instruction->IfFalseSuccessor(); + } else { + // We don't handle '=='/'!=' test in case left and right can cross and + // miss each other. + return; + } + + if (successor != nullptr) { + bool overflow; + bool underflow; + ValueRange* new_left_range = new (GetGraph()->GetArena()) ValueRange( + GetGraph()->GetArena(), + left_range->GetBound(), + right_range->GetBound().Add(left_compensation, &overflow, &underflow)); + if (!overflow && !underflow) { + ApplyRangeFromComparison(left, instruction->GetBlock(), successor, + new_left_range); + } + + ValueRange* new_right_range = new (GetGraph()->GetArena()) ValueRange( + GetGraph()->GetArena(), + left_range->GetBound().Add(right_compensation, &overflow, &underflow), + right_range->GetBound()); + if (!overflow && !underflow) { + ApplyRangeFromComparison(right, instruction->GetBlock(), successor, + new_right_range); + } + } + } + } + // Handle "if (left cmp_cond right)". void HandleIf(HIf* instruction, HInstruction* left, HInstruction* right, IfCondition cond) { HBasicBlock* block = instruction->GetBlock(); @@ -515,10 +586,19 @@ class BCEVisitor : public HGraphVisitor { if (!found) { // No constant or array.length+c format bound found. // For i<j, we can still use j's upper bound as i's upper bound. Same for lower. - ValueRange* range = LookupValueRange(right, block); - if (range != nullptr) { - lower = range->GetLower(); - upper = range->GetUpper(); + ValueRange* right_range = LookupValueRange(right, block); + if (right_range != nullptr) { + if (right_range->IsMonotonicValueRange()) { + ValueRange* left_range = LookupValueRange(left, block); + if (left_range != nullptr && left_range->IsMonotonicValueRange()) { + HandleIfBetweenTwoMonotonicValueRanges(instruction, left, right, cond, + left_range->AsMonotonicValueRange(), + right_range->AsMonotonicValueRange()); + return; + } + } + lower = right_range->GetLower(); + upper = right_range->GetUpper(); } else { lower = ValueBound::Min(); upper = ValueBound::Max(); diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index cda5c1a99c..07cc41a8d5 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -988,7 +988,7 @@ void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) { __ cmp(left, ShifterOperand(locations->InAt(1).AsRegister<Register>())); } else { DCHECK(locations->InAt(1).IsConstant()); - int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue(); + int32_t value = CodeGenerator::GetInt32ValueOf(locations->InAt(1).GetConstant()); ShifterOperand operand; if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, value, &operand)) { __ cmp(left, operand); diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 116dd158d1..3c8f62c789 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -922,7 +922,7 @@ void InstructionCodeGeneratorX86::VisitCondition(HCondition* comp) { if (rhs.IsRegister()) { __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>()); } else if (rhs.IsConstant()) { - int32_t constant = rhs.GetConstant()->AsIntConstant()->GetValue(); + int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant()); if (constant == 0) { __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>()); } else { diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index adc022a2ce..6365bca319 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -894,7 +894,7 @@ void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* comp) { if (rhs.IsRegister()) { __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>()); } else if (rhs.IsConstant()) { - int32_t constant = rhs.GetConstant()->AsIntConstant()->GetValue(); + int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant()); if (constant == 0) { __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>()); } else { diff --git a/compiler/optimizing/common_arm64.h b/compiler/optimizing/common_arm64.h index 007324eb68..9447d3b816 100644 --- a/compiler/optimizing/common_arm64.h +++ b/compiler/optimizing/common_arm64.h @@ -118,8 +118,14 @@ static inline vixl::CPURegister InputCPURegisterAt(HInstruction* instr, int inde static inline int64_t Int64ConstantFrom(Location location) { HConstant* instr = location.GetConstant(); - return instr->IsIntConstant() ? instr->AsIntConstant()->GetValue() - : instr->AsLongConstant()->GetValue(); + if (instr->IsIntConstant()) { + return instr->AsIntConstant()->GetValue(); + } else if (instr->IsNullConstant()) { + return 0; + } else { + DCHECK(instr->IsLongConstant()); + return instr->AsLongConstant()->GetValue(); + } } static inline vixl::Operand OperandFrom(Location location, Primitive::Type type) { diff --git a/compiler/optimizing/gvn.cc b/compiler/optimizing/gvn.cc index cb448c883f..ea65dc0780 100644 --- a/compiler/optimizing/gvn.cc +++ b/compiler/optimizing/gvn.cc @@ -299,8 +299,17 @@ void GlobalValueNumberer::VisitBasicBlock(HBasicBlock* block) { // Save the next instruction in case `current` is removed from the graph. HInstruction* next = current->GetNext(); if (current->CanBeMoved()) { + if (current->IsBinaryOperation() && current->AsBinaryOperation()->IsCommutative()) { + // For commutative ops, (x op y) will be treated the same as (y op x) + // after fixed ordering. + current->AsBinaryOperation()->OrderInputs(); + } HInstruction* existing = set->Lookup(current); if (existing != nullptr) { + // This replacement doesn't make more OrderInputs() necessary since + // current is either used by an instruction that it dominates, + // which hasn't been visited yet due to the order we visit instructions. + // Or current is used by a phi, and we don't do OrderInputs() on a phi anyway. current->ReplaceWith(existing); current->GetBlock()->RemoveInstruction(current); } else { diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 7e075644ef..98076a05f2 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -1500,7 +1500,39 @@ class HBinaryOperation : public HExpression<2> { HInstruction* GetRight() const { return InputAt(1); } Primitive::Type GetResultType() const { return GetType(); } - virtual bool IsCommutative() { return false; } + virtual bool IsCommutative() const { return false; } + + // Put constant on the right. + // Returns whether order is changed. + bool OrderInputsWithConstantOnTheRight() { + HInstruction* left = InputAt(0); + HInstruction* right = InputAt(1); + if (left->IsConstant() && !right->IsConstant()) { + ReplaceInput(right, 0); + ReplaceInput(left, 1); + return true; + } + return false; + } + + // Order inputs by instruction id, but favor constant on the right side. + // This helps GVN for commutative ops. + void OrderInputs() { + DCHECK(IsCommutative()); + HInstruction* left = InputAt(0); + HInstruction* right = InputAt(1); + if (left == right || (!left->IsConstant() && right->IsConstant())) { + return; + } + if (OrderInputsWithConstantOnTheRight()) { + return; + } + // Order according to instruction id. + if (left->GetId() > right->GetId()) { + ReplaceInput(right, 0); + ReplaceInput(left, 1); + } + } virtual bool CanBeMoved() const { return true; } virtual bool InstructionDataEquals(HInstruction* other) const { @@ -1529,8 +1561,6 @@ class HCondition : public HBinaryOperation { : HBinaryOperation(Primitive::kPrimBoolean, first, second), needs_materialization_(true) {} - virtual bool IsCommutative() { return true; } - bool NeedsMaterialization() const { return needs_materialization_; } void ClearNeedsMaterialization() { needs_materialization_ = false; } @@ -1556,6 +1586,8 @@ class HEqual : public HCondition { HEqual(HInstruction* first, HInstruction* second) : HCondition(first, second) {} + bool IsCommutative() const OVERRIDE { return true; } + virtual int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x == y ? 1 : 0; } @@ -1578,6 +1610,8 @@ class HNotEqual : public HCondition { HNotEqual(HInstruction* first, HInstruction* second) : HCondition(first, second) {} + bool IsCommutative() const OVERRIDE { return true; } + virtual int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x != y ? 1 : 0; } @@ -2136,7 +2170,7 @@ class HAdd : public HBinaryOperation { HAdd(Primitive::Type result_type, HInstruction* left, HInstruction* right) : HBinaryOperation(result_type, left, right) {} - virtual bool IsCommutative() { return true; } + virtual bool IsCommutative() const OVERRIDE { return true; } virtual int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x + y; @@ -2174,7 +2208,7 @@ class HMul : public HBinaryOperation { HMul(Primitive::Type result_type, HInstruction* left, HInstruction* right) : HBinaryOperation(result_type, left, right) {} - virtual bool IsCommutative() { return true; } + virtual bool IsCommutative() const OVERRIDE { return true; } virtual int32_t Evaluate(int32_t x, int32_t y) const { return x * y; } virtual int64_t Evaluate(int64_t x, int64_t y) const { return x * y; } @@ -2323,7 +2357,7 @@ class HAnd : public HBinaryOperation { HAnd(Primitive::Type result_type, HInstruction* left, HInstruction* right) : HBinaryOperation(result_type, left, right) {} - bool IsCommutative() OVERRIDE { return true; } + bool IsCommutative() const OVERRIDE { return true; } int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x & y; } int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE { return x & y; } @@ -2339,7 +2373,7 @@ class HOr : public HBinaryOperation { HOr(Primitive::Type result_type, HInstruction* left, HInstruction* right) : HBinaryOperation(result_type, left, right) {} - bool IsCommutative() OVERRIDE { return true; } + bool IsCommutative() const OVERRIDE { return true; } int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x | y; } int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE { return x | y; } @@ -2355,7 +2389,7 @@ class HXor : public HBinaryOperation { HXor(Primitive::Type result_type, HInstruction* left, HInstruction* right) : HBinaryOperation(result_type, left, right) {} - bool IsCommutative() OVERRIDE { return true; } + bool IsCommutative() const OVERRIDE { return true; } int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x ^ y; } int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE { return x ^ y; } |