Chromium Code Reviews| Index: pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart |
| diff --git a/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart b/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart |
| index 63e3a26aa3761b6d11e5d16c480fd1921960b65d..c3bc80425d52b86de3d0e1e86b651440b21743cb 100644 |
| --- a/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart |
| +++ b/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart |
| @@ -74,6 +74,7 @@ class InvokeDynamicSpecializer { |
| if (name == 'round') return const RoundSpecializer(); |
| } else if (argumentCount == 1) { |
| if (name == 'codeUnitAt') return const CodeUnitAtSpecializer(); |
| + if (name == 'remainder') return const RemainderSpecializer(); |
| } |
| } |
| } |
| @@ -306,11 +307,89 @@ class ModuloSpecializer extends BinaryArithmeticSpecializer { |
| HInstruction newBuiltinVariant( |
| HInvokeDynamic instruction, Compiler compiler) { |
| // Modulo cannot be mapped to the native operator (different semantics). |
| - // TODO(sra): For non-negative values we can use JavaScript's %. |
| + |
| + // We can use HRemainder if both inputs are non-negative and the receiver |
| + // cannot be -0.0. Note that -0.0 is considered to be an int, so until we |
| + // track -0.0 precisely, we have to syntatically filter inputs that cannot |
| + // generate -0.0. |
| + bool canBePositiveZero(HInstruction input) { |
| + if (input is HConstant) { |
| + ConstantValue value = input.constant; |
| + if (value is DoubleConstantValue && value.isZero) return true; |
| + if (value is IntConstantValue && value.isZero) return true; |
| + return false; |
| + } |
| + return true; |
| + } |
| + bool inPhi = false; |
| + bool canBeNegativeZero(HInstruction input) { |
| + if (input is HConstant) { |
| + ConstantValue value = input.constant; |
| + if (value is DoubleConstantValue && value.isMinusZero) return true; |
| + return false; |
| + } |
| + if (input is HAdd) { |
| + // '+' is can only generate -0.0 when both inputs are -0.0. |
|
Siggi Cherem (dart-lang)
2016/12/08 14:54:29
is can => can
sra1
2016/12/08 20:43:44
Done.
|
| + return canBeNegativeZero(input.left) && canBeNegativeZero(input.right); |
| + } |
| + if (input is HSubtract) { |
| + return canBeNegativeZero(input.left) && canBePositiveZero(input.right); |
| + } |
| + if (input is HPhi) { |
| + if (inPhi) return true; |
| + inPhi = true; |
| + bool result = input.inputs.any(canBeNegativeZero); |
| + inPhi = false; |
| + return result; |
| + } |
| + return true; |
| + } |
| + |
| + if (inputsArePositiveIntegers(instruction, compiler) && |
| + !canBeNegativeZero(instruction.getDartReceiver(compiler))) { |
| + return new HRemainder( |
| + instruction.inputs[1], |
| + instruction.inputs[2], |
| + instruction.selector, |
| + computeTypeFromInputTypes(instruction, compiler)); |
| + } |
| + // TODO(sra): |
| + // a % N --> a & (N-1), N=2^k, where a>=0, does not have -0.0 problem. |
| + |
| + // TODO(sra): We could avoid problems with -0.0 if we generate x % y as (x + |
| + // 0) % y, but we would have to fix HAdd optimizations. |
| + |
| + // TODO(sra): We could replace $mod with HRemainder when we don't care about |
| + // a -0.0 result (e.g. a % 10 == 0, a[i % 3]). This is tricky, since we |
| + // don't want to ruin GVN opportunities. |
| return null; |
| } |
| } |
| +class RemainderSpecializer extends BinaryArithmeticSpecializer { |
| + const RemainderSpecializer(); |
| + |
| + TypeMask computeTypeFromInputTypes( |
| + HInvokeDynamic instruction, Compiler compiler) { |
| + if (inputsArePositiveIntegers(instruction, compiler)) { |
| + JavaScriptBackend backend = compiler.backend; |
| + return backend.positiveIntType; |
| + } |
| + return super.computeTypeFromInputTypes(instruction, compiler); |
| + } |
| + |
| + BinaryOperation operation(ConstantSystem constantSystem) { |
| + return constantSystem.remainder; |
| + } |
| + |
| + HInstruction newBuiltinVariant( |
| + HInvokeDynamic instruction, Compiler compiler) { |
| + JavaScriptBackend backend = compiler.backend; |
| + return new HRemainder(instruction.inputs[1], instruction.inputs[2], |
| + instruction.selector, computeTypeFromInputTypes(instruction, compiler)); |
| + } |
| +} |
| + |
| class MultiplySpecializer extends BinaryArithmeticSpecializer { |
| const MultiplySpecializer(); |