JVM_IR configure loop shape in the backend context

This commit is contained in:
Dmitry Petrov
2021-07-29 08:38:11 +03:00
committed by teamcityserver
parent 38d6c8ded0
commit b93dff003f
5 changed files with 37 additions and 9 deletions
@@ -50,4 +50,7 @@ interface CommonBackendContext : BackendContext, LoggingContext {
fun isSideEffectFree(call: IrCall): Boolean {
return false
}
val preferJavaLikeCounterLoop: Boolean
get() = false
}
@@ -252,6 +252,8 @@ class ProgressionLoopHeader(
context: CommonBackendContext
) : NumericForLoopHeader<ProgressionHeaderInfo>(headerInfo, builder, context) {
private val preferJavaLikeCounterLoop = context.preferJavaLikeCounterLoop
// For this loop:
//
// for (i in first()..last() step step())
@@ -331,7 +333,7 @@ class ProgressionLoopHeader(
val loopCondition = buildLoopCondition(this@with)
LoopReplacement(newLoop, irIfThen(loopCondition, newLoop))
} else if (!headerInfo.isLastInclusive) {
} else if (preferJavaLikeCounterLoop && !headerInfo.isLastInclusive) {
// It is critically important for loop code performance on JVM to "look like" a simple counter loop in Java when possible
// (`for (int i = first; i < lastExclusive; ++i) { ... }`).
// Otherwise loop-related optimizations will not kick in, resulting in significant performance degradation.
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.builders.irInt
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.getPropertyGetter
@@ -23,21 +24,38 @@ import org.jetbrains.kotlin.name.FqName
internal abstract class IndicesHandler(protected val context: CommonBackendContext) :
ProgressionHandler {
private val preferJavaLikeCounterLoop = context.preferJavaLikeCounterLoop
override fun build(expression: IrCall, data: ProgressionType, scopeOwner: IrSymbol): HeaderInfo? =
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
// `last = array.size - 1` (last is inclusive) for the loop `for (i in array.indices)`.
val last = irCall(expression.symbol.owner.extensionReceiverParameter!!.type.sizePropertyGetter)
.apply { dispatchReceiver = expression.extensionReceiver!! }
val last: IrExpression
val lastInclusive: IrExpression?
val isLastInclusive: Boolean
if (preferJavaLikeCounterLoop) {
// Convert range with inclusive upper bound to exclusive upper bound if possible.
// This affects loop code performance on JVM.
last = irCall(expression.symbol.owner.extensionReceiverParameter!!.type.sizePropertyGetter)
.apply { dispatchReceiver = expression.extensionReceiver!! }
lastInclusive = last.decrement()
isLastInclusive = false
} else {
last = irCall(expression.symbol.owner.extensionReceiverParameter!!.type.sizePropertyGetter)
.apply { dispatchReceiver = expression.extensionReceiver!! }
.decrement()
lastInclusive = null
isLastInclusive = true
}
ProgressionHeaderInfo(
data,
first = irInt(0),
last = last,
step = irInt(1),
isLastInclusive = false,
isLastInclusive = isLastInclusive,
canOverflow = false,
direction = ProgressionDirection.INCREASING,
originalLastInclusive = last.decrement()
originalLastInclusive = lastInclusive
)
}
@@ -26,6 +26,8 @@ import org.jetbrains.kotlin.util.OperatorNameConventions
internal class RangeToHandler(private val context: CommonBackendContext) :
ProgressionHandler {
private val preferJavaLikeCounterLoop = context.preferJavaLikeCounterLoop
private val progressionElementTypes = context.ir.symbols.progressionElementTypes
override val matcher = SimpleCalleeMatcher {
@@ -39,9 +41,9 @@ internal class RangeToHandler(private val context: CommonBackendContext) :
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
val last = expression.getValueArgument(0)!!
// Convert range with inclusive upper bound to exclusive upper bound if possible.
// This affects loop code performance on JVM.
if (canUseExclusiveUpperBound(last, data)) {
if (preferJavaLikeCounterLoop && canUseExclusiveUpperBound(last, data)) {
// Convert range with inclusive upper bound to exclusive upper bound if possible.
// This affects loop code performance on JVM.
val lastExclusive = last.convertToExclusiveUpperBound()
if (lastExclusive != null) {
return@with ProgressionHeaderInfo(
@@ -212,6 +212,9 @@ class JvmBackendContext(
super.handleDeepCopy(fileSymbolMap, classSymbolMap, functionSymbolMap)
}
override val preferJavaLikeCounterLoop: Boolean
get() = true
inner class JvmIr(
irModuleFragment: IrModuleFragment,
symbolTable: SymbolTable