diff options
Diffstat (limited to 'compiler/optimizing')
| -rw-r--r-- | compiler/optimizing/nodes.h | 20 | ||||
| -rw-r--r-- | compiler/optimizing/reference_type_propagation.cc | 39 | ||||
| -rw-r--r-- | compiler/optimizing/reference_type_propagation.h | 1 |
3 files changed, 55 insertions, 5 deletions
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index de448cc483..7e075644ef 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -1039,6 +1039,8 @@ class HInstruction : public ArenaObject<kArenaAllocMisc> { virtual bool CanThrow() const { return false; } bool HasSideEffects() const { return side_effects_.HasSideEffects(); } + virtual bool ActAsNullConstant() const { return false; } + // Does not apply for all instructions, but having this at top level greatly // simplifies the null check elimination. virtual bool CanBeNull() const { @@ -1049,10 +1051,14 @@ class HInstruction : public ArenaObject<kArenaAllocMisc> { virtual bool CanDoImplicitNullCheck() const { return false; } void SetReferenceTypeInfo(ReferenceTypeInfo reference_type_info) { + DCHECK_EQ(GetType(), Primitive::kPrimNot); reference_type_info_ = reference_type_info; } - ReferenceTypeInfo GetReferenceTypeInfo() const { return reference_type_info_; } + ReferenceTypeInfo GetReferenceTypeInfo() const { + DCHECK_EQ(GetType(), Primitive::kPrimNot); + return reference_type_info_; + } void AddUseAt(HInstruction* user, size_t index) { DCHECK(user != nullptr); @@ -1838,6 +1844,8 @@ class HNullConstant : public HConstant { size_t ComputeHashCode() const OVERRIDE { return 0; } + bool ActAsNullConstant() const OVERRIDE { return true; } + DECLARE_INSTRUCTION(NullConstant); private: @@ -1852,11 +1860,16 @@ class HIntConstant : public HConstant { int32_t GetValue() const { return value_; } - virtual bool InstructionDataEquals(HInstruction* other) const { + bool InstructionDataEquals(HInstruction* other) const OVERRIDE { return other->AsIntConstant()->value_ == value_; } - virtual size_t ComputeHashCode() const { return GetValue(); } + size_t ComputeHashCode() const OVERRIDE { return GetValue(); } + + // TODO: Null is represented by the `0` constant. In most cases we replace it + // with a HNullConstant but we don't do it when comparing (a != null). This + // method is an workaround until we fix the above. + bool ActAsNullConstant() const OVERRIDE { return value_ == 0; } DECLARE_INSTRUCTION(IntConstant); @@ -3063,6 +3076,7 @@ class HBoundType : public HExpression<1> { HBoundType(HInstruction* input, ReferenceTypeInfo bound_type) : HExpression(Primitive::kPrimNot, SideEffects::None()), bound_type_(bound_type) { + DCHECK_EQ(input->GetType(), Primitive::kPrimNot); SetRawInputAt(0, input); } diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc index 76b8d7eacf..479b87fea0 100644 --- a/compiler/optimizing/reference_type_propagation.cc +++ b/compiler/optimizing/reference_type_propagation.cc @@ -23,8 +23,6 @@ namespace art { -// TODO: handle: a !=/== null. - void ReferenceTypePropagation::Run() { // To properly propagate type info we need to visit in the dominator-based order. // Reverse post order guarantees a node's dominators are visited first. @@ -55,9 +53,46 @@ void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) { } // Add extra nodes to bound types. + BoundTypeForIfNotNull(block); BoundTypeForIfInstanceOf(block); } +void ReferenceTypePropagation::BoundTypeForIfNotNull(HBasicBlock* block) { + HInstruction* lastInstruction = block->GetLastInstruction(); + if (!lastInstruction->IsIf()) { + return; + } + HInstruction* ifInput = lastInstruction->InputAt(0); + if (!ifInput->IsNotEqual() && !ifInput->IsEqual()) { + return; + } + HInstruction* input0 = ifInput->InputAt(0); + HInstruction* input1 = ifInput->InputAt(1); + HInstruction* obj; + + if ((input0->GetType() == Primitive::kPrimNot) && input1->ActAsNullConstant()) { + obj = input0; + } else if ((input1->GetType() == Primitive::kPrimNot) && input0->ActAsNullConstant()) { + obj = input1; + } else { + return; + } + + HBoundType* bound_type = + new (graph_->GetArena()) HBoundType(obj, ReferenceTypeInfo::CreateTop(false)); + + block->InsertInstructionBefore(bound_type, lastInstruction); + HBasicBlock* notNullBlock = ifInput->IsNotEqual() + ? lastInstruction->AsIf()->IfTrueSuccessor() + : lastInstruction->AsIf()->IfFalseSuccessor(); + for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) { + HInstruction* user = it.Current()->GetUser(); + if (notNullBlock->Dominates(user->GetBlock())) { + user->ReplaceInput(bound_type, it.Current()->GetIndex()); + } + } +} + // Detects if `block` is the True block for the pattern // `if (x instanceof ClassX) { }` // If that's the case insert an HBoundType instruction to bound the type of `x` diff --git a/compiler/optimizing/reference_type_propagation.h b/compiler/optimizing/reference_type_propagation.h index e346dbfc6c..815caab4f3 100644 --- a/compiler/optimizing/reference_type_propagation.h +++ b/compiler/optimizing/reference_type_propagation.h @@ -51,6 +51,7 @@ class ReferenceTypePropagation : public HOptimization { void UpdateBoundType(HBoundType* bound_type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void UpdatePhi(HPhi* phi) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + void BoundTypeForIfNotNull(HBasicBlock* block); void BoundTypeForIfInstanceOf(HBasicBlock* block); void ProcessWorklist(); |