[vm/compiler] Fix crashes in AOT X64 DEBUG compiler.

Rationale:
The method ConstructReplacementFor() in range analysis would unconditionally
replace an UnaryInt64Op with an UnaryUint32Op, regardless of whether it contains
an NEGATE or NOT. None of the backends supports a NEGATE UnaryUint32Op,
however (I added a missing assert to X64 for the future, even though we currently
found the issue in the constructor already). Note that alternatively we could implement
NEGATE UnaryUint32Op for all platforms.

Note:
A similar issue was found for TRUNCDIV with a second fuzz test, which is fixed
in same CL with a more general approach.

Bug:
https://github.com/dart-lang/sdk/issues/34678
https://github.com/dart-lang/sdk/issues/34679


Change-Id: I370268620008e5d4cb605c0bd11e423d8fcd5327
Reviewed-on: https://dart-review.googlesource.com/c/78148
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Commit-Queue: Aart Bik <ajcbik@google.com>
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index ca93a55..b30532f 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -6165,7 +6165,7 @@
  public:
   UnaryUint32OpInstr(Token::Kind op_kind, Value* value, intptr_t deopt_id)
       : UnaryIntegerOpInstr(op_kind, value, deopt_id) {
-    ASSERT(op_kind == Token::kBIT_NOT);
+    ASSERT(IsSupported(op_kind));
   }
 
   virtual bool ComputeCanDeoptimize() const { return false; }
@@ -6179,6 +6179,10 @@
     return kUnboxedUint32;
   }
 
+  static bool IsSupported(Token::Kind op_kind) {
+    return op_kind == Token::kBIT_NOT;
+  }
+
   DECLARE_INSTRUCTION(UnaryUint32Op)
 
  private:
@@ -6420,9 +6424,9 @@
     SetInputAt(1, right);
   }
 
-  static bool IsSupported(Token::Kind op, Value* left, Value* right) {
+  static bool IsSupported(Token::Kind op_kind, Value* left, Value* right) {
 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM)
-    switch (op) {
+    switch (op_kind) {
       case Token::kADD:
       case Token::kSUB:
       case Token::kMUL:
@@ -6473,6 +6477,7 @@
                       intptr_t deopt_id)
       : BinaryIntegerOpInstr(op_kind, left, right, deopt_id) {
     mark_truncating();
+    ASSERT(IsSupported(op_kind));
   }
 
   virtual bool ComputeCanDeoptimize() const { return false; }
@@ -6486,6 +6491,20 @@
 
   virtual CompileType ComputeType() const;
 
+  static bool IsSupported(Token::Kind op_kind) {
+    switch (op_kind) {
+      case Token::kADD:
+      case Token::kSUB:
+      case Token::kMUL:
+      case Token::kBIT_AND:
+      case Token::kBIT_OR:
+      case Token::kBIT_XOR:
+        return true;
+      default:
+        return false;
+    }
+  }
+
   DECLARE_INSTRUCTION(BinaryUint32Op)
 
  private:
diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc
index eaea5db..687ecd0 100644
--- a/runtime/vm/compiler/backend/il_x64.cc
+++ b/runtime/vm/compiler/backend/il_x64.cc
@@ -6017,6 +6017,7 @@
 }
 
 DEFINE_BACKEND(UnaryUint32Op, (SameAsFirstInput, Register value)) {
+  ASSERT(instr->op_kind() == Token::kBIT_NOT);
   __ notl(value);
 }
 
diff --git a/runtime/vm/compiler/backend/range_analysis.cc b/runtime/vm/compiler/backend/range_analysis.cc
index 2319532..71fd853 100644
--- a/runtime/vm/compiler/backend/range_analysis.cc
+++ b/runtime/vm/compiler/backend/range_analysis.cc
@@ -1552,9 +1552,12 @@
   // TODO(johnmccutchan): Consider Smi operations, to avoid unnecessary tagging
   // & untagged of intermediate results.
   // TODO(johnmccutchan): Consider phis.
-  return def->IsBoxInt64() || def->IsUnboxInt64() || def->IsBinaryInt64Op() ||
-         def->IsShiftInt64Op() || def->IsSpeculativeShiftInt64Op() ||
-         def->IsUnaryInt64Op();
+  return def->IsBoxInt64() || def->IsUnboxInt64() || def->IsShiftInt64Op() ||
+         def->IsSpeculativeShiftInt64Op() ||
+         (def->IsBinaryInt64Op() && BinaryUint32OpInstr::IsSupported(
+                                        def->AsBinaryInt64Op()->op_kind())) ||
+         (def->IsUnaryInt64Op() &&
+          UnaryUint32OpInstr::IsSupported(def->AsUnaryInt64Op()->op_kind()));
 }
 
 void IntegerInstructionSelector::FindPotentialUint32Definitions() {