[K/N] Supported ..< operator for BCE optimization
This commit is contained in:
+18
-10
@@ -13,13 +13,13 @@ import org.jetbrains.kotlin.ir.expressions.*
|
|||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
|
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
import org.jetbrains.kotlin.ir.types.getClass
|
import org.jetbrains.kotlin.ir.types.getClass
|
||||||
import org.jetbrains.kotlin.ir.types.isArray
|
import org.jetbrains.kotlin.ir.types.isArray
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
|
|
||||||
// Base class describing value of expression.
|
// Base class describing value of expression.
|
||||||
@@ -194,6 +194,8 @@ class KonanBCEForLoopBodyTransformer : ForLoopBodyTransformer() {
|
|||||||
(symbol.signature as? IdSignature.AccessorSignature)?.propertySignature?.asPublic()?.shortName == propertyName &&
|
(symbol.signature as? IdSignature.AccessorSignature)?.propertySignature?.asPublic()?.shortName == propertyName &&
|
||||||
dispatchReceiver?.type?.getClass()?.symbol in context.ir.symbols.progressionClasses
|
dispatchReceiver?.type?.getClass()?.symbol in context.ir.symbols.progressionClasses
|
||||||
|
|
||||||
|
private val untilFqName = FqName("kotlin.ranges.until")
|
||||||
|
|
||||||
private fun analyzeLoopHeader(loopHeader: ForLoopHeader): BoundsCheckAnalysisResult {
|
private fun analyzeLoopHeader(loopHeader: ForLoopHeader): BoundsCheckAnalysisResult {
|
||||||
var analysisResult = BoundsCheckAnalysisResult(false, null)
|
var analysisResult = BoundsCheckAnalysisResult(false, null)
|
||||||
when (loopHeader) {
|
when (loopHeader) {
|
||||||
@@ -247,21 +249,27 @@ class KonanBCEForLoopBodyTransformer : ForLoopBodyTransformer() {
|
|||||||
analysisResult = checkIrCallCondition(loopHeader.headerInfo.first, ::lessThanSize)
|
analysisResult = checkIrCallCondition(loopHeader.headerInfo.first, ::lessThanSize)
|
||||||
}
|
}
|
||||||
ProgressionDirection.UNKNOWN ->
|
ProgressionDirection.UNKNOWN ->
|
||||||
// Case of progression - for (i in 0 until array.size step n)
|
// Case of progression - for (i in 0 until array.size step n) or for (i in 0..<array.size step n)
|
||||||
if (loopHeader.headerInfo.first.isProgressionPropertyGetter("first") &&
|
if (loopHeader.headerInfo.first.isProgressionPropertyGetter("first") &&
|
||||||
loopHeader.headerInfo.last.isProgressionPropertyGetter("last")) {
|
loopHeader.headerInfo.last.isProgressionPropertyGetter("last")) {
|
||||||
val firstReceiver = (loopHeader.headerInfo.first as IrCall).dispatchReceiver as? IrGetValue
|
val firstReceiver = ((loopHeader.headerInfo.first as IrCall).dispatchReceiver as? IrGetValue)?.symbol?.owner
|
||||||
val lastReceiver = (loopHeader.headerInfo.last as IrCall).dispatchReceiver as? IrGetValue
|
val lastReceiver = ((loopHeader.headerInfo.last as IrCall).dispatchReceiver as? IrGetValue)?.symbol?.owner
|
||||||
if (firstReceiver?.symbol?.owner == lastReceiver?.symbol?.owner) {
|
if (firstReceiver == lastReceiver) {
|
||||||
val untilFunction =
|
val createRange = ((firstReceiver as? IrVariable)?.initializer as? IrCall)?.extensionReceiver as? IrCall
|
||||||
((firstReceiver?.symbol?.owner as? IrVariable)?.initializer as? IrCall)?.extensionReceiver as? IrCall
|
val first = createRange?.symbol?.owner?.let {
|
||||||
if (untilFunction?.symbol?.owner?.name?.asString() == "until" && untilFunction.extensionReceiver?.compareIntegerNumericConst { it >= 0 } == true) {
|
when {
|
||||||
val last = untilFunction.getValueArgument(0)!!
|
it.fqNameWhenAvailable == untilFqName -> createRange.extensionReceiver
|
||||||
|
createRange.origin == IrStatementOrigin.RANGE_UNTIL -> createRange.dispatchReceiver
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (first?.compareIntegerNumericConst { it >= 0 } == true) {
|
||||||
|
val last = createRange.getValueArgument(0)!!
|
||||||
analysisResult = checkIrCallCondition(last) { call ->
|
analysisResult = checkIrCallCondition(last) { call ->
|
||||||
// `isLastInclusive` for current case is set to true.
|
// `isLastInclusive` for current case is set to true.
|
||||||
// This case isn't fully optimized in ForLoopsLowering.
|
// This case isn't fully optimized in ForLoopsLowering.
|
||||||
if (call.isGetSizeCall())
|
if (call.isGetSizeCall())
|
||||||
BoundsCheckAnalysisResult(true, call.dispatchReceiver?.let { findExpressionValueDescription(it) } )
|
BoundsCheckAnalysisResult(true, call.dispatchReceiver?.let { findExpressionValueDescription(it) })
|
||||||
else
|
else
|
||||||
lessThanSize(call)
|
lessThanSize(call)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,18 @@ fun forUntilSize() {
|
|||||||
}
|
}
|
||||||
// CHECK-LABEL: {{^}}epilogue:
|
// CHECK-LABEL: {{^}}epilogue:
|
||||||
|
|
||||||
|
// CHECK-LABEL: define void @"kfun:#forRangeUntilSize(){}"()
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
fun forRangeUntilSize() {
|
||||||
|
val array = Array(10) { 0L }
|
||||||
|
// CHECK: {{^}}do_while_loop{{.*}}:
|
||||||
|
for (i in 0..<array.size) {
|
||||||
|
// CHECK: {{call|invoke}} void @Kotlin_Array_set_without_BoundCheck
|
||||||
|
array[i] = 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// CHECK-LABEL: {{^}}epilogue:
|
||||||
|
|
||||||
// CHECK-LABEL: define void @"kfun:#forDownToSize(){}"()
|
// CHECK-LABEL: define void @"kfun:#forDownToSize(){}"()
|
||||||
fun forDownToSize() {
|
fun forDownToSize() {
|
||||||
val array = Array(10) { 0L }
|
val array = Array(10) { 0L }
|
||||||
@@ -87,6 +99,18 @@ fun forUntilWithStep() {
|
|||||||
}
|
}
|
||||||
// CHECK-LABEL: {{^}}epilogue:
|
// CHECK-LABEL: {{^}}epilogue:
|
||||||
|
|
||||||
|
// CHECK-LABEL: define void @"kfun:#forRangeUntilWithStep(){}"()
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
fun forRangeUntilWithStep() {
|
||||||
|
val array = CharArray(10) { '0' }
|
||||||
|
// CHECK: {{^}}do_while_loop{{.*}}:
|
||||||
|
for (i in 0..<array.size step 2) {
|
||||||
|
// CHECK: {{call|invoke}} void @Kotlin_CharArray_set_without_BoundCheck
|
||||||
|
array[i] = '6'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// CHECK-LABEL: {{^}}epilogue:
|
||||||
|
|
||||||
// CHECK-LABEL: define void @"kfun:#forDownToWithStep(){}"()
|
// CHECK-LABEL: define void @"kfun:#forDownToWithStep(){}"()
|
||||||
fun forDownToWithStep() {
|
fun forDownToWithStep() {
|
||||||
val array = UIntArray(10) { 0U }
|
val array = UIntArray(10) { 0U }
|
||||||
@@ -132,6 +156,18 @@ fun forReversed() {
|
|||||||
}
|
}
|
||||||
// CHECK-LABEL: {{^}}epilogue:
|
// CHECK-LABEL: {{^}}epilogue:
|
||||||
|
|
||||||
|
// CHECK-LABEL: define void @"kfun:#forRangeUntilReversed(){}"()
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
fun forRangeUntilReversed() {
|
||||||
|
val array = Array(10) { 100 }
|
||||||
|
// CHECK: {{^}}do_while_loop{{.*}}:
|
||||||
|
for (i in (0..<array.size).reversed()) {
|
||||||
|
// CHECK: {{call|invoke}} void @Kotlin_Array_set_without_BoundCheck
|
||||||
|
array[i] = 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// CHECK-LABEL: {{^}}epilogue:
|
||||||
|
|
||||||
fun foo(a: Int, b : Int): Int = a + b * 2
|
fun foo(a: Int, b : Int): Int = a + b * 2
|
||||||
|
|
||||||
// CHECK-LABEL: define void @"kfun:#forEachCall(){}"()
|
// CHECK-LABEL: define void @"kfun:#forEachCall(){}"()
|
||||||
@@ -274,17 +310,21 @@ fun chainedReceivers() {
|
|||||||
}
|
}
|
||||||
// CHECK-LABEL: {{^}}epilogue:
|
// CHECK-LABEL: {{^}}epilogue:
|
||||||
|
|
||||||
|
@ExperimentalStdlibApi
|
||||||
fun main() {
|
fun main() {
|
||||||
forEachIndicies()
|
forEachIndicies()
|
||||||
forUntilSize()
|
forUntilSize()
|
||||||
|
forRangeUntilSize()
|
||||||
forDownToSize()
|
forDownToSize()
|
||||||
forRangeToSize()
|
forRangeToSize()
|
||||||
forRangeToWithStep()
|
forRangeToWithStep()
|
||||||
forUntilWithStep()
|
forUntilWithStep()
|
||||||
|
forRangeUntilWithStep()
|
||||||
forDownToWithStep()
|
forDownToWithStep()
|
||||||
forIndiciesWithStep()
|
forIndiciesWithStep()
|
||||||
forWithIndex()
|
forWithIndex()
|
||||||
forReversed()
|
forReversed()
|
||||||
|
forRangeUntilReversed()
|
||||||
forEachCall()
|
forEachCall()
|
||||||
forLoop()
|
forLoop()
|
||||||
innerLoop()
|
innerLoop()
|
||||||
|
|||||||
Reference in New Issue
Block a user