Fix braino when handling branches fallthrough in arm backend.
bug: 62210114
Test: 657-branches
Change-Id: I753a9a57e404c792cd4375ea66c91839684bdee2
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 0b3ac20..6b9f232 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -2875,21 +2875,28 @@
if (CanGenerateTest(condition, codegen_->GetAssembler())) {
Label* non_fallthrough_target;
bool invert;
+ bool emit_both_branches;
if (true_target_in == nullptr) {
+ // The true target is fallthrough.
DCHECK(false_target_in != nullptr);
non_fallthrough_target = false_target_in;
invert = true;
+ emit_both_branches = false;
} else {
+ // Either the false target is fallthrough, or there is no fallthrough
+ // and both branches must be emitted.
non_fallthrough_target = true_target_in;
invert = false;
+ emit_both_branches = (false_target_in != nullptr);
}
const auto cond = GenerateTest(condition, invert, codegen_);
__ b(non_fallthrough_target, cond.first);
- if (false_target_in != nullptr && false_target_in != non_fallthrough_target) {
+ if (emit_both_branches) {
+ // No target falls through, we need to branch.
__ b(false_target_in);
}
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 34397e6..2561ed0 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -3608,9 +3608,6 @@
size_t condition_input_index,
vixl::aarch64::Label* true_target,
vixl::aarch64::Label* false_target) {
- // FP branching requires both targets to be explicit. If either of the targets
- // is nullptr (fallthrough) use and bind `fallthrough_target` instead.
- vixl::aarch64::Label fallthrough_target;
HInstruction* cond = instruction->InputAt(condition_input_index);
if (true_target == nullptr && false_target == nullptr) {
@@ -3711,10 +3708,6 @@
if (true_target != nullptr && false_target != nullptr) {
__ B(false_target);
}
-
- if (fallthrough_target.IsLinked()) {
- __ Bind(&fallthrough_target);
- }
}
void LocationsBuilderARM64::VisitIf(HIf* if_instr) {
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index a8b00c3..9a2402b 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -2964,21 +2964,28 @@
if (CanGenerateTest(condition, codegen_->GetAssembler())) {
vixl32::Label* non_fallthrough_target;
bool invert;
+ bool emit_both_branches;
if (true_target_in == nullptr) {
+ // The true target is fallthrough.
DCHECK(false_target_in != nullptr);
non_fallthrough_target = false_target_in;
invert = true;
+ emit_both_branches = false;
} else {
non_fallthrough_target = true_target_in;
invert = false;
+ // Either the false target is fallthrough, or there is no fallthrough
+ // and both branches must be emitted.
+ emit_both_branches = (false_target_in != nullptr);
}
const auto cond = GenerateTest(condition, invert, codegen_);
__ B(cond.first, non_fallthrough_target, is_far_target);
- if (false_target_in != nullptr && false_target_in != non_fallthrough_target) {
+ if (emit_both_branches) {
+ // No target falls through, we need to branch.
__ B(false_target_in);
}
diff --git a/test/657-branches/expected.txt b/test/657-branches/expected.txt
new file mode 100644
index 0000000..d9fd864
--- /dev/null
+++ b/test/657-branches/expected.txt
@@ -0,0 +1 @@
+Hello World: 4.0
diff --git a/test/657-branches/info.txt b/test/657-branches/info.txt
new file mode 100644
index 0000000..84a2bb9
--- /dev/null
+++ b/test/657-branches/info.txt
@@ -0,0 +1,2 @@
+Regression test for the ARM backend, which used to have a bug
+handling branches fallthrough.
diff --git a/test/657-branches/src/Main.java b/test/657-branches/src/Main.java
new file mode 100644
index 0000000..2b62c5f
--- /dev/null
+++ b/test/657-branches/src/Main.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+public class Main {
+
+ public static void foo(float f) {
+ // The reason this used to break:
+ // 1) We inline the 'foo' call, so blocks now only contain HLoadClass instructions.
+ // 2) We then run the select_generator pass, which cannot change the
+ // if/else because blocks contain instructions.
+ // 3) We run GVN which will remove the HLoadClass instructions in the blocks.
+ // 4) At code generation, we are in the unlikely situation that a diamond shape
+ // contains no instruction (usually removed by select_generator). This used
+ // to trip the ARM code generators.
+ if (f < 1.2f) {
+ foo(Main.class, Object.class);
+ if (f < 0.2f) {
+ foo(Main.class, Object.class);
+ } else {
+ foo(Main.class, Object.class);
+ }
+ } else {
+ System.out.println("Hello World: " + f);
+ }
+ }
+
+ public static void foo(Object a, Object b) {}
+
+ public static void main(String[] args) {
+ foo(0f);
+ foo(4f);
+ foo(0.1f);
+ }
+}