| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library tree_ir.optimization.logical_rewriter; | 5 library tree_ir.optimization.logical_rewriter; |
| 6 | 6 |
| 7 import '../tree_ir_nodes.dart'; | 7 import '../tree_ir_nodes.dart'; |
| 8 import 'optimization.dart' show Pass; | 8 import 'optimization.dart' show Pass; |
| 9 import '../../constants/values.dart' as values; | 9 import '../../constants/values.dart' as values; |
| 10 | 10 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 45 /// Conditionals are tricky to rewrite when they occur out of boolean context. | 45 /// Conditionals are tricky to rewrite when they occur out of boolean context. |
| 46 /// Here we must apply more conservative rules, such as: | 46 /// Here we must apply more conservative rules, such as: |
| 47 /// | 47 /// |
| 48 /// x ? true : false ==> !!x | 48 /// x ? true : false ==> !!x |
| 49 /// | 49 /// |
| 50 /// If the possible falsy values of the condition are known, we can sometimes | 50 /// If the possible falsy values of the condition are known, we can sometimes |
| 51 /// introduce a logical operator: | 51 /// introduce a logical operator: |
| 52 /// | 52 /// |
| 53 /// !x ? y : false ==> !x && y | 53 /// !x ? y : false ==> !x && y |
| 54 /// | 54 /// |
| 55 class LogicalRewriter extends RecursiveTransformer | 55 class LogicalRewriter extends RecursiveTransformer implements Pass { |
| 56 implements Pass { | |
| 57 String get passName => 'Logical rewriter'; | 56 String get passName => 'Logical rewriter'; |
| 58 | 57 |
| 59 @override | 58 @override |
| 60 void rewrite(FunctionDefinition node) { | 59 void rewrite(FunctionDefinition node) { |
| 61 node.body = visitStatement(node.body); | 60 node.body = visitStatement(node.body); |
| 62 } | 61 } |
| 63 | 62 |
| 64 final FallthroughStack fallthrough = new FallthroughStack(); | 63 final FallthroughStack fallthrough = new FallthroughStack(); |
| 65 | 64 |
| 66 /// True if the given statement is equivalent to its fallthrough semantics. | 65 /// True if the given statement is equivalent to its fallthrough semantics. |
| 67 /// | 66 /// |
| 68 /// This means it will ultimately translate to an empty statement. | 67 /// This means it will ultimately translate to an empty statement. |
| 69 bool isFallthrough(Statement node) { | 68 bool isFallthrough(Statement node) { |
| 70 return node is Break && isFallthroughBreak(node) || | 69 return node is Break && isFallthroughBreak(node) || |
| 71 node is Continue && isFallthroughContinue(node) || | 70 node is Continue && isFallthroughContinue(node) || |
| 72 node is Return && isFallthroughReturn(node); | 71 node is Return && isFallthroughReturn(node); |
| 73 } | 72 } |
| 74 | 73 |
| 75 bool isFallthroughBreak(Break node) { | 74 bool isFallthroughBreak(Break node) { |
| 76 Statement target = fallthrough.target; | 75 Statement target = fallthrough.target; |
| 77 return node.target.binding.next == target || | 76 return node.target.binding.next == target || |
| 78 target is Break && target.target == node.target; | 77 target is Break && target.target == node.target; |
| 79 } | 78 } |
| 80 | 79 |
| 81 bool isFallthroughContinue(Continue node) { | 80 bool isFallthroughContinue(Continue node) { |
| 82 Statement target = fallthrough.target; | 81 Statement target = fallthrough.target; |
| 83 return node.target.binding == target || | 82 return node.target.binding == target || |
| 84 target is Continue && target.target == node.target; | 83 target is Continue && target.target == node.target; |
| 85 } | 84 } |
| 86 | 85 |
| 87 bool isFallthroughReturn(Return node) { | 86 bool isFallthroughReturn(Return node) { |
| 88 return isNull(node.value) && fallthrough.target == null; | 87 return isNull(node.value) && fallthrough.target == null; |
| 89 } | 88 } |
| 90 | 89 |
| 91 bool isTerminator(Statement node) { | 90 bool isTerminator(Statement node) { |
| 92 return (node is Jump || node is Return) && !isFallthrough(node) || | 91 return (node is Jump || node is Return) && !isFallthrough(node) || |
| 93 (node is ExpressionStatement && node.next is Unreachable) || | 92 (node is ExpressionStatement && node.next is Unreachable) || |
| 94 node is Throw; | 93 node is Throw; |
| 95 } | 94 } |
| 96 | 95 |
| 97 Statement visitIf(If node) { | 96 Statement visitIf(If node) { |
| 98 // If one of the branches is empty (i.e. just a fallthrough), then that | 97 // If one of the branches is empty (i.e. just a fallthrough), then that |
| 99 // branch should preferably be the 'else' so we won't have to print it. | 98 // branch should preferably be the 'else' so we won't have to print it. |
| 100 // In other words, we wish to perform this rewrite: | 99 // In other words, we wish to perform this rewrite: |
| 101 // if (E) {} else {S} | 100 // if (E) {} else {S} |
| 102 // ==> | 101 // ==> |
| 103 // if (!E) {S} | 102 // if (!E) {S} |
| 104 // In the tree language, empty statements do not exist yet, so we must check | 103 // In the tree language, empty statements do not exist yet, so we must check |
| (...skipping 11 matching lines...) Expand all Loading... |
| 116 const int THEN = 1; | 115 const int THEN = 1; |
| 117 const int NEITHER = 0; | 116 const int NEITHER = 0; |
| 118 const int ELSE = -1; | 117 const int ELSE = -1; |
| 119 int bestThenBranch = NEITHER; | 118 int bestThenBranch = NEITHER; |
| 120 if (isFallthrough(node.thenStatement) && | 119 if (isFallthrough(node.thenStatement) && |
| 121 !isFallthrough(node.elseStatement)) { | 120 !isFallthrough(node.elseStatement)) { |
| 122 // Put the empty statement in the 'else' branch. | 121 // Put the empty statement in the 'else' branch. |
| 123 // if (E) {} else {S} ==> if (!E) {S} | 122 // if (E) {} else {S} ==> if (!E) {S} |
| 124 bestThenBranch = ELSE; | 123 bestThenBranch = ELSE; |
| 125 } else if (isFallthrough(node.elseStatement) && | 124 } else if (isFallthrough(node.elseStatement) && |
| 126 !isFallthrough(node.thenStatement)) { | 125 !isFallthrough(node.thenStatement)) { |
| 127 // Keep the empty statement in the 'else' branch. | 126 // Keep the empty statement in the 'else' branch. |
| 128 // if (E) {S} else {} | 127 // if (E) {S} else {} |
| 129 bestThenBranch = THEN; | 128 bestThenBranch = THEN; |
| 130 } else if (thenHasFallthrough && !elseHasFallthrough) { | 129 } else if (thenHasFallthrough && !elseHasFallthrough) { |
| 131 // Put abrupt termination in the 'then' branch to omit 'else'. | 130 // Put abrupt termination in the 'then' branch to omit 'else'. |
| 132 // if (E) {S1} else {S2; return v} ==> if (!E) {S2; return v}; S1 | 131 // if (E) {S1} else {S2; return v} ==> if (!E) {S2; return v}; S1 |
| 133 bestThenBranch = ELSE; | 132 bestThenBranch = ELSE; |
| 134 } else if (!thenHasFallthrough && elseHasFallthrough) { | 133 } else if (!thenHasFallthrough && elseHasFallthrough) { |
| 135 // Keep abrupt termination in the 'then' branch to omit 'else'. | 134 // Keep abrupt termination in the 'then' branch to omit 'else'. |
| 136 // if (E) {S1; return v}; S2 | 135 // if (E) {S1; return v}; S2 |
| 137 bestThenBranch = THEN; | 136 bestThenBranch = THEN; |
| 138 } else if (isTerminator(node.elseStatement) && | 137 } else if (isTerminator(node.elseStatement) && |
| 139 !isTerminator(node.thenStatement)) { | 138 !isTerminator(node.thenStatement)) { |
| 140 // Put early termination in the 'then' branch to reduce nesting depth. | 139 // Put early termination in the 'then' branch to reduce nesting depth. |
| 141 // if (E) {S}; return v ==> if (!E) return v; S | 140 // if (E) {S}; return v ==> if (!E) return v; S |
| 142 bestThenBranch = ELSE; | 141 bestThenBranch = ELSE; |
| 143 } else if (isTerminator(node.thenStatement) && | 142 } else if (isTerminator(node.thenStatement) && |
| 144 !isTerminator(node.elseStatement)) { | 143 !isTerminator(node.elseStatement)) { |
| 145 // Keep early termination in the 'then' branch to reduce nesting depth. | 144 // Keep early termination in the 'then' branch to reduce nesting depth. |
| 146 // if (E) {return v;} S | 145 // if (E) {return v;} S |
| 147 bestThenBranch = THEN; | 146 bestThenBranch = THEN; |
| 148 } | 147 } |
| 149 | 148 |
| 150 // Swap branches if 'else' is better as 'then' | 149 // Swap branches if 'else' is better as 'then' |
| 151 if (bestThenBranch == ELSE) { | 150 if (bestThenBranch == ELSE) { |
| 152 node.condition = new Not(node.condition); | 151 node.condition = new Not(node.condition); |
| 153 Statement tmp = node.thenStatement; | 152 Statement tmp = node.thenStatement; |
| 154 node.thenStatement = node.elseStatement; | 153 node.thenStatement = node.elseStatement; |
| 155 node.elseStatement = tmp; | 154 node.elseStatement = tmp; |
| 156 } | 155 } |
| 157 | 156 |
| 158 // If neither branch is better, eliminate a negation in the condition | 157 // If neither branch is better, eliminate a negation in the condition |
| 159 // if (!E) S1 else S2 | 158 // if (!E) S1 else S2 |
| 160 // ==> | 159 // ==> |
| 161 // if (E) S2 else S1 | 160 // if (E) S2 else S1 |
| 162 node.condition = makeCondition(node.condition, true, | 161 node.condition = makeCondition(node.condition, true, |
| 163 liftNots: bestThenBranch == NEITHER); | 162 liftNots: bestThenBranch == NEITHER); |
| 164 if (bestThenBranch == NEITHER && node.condition is Not) { | 163 if (bestThenBranch == NEITHER && node.condition is Not) { |
| 165 node.condition = (node.condition as Not).operand; | 164 node.condition = (node.condition as Not).operand; |
| 166 Statement tmp = node.thenStatement; | 165 Statement tmp = node.thenStatement; |
| 167 node.thenStatement = node.elseStatement; | 166 node.thenStatement = node.elseStatement; |
| 168 node.elseStatement = tmp; | 167 node.elseStatement = tmp; |
| 169 } | 168 } |
| 170 | 169 |
| 171 return node; | 170 return node; |
| 172 } | 171 } |
| 173 | 172 |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 262 // x ? false : true --> !x | 261 // x ? false : true --> !x |
| 263 if (isFalse(node.thenExpression) && isTrue(node.elseExpression)) { | 262 if (isFalse(node.thenExpression) && isTrue(node.elseExpression)) { |
| 264 return toBoolean(makeCondition(node.condition, false, liftNots: false)); | 263 return toBoolean(makeCondition(node.condition, false, liftNots: false)); |
| 265 } | 264 } |
| 266 | 265 |
| 267 // x ? y : false ==> x && y (if x is truthy or false) | 266 // x ? y : false ==> x && y (if x is truthy or false) |
| 268 // x ? y : null ==> x && y (if x is truthy or null) | 267 // x ? y : null ==> x && y (if x is truthy or null) |
| 269 // x ? y : 0 ==> x && y (if x is truthy or zero) (and so on...) | 268 // x ? y : 0 ==> x && y (if x is truthy or zero) (and so on...) |
| 270 if (matchesFalsyValue(node.condition, getConstant(node.elseExpression))) { | 269 if (matchesFalsyValue(node.condition, getConstant(node.elseExpression))) { |
| 271 return new LogicalOperator.and( | 270 return new LogicalOperator.and( |
| 272 visitExpression(node.condition), | 271 visitExpression(node.condition), node.thenExpression); |
| 273 node.thenExpression); | |
| 274 } | 272 } |
| 275 // x ? true : y ==> x || y (if x is falsy or true) | 273 // x ? true : y ==> x || y (if x is falsy or true) |
| 276 // x ? 1 : y ==> x || y (if x is falsy or one) (and so on...) | 274 // x ? 1 : y ==> x || y (if x is falsy or one) (and so on...) |
| 277 if (matchesTruthyValue(node.condition, getConstant(node.thenExpression))) { | 275 if (matchesTruthyValue(node.condition, getConstant(node.thenExpression))) { |
| 278 return new LogicalOperator.or( | 276 return new LogicalOperator.or( |
| 279 visitExpression(node.condition), | 277 visitExpression(node.condition), node.elseExpression); |
| 280 node.elseExpression); | |
| 281 } | 278 } |
| 282 // x ? y : true ==> !x || y | 279 // x ? y : true ==> !x || y |
| 283 if (isTrue(node.elseExpression)) { | 280 if (isTrue(node.elseExpression)) { |
| 284 return new LogicalOperator.or( | 281 return new LogicalOperator.or( |
| 285 toBoolean(makeCondition(node.condition, false, liftNots: false)), | 282 toBoolean(makeCondition(node.condition, false, liftNots: false)), |
| 286 node.thenExpression); | 283 node.thenExpression); |
| 287 } | 284 } |
| 288 // x ? false : y ==> !x && y | 285 // x ? false : y ==> !x && y |
| 289 if (isFalse(node.thenExpression)) { | 286 if (isFalse(node.thenExpression)) { |
| 290 return new LogicalOperator.and( | 287 return new LogicalOperator.and( |
| (...skipping 30 matching lines...) Expand all Loading... |
| 321 node.right = visitExpression(node.right); | 318 node.right = visitExpression(node.right); |
| 322 return node; | 319 return node; |
| 323 } | 320 } |
| 324 | 321 |
| 325 /// True if the given expression is known to evaluate to a boolean. | 322 /// True if the given expression is known to evaluate to a boolean. |
| 326 /// This will not recursively traverse [Conditional] expressions, but if | 323 /// This will not recursively traverse [Conditional] expressions, but if |
| 327 /// applied to the result of [visitExpression] conditionals will have been | 324 /// applied to the result of [visitExpression] conditionals will have been |
| 328 /// rewritten anyway. | 325 /// rewritten anyway. |
| 329 bool isBooleanValued(Expression e) { | 326 bool isBooleanValued(Expression e) { |
| 330 return isTrue(e) || | 327 return isTrue(e) || |
| 331 isFalse(e) || | 328 isFalse(e) || |
| 332 e is Not || | 329 e is Not || |
| 333 e is LogicalOperator && isBooleanValuedLogicalOperator(e) || | 330 e is LogicalOperator && isBooleanValuedLogicalOperator(e) || |
| 334 e is ApplyBuiltinOperator && operatorReturnsBool(e.operator) || | 331 e is ApplyBuiltinOperator && operatorReturnsBool(e.operator) || |
| 335 e is TypeOperator && isBooleanValuedTypeOperator(e); | 332 e is TypeOperator && isBooleanValuedTypeOperator(e); |
| 336 } | 333 } |
| 337 | 334 |
| 338 bool isBooleanValuedLogicalOperator(LogicalOperator e) { | 335 bool isBooleanValuedLogicalOperator(LogicalOperator e) { |
| 339 return isBooleanValued(e.left) && isBooleanValued(e.right); | 336 return isBooleanValued(e.left) && isBooleanValued(e.right); |
| 340 } | 337 } |
| 341 | 338 |
| 342 /// True if the given operator always returns `true` or `false`. | 339 /// True if the given operator always returns `true` or `false`. |
| 343 bool operatorReturnsBool(BuiltinOperator operator) { | 340 bool operatorReturnsBool(BuiltinOperator operator) { |
| 344 switch (operator) { | 341 switch (operator) { |
| 345 case BuiltinOperator.StrictEq: | 342 case BuiltinOperator.StrictEq: |
| (...skipping 15 matching lines...) Expand all Loading... |
| 361 return false; | 358 return false; |
| 362 } | 359 } |
| 363 } | 360 } |
| 364 | 361 |
| 365 bool isBooleanValuedTypeOperator(TypeOperator e) { | 362 bool isBooleanValuedTypeOperator(TypeOperator e) { |
| 366 return e.isTypeTest; | 363 return e.isTypeTest; |
| 367 } | 364 } |
| 368 | 365 |
| 369 BuiltinOperator negateBuiltin(BuiltinOperator operator) { | 366 BuiltinOperator negateBuiltin(BuiltinOperator operator) { |
| 370 switch (operator) { | 367 switch (operator) { |
| 371 case BuiltinOperator.StrictEq: return BuiltinOperator.StrictNeq; | 368 case BuiltinOperator.StrictEq: |
| 372 case BuiltinOperator.StrictNeq: return BuiltinOperator.StrictEq; | 369 return BuiltinOperator.StrictNeq; |
| 373 case BuiltinOperator.LooseEq: return BuiltinOperator.LooseNeq; | 370 case BuiltinOperator.StrictNeq: |
| 374 case BuiltinOperator.LooseNeq: return BuiltinOperator.LooseEq; | 371 return BuiltinOperator.StrictEq; |
| 375 case BuiltinOperator.IsNumber: return BuiltinOperator.IsNotNumber; | 372 case BuiltinOperator.LooseEq: |
| 376 case BuiltinOperator.IsNotNumber: return BuiltinOperator.IsNumber; | 373 return BuiltinOperator.LooseNeq; |
| 377 case BuiltinOperator.IsInteger: return BuiltinOperator.IsNotInteger; | 374 case BuiltinOperator.LooseNeq: |
| 378 case BuiltinOperator.IsNotInteger: return BuiltinOperator.IsInteger; | 375 return BuiltinOperator.LooseEq; |
| 376 case BuiltinOperator.IsNumber: |
| 377 return BuiltinOperator.IsNotNumber; |
| 378 case BuiltinOperator.IsNotNumber: |
| 379 return BuiltinOperator.IsNumber; |
| 380 case BuiltinOperator.IsInteger: |
| 381 return BuiltinOperator.IsNotInteger; |
| 382 case BuiltinOperator.IsNotInteger: |
| 383 return BuiltinOperator.IsInteger; |
| 379 case BuiltinOperator.IsUnsigned32BitInteger: | 384 case BuiltinOperator.IsUnsigned32BitInteger: |
| 380 return BuiltinOperator.IsNotUnsigned32BitInteger; | 385 return BuiltinOperator.IsNotUnsigned32BitInteger; |
| 381 case BuiltinOperator.IsNotUnsigned32BitInteger: | 386 case BuiltinOperator.IsNotUnsigned32BitInteger: |
| 382 return BuiltinOperator.IsUnsigned32BitInteger; | 387 return BuiltinOperator.IsUnsigned32BitInteger; |
| 383 | 388 |
| 384 // Because of NaN, these do not have a negated form. | 389 // Because of NaN, these do not have a negated form. |
| 385 case BuiltinOperator.NumLt: | 390 case BuiltinOperator.NumLt: |
| 386 case BuiltinOperator.NumLe: | 391 case BuiltinOperator.NumLe: |
| 387 case BuiltinOperator.NumGt: | 392 case BuiltinOperator.NumGt: |
| 388 case BuiltinOperator.NumGe: | 393 case BuiltinOperator.NumGe: |
| (...skipping 10 matching lines...) Expand all Loading... |
| 399 return e; | 404 return e; |
| 400 else | 405 else |
| 401 return new Not(new Not(e)); | 406 return new Not(new Not(e)); |
| 402 } | 407 } |
| 403 | 408 |
| 404 /// Creates an equivalent boolean expression. The expression must occur in a | 409 /// Creates an equivalent boolean expression. The expression must occur in a |
| 405 /// context where its result is immediately subject to boolean conversion. | 410 /// context where its result is immediately subject to boolean conversion. |
| 406 /// If [polarity] if false, the negated condition will be created instead. | 411 /// If [polarity] if false, the negated condition will be created instead. |
| 407 /// If [liftNots] is true (default) then Not expressions will be lifted toward | 412 /// If [liftNots] is true (default) then Not expressions will be lifted toward |
| 408 /// the root of the condition so they can be eliminated by the caller. | 413 /// the root of the condition so they can be eliminated by the caller. |
| 409 Expression makeCondition(Expression e, bool polarity, {bool liftNots:true}) { | 414 Expression makeCondition(Expression e, bool polarity, {bool liftNots: true}) { |
| 410 if (e is Not) { | 415 if (e is Not) { |
| 411 // !!E ==> E | 416 // !!E ==> E |
| 412 return makeCondition(e.operand, !polarity, liftNots: liftNots); | 417 return makeCondition(e.operand, !polarity, liftNots: liftNots); |
| 413 } | 418 } |
| 414 if (e is LogicalOperator) { | 419 if (e is LogicalOperator) { |
| 415 // If polarity=false, then apply the rewrite !(x && y) ==> !x || !y | 420 // If polarity=false, then apply the rewrite !(x && y) ==> !x || !y |
| 416 e.left = makeCondition(e.left, polarity); | 421 e.left = makeCondition(e.left, polarity); |
| 417 e.right = makeCondition(e.right, polarity); | 422 e.right = makeCondition(e.right, polarity); |
| 418 if (!polarity) { | 423 if (!polarity) { |
| 419 e.isAnd = !e.isAnd; | 424 e.isAnd = !e.isAnd; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 446 // x ? true : false ==> x | 451 // x ? true : false ==> x |
| 447 if (isTrue(e.thenExpression) && isFalse(e.elseExpression)) { | 452 if (isTrue(e.thenExpression) && isFalse(e.elseExpression)) { |
| 448 return makeCondition(e.condition, true, liftNots: liftNots); | 453 return makeCondition(e.condition, true, liftNots: liftNots); |
| 449 } | 454 } |
| 450 // x ? false : true ==> !x | 455 // x ? false : true ==> !x |
| 451 if (isFalse(e.thenExpression) && isTrue(e.elseExpression)) { | 456 if (isFalse(e.thenExpression) && isTrue(e.elseExpression)) { |
| 452 return makeCondition(e.condition, false, liftNots: liftNots); | 457 return makeCondition(e.condition, false, liftNots: liftNots); |
| 453 } | 458 } |
| 454 // x ? true : y ==> x || y | 459 // x ? true : y ==> x || y |
| 455 if (isTrue(e.thenExpression)) { | 460 if (isTrue(e.thenExpression)) { |
| 456 return makeOr(makeCondition(e.condition, true), | 461 return makeOr(makeCondition(e.condition, true), e.elseExpression, |
| 457 e.elseExpression, | 462 liftNots: liftNots); |
| 458 liftNots: liftNots); | |
| 459 } | 463 } |
| 460 // x ? false : y ==> !x && y | 464 // x ? false : y ==> !x && y |
| 461 if (isFalse(e.thenExpression)) { | 465 if (isFalse(e.thenExpression)) { |
| 462 return makeAnd(makeCondition(e.condition, false), | 466 return makeAnd(makeCondition(e.condition, false), e.elseExpression, |
| 463 e.elseExpression, | 467 liftNots: liftNots); |
| 464 liftNots: liftNots); | |
| 465 } | 468 } |
| 466 // x ? y : true ==> !x || y | 469 // x ? y : true ==> !x || y |
| 467 if (isTrue(e.elseExpression)) { | 470 if (isTrue(e.elseExpression)) { |
| 468 return makeOr(makeCondition(e.condition, false), | 471 return makeOr(makeCondition(e.condition, false), e.thenExpression, |
| 469 e.thenExpression, | 472 liftNots: liftNots); |
| 470 liftNots: liftNots); | |
| 471 } | 473 } |
| 472 // x ? y : false ==> x && y | 474 // x ? y : false ==> x && y |
| 473 if (isFalse(e.elseExpression)) { | 475 if (isFalse(e.elseExpression)) { |
| 474 return makeAnd(makeCondition(e.condition, true), | 476 return makeAnd(makeCondition(e.condition, true), e.thenExpression, |
| 475 e.thenExpression, | 477 liftNots: liftNots); |
| 476 liftNots: liftNots); | |
| 477 } | 478 } |
| 478 | 479 |
| 479 e.condition = makeCondition(e.condition, true); | 480 e.condition = makeCondition(e.condition, true); |
| 480 | 481 |
| 481 // !x ? y : z ==> x ? z : y | 482 // !x ? y : z ==> x ? z : y |
| 482 if (e.condition is Not) { | 483 if (e.condition is Not) { |
| 483 e.condition = (e.condition as Not).operand; | 484 e.condition = (e.condition as Not).operand; |
| 484 Expression tmp = e.thenExpression; | 485 Expression tmp = e.thenExpression; |
| 485 e.thenExpression = e.elseExpression; | 486 e.thenExpression = e.elseExpression; |
| 486 e.elseExpression = tmp; | 487 e.elseExpression = tmp; |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 556 } else if (e1 is Assign) { | 557 } else if (e1 is Assign) { |
| 557 return e2 is VariableUse && e1.variable == e2.variable; | 558 return e2 is VariableUse && e1.variable == e2.variable; |
| 558 } | 559 } |
| 559 return false; | 560 return false; |
| 560 } | 561 } |
| 561 | 562 |
| 562 void destroyVariableUse(VariableUse node) { | 563 void destroyVariableUse(VariableUse node) { |
| 563 --node.variable.readCount; | 564 --node.variable.readCount; |
| 564 } | 565 } |
| 565 } | 566 } |
| OLD | NEW |