From 46f3efb8eb4a5ef284bcd88213b4c64ffaa13a55 Mon Sep 17 00:00:00 2001 From: Aske Simon Christensen Date: Wed, 18 Jan 2023 13:37:22 +0000 Subject: [PATCH] [dart2wasm] Inlined and optimized some int and double operations. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In particular functions that will benefit from the subsequent unboxing and value propagation by Binaryen are marked for inlining. Change-Id: Id131de47b42af11f17e227003ee828eb02c5d3cf Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/279097 Reviewed-by: Ömer Ağacan Commit-Queue: Aske Simon Christensen --- pkg/dart2wasm/lib/intrinsics.dart | 9 ++++- sdk/lib/_internal/wasm/lib/double.dart | 47 ++++++++++++++++++++------ sdk/lib/_internal/wasm/lib/int.dart | 31 +++++++++++++++++ 3 files changed, 75 insertions(+), 12 deletions(-) diff --git a/pkg/dart2wasm/lib/intrinsics.dart b/pkg/dart2wasm/lib/intrinsics.dart index 1f414e21643..375db5f89ca 100644 --- a/pkg/dart2wasm/lib/intrinsics.dart +++ b/pkg/dart2wasm/lib/intrinsics.dart @@ -50,6 +50,7 @@ class Intrinsifier { '_shl': (b) => b.i64_shl(), '_shr_s': (b) => b.i64_shr_s(), '_shr_u': (b) => b.i64_shr_u(), + '_le_u': (b) => b.i64_le_u(), '_lt_u': (b) => b.i64_lt_u(), } }, @@ -63,6 +64,7 @@ class Intrinsifier { '<=': (b) => b.f64_le(), '>': (b) => b.f64_gt(), '>=': (b) => b.f64_ge(), + '_copysign': (b) => b.f64_copysign(), } }, }; @@ -117,7 +119,12 @@ class Intrinsifier { } static bool isComparison(String op) => - op == '<' || op == '<=' || op == '>' || op == '>=' || op == '_lt_u'; + op == '<' || + op == '<=' || + op == '>' || + op == '>=' || + op == '_le_u' || + op == '_lt_u'; Intrinsifier(this.codeGen); diff --git a/sdk/lib/_internal/wasm/lib/double.dart b/sdk/lib/_internal/wasm/lib/double.dart index 58c27c88c6c..b70d5bece75 100644 --- a/sdk/lib/_internal/wasm/lib/double.dart +++ b/sdk/lib/_internal/wasm/lib/double.dart @@ -52,6 +52,9 @@ class double { /// Wasm i64.trunc_sat_f64_s instruction external int _toInt(); + + /// Wasm f64.copysign instruction + external double _copysign(double other); } @pragma("wasm:entry-point") @@ -86,11 +89,16 @@ class _BoxedDouble extends double { return (bits ^ (bits >>> 32)) & 0x3FFFFFFF; } + @pragma("wasm:prefer-inline") double operator +(num other) => this + other.toDouble(); // Intrinsic + + @pragma("wasm:prefer-inline") double operator -(num other) => this - other.toDouble(); // Intrinsic - + @pragma("wasm:prefer-inline") double operator *(num other) => this * other.toDouble(); // Intrinsic * + @pragma("wasm:prefer-inline") double operator /(num other) => this / other.toDouble(); // Intrinsic / + @pragma("wasm:prefer-inline") int operator ~/(num other) { return _truncDiv(this, other.toDouble()); } @@ -99,6 +107,7 @@ class _BoxedDouble extends double { return (a / b).toInt(); } + @pragma("wasm:prefer-inline") double operator %(num other) { return _modulo(this, other.toDouble()); } @@ -116,6 +125,7 @@ class _BoxedDouble extends double { return rem; } + @pragma("wasm:prefer-inline") double remainder(num other) { return _remainder(this, other.toDouble()); } @@ -126,6 +136,7 @@ class _BoxedDouble extends double { external double operator -(); + @pragma("wasm:prefer-inline") bool operator ==(Object other) { return other is double ? this == other // Intrinsic == @@ -134,53 +145,65 @@ class _BoxedDouble extends double { : false; } + @pragma("wasm:prefer-inline") bool operator <(num other) => this < other.toDouble(); // Intrinsic < + @pragma("wasm:prefer-inline") bool operator >(num other) => this > other.toDouble(); // Intrinsic > + @pragma("wasm:prefer-inline") bool operator >=(num other) => this >= other.toDouble(); // Intrinsic >= + @pragma("wasm:prefer-inline") bool operator <=(num other) => this <= other.toDouble(); // Intrinsic <= + @pragma("wasm:prefer-inline") bool get isNegative { - if (isNaN) { - return false; - } + // Sign bit set, not NaN int bits = doubleToIntBits(this); - return (bits & _signMask) != 0; + return (bits ^ _signMask)._le_u(_exponentMask); } + @pragma("wasm:prefer-inline") bool get isInfinite { + // Exponent at max, mantissa zero int bits = doubleToIntBits(this); - return (bits & _exponentMask) == _exponentMask && - (bits & _mantissaMask) == 0; + return (bits & (_exponentMask | _mantissaMask)) == _exponentMask; } + @pragma("wasm:prefer-inline") bool get isNaN { + // Exponent at max, mantissa nonzero int bits = doubleToIntBits(this); - return (bits & _exponentMask) == _exponentMask && - (bits & _mantissaMask) != 0; + return (bits & (_exponentMask | _mantissaMask)) > _exponentMask; } + @pragma("wasm:prefer-inline") bool get isFinite { + // Exponent not at max int bits = doubleToIntBits(this); return (bits & _exponentMask) != _exponentMask; } + @pragma("wasm:prefer-inline") double abs() { - // Handle negative 0.0. - if (this == 0.0) return 0.0; - return this < 0.0 ? -this : this; + return _copysign(0.0); } + @pragma("wasm:prefer-inline") double get sign { if (this > 0.0) return 1.0; if (this < 0.0) return -1.0; return this; // +/-0.0 or NaN. } + @pragma("wasm:prefer-inline") int round() => roundToDouble().toInt(); + @pragma("wasm:prefer-inline") int floor() => floorToDouble().toInt(); + @pragma("wasm:prefer-inline") int ceil() => ceilToDouble().toInt(); + @pragma("wasm:prefer-inline") int truncate() => truncateToDouble().toInt(); + @pragma("wasm:prefer-inline") double roundToDouble() { return _roundToDouble(this); } @@ -223,6 +246,7 @@ class _BoxedDouble extends double { return this; } + @pragma("wasm:prefer-inline") int toInt() { if (!isFinite) { throw UnsupportedError("Infinity or NaN toInt"); @@ -230,6 +254,7 @@ class _BoxedDouble extends double { return _toInt(); } + @pragma("wasm:prefer-inline") double toDouble() { return this; } diff --git a/sdk/lib/_internal/wasm/lib/int.dart b/sdk/lib/_internal/wasm/lib/int.dart index 545b4f99afc..41b5185ded1 100644 --- a/sdk/lib/_internal/wasm/lib/int.dart +++ b/sdk/lib/_internal/wasm/lib/int.dart @@ -9,6 +9,9 @@ class int { /// Wasm i64.div_s instruction external int _div_s(int divisor); + /// Wasm i64.le_u instruction + external bool _le_u(int other); + /// Wasm i64.lt_u instruction external bool _lt_u(int other); @@ -38,14 +41,17 @@ class _BoxedInt extends int { external num operator -(num other); external num operator *(num other); + @pragma("wasm:prefer-inline") double operator /(num other) { return this.toDouble() / other.toDouble(); } + @pragma("wasm:prefer-inline") int operator ~/(num other) => other is int ? _truncDiv(this.value, other) : _BoxedDouble._truncDiv(toDouble(), unsafeCast(other)); + @pragma("wasm:prefer-inline") num operator %(num other) => other is int ? _modulo(this, other) : _BoxedDouble._modulo(toDouble(), unsafeCast(other)); @@ -62,6 +68,7 @@ class _BoxedInt extends int { return rem; } + @pragma("wasm:prefer-inline") static int _truncDiv(int a, int b) { // Division special case: overflow in I64. // MIN_VALUE / -1 = (MAX_VALUE + 1), which wraps around to MIN_VALUE @@ -77,6 +84,7 @@ class _BoxedInt extends int { return a._div_s(b); } + @pragma("wasm:prefer-inline") num remainder(num other) => other is int ? this - (this ~/ other) * other : _BoxedDouble._remainder(toDouble(), unsafeCast(other)); @@ -87,6 +95,7 @@ class _BoxedInt extends int { external int operator |(int other); external int operator ^(int other); + @pragma("wasm:prefer-inline") int operator >>(int shift) { // Unsigned comparison to check for large and negative shifts if (shift._lt_u(64)) { @@ -101,6 +110,7 @@ class _BoxedInt extends int { return this._shr_s(63); } + @pragma("wasm:prefer-inline") int operator >>>(int shift) { // Unsigned comparison to check for large and negative shifts if (shift._lt_u(64)) { @@ -115,6 +125,7 @@ class _BoxedInt extends int { return 0; } + @pragma("wasm:prefer-inline") int operator <<(int shift) { // Unsigned comparison to check for large and negative shifts if (shift._lt_u(64)) { @@ -134,6 +145,7 @@ class _BoxedInt extends int { external bool operator >=(num other); external bool operator <=(num other); + @pragma("wasm:prefer-inline") bool operator ==(Object other) { return other is int ? this == other // Intrinsic == @@ -142,10 +154,12 @@ class _BoxedInt extends int { : false; } + @pragma("wasm:prefer-inline") int abs() { return this < 0 ? -this : this; } + @pragma("wasm:prefer-inline") int get sign { return (this > 0) ? 1 @@ -154,17 +168,25 @@ class _BoxedInt extends int { : 0; } + @pragma("wasm:prefer-inline") bool get isEven => (this & 1) == 0; + @pragma("wasm:prefer-inline") bool get isOdd => (this & 1) != 0; + @pragma("wasm:prefer-inline") bool get isNaN => false; + @pragma("wasm:prefer-inline") bool get isNegative => this < 0; + @pragma("wasm:prefer-inline") bool get isInfinite => false; + @pragma("wasm:prefer-inline") bool get isFinite => true; + @pragma("wasm:prefer-inline") int toUnsigned(int width) { return this & ((1 << width) - 1); } + @pragma("wasm:prefer-inline") int toSigned(int width) { // The value of binary number weights each bit by a power of two. The // twos-complement value weights the sign bit negatively. We compute the @@ -214,34 +236,42 @@ class _BoxedInt extends int { } } + @pragma("wasm:prefer-inline") int round() { return this; } + @pragma("wasm:prefer-inline") int floor() { return this; } + @pragma("wasm:prefer-inline") int ceil() { return this; } + @pragma("wasm:prefer-inline") int truncate() { return this; } + @pragma("wasm:prefer-inline") double roundToDouble() { return this.toDouble(); } + @pragma("wasm:prefer-inline") double floorToDouble() { return this.toDouble(); } + @pragma("wasm:prefer-inline") double ceilToDouble() { return this.toDouble(); } + @pragma("wasm:prefer-inline") double truncateToDouble() { return this.toDouble(); } @@ -264,6 +294,7 @@ class _BoxedInt extends int { return this; } + @pragma("wasm:prefer-inline") int toInt() { return this; }