diff options
author | 2016-04-13 16:41:35 -0700 | |
---|---|---|
committer | 2016-04-15 10:49:34 -0700 | |
commit | 18b36abc7cc03076fe1c399c0bb8ec8793cc6806 (patch) | |
tree | 3e38ee71b94c7bbde6f93976e16416a2f6d33ee0 | |
parent | defccc564481c2c892792680c6abb6020e36bacd (diff) |
Remove the no-longer-needed F/I and D/J alias.
Rationale:
Now that our HIR is type clean (yeah!), we no longer have
to conservatively assume F/I and D/J are aliased. This
enables more accurate side effects analysis, with improvements
in all clients, such a LICM.
Refinement:
The HIR is not completely clean between building and SSA.
This refinement takes care of that, with new tests.
BUG=22538329
Change-Id: Id78ff0ff4e325aeebf0022d868937cff73d3a742
-rw-r--r-- | compiler/optimizing/licm_test.cc | 12 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 52 | ||||
-rw-r--r-- | compiler/optimizing/side_effects_test.cc | 34 | ||||
-rw-r--r-- | compiler/optimizing/ssa_builder.cc | 3 | ||||
-rw-r--r-- | test/525-checker-arrays-and-fields/expected.txt | 0 | ||||
-rw-r--r-- | test/525-checker-arrays-and-fields/info.txt | 1 | ||||
-rw-r--r-- | test/525-checker-arrays-fields1/expected.txt | 1 | ||||
-rw-r--r-- | test/525-checker-arrays-fields1/info.txt | 1 | ||||
-rw-r--r-- | test/525-checker-arrays-fields1/src/Main.java | 711 | ||||
-rw-r--r-- | test/525-checker-arrays-fields2/expected.txt | 1 | ||||
-rw-r--r-- | test/525-checker-arrays-fields2/info.txt | 1 | ||||
-rw-r--r-- | test/525-checker-arrays-fields2/src/Main.java (renamed from test/525-checker-arrays-and-fields/src/Main.java) | 638 | ||||
-rw-r--r-- | test/594-checker-array-alias/expected.txt | 1 | ||||
-rw-r--r-- | test/594-checker-array-alias/info.txt | 1 | ||||
-rw-r--r-- | test/594-checker-array-alias/src/Main.java | 255 |
15 files changed, 1145 insertions, 567 deletions
diff --git a/compiler/optimizing/licm_test.cc b/compiler/optimizing/licm_test.cc index d446539700..2a62643465 100644 --- a/compiler/optimizing/licm_test.cc +++ b/compiler/optimizing/licm_test.cc @@ -169,13 +169,11 @@ TEST_F(LICMTest, ArrayHoisting) { BuildLoop(); // Populate the loop with instructions: set/get array with different types. - // ArrayGet is typed as kPrimByte and ArraySet given a float value in order to - // avoid SsaBuilder's typing of ambiguous array operations from reference type info. HInstruction* get_array = new (&allocator_) HArrayGet( - parameter_, int_constant_, Primitive::kPrimByte, 0); + parameter_, int_constant_, Primitive::kPrimInt, 0); loop_body_->InsertInstructionBefore(get_array, loop_body_->GetLastInstruction()); HInstruction* set_array = new (&allocator_) HArraySet( - parameter_, int_constant_, float_constant_, Primitive::kPrimShort, 0); + parameter_, int_constant_, float_constant_, Primitive::kPrimFloat, 0); loop_body_->InsertInstructionBefore(set_array, loop_body_->GetLastInstruction()); EXPECT_EQ(get_array->GetBlock(), loop_body_); @@ -189,13 +187,11 @@ TEST_F(LICMTest, NoArrayHoisting) { BuildLoop(); // Populate the loop with instructions: set/get array with same types. - // ArrayGet is typed as kPrimByte and ArraySet given a float value in order to - // avoid SsaBuilder's typing of ambiguous array operations from reference type info. HInstruction* get_array = new (&allocator_) HArrayGet( - parameter_, int_constant_, Primitive::kPrimByte, 0); + parameter_, int_constant_, Primitive::kPrimFloat, 0); loop_body_->InsertInstructionBefore(get_array, loop_body_->GetLastInstruction()); HInstruction* set_array = new (&allocator_) HArraySet( - parameter_, get_array, float_constant_, Primitive::kPrimByte, 0); + parameter_, get_array, float_constant_, Primitive::kPrimFloat, 0); loop_body_->InsertInstructionBefore(set_array, loop_body_->GetLastInstruction()); EXPECT_EQ(get_array->GetBlock(), loop_body_); diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index dc5a8fa9cb..8b64fe0201 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -1551,21 +1551,21 @@ class SideEffects : public ValueObject { static SideEffects FieldWriteOfType(Primitive::Type type, bool is_volatile) { return is_volatile ? AllWritesAndReads() - : SideEffects(TypeFlagWithAlias(type, kFieldWriteOffset)); + : SideEffects(TypeFlag(type, kFieldWriteOffset)); } static SideEffects ArrayWriteOfType(Primitive::Type type) { - return SideEffects(TypeFlagWithAlias(type, kArrayWriteOffset)); + return SideEffects(TypeFlag(type, kArrayWriteOffset)); } static SideEffects FieldReadOfType(Primitive::Type type, bool is_volatile) { return is_volatile ? AllWritesAndReads() - : SideEffects(TypeFlagWithAlias(type, kFieldReadOffset)); + : SideEffects(TypeFlag(type, kFieldReadOffset)); } static SideEffects ArrayReadOfType(Primitive::Type type) { - return SideEffects(TypeFlagWithAlias(type, kArrayReadOffset)); + return SideEffects(TypeFlag(type, kArrayReadOffset)); } static SideEffects CanTriggerGC() { @@ -1692,23 +1692,6 @@ class SideEffects : public ValueObject { static constexpr uint64_t kAllReads = ((1ULL << (kLastBitForReads + 1 - kFieldReadOffset)) - 1) << kFieldReadOffset; - // Work around the fact that HIR aliases I/F and J/D. - // TODO: remove this interceptor once HIR types are clean - static uint64_t TypeFlagWithAlias(Primitive::Type type, int offset) { - switch (type) { - case Primitive::kPrimInt: - case Primitive::kPrimFloat: - return TypeFlag(Primitive::kPrimInt, offset) | - TypeFlag(Primitive::kPrimFloat, offset); - case Primitive::kPrimLong: - case Primitive::kPrimDouble: - return TypeFlag(Primitive::kPrimLong, offset) | - TypeFlag(Primitive::kPrimDouble, offset); - default: - return TypeFlag(type, offset); - } - } - // Translates type to bit flag. static uint64_t TypeFlag(Primitive::Type type, int offset) { CHECK_NE(type, Primitive::kPrimVoid); @@ -5137,14 +5120,8 @@ class HInstanceFieldSet : public HTemplateInstruction<2> { class HArrayGet : public HExpression<2> { public: - HArrayGet(HInstruction* array, - HInstruction* index, - Primitive::Type type, - uint32_t dex_pc, - SideEffects additional_side_effects = SideEffects::None()) - : HExpression(type, - SideEffects::ArrayReadOfType(type).Union(additional_side_effects), - dex_pc) { + HArrayGet(HInstruction* array, HInstruction* index, Primitive::Type type, uint32_t dex_pc) + : HExpression(type, SideEffects::ArrayReadOfType(type), dex_pc) { SetRawInputAt(0, array); SetRawInputAt(1, index); } @@ -5193,13 +5170,8 @@ class HArraySet : public HTemplateInstruction<3> { HInstruction* index, HInstruction* value, Primitive::Type expected_component_type, - uint32_t dex_pc, - SideEffects additional_side_effects = SideEffects::None()) - : HTemplateInstruction( - SideEffects::ArrayWriteOfType(expected_component_type).Union( - SideEffectsForArchRuntimeCalls(value->GetType())).Union( - additional_side_effects), - dex_pc) { + uint32_t dex_pc) + : HTemplateInstruction(SideEffects::None(), dex_pc) { SetPackedField<ExpectedComponentTypeField>(expected_component_type); SetPackedFlag<kFlagNeedsTypeCheck>(value->GetType() == Primitive::kPrimNot); SetPackedFlag<kFlagValueCanBeNull>(true); @@ -5207,6 +5179,8 @@ class HArraySet : public HTemplateInstruction<3> { SetRawInputAt(0, array); SetRawInputAt(1, index); SetRawInputAt(2, value); + // Make a best guess now, may be refined during SSA building. + ComputeSideEffects(); } bool NeedsEnvironment() const OVERRIDE { @@ -5259,6 +5233,12 @@ class HArraySet : public HTemplateInstruction<3> { return GetPackedField<ExpectedComponentTypeField>(); } + void ComputeSideEffects() { + Primitive::Type type = GetComponentType(); + SetSideEffects(SideEffects::ArrayWriteOfType(type).Union( + SideEffectsForArchRuntimeCalls(type))); + } + static SideEffects SideEffectsForArchRuntimeCalls(Primitive::Type value_type) { return (value_type == Primitive::kPrimNot) ? SideEffects::CanTriggerGC() : SideEffects::None(); } diff --git a/compiler/optimizing/side_effects_test.cc b/compiler/optimizing/side_effects_test.cc index 9bbc354290..b01bc1ca0d 100644 --- a/compiler/optimizing/side_effects_test.cc +++ b/compiler/optimizing/side_effects_test.cc @@ -148,19 +148,19 @@ TEST(SideEffectsTest, VolatileDependences) { EXPECT_FALSE(any_write.MayDependOn(volatile_read)); } -TEST(SideEffectsTest, SameWidthTypes) { +TEST(SideEffectsTest, SameWidthTypesNoAlias) { // Type I/F. - testWriteAndReadDependence( + testNoWriteAndReadDependence( SideEffects::FieldWriteOfType(Primitive::kPrimInt, /* is_volatile */ false), SideEffects::FieldReadOfType(Primitive::kPrimFloat, /* is_volatile */ false)); - testWriteAndReadDependence( + testNoWriteAndReadDependence( SideEffects::ArrayWriteOfType(Primitive::kPrimInt), SideEffects::ArrayReadOfType(Primitive::kPrimFloat)); // Type L/D. - testWriteAndReadDependence( + testNoWriteAndReadDependence( SideEffects::FieldWriteOfType(Primitive::kPrimLong, /* is_volatile */ false), SideEffects::FieldReadOfType(Primitive::kPrimDouble, /* is_volatile */ false)); - testWriteAndReadDependence( + testNoWriteAndReadDependence( SideEffects::ArrayWriteOfType(Primitive::kPrimLong), SideEffects::ArrayReadOfType(Primitive::kPrimDouble)); } @@ -216,14 +216,32 @@ TEST(SideEffectsTest, BitStrings) { "||||||L|", SideEffects::FieldWriteOfType(Primitive::kPrimNot, false).ToString().c_str()); EXPECT_STREQ( + "||DFJISCBZL|DFJISCBZL||DFJISCBZL|DFJISCBZL|", + SideEffects::FieldWriteOfType(Primitive::kPrimNot, true).ToString().c_str()); + EXPECT_STREQ( "|||||Z||", SideEffects::ArrayWriteOfType(Primitive::kPrimBoolean).ToString().c_str()); EXPECT_STREQ( + "|||||C||", + SideEffects::ArrayWriteOfType(Primitive::kPrimChar).ToString().c_str()); + EXPECT_STREQ( + "|||||S||", + SideEffects::ArrayWriteOfType(Primitive::kPrimShort).ToString().c_str()); + EXPECT_STREQ( "|||B||||", SideEffects::FieldReadOfType(Primitive::kPrimByte, false).ToString().c_str()); EXPECT_STREQ( - "||DJ|||||", // note: DJ alias + "||D|||||", SideEffects::ArrayReadOfType(Primitive::kPrimDouble).ToString().c_str()); + EXPECT_STREQ( + "||J|||||", + SideEffects::ArrayReadOfType(Primitive::kPrimLong).ToString().c_str()); + EXPECT_STREQ( + "||F|||||", + SideEffects::ArrayReadOfType(Primitive::kPrimFloat).ToString().c_str()); + EXPECT_STREQ( + "||I|||||", + SideEffects::ArrayReadOfType(Primitive::kPrimInt).ToString().c_str()); SideEffects s = SideEffects::None(); s = s.Union(SideEffects::FieldWriteOfType(Primitive::kPrimChar, /* is_volatile */ false)); s = s.Union(SideEffects::FieldWriteOfType(Primitive::kPrimLong, /* is_volatile */ false)); @@ -231,9 +249,7 @@ TEST(SideEffectsTest, BitStrings) { s = s.Union(SideEffects::FieldReadOfType(Primitive::kPrimInt, /* is_volatile */ false)); s = s.Union(SideEffects::ArrayReadOfType(Primitive::kPrimFloat)); s = s.Union(SideEffects::ArrayReadOfType(Primitive::kPrimDouble)); - EXPECT_STREQ( - "||DFJI|FI||S|DJC|", // note: DJ/FI alias. - s.ToString().c_str()); + EXPECT_STREQ("||DF|I||S|JC|", s.ToString().c_str()); } } // namespace art diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc index eeadbeb0d1..2fe2f2053a 100644 --- a/compiler/optimizing/ssa_builder.cc +++ b/compiler/optimizing/ssa_builder.cc @@ -391,6 +391,9 @@ bool SsaBuilder::FixAmbiguousArrayOps() { worklist.push_back(equivalent->AsPhi()); } } + // Refine the side effects of this floating point aset. Note that we do this even if + // no replacement occurs, since the right-hand-side may have been corrected already. + aset->ComputeSideEffects(); } else { // Array elements are integral and the value assigned to it initially // was integral too. Nothing to do. diff --git a/test/525-checker-arrays-and-fields/expected.txt b/test/525-checker-arrays-and-fields/expected.txt deleted file mode 100644 index e69de29bb2..0000000000 --- a/test/525-checker-arrays-and-fields/expected.txt +++ /dev/null diff --git a/test/525-checker-arrays-and-fields/info.txt b/test/525-checker-arrays-and-fields/info.txt deleted file mode 100644 index 3e16abf204..0000000000 --- a/test/525-checker-arrays-and-fields/info.txt +++ /dev/null @@ -1 +0,0 @@ -Test on (in)variant static and instance field and array references in loops. diff --git a/test/525-checker-arrays-fields1/expected.txt b/test/525-checker-arrays-fields1/expected.txt new file mode 100644 index 0000000000..b0aad4deb5 --- /dev/null +++ b/test/525-checker-arrays-fields1/expected.txt @@ -0,0 +1 @@ +passed diff --git a/test/525-checker-arrays-fields1/info.txt b/test/525-checker-arrays-fields1/info.txt new file mode 100644 index 0000000000..7d0a088934 --- /dev/null +++ b/test/525-checker-arrays-fields1/info.txt @@ -0,0 +1 @@ +Test on (in)variant static field and array references in loops. diff --git a/test/525-checker-arrays-fields1/src/Main.java b/test/525-checker-arrays-fields1/src/Main.java new file mode 100644 index 0000000000..ba0476af5f --- /dev/null +++ b/test/525-checker-arrays-fields1/src/Main.java @@ -0,0 +1,711 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// Test on (in)variant static field and array references in loops. +// +public class Main { + + private static Object anObject = new Object(); + private static Object anotherObject = new Object(); + + // + // Static fields. + // + + private static boolean sZ; + private static byte sB; + private static char sC; + private static short sS; + private static int sI; + private static long sJ; + private static float sF; + private static double sD; + private static Object sL; + + // + // Static arrays. + // + + private static boolean[] sArrZ; + private static byte[] sArrB; + private static char[] sArrC; + private static short[] sArrS; + private static int[] sArrI; + private static long[] sArrJ; + private static float[] sArrF; + private static double[] sArrD; + private static Object[] sArrL; + + // + // Loops on static arrays with invariant static field references. + // The checker is used to ensure hoisting occurred. + // + + /// CHECK-START: void Main.InvLoopZ() licm (before) + /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} + /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} + + /// CHECK-START: void Main.InvLoopZ() licm (after) + /// CHECK-DAG: StaticFieldGet loop:none + /// CHECK-DAG: StaticFieldGet loop:none + + private static void InvLoopZ() { + for (int i = 0; i < sArrZ.length; i++) { + sArrZ[i] = sZ; + } + } + + /// CHECK-START: void Main.InvLoopB() licm (before) + /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} + /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} + + /// CHECK-START: void Main.InvLoopB() licm (after) + /// CHECK-DAG: StaticFieldGet loop:none + /// CHECK-DAG: StaticFieldGet loop:none + + private static void InvLoopB() { + for (int i = 0; i < sArrB.length; i++) { + sArrB[i] = sB; + } + } + + /// CHECK-START: void Main.InvLoopC() licm (before) + /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} + /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} + + /// CHECK-START: void Main.InvLoopC() licm (after) + /// CHECK-DAG: StaticFieldGet loop:none + /// CHECK-DAG: StaticFieldGet loop:none + + private static void InvLoopC() { + for (int i = 0; i < sArrC.length; i++) { + sArrC[i] = sC; + } + } + + /// CHECK-START: void Main.InvLoopS() licm (before) + /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} + /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} + + /// CHECK-START: void Main.InvLoopS() licm (after) + /// CHECK-DAG: StaticFieldGet loop:none + /// CHECK-DAG: StaticFieldGet loop:none + + private static void InvLoopS() { + for (int i = 0; i < sArrS.length; i++) { + sArrS[i] = sS; + } + } + + /// CHECK-START: void Main.InvLoopI() licm (before) + /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} + /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} + + /// CHECK-START: void Main.InvLoopI() licm (after) + /// CHECK-DAG: StaticFieldGet loop:none + /// CHECK-DAG: StaticFieldGet loop:none + + private static void InvLoopI() { + for (int i = 0; i < sArrI.length; i++) { + sArrI[i] = sI; + } + } + + /// CHECK-START: void Main.InvLoopJ() licm (before) + /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} + /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} + + /// CHECK-START: void Main.InvLoopJ() licm (after) + /// CHECK-DAG: StaticFieldGet loop:none + /// CHECK-DAG: StaticFieldGet loop:none + + private static void InvLoopJ() { + for (int i = 0; i < sArrJ.length; i++) { + sArrJ[i] = sJ; + } + } + + /// CHECK-START: void Main.InvLoopF() licm (before) + /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} + /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} + + /// CHECK-START: void Main.InvLoopF() licm (after) + /// CHECK-DAG: StaticFieldGet loop:none + /// CHECK-DAG: StaticFieldGet loop:none + + private static void InvLoopF() { + for (int i = 0; i < sArrF.length; i++) { + sArrF[i] = sF; + } + } + + /// CHECK-START: void Main.InvLoopD() licm (before) + /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} + /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} + + /// CHECK-START: void Main.InvLoopD() licm (after) + /// CHECK-DAG: StaticFieldGet loop:none + /// CHECK-DAG: StaticFieldGet loop:none + + private static void InvLoopD() { + for (int i = 0; i < sArrD.length; i++) { + sArrD[i] = sD; + } + } + + /// CHECK-START: void Main.InvLoopL() licm (before) + /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} + /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} + + /// CHECK-START: void Main.InvLoopL() licm (after) + /// CHECK-DAG: StaticFieldGet loop:none + /// CHECK-DAG: StaticFieldGet loop:none + + private static void InvLoopL() { + for (int i = 0; i < sArrL.length; i++) { + sArrL[i] = sL; + } + } + + // + // Loops on static arrays with variant static field references. + // Incorrect hoisting is detected by incorrect outcome. + // + + private static void VarLoopZ() { + for (int i = 0; i < sArrZ.length; i++) { + sArrZ[i] = sZ; + if (i == 10) + sZ = !sZ; + } + } + + private static void VarLoopB() { + for (int i = 0; i < sArrB.length; i++) { + sArrB[i] = sB; + if (i == 10) + sB++; + } + } + + private static void VarLoopC() { + for (int i = 0; i < sArrC.length; i++) { + sArrC[i] = sC; + if (i == 10) + sC++; + } + } + + private static void VarLoopS() { + for (int i = 0; i < sArrS.length; i++) { + sArrS[i] = sS; + if (i == 10) + sS++; + } + } + + private static void VarLoopI() { + for (int i = 0; i < sArrI.length; i++) { + sArrI[i] = sI; + if (i == 10) + sI++; + } + } + + private static void VarLoopJ() { + for (int i = 0; i < sArrJ.length; i++) { + sArrJ[i] = sJ; + if (i == 10) + sJ++; + } + } + + private static void VarLoopF() { + for (int i = 0; i < sArrF.length; i++) { + sArrF[i] = sF; + if (i == 10) + sF++; + } + } + + private static void VarLoopD() { + for (int i = 0; i < sArrD.length; i++) { + sArrD[i] = sD; + if (i == 10) + sD++; + } + } + + private static void VarLoopL() { + for (int i = 0; i < sArrL.length; i++) { + sArrL[i] = sL; + if (i == 10) + sL = anotherObject; + } + } + + // + // Loops on static arrays with a cross-over reference. + // Incorrect hoisting is detected by incorrect outcome. + // In addition, the checker is used to detect no hoisting. + // + + /// CHECK-START: void Main.CrossOverLoopZ() licm (before) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + /// CHECK-START: void Main.CrossOverLoopZ() licm (after) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + private static void CrossOverLoopZ() { + sArrZ[20] = false; + for (int i = 0; i < sArrZ.length; i++) { + sArrZ[i] = !sArrZ[20]; + } + } + + /// CHECK-START: void Main.CrossOverLoopB() licm (before) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + /// CHECK-START: void Main.CrossOverLoopB() licm (after) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + private static void CrossOverLoopB() { + sArrB[20] = 11; + for (int i = 0; i < sArrB.length; i++) { + sArrB[i] = (byte)(sArrB[20] + 2); + } + } + + /// CHECK-START: void Main.CrossOverLoopC() licm (before) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + /// CHECK-START: void Main.CrossOverLoopC() licm (after) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + private static void CrossOverLoopC() { + sArrC[20] = 11; + for (int i = 0; i < sArrC.length; i++) { + sArrC[i] = (char)(sArrC[20] + 2); + } + } + + /// CHECK-START: void Main.CrossOverLoopS() licm (before) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + /// CHECK-START: void Main.CrossOverLoopS() licm (after) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + private static void CrossOverLoopS() { + sArrS[20] = 11; + for (int i = 0; i < sArrS.length; i++) { + sArrS[i] = (short)(sArrS[20] + 2); + } + } + + /// CHECK-START: void Main.CrossOverLoopI() licm (before) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + /// CHECK-START: void Main.CrossOverLoopI() licm (after) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + private static void CrossOverLoopI() { + sArrI[20] = 11; + for (int i = 0; i < sArrI.length; i++) { + sArrI[i] = sArrI[20] + 2; + } + } + + /// CHECK-START: void Main.CrossOverLoopJ() licm (before) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + /// CHECK-START: void Main.CrossOverLoopJ() licm (after) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + private static void CrossOverLoopJ() { + sArrJ[20] = 11; + for (int i = 0; i < sArrJ.length; i++) { + sArrJ[i] = sArrJ[20] + 2; + } + } + + /// CHECK-START: void Main.CrossOverLoopF() licm (before) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + /// CHECK-START: void Main.CrossOverLoopF() licm (after) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + private static void CrossOverLoopF() { + sArrF[20] = 11; + for (int i = 0; i < sArrF.length; i++) { + sArrF[i] = sArrF[20] + 2; + } + } + + /// CHECK-START: void Main.CrossOverLoopD() licm (before) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + /// CHECK-START: void Main.CrossOverLoopD() licm (after) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + private static void CrossOverLoopD() { + sArrD[20] = 11; + for (int i = 0; i < sArrD.length; i++) { + sArrD[i] = sArrD[20] + 2; + } + } + + /// CHECK-START: void Main.CrossOverLoopL() licm (before) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + /// CHECK-START: void Main.CrossOverLoopL() licm (after) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + private static void CrossOverLoopL() { + sArrL[20] = anotherObject; + for (int i = 0; i < sArrL.length; i++) { + sArrL[i] = (sArrL[20] == anObject) ? anotherObject : anObject; + } + } + + // + // False cross-over loops on static arrays with data types (I/F and J/D) that used + // to be aliased in an older version of the compiler. This alias has been removed, + // however, which enables hoisting the invariant array reference. + // + + /// CHECK-START: void Main.FalseCrossOverLoop1() licm (before) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + /// CHECK-START: void Main.FalseCrossOverLoop1() licm (after) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:none + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + private static void FalseCrossOverLoop1() { + sArrF[20] = -1; + for (int i = 0; i < sArrI.length; i++) { + sArrI[i] = (int) sArrF[20] - 2; + } + } + + /// CHECK-START: void Main.FalseCrossOverLoop2() licm (before) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + /// CHECK-START: void Main.FalseCrossOverLoop2() licm (after) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:none + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + private static void FalseCrossOverLoop2() { + sArrI[20] = -2; + for (int i = 0; i < sArrF.length; i++) { + sArrF[i] = sArrI[20] - 2; + } + } + + /// CHECK-START: void Main.FalseCrossOverLoop3() licm (before) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + /// CHECK-START: void Main.FalseCrossOverLoop3() licm (after) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:none + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + private static void FalseCrossOverLoop3() { + sArrD[20] = -3; + for (int i = 0; i < sArrJ.length; i++) { + sArrJ[i] = (long) sArrD[20] - 2; + } + } + + /// CHECK-START: void Main.FalseCrossOverLoop4() licm (before) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + /// CHECK-START: void Main.FalseCrossOverLoop4() licm (after) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:none + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + private static void FalseCrossOverLoop4() { + sArrJ[20] = -4; + for (int i = 0; i < sArrD.length; i++) { + sArrD[i] = sArrJ[20] - 2; + } + } + + // + // Main driver and testers. + // + + public static void main(String[] args) { + DoStaticTests(); + System.out.println("passed"); + } + + private static void DoStaticTests() { + // Type Z. + sZ = true; + sArrZ = new boolean[100]; + InvLoopZ(); + for (int i = 0; i < sArrZ.length; i++) { + expectEquals(true, sArrZ[i]); + } + VarLoopZ(); + for (int i = 0; i < sArrZ.length; i++) { + expectEquals(i <= 10, sArrZ[i]); + } + CrossOverLoopZ(); + for (int i = 0; i < sArrZ.length; i++) { + expectEquals(i <= 20, sArrZ[i]); + } + // Type B. + sB = 1; + sArrB = new byte[100]; + InvLoopB(); + for (int i = 0; i < sArrB.length; i++) { + expectEquals(1, sArrB[i]); + } + VarLoopB(); + for (int i = 0; i < sArrB.length; i++) { + expectEquals(i <= 10 ? 1 : 2, sArrB[i]); + } + CrossOverLoopB(); + for (int i = 0; i < sArrB.length; i++) { + expectEquals(i <= 20 ? 13 : 15, sArrB[i]); + } + // Type C. + sC = 2; + sArrC = new char[100]; + InvLoopC(); + for (int i = 0; i < sArrC.length; i++) { + expectEquals(2, sArrC[i]); + } + VarLoopC(); + for (int i = 0; i < sArrC.length; i++) { + expectEquals(i <= 10 ? 2 : 3, sArrC[i]); + } + CrossOverLoopC(); + for (int i = 0; i < sArrC.length; i++) { + expectEquals(i <= 20 ? 13 : 15, sArrC[i]); + } + // Type S. + sS = 3; + sArrS = new short[100]; + InvLoopS(); + for (int i = 0; i < sArrS.length; i++) { + expectEquals(3, sArrS[i]); + } + VarLoopS(); + for (int i = 0; i < sArrS.length; i++) { + expectEquals(i <= 10 ? 3 : 4, sArrS[i]); + } + CrossOverLoopS(); + for (int i = 0; i < sArrS.length; i++) { + expectEquals(i <= 20 ? 13 : 15, sArrS[i]); + } + // Type I. + sI = 4; + sArrI = new int[100]; + InvLoopI(); + for (int i = 0; i < sArrI.length; i++) { + expectEquals(4, sArrI[i]); + } + VarLoopI(); + for (int i = 0; i < sArrI.length; i++) { + expectEquals(i <= 10 ? 4 : 5, sArrI[i]); + } + CrossOverLoopI(); + for (int i = 0; i < sArrI.length; i++) { + expectEquals(i <= 20 ? 13 : 15, sArrI[i]); + } + // Type J. + sJ = 5; + sArrJ = new long[100]; + InvLoopJ(); + for (int i = 0; i < sArrJ.length; i++) { + expectEquals(5, sArrJ[i]); + } + VarLoopJ(); + for (int i = 0; i < sArrJ.length; i++) { + expectEquals(i <= 10 ? 5 : 6, sArrJ[i]); + } + CrossOverLoopJ(); + for (int i = 0; i < sArrJ.length; i++) { + expectEquals(i <= 20 ? 13 : 15, sArrJ[i]); + } + // Type F. + sF = 6.0f; + sArrF = new float[100]; + InvLoopF(); + for (int i = 0; i < sArrF.length; i++) { + expectEquals(6, sArrF[i]); + } + VarLoopF(); + for (int i = 0; i < sArrF.length; i++) { + expectEquals(i <= 10 ? 6 : 7, sArrF[i]); + } + CrossOverLoopF(); + for (int i = 0; i < sArrF.length; i++) { + expectEquals(i <= 20 ? 13 : 15, sArrF[i]); + } + // Type D. + sD = 7.0; + sArrD = new double[100]; + InvLoopD(); + for (int i = 0; i < sArrD.length; i++) { + expectEquals(7.0, sArrD[i]); + } + VarLoopD(); + for (int i = 0; i < sArrD.length; i++) { + expectEquals(i <= 10 ? 7 : 8, sArrD[i]); + } + CrossOverLoopD(); + for (int i = 0; i < sArrD.length; i++) { + expectEquals(i <= 20 ? 13 : 15, sArrD[i]); + } + // Type L. + sL = anObject; + sArrL = new Object[100]; + InvLoopL(); + for (int i = 0; i < sArrL.length; i++) { + expectEquals(anObject, sArrL[i]); + } + VarLoopL(); + for (int i = 0; i < sArrL.length; i++) { + expectEquals(i <= 10 ? anObject : anotherObject, sArrL[i]); + } + CrossOverLoopL(); + for (int i = 0; i < sArrL.length; i++) { + expectEquals(i <= 20 ? anObject : anotherObject, sArrL[i]); + } + // False cross-over. + FalseCrossOverLoop1(); + for (int i = 0; i < sArrI.length; i++) { + expectEquals(-3, sArrI[i]); + } + FalseCrossOverLoop2(); + for (int i = 0; i < sArrF.length; i++) { + expectEquals(-4, sArrF[i]); + } + FalseCrossOverLoop3(); + for (int i = 0; i < sArrJ.length; i++) { + expectEquals(-5, sArrJ[i]); + } + FalseCrossOverLoop4(); + for (int i = 0; i < sArrD.length; i++) { + expectEquals(-6, sArrD[i]); + } + } + + private static void expectEquals(boolean expected, boolean result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + private static void expectEquals(byte expected, byte result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + private static void expectEquals(char expected, char result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + private static void expectEquals(short expected, short result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + private static void expectEquals(int expected, int result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + private static void expectEquals(long expected, long result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + private static void expectEquals(float expected, float result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + private static void expectEquals(double expected, double result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + private static void expectEquals(Object expected, Object result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } +} diff --git a/test/525-checker-arrays-fields2/expected.txt b/test/525-checker-arrays-fields2/expected.txt new file mode 100644 index 0000000000..b0aad4deb5 --- /dev/null +++ b/test/525-checker-arrays-fields2/expected.txt @@ -0,0 +1 @@ +passed diff --git a/test/525-checker-arrays-fields2/info.txt b/test/525-checker-arrays-fields2/info.txt new file mode 100644 index 0000000000..3464e540a6 --- /dev/null +++ b/test/525-checker-arrays-fields2/info.txt @@ -0,0 +1 @@ +Test on (in)variant instance field and array references in loops. diff --git a/test/525-checker-arrays-and-fields/src/Main.java b/test/525-checker-arrays-fields2/src/Main.java index a635a5157f..2aa40fcdc1 100644 --- a/test/525-checker-arrays-and-fields/src/Main.java +++ b/test/525-checker-arrays-fields2/src/Main.java @@ -15,7 +15,7 @@ */ // -// Test on (in)variant static and instance field and array references in loops. +// Test on (in)variant instance field and array references in loops. // public class Main { @@ -23,34 +23,6 @@ public class Main { private static Object anotherObject = new Object(); // - // Static fields. - // - - private static boolean sZ; - private static byte sB; - private static char sC; - private static short sS; - private static int sI; - private static long sJ; - private static float sF; - private static double sD; - private static Object sL; - - // - // Static arrays. - // - - private static boolean[] sArrZ; - private static byte[] sArrB; - private static char[] sArrC; - private static short[] sArrS; - private static int[] sArrI; - private static long[] sArrJ; - private static float[] sArrF; - private static double[] sArrD; - private static Object[] sArrL; - - // // Instance fields. // @@ -79,346 +51,6 @@ public class Main { private Object[] mArrL; // - // Loops on static arrays with invariant static field references. - // The checker is used to ensure hoisting occurred. - // - - /// CHECK-START: void Main.SInvLoopZ() licm (before) - /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} - /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} - - /// CHECK-START: void Main.SInvLoopZ() licm (after) - /// CHECK-DAG: StaticFieldGet loop:none - /// CHECK-DAG: StaticFieldGet loop:none - - private static void SInvLoopZ() { - for (int i = 0; i < sArrZ.length; i++) { - sArrZ[i] = sZ; - } - } - - /// CHECK-START: void Main.SInvLoopB() licm (before) - /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} - /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} - - /// CHECK-START: void Main.SInvLoopB() licm (after) - /// CHECK-DAG: StaticFieldGet loop:none - /// CHECK-DAG: StaticFieldGet loop:none - - private static void SInvLoopB() { - for (int i = 0; i < sArrB.length; i++) { - sArrB[i] = sB; - } - } - - /// CHECK-START: void Main.SInvLoopC() licm (before) - /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} - /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} - - /// CHECK-START: void Main.SInvLoopC() licm (after) - /// CHECK-DAG: StaticFieldGet loop:none - /// CHECK-DAG: StaticFieldGet loop:none - - private static void SInvLoopC() { - for (int i = 0; i < sArrC.length; i++) { - sArrC[i] = sC; - } - } - - /// CHECK-START: void Main.SInvLoopS() licm (before) - /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} - /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} - - /// CHECK-START: void Main.SInvLoopS() licm (after) - /// CHECK-DAG: StaticFieldGet loop:none - /// CHECK-DAG: StaticFieldGet loop:none - - private static void SInvLoopS() { - for (int i = 0; i < sArrS.length; i++) { - sArrS[i] = sS; - } - } - - /// CHECK-START: void Main.SInvLoopI() licm (before) - /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} - /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} - - /// CHECK-START: void Main.SInvLoopI() licm (after) - /// CHECK-DAG: StaticFieldGet loop:none - /// CHECK-DAG: StaticFieldGet loop:none - - private static void SInvLoopI() { - for (int i = 0; i < sArrI.length; i++) { - sArrI[i] = sI; - } - } - - /// CHECK-START: void Main.SInvLoopJ() licm (before) - /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} - /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} - - /// CHECK-START: void Main.SInvLoopJ() licm (after) - /// CHECK-DAG: StaticFieldGet loop:none - /// CHECK-DAG: StaticFieldGet loop:none - - private static void SInvLoopJ() { - for (int i = 0; i < sArrJ.length; i++) { - sArrJ[i] = sJ; - } - } - - /// CHECK-START: void Main.SInvLoopF() licm (before) - /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} - /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} - - /// CHECK-START: void Main.SInvLoopF() licm (after) - /// CHECK-DAG: StaticFieldGet loop:none - /// CHECK-DAG: StaticFieldGet loop:none - - private static void SInvLoopF() { - for (int i = 0; i < sArrF.length; i++) { - sArrF[i] = sF; - } - } - - /// CHECK-START: void Main.SInvLoopD() licm (before) - /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} - /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} - - /// CHECK-START: void Main.SInvLoopD() licm (after) - /// CHECK-DAG: StaticFieldGet loop:none - /// CHECK-DAG: StaticFieldGet loop:none - - private static void SInvLoopD() { - for (int i = 0; i < sArrD.length; i++) { - sArrD[i] = sD; - } - } - - /// CHECK-START: void Main.SInvLoopL() licm (before) - /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} - /// CHECK-DAG: StaticFieldGet loop:{{B\d+}} - - /// CHECK-START: void Main.SInvLoopL() licm (after) - /// CHECK-DAG: StaticFieldGet loop:none - /// CHECK-DAG: StaticFieldGet loop:none - - private static void SInvLoopL() { - for (int i = 0; i < sArrL.length; i++) { - sArrL[i] = sL; - } - } - - // - // Loops on static arrays with variant static field references. - // Incorrect hoisting is detected by incorrect outcome. - // - - private static void SVarLoopZ() { - for (int i = 0; i < sArrZ.length; i++) { - sArrZ[i] = sZ; - if (i == 10) - sZ = !sZ; - } - } - - private static void SVarLoopB() { - for (int i = 0; i < sArrB.length; i++) { - sArrB[i] = sB; - if (i == 10) - sB++; - } - } - - private static void SVarLoopC() { - for (int i = 0; i < sArrC.length; i++) { - sArrC[i] = sC; - if (i == 10) - sC++; - } - } - - private static void SVarLoopS() { - for (int i = 0; i < sArrS.length; i++) { - sArrS[i] = sS; - if (i == 10) - sS++; - } - } - - private static void SVarLoopI() { - for (int i = 0; i < sArrI.length; i++) { - sArrI[i] = sI; - if (i == 10) - sI++; - } - } - - private static void SVarLoopJ() { - for (int i = 0; i < sArrJ.length; i++) { - sArrJ[i] = sJ; - if (i == 10) - sJ++; - } - } - - private static void SVarLoopF() { - for (int i = 0; i < sArrF.length; i++) { - sArrF[i] = sF; - if (i == 10) - sF++; - } - } - - private static void SVarLoopD() { - for (int i = 0; i < sArrD.length; i++) { - sArrD[i] = sD; - if (i == 10) - sD++; - } - } - - private static void SVarLoopL() { - for (int i = 0; i < sArrL.length; i++) { - sArrL[i] = sL; - if (i == 10) - sL = anotherObject; - } - } - - // - // Loops on static arrays with a cross-over reference. - // Incorrect hoisting is detected by incorrect outcome. - // In addition, the checker is used to detect no hoisting. - // - - /// CHECK-START: void Main.SCrossOverLoopZ() licm (before) - /// CHECK-DAG: ArrayGet loop:{{B\d+}} - /// CHECK-DAG: ArraySet loop:{{B\d+}} - - /// CHECK-START: void Main.SCrossOverLoopZ() licm (after) - /// CHECK-DAG: ArrayGet loop:{{B\d+}} - /// CHECK-DAG: ArraySet loop:{{B\d+}} - - private static void SCrossOverLoopZ() { - for (int i = 0; i < sArrZ.length; i++) { - sArrZ[i] = !sArrZ[20]; - } - } - - /// CHECK-START: void Main.SCrossOverLoopB() licm (before) - /// CHECK-DAG: ArrayGet loop:{{B\d+}} - /// CHECK-DAG: ArraySet loop:{{B\d+}} - - /// CHECK-START: void Main.SCrossOverLoopB() licm (after) - /// CHECK-DAG: ArrayGet loop:{{B\d+}} - /// CHECK-DAG: ArraySet loop:{{B\d+}} - - private static void SCrossOverLoopB() { - for (int i = 0; i < sArrB.length; i++) { - sArrB[i] = (byte)(sArrB[20] + 2); - } - } - - /// CHECK-START: void Main.SCrossOverLoopC() licm (before) - /// CHECK-DAG: ArrayGet loop:{{B\d+}} - /// CHECK-DAG: ArraySet loop:{{B\d+}} - - /// CHECK-START: void Main.SCrossOverLoopC() licm (after) - /// CHECK-DAG: ArrayGet loop:{{B\d+}} - /// CHECK-DAG: ArraySet loop:{{B\d+}} - - private static void SCrossOverLoopC() { - for (int i = 0; i < sArrC.length; i++) { - sArrC[i] = (char)(sArrC[20] + 2); - } - } - - /// CHECK-START: void Main.SCrossOverLoopS() licm (before) - /// CHECK-DAG: ArrayGet loop:{{B\d+}} - /// CHECK-DAG: ArraySet loop:{{B\d+}} - - /// CHECK-START: void Main.SCrossOverLoopS() licm (after) - /// CHECK-DAG: ArrayGet loop:{{B\d+}} - /// CHECK-DAG: ArraySet loop:{{B\d+}} - - private static void SCrossOverLoopS() { - for (int i = 0; i < sArrS.length; i++) { - sArrS[i] = (short)(sArrS[20] + 2); - } - } - - /// CHECK-START: void Main.SCrossOverLoopI() licm (before) - /// CHECK-DAG: ArrayGet loop:{{B\d+}} - /// CHECK-DAG: ArraySet loop:{{B\d+}} - - /// CHECK-START: void Main.SCrossOverLoopI() licm (after) - /// CHECK-DAG: ArrayGet loop:{{B\d+}} - /// CHECK-DAG: ArraySet loop:{{B\d+}} - - private static void SCrossOverLoopI() { - for (int i = 0; i < sArrI.length; i++) { - sArrI[i] = sArrI[20] + 2; - } - } - - /// CHECK-START: void Main.SCrossOverLoopJ() licm (before) - /// CHECK-DAG: ArrayGet loop:{{B\d+}} - /// CHECK-DAG: ArraySet loop:{{B\d+}} - - /// CHECK-START: void Main.SCrossOverLoopJ() licm (after) - /// CHECK-DAG: ArrayGet loop:{{B\d+}} - /// CHECK-DAG: ArraySet loop:{{B\d+}} - - private static void SCrossOverLoopJ() { - for (int i = 0; i < sArrJ.length; i++) { - sArrJ[i] = sArrJ[20] + 2; - } - } - - /// CHECK-START: void Main.SCrossOverLoopF() licm (before) - /// CHECK-DAG: ArrayGet loop:{{B\d+}} - /// CHECK-DAG: ArraySet loop:{{B\d+}} - - /// CHECK-START: void Main.SCrossOverLoopF() licm (after) - /// CHECK-DAG: ArrayGet loop:{{B\d+}} - /// CHECK-DAG: ArraySet loop:{{B\d+}} - - private static void SCrossOverLoopF() { - for (int i = 0; i < sArrF.length; i++) { - sArrF[i] = sArrF[20] + 2; - } - } - - /// CHECK-START: void Main.SCrossOverLoopD() licm (before) - /// CHECK-DAG: ArrayGet loop:{{B\d+}} - /// CHECK-DAG: ArraySet loop:{{B\d+}} - - /// CHECK-START: void Main.SCrossOverLoopD() licm (after) - /// CHECK-DAG: ArrayGet loop:{{B\d+}} - /// CHECK-DAG: ArraySet loop:{{B\d+}} - - private static void SCrossOverLoopD() { - for (int i = 0; i < sArrD.length; i++) { - sArrD[i] = sArrD[20] + 2; - } - } - - /// CHECK-START: void Main.SCrossOverLoopL() licm (before) - /// CHECK-DAG: ArrayGet loop:{{B\d+}} - /// CHECK-DAG: ArraySet loop:{{B\d+}} - - /// CHECK-START: void Main.SCrossOverLoopL() licm (after) - /// CHECK-DAG: ArrayGet loop:{{B\d+}} - /// CHECK-DAG: ArraySet loop:{{B\d+}} - - private static void SCrossOverLoopL() { - for (int i = 0; i < sArrL.length; i++) { - sArrL[i] = (sArrL[20] == anObject) ? anotherObject : anObject; - } - } - - // // Loops on instance arrays with invariant instance field references. // The checker is used to ensure hoisting occurred. // @@ -633,278 +265,241 @@ public class Main { // /// CHECK-START: void Main.CrossOverLoopZ() licm (before) + /// CHECK-DAG: ArraySet loop:none /// CHECK-DAG: ArrayGet loop:{{B\d+}} /// CHECK-DAG: ArraySet loop:{{B\d+}} /// CHECK-START: void Main.CrossOverLoopZ() licm (after) + /// CHECK-DAG: ArraySet loop:none /// CHECK-DAG: ArrayGet loop:{{B\d+}} /// CHECK-DAG: ArraySet loop:{{B\d+}} private void CrossOverLoopZ() { + mArrZ[20] = false; for (int i = 0; i < mArrZ.length; i++) { mArrZ[i] = !mArrZ[20]; } } /// CHECK-START: void Main.CrossOverLoopB() licm (before) + /// CHECK-DAG: ArraySet loop:none /// CHECK-DAG: ArrayGet loop:{{B\d+}} /// CHECK-DAG: ArraySet loop:{{B\d+}} /// CHECK-START: void Main.CrossOverLoopB() licm (after) + /// CHECK-DAG: ArraySet loop:none /// CHECK-DAG: ArrayGet loop:{{B\d+}} /// CHECK-DAG: ArraySet loop:{{B\d+}} private void CrossOverLoopB() { + mArrB[20] = 111; for (int i = 0; i < mArrB.length; i++) { mArrB[i] = (byte)(mArrB[20] + 2); } } /// CHECK-START: void Main.CrossOverLoopC() licm (before) + /// CHECK-DAG: ArraySet loop:none /// CHECK-DAG: ArrayGet loop:{{B\d+}} /// CHECK-DAG: ArraySet loop:{{B\d+}} /// CHECK-START: void Main.CrossOverLoopC() licm (after) + /// CHECK-DAG: ArraySet loop:none /// CHECK-DAG: ArrayGet loop:{{B\d+}} /// CHECK-DAG: ArraySet loop:{{B\d+}} private void CrossOverLoopC() { + mArrC[20] = 111; for (int i = 0; i < mArrC.length; i++) { mArrC[i] = (char)(mArrC[20] + 2); } } /// CHECK-START: void Main.CrossOverLoopS() licm (before) + /// CHECK-DAG: ArraySet loop:none /// CHECK-DAG: ArrayGet loop:{{B\d+}} /// CHECK-DAG: ArraySet loop:{{B\d+}} /// CHECK-START: void Main.CrossOverLoopS() licm (after) + /// CHECK-DAG: ArraySet loop:none /// CHECK-DAG: ArrayGet loop:{{B\d+}} /// CHECK-DAG: ArraySet loop:{{B\d+}} private void CrossOverLoopS() { + mArrS[20] = 111; for (int i = 0; i < mArrS.length; i++) { mArrS[i] = (short)(mArrS[20] + 2); } } /// CHECK-START: void Main.CrossOverLoopI() licm (before) + /// CHECK-DAG: ArraySet loop:none /// CHECK-DAG: ArrayGet loop:{{B\d+}} /// CHECK-DAG: ArraySet loop:{{B\d+}} /// CHECK-START: void Main.CrossOverLoopI() licm (after) + /// CHECK-DAG: ArraySet loop:none /// CHECK-DAG: ArrayGet loop:{{B\d+}} /// CHECK-DAG: ArraySet loop:{{B\d+}} private void CrossOverLoopI() { + mArrI[20] = 111; for (int i = 0; i < mArrI.length; i++) { mArrI[i] = mArrI[20] + 2; } } /// CHECK-START: void Main.CrossOverLoopJ() licm (before) + /// CHECK-DAG: ArraySet loop:none /// CHECK-DAG: ArrayGet loop:{{B\d+}} /// CHECK-DAG: ArraySet loop:{{B\d+}} /// CHECK-START: void Main.CrossOverLoopJ() licm (after) + /// CHECK-DAG: ArraySet loop:none /// CHECK-DAG: ArrayGet loop:{{B\d+}} /// CHECK-DAG: ArraySet loop:{{B\d+}} private void CrossOverLoopJ() { + mArrJ[20] = 111; for (int i = 0; i < mArrJ.length; i++) { mArrJ[i] = mArrJ[20] + 2; } } /// CHECK-START: void Main.CrossOverLoopF() licm (before) + /// CHECK-DAG: ArraySet loop:none /// CHECK-DAG: ArrayGet loop:{{B\d+}} /// CHECK-DAG: ArraySet loop:{{B\d+}} /// CHECK-START: void Main.CrossOverLoopF() licm (after) + /// CHECK-DAG: ArraySet loop:none /// CHECK-DAG: ArrayGet loop:{{B\d+}} /// CHECK-DAG: ArraySet loop:{{B\d+}} private void CrossOverLoopF() { + mArrF[20] = 111; for (int i = 0; i < mArrF.length; i++) { mArrF[i] = mArrF[20] + 2; } } /// CHECK-START: void Main.CrossOverLoopD() licm (before) + /// CHECK-DAG: ArraySet loop:none /// CHECK-DAG: ArrayGet loop:{{B\d+}} /// CHECK-DAG: ArraySet loop:{{B\d+}} /// CHECK-START: void Main.CrossOverLoopD() licm (after) + /// CHECK-DAG: ArraySet loop:none /// CHECK-DAG: ArrayGet loop:{{B\d+}} /// CHECK-DAG: ArraySet loop:{{B\d+}} private void CrossOverLoopD() { + mArrD[20] = 111; for (int i = 0; i < mArrD.length; i++) { mArrD[i] = mArrD[20] + 2; } } /// CHECK-START: void Main.CrossOverLoopL() licm (before) + /// CHECK-DAG: ArraySet loop:none /// CHECK-DAG: ArrayGet loop:{{B\d+}} /// CHECK-DAG: ArraySet loop:{{B\d+}} /// CHECK-START: void Main.CrossOverLoopL() licm (after) + /// CHECK-DAG: ArraySet loop:none /// CHECK-DAG: ArrayGet loop:{{B\d+}} /// CHECK-DAG: ArraySet loop:{{B\d+}} private void CrossOverLoopL() { + mArrL[20] = anotherObject; for (int i = 0; i < mArrL.length; i++) { mArrL[i] = (mArrL[20] == anObject) ? anotherObject : anObject; } } // - // Driver and testers. + // False cross-over loops on instance arrays with data types (I/F and J/D) that used + // to be aliased in an older version of the compiler. This alias has been removed, + // however, which enables hoisting the invariant array reference. // - public static void main(String[] args) { - DoStaticTests(); - new Main().DoInstanceTests(); - } + /// CHECK-START: void Main.FalseCrossOverLoop1() licm (before) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} - private static void DoStaticTests() { - // Type Z. - sZ = true; - sArrZ = new boolean[100]; - SInvLoopZ(); - for (int i = 0; i < sArrZ.length; i++) { - expectEquals(true, sArrZ[i]); - } - SVarLoopZ(); - for (int i = 0; i < sArrZ.length; i++) { - expectEquals(i <= 10, sArrZ[i]); - } - SCrossOverLoopZ(); - for (int i = 0; i < sArrZ.length; i++) { - expectEquals(i <= 20, sArrZ[i]); - } - // Type B. - sB = 1; - sArrB = new byte[100]; - SInvLoopB(); - for (int i = 0; i < sArrB.length; i++) { - expectEquals(1, sArrB[i]); - } - SVarLoopB(); - for (int i = 0; i < sArrB.length; i++) { - expectEquals(i <= 10 ? 1 : 2, sArrB[i]); - } - SCrossOverLoopB(); - for (int i = 0; i < sArrB.length; i++) { - expectEquals(i <= 20 ? 4 : 6, sArrB[i]); - } - // Type C. - sC = 2; - sArrC = new char[100]; - SInvLoopC(); - for (int i = 0; i < sArrC.length; i++) { - expectEquals(2, sArrC[i]); - } - SVarLoopC(); - for (int i = 0; i < sArrC.length; i++) { - expectEquals(i <= 10 ? 2 : 3, sArrC[i]); - } - SCrossOverLoopC(); - for (int i = 0; i < sArrC.length; i++) { - expectEquals(i <= 20 ? 5 : 7, sArrC[i]); - } - // Type S. - sS = 3; - sArrS = new short[100]; - SInvLoopS(); - for (int i = 0; i < sArrS.length; i++) { - expectEquals(3, sArrS[i]); - } - SVarLoopS(); - for (int i = 0; i < sArrS.length; i++) { - expectEquals(i <= 10 ? 3 : 4, sArrS[i]); - } - SCrossOverLoopS(); - for (int i = 0; i < sArrS.length; i++) { - expectEquals(i <= 20 ? 6 : 8, sArrS[i]); - } - // Type I. - sI = 4; - sArrI = new int[100]; - SInvLoopI(); - for (int i = 0; i < sArrI.length; i++) { - expectEquals(4, sArrI[i]); - } - SVarLoopI(); - for (int i = 0; i < sArrI.length; i++) { - expectEquals(i <= 10 ? 4 : 5, sArrI[i]); - } - SCrossOverLoopI(); - for (int i = 0; i < sArrI.length; i++) { - expectEquals(i <= 20 ? 7 : 9, sArrI[i]); - } - // Type J. - sJ = 5; - sArrJ = new long[100]; - SInvLoopJ(); - for (int i = 0; i < sArrJ.length; i++) { - expectEquals(5, sArrJ[i]); - } - SVarLoopJ(); - for (int i = 0; i < sArrJ.length; i++) { - expectEquals(i <= 10 ? 5 : 6, sArrJ[i]); - } - SCrossOverLoopJ(); - for (int i = 0; i < sArrJ.length; i++) { - expectEquals(i <= 20 ? 8 : 10, sArrJ[i]); - } - // Type F. - sF = 6.0f; - sArrF = new float[100]; - SInvLoopF(); - for (int i = 0; i < sArrF.length; i++) { - expectEquals(6, sArrF[i]); - } - SVarLoopF(); - for (int i = 0; i < sArrF.length; i++) { - expectEquals(i <= 10 ? 6 : 7, sArrF[i]); - } - SCrossOverLoopF(); - for (int i = 0; i < sArrF.length; i++) { - expectEquals(i <= 20 ? 9 : 11, sArrF[i]); - } - // Type D. - sD = 7.0; - sArrD = new double[100]; - SInvLoopD(); - for (int i = 0; i < sArrD.length; i++) { - expectEquals(7.0, sArrD[i]); - } - SVarLoopD(); - for (int i = 0; i < sArrD.length; i++) { - expectEquals(i <= 10 ? 7 : 8, sArrD[i]); - } - SCrossOverLoopD(); - for (int i = 0; i < sArrD.length; i++) { - expectEquals(i <= 20 ? 10 : 12, sArrD[i]); + /// CHECK-START: void Main.FalseCrossOverLoop1() licm (after) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:none + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + private void FalseCrossOverLoop1() { + mArrF[20] = -1; + for (int i = 0; i < mArrI.length; i++) { + mArrI[i] = (int) mArrF[20] - 2; } - // Type L. - sL = anObject; - sArrL = new Object[100]; - SInvLoopL(); - for (int i = 0; i < sArrL.length; i++) { - expectEquals(anObject, sArrL[i]); + } + + /// CHECK-START: void Main.FalseCrossOverLoop2() licm (before) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + /// CHECK-START: void Main.FalseCrossOverLoop2() licm (after) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:none + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + private void FalseCrossOverLoop2() { + mArrI[20] = -2; + for (int i = 0; i < mArrF.length; i++) { + mArrF[i] = mArrI[20] - 2; } - SVarLoopL(); - for (int i = 0; i < sArrL.length; i++) { - expectEquals(i <= 10 ? anObject : anotherObject, sArrL[i]); + } + + /// CHECK-START: void Main.FalseCrossOverLoop3() licm (before) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + /// CHECK-START: void Main.FalseCrossOverLoop3() licm (after) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:none + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + private void FalseCrossOverLoop3() { + mArrD[20] = -3; + for (int i = 0; i < mArrJ.length; i++) { + mArrJ[i] = (long) mArrD[20] - 2; } - SCrossOverLoopL(); - for (int i = 0; i < sArrL.length; i++) { - expectEquals(i <= 20 ? anObject : anotherObject, sArrL[i]); + } + + /// CHECK-START: void Main.FalseCrossOverLoop4() licm (before) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + /// CHECK-START: void Main.FalseCrossOverLoop4() licm (after) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:none + /// CHECK-DAG: ArraySet loop:{{B\d+}} + + private void FalseCrossOverLoop4() { + mArrJ[20] = -4; + for (int i = 0; i < mArrD.length; i++) { + mArrD[i] = mArrJ[20] - 2; } } + // + // Main driver and testers. + // + + public static void main(String[] args) { + new Main().DoInstanceTests(); + System.out.println("passed"); + } + private void DoInstanceTests() { // Type Z. mZ = true; @@ -934,7 +529,7 @@ public class Main { } CrossOverLoopB(); for (int i = 0; i < mArrB.length; i++) { - expectEquals(i <= 20 ? 4 : 6, mArrB[i]); + expectEquals(i <= 20 ? 113 : 115, mArrB[i]); } // Type C. mC = 2; @@ -949,7 +544,7 @@ public class Main { } CrossOverLoopC(); for (int i = 0; i < mArrC.length; i++) { - expectEquals(i <= 20 ? 5 : 7, mArrC[i]); + expectEquals(i <= 20 ? 113 : 115, mArrC[i]); } // Type S. mS = 3; @@ -964,7 +559,7 @@ public class Main { } CrossOverLoopS(); for (int i = 0; i < mArrS.length; i++) { - expectEquals(i <= 20 ? 6 : 8, mArrS[i]); + expectEquals(i <= 20 ? 113 : 115, mArrS[i]); } // Type I. mI = 4; @@ -979,7 +574,7 @@ public class Main { } CrossOverLoopI(); for (int i = 0; i < mArrI.length; i++) { - expectEquals(i <= 20 ? 7 : 9, mArrI[i]); + expectEquals(i <= 20 ? 113 : 115, mArrI[i]); } // Type J. mJ = 5; @@ -994,7 +589,7 @@ public class Main { } CrossOverLoopJ(); for (int i = 0; i < mArrJ.length; i++) { - expectEquals(i <= 20 ? 8 : 10, mArrJ[i]); + expectEquals(i <= 20 ? 113 : 115, mArrJ[i]); } // Type F. mF = 6.0f; @@ -1009,7 +604,7 @@ public class Main { } CrossOverLoopF(); for (int i = 0; i < mArrF.length; i++) { - expectEquals(i <= 20 ? 9 : 11, mArrF[i]); + expectEquals(i <= 20 ? 113 : 115, mArrF[i]); } // Type D. mD = 7.0; @@ -1024,7 +619,7 @@ public class Main { } CrossOverLoopD(); for (int i = 0; i < mArrD.length; i++) { - expectEquals(i <= 20 ? 10 : 12, mArrD[i]); + expectEquals(i <= 20 ? 113 : 115, mArrD[i]); } // Type L. mL = anObject; @@ -1041,6 +636,23 @@ public class Main { for (int i = 0; i < mArrL.length; i++) { expectEquals(i <= 20 ? anObject : anotherObject, mArrL[i]); } + // False cross-over. + FalseCrossOverLoop1(); + for (int i = 0; i < mArrI.length; i++) { + expectEquals(-3, mArrI[i]); + } + FalseCrossOverLoop2(); + for (int i = 0; i < mArrF.length; i++) { + expectEquals(-4, mArrF[i]); + } + FalseCrossOverLoop3(); + for (int i = 0; i < mArrJ.length; i++) { + expectEquals(-5, mArrJ[i]); + } + FalseCrossOverLoop4(); + for (int i = 0; i < mArrD.length; i++) { + expectEquals(-6, mArrD[i]); + } } private static void expectEquals(boolean expected, boolean result) { diff --git a/test/594-checker-array-alias/expected.txt b/test/594-checker-array-alias/expected.txt new file mode 100644 index 0000000000..b0aad4deb5 --- /dev/null +++ b/test/594-checker-array-alias/expected.txt @@ -0,0 +1 @@ +passed diff --git a/test/594-checker-array-alias/info.txt b/test/594-checker-array-alias/info.txt new file mode 100644 index 0000000000..57c6de541f --- /dev/null +++ b/test/594-checker-array-alias/info.txt @@ -0,0 +1 @@ +Tests on array parameters with and without alias. diff --git a/test/594-checker-array-alias/src/Main.java b/test/594-checker-array-alias/src/Main.java new file mode 100644 index 0000000000..5ece2e295e --- /dev/null +++ b/test/594-checker-array-alias/src/Main.java @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.Arrays; + +// +// Test on array parameters with or without potential aliasing. +// +public class Main { + + // + // Cross-over on parameters with potential aliasing on parameters. + // The arrays a and b may point to the same memory, which (without + // further runtime tests) prevents hoisting the seemingly invariant + // array reference. + // + + /// CHECK-START: void Main.CrossOverLoop1(int[], int[]) licm (before) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + // + /// CHECK-START: void Main.CrossOverLoop1(int[], int[]) licm (after) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + private static void CrossOverLoop1(int a[], int b[]) { + b[20] = 99; + for (int i = 0; i < a.length; i++) { + a[i] = b[20] - 7; + } + } + + /// CHECK-START: void Main.CrossOverLoop2(float[], float[]) licm (before) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + // + /// CHECK-START: void Main.CrossOverLoop2(float[], float[]) licm (after) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + private static void CrossOverLoop2(float a[], float b[]) { + b[20] = 99; + for (int i = 0; i < a.length; i++) { + a[i] = b[20] - 7; + } + } + + /// CHECK-START: void Main.CrossOverLoop3(long[], long[]) licm (before) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + // + /// CHECK-START: void Main.CrossOverLoop3(long[], long[]) licm (after) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + private static void CrossOverLoop3(long a[], long b[]) { + b[20] = 99; + for (int i = 0; i < a.length; i++) { + a[i] = b[20] - 7; + } + } + + /// CHECK-START: void Main.CrossOverLoop4(double[], double[]) licm (before) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + // + /// CHECK-START: void Main.CrossOverLoop4(double[], double[]) licm (after) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + private static void CrossOverLoop4(double a[], double b[]) { + b[20] = 99; + for (int i = 0; i < a.length; i++) { + a[i] = b[20] - 7; + } + } + + // + // False cross-over on parameters. Parameters have same width (which used to + // cause a false type aliasing in an older version of the compiler), but since + // the types are different cannot be aliased. Thus, the invariant array + // reference can be hoisted. + // + + /// CHECK-START: void Main.FalseCrossOverLoop1(int[], float[]) licm (before) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + // + /// CHECK-START: void Main.FalseCrossOverLoop1(int[], float[]) licm (after) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:none + /// CHECK-DAG: ArraySet loop:{{B\d+}} + private static void FalseCrossOverLoop1(int a[], float b[]) { + b[20] = -99; + for (int i = 0; i < a.length; i++) { + a[i] = (int) b[20] - 7; + } + } + + /// CHECK-START: void Main.FalseCrossOverLoop2(float[], int[]) licm (before) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + // + /// CHECK-START: void Main.FalseCrossOverLoop2(float[], int[]) licm (after) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:none + /// CHECK-DAG: ArraySet loop:{{B\d+}} + private static void FalseCrossOverLoop2(float a[], int b[]) { + b[20] = -99; + for (int i = 0; i < a.length; i++) { + a[i] = b[20] - 7; + } + } + + /// CHECK-START: void Main.FalseCrossOverLoop3(long[], double[]) licm (before) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + // + /// CHECK-START: void Main.FalseCrossOverLoop3(long[], double[]) licm (after) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:none + /// CHECK-DAG: ArraySet loop:{{B\d+}} + private static void FalseCrossOverLoop3(long a[], double b[]) { + b[20] = -99; + for (int i = 0; i < a.length; i++) { + a[i] = (long) b[20] - 7; + } + } + + /// CHECK-START: void Main.FalseCrossOverLoop4(double[], long[]) licm (before) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: ArraySet loop:{{B\d+}} + // + /// CHECK-START: void Main.FalseCrossOverLoop4(double[], long[]) licm (after) + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: ArrayGet loop:none + /// CHECK-DAG: ArraySet loop:{{B\d+}} + private static void FalseCrossOverLoop4(double a[], long b[]) { + b[20] = -99; + for (int i = 0; i < a.length; i++) { + a[i] = b[20] - 7; + } + } + + // + // Main driver and testers. + // + + public static void main(String[] args) { + int[] aI = new int[100]; + float[] aF = new float[100]; + long[] aJ = new long[100]; + double[] aD = new double[100]; + + // Type I. + CrossOverLoop1(aI, aI); + for (int i = 0; i < aI.length; i++) { + expectEquals(i <= 20 ? 92 : 85, aI[i]); + } + // Type F. + CrossOverLoop2(aF, aF); + for (int i = 0; i < aF.length; i++) { + expectEquals(i <= 20 ? 92 : 85, aF[i]); + } + // Type J. + CrossOverLoop3(aJ, aJ); + for (int i = 0; i < aJ.length; i++) { + expectEquals(i <= 20 ? 92 : 85, aJ[i]); + } + // Type D. + CrossOverLoop4(aD, aD); + for (int i = 0; i < aD.length; i++) { + expectEquals(i <= 20 ? 92 : 85, aD[i]); + } + + // Type I vs F. + FalseCrossOverLoop1(aI, aF); + for (int i = 0; i < aI.length; i++) { + expectEquals(-106, aI[i]); + } + // Type F vs I. + FalseCrossOverLoop2(aF, aI); + for (int i = 0; i < aF.length; i++) { + expectEquals(-106, aF[i]); + } + // Type J vs D. + FalseCrossOverLoop3(aJ, aD); + for (int i = 0; i < aJ.length; i++) { + expectEquals(-106, aJ[i]); + } + // Type D vs J. + FalseCrossOverLoop4(aD, aJ); + for (int i = 0; i < aD.length; i++) { + expectEquals(-106, aD[i]); + } + + // Real-world example where incorrect type assignment could introduce a bug. + // The library sorting algorithm is heavy on array reads and writes, and + // assigning the wrong J/D type to one of these would introduce errors. + for (int i = 0; i < aD.length; i++) { + aD[i] = aD.length - i - 1; + } + Arrays.sort(aD); + for (int i = 0; i < aD.length; i++) { + expectEquals((double) i, aD[i]); + } + + System.out.println("passed"); + } + + private static void expectEquals(int expected, int result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + private static void expectEquals(long expected, long result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + private static void expectEquals(float expected, float result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + private static void expectEquals(double expected, double result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } +} |