mirror of
https://github.com/dart-lang/sdk
synced 2024-09-18 21:11:19 +00:00
Fix range-analysis.
BUG= http://dartbug.com/19798 R=kmillikin@google.com, ngeoffray@google.com Review URL: https://codereview.chromium.org//369833005 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@38029 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
parent
7f7b986ac7
commit
a436303adf
|
@ -774,7 +774,7 @@ class SsaValueRangeAnalyzer extends HBaseVisitor implements OptimizationPhase {
|
|||
relational.block.rewrite(
|
||||
relational, graph.addConstantBool(true, compiler));
|
||||
relational.block.remove(relational);
|
||||
} else if (reverseOperation(operation).apply(leftRange, rightRange)) {
|
||||
} else if (negateOperation(operation).apply(leftRange, rightRange)) {
|
||||
relational.block.rewrite(
|
||||
relational, graph.addConstantBool(false, compiler));
|
||||
relational.block.remove(relational);
|
||||
|
@ -885,7 +885,7 @@ class SsaValueRangeAnalyzer extends HBaseVisitor implements OptimizationPhase {
|
|||
return newInstruction;
|
||||
}
|
||||
|
||||
static BinaryOperation reverseOperation(BinaryOperation operation) {
|
||||
static BinaryOperation negateOperation(BinaryOperation operation) {
|
||||
if (operation == const LessOperation()) {
|
||||
return const GreaterEqualOperation();
|
||||
} else if (operation == const LessEqualOperation()) {
|
||||
|
@ -899,6 +899,20 @@ class SsaValueRangeAnalyzer extends HBaseVisitor implements OptimizationPhase {
|
|||
}
|
||||
}
|
||||
|
||||
static BinaryOperation flipOperation(BinaryOperation operation) {
|
||||
if (operation == const LessOperation()) {
|
||||
return const GreaterOperation();
|
||||
} else if (operation == const LessEqualOperation()) {
|
||||
return const GreaterEqualOperation();
|
||||
} else if (operation == const GreaterOperation()) {
|
||||
return const LessOperation();
|
||||
} else if (operation == const GreaterEqualOperation()) {
|
||||
return const LessEqualOperation();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Range computeConstrainedRange(BinaryOperation operation,
|
||||
Range leftRange,
|
||||
Range rightRange) {
|
||||
|
@ -932,7 +946,7 @@ class SsaValueRangeAnalyzer extends HBaseVisitor implements OptimizationPhase {
|
|||
Range rightRange = ranges[right];
|
||||
Range leftRange = ranges[left];
|
||||
Operation operation = condition.operation(constantSystem);
|
||||
Operation reverse = reverseOperation(operation);
|
||||
Operation mirrorOp = flipOperation(operation);
|
||||
// Only update the true branch if this block is the only
|
||||
// predecessor.
|
||||
if (branch.trueBranch.predecessors.length == 1) {
|
||||
|
@ -946,7 +960,7 @@ class SsaValueRangeAnalyzer extends HBaseVisitor implements OptimizationPhase {
|
|||
ranges[instruction] = range;
|
||||
}
|
||||
|
||||
range = computeConstrainedRange(reverse, rightRange, leftRange);
|
||||
range = computeConstrainedRange(mirrorOp, rightRange, leftRange);
|
||||
if (rightRange != range) {
|
||||
HInstruction instruction =
|
||||
createRangeConversion(branch.trueBranch.first, right);
|
||||
|
@ -958,6 +972,8 @@ class SsaValueRangeAnalyzer extends HBaseVisitor implements OptimizationPhase {
|
|||
// predecessor.
|
||||
if (branch.falseBranch.predecessors.length == 1) {
|
||||
assert(branch.falseBranch.predecessors[0] == branch.block);
|
||||
Operation reverse = negateOperation(operation);
|
||||
Operation reversedMirror = flipOperation(reverse);
|
||||
// Update the false branch to use narrower ranges for [left] and
|
||||
// [right].
|
||||
Range range = computeConstrainedRange(reverse, leftRange, rightRange);
|
||||
|
@ -967,7 +983,7 @@ class SsaValueRangeAnalyzer extends HBaseVisitor implements OptimizationPhase {
|
|||
ranges[instruction] = range;
|
||||
}
|
||||
|
||||
range = computeConstrainedRange(operation, rightRange, leftRange);
|
||||
range = computeConstrainedRange(reversedMirror, rightRange, leftRange);
|
||||
if (rightRange != range) {
|
||||
HInstruction instruction =
|
||||
createRangeConversion(branch.falseBranch.first, right);
|
||||
|
|
210
tests/language/range_analysis3_test.dart
Normal file
210
tests/language/range_analysis3_test.dart
Normal file
|
@ -0,0 +1,210 @@
|
|||
// Copyright (c) 2014, 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:expect/expect.dart";
|
||||
|
||||
confuse(x) {
|
||||
if (new DateTime.now().millisecondsSinceEpoch == 0) {
|
||||
return confuse(x + 1);
|
||||
} else if (new DateTime.now().millisecondsSinceEpoch == 0) {
|
||||
return confuse(x - 1);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
test1() {
|
||||
int x = 0;
|
||||
// Give x a range of -1 to 0.
|
||||
if (confuse(0) == 1) x = -1;
|
||||
|
||||
int y = 0;
|
||||
// Give y a range of 0 to 1.
|
||||
if (confuse(0) == 1) y = 1;
|
||||
|
||||
var zero = 0;
|
||||
|
||||
var status = "bad";
|
||||
if (x < zero) {
|
||||
Expect.fail("unreachable");
|
||||
} else {
|
||||
// Dart2js must not conclude that zero has a range of [-1, 0].
|
||||
if (y <= zero) {
|
||||
status = "good";
|
||||
}
|
||||
}
|
||||
Expect.equals("good", status);
|
||||
}
|
||||
|
||||
test2() {
|
||||
int x = 0;
|
||||
// Give x a range of -1 to 0.
|
||||
if (confuse(0) == 1) x = -1;
|
||||
|
||||
int y = 0;
|
||||
// Give y a range of -1 to 1.
|
||||
if (confuse(0) == 1) y = 1;
|
||||
if (confuse(1) == 2) y = -1;
|
||||
|
||||
var status = "good";
|
||||
if (x < y) {
|
||||
Expect.fail("unreachable");
|
||||
} else {
|
||||
// Dart2js must not conclude that y has a range of [-1, -1].
|
||||
if (y == -1) {
|
||||
status = "bad";
|
||||
}
|
||||
}
|
||||
Expect.equals("good", status);
|
||||
}
|
||||
|
||||
test3a() {
|
||||
int x = 0;
|
||||
// Give x a range of -1 to 1.
|
||||
if (confuse(0) == 1) x = -1;
|
||||
if (confuse(1) == 2) x = 1;
|
||||
|
||||
int y = 0;
|
||||
// Give y a range of -1 to 1.
|
||||
if (confuse(0) == 1) y = 1;
|
||||
if (confuse(1) == 2) y = -1;
|
||||
|
||||
var status = "good";
|
||||
if (x < y) {
|
||||
Expect.fail("unreachable");
|
||||
} else {
|
||||
// Test that the range-analysis does not lose a value.
|
||||
if (x <= -1) status = "bad";
|
||||
if (x >= 1) status = "bad";
|
||||
if (x < 0) status = "bad";
|
||||
if (x > 0) status = "bad";
|
||||
if (-1 >= x) status = "bad";
|
||||
if (1 <= x) status = "bad";
|
||||
if (0 > x) status = "bad";
|
||||
if (0 < x) status = "bad";
|
||||
if (y <= -1) status = "bad";
|
||||
if (y >= 1) status = "bad";
|
||||
if (y < 0) status = "bad";
|
||||
if (y > 0) status = "bad";
|
||||
if (-1 >= y) status = "bad";
|
||||
if (1 <= y) status = "bad";
|
||||
if (0 > y) status = "bad";
|
||||
if (0 < y) status = "bad";
|
||||
}
|
||||
Expect.equals("good", status);
|
||||
}
|
||||
|
||||
test3b() {
|
||||
int x = 0;
|
||||
// Give x a range of -2 to 0.
|
||||
if (confuse(0) == 1) x = -2;
|
||||
|
||||
int y = 0;
|
||||
// Give y a range of -1 to 1.
|
||||
if (confuse(0) == 1) y = 1;
|
||||
if (confuse(1) == 2) y = -1;
|
||||
|
||||
var status = "good";
|
||||
if (x < y) {
|
||||
Expect.fail("unreachable");
|
||||
} else {
|
||||
// Test that the range-analysis does not lose a value.
|
||||
if (x <= -1) status = "bad";
|
||||
if (x >= 1) status = "bad";
|
||||
if (x < 0) status = "bad";
|
||||
if (x > 0) status = "bad";
|
||||
if (-1 >= x) status = "bad";
|
||||
if (1 <= x) status = "bad";
|
||||
if (0 > x) status = "bad";
|
||||
if (0 < x) status = "bad";
|
||||
if (y <= -1) status = "bad";
|
||||
if (y >= 1) status = "bad";
|
||||
if (y < 0) status = "bad";
|
||||
if (y > 0) status = "bad";
|
||||
if (-1 >= y) status = "bad";
|
||||
if (1 <= y) status = "bad";
|
||||
if (0 > y) status = "bad";
|
||||
if (0 < y) status = "bad";
|
||||
}
|
||||
Expect.equals("good", status);
|
||||
}
|
||||
|
||||
test4a() {
|
||||
int x = -1;
|
||||
// Give x a range of -1 to 1.
|
||||
if (confuse(0) == 1) x = 1;
|
||||
|
||||
int y = 0;
|
||||
// Give y a range of -1 to 1.
|
||||
if (confuse(0) == 1) y = 1;
|
||||
if (confuse(1) == 2) y = -1;
|
||||
|
||||
var status = "good";
|
||||
if (x < y) {
|
||||
// Test that the range-analysis does not lose a value.
|
||||
if (x <= -2) status = "bad";
|
||||
if (x >= 0) status = "bad";
|
||||
if (x < -1) status = "bad";
|
||||
if (x > -1) status = "bad";
|
||||
if (-2 >= x) status = "bad";
|
||||
if (0 <= x) status = "bad";
|
||||
if (-1 > x) status = "bad";
|
||||
if (-1 < x) status = "bad";
|
||||
if (y <= -1) status = "bad";
|
||||
if (y >= 1) status = "bad";
|
||||
if (y < 0) status = "bad";
|
||||
if (y > 0) status = "bad";
|
||||
if (-1 >= y) status = "bad";
|
||||
if (1 <= y) status = "bad";
|
||||
if (0 > y) status = "bad";
|
||||
if (0 < y) status = "bad";
|
||||
} else {
|
||||
Expect.fail("unreachable");
|
||||
}
|
||||
Expect.equals("good", status);
|
||||
}
|
||||
|
||||
test4b() {
|
||||
int x = -1;
|
||||
// Give x a range of -2 to 0.
|
||||
if (confuse(0) == 1) x = -2;
|
||||
if (confuse(1) == 2) x = 0;
|
||||
|
||||
int y = 0;
|
||||
// Give y a range of -1 to 1.
|
||||
if (confuse(0) == 1) y = 1;
|
||||
if (confuse(1) == 2) y = -1;
|
||||
|
||||
var status = "good";
|
||||
if (x < y) {
|
||||
// Test that the range-analysis does not lose a value.
|
||||
if (x <= -2) status = "bad";
|
||||
if (x >= 0) status = "bad";
|
||||
if (x < -1) status = "bad";
|
||||
if (x > -1) status = "bad";
|
||||
if (-2 >= x) status = "bad";
|
||||
if (0 <= x) status = "bad";
|
||||
if (-1 > x) status = "bad";
|
||||
if (-1 < x) status = "bad";
|
||||
if (y <= -1) status = "bad";
|
||||
if (y >= 1) status = "bad";
|
||||
if (y < 0) status = "bad";
|
||||
if (y > 0) status = "bad";
|
||||
if (-1 >= y) status = "bad";
|
||||
if (1 <= y) status = "bad";
|
||||
if (0 > y) status = "bad";
|
||||
if (0 < y) status = "bad";
|
||||
} else {
|
||||
Expect.fail("unreachable");
|
||||
}
|
||||
Expect.equals("good", status);
|
||||
}
|
||||
|
||||
main() {
|
||||
test1();
|
||||
test2();
|
||||
test3a();
|
||||
test3b();
|
||||
test4a();
|
||||
test4b();
|
||||
}
|
Loading…
Reference in a new issue