[vm/compiler] Fix generation of Smi immediates when using compressed pointers

When compiler generates 32-bit instructions with immediate operand
(such as add/sub etc) it expects to find 32-bit immediate value.
In compressed pointers mode Smi occupies 32 bits with unspecified
upper bits. So getting a raw value of a Smi using

  static_cast<int64_t>(constant.ptr())

is not correct. For example it may yield 0xfffffffe instead of
0xfffffffffffffffe for -1 value.

This change fixes a few places in code generator to use Smi::RawValue
instead of doing a static_cast.

TEST=runtime/tests/vm/dart/regress_47704_test.dart
Fixes https://github.com/dart-lang/sdk/issues/47704

Change-Id: I1f649c5a22f221c7f4e69a884c88c265973be606
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/220660
Auto-Submit: Alexander Markov <alexmarkov@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
diff --git a/runtime/tests/vm/dart/regress_47704_test.dart b/runtime/tests/vm/dart/regress_47704_test.dart
new file mode 100644
index 0000000..fca9648
--- /dev/null
+++ b/runtime/tests/vm/dart/regress_47704_test.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for https://github.com/dart-lang/sdk/issues/47704.
+// Verifies that compiler doesn't crash with compressed pointers when
+// generating code involving as 32-bit Smi constant which is not
+// sign-extended to 64 bits.
+
+// VMOptions=--deterministic --optimization_counter_threshold=80
+
+import 'dart:typed_data';
+import "package:expect/expect.dart";
+
+const int minLevel = -1;
+
+void foo() {
+  // Make sure this method is compiled.
+  for (int i = 0; i < 100; i++) {}
+
+  bool ok = false;
+  try {
+    for (int loc0 in ((Uint16List(40)).sublist(minLevel, 42))) {
+      print(loc0);
+    }
+  } catch (e) {
+    ok = true;
+  }
+  Expect.isTrue(ok);
+}
+
+void main() {
+  foo();
+  foo();
+}
diff --git a/runtime/tests/vm/dart_2/regress_47704_test.dart b/runtime/tests/vm/dart_2/regress_47704_test.dart
new file mode 100644
index 0000000..a0c2335
--- /dev/null
+++ b/runtime/tests/vm/dart_2/regress_47704_test.dart
@@ -0,0 +1,37 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for https://github.com/dart-lang/sdk/issues/47704.
+// Verifies that compiler doesn't crash with compressed pointers when
+// generating code involving as 32-bit Smi constant which is not
+// sign-extended to 64 bits.
+
+// VMOptions=--deterministic --optimization_counter_threshold=80
+
+// @dart = 2.9
+
+import 'dart:typed_data';
+import "package:expect/expect.dart";
+
+const int minLevel = -1;
+
+void foo() {
+  // Make sure this method is compiled.
+  for (int i = 0; i < 100; i++) {}
+
+  bool ok = false;
+  try {
+    for (int loc0 in ((Uint16List(40)).sublist(minLevel, 42))) {
+      print(loc0);
+    }
+  } catch (e) {
+    ok = true;
+  }
+  Expect.isTrue(ok);
+}
+
+void main() {
+  foo();
+  foo();
+}
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index 85e22b5..ab73a58 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -1071,7 +1071,7 @@
   Location right = locs()->in(1);
   if (right.IsConstant()) {
     ASSERT(right.constant().IsSmi());
-    const int64_t imm = static_cast<int64_t>(right.constant().ptr());
+    const int64_t imm = Smi::RawValue(Smi::Cast(right.constant()).Value());
     __ TestImmediate(left, imm, compiler::kObjectBytes);
   } else {
     __ tst(left, compiler::Operand(right.reg()), compiler::kObjectBytes);
@@ -3438,7 +3438,7 @@
   if (locs()->in(1).IsConstant()) {
     const Object& constant = locs()->in(1).constant();
     ASSERT(constant.IsSmi());
-    const int64_t imm = static_cast<int64_t>(constant.ptr());
+    const int64_t imm = Smi::RawValue(Smi::Cast(constant).Value());
     switch (op_kind()) {
       case Token::kADD: {
         if (deopt == NULL) {
diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc
index 4ca35a6..2d0a285 100644
--- a/runtime/vm/compiler/backend/il_x64.cc
+++ b/runtime/vm/compiler/backend/il_x64.cc
@@ -1037,7 +1037,7 @@
   Location right = locs()->in(1);
   if (right.IsConstant()) {
     ASSERT(right.constant().IsSmi());
-    const int64_t imm = static_cast<int64_t>(right.constant().ptr());
+    const int64_t imm = Smi::RawValue(Smi::Cast(right.constant()).Value());
     __ TestImmediate(left_reg, compiler::Immediate(imm),
                      compiler::kObjectBytes);
   } else {
@@ -3487,7 +3487,8 @@
 
 static bool CanBeImmediate(const Object& constant) {
   return constant.IsSmi() &&
-         compiler::Immediate(static_cast<int64_t>(constant.ptr())).is_int32();
+         compiler::Immediate(Smi::RawValue(Smi::Cast(constant).Value()))
+             .is_int32();
 }
 
 static bool IsSmiValue(const Object& constant, intptr_t value) {
@@ -3620,7 +3621,7 @@
   if (locs()->in(1).IsConstant()) {
     const Object& constant = locs()->in(1).constant();
     ASSERT(constant.IsSmi());
-    const int64_t imm = static_cast<int64_t>(constant.ptr());
+    const int64_t imm = Smi::RawValue(Smi::Cast(constant).Value());
     switch (op_kind()) {
       case Token::kADD: {
         __ AddImmediate(left, compiler::Immediate(imm), compiler::kObjectBytes);