Branched value refactoring, And/Or support

This commit is contained in:
Michael Bogdanov
2015-04-04 17:00:07 +03:00
parent c63ac3e30a
commit c7fe8e0b66
8 changed files with 179 additions and 76 deletions
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.codegen.stackvalue
package org.jetbrains.kotlin.codegen
import com.intellij.psi.tree.IElementType
import org.jetbrains.kotlin.codegen.AsmUtil
@@ -32,7 +32,7 @@ open class BranchedValue(val arg1: StackValue, val arg2: StackValue? = null, val
override fun putSelector(type: Type, v: InstructionAdapter) {
val branchJumpLabel = Label()
condJump(branchJumpLabel, v)
condJump(branchJumpLabel, v, true)
val endLabel = Label()
v.iconst(1)
v.visitJumpInsn(GOTO, endLabel)
@@ -42,14 +42,10 @@ open class BranchedValue(val arg1: StackValue, val arg2: StackValue? = null, val
coerceTo(type, v);
}
open fun condJump(jumpIfFalse: Label, v: InstructionAdapter) {
arg1.put(operandType, v)
open fun condJump(jumpLabel: Label, v: InstructionAdapter, jumpIfFalse: Boolean) {
if (arg1 is CondJump) arg1.condJump(jumpLabel, v, jumpIfFalse) else arg1.put(operandType, v)
arg2?.put(operandType, v)
v.visitJumpInsn(patchOpcode(opcode, v), jumpIfFalse);
}
protected open fun invert(): BranchedValue {
return BranchedValue(this, negatedOperations.get(opcode))
v.visitJumpInsn(patchOpcode(if (jumpIfFalse) opcode else negatedOperations[opcode], v), jumpLabel);
}
protected open fun patchOpcode(opcode: Int, v: InstructionAdapter): Int {
@@ -60,12 +56,11 @@ open class BranchedValue(val arg1: StackValue, val arg2: StackValue? = null, val
val negatedOperations = hashMapOf<Int, Int>()
val TRUE: BranchedValue = object : BranchedValue(StackValue.Constant(true, Type.BOOLEAN_TYPE), null, Type.BOOLEAN_TYPE, IFEQ) {
override fun invert(): BranchedValue {
return FALSE
}
override fun condJump(jumpIfFalse: Label, v: InstructionAdapter) {
override fun condJump(jumpLabel: Label, v: InstructionAdapter, jumpIfFalse: Boolean) {
if (!jumpIfFalse) {
v.goTo(jumpLabel)
}
}
override fun putSelector(type: Type, v: InstructionAdapter) {
@@ -73,13 +68,12 @@ open class BranchedValue(val arg1: StackValue, val arg2: StackValue? = null, val
coerceTo(type, v);
}
}
val FALSE: BranchedValue = object : BranchedValue(StackValue.Constant(false, Type.BOOLEAN_TYPE), null, Type.BOOLEAN_TYPE, IFEQ) {
override fun invert(): BranchedValue {
return TRUE
}
override fun condJump(jumpIfFalse: Label, v: InstructionAdapter) {
v.goTo(jumpIfFalse)
val FALSE: BranchedValue = object : BranchedValue(StackValue.Constant(false, Type.BOOLEAN_TYPE), null, Type.BOOLEAN_TYPE, IFEQ) {
override fun condJump(jumpLabel: Label, v: InstructionAdapter, jumpIfFalse: Boolean) {
if (jumpIfFalse) {
v.goTo(jumpLabel)
}
}
override fun putSelector(type: Type, v: InstructionAdapter) {
@@ -110,40 +104,73 @@ open class BranchedValue(val arg1: StackValue, val arg2: StackValue? = null, val
if (argument.type != Type.BOOLEAN_TYPE) {
throw UnsupportedOperationException("operand of ! must be boolean")
}
if (argument is BranchedValue) {
return argument.invert()
}
return BranchedValue(argument, null, Type.BOOLEAN_TYPE, IFNE)
return Invert(condJump(argument))
}
fun condJump(condition: StackValue, label: Label, jumpIfFalse: Boolean, iv: InstructionAdapter) {
var condJump: BranchedValue = if (condition is BranchedValue) {
condJump(condition).condJump(label, iv, jumpIfFalse)
}
fun condJump(condition: StackValue): CondJump {
return CondJump(if (condition is BranchedValue) {
condition
}
else {
BranchedValue(condition, null, Type.BOOLEAN_TYPE, IFEQ)
}
condJump = if (jumpIfFalse) condJump else condJump.invert()
condJump.condJump(label, iv)
}, IFEQ)
}
public fun cmp(opToken: IElementType, operandType: Type, left: StackValue, right: StackValue): StackValue =
if (operandType.getSort() == Type.OBJECT)
ObjectCompare(opToken, ObjectCompare.getObjectCompareOpcode(opToken), operandType, left, right)
ObjectCompare(opToken, operandType, left, right)
else
NumberCompare(opToken, NumberCompare.getNumberCompareOpcode(opToken), operandType, left, right)
NumberCompare(opToken, operandType, left, right)
}
}
class And(arg1: StackValue, arg2: StackValue) :
BranchedValue(BranchedValue.condJump(arg1), BranchedValue.condJump(arg2), Type.BOOLEAN_TYPE, IFEQ) {
class NumberCompare(val opToken: IElementType, opcode: Int, operandType: Type, left: StackValue, right: StackValue) :
BranchedValue(left, right, operandType, opcode) {
override fun invert(): BranchedValue {
return NumberCompare(opToken, BranchedValue.negatedOperations[opcode], operandType, arg1, arg2!!)
override fun condJump(jumpLabel: Label, v: InstructionAdapter, jumpIfFalse: Boolean) {
val stayLabel = Label()
(arg1 as CondJump).condJump(if (jumpIfFalse) jumpLabel else stayLabel, v, true)
(arg2 as CondJump).condJump(jumpLabel, v, jumpIfFalse)
v.visitLabel(stayLabel)
}
}
class Or(arg1: StackValue, arg2: StackValue) :
BranchedValue(BranchedValue.condJump(arg1), BranchedValue.condJump(arg2), Type.BOOLEAN_TYPE, IFEQ) {
override fun condJump(jumpLabel: Label, v: InstructionAdapter, jumpIfFalse: Boolean) {
val stayLabel = Label()
(arg1 as CondJump).condJump(if (jumpIfFalse) stayLabel else jumpLabel, v, false)
(arg2 as CondJump).condJump(jumpLabel, v, jumpIfFalse)
v.visitLabel(stayLabel)
}
}
class Invert(val condition: BranchedValue) : BranchedValue(condition, null, Type.BOOLEAN_TYPE, IFEQ) {
override fun condJump(jumpLabel: Label, v: InstructionAdapter, jumpIfFalse: Boolean) {
condition.condJump(jumpLabel, v, !jumpIfFalse)
}
}
class CondJump(val condition: BranchedValue, op: Int) : BranchedValue(condition, null, Type.BOOLEAN_TYPE, op) {
override fun putSelector(type: Type, v: InstructionAdapter) {
throw UnsupportedOperationException("Use condJump instead")
}
override fun condJump(jumpLabel: Label, v: InstructionAdapter, jumpIfFalse: Boolean) {
condition.condJump(jumpLabel, v, jumpIfFalse)
}
}
class NumberCompare(val opToken: IElementType, operandType: Type, left: StackValue, right: StackValue) :
BranchedValue(left, right, operandType, NumberCompare.getNumberCompareOpcode(opToken)) {
override fun patchOpcode(opcode: Int, v: InstructionAdapter): Int {
when (operandType) {
@@ -182,12 +209,8 @@ class NumberCompare(val opToken: IElementType, opcode: Int, operandType: Type, l
}
}
class ObjectCompare(val opToken: IElementType, opcode: Int, operandType: Type, left: StackValue, right: StackValue) :
BranchedValue(left, right, operandType, opcode) {
override fun invert(): BranchedValue {
return ObjectCompare(opToken, BranchedValue.negatedOperations[opcode], operandType, arg1, arg2!!)
}
class ObjectCompare(val opToken: IElementType, operandType: Type, left: StackValue, right: StackValue) :
BranchedValue(left, right, operandType, ObjectCompare.getObjectCompareOpcode(opToken)) {
companion object {
fun getObjectCompareOpcode(opToken: IElementType): Int {
@@ -38,7 +38,6 @@ import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension;
import org.jetbrains.kotlin.codegen.inline.*;
import org.jetbrains.kotlin.codegen.intrinsics.*;
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter;
import org.jetbrains.kotlin.codegen.stackvalue.BranchedValue;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
import org.jetbrains.kotlin.codegen.when.SwitchCodegen;
@@ -3059,40 +3058,12 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
v.and(Type.INT_TYPE);
}
private StackValue generateBooleanAnd(final JetBinaryExpression expression) {
return StackValue.operation(Type.BOOLEAN_TYPE, new Function1<InstructionAdapter, Unit>() {
@Override
public Unit invoke(InstructionAdapter v) {
gen(expression.getLeft(), Type.BOOLEAN_TYPE);
Label ifFalse = new Label();
v.ifeq(ifFalse);
gen(expression.getRight(), Type.BOOLEAN_TYPE);
Label end = new Label();
v.goTo(end);
v.mark(ifFalse);
v.iconst(0);
v.mark(end);
return Unit.INSTANCE$;
}
});
private StackValue generateBooleanAnd(JetBinaryExpression expression) {
return StackValue.and(genLazy(expression.getLeft(), Type.BOOLEAN_TYPE), genLazy(expression.getRight(), Type.BOOLEAN_TYPE));
}
private StackValue generateBooleanOr(final JetBinaryExpression expression) {
return StackValue.operation(Type.BOOLEAN_TYPE, new Function1<InstructionAdapter, Unit>() {
@Override
public Unit invoke(InstructionAdapter v) {
gen(expression.getLeft(), Type.BOOLEAN_TYPE);
Label ifTrue = new Label();
v.ifne(ifTrue);
gen(expression.getRight(), Type.BOOLEAN_TYPE);
Label end = new Label();
v.goTo(end);
v.mark(ifTrue);
v.iconst(1);
v.mark(end);
return Unit.INSTANCE$;
}
});
private StackValue generateBooleanOr(JetBinaryExpression expression) {
return StackValue.or(genLazy(expression.getLeft(), Type.BOOLEAN_TYPE), genLazy(expression.getRight(), Type.BOOLEAN_TYPE));
}
private StackValue generateEquals(JetExpression left, JetExpression right, IElementType opToken) {
@@ -23,7 +23,6 @@ import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.PrimitiveType;
import org.jetbrains.kotlin.codegen.stackvalue.BranchedValue;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
import org.jetbrains.kotlin.descriptors.*;
@@ -171,6 +170,14 @@ public abstract class StackValue {
return BranchedValue.Companion.createInvertValue(stackValue);
}
public static StackValue or(@NotNull StackValue left, @NotNull StackValue right) {
return new Or(left, right);
}
public static StackValue and(@NotNull StackValue left, @NotNull StackValue right) {
return new And(left, right);
}
@NotNull
public static StackValue arrayElement(@NotNull Type type, StackValue array, StackValue index) {
return new ArrayElement(type, array, index);
@@ -0,0 +1,17 @@
fun main() {
val a = false
val b = false
val c = false
if (a && b && c) {
"then"
} else {
"else"
}
}
// 3 ICONST_0
// 0 ICONST_1
// 3 IFEQ
// 0 IFNE
// 3 IF
// 1 GOTO
@@ -0,0 +1,17 @@
fun main() {
val a = false
val b = false
val c = false
if (a || b || c) {
"then"
} else {
"else"
}
}
// 3 ICONST_0
// 0 ICONST_1
// 1 IFEQ
// 2 IFNE
// 3 IF
// 1 GOTO
@@ -0,0 +1,17 @@
fun main() {
val a = false
val b = false
val c = false
if (!(a && b && c)) {
"then"
} else {
"else"
}
}
// 3 ICONST_0
// 0 ICONST_1
// 2 IFEQ
// 1 IFNE
// 3 IF
// 1 GOTO
@@ -0,0 +1,17 @@
fun main() {
val a = false
val b = false
val c = false
if (!(a || b || c)) {
"then"
} else {
"else"
}
}
// 3 ICONST_0
// 0 ICONST_1
// 0 IFEQ
// 3 IFNE
// 3 IF
// 1 GOTO
@@ -32,6 +32,7 @@ import java.util.regex.Pattern;
@TestDataPath("$PROJECT_ROOT")
@InnerTestClasses({
BytecodeTextTestGenerated.BoxingOptimization.class,
BytecodeTextTestGenerated.Conditions.class,
BytecodeTextTestGenerated.Constants.class,
BytecodeTextTestGenerated.DeadCodeElimination.class,
BytecodeTextTestGenerated.DirectInvoke.class,
@@ -296,6 +297,39 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
}
}
@TestMetadata("compiler/testData/codegen/bytecodeText/conditions")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Conditions extends AbstractBytecodeTextTest {
public void testAllFilesPresentInConditions() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/conditions"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("conjuction.kt")
public void testConjuction() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/conditions/conjuction.kt");
doTest(fileName);
}
@TestMetadata("disjunction.kt")
public void testDisjunction() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/conditions/disjunction.kt");
doTest(fileName);
}
@TestMetadata("negatedConjuction.kt")
public void testNegatedConjuction() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/conditions/negatedConjuction.kt");
doTest(fileName);
}
@TestMetadata("negatedDisjunction.kt")
public void testNegatedDisjunction() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/conditions/negatedDisjunction.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/bytecodeText/constants")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)