diff --git a/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart b/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart index b7dcfbed201..f02b6c6a43f 100644 --- a/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart +++ b/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart @@ -248,8 +248,18 @@ class UnaryNegateSpecializer extends InvokeDynamicSpecializer { GlobalTypeInferenceResults results, CompilerOptions options, ClosedWorld closedWorld) { - TypeMask operandType = instruction.inputs[1].instructionType; - if (instruction.inputs[1].isNumberOrNull(closedWorld)) return operandType; + HInstruction operand = instruction.inputs[1]; + if (operand.isNumberOrNull(closedWorld)) { + // We have integer subclasses that represent ranges, so widen any int + // subclass to full integer. + if (operand.isIntegerOrNull(closedWorld)) { + return closedWorld.commonMasks.intType; + } + if (operand.isDoubleOrNull(closedWorld)) { + return closedWorld.commonMasks.doubleType; + } + return closedWorld.commonMasks.numType; + } return super .computeTypeFromInputTypes(instruction, results, options, closedWorld); } @@ -263,7 +273,11 @@ class UnaryNegateSpecializer extends InvokeDynamicSpecializer { ClosedWorld closedWorld) { HInstruction input = instruction.inputs[1]; if (input.isNumber(closedWorld)) { - return new HNegate(input, instruction.selector, input.instructionType); + return new HNegate( + input, + instruction.selector, + computeTypeFromInputTypes( + instruction, results, options, closedWorld)); } return null; } diff --git a/tests/compiler/dart2js/codegen/negation_shift_regression_test.dart b/tests/compiler/dart2js/codegen/negation_shift_regression_test.dart new file mode 100644 index 00000000000..ec028c871f1 --- /dev/null +++ b/tests/compiler/dart2js/codegen/negation_shift_regression_test.dart @@ -0,0 +1,47 @@ +// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:async_helper/async_helper.dart'; +import '../compiler_helper.dart'; + +// A bug in UnaryNegateSpecializer left '-a' labelled as 'positive', allowing +// misoptimization of '<<'. +const String TEST1 = r""" +foo(param) { + var a = param ? 0xFFFFFFFF : 1; + return 1 << -a; + // present: '$shl' + // absent: '_shlPositive' +} +"""; + +const String TEST2 = r""" +foo(param) { + var a = param ? 0xFFFFFFFF : 1; + return 1 << a; + // present: '_shlPositive' + // absent: '$shl' +} +"""; + +main() { + runTests({bool useKernel}) async { + check(String test) async { + await compile(test, + entry: 'foo', + useKernel: useKernel, + check: checkerForAbsentPresent(test)); + } + + await check(TEST1); + await check(TEST2); + } + + asyncTest(() async { + print('--test from ast---------------------------------------------------'); + await runTests(useKernel: false); + print('--test from kernel------------------------------------------------'); + await runTests(useKernel: true); + }); +}