Don't generate DUPX instructions for in-range-literal expressions
Store argument into a local variable instead.
This commit is contained in:
+1
-1
@@ -41,5 +41,5 @@ class ComparableRangeLiteralRangeValue(
|
||||
codegen: ExpressionCodegen,
|
||||
operatorReference: KtSimpleNameExpression,
|
||||
resolvedCall: ResolvedCall<out CallableDescriptor>
|
||||
) = InContinuousRangeOfComparableExpressionGenerator(operatorReference, boundedValue)
|
||||
) = InContinuousRangeOfComparableExpressionGenerator(operatorReference, boundedValue, codegen.frameMap)
|
||||
}
|
||||
+3
-1
@@ -42,7 +42,9 @@ abstract class PrimitiveNumberRangeIntrinsicRangeValue(rangeCall: ResolvedCall<o
|
||||
): InExpressionGenerator {
|
||||
val comparisonGenerator = getComparisonGeneratorForRangeContainsCall(codegen, resolvedCall)
|
||||
return if (comparisonGenerator != null)
|
||||
InPrimitiveContinuousRangeExpressionGenerator(operatorReference, getBoundedValue(codegen), comparisonGenerator)
|
||||
InPrimitiveContinuousRangeExpressionGenerator(
|
||||
operatorReference, getBoundedValue(codegen), comparisonGenerator, codegen.frameMap
|
||||
)
|
||||
else
|
||||
CallBasedInExpressionGenerator(codegen, operatorReference)
|
||||
}
|
||||
|
||||
+79
-70
@@ -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.ObjectComparisonGenerator
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
@@ -30,7 +27,8 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
class InContinuousRangeOfComparableExpressionGenerator(
|
||||
operatorReference: KtSimpleNameExpression,
|
||||
private val boundedValue: BoundedValue
|
||||
private val boundedValue: BoundedValue,
|
||||
private val frameMap: FrameMap
|
||||
) : InExpressionGenerator {
|
||||
private val isNotIn = operatorReference.getReferencedNameElementType() == KtTokens.NOT_IN
|
||||
private val comparisonGenerator = ObjectComparisonGenerator
|
||||
@@ -52,84 +50,95 @@ class InContinuousRangeOfComparableExpressionGenerator(
|
||||
private fun genJumpIfTrue(v: InstructionAdapter, jumpLabel: Label) {
|
||||
// if (arg is in range) goto jumpLabel
|
||||
|
||||
val exitLabel1 = Label()
|
||||
val exitLabel2 = Label()
|
||||
frameMap.useTmpVar(operandType) { arg1Var ->
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+72
-64
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user