[JS BE] Reduce temporary variable number produced during lowering
- Do not create temporary variable for pure expressions - Clean up unused and unreachable r-value on top level of statement block
This commit is contained in:
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.descriptors.Modality
|
|||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
import org.jetbrains.kotlin.ir.builders.Scope
|
import org.jetbrains.kotlin.ir.builders.Scope
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
@@ -605,4 +606,4 @@ fun copyBodyWithParametersMapping(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val IrSymbol.isSuspend: Boolean
|
val IrSymbol.isSuspend: Boolean
|
||||||
get() = this is IrSimpleFunctionSymbol && owner.isSuspend
|
get() = this is IrSimpleFunctionSymbol && owner.isSuspend
|
||||||
|
|||||||
+46
@@ -13,10 +13,12 @@ import org.jetbrains.kotlin.ir.IrElement
|
|||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.isPure
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
|
import org.jetbrains.kotlin.ir.types.isNothing
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
@@ -51,6 +53,49 @@ abstract class AbstractBlockDecomposerLowering(context: CommonBackendContext) :
|
|||||||
else -> listOf(declaration)
|
else -> listOf(declaration)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
irDeclarationContainer.transformChildrenVoid(CodeCleaner())
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class CodeCleaner : IrElementTransformerVoid() {
|
||||||
|
|
||||||
|
private fun IrStatementContainer.cleanUpStatements() {
|
||||||
|
var unreachable = false
|
||||||
|
|
||||||
|
val newStatements = statements.filter {
|
||||||
|
when {
|
||||||
|
unreachable -> false
|
||||||
|
it.isPure(true) -> false
|
||||||
|
it is IrGetField -> it.receiver?.let { !it.isPure(true) } ?: false
|
||||||
|
else -> {
|
||||||
|
unreachable = it is IrExpression && it.type.isNothing()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
statements.clear()
|
||||||
|
|
||||||
|
statements += newStatements
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitBlock(expression: IrBlock): IrExpression {
|
||||||
|
expression.transformChildrenVoid(this)
|
||||||
|
expression.cleanUpStatements()
|
||||||
|
return expression
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitBlockBody(body: IrBlockBody): IrBody {
|
||||||
|
body.transformChildrenVoid(this)
|
||||||
|
body.cleanUpStatements()
|
||||||
|
return body
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitComposite(expression: IrComposite): IrExpression {
|
||||||
|
expression.transformChildrenVoid(this)
|
||||||
|
expression.cleanUpStatements()
|
||||||
|
return expression
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun lower(irScript: IrScript) {
|
fun lower(irScript: IrScript) {
|
||||||
@@ -527,6 +572,7 @@ class BlockDecomposerTransformer(
|
|||||||
compositesLeft == 0 -> value
|
compositesLeft == 0 -> value
|
||||||
index == 0 && dontDetachFirstArgument -> value
|
index == 0 && dontDetachFirstArgument -> value
|
||||||
value == null -> value
|
value == null -> value
|
||||||
|
value.isPure(false) -> value
|
||||||
else -> {
|
else -> {
|
||||||
// TODO: do not wrap if value is pure (const, variable, etc)
|
// TODO: do not wrap if value is pure (const, variable, etc)
|
||||||
val irVar = makeTempVar(value.type, value)
|
val irVar = makeTempVar(value.type, value)
|
||||||
|
|||||||
+8
-3
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.ir.IrStatement
|
|||||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrArithBuilder
|
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrArithBuilder
|
||||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.isPure
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationParent
|
import org.jetbrains.kotlin.ir.declarations.IrDeclarationParent
|
||||||
@@ -200,9 +201,13 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
|||||||
newStatements: MutableList<IrStatement>,
|
newStatements: MutableList<IrStatement>,
|
||||||
declaration: IrDeclarationParent
|
declaration: IrDeclarationParent
|
||||||
): () -> IrExpressionWithCopy {
|
): () -> IrExpressionWithCopy {
|
||||||
val varDeclaration = JsIrBuilder.buildVar(value.type, declaration, initializer = value)
|
return if (value.isPure(true)) {
|
||||||
newStatements += varDeclaration
|
{ value.deepCopyWithSymbols() as IrExpressionWithCopy }
|
||||||
return { JsIrBuilder.buildGetValue(varDeclaration.symbol) }
|
} else {
|
||||||
|
val varDeclaration = JsIrBuilder.buildVar(value.type, declaration, initializer = value)
|
||||||
|
newStatements += varDeclaration
|
||||||
|
{ JsIrBuilder.buildGetValue(varDeclaration.symbol) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateTypeCheck(argument: () -> IrExpressionWithCopy, toType: IrType): IrExpression {
|
private fun generateTypeCheck(argument: () -> IrExpressionWithCopy, toType: IrType): IrExpression {
|
||||||
|
|||||||
@@ -6,14 +6,19 @@
|
|||||||
package org.jetbrains.kotlin.ir.backend.js.utils
|
package org.jetbrains.kotlin.ir.backend.js.utils
|
||||||
|
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrGetObjectValue
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrGetValue
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
import org.jetbrains.kotlin.ir.types.isNullableAny
|
import org.jetbrains.kotlin.ir.types.isNullableAny
|
||||||
|
import org.jetbrains.kotlin.ir.types.isUnit
|
||||||
import org.jetbrains.kotlin.ir.util.isTopLevelDeclaration
|
import org.jetbrains.kotlin.ir.util.isTopLevelDeclaration
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
@@ -38,4 +43,19 @@ fun List<IrExpression>.toJsArrayLiteral(context: JsIrBackendContext, arrayType:
|
|||||||
return IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, arrayType, context.intrinsics.arrayLiteral).apply {
|
return IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, arrayType, context.intrinsics.arrayLiteral).apply {
|
||||||
putValueArgument(0, irVararg)
|
putValueArgument(0, irVararg)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: support more cases like built-in operator call, getField and so on
|
||||||
|
fun IrStatement.isPure(anyVariable: Boolean): Boolean {
|
||||||
|
return when (this) {
|
||||||
|
is IrConst<*> -> true
|
||||||
|
is IrGetValue -> {
|
||||||
|
if (anyVariable) return true
|
||||||
|
val valueDeclaration = symbol.owner
|
||||||
|
if (valueDeclaration is IrVariable) !valueDeclaration.isVar
|
||||||
|
else true
|
||||||
|
}
|
||||||
|
is IrGetObjectValue -> type.isUnit()
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user