KT-12275 Add JS optimization that transforms the following code

```
do {
    X
    if (B) break;
} while (A)
```

to

```
do {
    X
} while (!B && A)
```

Add inversion that takes boolean expression and applies negation to it, simplifying if possible (like !!a => a).
This commit is contained in:
Alexey Andreev
2016-05-16 13:08:44 +03:00
parent b3d29adad9
commit 05dd039151
27 changed files with 812 additions and 1 deletions
@@ -36,7 +36,6 @@ import org.jetbrains.kotlin.js.translate.general.AbstractTranslator;
import org.jetbrains.kotlin.js.translate.general.Translation;
import org.jetbrains.kotlin.js.translate.intrinsic.functions.factories.TopLevelFIF;
import org.jetbrains.kotlin.js.translate.utils.BindingUtils;
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils;
import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.name.Name;
@@ -238,6 +238,43 @@ public final class JsAstUtils {
return new JsPrefixOperation(JsUnaryOperator.NOT, expression);
}
@NotNull
public static JsExpression negatedOptimized(@NotNull JsExpression expression) {
if (expression instanceof JsUnaryOperation) {
JsUnaryOperation unary = (JsUnaryOperation) expression;
if (unary.getOperator() == JsUnaryOperator.NOT) return unary.getArg();
}
else if (expression instanceof JsBinaryOperation) {
JsBinaryOperation binary = (JsBinaryOperation) expression;
switch (binary.getOperator()) {
case AND:
return or(negatedOptimized(binary.getArg1()), negatedOptimized(binary.getArg2()));
case OR:
return and(negatedOptimized(binary.getArg1()), negatedOptimized(binary.getArg2()));
case EQ:
return new JsBinaryOperation(JsBinaryOperator.NEQ, binary.getArg1(), binary.getArg2());
case NEQ:
return new JsBinaryOperation(JsBinaryOperator.EQ, binary.getArg1(), binary.getArg2());
case REF_EQ:
return inequality(binary.getArg1(), binary.getArg2());
case REF_NEQ:
return equality(binary.getArg1(), binary.getArg2());
case LT:
return greaterThanEq(binary.getArg1(), binary.getArg2());
case LTE:
return greaterThan(binary.getArg1(), binary.getArg2());
case GT:
return lessThanEq(binary.getArg1(), binary.getArg2());
case GTE:
return lessThan(binary.getArg1(), binary.getArg2());
default:
break;
}
}
return negated(expression);
}
@NotNull
public static JsBinaryOperation and(@NotNull JsExpression op1, @NotNull JsExpression op2) {
return new JsBinaryOperation(JsBinaryOperator.AND, op1, op2);
@@ -0,0 +1,12 @@
function box() {
var i = 1;
var sum = 0;
while (i < 10 && sum <= 30) {
sum += i;
i++
}
if (sum != 36) return "fail: " + sum;
return "OK"
}
@@ -0,0 +1,18 @@
function box() {
var i = 1;
var sum = 0;
while (true) {
if (i >= 10) {
break;
}
if (sum > 30) {
break;
}
sum += i;
i++
}
if (sum != 36) return "fail: " + sum;
return "OK"
}
@@ -0,0 +1,20 @@
var global = "";
function foo(x) {
global += x + ";";
return x;
}
function box() {
var i = 1;
var sum = 0;
do {
sum += i;
i++;
} while (foo(i) < 10 && foo(sum) <= 30);
if (global != "2;1;3;3;4;6;5;10;6;15;7;21;8;28;9;36;") return "fail1: " + global;
if (sum != 36) return "fail2: " + sum;
return "OK"
}
@@ -0,0 +1,26 @@
var global = "";
function foo(x) {
global += x + ";";
return x;
}
function box() {
var i = 1;
var sum = 0;
do {
sum += i;
i++;
if (foo(i) >= 10) {
break;
}
if (foo(sum) > 30) {
break;
}
} while (true);
if (global != "2;1;3;3;4;6;5;10;6;15;7;21;8;28;9;36;") return "fail1: " + global;
if (sum != 36) return "fail2: " + sum;
return "OK"
}
@@ -0,0 +1,24 @@
var global = "";
function foo(x) {
global += x;
return x;
}
function box() {
var i = 0;
do {
++i;
if (i == 5) {
continue
}
global += ";";
if (foo(i) >= 10) {
break;
}
} while (true);
if (global != ";1;2;3;4;6;7;8;9;10") return "fail: " + global;
return "OK"
}
@@ -0,0 +1,24 @@
var global = "";
function foo(x) {
global += x;
return x;
}
function box() {
var i = 0;
do {
++i;
if (i == 5) {
continue
}
global += ";";
if (foo(i) >= 10) {
break;
}
} while (true);
if (global != ";1;2;3;4;6;7;8;9;10") return "fail: " + global;
return "OK"
}
@@ -0,0 +1,45 @@
var global = "";
function foo(x) {
global += x;
return x;
}
function box() {
var i = 0;
var j;
do {
++i;
global += ";";
for (j = 0; j < 2; ++j) {
if (j == 1) {
continue;
}
global += "-";
}
for (k in { a: 2, b: 3 }) {
if (k != "a") {
continue;
}
global += "@";
}
j = 0;
while (j++ < 2) {
if (j == 1) {
continue;
}
global += "$";
}
j = 0;
do {
if (j == 1) {
continue;
}
global += "#";
} while (j++ < 2);
} while (foo(i) < 3);
if (global != ";-@$##1;-@$##2;-@$##3") return "fail: " + global;
return "OK"
}
@@ -0,0 +1,48 @@
var global = "";
function foo(x) {
global += x;
return x;
}
function box() {
var i = 0;
var j;
do {
++i;
global += ";";
for (j = 0; j < 2; ++j) {
if (j == 1) {
continue;
}
global += "-";
}
for (k in { a: 2, b: 3 }) {
if (k != "a") {
continue;
}
global += "@";
}
j = 0;
while (j++ < 2) {
if (j == 1) {
continue;
}
global += "$";
}
j = 0;
do {
if (j == 1) {
continue;
}
global += "#";
} while (j++ < 2);
if (foo(i) >= 3) {
break;
}
} while (true);
if (global != ";-@$##1;-@$##2;-@$##3") return "fail: " + global;
return "OK"
}
@@ -0,0 +1,15 @@
function box() {
var i = 1;
var sum = 0;
outer: {
while (i < 10) {
sum += i;
i++;
if (sum > 20) break outer;
}
}
if (sum != 21) return "fail: " + sum;
return "OK"
}
@@ -0,0 +1,18 @@
function box() {
var i = 1;
var sum = 0;
outer: {
while (true) {
if (i >= 10) {
break;
}
sum += i;
i++;
if (sum > 20) break outer;
}
}
if (sum != 21) return "fail: " + sum;
return "OK"
}
@@ -0,0 +1,16 @@
function box() {
var i;
var sum = 0;
var count = 2;
while (count-- > 0) {
i = 1;
while (i < 10) {
sum += i;
i++
}
}
if (sum != 90) return "fail: " + sum;
return "OK"
}
@@ -0,0 +1,19 @@
function box() {
var i;
var sum = 0;
var count = 2;
while (count-- > 0) {
i = 1;
while (true) {
if (i >= 10) {
break;
}
sum += i;
i++
}
}
if (sum != 90) return "fail: " + sum;
return "OK"
}
@@ -0,0 +1,28 @@
var global = "";
function foo(x) {
global += x;
return x;
}
function box() {
var i = 0;
var j;
loop: do {
++i;
global += ";";
for (j = 0; j < 2; ++j) {
if (j == 1 && i == 2) {
continue loop;
}
global += "-";
}
if (foo(i) >= 5) {
break;
}
} while (true);
if (global != ";--1;-;--3;--4;--5") return "fail: " + global;
return "OK"
}
@@ -0,0 +1,28 @@
var global = "";
function foo(x) {
global += x;
return x;
}
function box() {
var i = 0;
var j;
loop: do {
++i;
global += ";";
for (j = 0; j < 2; ++j) {
if (j == 1 && i == 2) {
continue loop;
}
global += "-";
}
if (foo(i) >= 5) {
break;
}
} while (true);
if (global != ";--1;-;--3;--4;--5") return "fail: " + global;
return "OK"
}
@@ -0,0 +1,12 @@
function box() {
var i = 1;
var sum = 0;
while (i < 5 || sum <= 40) {
sum += i;
i++
}
if (sum != 45) return "fail: " + sum;
return "OK"
}
@@ -0,0 +1,15 @@
function box() {
var i = 1;
var sum = 0;
while (true) {
if (i >= 5) {
if (sum > 40) break;
}
sum += i;
i++
}
if (sum != 45) return "fail: " + sum;
return "OK"
}
@@ -0,0 +1,18 @@
var global = "";
function foo(x) {
global += x;
return x;
}
function box() {
var i = 0;
do {
++i;
global += ";";
} while (foo(i) < 10);
if (global != ";1;2;3;4;5;6;7;8;9;10") return "fail: " + global;
return "OK"
}
@@ -0,0 +1,21 @@
var global = "";
function foo(x) {
global += x;
return x;
}
function box() {
var i = 0;
do {
++i;
global += ";";
if (foo(i) >= 10) {
break;
}
} while (true);
if (global != ";1;2;3;4;5;6;7;8;9;10") return "fail: " + global;
return "OK"
}
@@ -0,0 +1,12 @@
function box() {
var i = 1;
var sum = 0;
while (i < 10) {
sum += i;
i++
}
if (sum != 45) return "fail: " + sum;
return "OK"
}
@@ -0,0 +1,15 @@
function box() {
var i = 1;
var sum = 0;
while (true) {
if (i >= 10) {
break;
}
sum += i;
i++
}
if (sum != 45) return "fail: " + sum;
return "OK"
}
@@ -0,0 +1,20 @@
var global = "";
function foo(x) {
global += x + ";";
return x;
}
function box() {
var i = 1;
var sum = 0;
while (foo(i) < 10 && foo(sum) <= 30) {
sum += i;
i++;
}
if (global != "1;0;2;1;3;3;4;6;5;10;6;15;7;21;8;28;9;36;") return "fail1: " + global;
if (sum != 36) return "fail2: " + sum;
return "OK"
}
@@ -0,0 +1,26 @@
var global = "";
function foo(x) {
global += x + ";";
return x;
}
function box() {
var i = 1;
var sum = 0;
while (true) {
if (foo(i) >= 10) {
break;
}
if (foo(sum) > 30) {
break;
}
sum += i;
i++;
}
if (global != "1;0;2;1;3;3;4;6;5;10;6;15;7;21;8;28;9;36;") return "fail1: " + global;
if (sum != 36) return "fail2: " + sum;
return "OK"
}