summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Santiago Aboy Solanes <solanes@google.com> 2023-03-10 15:58:17 +0000
committer Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> 2023-10-10 12:51:37 +0000
commitd003e7530ed0b00df5504cf57f0dd6479629c67a (patch)
tree205938c02bfb914f007fc4e7e30f78b9b50b63e4
parent472f6bced8e088fe8f97213587933e0c4420238f (diff)
Add optimization to simplify Select+Binary/Unary ops
We can simplify a Select + Binary/Unary Op if: * Both inputs to the Select instruction are constant, and * The Select instruction is not used in another instruction to avoid duplicating Selects. * In the case of Binary ops, both inputs can't be Select. Test: art/test/testrunner/testrunner.py --host --64 --optimizing -b Change-Id: Ic716155e9a8515126c2867bb1d54593fa63011ae
-rw-r--r--compiler/optimizing/constant_folding.cc88
-rw-r--r--compiler/optimizing/nodes.cc72
-rw-r--r--compiler/optimizing/nodes.h15
-rw-r--r--test/2265-checker-select-binary-unary/expected-stderr.txt0
-rw-r--r--test/2265-checker-select-binary-unary/expected-stdout.txt0
-rw-r--r--test/2265-checker-select-binary-unary/info.txt5
-rw-r--r--test/2265-checker-select-binary-unary/src/Main.java145
-rw-r--r--test/567-checker-builder-intrinsics/src/TestSignum.java8
-rw-r--r--test/570-checker-select/src/Main.java1
-rw-r--r--test/593-checker-boolean-2-integral-conv/smali/SmaliTests.smali6
-rw-r--r--test/646-checker-long-const-to-int/src/Main.java10
11 files changed, 305 insertions, 45 deletions
diff --git a/compiler/optimizing/constant_folding.cc b/compiler/optimizing/constant_folding.cc
index 2163c007e6..e20d9e83e6 100644
--- a/compiler/optimizing/constant_folding.cc
+++ b/compiler/optimizing/constant_folding.cc
@@ -37,6 +37,13 @@ class HConstantFoldingVisitor final : public HGraphDelegateVisitor {
void VisitUnaryOperation(HUnaryOperation* inst) override;
void VisitBinaryOperation(HBinaryOperation* inst) override;
+ // Tries to replace constants in binary operations like:
+ // * BinaryOp(Select(false_constant, true_constant, condition), other_constant), or
+ // * BinaryOp(other_constant, Select(false_constant, true_constant, condition))
+ // with consolidated constants. For example, Add(Select(10, 20, condition), 5) can be replaced
+ // with Select(15, 25, condition).
+ bool TryRemoveBinaryOperationViaSelect(HBinaryOperation* inst);
+
void VisitArrayLength(HArrayLength* inst) override;
void VisitDivZeroCheck(HDivZeroCheck* inst) override;
void VisitIf(HIf* inst) override;
@@ -113,9 +120,69 @@ void HConstantFoldingVisitor::VisitUnaryOperation(HUnaryOperation* inst) {
if (constant != nullptr) {
inst->ReplaceWith(constant);
inst->GetBlock()->RemoveInstruction(inst);
+ } else if (inst->InputAt(0)->IsSelect() && inst->InputAt(0)->HasOnlyOneNonEnvironmentUse()) {
+ // Try to replace the select's inputs in Select+UnaryOperation cases. We can do this if both
+ // inputs to the select are constants, and this is the only use of the select.
+ HSelect* select = inst->InputAt(0)->AsSelect();
+ HConstant* false_constant = inst->TryStaticEvaluation(select->GetFalseValue());
+ if (false_constant == nullptr) {
+ return;
+ }
+ HConstant* true_constant = inst->TryStaticEvaluation(select->GetTrueValue());
+ if (true_constant == nullptr) {
+ return;
+ }
+ DCHECK_EQ(select->InputAt(0), select->GetFalseValue());
+ DCHECK_EQ(select->InputAt(1), select->GetTrueValue());
+ select->ReplaceInput(false_constant, 0);
+ select->ReplaceInput(true_constant, 1);
+ select->UpdateType();
+ inst->ReplaceWith(select);
+ inst->GetBlock()->RemoveInstruction(inst);
}
}
+bool HConstantFoldingVisitor::TryRemoveBinaryOperationViaSelect(HBinaryOperation* inst) {
+ if (inst->GetLeft()->IsSelect() == inst->GetRight()->IsSelect()) {
+ // If both of them are constants, VisitBinaryOperation already tried the static evaluation. If
+ // both of them are selects, then we can't simplify.
+ // TODO(solanes): Technically, if both of them are selects we could simplify iff both select's
+ // conditions are equal e.g. Add(Select(1, 2, cond), Select(3, 4, cond)) could be replaced with
+ // Select(4, 6, cond). This seems very unlikely to happen so we don't implement it.
+ return false;
+ }
+
+ const bool left_is_select = inst->GetLeft()->IsSelect();
+ HSelect* select = left_is_select ? inst->GetLeft()->AsSelect() : inst->GetRight()->AsSelect();
+ HInstruction* maybe_constant = left_is_select ? inst->GetRight() : inst->GetLeft();
+
+ if (select->HasOnlyOneNonEnvironmentUse()) {
+ // Try to replace the select's inputs in Select+BinaryOperation. We can do this if both
+ // inputs to the select are constants, and this is the only use of the select.
+ HConstant* false_constant =
+ inst->TryStaticEvaluation(left_is_select ? select->GetFalseValue() : maybe_constant,
+ left_is_select ? maybe_constant : select->GetFalseValue());
+ if (false_constant == nullptr) {
+ return false;
+ }
+ HConstant* true_constant =
+ inst->TryStaticEvaluation(left_is_select ? select->GetTrueValue() : maybe_constant,
+ left_is_select ? maybe_constant : select->GetTrueValue());
+ if (true_constant == nullptr) {
+ return false;
+ }
+ DCHECK_EQ(select->InputAt(0), select->GetFalseValue());
+ DCHECK_EQ(select->InputAt(1), select->GetTrueValue());
+ select->ReplaceInput(false_constant, 0);
+ select->ReplaceInput(true_constant, 1);
+ select->UpdateType();
+ inst->ReplaceWith(select);
+ inst->GetBlock()->RemoveInstruction(inst);
+ return true;
+ }
+ return false;
+}
+
void HConstantFoldingVisitor::VisitBinaryOperation(HBinaryOperation* inst) {
// Constant folding: replace `op(a, b)' with a constant at
// compile time if `a' and `b' are both constants.
@@ -123,6 +190,8 @@ void HConstantFoldingVisitor::VisitBinaryOperation(HBinaryOperation* inst) {
if (constant != nullptr) {
inst->ReplaceWith(constant);
inst->GetBlock()->RemoveInstruction(inst);
+ } else if (TryRemoveBinaryOperationViaSelect(inst)) {
+ // Already replaced inside TryRemoveBinaryOperationViaSelect.
} else {
InstructionWithAbsorbingInputSimplifier simplifier(GetGraph());
inst->Accept(&simplifier);
@@ -299,6 +368,25 @@ void HConstantFoldingVisitor::VisitTypeConversion(HTypeConversion* inst) {
if (constant != nullptr) {
inst->ReplaceWith(constant);
inst->GetBlock()->RemoveInstruction(inst);
+ } else if (inst->InputAt(0)->IsSelect() && inst->InputAt(0)->HasOnlyOneNonEnvironmentUse()) {
+ // Try to replace the select's inputs in Select+TypeConversion. We can do this if both
+ // inputs to the select are constants, and this is the only use of the select.
+ HSelect* select = inst->InputAt(0)->AsSelect();
+ HConstant* false_constant = inst->TryStaticEvaluation(select->GetFalseValue());
+ if (false_constant == nullptr) {
+ return;
+ }
+ HConstant* true_constant = inst->TryStaticEvaluation(select->GetTrueValue());
+ if (true_constant == nullptr) {
+ return;
+ }
+ DCHECK_EQ(select->InputAt(0), select->GetFalseValue());
+ DCHECK_EQ(select->InputAt(1), select->GetTrueValue());
+ select->ReplaceInput(false_constant, 0);
+ select->ReplaceInput(true_constant, 1);
+ select->UpdateType();
+ inst->ReplaceWith(select);
+ inst->GetBlock()->RemoveInstruction(inst);
}
}
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 2b7e384f34..5795ea7ca9 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -1816,10 +1816,12 @@ void HGraphVisitor::VisitBasicBlock(HBasicBlock* block) {
}
}
-HConstant* HTypeConversion::TryStaticEvaluation() const {
- HGraph* graph = GetBlock()->GetGraph();
- if (GetInput()->IsIntConstant()) {
- int32_t value = GetInput()->AsIntConstant()->GetValue();
+HConstant* HTypeConversion::TryStaticEvaluation() const { return TryStaticEvaluation(GetInput()); }
+
+HConstant* HTypeConversion::TryStaticEvaluation(HInstruction* input) const {
+ HGraph* graph = input->GetBlock()->GetGraph();
+ if (input->IsIntConstant()) {
+ int32_t value = input->AsIntConstant()->GetValue();
switch (GetResultType()) {
case DataType::Type::kInt8:
return graph->GetIntConstant(static_cast<int8_t>(value), GetDexPc());
@@ -1838,8 +1840,8 @@ HConstant* HTypeConversion::TryStaticEvaluation() const {
default:
return nullptr;
}
- } else if (GetInput()->IsLongConstant()) {
- int64_t value = GetInput()->AsLongConstant()->GetValue();
+ } else if (input->IsLongConstant()) {
+ int64_t value = input->AsLongConstant()->GetValue();
switch (GetResultType()) {
case DataType::Type::kInt8:
return graph->GetIntConstant(static_cast<int8_t>(value), GetDexPc());
@@ -1858,8 +1860,8 @@ HConstant* HTypeConversion::TryStaticEvaluation() const {
default:
return nullptr;
}
- } else if (GetInput()->IsFloatConstant()) {
- float value = GetInput()->AsFloatConstant()->GetValue();
+ } else if (input->IsFloatConstant()) {
+ float value = input->AsFloatConstant()->GetValue();
switch (GetResultType()) {
case DataType::Type::kInt32:
if (std::isnan(value))
@@ -1882,8 +1884,8 @@ HConstant* HTypeConversion::TryStaticEvaluation() const {
default:
return nullptr;
}
- } else if (GetInput()->IsDoubleConstant()) {
- double value = GetInput()->AsDoubleConstant()->GetValue();
+ } else if (input->IsDoubleConstant()) {
+ double value = input->AsDoubleConstant()->GetValue();
switch (GetResultType()) {
case DataType::Type::kInt32:
if (std::isnan(value))
@@ -1910,41 +1912,47 @@ HConstant* HTypeConversion::TryStaticEvaluation() const {
return nullptr;
}
-HConstant* HUnaryOperation::TryStaticEvaluation() const {
- if (GetInput()->IsIntConstant()) {
- return Evaluate(GetInput()->AsIntConstant());
- } else if (GetInput()->IsLongConstant()) {
- return Evaluate(GetInput()->AsLongConstant());
+HConstant* HUnaryOperation::TryStaticEvaluation() const { return TryStaticEvaluation(GetInput()); }
+
+HConstant* HUnaryOperation::TryStaticEvaluation(HInstruction* input) const {
+ if (input->IsIntConstant()) {
+ return Evaluate(input->AsIntConstant());
+ } else if (input->IsLongConstant()) {
+ return Evaluate(input->AsLongConstant());
} else if (kEnableFloatingPointStaticEvaluation) {
- if (GetInput()->IsFloatConstant()) {
- return Evaluate(GetInput()->AsFloatConstant());
- } else if (GetInput()->IsDoubleConstant()) {
- return Evaluate(GetInput()->AsDoubleConstant());
+ if (input->IsFloatConstant()) {
+ return Evaluate(input->AsFloatConstant());
+ } else if (input->IsDoubleConstant()) {
+ return Evaluate(input->AsDoubleConstant());
}
}
return nullptr;
}
HConstant* HBinaryOperation::TryStaticEvaluation() const {
- if (GetLeft()->IsIntConstant() && GetRight()->IsIntConstant()) {
- return Evaluate(GetLeft()->AsIntConstant(), GetRight()->AsIntConstant());
- } else if (GetLeft()->IsLongConstant()) {
- if (GetRight()->IsIntConstant()) {
+ return TryStaticEvaluation(GetLeft(), GetRight());
+}
+
+HConstant* HBinaryOperation::TryStaticEvaluation(HInstruction* left, HInstruction* right) const {
+ if (left->IsIntConstant() && right->IsIntConstant()) {
+ return Evaluate(left->AsIntConstant(), right->AsIntConstant());
+ } else if (left->IsLongConstant()) {
+ if (right->IsIntConstant()) {
// The binop(long, int) case is only valid for shifts and rotations.
DCHECK(IsShl() || IsShr() || IsUShr() || IsRor()) << DebugName();
- return Evaluate(GetLeft()->AsLongConstant(), GetRight()->AsIntConstant());
- } else if (GetRight()->IsLongConstant()) {
- return Evaluate(GetLeft()->AsLongConstant(), GetRight()->AsLongConstant());
+ return Evaluate(left->AsLongConstant(), right->AsIntConstant());
+ } else if (right->IsLongConstant()) {
+ return Evaluate(left->AsLongConstant(), right->AsLongConstant());
}
- } else if (GetLeft()->IsNullConstant() && GetRight()->IsNullConstant()) {
+ } else if (left->IsNullConstant() && right->IsNullConstant()) {
// The binop(null, null) case is only valid for equal and not-equal conditions.
DCHECK(IsEqual() || IsNotEqual()) << DebugName();
- return Evaluate(GetLeft()->AsNullConstant(), GetRight()->AsNullConstant());
+ return Evaluate(left->AsNullConstant(), right->AsNullConstant());
} else if (kEnableFloatingPointStaticEvaluation) {
- if (GetLeft()->IsFloatConstant() && GetRight()->IsFloatConstant()) {
- return Evaluate(GetLeft()->AsFloatConstant(), GetRight()->AsFloatConstant());
- } else if (GetLeft()->IsDoubleConstant() && GetRight()->IsDoubleConstant()) {
- return Evaluate(GetLeft()->AsDoubleConstant(), GetRight()->AsDoubleConstant());
+ if (left->IsFloatConstant() && right->IsFloatConstant()) {
+ return Evaluate(left->AsFloatConstant(), right->AsFloatConstant());
+ } else if (left->IsDoubleConstant() && right->IsDoubleConstant()) {
+ return Evaluate(left->AsDoubleConstant(), right->AsDoubleConstant());
}
}
return nullptr;
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 3f60ec5241..9cf52183b8 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -3858,6 +3858,9 @@ class HUnaryOperation : public HExpression<1> {
// be evaluated as a constant, return null.
HConstant* TryStaticEvaluation() const;
+ // Same but for `input` instead of GetInput().
+ HConstant* TryStaticEvaluation(HInstruction* input) const;
+
// Apply this operation to `x`.
virtual HConstant* Evaluate(HIntConstant* x) const = 0;
virtual HConstant* Evaluate(HLongConstant* x) const = 0;
@@ -3934,6 +3937,9 @@ class HBinaryOperation : public HExpression<2> {
// be evaluated as a constant, return null.
HConstant* TryStaticEvaluation() const;
+ // Same but for `left` and `right` instead of GetLeft() and GetRight().
+ HConstant* TryStaticEvaluation(HInstruction* left, HInstruction* right) const;
+
// Apply this operation to `x` and `y`.
virtual HConstant* Evaluate([[maybe_unused]] HNullConstant* x,
[[maybe_unused]] HNullConstant* y) const {
@@ -6188,6 +6194,9 @@ class HTypeConversion final : public HExpression<1> {
// containing the result. If the input cannot be converted, return nullptr.
HConstant* TryStaticEvaluation() const;
+ // Same but for `input` instead of GetInput().
+ HConstant* TryStaticEvaluation(HInstruction* input) const;
+
DECLARE_INSTRUCTION(TypeConversion);
protected:
@@ -8377,6 +8386,12 @@ class HSelect final : public HExpression<3> {
return GetTrueValue()->CanBeNull() || GetFalseValue()->CanBeNull();
}
+ void UpdateType() {
+ DCHECK_EQ(HPhi::ToPhiType(GetTrueValue()->GetType()),
+ HPhi::ToPhiType(GetFalseValue()->GetType()));
+ SetPackedField<TypeField>(HPhi::ToPhiType(GetTrueValue()->GetType()));
+ }
+
DECLARE_INSTRUCTION(Select);
protected:
diff --git a/test/2265-checker-select-binary-unary/expected-stderr.txt b/test/2265-checker-select-binary-unary/expected-stderr.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/2265-checker-select-binary-unary/expected-stderr.txt
diff --git a/test/2265-checker-select-binary-unary/expected-stdout.txt b/test/2265-checker-select-binary-unary/expected-stdout.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/2265-checker-select-binary-unary/expected-stdout.txt
diff --git a/test/2265-checker-select-binary-unary/info.txt b/test/2265-checker-select-binary-unary/info.txt
new file mode 100644
index 0000000000..b20b11a604
--- /dev/null
+++ b/test/2265-checker-select-binary-unary/info.txt
@@ -0,0 +1,5 @@
+Tests that we can simplify a Select + Binary/UnaryOps if:
+ * Both inputs to the Select instruction are constant, and
+ * The Select instruction is not used in another instruction
+ to avoid duplicating Selects.
+ * In the case of Binary ops, both inputs can't be Select.
diff --git a/test/2265-checker-select-binary-unary/src/Main.java b/test/2265-checker-select-binary-unary/src/Main.java
new file mode 100644
index 0000000000..33734fc4d6
--- /dev/null
+++ b/test/2265-checker-select-binary-unary/src/Main.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2023 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.lang.reflect.Method;
+
+public class Main {
+ public static void main(String[] args) throws Throwable {
+ assertLongEquals(11L, $noinline$testIntToLong(0, 1));
+ assertLongEquals(12L, $noinline$testIntToLong(1, 0));
+
+ assertFloatEquals(11f, $noinline$testIntToFloat(0, 1));
+ assertFloatEquals(12f, $noinline$testIntToFloat(1, 0));
+
+ assertIntEquals(11, $noinline$testIntToByte(0, 1));
+ assertIntEquals(12, $noinline$testIntToByte(1, 0));
+
+ assertIntEquals(11, $noinline$testLongToInt(0, 1));
+ assertIntEquals(12, $noinline$testLongToInt(1, 0));
+ }
+
+ /// CHECK-START: long Main.$noinline$testIntToLong(int, int) select_generator (after)
+ /// CHECK: <<Const10:j\d+>> LongConstant 10
+ /// CHECK: <<Const1:i\d+>> IntConstant 1
+ /// CHECK: <<Const2:i\d+>> IntConstant 2
+ /// CHECK: <<Sel:i\d+>> Select [<<Const1>>,<<Const2>>,<<Condition:z\d+>>]
+ /// CHECK: <<Type:j\d+>> TypeConversion [<<Sel>>]
+ /// CHECK: Add [<<Type>>,<<Const10>>]
+
+ /// CHECK-START: long Main.$noinline$testIntToLong(int, int) constant_folding$after_gvn (after)
+ /// CHECK: <<Const11:j\d+>> LongConstant 11
+ /// CHECK: <<Const12:j\d+>> LongConstant 12
+ /// CHECK: Select [<<Const11>>,<<Const12>>,<<Condition:z\d+>>]
+
+ /// CHECK-START: long Main.$noinline$testIntToLong(int, int) constant_folding$after_gvn (after)
+ /// CHECK-NOT: TypeConversion
+ /// CHECK-NOT: Add
+ private static long $noinline$testIntToLong(int a, int b) {
+ long result = 10;
+ int c = 1;
+ int d = 2;
+ return result + (a < b ? c : d);
+ }
+
+ /// CHECK-START: float Main.$noinline$testIntToFloat(int, int) select_generator (after)
+ /// CHECK: <<Const10:f\d+>> FloatConstant 10
+ /// CHECK: <<Const1:i\d+>> IntConstant 1
+ /// CHECK: <<Const2:i\d+>> IntConstant 2
+ /// CHECK: <<Sel:i\d+>> Select [<<Const1>>,<<Const2>>,<<Condition:z\d+>>]
+ /// CHECK: <<Type:f\d+>> TypeConversion [<<Sel>>]
+ /// CHECK: Add [<<Type>>,<<Const10>>]
+
+ /// CHECK-START: float Main.$noinline$testIntToFloat(int, int) constant_folding$after_gvn (after)
+ /// CHECK: <<Const11:f\d+>> FloatConstant 11
+ /// CHECK: <<Const12:f\d+>> FloatConstant 12
+ /// CHECK: Select [<<Const11>>,<<Const12>>,<<Condition:z\d+>>]
+
+ /// CHECK-START: float Main.$noinline$testIntToFloat(int, int) constant_folding$after_gvn (after)
+ /// CHECK-NOT: TypeConversion
+ /// CHECK-NOT: Add
+ private static float $noinline$testIntToFloat(int a, int b) {
+ float result = 10;
+ int c = 1;
+ int d = 2;
+ return result + (a < b ? c : d);
+ }
+
+ /// CHECK-START: byte Main.$noinline$testIntToByte(int, int) select_generator (after)
+ /// CHECK: <<Const10:i\d+>> IntConstant 10
+ /// CHECK: <<Const257:i\d+>> IntConstant 257
+ /// CHECK: <<Const258:i\d+>> IntConstant 258
+ /// CHECK: <<Sel:i\d+>> Select [<<Const257>>,<<Const258>>,<<Condition:z\d+>>]
+ /// CHECK: <<Type:b\d+>> TypeConversion [<<Sel>>]
+ /// CHECK: Add [<<Type>>,<<Const10>>]
+
+ /// CHECK-START: byte Main.$noinline$testIntToByte(int, int) constant_folding$after_gvn (after)
+ /// CHECK: <<Const11:i\d+>> IntConstant 11
+ /// CHECK: <<Const12:i\d+>> IntConstant 12
+ /// CHECK: Select [<<Const11>>,<<Const12>>,<<Condition:z\d+>>]
+
+ /// CHECK-START: byte Main.$noinline$testIntToByte(int, int) constant_folding$after_gvn (after)
+ /// CHECK-NOT: TypeConversion
+ /// CHECK-NOT: Add
+ private static byte $noinline$testIntToByte(int a, int b) {
+ byte result = 10;
+ int c = 257; // equal to 1 in byte
+ int d = 258; // equal to 2 in byte
+ // Due to `+` operating in ints, we need to do an extra cast. We can optimize away both type
+ // conversions.
+ return (byte) (result + (byte) (a < b ? c : d));
+ }
+
+ /// CHECK-START: int Main.$noinline$testLongToInt(int, int) select_generator (after)
+ /// CHECK: <<Const10:i\d+>> IntConstant 10
+ /// CHECK: <<Const1:j\d+>> LongConstant 4294967297
+ /// CHECK: <<Const2:j\d+>> LongConstant 4294967298
+ /// CHECK: <<Sel:j\d+>> Select [<<Const1>>,<<Const2>>,<<Condition:z\d+>>]
+ /// CHECK: <<Type:i\d+>> TypeConversion [<<Sel>>]
+ /// CHECK: Add [<<Type>>,<<Const10>>]
+
+ /// CHECK-START: int Main.$noinline$testLongToInt(int, int) constant_folding$after_gvn (after)
+ /// CHECK: <<Const11:i\d+>> IntConstant 11
+ /// CHECK: <<Const12:i\d+>> IntConstant 12
+ /// CHECK: Select [<<Const11>>,<<Const12>>,<<Condition:z\d+>>]
+
+ /// CHECK-START: int Main.$noinline$testLongToInt(int, int) constant_folding$after_gvn (after)
+ /// CHECK-NOT: TypeConversion
+ /// CHECK-NOT: Add
+ private static int $noinline$testLongToInt(int a, int b) {
+ int result = 10;
+ long c = (1L << 32) + 1L; // Will be 1, when cast to int
+ long d = (1L << 32) + 2L; // Will be 2, when cast to int
+ return result + (int) (a < b ? c : d);
+ }
+
+ private static void assertIntEquals(int expected, int actual) {
+ if (expected != actual) {
+ throw new AssertionError("Expected " + expected + " got " + actual);
+ }
+ }
+
+ private static void assertLongEquals(long expected, long actual) {
+ if (expected != actual) {
+ throw new AssertionError("Expected " + expected + " got " + actual);
+ }
+ }
+
+ private static void assertFloatEquals(float expected, float actual) {
+ if (expected != actual) {
+ throw new AssertionError("Expected " + expected + " got " + actual);
+ }
+ }
+}
diff --git a/test/567-checker-builder-intrinsics/src/TestSignum.java b/test/567-checker-builder-intrinsics/src/TestSignum.java
index ed3c5fe3df..c807743b6f 100644
--- a/test/567-checker-builder-intrinsics/src/TestSignum.java
+++ b/test/567-checker-builder-intrinsics/src/TestSignum.java
@@ -92,13 +92,11 @@ public class TestSignum {
/// CHECK-START: int TestSignum.signBoolean(boolean) select_generator (after)
/// CHECK-NOT: Phi
- /// CHECK-START: int TestSignum.signBoolean(boolean) instruction_simplifier$before_codegen (after)
+ /// CHECK-START: int TestSignum.signBoolean(boolean) instruction_simplifier$after_gvn (after)
/// CHECK-DAG: <<Arg:z\d+>> ParameterValue
- /// CHECK-DAG: <<Zero:i\d+>> IntConstant 0
- /// CHECK-DAG: <<Result:i\d+>> Compare [<<Arg>>,<<Zero>>]
- /// CHECK-DAG: Return [<<Result>>]
+ /// CHECK-DAG: Return [<<Arg>>]
- /// CHECK-START: int TestSignum.signBoolean(boolean) instruction_simplifier$before_codegen (after)
+ /// CHECK-START: int TestSignum.signBoolean(boolean) instruction_simplifier$after_gvn (after)
/// CHECK-NOT: Select
private static int signBoolean(boolean x) {
diff --git a/test/570-checker-select/src/Main.java b/test/570-checker-select/src/Main.java
index 0e23b3dc00..57e4db5dbd 100644
--- a/test/570-checker-select/src/Main.java
+++ b/test/570-checker-select/src/Main.java
@@ -500,7 +500,6 @@ public class Main {
/// CHECK-START: float Main.$noinline$FloatGtMatCond_FloatVarVar(float, float, float, float) register (after)
/// CHECK: <<Cond:z\d+>> GreaterThanOrEqual
/// CHECK-NEXT: <<Sel:f\d+>> Select [{{f\d+}},{{f\d+}},<<Cond>>]
- /// CHECK-NEXT: TypeConversion [<<Cond>>]
/// CHECK-START-ARM64: float Main.$noinline$FloatGtMatCond_FloatVarVar(float, float, float, float) disassembly (after)
/// CHECK: GreaterThanOrEqual
diff --git a/test/593-checker-boolean-2-integral-conv/smali/SmaliTests.smali b/test/593-checker-boolean-2-integral-conv/smali/SmaliTests.smali
index f3f52a8f11..8e84d054a0 100644
--- a/test/593-checker-boolean-2-integral-conv/smali/SmaliTests.smali
+++ b/test/593-checker-boolean-2-integral-conv/smali/SmaliTests.smali
@@ -187,8 +187,10 @@
## CHECK-START: long SmaliTests.booleanToLong(boolean) instruction_simplifier$before_codegen (after)
## CHECK-DAG: <<Arg:z\d+>> ParameterValue
-## CHECK-DAG: <<ZToJ:j\d+>> TypeConversion [<<Arg>>]
-## CHECK-DAG: Return [<<ZToJ>>]
+## CHECK-DAG: <<Zero:j\d+>> LongConstant 0
+## CHECK-DAG: <<One:j\d+>> LongConstant 1
+## CHECK-DAG: <<Sel:j\d+>> Select [<<Zero>>,<<One>>,<<Arg>>]
+## CHECK-DAG: Return [<<Sel>>]
.method public static booleanToLong(Z)J
.registers 3
.param p0, "b" # Z
diff --git a/test/646-checker-long-const-to-int/src/Main.java b/test/646-checker-long-const-to-int/src/Main.java
index 2133588d75..491565bc17 100644
--- a/test/646-checker-long-const-to-int/src/Main.java
+++ b/test/646-checker-long-const-to-int/src/Main.java
@@ -16,7 +16,7 @@
public class Main {
public static void main(String[] args) {
- System.out.println(test());
+ System.out.println(test(0L));
}
public static long testField = 0;
@@ -29,18 +29,18 @@ public class Main {
public static long longField6 = 0;
public static long longField7 = 0;
- /// CHECK-START-ARM: int Main.test() register (after)
+ /// CHECK-START-ARM: int Main.test(long) register (after)
/// CHECK: TypeConversion locations:[#-8690466096623102344]->{{.*}}
- public static int test() {
+ public static int test(long other) {
// To avoid constant folding TypeConversion(const), hide the constant in a field. Then, hide
- // it even more inside a Select that can only be reduced after LSE+InstructionSelector. We
+ // it even more inside a Select that can only be reduced after LSE+InstructionSimplifier. We
// don't run constant folding after that.
testField = 0x8765432112345678L;
long value = testField;
if (value + 1 == 0x8765432112345679L) {
value = testField;
} else {
- value = 0;
+ value = other;
}
// Now, the `value` is in a register because of the store but we need
// a constant location to trigger the bug, so load a bunch of other fields.