[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.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()
|
||||
|
||||
Reference in New Issue
Block a user