[vm/compiler] Improve logic for combining types when both types have the same cid
Previously, a type with known cid was immediately selected, even
if another type also has a known cid. Now, if cids match, the static
types are also compared. This is useful for record types, because
static record type is more accurate than known kRecordCid.
TEST=vm/dart/records_field_operations_il_test
Issue: https://github.com/dart-lang/sdk/issues/51637
Cq-Include-Trybots: luci.dart.try:vm-aot-linux-release-x64-try,vm-aot-linux-debug-x64-try
Change-Id: I4e528d80a355a79d428bf3f03212c5a65af0b661
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/292983
Auto-Submit: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
diff --git a/runtime/tests/vm/dart/records_field_operations_il_test.dart b/runtime/tests/vm/dart/records_field_operations_il_test.dart
index 688753d..dd4369b 100644
--- a/runtime/tests/vm/dart/records_field_operations_il_test.dart
+++ b/runtime/tests/vm/dart/records_field_operations_il_test.dart
@@ -31,6 +31,12 @@
@pragma('vm:never-inline')
(double, double) staticCallD() => (d(1), d(2));
+@pragma('vm:prefer-inline')
+void inlinedCallD((double, double) xy) {
+ var (x, y) = xy;
+ print(x - y);
+}
+
@pragma('vm:never-inline')
@pragma('vm:testing:print-flow-graph')
void testDouble(A obj, double a, double b, (double, double) param) {
@@ -64,6 +70,11 @@
var (x, y) = obj.instanceCallD();
print(x + y);
}
+
+ {
+ final local = (a, b);
+ inlinedCallD(local);
+ }
}
void matchIL$testDouble(FlowGraph graph) {
@@ -124,6 +135,11 @@
'v6' << match.BinaryDoubleOp('x6_unboxed', 'y6_unboxed'),
'v6_boxed' << match.Box('v6'),
match.MoveArgument('v6_boxed'),
+ match.StaticCall(),
+ 'v7' << match.BinaryDoubleOp('a', 'b'),
+ 'v7_boxed' << match.Box('v7'),
+ match.MoveArgument('v7_boxed'),
+ match.StaticCall(),
match.Return(),
]),
]);
@@ -151,6 +167,12 @@
@pragma('vm:never-inline')
(int, int) staticCallI() => (i(1), i(2));
+@pragma('vm:prefer-inline')
+void inlinedCallI((int, int) xy) {
+ var (x, y) = xy;
+ print(x - y);
+}
+
@pragma('vm:never-inline')
@pragma('vm:testing:print-flow-graph')
void testInt(B obj, int a, int b, (int, int) param) {
@@ -184,6 +206,11 @@
var (x, y) = obj.instanceCallI();
print(x + y);
}
+
+ {
+ final local = (a, b);
+ inlinedCallI(local);
+ }
}
void matchIL$testInt(FlowGraph graph) {
@@ -245,6 +272,10 @@
'v6_boxed' << match.BoxInt64('v6'),
match.MoveArgument('v6_boxed'),
match.StaticCall(),
+ 'v7' << match.BinaryInt64Op('a', 'b'),
+ 'v7_boxed' << match.BoxInt64('v7'),
+ match.MoveArgument('v7_boxed'),
+ match.StaticCall(),
match.Return(),
]),
]);
diff --git a/runtime/vm/compiler/backend/type_propagator.cc b/runtime/vm/compiler/backend/type_propagator.cc
index 7ee69f5..3e5daa2 100644
--- a/runtime/vm/compiler/backend/type_propagator.cc
+++ b/runtime/vm/compiler/backend/type_propagator.cc
@@ -627,30 +627,36 @@
return old_type;
}
- // Prefer exact Cid if known.
- if (new_type->ToCid() != kDynamicCid) {
- return new_type;
- }
- if (old_type->ToCid() != kDynamicCid) {
- return old_type;
- }
-
- const AbstractType* old_abstract_type = old_type->ToAbstractType();
- const AbstractType* new_abstract_type = new_type->ToAbstractType();
CompileType* preferred_type = nullptr;
- // Prefer 'int' if known.
- if (old_type->IsNullableInt()) {
- preferred_type = old_type;
- } else if (new_type->IsNullableInt()) {
- preferred_type = new_type;
- } else if (old_abstract_type->IsSubtypeOf(*new_abstract_type, Heap::kOld)) {
- // Prefer old type, as it is clearly more specific.
- preferred_type = old_type;
- } else {
- // Prefer new type as it is more recent, even though it might be
- // no better than the old type.
- preferred_type = new_type;
+ // Prefer exact Cid if known.
+ const intptr_t new_type_cid = new_type->ToCid();
+ const intptr_t old_type_cid = old_type->ToCid();
+ if (new_type_cid != old_type_cid) {
+ if (new_type_cid != kDynamicCid) {
+ preferred_type = new_type;
+ } else if (old_type_cid != kDynamicCid) {
+ preferred_type = old_type;
+ }
+ }
+
+ if (preferred_type == nullptr) {
+ const AbstractType* old_abstract_type = old_type->ToAbstractType();
+ const AbstractType* new_abstract_type = new_type->ToAbstractType();
+
+ // Prefer 'int' if known.
+ if (old_type->IsNullableInt()) {
+ preferred_type = old_type;
+ } else if (new_type->IsNullableInt()) {
+ preferred_type = new_type;
+ } else if (old_abstract_type->IsSubtypeOf(*new_abstract_type, Heap::kOld)) {
+ // Prefer old type, as it is clearly more specific.
+ preferred_type = old_type;
+ } else {
+ // Prefer new type as it is more recent, even though it might be
+ // no better than the old type.
+ preferred_type = new_type;
+ }
}
// Refine non-nullability and whether it can be sentinel.