[dart2wasm] Fix int left and right shifts

New passing tests:

- co19/Language/Expressions/Numbers/syntax_t06
- co19/Language/Expressions/Shift/integer_t01
- co19/Language/Expressions/Shift/integer_t02
- co19/Language/Expressions/Shift/integer_t03
- co19/Language/Expressions/Shift/integer_t04
- co19/Language/Expressions/Shift/integer_t06
- co19/Language/Expressions/Shift/integer_t07
- co19/Language/Types/Type_Aliases/built-in_types_t09
- co19/Language/Types/Type_Aliases/built-in_types_t10
- co19/Language/Types/Type_Aliases/built-in_types_t11
- co19/LanguageFeatures/Triple-Shift/Constants_A01_t09
- co19/LibTest/core/int/operator_left_shift_A01_t03
- co19/LibTest/core/int/operator_right_shift_A01_t03
- corelib/integer_parsed_arith_vm_test
- corelib/unsigned_shift_test/07
- corelib/unsigned_shift_test/08
- corelib/unsigned_shift_test/none
- language/operator/bit_operations_test/03
- language/operator/bit_operations_test/04
- language/operator/bit_operations_test/none
- language/operator/bit_shift_test
- language/regress/regress24283_test

Change-Id: I61c1224f8490d413002ea53270773370bc2cd334
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/267921
Reviewed-by: Aske Simon Christensen <askesc@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
diff --git a/pkg/dart2wasm/lib/intrinsics.dart b/pkg/dart2wasm/lib/intrinsics.dart
index a6889ab..92bb76c 100644
--- a/pkg/dart2wasm/lib/intrinsics.dart
+++ b/pkg/dart2wasm/lib/intrinsics.dart
@@ -37,9 +37,6 @@
         '&': (b) => b.i64_and(),
         '|': (b) => b.i64_or(),
         '^': (b) => b.i64_xor(),
-        '<<': (b) => b.i64_shl(),
-        '>>': (b) => b.i64_shr_s(),
-        '>>>': (b) => b.i64_shr_u(),
         '<': (b) => b.i64_lt_s(),
         '<=': (b) => b.i64_le_s(),
         '>': (b) => b.i64_gt_s(),
@@ -734,6 +731,42 @@
           codeGen.wrap(second, w.NumType.i64);
           b.i64_div_s();
           return w.NumType.i64;
+        case "_shl":
+          assert(cls == translator.boxedIntClass);
+          assert(node.arguments.positional.length == 2);
+          Expression first = node.arguments.positional[0];
+          Expression second = node.arguments.positional[1];
+          codeGen.wrap(first, w.NumType.i64);
+          codeGen.wrap(second, w.NumType.i64);
+          b.i64_shl();
+          return w.NumType.i64;
+        case "_shr_s":
+          assert(cls == translator.boxedIntClass);
+          assert(node.arguments.positional.length == 2);
+          Expression first = node.arguments.positional[0];
+          Expression second = node.arguments.positional[1];
+          codeGen.wrap(first, w.NumType.i64);
+          codeGen.wrap(second, w.NumType.i64);
+          b.i64_shr_s();
+          return w.NumType.i64;
+        case "_shr_u":
+          assert(cls == translator.boxedIntClass);
+          assert(node.arguments.positional.length == 2);
+          Expression first = node.arguments.positional[0];
+          Expression second = node.arguments.positional[1];
+          codeGen.wrap(first, w.NumType.i64);
+          codeGen.wrap(second, w.NumType.i64);
+          b.i64_shr_u();
+          return w.NumType.i64;
+        case "_lt_u":
+          assert(cls == translator.boxedIntClass);
+          assert(node.arguments.positional.length == 2);
+          Expression first = node.arguments.positional[0];
+          Expression second = node.arguments.positional[1];
+          codeGen.wrap(first, w.NumType.i64);
+          codeGen.wrap(second, w.NumType.i64);
+          b.i64_lt_u();
+          return w.NumType.i32; // bool
         case "_toInt":
           assert(cls == translator.boxedDoubleClass);
           assert(node.arguments.positional.length == 1);
diff --git a/sdk/lib/_internal/wasm/lib/int.dart b/sdk/lib/_internal/wasm/lib/int.dart
index f7dcc06..72457ff 100644
--- a/sdk/lib/_internal/wasm/lib/int.dart
+++ b/sdk/lib/_internal/wasm/lib/int.dart
@@ -66,9 +66,59 @@
   external int operator |(int other);
   external int operator ^(int other);
 
-  external int operator >>(int other);
-  external int operator >>>(int other);
-  external int operator <<(int other);
+  int operator >>(int shift) {
+    // Unsigned comparison to check for large and negative shifts
+    if (_lt_u(shift, 64)) {
+      return _shr_s(this, shift);
+    }
+
+    if (shift < 0) {
+      throw ArgumentError(shift);
+    }
+
+    // shift >= 64, 0 or -1 depending on sign: `this >= 0 ? 0 : -1`
+    return _shr_s(this, 63);
+  }
+
+  int operator >>>(int shift) {
+    // Unsigned comparison to check for large and negative shifts
+    if (_lt_u(shift, 64)) {
+      return _shr_u(this, shift);
+    }
+
+    if (shift < 0) {
+      throw ArgumentError(shift);
+    }
+
+    // shift >= 64
+    return 0;
+  }
+
+  int operator <<(int shift) {
+    // Unsigned comparison to check for large and negative shifts
+    if (_lt_u(shift, 64)) {
+      return _shl(this, shift);
+    }
+
+    if (shift < 0) {
+      throw ArgumentError(shift);
+    }
+
+    // shift >= 64
+    return 0;
+  }
+
+  /// Wasm i64.lt_u instruction
+  external static bool _lt_u(int a, int b);
+
+  /// Wasm i64.shr_s instruction
+  external static int _shr_s(int a, int b);
+
+  /// Wasm i64.shr_u instruction
+  external static int _shr_u(int a, int b);
+
+  /// Wasm i64.shl instruction
+  external static int _shl(int a, int b);
 
   external bool operator <(num other);
   external bool operator >(num other);