Skip to content

Commit

Permalink
[dart2wasm] Generate inline code for int ~/ operator
Browse files Browse the repository at this point in the history
The implementation of `~/` is a bit more complicated than other
operators as it needs to handle some special cases, so we currently
don't generate inline code for it.

This causes generating indirect calls to `~/` in some cases even when
the static Dart type of the arguments are `int`s, see [1] for details.

Update the intrinsic matcher to specially handle this operator by
calling `_BoxedInt._truncDiv`, which is then inlined.

This leads to huge performance wins in [2] as typed data `length`
getters currently compiled to indirect calls to `~/`.

[1]: #53921
[2]: https://dart-review.googlesource.com/c/sdk/+/328920

Change-Id: I92d89db76af38b1f843e25a841074f00ff2ef30a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/333381
Reviewed-by: Aske Simon Christensen <askesc@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
  • Loading branch information
osa1 authored and Commit Queue committed Nov 2, 2023
1 parent ee79d8e commit 12e0690
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 54 deletions.
109 changes: 55 additions & 54 deletions pkg/dart2wasm/lib/intrinsics.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import 'package:kernel/ast.dart';
import 'package:wasm_builder/wasm_builder.dart' as w;
import 'abi.dart' show kWasmAbiEnumIndex;

typedef CodeGenCallback = void Function(w.InstructionsBuilder);
typedef CodeGenCallback = void Function(CodeGenerator);

