From 354d54aef6143d406cc3e92890c8e78b9d771a6f Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Tue, 24 Oct 2017 11:03:53 +0300 Subject: [PATCH] Don't generate DUPX instructions for in-range-literal expressions Store argument into a local variable instead. --- .../range/ComparableRangeLiteralRangeValue.kt | 2 +- ...PrimitiveNumberRangeIntrinsicRangeValue.kt | 4 +- ...ousRangeOfComparableExpressionGenerator.kt | 149 ++++++++++-------- ...itiveContinuousRangeExpressionGenerator.kt | 136 ++++++++-------- .../ranges/noDupXForLiteralRangeContains.kt | 12 ++ .../ranges/noSwap2ForConstLongRangeTo.kt | 7 - .../codegen/BytecodeTextTestGenerated.java | 6 +- 7 files changed, 170 insertions(+), 146 deletions(-) create mode 100644 compiler/testData/codegen/bytecodeText/ranges/noDupXForLiteralRangeContains.kt delete mode 100644 compiler/testData/codegen/bytecodeText/ranges/noSwap2ForConstLongRangeTo.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/range/ComparableRangeLiteralRangeValue.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/range/ComparableRangeLiteralRangeValue.kt index 8fd9252e1b7..61f49700f73 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/range/ComparableRangeLiteralRangeValue.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/range/ComparableRangeLiteralRangeValue.kt @@ -41,5 +41,5 @@ class ComparableRangeLiteralRangeValue( codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression, resolvedCall: ResolvedCall - ) = InContinuousRangeOfComparableExpressionGenerator(operatorReference, boundedValue) + ) = InContinuousRangeOfComparableExpressionGenerator(operatorReference, boundedValue, codegen.frameMap) } \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/range/PrimitiveNumberRangeIntrinsicRangeValue.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/range/PrimitiveNumberRangeIntrinsicRangeValue.kt index 77b29686b70..42979e90b55 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/range/PrimitiveNumberRangeIntrinsicRangeValue.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/range/PrimitiveNumberRangeIntrinsicRangeValue.kt @@ -42,7 +42,9 @@ abstract class PrimitiveNumberRangeIntrinsicRangeValue(rangeCall: ResolvedCall + val exitLabel1 = Label() + val exitLabel2 = Label() - boundedValue.putHighLow(v, operandType) - arg1.put(operandType, v) - AsmUtil.dupx(v, operandType) + boundedValue.putHighLow(v, operandType) - // On stack: high arg low arg - // if (low bound is NOT satisfied) goto exitLabel1 - if (boundedValue.isLowInclusive) { - // arg < low - v.swap() - comparisonGenerator.jumpIfLess(v, exitLabel1) - } - else { - // arg <= low - v.swap() - comparisonGenerator.jumpIfLessOrEqual(v, exitLabel1) + arg1.put(operandType, v) + v.store(arg1Var, operandType) + v.load(arg1Var, operandType) + + // On stack: high low arg + // if (low bound is NOT satisfied) goto exitLabel1 + if (boundedValue.isLowInclusive) { + // arg < low + v.swap() + comparisonGenerator.jumpIfLess(v, exitLabel1) + } + else { + // arg <= low + v.swap() + comparisonGenerator.jumpIfLessOrEqual(v, exitLabel1) + } + + v.load(arg1Var, operandType) + // On stack: high arg + // if (high bound is satisfied) goto jumpLabel + if (boundedValue.isHighInclusive) { + // arg <= high + v.swap() + comparisonGenerator.jumpIfLessOrEqual(v, jumpLabel) + } + else { + // arg < high + v.swap() + comparisonGenerator.jumpIfLess(v, jumpLabel) + } + v.goTo(exitLabel2) + + v.mark(exitLabel1) + AsmUtil.pop(v, operandType) + + v.mark(exitLabel2) } - // On stack: high arg - // if (high bound is satisfied) goto jumpLabel - if (boundedValue.isHighInclusive) { - // arg <= high - v.swap() - comparisonGenerator.jumpIfLessOrEqual(v, jumpLabel) - } - else { - // arg < high - v.swap() - comparisonGenerator.jumpIfLess(v, jumpLabel) - } - v.goTo(exitLabel2) - - v.mark(exitLabel1) - AsmUtil.pop2(v, operandType) - - v.mark(exitLabel2) } private fun genJumpIfFalse(v: InstructionAdapter, jumpLabel: Label) { // if (arg is NOT in range) goto jumpLabel - val cmpHighLabel = Label() + frameMap.useTmpVar(operandType) { arg1Var -> + val cmpHighLabel = Label() - boundedValue.putHighLow(v, operandType) - arg1.put(operandType, v) - AsmUtil.dupx(v, operandType) + boundedValue.putHighLow(v, operandType) - // On stack: high arg low arg - // if ([low bound is satisfied]) goto cmpHighLabel - if (boundedValue.isLowInclusive) { - // arg >= low - v.swap() - comparisonGenerator.jumpIfGreaterOrEqual(v, cmpHighLabel) - } - else { - // arg > low - v.swap() - comparisonGenerator.jumpIfGreater(v, cmpHighLabel) - } + arg1.put(operandType, v) + v.store(arg1Var, operandType) + v.load(arg1Var, operandType) - // Low bound is NOT satisfied, clear stack and goto jumpLabel - AsmUtil.pop2(v, operandType) - v.goTo(jumpLabel) + // On stack: high low arg + // if ([low bound is satisfied]) goto cmpHighLabel + if (boundedValue.isLowInclusive) { + // arg >= low + v.swap() + comparisonGenerator.jumpIfGreaterOrEqual(v, cmpHighLabel) + } + else { + // arg > low + v.swap() + comparisonGenerator.jumpIfGreater(v, cmpHighLabel) + } - v.mark(cmpHighLabel) - // On stack: high arg - // if ([high bound is NOT satisfied]) goto jumpLabel - if (boundedValue.isHighInclusive) { - // arg > high - v.swap() - comparisonGenerator.jumpIfGreater(v, jumpLabel) - } - else { - // arg >= high - v.swap() - comparisonGenerator.jumpIfGreaterOrEqual(v, jumpLabel) + // Low bound is NOT satisfied, clear stack and goto jumpLabel + AsmUtil.pop(v, operandType) + v.goTo(jumpLabel) + + v.mark(cmpHighLabel) + v.load(arg1Var, operandType) + // On stack: high arg + // if ([high bound is NOT satisfied]) goto jumpLabel + if (boundedValue.isHighInclusive) { + // arg > high + v.swap() + comparisonGenerator.jumpIfGreater(v, jumpLabel) + } + else { + // arg >= high + v.swap() + comparisonGenerator.jumpIfGreaterOrEqual(v, jumpLabel) + } } } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/range/inExpression/InPrimitiveContinuousRangeExpressionGenerator.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/range/inExpression/InPrimitiveContinuousRangeExpressionGenerator.kt index 72c9718fd8d..efe058814f9 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/range/inExpression/InPrimitiveContinuousRangeExpressionGenerator.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/range/inExpression/InPrimitiveContinuousRangeExpressionGenerator.kt @@ -16,10 +16,7 @@ package org.jetbrains.kotlin.codegen.range.inExpression -import org.jetbrains.kotlin.codegen.AsmUtil -import org.jetbrains.kotlin.codegen.BranchedValue -import org.jetbrains.kotlin.codegen.Invert -import org.jetbrains.kotlin.codegen.StackValue +import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.range.BoundedValue import org.jetbrains.kotlin.codegen.range.comparison.ComparisonGenerator import org.jetbrains.kotlin.lexer.KtTokens @@ -31,7 +28,8 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter class InPrimitiveContinuousRangeExpressionGenerator( operatorReference: KtSimpleNameExpression, private val boundedValue: BoundedValue, - private val comparisonGenerator: ComparisonGenerator + private val comparisonGenerator: ComparisonGenerator, + private val frameMap: FrameMap ) : InExpressionGenerator { private val isNotIn = operatorReference.getReferencedNameElementType() == KtTokens.NOT_IN @@ -51,78 +49,88 @@ class InPrimitiveContinuousRangeExpressionGenerator( private fun genJumpIfTrue(v: InstructionAdapter, jumpLabel: Label) { // if (arg is in range) goto jumpLabel + frameMap.useTmpVar(operandType) { arg1Var -> + val exitLabel1 = Label() + val exitLabel2 = Label() - val exitLabel1 = Label() - val exitLabel2 = Label() + boundedValue.putHighLow(v, operandType) - boundedValue.putHighLow(v, operandType) - arg1.put(operandType, v) - AsmUtil.dupx(v, operandType) + arg1.put(operandType, v) + v.store(arg1Var, operandType) + v.load(arg1Var, operandType) - // On stack: high arg low arg - // if (low bound is NOT satisfied) goto exitLabel1 - if (boundedValue.isLowInclusive) { - // low > arg - comparisonGenerator.jumpIfGreater(v, exitLabel1) + // On stack: high low arg + // if (low bound is NOT satisfied) goto exitLabel1 + if (boundedValue.isLowInclusive) { + // low > arg + comparisonGenerator.jumpIfGreater(v, exitLabel1) + } + else { + // low >= arg + comparisonGenerator.jumpIfGreaterOrEqual(v, exitLabel1) + } + + v.load(arg1Var, operandType) + // On stack: high arg + // if (high bound is satisfied) goto jumpLabel + if (boundedValue.isHighInclusive) { + // high >= arg + comparisonGenerator.jumpIfGreaterOrEqual(v, jumpLabel) + } + else { + // high > arg + comparisonGenerator.jumpIfGreater(v, jumpLabel) + } + v.goTo(exitLabel2) + + v.mark(exitLabel1) + AsmUtil.pop(v, operandType) + + v.mark(exitLabel2) } - else { - // low >= arg - comparisonGenerator.jumpIfGreaterOrEqual(v, exitLabel1) - } - - // On stack: high arg - // if (high bound is satisfied) goto jumpLabel - if (boundedValue.isHighInclusive) { - // high >= arg - comparisonGenerator.jumpIfGreaterOrEqual(v, jumpLabel) - } - else { - // high > arg - comparisonGenerator.jumpIfGreater(v, jumpLabel) - } - v.goTo(exitLabel2) - - v.mark(exitLabel1) - AsmUtil.pop2(v, operandType) - - v.mark(exitLabel2) } private fun genJumpIfFalse(v: InstructionAdapter, jumpLabel: Label) { // if (arg is NOT in range) goto jumpLabel - val cmpHighLabel = Label() + frameMap.useTmpVar(operandType) { arg1Var -> + val cmpHighLabel = Label() - boundedValue.putHighLow(v, operandType) - arg1.put(operandType, v) - AsmUtil.dupx(v, operandType) + boundedValue.putHighLow(v, operandType) - // On stack: high arg low arg - // if ([low bound is satisfied]) goto cmpHighLabel - if (boundedValue.isLowInclusive) { - // low <= arg - comparisonGenerator.jumpIfLessOrEqual(v, cmpHighLabel) - } - else { - // low < arg - comparisonGenerator.jumpIfLess(v, cmpHighLabel) + arg1.put(operandType, v) + v.store(arg1Var, operandType) + v.load(arg1Var, operandType) + + // On stack: high low arg + // if ([low bound is satisfied]) goto cmpHighLabel + if (boundedValue.isLowInclusive) { + // low <= arg + comparisonGenerator.jumpIfLessOrEqual(v, cmpHighLabel) + } + else { + // low < arg + comparisonGenerator.jumpIfLess(v, cmpHighLabel) + } + + // Low bound is NOT satisfied, clear stack and goto jumpLabel + AsmUtil.pop(v, operandType) + v.goTo(jumpLabel) + + v.mark(cmpHighLabel) + v.load(arg1Var, operandType) + // On stack: high arg + // if ([high bound is NOT satisfied]) goto jumpLabel + if (boundedValue.isHighInclusive) { + // high < arg + comparisonGenerator.jumpIfLess(v, jumpLabel) + } + else { + // high <= arg + comparisonGenerator.jumpIfLessOrEqual(v, jumpLabel) + } } - // Low bound is NOT satisfied, clear stack and goto jumpLabel - AsmUtil.pop2(v, operandType) - v.goTo(jumpLabel) - - v.mark(cmpHighLabel) - // On stack: high arg - // if ([high bound is NOT satisfied]) goto jumpLabel - if (boundedValue.isHighInclusive) { - // high < arg - comparisonGenerator.jumpIfLess(v, jumpLabel) - } - else { - // high <= arg - comparisonGenerator.jumpIfLessOrEqual(v, jumpLabel) - } } } } \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/ranges/noDupXForLiteralRangeContains.kt b/compiler/testData/codegen/bytecodeText/ranges/noDupXForLiteralRangeContains.kt new file mode 100644 index 00000000000..96912848084 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/ranges/noDupXForLiteralRangeContains.kt @@ -0,0 +1,12 @@ +// WITH_RUNTIME + +fun test(a: Int) = a in 1 .. 10 +fun test(a: Long) = a in 1L .. 10L +fun test(a: Float) = a in 1.0f .. 10.0f +fun test(a: Double) = a in 1.0 .. 10.0 +fun test(a: String) = a in "abc" .. "def" + +// 0 DUP_X1 +// 0 DUP2_X1 +// 0 DUP_X2 +// 0 DUP2_X2 \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/ranges/noSwap2ForConstLongRangeTo.kt b/compiler/testData/codegen/bytecodeText/ranges/noSwap2ForConstLongRangeTo.kt deleted file mode 100644 index a83b6e80e77..00000000000 --- a/compiler/testData/codegen/bytecodeText/ranges/noSwap2ForConstLongRangeTo.kt +++ /dev/null @@ -1,7 +0,0 @@ -// WITH_RUNTIME - -fun test(a: Long) = a in 1L .. 10L - -// One DUP2_X2 generated for 'in' operator, -// no DUP2_X2 generated for range on stack. -// 1 DUP2_X2 \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index e5ece964034..4403fad3f29 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -2006,9 +2006,9 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { doTest(fileName); } - @TestMetadata("noSwap2ForConstLongRangeTo.kt") - public void testNoSwap2ForConstLongRangeTo() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/ranges/noSwap2ForConstLongRangeTo.kt"); + @TestMetadata("noDupXForLiteralRangeContains.kt") + public void testNoDupXForLiteralRangeContains() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/ranges/noDupXForLiteralRangeContains.kt"); doTest(fileName); } }