| Index: pkg/compiler/lib/src/ssa/optimize.dart
|
| diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
|
| index cbc92f6adcd24d997785dd08e6e5c61393662102..e9bfd4a87d12b9fda292fc5a8034c7b7d504569f 100644
|
| --- a/pkg/compiler/lib/src/ssa/optimize.dart
|
| +++ b/pkg/compiler/lib/src/ssa/optimize.dart
|
| @@ -2110,29 +2110,22 @@ class SsaTypeConversionInserter extends HBaseVisitor
|
| return;
|
| }
|
|
|
| - List<HInstruction> ifUsers = <HInstruction>[];
|
| - List<HInstruction> notIfUsers = <HInstruction>[];
|
| + List<HBasicBlock> trueTargets = <HBasicBlock>[];
|
| + List<HBasicBlock> falseTargets = <HBasicBlock>[];
|
|
|
| - collectIfUsers(instruction, ifUsers, notIfUsers);
|
| + collectTargets(instruction, trueTargets, falseTargets);
|
|
|
| - if (ifUsers.isEmpty && notIfUsers.isEmpty) return;
|
| + if (trueTargets.isEmpty && falseTargets.isEmpty) return;
|
|
|
| TypeMask convertedType =
|
| new TypeMask.nonNullSubtype(element, compiler.closedWorld);
|
| HInstruction input = instruction.expression;
|
|
|
| - for (HIf ifUser in ifUsers) {
|
| - insertTypePropagationForDominatedUsers(
|
| - ifUser.thenBlock, input, convertedType);
|
| - // TODO(ngeoffray): Also change uses for the else block on a type
|
| - // that knows it is not of a specific type.
|
| - }
|
| - for (HIf ifUser in notIfUsers) {
|
| - insertTypePropagationForDominatedUsers(
|
| - ifUser.elseBlock, input, convertedType);
|
| - // TODO(ngeoffray): Also change uses for the then block on a type
|
| - // that knows it is not of a specific type.
|
| + for (HBasicBlock block in trueTargets) {
|
| + insertTypePropagationForDominatedUsers(block, input, convertedType);
|
| }
|
| + // TODO(sra): Also strengthen uses for when the condition is known
|
| + // false. Avoid strengthening to `null`.
|
| }
|
|
|
| void visitIdentity(HIdentity instruction) {
|
| @@ -2151,34 +2144,50 @@ class SsaTypeConversionInserter extends HBaseVisitor
|
|
|
| if (!input.instructionType.isNullable) return;
|
|
|
| - List<HInstruction> ifUsers = <HInstruction>[];
|
| - List<HInstruction> notIfUsers = <HInstruction>[];
|
| + List<HBasicBlock> trueTargets = <HBasicBlock>[];
|
| + List<HBasicBlock> falseTargets = <HBasicBlock>[];
|
|
|
| - collectIfUsers(instruction, ifUsers, notIfUsers);
|
| + collectTargets(instruction, trueTargets, falseTargets);
|
|
|
| - if (ifUsers.isEmpty && notIfUsers.isEmpty) return;
|
| + if (trueTargets.isEmpty && falseTargets.isEmpty) return;
|
|
|
| TypeMask nonNullType = input.instructionType.nonNullable();
|
|
|
| - for (HIf ifUser in ifUsers) {
|
| - insertTypePropagationForDominatedUsers(
|
| - ifUser.elseBlock, input, nonNullType);
|
| - // Uses in thenBlock are `null`, but probably not common.
|
| - }
|
| - for (HIf ifUser in notIfUsers) {
|
| - insertTypePropagationForDominatedUsers(
|
| - ifUser.thenBlock, input, nonNullType);
|
| - // Uses in elseBlock are `null`, but probably not common.
|
| + for (HBasicBlock block in falseTargets) {
|
| + insertTypePropagationForDominatedUsers(block, input, nonNullType);
|
| }
|
| + // We don't strengthen the known-true references. It doesn't happen often
|
| + // and we don't want "if (x==null) return x;" to convert between JavaScript
|
| + // 'null' and 'undefined'.
|
| }
|
|
|
| - collectIfUsers(HInstruction instruction, List<HInstruction> ifUsers,
|
| - List<HInstruction> notIfUsers) {
|
| + collectTargets(HInstruction instruction, List<HBasicBlock> trueTargets,
|
| + List<HBasicBlock> falseTargets) {
|
| for (HInstruction user in instruction.usedBy) {
|
| if (user is HIf) {
|
| - ifUsers.add(user);
|
| + trueTargets?.add(user.thenBlock);
|
| + falseTargets?.add(user.elseBlock);
|
| } else if (user is HNot) {
|
| - collectIfUsers(user, notIfUsers, ifUsers);
|
| + collectTargets(user, falseTargets, trueTargets);
|
| + } else if (user is HPhi) {
|
| + List<HInstruction> inputs = user.inputs;
|
| + if (inputs.length == 2) {
|
| + assert(inputs.contains(instruction));
|
| + HInstruction other = inputs[(inputs[0] == instruction) ? 1 : 0];
|
| + if (other.isConstantTrue()) {
|
| + // The condition flows to a HPhi(true, user), which means that a
|
| + // downstream HIf has true-branch control flow that does not depend
|
| + // on the original instruction, so stop collecting [trueTargets].
|
| + collectTargets(user, null, falseTargets);
|
| + } else if (other.isConstantFalse()) {
|
| + // Ditto for false.
|
| + collectTargets(user, trueTargets, null);
|
| + }
|
| + }
|
| + } else if (user is HBoolify) {
|
| + // We collect targets for strictly boolean operations so HBoolify cannot
|
| + // change the result.
|
| + collectTargets(user, trueTargets, falseTargets);
|
| }
|
| }
|
| }
|
|
|