mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 03:17:55 +00:00
[dart2wasm] Generate inline code for int ~/ operator
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]: https://github.com/dart-lang/sdk/issues/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>
This commit is contained in:
parent
ee79d8e4b8
commit
12e0690dfe
|
@ -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.
|
||||
///
|
||||
|
@ -29,42 +29,43 @@ 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(),
|
||||
}
|
||||
},
|
||||
};
|
||||
|
@ -72,33 +73,33 @@ class Intrinsifier {
|
|||
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();
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 =
|
||||
|
|
Loading…
Reference in a new issue