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 { fun isSideEffectFree(call: IrCall): Boolean {
return false return false
} }
val preferJavaLikeCounterLoop: Boolean
get() = false
} }
@@ -252,6 +252,8 @@ class ProgressionLoopHeader(
context: CommonBackendContext context: CommonBackendContext
) : NumericForLoopHeader<ProgressionHeaderInfo>(headerInfo, builder, context) { ) : NumericForLoopHeader<ProgressionHeaderInfo>(headerInfo, builder, context) {
private val preferJavaLikeCounterLoop = context.preferJavaLikeCounterLoop
// For this loop: // For this loop:
// //
// for (i in first()..last() step step()) // for (i in first()..last() step step())
@@ -331,7 +333,7 @@ class ProgressionLoopHeader(
val loopCondition = buildLoopCondition(this@with) val loopCondition = buildLoopCondition(this@with)
LoopReplacement(newLoop, irIfThen(loopCondition, newLoop)) 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 // 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) { ... }`). // (`for (int i = first; i < lastExclusive; ++i) { ... }`).
// Otherwise loop-related optimizations will not kick in, resulting in significant performance degradation. // 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.builders.irInt
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.expressions.IrCall 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.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.getPropertyGetter 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) : internal abstract class IndicesHandler(protected val context: CommonBackendContext) :
ProgressionHandler { ProgressionHandler {
private val preferJavaLikeCounterLoop = context.preferJavaLikeCounterLoop
override fun build(expression: IrCall, data: ProgressionType, scopeOwner: IrSymbol): HeaderInfo? = override fun build(expression: IrCall, data: ProgressionType, scopeOwner: IrSymbol): HeaderInfo? =
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) { 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: IrExpression
val last = irCall(expression.symbol.owner.extensionReceiverParameter!!.type.sizePropertyGetter) val lastInclusive: IrExpression?
.apply { dispatchReceiver = expression.extensionReceiver!! } 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( ProgressionHeaderInfo(
data, data,
first = irInt(0), first = irInt(0),
last = last, last = last,
step = irInt(1), step = irInt(1),
isLastInclusive = false, isLastInclusive = isLastInclusive,
canOverflow = false, canOverflow = false,
direction = ProgressionDirection.INCREASING, 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) : internal class RangeToHandler(private val context: CommonBackendContext) :
ProgressionHandler { ProgressionHandler {
private val preferJavaLikeCounterLoop = context.preferJavaLikeCounterLoop
private val progressionElementTypes = context.ir.symbols.progressionElementTypes private val progressionElementTypes = context.ir.symbols.progressionElementTypes
override val matcher = SimpleCalleeMatcher { override val matcher = SimpleCalleeMatcher {
@@ -39,9 +41,9 @@ internal class RangeToHandler(private val context: CommonBackendContext) :
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) { with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
val last = expression.getValueArgument(0)!! val last = expression.getValueArgument(0)!!
// Convert range with inclusive upper bound to exclusive upper bound if possible. if (preferJavaLikeCounterLoop && canUseExclusiveUpperBound(last, data)) {
// This affects loop code performance on JVM. // Convert range with inclusive upper bound to exclusive upper bound if possible.
if (canUseExclusiveUpperBound(last, data)) { // This affects loop code performance on JVM.
val lastExclusive = last.convertToExclusiveUpperBound() val lastExclusive = last.convertToExclusiveUpperBound()
if (lastExclusive != null) { if (lastExclusive != null) {
return@with ProgressionHeaderInfo( return@with ProgressionHeaderInfo(
@@ -212,6 +212,9 @@ class JvmBackendContext(
super.handleDeepCopy(fileSymbolMap, classSymbolMap, functionSymbolMap) super.handleDeepCopy(fileSymbolMap, classSymbolMap, functionSymbolMap)
} }
override val preferJavaLikeCounterLoop: Boolean
get() = true
inner class JvmIr( inner class JvmIr(
irModuleFragment: IrModuleFragment, irModuleFragment: IrModuleFragment,
symbolTable: SymbolTable symbolTable: SymbolTable