| // Copyright (c) 2021, 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. |
| |
| // @dart = 2.7 |
| |
| // Tests for simplifying that we know a condition is true in the then-branch and |
| // false in the else-branch, and sometimes after join when a diamond exits. |
| |
| /*member: check0:ConditionValue=[]*/ |
| check0(int x) { |
| if (x != 1) { |
| return 200; |
| } else { |
| return 400; |
| } |
| } |
| |
| /*member: check1:ConditionValue=[count=1&value=false&where=else,count=1&value=true&where=then]*/ |
| check1(int x) { |
| if (x == 1) { |
| if (x == 1) return 100; |
| return 200; |
| } else { |
| if (x == 1) return 300; |
| return 400; |
| } |
| } |
| |
| /*member: check2:ConditionValue=[count=1&value=false&where=then,count=1&value=true&where=else]*/ |
| check2(int x) { |
| if (x != 1) { |
| if (x == 1) return 100; |
| return 200; |
| } else { |
| if (x == 1) return 300; |
| return 400; |
| } |
| } |
| |
| /*member: check3:ConditionValue=[count=1&value=false&where=else,count=1&value=true&where=then]*/ |
| check3(int x) { |
| if (x == 1) { |
| if (x != 1) return 100; |
| return 200; |
| } else { |
| if (x != 1) return 300; |
| return 400; |
| } |
| } |
| |
| /*member: check4:ConditionValue=[count=1&value=false&where=else,count=1&value=true&where=then]*/ |
| check4(int x) { |
| if (x != 1) { |
| if (x != 1) return 100; |
| return 200; |
| } else { |
| if (x != 1) return 300; |
| return 400; |
| } |
| } |
| |
| // The first throw is in statement position, so it has an exit edge, leaving the |
| // rest of the method in the first branch 'else'. |
| /*member: join0Else:ConditionValue=[count=2&value=false&where=else]*/ |
| join0Else(int x) { |
| int a = 0, b = 0, c = 0; |
| if (x == 1) |
| throw 'bad'; |
| else |
| a = x + 1; |
| if (x == 1) |
| throw 'bad'; |
| else |
| b = x + 2; |
| if (x == 1) |
| throw 'bad'; |
| else |
| c = x + 3; |
| return a * b * c; |
| } |
| |
| /*member: join1:ConditionValue=[count=2&value=false&where=else-join]*/ |
| join1(int x) { |
| int a = (x == 1 ? throw 'bad' : x) + 1; |
| int b = (x == 1 ? throw 'bad' : x) + 2; |
| int c = (x == 1 ? throw 'bad' : x) + 3; |
| return a * b * c; |
| } |
| |
| /*member: join2:ConditionValue=[count=2&value=true&where=then-join]*/ |
| join2(int x) { |
| int a = (x == 1 ? x : throw 'bad') + 1; |
| int b = (x == 1 ? x : throw 'bad') + 2; |
| int c = (x == 1 ? x : throw 'bad') + 3; |
| return a * b * c; |
| } |
| |
| /*member: join3:ConditionValue=[count=2&value=false&where=else-join]*/ |
| join3(int x) { |
| int a = (x != 1 ? throw 'bad' : x) + 1; |
| int b = (x != 1 ? throw 'bad' : x) + 2; |
| int c = (x != 1 ? throw 'bad' : x) + 3; |
| return a * b * c; |
| } |
| |
| /*member: join4:ConditionValue=[count=2&value=true&where=then-join]*/ |
| join4(int x) { |
| int a = (x != 1 ? x : throw 'bad') + 1; |
| int b = (x != 1 ? x : throw 'bad') + 2; |
| int c = (x != 1 ? x : throw 'bad') + 3; |
| return a * b * c; |
| } |
| |
| /*member: loop1:ConditionValue=[count=1&value=true&where=then]*/ |
| loop1(int x) { |
| for (int i = 0; i < 10; i++) { |
| if (x == 1) { |
| sink = x == 1; |
| } |
| } |
| } |
| |
| /*member: loop2HoistedThen:ConditionValue=[count=1&value=false&where=hoisted-then]*/ |
| loop2HoistedThen(int x) { |
| // t1 = x == 1; |
| // t2 = !t1; |
| // loop: |
| // if (t1) |
| // sink = t2; // replaced with `false`. |
| for (int i = 0; i < 10; i++) { |
| if (x == 1) { |
| sink = x != 1; |
| } |
| } |
| } |
| |
| /*member: loop3:ConditionValue=[count=1&value=false&where=then]*/ |
| loop3(int x) { |
| for (int i = 0; i < 10; i++) { |
| if (x != 1) { |
| sink = x == 1; |
| } |
| } |
| } |
| |
| /*member: loop4:ConditionValue=[count=1&value=true&where=then]*/ |
| loop4(int x) { |
| for (int i = 0; i < 10; i++) { |
| if (x != 1) { |
| sink = x != 1; |
| } |
| } |
| } |
| |
| /*member: loop5HoistedElseJoin:ConditionValue=[count=1&value=true&where=hoisted-else-join]*/ |
| loop5HoistedElseJoin(int x) { |
| for (int i = 0; i < 10; i++) { |
| sink = (x == 1 ? throw 'bad' : x) + 1; |
| sink = x != 1; |
| } |
| } |
| |
| // Unlike loop5, this is not 'hoisted'. GVN is not required to match the |
| // condition with its use, so the subsitution happens in a simplify pass before |
| // GVN/LICM can hoist the negation. |
| /*member: loop6ElseJoin:ConditionValue=[count=1&value=false&where=else-join]*/ |
| loop6ElseJoin(bool x) { |
| for (int i = 0; i < 10; i++) { |
| sink = (x ? throw 'bad' : i) + 1; |
| sink = !x; |
| } |
| } |
| |
| dynamic sink; |
| |
| void main() { |
| check0(1); |
| check0(2); |
| |
| check1(1); |
| check1(2); |
| check2(1); |
| check2(2); |
| check3(1); |
| check3(2); |
| check4(1); |
| check4(2); |
| |
| join0Else(1); |
| join0Else(2); |
| join1(1); |
| join1(2); |
| join2(1); |
| join2(2); |
| join3(1); |
| join3(2); |
| join4(1); |
| join4(2); |
| |
| loop1(1); |
| loop1(2); |
| loop2HoistedThen(1); |
| loop2HoistedThen(2); |
| loop3(1); |
| loop3(2); |
| loop4(1); |
| loop4(2); |
| loop5HoistedElseJoin(1); |
| loop5HoistedElseJoin(2); |
| loop6ElseJoin(true); |
| loop6ElseJoin(false); |
| |
| print(sink); |
| } |