Extract SameTypeNamedCompilerPhase from NamedCompilerPhase
Currently, compiler pipelines are heavily couples with NamedCompilerPhase. Unfortunately, NamedCompilerPhase uses the same type for Input and Output, thus it is not applicable to phases that try to transform some data purely. Thus, we separate this class into two, allowing to have a new inheritor of NamedCompilerPhase with different Input and Output types.
This commit is contained in:
committed by
Space Team
parent
3a500e536a
commit
6a4722188f
+70
-33
@@ -18,7 +18,7 @@ class PhaserState<Data>(
|
||||
}
|
||||
|
||||
// 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>.changePhaserStateType() = PhaserState<Output>(alreadyDone, depth, phaseCount, mutableSetOf())
|
||||
|
||||
inline fun <R, D> PhaserState<D>.downlevel(nlevels: Int, block: () -> R): R {
|
||||
depth += nlevels
|
||||
@@ -30,7 +30,7 @@ inline fun <R, D> PhaserState<D>.downlevel(nlevels: Int, block: () -> R): R {
|
||||
interface CompilerPhase<in Context : LoggingContext, Input, Output> {
|
||||
fun invoke(phaseConfig: PhaseConfigurationService, phaserState: PhaserState<Input>, context: Context, input: Input): Output
|
||||
|
||||
fun getNamedSubphases(startDepth: Int = 0): List<Pair<Int, NamedCompilerPhase<Context, *>>> = emptyList()
|
||||
fun getNamedSubphases(startDepth: Int = 0): List<Pair<Int, AbstractNamedCompilerPhase<Context, *, *>>> = emptyList()
|
||||
|
||||
// In phase trees, `stickyPostconditions` is inherited along the right edge to be used in `then`.
|
||||
val stickyPostconditions: Set<Checker<Output>> get() = emptySet()
|
||||
@@ -47,7 +47,7 @@ interface SameTypeCompilerPhase<in Context : LoggingContext, Data> : CompilerPha
|
||||
// A failing checker should just throw an exception.
|
||||
typealias Checker<Data> = (Data) -> Unit
|
||||
|
||||
typealias AnyNamedPhase = NamedCompilerPhase<*, *>
|
||||
typealias AnyNamedPhase = AbstractNamedCompilerPhase<*, *, *>
|
||||
|
||||
enum class BeforeOrAfter { BEFORE, AFTER }
|
||||
|
||||
@@ -66,20 +66,18 @@ infix operator fun <Data, Context> Action<Data, Context>.plus(other: Action<Data
|
||||
other(phaseState, data, context)
|
||||
}
|
||||
|
||||
class NamedCompilerPhase<in Context : LoggingContext, Data>(
|
||||
// TODO: A better name would be just `NamedCompilerPhase`, but it is already used (see below).
|
||||
abstract class AbstractNamedCompilerPhase<in Context : LoggingContext, Input, Output>(
|
||||
val name: String,
|
||||
val description: String,
|
||||
val prerequisite: Set<NamedCompilerPhase<Context, *>> = emptySet(),
|
||||
private val lower: CompilerPhase<Context, Data, Data>,
|
||||
val preconditions: Set<Checker<Data>> = emptySet(),
|
||||
val postconditions: Set<Checker<Data>> = emptySet(),
|
||||
override val stickyPostconditions: Set<Checker<Data>> = emptySet(),
|
||||
private val actions: Set<Action<Data, Context>> = emptySet(),
|
||||
private val nlevels: Int = 0
|
||||
) : SameTypeCompilerPhase<Context, Data> {
|
||||
override fun invoke(phaseConfig: PhaseConfigurationService, phaserState: PhaserState<Data>, context: Context, input: Data): Data {
|
||||
val prerequisite: Set<AbstractNamedCompilerPhase<Context, *, *>> = emptySet(),
|
||||
val preconditions: Set<Checker<Input>> = emptySet(),
|
||||
val postconditions: Set<Checker<Output>> = emptySet(),
|
||||
protected val nlevels: Int = 0
|
||||
) : CompilerPhase<Context, Input, Output> {
|
||||
override fun invoke(phaseConfig: PhaseConfigurationService, phaserState: PhaserState<Input>, context: Context, input: Input): Output {
|
||||
if (!phaseConfig.isEnabled(this)) {
|
||||
return input
|
||||
return outputIfNotEnabled(phaseConfig, phaserState, context, input)
|
||||
}
|
||||
|
||||
assert(phaserState.alreadyDone.containsAll(prerequisite)) {
|
||||
@@ -93,10 +91,10 @@ class NamedCompilerPhase<in Context : LoggingContext, Data>(
|
||||
runAndProfile(phaseConfig, phaserState, context, input)
|
||||
} else {
|
||||
phaserState.downlevel(nlevels) {
|
||||
lower.invoke(phaseConfig, phaserState, context, input)
|
||||
phaseBody(phaseConfig, phaserState, context, input)
|
||||
}
|
||||
}
|
||||
runAfter(phaseConfig, phaserState, context, output)
|
||||
runAfter(phaseConfig, changePhaserStateType(phaserState), context, output)
|
||||
|
||||
phaserState.alreadyDone.add(this)
|
||||
phaserState.phaseCount++
|
||||
@@ -104,7 +102,57 @@ class NamedCompilerPhase<in Context : LoggingContext, Data>(
|
||||
return output
|
||||
}
|
||||
|
||||
private fun runBefore(phaseConfig: PhaseConfigurationService, phaserState: PhaserState<Data>, context: Context, input: Data) {
|
||||
abstract fun phaseBody(phaseConfig: PhaseConfigurationService, phaserState: PhaserState<Input>, context: Context, input: Input): Output
|
||||
|
||||
abstract fun outputIfNotEnabled(phaseConfig: PhaseConfigurationService, phaserState: PhaserState<Input>, context: Context, input: Input): Output
|
||||
|
||||
abstract fun changePhaserStateType(phaserState: PhaserState<Input>): PhaserState<Output>
|
||||
|
||||
abstract fun runBefore(phaseConfig: PhaseConfigurationService, phaserState: PhaserState<Input>, context: Context, input: Input)
|
||||
|
||||
abstract fun runAfter(phaseConfig: PhaseConfigurationService, phaserState: PhaserState<Output>, context: Context, output: Output)
|
||||
|
||||
private fun runAndProfile(phaseConfig: PhaseConfigurationService, phaserState: PhaserState<Input>, context: Context, source: Input): Output {
|
||||
var result: Output? = null
|
||||
val msec = measureTimeMillis {
|
||||
result = phaserState.downlevel(nlevels) {
|
||||
phaseBody(phaseConfig, phaserState, context, source)
|
||||
}
|
||||
}
|
||||
// TODO: use a proper logger
|
||||
println("${"\t".repeat(phaserState.depth)}$description: $msec msec")
|
||||
return result!!
|
||||
}
|
||||
|
||||
override fun toString() = "Compiler Phase @$name"
|
||||
}
|
||||
|
||||
// TODO: This class should be named `SameTypeNamedCompilerPhase`,
|
||||
// but it would be a breaking change (e.g. there are usages in IntelliJ repo),
|
||||
// so we introduce a typealias instead as a temporary solution.
|
||||
class NamedCompilerPhase<in Context : LoggingContext, Data>(
|
||||
name: String,
|
||||
description: String,
|
||||
prerequisite: Set<AbstractNamedCompilerPhase<Context, *, *>> = emptySet(),
|
||||
private val lower: CompilerPhase<Context, Data, Data>,
|
||||
preconditions: Set<Checker<Data>> = emptySet(),
|
||||
postconditions: Set<Checker<Data>> = emptySet(),
|
||||
override val stickyPostconditions: Set<Checker<Data>> = emptySet(),
|
||||
private val actions: Set<Action<Data, Context>> = emptySet(),
|
||||
nlevels: Int = 0
|
||||
) : AbstractNamedCompilerPhase<Context, Data, Data>(
|
||||
name, description, prerequisite, preconditions, postconditions, nlevels
|
||||
) {
|
||||
override fun phaseBody(phaseConfig: PhaseConfigurationService, phaserState: PhaserState<Data>, context: Context, input: Data): Data =
|
||||
lower.invoke(phaseConfig, phaserState, context, input)
|
||||
|
||||
override fun outputIfNotEnabled(phaseConfig: PhaseConfigurationService, phaserState: PhaserState<Data>, context: Context, input: Data): Data =
|
||||
input
|
||||
|
||||
override fun changePhaserStateType(phaserState: PhaserState<Data>): PhaserState<Data> =
|
||||
phaserState
|
||||
|
||||
override fun runBefore(phaseConfig: PhaseConfigurationService, phaserState: PhaserState<Data>, context: Context, input: Data) {
|
||||
val state = ActionState(phaseConfig, this, phaserState.phaseCount, BeforeOrAfter.BEFORE)
|
||||
for (action in actions) action(state, input, context)
|
||||
|
||||
@@ -113,7 +161,7 @@ class NamedCompilerPhase<in Context : LoggingContext, Data>(
|
||||
}
|
||||
}
|
||||
|
||||
private fun runAfter(phaseConfig: PhaseConfigurationService, phaserState: PhaserState<Data>, context: Context, output: Data) {
|
||||
override fun runAfter(phaseConfig: PhaseConfigurationService, phaserState: PhaserState<Data>, context: Context, output: Data) {
|
||||
val state = ActionState(phaseConfig, this, phaserState.phaseCount, BeforeOrAfter.AFTER)
|
||||
for (action in actions) action(state, output, context)
|
||||
|
||||
@@ -126,20 +174,9 @@ class NamedCompilerPhase<in Context : LoggingContext, Data>(
|
||||
}
|
||||
}
|
||||
|
||||
private fun runAndProfile(phaseConfig: PhaseConfigurationService, phaserState: PhaserState<Data>, context: Context, source: Data): Data {
|
||||
var result: Data? = null
|
||||
val msec = measureTimeMillis {
|
||||
result = phaserState.downlevel(nlevels) {
|
||||
lower.invoke(phaseConfig, phaserState, context, source)
|
||||
}
|
||||
}
|
||||
// TODO: use a proper logger
|
||||
println("${"\t".repeat(phaserState.depth)}$description: $msec msec")
|
||||
return result!!
|
||||
}
|
||||
|
||||
override fun getNamedSubphases(startDepth: Int): List<Pair<Int, NamedCompilerPhase<Context, *>>> =
|
||||
override fun getNamedSubphases(startDepth: Int): List<Pair<Int, AbstractNamedCompilerPhase<Context, *, *>>> =
|
||||
listOf(startDepth to this) + lower.getNamedSubphases(startDepth + nlevels)
|
||||
|
||||
override fun toString() = "Compiler Phase @$name"
|
||||
}
|
||||
|
||||
|
||||
typealias SameTypeNamedCompilerPhase<Context, Data> = NamedCompilerPhase<Context, Data>
|
||||
+16
-16
@@ -23,7 +23,7 @@ private class CompositePhase<Context : CommonBackendContext, Input, Output>(
|
||||
for ((previous, next) in phases.zip(phases.drop(1))) {
|
||||
if (next !is SameTypeCompilerPhase<*, *>) {
|
||||
// Discard `stickyPostconditions`, they are useless since data type is changing.
|
||||
currentState = currentState.changeType()
|
||||
currentState = currentState.changePhaserStateType()
|
||||
}
|
||||
currentState.stickyPostconditions.addAll(previous.stickyPostconditions)
|
||||
result = next.invoke(phaseConfig, currentState, context, result)
|
||||
@@ -32,7 +32,7 @@ private class CompositePhase<Context : CommonBackendContext, Input, Output>(
|
||||
return result as Output
|
||||
}
|
||||
|
||||
override fun getNamedSubphases(startDepth: Int): List<Pair<Int, NamedCompilerPhase<Context, *>>> =
|
||||
override fun getNamedSubphases(startDepth: Int): List<Pair<Int, AbstractNamedCompilerPhase<Context, *, *>>> =
|
||||
phases.flatMap { it.getNamedSubphases(startDepth) }
|
||||
|
||||
override val stickyPostconditions get() = phases.last().stickyPostconditions
|
||||
@@ -51,14 +51,14 @@ fun <Context : CommonBackendContext, Element : IrElement> makeCustomPhase(
|
||||
op: (Context, Element) -> Unit,
|
||||
name: String,
|
||||
description: String,
|
||||
prerequisite: Set<NamedCompilerPhase<Context, *>> = emptySet(),
|
||||
prerequisite: Set<AbstractNamedCompilerPhase<Context, *, *>> = emptySet(),
|
||||
preconditions: Set<Checker<Element>> = emptySet(),
|
||||
postconditions: Set<Checker<Element>> = emptySet(),
|
||||
stickyPostconditions: Set<Checker<Element>> = emptySet(),
|
||||
actions: Set<Action<Element, Context>> = setOf(defaultDumper, validationAction),
|
||||
nlevels: Int = 1
|
||||
): NamedCompilerPhase<Context, Element> =
|
||||
NamedCompilerPhase(
|
||||
): SameTypeNamedCompilerPhase<Context, Element> =
|
||||
SameTypeNamedCompilerPhase(
|
||||
name, description, prerequisite, CustomPhaseAdapter(op), preconditions, postconditions, stickyPostconditions, actions, nlevels,
|
||||
)
|
||||
|
||||
@@ -74,11 +74,11 @@ private class CustomPhaseAdapter<Context : CommonBackendContext, Element>(
|
||||
fun <Context : CommonBackendContext> namedUnitPhase(
|
||||
name: String,
|
||||
description: String,
|
||||
prerequisite: Set<NamedCompilerPhase<Context, *>> = emptySet(),
|
||||
prerequisite: Set<AbstractNamedCompilerPhase<Context, *, *>> = emptySet(),
|
||||
nlevels: Int = 1,
|
||||
lower: CompilerPhase<Context, Unit, Unit>
|
||||
): NamedCompilerPhase<Context, Unit> =
|
||||
NamedCompilerPhase(
|
||||
): SameTypeNamedCompilerPhase<Context, Unit> =
|
||||
SameTypeNamedCompilerPhase(
|
||||
name, description, prerequisite, lower, nlevels = nlevels
|
||||
)
|
||||
|
||||
@@ -86,9 +86,9 @@ fun <Context : CommonBackendContext> namedUnitPhase(
|
||||
fun <Context : CommonBackendContext> namedOpUnitPhase(
|
||||
name: String,
|
||||
description: String,
|
||||
prerequisite: Set<NamedCompilerPhase<Context, *>>,
|
||||
prerequisite: Set<AbstractNamedCompilerPhase<Context, *, *>>,
|
||||
op: Context.() -> Unit
|
||||
): NamedCompilerPhase<Context, Unit> = namedUnitPhase(
|
||||
): SameTypeNamedCompilerPhase<Context, Unit> = namedUnitPhase(
|
||||
name, description, prerequisite,
|
||||
nlevels = 0,
|
||||
lower = object : SameTypeCompilerPhase<Context, Unit> {
|
||||
@@ -102,13 +102,13 @@ fun <Context : CommonBackendContext> makeIrFilePhase(
|
||||
lowering: (Context) -> FileLoweringPass,
|
||||
name: String,
|
||||
description: String,
|
||||
prerequisite: Set<NamedCompilerPhase<Context, *>> = emptySet(),
|
||||
prerequisite: Set<AbstractNamedCompilerPhase<Context, *, *>> = emptySet(),
|
||||
preconditions: Set<Checker<IrFile>> = emptySet(),
|
||||
postconditions: Set<Checker<IrFile>> = emptySet(),
|
||||
stickyPostconditions: Set<Checker<IrFile>> = emptySet(),
|
||||
actions: Set<Action<IrFile, Context>> = setOf(defaultDumper, validationAction)
|
||||
): NamedCompilerPhase<Context, IrFile> =
|
||||
NamedCompilerPhase(
|
||||
): SameTypeNamedCompilerPhase<Context, IrFile> =
|
||||
SameTypeNamedCompilerPhase(
|
||||
name, description, prerequisite, FileLoweringPhaseAdapter(lowering), preconditions, postconditions, stickyPostconditions, actions,
|
||||
nlevels = 0,
|
||||
)
|
||||
@@ -126,13 +126,13 @@ fun <Context : CommonBackendContext> makeIrModulePhase(
|
||||
lowering: (Context) -> FileLoweringPass,
|
||||
name: String,
|
||||
description: String,
|
||||
prerequisite: Set<NamedCompilerPhase<Context, *>> = emptySet(),
|
||||
prerequisite: Set<AbstractNamedCompilerPhase<Context, *, *>> = emptySet(),
|
||||
preconditions: Set<Checker<IrModuleFragment>> = emptySet(),
|
||||
postconditions: Set<Checker<IrModuleFragment>> = emptySet(),
|
||||
stickyPostconditions: Set<Checker<IrModuleFragment>> = emptySet(),
|
||||
actions: Set<Action<IrModuleFragment, Context>> = setOf(defaultDumper, validationAction)
|
||||
): NamedCompilerPhase<Context, IrModuleFragment> =
|
||||
NamedCompilerPhase(
|
||||
): SameTypeNamedCompilerPhase<Context, IrModuleFragment> =
|
||||
SameTypeNamedCompilerPhase(
|
||||
name, description, prerequisite, ModuleLoweringPhaseAdapter(lowering), preconditions, postconditions, stickyPostconditions, actions,
|
||||
nlevels = 0,
|
||||
)
|
||||
|
||||
+5
-5
@@ -32,8 +32,8 @@ fun <Context : CommonBackendContext> performByIrFile(
|
||||
description: String = "Perform phases by IrFile",
|
||||
copyBeforeLowering: Boolean = true,
|
||||
lower: List<CompilerPhase<Context, IrFile, IrFile>>,
|
||||
): NamedCompilerPhase<Context, IrModuleFragment> =
|
||||
NamedCompilerPhase(
|
||||
): SameTypeNamedCompilerPhase<Context, IrModuleFragment> =
|
||||
SameTypeNamedCompilerPhase(
|
||||
name, description, emptySet(), PerformByIrFilePhase(lower, copyBeforeLowering), emptySet(), emptySet(), emptySet(),
|
||||
setOf(defaultDumper), nlevels = 1,
|
||||
)
|
||||
@@ -60,7 +60,7 @@ private class PerformByIrFilePhase<Context : CommonBackendContext>(
|
||||
): IrModuleFragment {
|
||||
for (irFile in input.files) {
|
||||
try {
|
||||
val filePhaserState = phaserState.changeType<IrModuleFragment, IrFile>()
|
||||
val filePhaserState = phaserState.changePhaserStateType<IrModuleFragment, IrFile>()
|
||||
for (phase in lower) {
|
||||
phase.invoke(phaseConfig, filePhaserState, context, irFile)
|
||||
}
|
||||
@@ -97,7 +97,7 @@ private class PerformByIrFilePhase<Context : CommonBackendContext>(
|
||||
for ((irFile, state) in filesAndStates) {
|
||||
executor.execute {
|
||||
try {
|
||||
val filePhaserState = state.changeType<IrModuleFragment, IrFile>()
|
||||
val filePhaserState = state.changePhaserStateType<IrModuleFragment, IrFile>()
|
||||
for (phase in lower) {
|
||||
phase.invoke(phaseConfig, filePhaserState, context, irFile)
|
||||
}
|
||||
@@ -134,7 +134,7 @@ private class PerformByIrFilePhase<Context : CommonBackendContext>(
|
||||
return input
|
||||
}
|
||||
|
||||
override fun getNamedSubphases(startDepth: Int): List<Pair<Int, NamedCompilerPhase<Context, *>>> =
|
||||
override fun getNamedSubphases(startDepth: Int): List<Pair<Int, AbstractNamedCompilerPhase<Context, *, *>>> =
|
||||
lower.flatMap { it.getNamedSubphases(startDepth) }
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user