| // 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. | |
| // 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 substitution 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); | |
| } |