summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Artem Serov <artem.serov@linaro.org> 2018-06-05 20:54:42 +0100
committer Artem Serov <artem.serov@linaro.org> 2018-06-15 16:37:44 +0100
commit4d277ba858389980525c16c4b0655ee72af5a44c (patch)
tree5f8c522b1340e52a94af1d329cf069c74d1bb288
parent0e3a330f4a545a6a2d352bd4a803c8387f54e76b (diff)
ART: Make GVN work with BoundType.
Support BoundType instruction treatment in GVN. Note: BoundType must not be a subject to LICM as it must not be moved from more control dependent basic blocks to less control dependent (e.g. hoisted out from the loop) due to semantics of bounding the type. Test: 477-checker-bound-type. Test: test-art-target, test-art-host. Change-Id: I64263d6ec7d9ad75d1fb07d3a89e9973be67682b
-rw-r--r--compiler/optimizing/gvn.cc5
-rw-r--r--compiler/optimizing/nodes.cc8
-rw-r--r--compiler/optimizing/nodes.h1
-rw-r--r--test/477-checker-bound-type/src/Main.java76
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) { }
}