[VM] Use redefinitions for strenghtening, prefer equality comparison over strict comparison

When strenghtening the types in AOT call specializer, we do it via redefinitions
instead of setting a reachingt type on the Value.  This has the advantage that all
uses will get the new type, which improves e.g. StaticCall(_IntegerImpl.*, v1, v1)
where multiple uses can benefit.

This CL also changes the AOT call specializer to prefer equality comparisons over
strict comparisons, because strict comparisons can force boxing (which causes code bloat).

Change-Id: I803bb09c70ee2f4656062b5ce3cb28ffaf940e9b
Reviewed-on: https://dart-review.googlesource.com/c/84525
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
diff --git a/runtime/vm/compiler/aot/aot_call_specializer.cc b/runtime/vm/compiler/aot/aot_call_specializer.cc
index 4213020..342b101 100644
--- a/runtime/vm/compiler/aot/aot_call_specializer.cc
+++ b/runtime/vm/compiler/aot/aot_call_specializer.cc
@@ -320,7 +320,8 @@
   return input;
 }
 
-void AotCallSpecializer::StrengthenReachingType(Value* input, intptr_t cid) {
+CompileType AotCallSpecializer::BuildStrengthenedReceiverType(Value* input,
+                                                              intptr_t cid) {
   CompileType* old_type = input->Type();
   CompileType* refined_type = old_type;
 
@@ -340,8 +341,9 @@
   }
 
   if (refined_type != old_type) {
-    input->SetReachingType(new (Z) CompileType(*refined_type));
+    return *refined_type;
   }
+  return CompileType::None();
 }
 
 // After replacing a call with a specialized instruction, make sure to
@@ -393,9 +395,19 @@
     // tighten it (this is safe since it was proven that te receiver is either
     // null or will end up with that target).
     const intptr_t receiver_index = instr->FirstArgIndex();
-    if (instr->ArgumentCountWithoutTypeArgs() >= 1) {
-      StrengthenReachingType(instr->PushArgumentAt(receiver_index)->value(),
-                             cid);
+    const intptr_t argument_count = instr->ArgumentCountWithoutTypeArgs();
+    if (argument_count >= 1) {
+      auto push_receiver = instr->PushArgumentAt(receiver_index);
+      auto receiver_value = push_receiver->value();
+      auto receiver = receiver_value->definition();
+      auto type = BuildStrengthenedReceiverType(receiver_value, cid);
+      if (!type.IsNone()) {
+        auto redefinition = flow_graph()->EnsureRedefinition(
+            push_receiver->previous(), receiver, type);
+        if (redefinition != nullptr) {
+          RefineUseTypes(redefinition);
+        }
+      }
     }
   }
 
@@ -419,8 +431,16 @@
     CompileType* left_type = left_value->Type();
     CompileType* right_type = right_value->Type();
 
-    // We only support binary operations on nullable integers.
-    if (!left_type->IsNullableInt() || !right_type->IsNullableInt()) {
+    const bool is_equality_op = Token::IsEqualityOperator(op_kind);
+    const bool can_use_strict_compare =
+        is_equality_op &&
+        (left_type->IsNullableSmi() || right_type->IsNullableSmi());
+    const bool has_nullable_int_args =
+        left_type->IsNullableInt() && right_type->IsNullableInt();
+
+    // We only support binary operations if both operands are nullable integers
+    // or when we can use a cheap strict comparison operation.
+    if (!has_nullable_int_args && !can_use_strict_compare) {
       return false;
     }
 
@@ -431,9 +451,15 @@
       case Token::kLTE:
       case Token::kGT:
       case Token::kGTE: {
-        const bool is_equality_op = Token::IsEqualityOperator(op_kind);
-        if (is_equality_op && (left_type->ToNullableCid() == kSmiCid ||
-                               right_type->ToNullableCid() == kSmiCid)) {
+        const bool supports_unboxed_int =
+            FlowGraphCompiler::SupportsUnboxedInt64();
+        const bool can_use_equality_compare =
+            supports_unboxed_int && is_equality_op && left_type->IsInt() &&
+            right_type->IsInt();
+
+        // We prefer equality compare, since it doesn't require boxing.
+        if (is_equality_op && !can_use_equality_compare &&
+            (left_type->IsNullableSmi() || right_type->IsNullableSmi())) {
           replacement = new (Z) StrictCompareInstr(
               instr->token_pos(),
               (op_kind == Token::kEQ) ? Token::kEQ_STRICT : Token::kNE_STRICT,
@@ -442,8 +468,8 @@
           break;
         }
 
-        if (FlowGraphCompiler::SupportsUnboxedInt64()) {
-          if (is_equality_op && left_type->IsInt() && right_type->IsInt()) {
+        if (supports_unboxed_int) {
+          if (can_use_equality_compare) {
             replacement = new (Z) EqualityCompareInstr(
                 instr->token_pos(), op_kind, left_value->CopyWithType(Z),
                 right_value->CopyWithType(Z), kMintCid, DeoptId::kNone,
diff --git a/runtime/vm/compiler/aot/aot_call_specializer.h b/runtime/vm/compiler/aot/aot_call_specializer.h
index cbced5d..a18b78c 100644
--- a/runtime/vm/compiler/aot/aot_call_specializer.h
+++ b/runtime/vm/compiler/aot/aot_call_specializer.h
@@ -48,7 +48,7 @@
   bool IsSupportedIntOperandForStaticDoubleOp(CompileType* operand_type);
   Value* PrepareStaticOpInput(Value* input, intptr_t cid, Instruction* call);
 
-  void StrengthenReachingType(Value* input, intptr_t cid);
+  CompileType BuildStrengthenedReceiverType(Value* input, intptr_t cid);
 
   bool TryOptimizeInstanceCallUsingStaticTypes(InstanceCallInstr* instr);
 
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index 845f173..dff225c 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -204,6 +204,17 @@
     return false;
   }
 
+  // Returns true if value of this type is either Smi or null.
+  bool IsNullableSmi() {
+    if (cid_ == kSmiCid) {
+      return true;
+    }
+    if ((cid_ == kIllegalCid) || (cid_ == kDynamicCid)) {
+      return type_ != nullptr && type_->IsSmiType();
+    }
+    return false;
+  }
+
   // Returns true if value of this type is either double or null.
   bool IsNullableDouble() {
     if (cid_ == kDoubleCid) {