IR: simplify phaser code a little

- merge NamedCompilerPhase, SameTypeNamedPhaseWrapper,
  AbstractNamedPhaseWrapper and inherit it from SameTypeCompilerPhase
- inline some functions to simplify stacktraces
- reformat and fix inspections
This commit is contained in:
Alexander Udalov
2020-07-01 01:18:07 +02:00
parent 74ce26cdc2
commit ef58f1e72e
4 changed files with 53 additions and 103 deletions
@@ -18,8 +18,7 @@ class PhaserState<Data>(
// Copy state, forgetting the sticky postconditions (which will not be applicable to the new type) // Copy state, forgetting the sticky postconditions (which will not be applicable to the new type)
fun <Input, Output> PhaserState<Input>.changeType() = PhaserState<Output>(alreadyDone, depth, phaseCount, mutableSetOf()) fun <Input, Output> PhaserState<Input>.changeType() = PhaserState<Output>(alreadyDone, depth, phaseCount, mutableSetOf())
inline fun <R, D> PhaserState<D>.downlevel(nlevels: Int, block: () -> R): R {
fun <R, D> PhaserState<D>.downlevel(nlevels: Int = 1, block: () -> R): R {
depth += nlevels depth += nlevels
val result = block() val result = block()
depth -= nlevels depth -= nlevels
@@ -35,28 +34,19 @@ interface CompilerPhase<in Context : CommonBackendContext, Input, Output> {
val stickyPostconditions: Set<Checker<Output>> get() = emptySet() val stickyPostconditions: Set<Checker<Output>> get() = emptySet()
} }
fun <Context: CommonBackendContext, Input, Output> CompilerPhase<Context, Input, Output>.invokeToplevel( fun <Context : CommonBackendContext, Input, Output> CompilerPhase<Context, Input, Output>.invokeToplevel(
phaseConfig: PhaseConfig, phaseConfig: PhaseConfig,
context: Context, context: Context,
input: Input input: Input
): Output = invoke(phaseConfig, PhaserState(), context, input) ): Output = invoke(phaseConfig, PhaserState(), context, input)
interface SameTypeCompilerPhase<in Context: CommonBackendContext, Data> : CompilerPhase<Context, Data, Data> interface SameTypeCompilerPhase<in Context : CommonBackendContext, Data> : CompilerPhase<Context, Data, Data>
// A failing checker should just throw an exception. // A failing checker should just throw an exception.
typealias Checker<Data> = (Data) -> Unit typealias Checker<Data> = (Data) -> Unit
interface NamedCompilerPhase<in Context : CommonBackendContext, Input, Output> : CompilerPhase<Context, Input, Output> { typealias AnyNamedPhase = NamedCompilerPhase<*, *>
val name: String
val description: String
val prerequisite: Set<AnyNamedPhase> get() = emptySet()
val preconditions: Set<Checker<Input>>
val postconditions: Set<Checker<Output>>
val actionsBefore: Set<Action<Input, Context>>
val actionsAfter: Set<Action<Output, Context>>
}
typealias AnyNamedPhase = NamedCompilerPhase<*, *, *>
enum class BeforeOrAfter { BEFORE, AFTER } enum class BeforeOrAfter { BEFORE, AFTER }
data class ActionState( data class ActionState(
@@ -74,25 +64,20 @@ infix operator fun <Data, Context> Action<Data, Context>.plus(other: Action<Data
other(phaseState, data, context) other(phaseState, data, context)
} }
abstract class AbstractNamedPhaseWrapper<in Context : CommonBackendContext, Input, Output>( class NamedCompilerPhase<in Context : CommonBackendContext, Data>(
override val name: String, val name: String,
override val description: String, val description: String,
override val prerequisite: Set<AnyNamedPhase>, val prerequisite: Set<AnyNamedPhase>,
private val lower: CompilerPhase<Context, Input, Output>, private val lower: CompilerPhase<Context, Data, Data>,
override val preconditions: Set<Checker<Input>> = emptySet(), val preconditions: Set<Checker<Data>> = emptySet(),
override val postconditions: Set<Checker<Output>> = emptySet(), val postconditions: Set<Checker<Data>> = emptySet(),
override val stickyPostconditions: Set<Checker<Output>> = emptySet(), override val stickyPostconditions: Set<Checker<Data>> = emptySet(),
override val actionsBefore: Set<Action<Input, Context>> = emptySet(), private val actions: Set<Action<Data, Context>> = emptySet(),
override val actionsAfter: Set<Action<Output, Context>> = emptySet(),
private val nlevels: Int = 0 private val nlevels: Int = 0
) : NamedCompilerPhase<Context, Input, Output> { ) : SameTypeCompilerPhase<Context, Data> {
override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<Data>, context: Context, input: Data): Data {
override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<Input>, context: Context, input: Input): Output { if (this !in phaseConfig.enabled) {
if (this is SameTypeCompilerPhase<*, *> && return input
this !in phaseConfig.enabled
) {
@Suppress("UNCHECKED_CAST")
return input as Output
} }
assert(phaserState.alreadyDone.containsAll(prerequisite)) { assert(phaserState.alreadyDone.containsAll(prerequisite)) {
@@ -102,7 +87,13 @@ abstract class AbstractNamedPhaseWrapper<in Context : CommonBackendContext, Inpu
context.inVerbosePhase = this in phaseConfig.verbose context.inVerbosePhase = this in phaseConfig.verbose
runBefore(phaseConfig, phaserState, context, input) runBefore(phaseConfig, phaserState, context, input)
val output = runBody(phaseConfig, phaserState, context, input) val output = if (phaseConfig.needProfiling) {
runAndProfile(phaseConfig, phaserState, context, input)
} else {
phaserState.downlevel(nlevels) {
lower.invoke(phaseConfig, phaserState, context, input)
}
}
runAfter(phaseConfig, phaserState, context, output) runAfter(phaseConfig, phaserState, context, output)
phaserState.alreadyDone.add(this) phaserState.alreadyDone.add(this)
@@ -111,41 +102,30 @@ abstract class AbstractNamedPhaseWrapper<in Context : CommonBackendContext, Inpu
return output return output
} }
private fun runBefore(phaseConfig: PhaseConfig, phaserState: PhaserState<Input>, context: Context, input: Input) { private fun runBefore(phaseConfig: PhaseConfig, phaserState: PhaserState<Data>, context: Context, input: Data) {
val state = ActionState(phaseConfig, this, phaserState.phaseCount, BeforeOrAfter.BEFORE) val state = ActionState(phaseConfig, this, phaserState.phaseCount, BeforeOrAfter.BEFORE)
for (action in actionsBefore) action(state, input, context) for (action in actions) action(state, input, context)
if (phaseConfig.checkConditions) { if (phaseConfig.checkConditions) {
for (pre in preconditions) pre(input) for (pre in preconditions) pre(input)
} }
} }
private fun runBody(phaseConfig: PhaseConfig, phaserState: PhaserState<Input>, context: Context, input: Input): Output { private fun runAfter(phaseConfig: PhaseConfig, phaserState: PhaserState<Data>, context: Context, output: Data) {
return if (phaseConfig.needProfiling) {
runAndProfile(phaseConfig, phaserState, context, input)
} else {
phaserState.downlevel(nlevels) {
lower.invoke(phaseConfig, phaserState, context, input)
}
}
}
private fun runAfter(phaseConfig: PhaseConfig, phaserState: PhaserState<Input>, context: Context, output: Output) {
val state = ActionState(phaseConfig, this, phaserState.phaseCount, BeforeOrAfter.AFTER) val state = ActionState(phaseConfig, this, phaserState.phaseCount, BeforeOrAfter.AFTER)
for (action in actionsAfter) action(state, output, context) for (action in actions) action(state, output, context)
if (phaseConfig.checkConditions) { if (phaseConfig.checkConditions) {
for (post in postconditions) post(output) for (post in postconditions) post(output)
for (post in stickyPostconditions) post(output) for (post in stickyPostconditions) post(output)
if (phaseConfig.checkStickyConditions && this is SameTypeCompilerPhase<*, *>) { if (phaseConfig.checkStickyConditions) {
@Suppress("UNCHECKED_CAST") val phaserStateO = phaserState as PhaserState<Output> for (post in phaserState.stickyPostconditions) post(output)
for (post in phaserStateO.stickyPostconditions) post(output)
} }
} }
} }
private fun runAndProfile(phaseConfig: PhaseConfig, phaserState: PhaserState<Input>, context: Context, source: Input): Output { private fun runAndProfile(phaseConfig: PhaseConfig, phaserState: PhaserState<Data>, context: Context, source: Data): Data {
var result: Output? = null var result: Data? = null
val msec = measureTimeMillis { val msec = measureTimeMillis {
result = phaserState.downlevel(nlevels) { result = phaserState.downlevel(nlevels) {
lower.invoke(phaseConfig, phaserState, context, source) lower.invoke(phaseConfig, phaserState, context, source)
@@ -156,26 +136,8 @@ abstract class AbstractNamedPhaseWrapper<in Context : CommonBackendContext, Inpu
return result!! return result!!
} }
private fun checkAndRun(set: Set<AnyNamedPhase>, block: () -> Unit) { override fun getNamedSubphases(startDepth: Int): List<Pair<Int, NamedCompilerPhase<*, *>>> =
if (this in set) block()
}
override fun getNamedSubphases(startDepth: Int): List<Pair<Int, NamedCompilerPhase<*, *, *>>> =
listOf(startDepth to this) + lower.getNamedSubphases(startDepth + nlevels) listOf(startDepth to this) + lower.getNamedSubphases(startDepth + nlevels)
override fun toString() = "Compiler Phase @$name" override fun toString() = "Compiler Phase @$name"
} }
class SameTypeNamedPhaseWrapper<in Context : CommonBackendContext, Data>(
name: String,
description: String,
prerequisite: Set<AnyNamedPhase>,
lower: CompilerPhase<Context, Data, Data>,
preconditions: Set<Checker<Data>> = emptySet(),
postconditions: Set<Checker<Data>> = emptySet(),
stickyPostconditions: Set<Checker<Data>> = lower.stickyPostconditions,
actions: Set<Action<Data, Context>> = emptySet(),
nlevels: Int = 0
) : AbstractNamedPhaseWrapper<Context, Data, Data>(
name, description, prerequisite, lower, preconditions, postconditions, stickyPostconditions, actions, actions, nlevels
), SameTypeCompilerPhase<Context, Data>
@@ -23,7 +23,7 @@ private class CompositePhase<Context : CommonBackendContext, Input, Output>(
var result = phases.first().invoke(phaseConfig, currentState, context, input) var result = phases.first().invoke(phaseConfig, currentState, context, input)
for ((previous, next) in phases.zip(phases.drop(1))) { for ((previous, next) in phases.zip(phases.drop(1))) {
if (next !is SameTypeCompilerPhase<*, *>) { if (next !is SameTypeCompilerPhase<*, *>) {
// Discard `stickyPostcoditions`, they are useless since data type is changing. // Discard `stickyPostconditions`, they are useless since data type is changing.
currentState = currentState.changeType() currentState = currentState.changeType()
} }
currentState.stickyPostconditions.addAll(previous.stickyPostconditions) currentState.stickyPostconditions.addAll(previous.stickyPostconditions)
@@ -58,7 +58,7 @@ fun <Context : CommonBackendContext> namedIrModulePhase(
stickyPostconditions: Set<Checker<IrModuleFragment>> = lower.stickyPostconditions, stickyPostconditions: Set<Checker<IrModuleFragment>> = lower.stickyPostconditions,
actions: Set<Action<IrModuleFragment, Context>> = setOf(defaultDumper, validationAction), actions: Set<Action<IrModuleFragment, Context>> = setOf(defaultDumper, validationAction),
nlevels: Int = 1 nlevels: Int = 1
) = SameTypeNamedPhaseWrapper( ) = NamedCompilerPhase(
name, name,
description, description,
prerequisite, prerequisite,
@@ -80,7 +80,7 @@ fun <Context : CommonBackendContext> namedIrFilePhase(
stickyPostconditions: Set<Checker<IrFile>> = lower.stickyPostconditions, stickyPostconditions: Set<Checker<IrFile>> = lower.stickyPostconditions,
actions: Set<Action<IrFile, Context>> = setOf(defaultDumper, validationAction), actions: Set<Action<IrFile, Context>> = setOf(defaultDumper, validationAction),
nlevels: Int = 1 nlevels: Int = 1
) = SameTypeNamedPhaseWrapper( ) = NamedCompilerPhase(
name, name,
description, description,
prerequisite, prerequisite,
@@ -102,7 +102,7 @@ fun <Context : CommonBackendContext, Element : IrElement> makeCustomPhase(
stickyPostconditions: Set<Checker<Element>> = emptySet(), stickyPostconditions: Set<Checker<Element>> = emptySet(),
actions: Set<Action<Element, Context>> = setOf(defaultDumper, validationAction), actions: Set<Action<Element, Context>> = setOf(defaultDumper, validationAction),
nlevels: Int = 1 nlevels: Int = 1
) = SameTypeNamedPhaseWrapper( ) = NamedCompilerPhase(
name, name,
description, description,
prerequisite, prerequisite,
@@ -130,12 +130,13 @@ fun <Context : CommonBackendContext> namedUnitPhase(
prerequisite: Set<AnyNamedPhase> = emptySet(), prerequisite: Set<AnyNamedPhase> = emptySet(),
nlevels: Int = 1, nlevels: Int = 1,
lower: CompilerPhase<Context, Unit, Unit> lower: CompilerPhase<Context, Unit, Unit>
) = SameTypeNamedPhaseWrapper( ) = NamedCompilerPhase(
name, description, prerequisite, name, description, prerequisite,
lower = lower, lower = lower,
nlevels = nlevels nlevels = nlevels
) )
@Suppress("unused") // Used in kotlin-native
fun <Context : CommonBackendContext> namedOpUnitPhase( fun <Context : CommonBackendContext> namedOpUnitPhase(
name: String, name: String,
description: String, description: String,
@@ -225,7 +226,7 @@ fun <Context : CommonBackendContext> makeIrModulePhase(
actions: Set<Action<IrModuleFragment, Context>> = setOf(defaultDumper, validationAction) actions: Set<Action<IrModuleFragment, Context>> = setOf(defaultDumper, validationAction)
) = namedIrModulePhase( ) = namedIrModulePhase(
name, description, prerequisite, name, description, prerequisite,
preconditions=preconditions, preconditions = preconditions,
postconditions = postconditions, postconditions = postconditions,
stickyPostconditions = stickyPostconditions, stickyPostconditions = stickyPostconditions,
actions = actions, actions = actions,
@@ -243,29 +244,13 @@ fun <Context : CommonBackendContext> makeIrModulePhase(
} }
) )
fun <Context : CommonBackendContext, Input> unitPhase( @Suppress("unused") // Used in kotlin-native
name: String,
description: String,
prerequisite: Set<AnyNamedPhase>,
preconditions: Set<Checker<Input>>,
op: Context.() -> Unit
) =
object : AbstractNamedPhaseWrapper<Context, Input, Unit>(
name, description, prerequisite,
preconditions = preconditions,
nlevels = 0,
lower = object : CompilerPhase<Context, Input, Unit> {
override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<Input>, context: Context, input: Input) {
context.op()
}
}
) {}
fun <Context : CommonBackendContext, Input> unitSink() = object : CompilerPhase<Context, Input, Unit> { fun <Context : CommonBackendContext, Input> unitSink() = object : CompilerPhase<Context, Input, Unit> {
override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<Input>, context: Context, input: Input) {} override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<Input>, context: Context, input: Input) {}
} }
// Intermediate phases to change the object of transformations // Intermediate phases to change the object of transformations
@Suppress("unused") // Used in kotlin-native
fun <Context : CommonBackendContext, OldData, NewData> takeFromContext(op: (Context) -> NewData) = fun <Context : CommonBackendContext, OldData, NewData> takeFromContext(op: (Context) -> NewData) =
object : CompilerPhase<Context, OldData, NewData> { object : CompilerPhase<Context, OldData, NewData> {
override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<OldData>, context: Context, input: OldData) = op(context) override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<OldData>, context: Context, input: OldData) = op(context)
@@ -46,7 +46,7 @@ private fun makeCustomJsModulePhase(
description: String, description: String,
name: String, name: String,
prerequisite: Set<AnyNamedPhase> = emptySet() prerequisite: Set<AnyNamedPhase> = emptySet()
) = SameTypeNamedPhaseWrapper( ) = NamedCompilerPhase(
name = name, name = name,
description = description, description = description,
prerequisite = prerequisite, prerequisite = prerequisite,
@@ -79,7 +79,7 @@ private fun <C> Action<IrElement, C>.toMultiModuleAction(): Action<Iterable<IrMo
} }
sealed class Lowering(val name: String) { sealed class Lowering(val name: String) {
abstract val modulePhase: SameTypeNamedPhaseWrapper<JsIrBackendContext, Iterable<IrModuleFragment>> abstract val modulePhase: NamedCompilerPhase<JsIrBackendContext, Iterable<IrModuleFragment>>
} }
class DeclarationLowering( class DeclarationLowering(
@@ -110,7 +110,7 @@ class BodyLowering(
class ModuleLowering( class ModuleLowering(
name: String, name: String,
override val modulePhase: SameTypeNamedPhaseWrapper<JsIrBackendContext, Iterable<IrModuleFragment>> override val modulePhase: NamedCompilerPhase<JsIrBackendContext, Iterable<IrModuleFragment>>
) : Lowering(name) ) : Lowering(name)
private fun makeDeclarationTransformerPhase( private fun makeDeclarationTransformerPhase(
@@ -127,7 +127,7 @@ private fun makeBodyLoweringPhase(
prerequisite: Set<Lowering> = emptySet() prerequisite: Set<Lowering> = emptySet()
) = BodyLowering(name, description, prerequisite.map { it.modulePhase }.toSet(), lowering) ) = BodyLowering(name, description, prerequisite.map { it.modulePhase }.toSet(), lowering)
fun SameTypeNamedPhaseWrapper<JsIrBackendContext, Iterable<IrModuleFragment>>.toModuleLowering() = ModuleLowering(this.name, this) fun NamedCompilerPhase<JsIrBackendContext, Iterable<IrModuleFragment>>.toModuleLowering() = ModuleLowering(this.name, this)
private val validateIrBeforeLowering = makeCustomJsModulePhase( private val validateIrBeforeLowering = makeCustomJsModulePhase(
{ context, module -> validationCallback(context, module) }, { context, module -> validationCallback(context, module) },
@@ -732,7 +732,7 @@ val loweringList = listOf<Lowering>(
// TODO comment? Eliminate ModuleLowering's? Don't filter them here? // TODO comment? Eliminate ModuleLowering's? Don't filter them here?
val pirLowerings = loweringList.filter { it is DeclarationLowering || it is BodyLowering } + staticMembersLoweringPhase val pirLowerings = loweringList.filter { it is DeclarationLowering || it is BodyLowering } + staticMembersLoweringPhase
val jsPhases = SameTypeNamedPhaseWrapper( val jsPhases = NamedCompilerPhase(
name = "IrModuleLowering", name = "IrModuleLowering",
description = "IR module lowering", description = "IR module lowering",
prerequisite = emptySet(), prerequisite = emptySet(),
@@ -20,12 +20,15 @@ import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.ir.createStaticFunctionWithReceivers import org.jetbrains.kotlin.backend.common.ir.createStaticFunctionWithReceivers
import org.jetbrains.kotlin.backend.common.ir.moveBodyTo import org.jetbrains.kotlin.backend.common.ir.moveBodyTo
import org.jetbrains.kotlin.backend.common.phaser.SameTypeNamedPhaseWrapper import org.jetbrains.kotlin.backend.common.phaser.NamedCompilerPhase
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.common.phaser.then import org.jetbrains.kotlin.backend.common.phaser.then
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction
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.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrReturn import org.jetbrains.kotlin.ir.expressions.IrReturn
@@ -45,7 +48,7 @@ private val callLoweringPhase = makeIrFilePhase(
description = "Generate calls of static functions for default parameters" description = "Generate calls of static functions for default parameters"
) )
internal val staticDefaultFunctionPhase = SameTypeNamedPhaseWrapper( internal val staticDefaultFunctionPhase = NamedCompilerPhase(
name = "StaticDefaultFunction", name = "StaticDefaultFunction",
description = "Make function adapters for default arguments static", description = "Make function adapters for default arguments static",
lower = functionDefinitionLoweringPhase then callLoweringPhase, lower = functionDefinitionLoweringPhase then callLoweringPhase,