Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(85)

Unified Diff: pkg/compiler/lib/src/cps_ir/type_propagation.dart

Issue 1393763004: dart2js cps_ir: BuiltinOperation improvements. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/compiler/lib/src/cps_ir/type_propagation.dart
diff --git a/pkg/compiler/lib/src/cps_ir/type_propagation.dart b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
index 0a2b4cef8060d3aa61435b707c5d6d69397d3fc1..fa48c8436cf40d289e944a71142155bc5d0e31e4 100644
--- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart
+++ b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
@@ -121,6 +121,24 @@ class ConstantPropagationLattice {
typeSystem.isDefinitelyInt(value.type, allowNull: allowNull);
}
+ bool isDefinitelyUint31(AbstractValue value,
+ {bool allowNull: false}) {
+ return value.isNothing ||
+ typeSystem.isDefinitelyUint31(value.type, allowNull: allowNull);
+ }
+
+ bool isDefinitelyUint32(AbstractValue value,
+ {bool allowNull: false}) {
+ return value.isNothing ||
+ typeSystem.isDefinitelyUint32(value.type, allowNull: allowNull);
+ }
+
+ bool isDefinitelyUint(AbstractValue value,
+ {bool allowNull: false}) {
+ return value.isNothing ||
+ typeSystem.isDefinitelyUint(value.type, allowNull: allowNull);
+ }
+
bool isDefinitelyNativeList(AbstractValue value,
{bool allowNull: false}) {
return value.isNothing ||
@@ -153,6 +171,19 @@ class ConstantPropagationLattice {
typeSystem.isDefinitelyIndexable(value.type, allowNull: allowNull);
}
+ /// Returns `true` if [value] represents an int value that must be in the
+ /// inclusive range.
+ bool isDefinitelyIntInRange(AbstractValue value, {int min, int max}) {
+ if (value.isNothing) return true;
+ if (!isDefinitelyInt(value)) return false;
+ PrimitiveConstantValue constant = value.constant;
+ if (constant == null) return false;
+ if (!constant.isInt) return false;
+ if (min != null && constant.primitiveValue < min) return false;
+ if (max != null && constant.primitiveValue > max) return false;
+ return true;
+ }
+
/// Returns whether the given [value] is an instance of [type].
///
/// Since [value] and [type] are not always known, [AbstractBool.Maybe] is
@@ -236,40 +267,229 @@ class ConstantPropagationLattice {
AbstractValue binaryOp(BinaryOperator operator,
AbstractValue left,
AbstractValue right) {
+ switch (operator.kind) {
+ case BinaryOperatorKind.ADD:
+ return addSpecial(left, right);
+
+ case BinaryOperatorKind.SUB:
+ return subtractSpecial(left, right);
+
+ case BinaryOperatorKind.MUL:
+ return multiplySpecial(left, right);
+
+ case BinaryOperatorKind.DIV:
+ return divideSpecial(left, right);
+
+ case BinaryOperatorKind.IDIV:
+ return truncatingDivideSpecial(left, right);
+
+ case BinaryOperatorKind.MOD:
+ return moduloSpecial(left, right);
+
+ case BinaryOperatorKind.EQ:
+ return equalSpecial(left, right);
+
+ case BinaryOperatorKind.AND:
+ return andSpecial(left, right);
+
+ case BinaryOperatorKind.OR:
+ return orSpecial(left, right);
+
+ case BinaryOperatorKind.XOR:
+ return xorSpecial(left, right);
+
+ case BinaryOperatorKind.SHL:
+ return shiftLeftSpecial(left, right);
+
+ case BinaryOperatorKind.SHR:
+ return shiftRightSpecial(left, right);
+
+ case BinaryOperatorKind.LT:
+ return lessSpecial(left, right);
+
+ case BinaryOperatorKind.LTEQ:
+ return lessEqualSpecial(left, right);
+
+ case BinaryOperatorKind.GT:
+ return greaterSpecial(left, right);
+
+ case BinaryOperatorKind.GTEQ:
+ return greaterEqualSpecial(left, right);
+
+ default:
+ break;
+ }
+
if (left.isNothing || right.isNothing) {
return nothing;
}
if (left.isConstant && right.isConstant) {
BinaryOperation operation = constantSystem.lookupBinary(operator);
ConstantValue result = operation.fold(left.constant, right.constant);
- if (result == null) return anything;
- return constant(result);
+ if (result != null) return constant(result);
}
- // TODO(asgerf): Handle remaining operators and the UIntXX types.
- switch (operator.kind) {
- case BinaryOperatorKind.ADD:
- case BinaryOperatorKind.SUB:
- case BinaryOperatorKind.MUL:
- if (isDefinitelyInt(left) && isDefinitelyInt(right)) {
- return nonConstant(typeSystem.intType);
- }
- return null;
+ return null; // The caller will use return type from type inference.
+ }
- case BinaryOperatorKind.EQ:
- bool behavesLikeIdentity =
- isDefinitelyNumStringBool(left, allowNull: true) ||
- right.isNullConstant;
- if (behavesLikeIdentity &&
- typeSystem.areDisjoint(left.type, right.type)) {
- return constant(new FalseConstantValue());
- }
- return null;
+ AbstractValue foldBinary(BinaryOperation operation,
+ AbstractValue left, AbstractValue right) {
+ if (left.isNothing || right.isNothing) return nothing;
+ if (left.isConstant && right.isConstant) {
+ ConstantValue result = operation.fold(left.constant, right.constant);
+ if (result != null) return constant(result);
+ }
+ return null;
+ }
- default:
- return null; // The caller will use return type from type inference.
+ AbstractValue closedOnInt(AbstractValue left, AbstractValue right) {
+ if (isDefinitelyInt(left) && isDefinitelyInt(right)) {
+ return nonConstant(typeSystem.intType);
+ }
+ return null;
+ }
+
+ AbstractValue closedOnUint(AbstractValue left, AbstractValue right) {
+ if (isDefinitelyUint(left) && isDefinitelyUint(right)) {
+ return nonConstant(typeSystem.uintType);
+ }
+ return null;
+ }
+
+ AbstractValue closedOnUint31(AbstractValue left, AbstractValue right) {
+ if (isDefinitelyUint31(left) && isDefinitelyUint31(right)) {
+ return nonConstant(typeSystem.uint31Type);
}
+ return null;
}
+ AbstractValue addSpecial(AbstractValue left, AbstractValue right) {
+ AbstractValue folded = foldBinary(constantSystem.add, left, right);
+ if (folded != null) return folded;
+ if (isDefinitelyNum(left)) {
+ if (isDefinitelyUint31(left) && isDefinitelyUint31(right)) {
+ return nonConstant(typeSystem.uint32Type);
+ }
+ return closedOnUint(left, right) ?? closedOnInt(left, right);
+ }
+ return null;
+ }
+
+ AbstractValue subtractSpecial(AbstractValue left, AbstractValue right) {
+ AbstractValue folded = foldBinary(constantSystem.subtract, left, right);
+ return folded ?? closedOnInt(left, right);
+ }
+
+ AbstractValue multiplySpecial(AbstractValue left, AbstractValue right) {
+ AbstractValue folded = foldBinary(constantSystem.multiply, left, right);
+ return folded ?? closedOnUint(left, right) ?? closedOnInt(left, right);
+ }
+
+ AbstractValue divideSpecial(AbstractValue left, AbstractValue right) {
+ return foldBinary(constantSystem.divide, left, right);
+ }
+
+ AbstractValue truncatingDivideSpecial(
+ AbstractValue left, AbstractValue right) {
+ AbstractValue folded =
+ foldBinary(constantSystem.truncatingDivide, left, right);
+ if (folded != null) return folded;
+ if (isDefinitelyNum(left)) {
+ if (isDefinitelyUint32(left) && isDefinitelyIntInRange(right, min: 2)) {
+ return nonConstant(typeSystem.uint31Type);
+ }
+ if (isDefinitelyUint(right)) {
+ // `0` will be an exception, other values will shrink the result.
+ if (isDefinitelyUint31(left)) return nonConstant(typeSystem.uint31Type);
+ if (isDefinitelyUint32(left)) return nonConstant(typeSystem.uint32Type);
+ if (isDefinitelyUint(left)) return nonConstant(typeSystem.uintType);
+ }
+ return nonConstant(typeSystem.intType);
+ }
+ return null;
+ }
+
+ AbstractValue moduloSpecial(AbstractValue left, AbstractValue right) {
+ AbstractValue folded = foldBinary(constantSystem.modulo, left, right);
+ return folded ?? closedOnUint(left, right) ?? closedOnInt(left, right);
+ }
+
+ AbstractValue remainderSpecial(AbstractValue left, AbstractValue right) {
+ if (left.isNothing || right.isNothing) return nothing;
+ AbstractValue folded = null; // Remainder not in constant system.
+ return folded ?? closedOnUint(left, right) ?? closedOnInt(left, right);
+ }
+
+ AbstractValue equalSpecial(AbstractValue left, AbstractValue right) {
+ AbstractValue folded = foldBinary(constantSystem.equal, left, right);
+ if (folded != null) return folded;
+ bool behavesLikeIdentity =
+ isDefinitelyNumStringBool(left, allowNull: true) ||
+ right.isNullConstant;
+ if (behavesLikeIdentity &&
+ typeSystem.areDisjoint(left.type, right.type)) {
+ return constant(new FalseConstantValue());
+ }
+ return null;
+ }
+
+ AbstractValue andSpecial(AbstractValue left, AbstractValue right) {
+ AbstractValue folded = foldBinary(constantSystem.bitAnd, left, right);
+ if (folded != null) return folded;
+ if (isDefinitelyNum(left)) {
+ if (isDefinitelyUint31(left) || isDefinitelyUint31(right)) {
+ // Either 31-bit argument will truncate the other.
+ return nonConstant(typeSystem.uint31Type);
+ }
+ }
+ return null;
+ }
+
+ AbstractValue orSpecial(AbstractValue left, AbstractValue right) {
+ AbstractValue folded = foldBinary(constantSystem.bitOr, left, right);
+ return folded ?? closedOnUint31(left, right);
+ }
+
+ AbstractValue xorSpecial(AbstractValue left, AbstractValue right) {
+ AbstractValue folded = foldBinary(constantSystem.bitXor, left, right);
+ return folded ?? closedOnUint31(left, right);
+ }
+
+ AbstractValue shiftLeftSpecial(AbstractValue left, AbstractValue right) {
+ return foldBinary(constantSystem.shiftLeft, left, right);
+ }
+
+ AbstractValue shiftRightSpecial(AbstractValue left, AbstractValue right) {
+ AbstractValue folded = foldBinary(constantSystem.shiftRight, left, right);
+ if (folded != null) return folded;
+ if (isDefinitelyUint31(left)) {
+ return nonConstant(typeSystem.uint31Type);
+ } else if (isDefinitelyUint32(left)) {
+ if (isDefinitelyIntInRange(right, min: 1, max: 31)) {
+ // A zero will be shifted into the 'sign' bit.
+ return nonConstant(typeSystem.uint31Type);
+ }
+ return nonConstant(typeSystem.uint32Type);
+ }
+ return null;
+ }
+
+ AbstractValue lessSpecial(AbstractValue left, AbstractValue right) {
+ return foldBinary(constantSystem.less, left, right);
+ }
+
+ AbstractValue lessEqualSpecial(AbstractValue left, AbstractValue right) {
+ return foldBinary(constantSystem.lessEqual, left, right);
+ }
+
+ AbstractValue greaterSpecial(AbstractValue left, AbstractValue right) {
+ return foldBinary(constantSystem.greater, left, right);
+ }
+
+ AbstractValue greaterEqualSpecial(AbstractValue left, AbstractValue right) {
+ return foldBinary(constantSystem.greaterEqual, left, right);
+ }
+
+
AbstractValue stringConstant(String value) {
return constant(new StringConstantValue(new ast.DartString.literal(value)));
}
@@ -395,6 +615,7 @@ final Map<String, BuiltinOperator> NumBinaryBuiltins =
'+': BuiltinOperator.NumAdd,
'-': BuiltinOperator.NumSubtract,
'*': BuiltinOperator.NumMultiply,
+ '/': BuiltinOperator.NumDivide,
'&': BuiltinOperator.NumAnd,
'|': BuiltinOperator.NumOr,
'^': BuiltinOperator.NumXor,
@@ -769,21 +990,39 @@ class TransformingVisitor extends LeafVisitor {
if (operator != null) {
return replaceWithBinary(operator, leftArg, rightArg);
}
- // Try to insert a shift-left operator.
// Shift operators are not in [NumBinaryBuiltins] because Dart shifts
- // behave different than JS shifts.
- // We do not introduce shift-right operators yet because the operator
- // to use depends on whether the left-hand operand is negative.
- // See js_number.dart in js_runtime for details.
- PrimitiveConstantValue rightConstant = right.constant;
+ // behave different to JS shifts, especially in the handling of the
+ // shift count.
+ // Try to insert a shift-left operator.
if (opname == '<<' &&
lattice.isDefinitelyInt(left) &&
- rightConstant != null &&
- rightConstant.isInt &&
- rightConstant.primitiveValue >= 0 &&
- rightConstant.primitiveValue <= 31) {
- return replaceWithBinary(BuiltinOperator.NumShl,
- leftArg, rightArg);
+ lattice.isDefinitelyIntInRange(right, min: 0, max: 31)) {
+ return replaceWithBinary(BuiltinOperator.NumShl, leftArg, rightArg);
+ }
+ // Try to insert a shift-right operator. JavaScript's right shift is
+ // consistent with Dart's only for left operands in the unsigned
+ // 32-bit range.
+ if (opname == '>>' &&
+ lattice.isDefinitelyUint32(left) &&
+ lattice.isDefinitelyIntInRange(right, min: 0, max: 31)) {
+ return replaceWithBinary(BuiltinOperator.NumShr, leftArg, rightArg);
+ }
+ // Try to use remainder for '%'. Both operands must be non-negative
+ // and the divisor must be non-zero.
+ if (opname == '%' &&
+ lattice.isDefinitelyUint(left) &&
+ lattice.isDefinitelyUint(right) &&
+ lattice.isDefinitelyIntInRange(right, min: 1)) {
+ return replaceWithBinary(
+ BuiltinOperator.NumRemainder, leftArg, rightArg);
+ }
+
+ if (opname == '~/' &&
+ lattice.isDefinitelyUint32(left) &&
+ lattice.isDefinitelyIntInRange(right, min: 2)) {
+ return replaceWithBinary(
+ BuiltinOperator.NumTruncatingDivideToSigned32,
+ leftArg, rightArg);
}
}
if (lattice.isDefinitelyString(left, allowNull: false) &&
@@ -794,11 +1033,34 @@ class TransformingVisitor extends LeafVisitor {
}
}
}
+ if (node.selector.isCall) {
+ String name = node.selector.name;
+ Primitive receiver = getDartReceiver(node);
+ AbstractValue receiverValue = getValue(receiver);
+ if (name == 'remainder') {
+ if (node.arguments.length == 2) {
+ Primitive arg = getDartArgument(node, 0);
+ AbstractValue argValue = getValue(arg);
+ if (lattice.isDefinitelyInt(receiverValue) &&
+ lattice.isDefinitelyInt(argValue) &&
+ isIntNotZero(argValue)) {
+ return
+ replaceWithBinary(BuiltinOperator.NumRemainder, receiver, arg);
+ }
+ }
+ }
+ }
// We should only get here if the node was not specialized.
assert(node.parent != null);
return false;
}
+ /// Returns `true` if [value] represents an int value that cannot be zero.
+ bool isIntNotZero(AbstractValue value) {
+ return lattice.isDefinitelyIntInRange(value, min: 1) ||
+ lattice.isDefinitelyIntInRange(value, max: -1);
+ }
+
bool isInterceptedSelector(Selector selector) {
return backend.isInterceptedSelector(selector);
}
@@ -2223,6 +2485,30 @@ class TypePropagationVisitor implements Visitor {
}
void visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
+
+ void binaryOp(
+ AbstractValue operation(AbstractValue left, AbstractValue right),
+ TypeMask defaultType) {
+ AbstractValue left = getValue(node.arguments[0].definition);
+ AbstractValue right = getValue(node.arguments[1].definition);
+ setValue(node, operation(left, right) ?? nonConstant(defaultType));
+ }
+
+ void binaryNumOp(
+ AbstractValue operation(AbstractValue left, AbstractValue right)) {
+ binaryOp(operation, typeSystem.numType);
+ }
+
+ void binaryUint32Op(
+ AbstractValue operation(AbstractValue left, AbstractValue right)) {
+ binaryOp(operation, typeSystem.uint32Type);
+ }
+
+ void binaryBoolOp(
+ AbstractValue operation(AbstractValue left, AbstractValue right)) {
+ binaryOp(operation, typeSystem.boolType);
+ }
+
switch (node.operator) {
case BuiltinOperator.StringConcatenate:
ast.DartString stringValue = const ast.LiteralDartString('');
@@ -2272,6 +2558,7 @@ class TypePropagationVisitor implements Visitor {
assert(leftConst.isConstant && rightConst.isConstant);
PrimitiveConstantValue left = leftValue;
PrimitiveConstantValue right = rightValue;
+ // Should this be constantSystem.identity.fold(left, right)?
ConstantValue result =
new BoolConstantValue(left.primitiveValue == right.primitiveValue);
setValue(node, constantValue(result, typeSystem.boolType));
@@ -2280,27 +2567,66 @@ class TypePropagationVisitor implements Visitor {
}
break;
- // TODO(asgerf): Implement constant propagation for builtins.
case BuiltinOperator.NumAdd:
+ binaryNumOp(lattice.addSpecial);
+ break;
+
case BuiltinOperator.NumSubtract:
+ binaryNumOp(lattice.subtractSpecial);
+ break;
+
case BuiltinOperator.NumMultiply:
+ binaryNumOp(lattice.multiplySpecial);
+ break;
+
+ case BuiltinOperator.NumDivide:
+ binaryNumOp(lattice.divideSpecial);
+ break;
+
+ case BuiltinOperator.NumRemainder:
+ binaryNumOp(lattice.remainderSpecial);
+ break;
+
+ case BuiltinOperator.NumTruncatingDivideToSigned32:
+ binaryNumOp(lattice.truncatingDivideSpecial);
+ break;
+
case BuiltinOperator.NumAnd:
+ binaryUint32Op(lattice.andSpecial);
+ break;
+
case BuiltinOperator.NumOr:
+ binaryUint32Op(lattice.orSpecial);
+ break;
+
case BuiltinOperator.NumXor:
+ binaryUint32Op(lattice.xorSpecial);
+ break;
+
case BuiltinOperator.NumShl:
- AbstractValue left = getValue(node.arguments[0].definition);
- AbstractValue right = getValue(node.arguments[1].definition);
- if (lattice.isDefinitelyInt(left) && lattice.isDefinitelyInt(right)) {
- setValue(node, nonConstant(typeSystem.intType));
- } else {
- setValue(node, nonConstant(typeSystem.numType));
- }
+ binaryUint32Op(lattice.shiftLeftSpecial);
+ break;
+
+ case BuiltinOperator.NumShr:
+ binaryUint32Op(lattice.shiftRightSpecial);
break;
case BuiltinOperator.NumLt:
+ binaryBoolOp(lattice.lessSpecial);
+ break;
+
case BuiltinOperator.NumLe:
+ binaryBoolOp(lattice.lessEqualSpecial);
+ break;
+
case BuiltinOperator.NumGt:
+ binaryBoolOp(lattice.greaterSpecial);
+ break;
+
case BuiltinOperator.NumGe:
+ binaryBoolOp(lattice.greaterEqualSpecial);
+ break;
+
case BuiltinOperator.StrictNeq:
case BuiltinOperator.LooseNeq:
case BuiltinOperator.IsFalsy:
@@ -2375,7 +2701,7 @@ class TypePropagationVisitor implements Visitor {
void visitTypeTestViaFlag(TypeTestViaFlag node) {
// TODO(sra): We could see if we can find the value in the interceptor
- // expression. It would p[robably have no benefit - we only see
+ // expression. It would probably have no benefit - we only see
// TypeTestViaFlag after rewriting TypeTest and the rewrite of TypeTest
// would already have done the interesting optimizations.
setValue(node, nonConstant(typeSystem.boolType));
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/type_mask_system.dart ('k') | pkg/compiler/lib/src/js_backend/codegen/codegen.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698