diff options
author | 2016-11-10 18:21:30 -0800 | |
---|---|---|
committer | 2016-11-11 09:34:56 -0800 | |
commit | 08ec180de9481024c16be6841f068a45284cd8cc (patch) | |
tree | e8d450a7be42213ee14d465cd374e90f205e54df | |
parent | 5302bd999afee6db5b0cfd63e6a49b0fcbf92dd4 (diff) |
Fixed bug in LICM
Rationale:
We should stop hoisting anything that can throw
as soon as something else that can do something
visible (either throw or write something) is *not*
hoisted (used to be just throw test on second part).
Bug: 32810295
Test: test-art-host
Change-Id: Id88b712a5d9e37598d0bebbd4ecf4b1d8ee787b5
-rw-r--r-- | compiler/optimizing/licm.cc | 20 | ||||
-rw-r--r-- | test/625-checker-licm-regressions/expected.txt | 1 | ||||
-rw-r--r-- | test/625-checker-licm-regressions/info.txt | 1 | ||||
-rw-r--r-- | test/625-checker-licm-regressions/src/Main.java | 66 |
4 files changed, 78 insertions, 10 deletions
diff --git a/compiler/optimizing/licm.cc b/compiler/optimizing/licm.cc index eb2d18dd88..f0086fb202 100644 --- a/compiler/optimizing/licm.cc +++ b/compiler/optimizing/licm.cc @@ -120,17 +120,17 @@ void LICM::Run() { } DCHECK(!loop_info->IsIrreducible()); - // We can move an instruction that can throw only if it is the first - // throwing instruction in the loop. Note that the first potentially - // throwing instruction encountered that is not hoisted stops this - // optimization. Non-throwing instruction can still be hoisted. - bool found_first_non_hoisted_throwing_instruction_in_loop = !inner->IsLoopHeader(); + // We can move an instruction that can throw only as long as it is the first visible + // instruction (throw or write) in the loop. Note that the first potentially visible + // instruction that is not hoisted stops this optimization. Non-throwing instructions, + // on the other hand, can still be hoisted. + bool found_first_non_hoisted_visible_instruction_in_loop = !inner->IsLoopHeader(); for (HInstructionIterator inst_it(inner->GetInstructions()); !inst_it.Done(); inst_it.Advance()) { HInstruction* instruction = inst_it.Current(); if (instruction->CanBeMoved() - && (!instruction->CanThrow() || !found_first_non_hoisted_throwing_instruction_in_loop) + && (!instruction->CanThrow() || !found_first_non_hoisted_visible_instruction_in_loop) && !instruction->GetSideEffects().MayDependOn(loop_effects) && InputsAreDefinedBeforeLoop(instruction)) { // We need to update the environment if the instruction has a loop header @@ -142,10 +142,10 @@ void LICM::Run() { } instruction->MoveBefore(pre_header->GetLastInstruction()); MaybeRecordStat(MethodCompilationStat::kLoopInvariantMoved); - } else if (instruction->CanThrow()) { - // If `instruction` can throw, we cannot move further instructions - // that can throw as well. - found_first_non_hoisted_throwing_instruction_in_loop = true; + } else if (instruction->CanThrow() || instruction->DoesAnyWrite()) { + // If `instruction` can do something visible (throw or write), + // we cannot move further instructions that can throw. + found_first_non_hoisted_visible_instruction_in_loop = true; } } } diff --git a/test/625-checker-licm-regressions/expected.txt b/test/625-checker-licm-regressions/expected.txt new file mode 100644 index 0000000000..b0aad4deb5 --- /dev/null +++ b/test/625-checker-licm-regressions/expected.txt @@ -0,0 +1 @@ +passed diff --git a/test/625-checker-licm-regressions/info.txt b/test/625-checker-licm-regressions/info.txt new file mode 100644 index 0000000000..10480df32c --- /dev/null +++ b/test/625-checker-licm-regressions/info.txt @@ -0,0 +1 @@ +Regression tests on LICM. diff --git a/test/625-checker-licm-regressions/src/Main.java b/test/625-checker-licm-regressions/src/Main.java new file mode 100644 index 0000000000..cc1e07cabf --- /dev/null +++ b/test/625-checker-licm-regressions/src/Main.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2016 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. + */ + +/** + * Regression tests for LICM. + */ +public class Main { + + static int sA; + + // + // We cannot hoist the null check (can throw) above the field + // assignment (has write side effects) because that would result + // in throwing an exception before the assignment is done. + // + /// CHECK-START: void Main.foo(int[]) licm (before) + /// CHECK-DAG: LoadClass loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: StaticFieldSet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: NullCheck loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayLength loop:<<Loop>> outer_loop:none + // + /// CHECK-START: void Main.foo(int[]) licm (after) + /// CHECK-DAG: LoadClass loop:none + /// CHECK-DAG: StaticFieldSet loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: NullCheck loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayLength loop:<<Loop>> outer_loop:none + // + /// CHECK-START: void Main.foo(int[]) licm (after) + /// CHECK-NOT: LoadClass loop:{{B\d+}} outer_loop:none + static void foo(int[] arr) { + int j = 0; + do { + sA = 1; + } while (j < arr.length); + } + + public static void main(String[] args) { + sA = 0; + try { + foo(null); + } catch (Exception e) { + } + expectEquals(1, sA); + + System.out.println("passed"); + } + + private static void expectEquals(int expected, int result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } +} |