/// Specialized code generation for external members.
///
Expand All @@ -29,76 +29,77 @@ class Intrinsifier {
_binaryOperatorMap = {
boolType: {
boolType: {
'|': (b) => b.i32_or(),
'^': (b) => b.i32_xor(),
'&': (b) => b.i32_and(),
'|': (c) => c.b.i32_or(),
'^': (c) => c.b.i32_xor(),
'&': (c) => c.b.i32_and(),
}
},
intType: {
intType: {
'+': (b) => b.i64_add(),
'-': (b) => b.i64_sub(),
'*': (b) => b.i64_mul(),
'&': (b) => b.i64_and(),
'|': (b) => b.i64_or(),
'^': (b) => b.i64_xor(),
'<': (b) => b.i64_lt_s(),
'<=': (b) => b.i64_le_s(),
'>': (b) => b.i64_gt_s(),
'>=': (b) => b.i64_ge_s(),
'_div_s': (b) => b.i64_div_s(),
'_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(),
'+': (c) => c.b.i64_add(),
'-': (c) => c.b.i64_sub(),
'*': (c) => c.b.i64_mul(),
'&': (c) => c.b.i64_and(),
'|': (c) => c.b.i64_or(),
'^': (c) => c.b.i64_xor(),
'<': (c) => c.b.i64_lt_s(),
'<=': (c) => c.b.i64_le_s(),
'>': (c) => c.b.i64_gt_s(),
'>=': (c) => c.b.i64_ge_s(),
'_div_s': (c) => c.b.i64_div_s(),
'_shl': (c) => c.b.i64_shl(),
'_shr_s': (c) => c.b.i64_shr_s(),
'_shr_u': (c) => c.b.i64_shr_u(),
'_le_u': (c) => c.b.i64_le_u(),
'_lt_u': (c) => c.b.i64_lt_u(),
'~/': (c) => c.call(c.translator.truncDiv.reference),
}
},
doubleType: {
doubleType: {
'+': (b) => b.f64_add(),
'-': (b) => b.f64_sub(),
'*': (b) => b.f64_mul(),
'/': (b) => b.f64_div(),
'<': (b) => b.f64_lt(),
'<=': (b) => b.f64_le(),
'>': (b) => b.f64_gt(),
'>=': (b) => b.f64_ge(),
'_copysign': (b) => b.f64_copysign(),
'+': (c) => c.b.f64_add(),
'-': (c) => c.b.f64_sub(),
'*': (c) => c.b.f64_mul(),
'/': (c) => c.b.f64_div(),
'<': (c) => c.b.f64_lt(),
'<=': (c) => c.b.f64_le(),
'>': (c) => c.b.f64_gt(),
'>=': (c) => c.b.f64_ge(),
'_copysign': (c) => c.b.f64_copysign(),
}
},
};

static final Map<w.ValueType, Map<String, CodeGenCallback>>
_unaryOperatorMap = {
intType: {
'unary-': (b) {
b.i64_const(-1);
b.i64_mul();
'unary-': (c) {
c.b.i64_const(-1);
c.b.i64_mul();
},
'~': (b) {
b.i64_const(-1);
b.i64_xor();
'~': (c) {
c.b.i64_const(-1);
c.b.i64_xor();
},
'toDouble': (b) {
b.f64_convert_i64_s();
'toDouble': (c) {
c.b.f64_convert_i64_s();
},
},
doubleType: {
'unary-': (b) {
b.f64_neg();
'unary-': (c) {
c.b.f64_neg();
},
'floorToDouble': (b) {
b.f64_floor();
'floorToDouble': (c) {
c.b.f64_floor();
},
'ceilToDouble': (b) {
b.f64_ceil();
'ceilToDouble': (c) {
c.b.f64_ceil();
},
'truncateToDouble': (b) {
b.f64_trunc();
'truncateToDouble': (c) {
c.b.f64_trunc();
},
'_toInt': (b) {
b.i64_trunc_sat_f64_s();
'_toInt': (c) {
c.b.i64_trunc_sat_f64_s();
},
},
};
Expand Down Expand Up @@ -443,7 +444,7 @@ class Intrinsifier {
w.ValueType outType = isComparison(name) ? w.NumType.i32 : leftType;
codeGen.wrap(left, leftType);
codeGen.wrap(right, rightType);
code(b);
code(codeGen);
return outType;
}
} else if (node.arguments.positional.isEmpty) {
Expand All @@ -453,7 +454,7 @@ class Intrinsifier {
var code = _unaryOperatorMap[opType]?[name];
if (code != null) {
codeGen.wrap(operand, opType);
code(b);
code(codeGen);
return _unaryResultMap[name] ?? opType;
}
}
Expand Down Expand Up @@ -1318,7 +1319,7 @@ class Intrinsifier {
w.ValueType outputType = function.type.outputs.single;
b.local_get(function.locals[0]);
translator.convertType(function, inputType, intType);
code(b);
code(codeGen);
translator.convertType(function, resultType, outputType);
return true;
}
Expand All @@ -1333,7 +1334,7 @@ class Intrinsifier {
b.local_get(function.locals[0]);
translator.convertType(function, leftType, intType);
b.local_get(function.locals[1]);
code(b);
code(codeGen);
if (!isComparison(op)) {
translator.convertType(function, intType, outputType);
}
Expand All @@ -1355,7 +1356,7 @@ class Intrinsifier {
// Inline double op
CodeGenCallback doubleCode =
_binaryOperatorMap[doubleType]![doubleType]![op]!;
doubleCode(b);
doubleCode(codeGen);
if (!isComparison(op)) {
translator.convertType(function, doubleType, outputType);
}
Expand All @@ -1368,7 +1369,7 @@ class Intrinsifier {
b.local_get(function.locals[0]);
translator.convertType(function, leftType, intType);
b.local_get(rightTemp);
code(b);
code(codeGen);
if (!isComparison(op)) {
translator.convertType(function, intType, outputType);
}
Expand All @@ -1389,7 +1390,7 @@ class Intrinsifier {
w.ValueType outputType = function.type.outputs.single;
b.local_get(function.locals[0]);
translator.convertType(function, inputType, doubleType);
code(b);
code(codeGen);
translator.convertType(function, resultType, outputType);
return true;
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/dart2wasm/lib/kernel_nodes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ mixin KernelNodes {
index.getProcedure("dart:_string", "StringBase", "==");
late final Procedure stringInterpolate =
index.getProcedure("dart:_string", "StringBase", "_interpolate");
late final Procedure truncDiv =
index.getProcedure("dart:core", "_BoxedInt", "_truncDiv");

// dart:core invocation/exception procedures
late final Procedure invocationGetterFactory =
Expand Down

0 comments on commit 12e0690

Please sign in to comment.