summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Santiago Aboy Solanes <solanes@google.com> 2024-11-14 15:09:41 +0000
committer Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> 2024-11-21 12:39:22 +0000
commita21eb118c8c1e9d362b7465327f1fae8db48a572 (patch)
treee5542170e0de695c9dd491fa7b77a7deb73e28ae
parent53d8174b0003eb22192aba21d54ca96947002151 (diff)
Allow the inliner to devirtualize intrinsics
To do so update: * TryReplaceStringBuilderAppend * Code paths relevant to previously InvokeVirtual that are now InvokeStaticOrDirect * checker tests. Bug: 369206455 Test: art/test/testrunner/testrunner.py --host --64 -b --optimizing Change-Id: I4d40980e416f3130d3c344c5f07b7b331deb5c97
-rw-r--r--compiler/optimizing/inliner.cc9
-rw-r--r--compiler/optimizing/instruction_simplifier.cc53
-rw-r--r--compiler/optimizing/nodes.cc26
-rw-r--r--compiler/optimizing/nodes.h24
-rw-r--r--test/624-checker-stringops/src/Main.java40
-rw-r--r--test/672-checker-throw-method/src/Main.java8
-rw-r--r--test/673-checker-throw-vmethod/src/Main.java8
7 files changed, 87 insertions, 81 deletions
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 44af0d6b66..d679261d42 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -1342,13 +1342,6 @@ bool HInliner::TryDevirtualize(HInvoke* invoke_instruction,
return false;
}
- // Don't try to devirtualize intrinsics as it breaks pattern matching from later phases.
- // TODO(solanes): This `if` could be removed if we update optimizations like
- // TryReplaceStringBuilderAppend.
- if (invoke_instruction->IsIntrinsic()) {
- return false;
- }
-
// Don't devirtualize to an intrinsic invalid after the builder phase. The ArtMethod might be an
// intrinsic even when the HInvoke isn't e.g. java.lang.CharSequence.isEmpty (not an intrinsic)
// can get devirtualized into java.lang.String.isEmpty (which is an intrinsic).
@@ -2452,7 +2445,7 @@ bool HInliner::ReturnTypeMoreSpecific(HInstruction* return_replacement,
ReferenceTypeInfo invoke_rti = invoke_instruction->GetReferenceTypeInfo();
if (IsReferenceTypeRefinement(invoke_rti.GetTypeHandle().Get(),
invoke_rti.IsExact(),
- /*declared_can_be_null=*/ true,
+ invoke_instruction->CanBeNull(),
return_replacement)) {
return true;
} else if (return_replacement->IsInstanceFieldGet()) {
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 931050855c..703f6c77e8 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -2976,13 +2976,8 @@ void InstructionSimplifierVisitor::SimplifyReturnThis(HInvoke* invoke) {
// Helper method for StringBuffer escape analysis.
static bool NoEscapeForStringBufferReference(HInstruction* reference, HInstruction* user) {
- if (user->IsInvokeStaticOrDirect()) {
- // Any constructor on StringBuffer is okay.
- return user->AsInvokeStaticOrDirect()->GetResolvedMethod() != nullptr &&
- user->AsInvokeStaticOrDirect()->GetResolvedMethod()->IsConstructor() &&
- user->InputAt(0) == reference;
- } else if (user->IsInvokeVirtual()) {
- switch (user->AsInvokeVirtual()->GetIntrinsic()) {
+ if (user->IsInvoke()) {
+ switch (user->AsInvoke()->GetIntrinsic()) {
case Intrinsics::kStringBufferLength:
case Intrinsics::kStringBufferToString:
DCHECK_EQ(user->InputAt(0), reference);
@@ -2996,6 +2991,14 @@ static bool NoEscapeForStringBufferReference(HInstruction* reference, HInstructi
break;
}
}
+
+ if (user->IsInvokeStaticOrDirect()) {
+ // Any constructor on StringBuffer is okay.
+ return user->AsInvokeStaticOrDirect()->GetResolvedMethod() != nullptr &&
+ user->AsInvokeStaticOrDirect()->GetResolvedMethod()->IsConstructor() &&
+ user->InputAt(0) == reference;
+ }
+
return false;
}
@@ -3051,13 +3054,24 @@ static bool TryReplaceStringBuilderAppend(CodeGenerator* codegen, HInvoke* invok
return false;
}
}
- // Then we should see the arguments.
- if (user->IsInvokeVirtual()) {
- HInvokeVirtual* as_invoke_virtual = user->AsInvokeVirtual();
+
+ // Pattern match seeing arguments, then constructor, then constructor fence.
+ if (user->IsInvokeStaticOrDirect() &&
+ user->AsInvokeStaticOrDirect()->GetResolvedMethod() != nullptr &&
+ user->AsInvokeStaticOrDirect()->GetResolvedMethod()->IsConstructor() &&
+ user->AsInvokeStaticOrDirect()->GetNumberOfArguments() == 1u) {
+ // After arguments, we should see the constructor.
+ // We accept only the constructor with no extra arguments.
+ DCHECK(!seen_constructor);
+ DCHECK(!seen_constructor_fence);
+ seen_constructor = true;
+ } else if (user->IsInvoke()) {
+ // The arguments.
+ HInvoke* as_invoke = user->AsInvoke();
DCHECK(!seen_constructor);
DCHECK(!seen_constructor_fence);
StringBuilderAppend::Argument arg;
- switch (as_invoke_virtual->GetIntrinsic()) {
+ switch (as_invoke->GetIntrinsic()) {
case Intrinsics::kStringBuilderAppendObject:
// TODO: Unimplemented, needs to call String.valueOf().
return false;
@@ -3089,7 +3103,7 @@ static bool TryReplaceStringBuilderAppend(CodeGenerator* codegen, HInvoke* invok
has_fp_args = true;
break;
case Intrinsics::kStringBuilderAppendCharSequence: {
- ReferenceTypeInfo rti = user->AsInvokeVirtual()->InputAt(1)->GetReferenceTypeInfo();
+ ReferenceTypeInfo rti = as_invoke->InputAt(1)->GetReferenceTypeInfo();
if (!rti.IsValid()) {
return false;
}
@@ -3112,23 +3126,14 @@ static bool TryReplaceStringBuilderAppend(CodeGenerator* codegen, HInvoke* invok
}
}
// Uses of the append return value should have been replaced with the first input.
- DCHECK(!as_invoke_virtual->HasUses());
- DCHECK(!as_invoke_virtual->HasEnvironmentUses());
+ DCHECK(!as_invoke->HasUses());
+ DCHECK(!as_invoke->HasEnvironmentUses());
if (num_args == StringBuilderAppend::kMaxArgs) {
return false;
}
format = (format << StringBuilderAppend::kBitsPerArg) | static_cast<uint32_t>(arg);
- args[num_args] = as_invoke_virtual->InputAt(1u);
+ args[num_args] = as_invoke->InputAt(1u);
++num_args;
- } else if (user->IsInvokeStaticOrDirect() &&
- user->AsInvokeStaticOrDirect()->GetResolvedMethod() != nullptr &&
- user->AsInvokeStaticOrDirect()->GetResolvedMethod()->IsConstructor() &&
- user->AsInvokeStaticOrDirect()->GetNumberOfArguments() == 1u) {
- // After arguments, we should see the constructor.
- // We accept only the constructor with no extra arguments.
- DCHECK(!seen_constructor);
- DCHECK(!seen_constructor_fence);
- seen_constructor = true;
} else if (user->IsConstructorFence()) {
// The last use we see is the constructor fence.
DCHECK(seen_constructor);
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index e7aabb223a..31e999a282 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -3263,17 +3263,35 @@ std::ostream& operator<<(std::ostream& os, HInvokeStaticOrDirect::ClinitCheckReq
}
bool HInvokeStaticOrDirect::CanBeNull() const {
- if (GetType() != DataType::Type::kReference || IsStringInit()) {
+ if (IsStringInit()) {
return false;
}
+ return HInvoke::CanBeNull();
+}
+
+bool HInvoke::CanBeNull() const {
switch (GetIntrinsic()) {
+ case Intrinsics::kThreadCurrentThread:
+ case Intrinsics::kStringBufferAppend:
+ case Intrinsics::kStringBufferToString:
+ case Intrinsics::kStringBuilderAppendObject:
+ case Intrinsics::kStringBuilderAppendString:
+ case Intrinsics::kStringBuilderAppendCharSequence:
+ case Intrinsics::kStringBuilderAppendCharArray:
+ case Intrinsics::kStringBuilderAppendBoolean:
+ case Intrinsics::kStringBuilderAppendChar:
+ case Intrinsics::kStringBuilderAppendInt:
+ case Intrinsics::kStringBuilderAppendLong:
+ case Intrinsics::kStringBuilderAppendFloat:
+ case Intrinsics::kStringBuilderAppendDouble:
+ case Intrinsics::kStringBuilderToString:
#define DEFINE_BOXED_CASE(name, unused1, unused2, unused3, unused4) \
- case Intrinsics::k##name##ValueOf: \
- return false;
+ case Intrinsics::k##name##ValueOf:
BOXED_TYPES(DEFINE_BOXED_CASE)
#undef DEFINE_BOXED_CASE
+ return false;
default:
- return true;
+ return GetType() == DataType::Type::kReference;
}
}
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 676a9b9dd2..e0913c821c 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -4632,6 +4632,8 @@ class HInvoke : public HVariableInputSizeInstruction {
bool CanBeMoved() const override { return IsIntrinsic() && !DoesAnyWrite(); }
+ bool CanBeNull() const override;
+
bool InstructionDataEquals(const HInstruction* other) const override {
return intrinsic_ != Intrinsics::kNone && intrinsic_ == other->AsInvoke()->intrinsic_;
}
@@ -5110,28 +5112,6 @@ class HInvokeVirtual final : public HInvoke {
bool IsClonable() const override { return true; }
- bool CanBeNull() const override {
- switch (GetIntrinsic()) {
- case Intrinsics::kThreadCurrentThread:
- case Intrinsics::kStringBufferAppend:
- case Intrinsics::kStringBufferToString:
- case Intrinsics::kStringBuilderAppendObject:
- case Intrinsics::kStringBuilderAppendString:
- case Intrinsics::kStringBuilderAppendCharSequence:
- case Intrinsics::kStringBuilderAppendCharArray:
- case Intrinsics::kStringBuilderAppendBoolean:
- case Intrinsics::kStringBuilderAppendChar:
- case Intrinsics::kStringBuilderAppendInt:
- case Intrinsics::kStringBuilderAppendLong:
- case Intrinsics::kStringBuilderAppendFloat:
- case Intrinsics::kStringBuilderAppendDouble:
- case Intrinsics::kStringBuilderToString:
- return false;
- default:
- return HInvoke::CanBeNull();
- }
- }
-
bool CanDoImplicitNullCheckOn(HInstruction* obj) const override;
uint32_t GetVTableIndex() const { return vtable_index_; }
diff --git a/test/624-checker-stringops/src/Main.java b/test/624-checker-stringops/src/Main.java
index 055a4d7ec9..06b1af36df 100644
--- a/test/624-checker-stringops/src/Main.java
+++ b/test/624-checker-stringops/src/Main.java
@@ -27,16 +27,16 @@ public class Main {
// Variant intrinsics remain in the loop, but invariant references are hoisted out of the loop.
//
/// CHECK-START: int Main.liveIndexOf() licm (before)
- /// CHECK-DAG: InvokeVirtual intrinsic:StringIndexOf loop:{{B\d+}} outer_loop:none
- /// CHECK-DAG: InvokeVirtual intrinsic:StringIndexOfAfter loop:{{B\d+}} outer_loop:none
- /// CHECK-DAG: InvokeVirtual intrinsic:StringStringIndexOf loop:{{B\d+}} outer_loop:none
- /// CHECK-DAG: InvokeVirtual intrinsic:StringStringIndexOfAfter loop:{{B\d+}} outer_loop:none
+ /// CHECK-DAG: InvokeVirtual intrinsic:StringIndexOf loop:{{B\d+}} outer_loop:none
+ /// CHECK-DAG: InvokeVirtual intrinsic:StringIndexOfAfter loop:{{B\d+}} outer_loop:none
+ /// CHECK-DAG: InvokeStaticOrDirect intrinsic:StringStringIndexOf loop:{{B\d+}} outer_loop:none
+ /// CHECK-DAG: InvokeStaticOrDirect intrinsic:StringStringIndexOfAfter loop:{{B\d+}} outer_loop:none
//
/// CHECK-START: int Main.liveIndexOf() licm (after)
- /// CHECK-DAG: InvokeVirtual intrinsic:StringIndexOf loop:{{B\d+}} outer_loop:none
- /// CHECK-DAG: InvokeVirtual intrinsic:StringIndexOfAfter loop:{{B\d+}} outer_loop:none
- /// CHECK-DAG: InvokeVirtual intrinsic:StringStringIndexOf loop:none
- /// CHECK-DAG: InvokeVirtual intrinsic:StringStringIndexOfAfter loop:none
+ /// CHECK-DAG: InvokeVirtual intrinsic:StringIndexOf loop:{{B\d+}} outer_loop:none
+ /// CHECK-DAG: InvokeVirtual intrinsic:StringIndexOfAfter loop:{{B\d+}} outer_loop:none
+ /// CHECK-DAG: InvokeStaticOrDirect intrinsic:StringStringIndexOf loop:none
+ /// CHECK-DAG: InvokeStaticOrDirect intrinsic:StringStringIndexOfAfter loop:none
static int liveIndexOf() {
int k = ABC.length() + XYZ.length(); // does LoadString before loops
for (char c = 'A'; c <= 'Z'; c++) {
@@ -89,8 +89,8 @@ public class Main {
// Explicit null check on receiver, implicit null check on argument prevents hoisting.
//
/// CHECK-START: int Main.indexOfExceptions(java.lang.String, java.lang.String) licm (after)
- /// CHECK-DAG: <<String:l\d+>> NullCheck loop:<<Loop:B\d+>> outer_loop:none
- /// CHECK-DAG: InvokeVirtual [<<String>>,{{l\d+}}] intrinsic:StringStringIndexOf loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<String:l\d+>> NullCheck loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: InvokeStaticOrDirect [<<String>>,{{l\d+}}] intrinsic:StringStringIndexOf loop:<<Loop>> outer_loop:none
static int indexOfExceptions(String s, String t) {
int k = 0;
for (char c = 'A'; c <= 'Z'; c++) {
@@ -234,17 +234,27 @@ public class Main {
}
//
- // All calls in the loop-body and thus loop can be eliminated.
+ // All calls in the loop-body are dead and thus loop can be eliminated.
//
- /// CHECK-START: int Main.bufferDeadLoop() instruction_simplifier (before)
+ /// CHECK-START: int Main.bufferDeadLoop() dead_code_elimination$initial (before)
/// CHECK-DAG: Phi loop:<<Loop:B\d+>>
/// CHECK-DAG: InvokeVirtual intrinsic:StringBufferToString loop:<<Loop>>
/// CHECK-DAG: InvokeVirtual intrinsic:StringStringIndexOfAfter loop:<<Loop>>
//
+ /// CHECK-START: int Main.bufferDeadLoop() dead_code_elimination$initial (after)
+ /// CHECK-NOT: InvokeVirtual intrinsic:StringStringIndexOfAfter
+ //
+ /// CHECK-START: int Main.bufferDeadLoop() instruction_simplifier$after_inlining (before)
+ /// CHECK: InvokeStaticOrDirect intrinsic:StringBufferToString
+ //
+ /// CHECK-START: int Main.bufferDeadLoop() instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: InvokeStaticOrDirect intrinsic:StringBufferToString
+ //
+ /// CHECK-START: int Main.bufferDeadLoop() loop_optimization (before)
+ /// CHECK: Phi
+ //
/// CHECK-START: int Main.bufferDeadLoop() loop_optimization (after)
/// CHECK-NOT: Phi
- /// CHECK-NOT: InvokeVirtual intrinsic:StringBufferToString
- /// CHECK-NOT: InvokeVirtual intrinsic:StringStringIndexOfAfter
static int bufferDeadLoop() {
StringBuffer b = new StringBuffer();
String x = "x";
@@ -255,7 +265,7 @@ public class Main {
}
//
- // All calls in the loop-body and thus loop can be eliminated.
+ // All calls in the loop-body are dead and thus loop can be eliminated.
//
/// CHECK-START: int Main.builderDeadLoop() instruction_simplifier (before)
/// CHECK-DAG: Phi loop:<<Loop:B\d+>>
diff --git a/test/672-checker-throw-method/src/Main.java b/test/672-checker-throw-method/src/Main.java
index c2344b23e8..f149536e1d 100644
--- a/test/672-checker-throw-method/src/Main.java
+++ b/test/672-checker-throw-method/src/Main.java
@@ -55,7 +55,7 @@ public class Main {
/// CHECK: If [<<Tst>>]
/// CHECK: end_block
/// CHECK: begin_block
- /// CHECK: InvokeVirtual [{{l\d+}},<<Str>>]
+ /// CHECK: InvokeStaticOrDirect [{{l\d+}},<<Str>>] method_name:java.lang.StringBuilder.append
/// CHECK: Throw
/// CHECK: end_block
//
@@ -66,7 +66,7 @@ public class Main {
/// CHECK: end_block
/// CHECK: begin_block
/// CHECK: <<Str:l\d+>> LoadString
- /// CHECK: InvokeVirtual [{{l\d+}},<<Str>>]
+ /// CHECK: InvokeStaticOrDirect [{{l\d+}},<<Str>>] method_name:java.lang.StringBuilder.append
/// CHECK: Throw
/// CHECK: end_block
static public void doit1(int[] a) {
@@ -117,7 +117,7 @@ public class Main {
/// CHECK: If [<<Tst>>]
/// CHECK: end_block
/// CHECK: begin_block
- /// CHECK: InvokeVirtual [{{l\d+}},<<Str>>]
+ /// CHECK: InvokeStaticOrDirect [{{l\d+}},<<Str>>] method_name:java.lang.StringBuilder.append
/// CHECK: Throw
/// CHECK: end_block
//
@@ -128,7 +128,7 @@ public class Main {
/// CHECK: end_block
/// CHECK: begin_block
/// CHECK: <<Str:l\d+>> LoadString
- /// CHECK: InvokeVirtual [{{l\d+}},<<Str>>]
+ /// CHECK: InvokeStaticOrDirect [{{l\d+}},<<Str>>] method_name:java.lang.StringBuilder.append
/// CHECK: Throw
/// CHECK: end_block
static public void doit3(int[] a) {
diff --git a/test/673-checker-throw-vmethod/src/Main.java b/test/673-checker-throw-vmethod/src/Main.java
index 39793001f0..dcffcabf51 100644
--- a/test/673-checker-throw-vmethod/src/Main.java
+++ b/test/673-checker-throw-vmethod/src/Main.java
@@ -49,7 +49,7 @@ public class Main {
/// CHECK: If [<<Tst>>]
/// CHECK: end_block
/// CHECK: begin_block
- /// CHECK: InvokeVirtual [{{l\d+}},<<Str>>]
+ /// CHECK: InvokeStaticOrDirect [{{l\d+}},<<Str>>] method_name:java.lang.StringBuilder.append
/// CHECK: Throw
/// CHECK: end_block
//
@@ -60,7 +60,7 @@ public class Main {
/// CHECK: end_block
/// CHECK: begin_block
/// CHECK: <<Str:l\d+>> LoadString
- /// CHECK: InvokeVirtual [{{l\d+}},<<Str>>]
+ /// CHECK: InvokeStaticOrDirect [{{l\d+}},<<Str>>] method_name:java.lang.StringBuilder.append
/// CHECK: Throw
/// CHECK: end_block
public void doit1(int[] a) {
@@ -111,7 +111,7 @@ public class Main {
/// CHECK: If [<<Tst>>]
/// CHECK: end_block
/// CHECK: begin_block
- /// CHECK: InvokeVirtual [{{l\d+}},<<Str>>]
+ /// CHECK: InvokeStaticOrDirect [{{l\d+}},<<Str>>] method_name:java.lang.StringBuilder.append
/// CHECK: Throw
/// CHECK: end_block
//
@@ -122,7 +122,7 @@ public class Main {
/// CHECK: end_block
/// CHECK: begin_block
/// CHECK: <<Str:l\d+>> LoadString
- /// CHECK: InvokeVirtual [{{l\d+}},<<Str>>]
+ /// CHECK: InvokeStaticOrDirect [{{l\d+}},<<Str>>] method_name:java.lang.StringBuilder.append
/// CHECK: Throw
/// CHECK: end_block
public void doit3(int[] a) {