[dart2wasm] Fix truncating int div code gen

Wasm `i64.div_s` result[1] is undefined when the division result is
2^63, and v8 traps with "divide result unrepresentable".

This change follows the checks in native runtime (in
`Integer::ArithmeticOp`) to handle overflowing in
`-9223372036854775808 ~/ -1`:

   case Token::kTRUNCDIV:
     if ((left_value == Mint::kMinValue) && (right_value == -1)) {
       return Integer::New(Mint::kMinValue, space);
     }
     return Integer::New(left_value / right_value, space);

These tests now pass:

- corelib/integer_parsed_div_rem_vm_test/01
- language/operator/left_shift_test

language/operator/arithmetic_test used to fail with the same trap, but
it now fails because of #50228.

[1]: https://webassembly.github.io/spec/core/exec/numerics.html#op-idiv-s

Change-Id: Ib43ac7a53d5cf96c01b016f73240da533ef84516
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/264460
Commit-Queue: Ömer Ağacan <omersa@google.com>
Reviewed-by: Joshua Litt <joshualitt@google.com>
diff --git a/pkg/dart2wasm/lib/intrinsics.dart b/pkg/dart2wasm/lib/intrinsics.dart
index 97efd6b..5b231aa 100644
--- a/pkg/dart2wasm/lib/intrinsics.dart
+++ b/pkg/dart2wasm/lib/intrinsics.dart
@@ -32,7 +32,35 @@
         '+': (b) => b.i64_add(),
         '-': (b) => b.i64_sub(),
         '*': (b) => b.i64_mul(),
-        '~/': (b) => b.i64_div_s(),
+        '~/': (b) {
+          final arg2Local = b.addLocal(intType, isParameter: false);
+          b.local_set(arg2Local);
+
+          final arg1Local = b.addLocal(intType, isParameter: false);
+          b.local_set(arg1Local);
+
+          // Division special case: overflow in I64.
+          // MIN_VALUE / -1 = (MAX_VALUE + 1), which wraps around to MIN_VALUE
+          b.local_get(arg2Local);
+          b.i64_const(-1);
+          b.i64_eq();
+          b.if_([], [intType]);
+          b.local_get(arg1Local);
+          b.i64_const(-9223372036854775808); // MIN_VALUE
+          b.i64_eq();
+          b.if_([], [intType]);
+          b.i64_const(-9223372036854775808); // MIN_VALUE
+          b.else_();
+          b.local_get(arg1Local);
+          b.local_get(arg2Local);
+          b.i64_div_s();
+          b.end();
+          b.else_();
+          b.local_get(arg1Local);
+          b.local_get(arg2Local);
+          b.i64_div_s();
+          b.end();
+        },
         '&': (b) => b.i64_and(),
         '|': (b) => b.i64_or(),
         '^': (b) => b.i64_xor(),