diff options
-rw-r--r-- | compiler/optimizing/gvn.cc | 5 | ||||
-rw-r--r-- | compiler/optimizing/nodes.cc | 8 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 1 | ||||
-rw-r--r-- | test/477-checker-bound-type/src/Main.java | 76 |
4 files changed, 88 insertions, 2 deletions
diff --git a/compiler/optimizing/gvn.cc b/compiler/optimizing/gvn.cc index 4863718518..e6b6326726 100644 --- a/compiler/optimizing/gvn.cc +++ b/compiler/optimizing/gvn.cc @@ -479,7 +479,10 @@ void GlobalValueNumberer::VisitBasicBlock(HBasicBlock* block) { HInstruction* next = current->GetNext(); // Do not kill the set with the side effects of the instruction just now: if // the instruction is GVN'ed, we don't need to kill. - if (current->CanBeMoved()) { + // + // BoundType is a special case example of an instruction which shouldn't be moved but can be + // GVN'ed. + if (current->CanBeMoved() || current->IsBoundType()) { if (current->IsBinaryOperation() && current->AsBinaryOperation()->IsCommutative()) { // For commutative ops, (x op y) will be treated the same as (y op x) // after fixed ordering. diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index ef8a757ad0..661f66a34c 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -2786,6 +2786,14 @@ void HInstruction::SetReferenceTypeInfo(ReferenceTypeInfo rti) { SetPackedFlag<kFlagReferenceTypeIsExact>(rti.IsExact()); } +bool HBoundType::InstructionDataEquals(const HInstruction* other) const { + const HBoundType* other_bt = other->AsBoundType(); + ScopedObjectAccess soa(Thread::Current()); + return GetUpperBound().IsEqual(other_bt->GetUpperBound()) && + GetUpperCanBeNull() == other_bt->GetUpperCanBeNull() && + CanBeNull() == other_bt->CanBeNull(); +} + void HBoundType::SetUpperBound(const ReferenceTypeInfo& upper_bound, bool can_be_null) { if (kIsDebugBuild) { ScopedObjectAccess soa(Thread::Current()); diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 2037879726..975ad1c324 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -7142,6 +7142,7 @@ class HBoundType FINAL : public HExpression<1> { SetRawInputAt(0, input); } + bool InstructionDataEquals(const HInstruction* other) const OVERRIDE; bool IsClonable() const OVERRIDE { return true; } // {Get,Set}Upper* should only be used in reference type propagation. diff --git a/test/477-checker-bound-type/src/Main.java b/test/477-checker-bound-type/src/Main.java index 2504ab2839..237e4dafb6 100644 --- a/test/477-checker-bound-type/src/Main.java +++ b/test/477-checker-bound-type/src/Main.java @@ -57,5 +57,79 @@ public class Main { } } - public static void main(String[] args) { } + /// CHECK-START: void Main.boundTypeInLoop(int[]) licm (before) + /// CHECK-DAG: <<Param:l\d+>> ParameterValue loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<BoundT:l\d+>> BoundType [<<Param>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayLength [<<BoundT>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none + + /// CHECK-START: void Main.boundTypeInLoop(int[]) licm (after) + /// CHECK-DAG: <<Param:l\d+>> ParameterValue loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<BoundT:l\d+>> BoundType [<<Param>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayLength [<<BoundT>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: BoundType + + /// CHECK-START: void Main.boundTypeInLoop(int[]) loop_optimization (after) + /// CHECK-DAG: <<Param:l\d+>> ParameterValue loop:none + /// CHECK-DAG: <<BoundTA:l\d+>> BoundType [<<Param>>] loop:none + /// CHECK-DAG: ArrayLength [<<BoundTA>>] loop:none + /// CHECK-DAG: ArrayGet loop:none + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<BoundT:l\d+>> BoundType [<<Param>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayLength [<<BoundT>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none + + /// CHECK-START: void Main.boundTypeInLoop(int[]) GVN$after_arch (after) + /// CHECK-DAG: <<Param:l\d+>> ParameterValue loop:none + /// CHECK-DAG: <<BoundTA:l\d+>> BoundType [<<Param>>] loop:none + /// CHECK-DAG: ArrayLength [<<BoundTA>>] loop:none + /// CHECK-DAG: ArrayGet loop:none + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: BoundType + /// CHECK-NOT: ArrayLength + private static void boundTypeInLoop(int[] a) { + for (int i = 0; a != null && i < a.length; i++) { + a[i] += 1; + } + } + + // BoundType must not be hoisted by LICM, in this example it leads to ArrayLength being + // hoisted as well which is invalid. + // + /// CHECK-START: void Main.BoundTypeNoLICM(java.lang.Object) licm (before) + /// CHECK-DAG: <<Param:l\d+>> ParameterValue loop:none + /// CHECK-DAG: SuspendCheck loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Bound1:l\d+>> BoundType [<<Param>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Bound2:l\d+>> BoundType [<<Bound1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayLength [<<Bound2>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START: void Main.BoundTypeNoLICM(java.lang.Object) licm (after) + /// CHECK-DAG: <<Param:l\d+>> ParameterValue loop:none + /// CHECK-DAG: SuspendCheck loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Bound1:l\d+>> BoundType [<<Param>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Bound2:l\d+>> BoundType [<<Bound1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayLength [<<Bound2>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: BoundType loop:none + private static void BoundTypeNoLICM(Object obj) { + int i = 0; + while (obj instanceof int[]) { + int[] a = (int[])obj; + a[0] = 1; + } + } + + public static void main(String[] args) { } } |