[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(),