Optimize comparison with zero and null
This commit is contained in:
@@ -89,6 +89,7 @@ open class BranchedValue(val arg1: StackValue, val arg2: StackValue? = null, val
|
|||||||
registerOperations(IFGE, IFLT)
|
registerOperations(IFGE, IFLT)
|
||||||
registerOperations(IFGT, IFLE)
|
registerOperations(IFGT, IFLE)
|
||||||
registerOperations(IF_ACMPNE, IF_ACMPEQ)
|
registerOperations(IF_ACMPNE, IF_ACMPEQ)
|
||||||
|
registerOperations(IFNULL, IFNONNULL)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun registerOperations(op: Int, negatedOp: Int) {
|
private fun registerOperations(op: Int, negatedOp: Int) {
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ import static org.jetbrains.kotlin.resolve.jvm.diagnostics.DiagnosticsPackage.Ot
|
|||||||
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.DiagnosticsPackage.TraitImpl;
|
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.DiagnosticsPackage.TraitImpl;
|
||||||
import static org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER;
|
import static org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER;
|
||||||
import static org.jetbrains.kotlin.serialization.deserialization.DeserializationPackage.findClassAcrossModuleDependencies;
|
import static org.jetbrains.kotlin.serialization.deserialization.DeserializationPackage.findClassAcrossModuleDependencies;
|
||||||
import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_PRIVATE;
|
import static org.jetbrains.org.objectweb.asm.Opcodes.*;
|
||||||
|
|
||||||
public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implements LocalLookup {
|
public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implements LocalLookup {
|
||||||
private static final Set<DeclarationDescriptor> INTEGRAL_RANGES = KotlinBuiltIns.getInstance().getIntegralRanges();
|
private static final Set<DeclarationDescriptor> INTEGRAL_RANGES = KotlinBuiltIns.getInstance().getIntegralRanges();
|
||||||
@@ -3063,19 +3063,19 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
|||||||
Type rightType = expressionType(right);
|
Type rightType = expressionType(right);
|
||||||
|
|
||||||
if (JetPsiUtil.isNullConstant(left)) {
|
if (JetPsiUtil.isNullConstant(left)) {
|
||||||
return genCmpWithNull(right, rightType, opToken);
|
return genCmpWithNull(right, opToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JetPsiUtil.isNullConstant(right)) {
|
if (JetPsiUtil.isNullConstant(right)) {
|
||||||
return genCmpWithNull(left, leftType, opToken);
|
return genCmpWithNull(left, opToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isIntZero(left, leftType) && isIntPrimitive(rightType)) {
|
if (isIntZero(left, leftType) && isIntPrimitive(rightType)) {
|
||||||
return genCmpWithZero(right, rightType, opToken);
|
return genCmpWithZero(right, opToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isIntZero(right, rightType) && isIntPrimitive(leftType)) {
|
if (isIntZero(right, rightType) && isIntPrimitive(leftType)) {
|
||||||
return genCmpWithZero(left, leftType, opToken);
|
return genCmpWithZero(left, opToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPrimitive(leftType) != isPrimitive(rightType)) {
|
if (isPrimitive(leftType) != isPrimitive(rightType)) {
|
||||||
@@ -3100,57 +3100,12 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
|||||||
return isIntPrimitive(exprType) && exprValue != null && Integer.valueOf(0).equals(exprValue.getValue());
|
return isIntPrimitive(exprType) && exprValue != null && Integer.valueOf(0).equals(exprValue.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
private StackValue genCmpWithZero(final JetExpression exp, final Type expType, final IElementType opToken) {
|
private StackValue genCmpWithZero(JetExpression exp, IElementType opToken) {
|
||||||
return StackValue.operation(Type.BOOLEAN_TYPE, new Function1<InstructionAdapter, Unit>() {
|
return StackValue.compareIntWithZero(gen(exp), (JetTokens.EQEQ == opToken || JetTokens.EQEQEQ == opToken) ? IFNE : IFEQ);
|
||||||
@Override
|
|
||||||
public Unit invoke(InstructionAdapter v) {
|
|
||||||
gen(exp, expType);
|
|
||||||
Label trueLabel = new Label();
|
|
||||||
Label afterLabel = new Label();
|
|
||||||
if (JetTokens.EQEQ == opToken || JetTokens.EQEQEQ == opToken) {
|
|
||||||
v.ifeq(trueLabel);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
v.ifne(trueLabel);
|
|
||||||
}
|
|
||||||
|
|
||||||
v.iconst(0);
|
|
||||||
v.goTo(afterLabel);
|
|
||||||
|
|
||||||
v.mark(trueLabel);
|
|
||||||
v.iconst(1);
|
|
||||||
|
|
||||||
v.mark(afterLabel);
|
|
||||||
return Unit.INSTANCE$;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private StackValue genCmpWithNull(final JetExpression exp, final Type expType, final IElementType opToken) {
|
private StackValue genCmpWithNull(JetExpression exp, IElementType opToken) {
|
||||||
return StackValue.operation(Type.BOOLEAN_TYPE, new Function1<InstructionAdapter, Unit>() {
|
return StackValue.compareWithNull(gen(exp), (JetTokens.EQEQ == opToken || JetTokens.EQEQEQ == opToken) ? IFNONNULL : IFNULL);
|
||||||
@Override
|
|
||||||
public Unit invoke(InstructionAdapter v) {
|
|
||||||
gen(exp, boxType(expType));
|
|
||||||
Label trueLabel = new Label();
|
|
||||||
Label afterLabel = new Label();
|
|
||||||
if (JetTokens.EQEQ == opToken || JetTokens.EQEQEQ == opToken) {
|
|
||||||
v.ifnull(trueLabel);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
v.ifnonnull(trueLabel);
|
|
||||||
}
|
|
||||||
|
|
||||||
v.iconst(0);
|
|
||||||
v.goTo(afterLabel);
|
|
||||||
|
|
||||||
v.mark(trueLabel);
|
|
||||||
v.iconst(1);
|
|
||||||
|
|
||||||
v.mark(afterLabel);
|
|
||||||
|
|
||||||
return Unit.INSTANCE$;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private StackValue generateElvis(@NotNull final JetBinaryExpression expression) {
|
private StackValue generateElvis(@NotNull final JetBinaryExpression expression) {
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.psi.JetExpression;
|
|||||||
import org.jetbrains.kotlin.resolve.annotations.AnnotationsPackage;
|
import org.jetbrains.kotlin.resolve.annotations.AnnotationsPackage;
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument;
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument;
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
|
||||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind;
|
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind;
|
||||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature;
|
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
||||||
@@ -178,6 +179,14 @@ public abstract class StackValue {
|
|||||||
return new And(left, right);
|
return new And(left, right);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static StackValue compareIntWithZero(@NotNull StackValue argument, int operation) {
|
||||||
|
return new BranchedValue(argument, null, Type.INT_TYPE, operation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StackValue compareWithNull(@NotNull StackValue argument, int operation) {
|
||||||
|
return new BranchedValue(argument, null, AsmTypes.OBJECT_TYPE, operation);
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static StackValue arrayElement(@NotNull Type type, StackValue array, StackValue index) {
|
public static StackValue arrayElement(@NotNull Type type, StackValue array, StackValue index) {
|
||||||
return new ArrayElement(type, array, index);
|
return new ArrayElement(type, array, index);
|
||||||
|
|||||||
@@ -13,5 +13,6 @@ fun bar() {
|
|||||||
|
|
||||||
// 0 valueOf
|
// 0 valueOf
|
||||||
// 0 Value\s\(\)
|
// 0 Value\s\(\)
|
||||||
// 1 IFNULL
|
// 0 IFNULL
|
||||||
// 0 IFNONNULL
|
// 1 IFNONNULL
|
||||||
|
// 1 IF
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
fun main(p: String?) {
|
||||||
|
if (!(p == null)) {
|
||||||
|
"then"
|
||||||
|
} else {
|
||||||
|
"else"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//0 ICONST_0
|
||||||
|
//0 ICONST_1
|
||||||
|
//0 ACONST_NULL
|
||||||
|
//1 IFNULL
|
||||||
|
//1 IF
|
||||||
|
//1 GOTO
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
fun main() {
|
||||||
|
val a = 1
|
||||||
|
if (!(a == 0)) {
|
||||||
|
"then"
|
||||||
|
} else {
|
||||||
|
"else"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//0 ICONST_0
|
||||||
|
//1 ICONST_1
|
||||||
|
//1 IFEQ
|
||||||
|
//0 IFNE
|
||||||
|
//1 IF
|
||||||
|
//1 GOTO
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
fun main(p: String?) {
|
||||||
|
if (p == null) {
|
||||||
|
"then"
|
||||||
|
} else {
|
||||||
|
"else"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//0 ICONST_0
|
||||||
|
//0 ICONST_1
|
||||||
|
//0 ACONST_NULL
|
||||||
|
//1 IFNONNULL
|
||||||
|
//1 IF
|
||||||
|
//1 GOTO
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
fun main() {
|
||||||
|
val a = 1
|
||||||
|
if (a == 0) {
|
||||||
|
"then"
|
||||||
|
} else {
|
||||||
|
"else"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//0 ICONST_0
|
||||||
|
//1 ICONST_1
|
||||||
|
//0 IFEQ
|
||||||
|
//1 IFNE
|
||||||
|
//1 IF
|
||||||
|
//1 GOTO
|
||||||
@@ -328,6 +328,30 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
|||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/conditions/negatedDisjunction.kt");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/conditions/negatedDisjunction.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("negatedNullCompare.kt")
|
||||||
|
public void testNegatedNullCompare() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/conditions/negatedNullCompare.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("negatedZeroCompare.kt")
|
||||||
|
public void testNegatedZeroCompare() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/conditions/negatedZeroCompare.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nullCompare.kt")
|
||||||
|
public void testNullCompare() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/conditions/nullCompare.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("zeroCompare.kt")
|
||||||
|
public void testZeroCompare() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/conditions/zeroCompare.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/bytecodeText/constants")
|
@TestMetadata("compiler/testData/codegen/bytecodeText/constants")
|
||||||
|
|||||||
Reference in New Issue
Block a user