[K/N] Supported ..< operator for BCE optimization

This commit is contained in:
Igor Chevdar
2023-01-25 17:18:12 +02:00
committed by Space Team
parent f87c5cf166
commit 29b7a8e435
2 changed files with 58 additions and 10 deletions
@@ -13,13 +13,13 @@ import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
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.types.IrType
import org.jetbrains.kotlin.ir.types.getClass
import org.jetbrains.kotlin.ir.types.isArray
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.util.OperatorNameConventions
// Base class describing value of expression.
@@ -194,6 +194,8 @@ class KonanBCEForLoopBodyTransformer : ForLoopBodyTransformer() {
(symbol.signature as? IdSignature.AccessorSignature)?.propertySignature?.asPublic()?.shortName == propertyName &&
dispatchReceiver?.type?.getClass()?.symbol in context.ir.symbols.progressionClasses
private val untilFqName = FqName("kotlin.ranges.until")
private fun analyzeLoopHeader(loopHeader: ForLoopHeader): BoundsCheckAnalysisResult {
var analysisResult = BoundsCheckAnalysisResult(false, null)
when (loopHeader) {
@@ -247,21 +249,27 @@ class KonanBCEForLoopBodyTransformer : ForLoopBodyTransformer() {
analysisResult = checkIrCallCondition(loopHeader.headerInfo.first, ::lessThanSize)
}
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") &&
loopHeader.headerInfo.last.isProgressionPropertyGetter("last")) {
val firstReceiver = (loopHeader.headerInfo.first as IrCall).dispatchReceiver as? IrGetValue
val lastReceiver = (loopHeader.headerInfo.last as IrCall).dispatchReceiver as? IrGetValue
if (firstReceiver?.symbol?.owner == lastReceiver?.symbol?.owner) {
val untilFunction =
((firstReceiver?.symbol?.owner as? IrVariable)?.initializer as? IrCall)?.extensionReceiver as? IrCall
if (untilFunction?.symbol?.owner?.name?.asString() == "until" && untilFunction.extensionReceiver?.compareIntegerNumericConst { it >= 0 } == true) {
val last = untilFunction.getValueArgument(0)!!
val firstReceiver = ((loopHeader.headerInfo.first as IrCall).dispatchReceiver as? IrGetValue)?.symbol?.owner
val lastReceiver = ((loopHeader.headerInfo.last as IrCall).dispatchReceiver as? IrGetValue)?.symbol?.owner
if (firstReceiver == lastReceiver) {
val createRange = ((firstReceiver as? IrVariable)?.initializer as? IrCall)?.extensionReceiver as? IrCall
val first = createRange?.symbol?.owner?.let {
when {
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 ->
// `isLastInclusive` for current case is set to true.
// This case isn't fully optimized in ForLoopsLowering.
if (call.isGetSizeCall())
BoundsCheckAnalysisResult(true, call.dispatchReceiver?.let { findExpressionValueDescription(it) } )
BoundsCheckAnalysisResult(true, call.dispatchReceiver?.let { findExpressionValueDescription(it) })
else
lessThanSize(call)
}
@@ -26,6 +26,18 @@ fun forUntilSize() {
}
// 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(){}"()
fun forDownToSize() {
val array = Array(10) { 0L }
@@ -87,6 +99,18 @@ fun forUntilWithStep() {
}
// 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(){}"()
fun forDownToWithStep() {
val array = UIntArray(10) { 0U }
@@ -132,6 +156,18 @@ fun forReversed() {
}
// 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
// CHECK-LABEL: define void @"kfun:#forEachCall(){}"()
@@ -274,17 +310,21 @@ fun chainedReceivers() {
}
// CHECK-LABEL: {{^}}epilogue:
@ExperimentalStdlibApi
fun main() {
forEachIndicies()
forUntilSize()
forRangeUntilSize()
forDownToSize()
forRangeToSize()
forRangeToWithStep()
forUntilWithStep()
forRangeUntilWithStep()
forDownToWithStep()
forIndiciesWithStep()
forWithIndex()
forReversed()
forRangeUntilReversed()
forEachCall()
forLoop()
innerLoop()