summaryrefslogtreecommitdiff
path: root/compiler/optimizing
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing')
-rw-r--r--compiler/optimizing/nodes.h20
-rw-r--r--compiler/optimizing/reference_type_propagation.cc39
-rw-r--r--compiler/optimizing/reference_type_propagation.h1
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();