Skip to content

Commit

Permalink
compiler: full support for IR based compilation
Browse files Browse the repository at this point in the history
  • Loading branch information
azenla committed Nov 24, 2023
1 parent 2d88666 commit 8951c3c
Show file tree
Hide file tree
Showing 32 changed files with 553 additions and 399 deletions.
4 changes: 2 additions & 2 deletions bir/src/main/kotlin/gay/pizza/pork/bir/IrCall.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package gay.pizza.pork.bir

data class IrCall(
val target: IrSymbol,
override val target: IrSymbol,
val arguments: List<IrCodeElement>,
val variableArguments: List<IrCodeElement>?
) : IrCodeElement {
) : IrCodeElement, IrSymbolUser {
override fun crawl(block: (IrElement) -> Unit) {
block(target)
arguments.forEach(block)
Expand Down
6 changes: 5 additions & 1 deletion bir/src/main/kotlin/gay/pizza/pork/bir/IrCodeBlock.kt
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
package gay.pizza.pork.bir

data class IrCodeBlock(val items: List<IrCodeElement>) : IrCodeElement
data class IrCodeBlock(val items: List<IrCodeElement>) : IrCodeElement {
override fun crawl(block: (IrElement) -> Unit) {
items.forEach(block)
}
}
2 changes: 1 addition & 1 deletion bir/src/main/kotlin/gay/pizza/pork/bir/IrContinue.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package gay.pizza.pork.bir

data class IrContinue(val target: IrSymbol) : IrCodeElement {
data class IrContinue(override val target: IrSymbol) : IrCodeElement, IrSymbolUser {
override fun crawl(block: (IrElement) -> Unit) {
block(target)
}
Expand Down
6 changes: 4 additions & 2 deletions bir/src/main/kotlin/gay/pizza/pork/bir/IrDefinition.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package gay.pizza.pork.bir

data class IrDefinition(
val symbol: IrSymbol,
override val symbol: IrSymbol,
val type: IrDefinitionType,
val arguments: List<IrFunctionArgument>,
val code: IrCodeBlock
) : IrElement {
) : IrElement, IrSymbolOwner {
override fun crawl(block: (IrElement) -> Unit) {
block(symbol)
arguments.forEach(block)
block(code)
}
}
3 changes: 2 additions & 1 deletion bir/src/main/kotlin/gay/pizza/pork/bir/IrDefinitionType.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ package gay.pizza.pork.bir

enum class IrDefinitionType {
Variable,
Function
CodeFunction,
NativeFunction
}
5 changes: 5 additions & 0 deletions bir/src/main/kotlin/gay/pizza/pork/bir/IrFunctionArgument.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package gay.pizza.pork.bir

data class IrFunctionArgument(override val symbol: IrSymbol) : IrSymbolOwner {
override fun crawl(block: (IrElement) -> Unit) {}
}
4 changes: 2 additions & 2 deletions bir/src/main/kotlin/gay/pizza/pork/bir/IrLoad.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package gay.pizza.pork.bir

data class IrLoad(val symbol: IrSymbol) : IrCodeElement {
data class IrLoad(override val target: IrSymbol) : IrCodeElement, IrSymbolUser {
override fun crawl(block: (IrElement) -> Unit) {
block(symbol)
block(target)
}
}
6 changes: 5 additions & 1 deletion bir/src/main/kotlin/gay/pizza/pork/bir/IrLoop.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package gay.pizza.pork.bir

data class IrLoop(val symbol: IrSymbol, val condition: IrCodeElement, val inner: IrCodeElement) : IrCodeElement {
data class IrLoop(
override val symbol: IrSymbol,
val condition: IrCodeElement,
val inner: IrCodeElement
) : IrCodeElement, IrSymbolOwner {
override fun crawl(block: (IrElement) -> Unit) {
block(symbol)
block(condition)
Expand Down
5 changes: 5 additions & 0 deletions bir/src/main/kotlin/gay/pizza/pork/bir/IrNativeDefinition.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package gay.pizza.pork.bir

data class IrNativeDefinition(val form: String, val definitions: List<String>) : IrCodeElement {
override fun crawl(block: (IrElement) -> Unit) {}
}
2 changes: 1 addition & 1 deletion bir/src/main/kotlin/gay/pizza/pork/bir/IrStore.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package gay.pizza.pork.bir

data class IrStore(val symbol: IrSymbol, val value: IrCodeElement) : IrCodeElement {
data class IrStore(override val target: IrSymbol, val value: IrCodeElement) : IrCodeElement, IrSymbolUser {
override fun crawl(block: (IrElement) -> Unit) {
value.crawl(block)
}
Expand Down
7 changes: 7 additions & 0 deletions bir/src/main/kotlin/gay/pizza/pork/bir/IrSuffix.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package gay.pizza.pork.bir

data class IrSuffix(val op: IrSuffixOp, override val target: IrSymbol) : IrCodeElement, IrSymbolUser {
override fun crawl(block: (IrElement) -> Unit) {
block(target)
}
}
6 changes: 6 additions & 0 deletions bir/src/main/kotlin/gay/pizza/pork/bir/IrSuffixOp.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package gay.pizza.pork.bir

enum class IrSuffixOp {
Increment,
Decrement
}
40 changes: 40 additions & 0 deletions bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolGraph.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package gay.pizza.pork.bir

class IrSymbolGraph {
private val edges = mutableSetOf<Pair<IrSymbolUser, IrSymbolOwner>>()

private fun crawlForKnown(known: MutableMap<IrSymbol, IrSymbolOwner>, root: IrElement) {
if (root is IrSymbolOwner) {
known[root.symbol] = root
}

root.crawl { item ->
crawlForKnown(known, item)
}
}

private fun crawlForAssociations(known: Map<IrSymbol, IrSymbolOwner>, root: IrElement) {
if (root is IrSymbolUser) {
val what = known[root.target]
if (what != null) {
edges.add(root to what)
}
}

root.crawl { item ->
crawlForAssociations(known, item)
}
}

fun crawl(root: IrElement) {
val known = mutableMapOf<IrSymbol, IrSymbolOwner>()
crawlForKnown(known, root)
crawlForAssociations(known, root)
}

fun forEachEdge(block: (IrSymbolUser, IrSymbolOwner) -> Unit) {
for ((from, to) in edges) {
block(from, to)
}
}
}
5 changes: 5 additions & 0 deletions bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolOwner.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package gay.pizza.pork.bir

sealed interface IrSymbolOwner : IrElement {
val symbol: IrSymbol
}
5 changes: 5 additions & 0 deletions bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolUser.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package gay.pizza.pork.bir

sealed interface IrSymbolUser : IrElement {
val target: IrSymbol
}
59 changes: 59 additions & 0 deletions bir/src/main/kotlin/gay/pizza/pork/bir/IrVisitor.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package gay.pizza.pork.bir

interface IrVisitor<T> {
fun visitIrSlab(ir: IrSlab): T
fun visitIrSlabLocation(ir: IrSlabLocation): T
fun visitIrDefinition(ir: IrDefinition): T
fun visitIrSymbol(ir: IrSymbol): T
fun visitIrBeak(ir: IrBreak): T
fun visitIrCall(ir: IrCall): T
fun visitIrCodeBlock(ir: IrCodeBlock): T
fun visitIrConditional(ir: IrConditional): T
fun visitIrBooleanConstant(ir: IrBooleanConstant): T
fun visitIrIntegerConstant(ir: IrIntegerConstant): T
fun visitIrLongConstant(ir: IrLongConstant): T
fun visitIrDoubleConstant(ir: IrDoubleConstant): T
fun visitIrStringConstant(ir: IrStringConstant): T
fun visitIrNoneConstant(ir: IrNoneConstant): T
fun visitIrContinue(ir: IrContinue): T
fun visitIrInfix(ir: IrInfix): T
fun visitIrList(ir: IrList): T
fun visitIrLoad(ir: IrLoad): T
fun visitIrLoop(ir: IrLoop): T
fun visitIrPrefix(ir: IrPrefix): T
fun visitIrReturn(ir: IrReturn): T
fun visitIrStore(ir: IrStore): T
fun visitIrSuffix(ir: IrSuffix): T
fun visitIrWorld(ir: IrWorld): T
fun visitIrNativeDefinition(ir: IrNativeDefinition): T
fun visitIrFunctionArgument(ir: IrFunctionArgument): T

fun visit(ir: IrElement): T = when (ir) {
is IrBreak -> visitIrBeak(ir)
is IrCall -> visitIrCall(ir)
is IrCodeBlock -> visitIrCodeBlock(ir)
is IrConditional -> visitIrConditional(ir)
is IrBooleanConstant -> visitIrBooleanConstant(ir)
is IrDoubleConstant -> visitIrDoubleConstant(ir)
is IrIntegerConstant -> visitIrIntegerConstant(ir)
is IrLongConstant -> visitIrLongConstant(ir)
is IrNoneConstant -> visitIrNoneConstant(ir)
is IrStringConstant -> visitIrStringConstant(ir)
is IrContinue -> visitIrContinue(ir)
is IrInfix -> visitIrInfix(ir)
is IrList -> visitIrList(ir)
is IrLoad -> visitIrLoad(ir)
is IrLoop -> visitIrLoop(ir)
is IrPrefix -> visitIrPrefix(ir)
is IrReturn -> visitIrReturn(ir)
is IrStore -> visitIrStore(ir)
is IrSuffix -> visitIrSuffix(ir)
is IrDefinition -> visitIrDefinition(ir)
is IrSlab -> visitIrSlab(ir)
is IrSlabLocation -> visitIrSlabLocation(ir)
is IrSymbol -> visitIrSymbol(ir)
is IrWorld -> visitIrWorld(ir)
is IrNativeDefinition -> visitIrNativeDefinition(ir)
is IrFunctionArgument -> visitIrFunctionArgument(ir)
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package gay.pizza.pork.bir

data class IrAccess(val target: IrSymbol) : IrCodeElement {
data class IrWorld(val slabs: List<IrSlab>) : IrElement {
override fun crawl(block: (IrElement) -> Unit) {
block(target)
slabs.forEach(block)
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
package gay.pizza.pork.bytecode

class MutableRel(var rel: UInt)
data class MutableRel(var rel: UInt)
3 changes: 0 additions & 3 deletions bytecode/src/main/kotlin/gay/pizza/pork/bytecode/Ops.kt

This file was deleted.

14 changes: 14 additions & 0 deletions compiler/src/main/kotlin/gay/pizza/pork/compiler/CompilableSlab.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package gay.pizza.pork.compiler

import gay.pizza.pork.ast.gen.Symbol
import gay.pizza.pork.bir.IrDefinition
import gay.pizza.pork.bir.IrSlab
import gay.pizza.pork.bir.IrSlabLocation
import gay.pizza.pork.frontend.Slab

class CompilableSlab(val compiler: Compiler, val slab: Slab) {
val compiledIrSlab: IrSlab by lazy { compileIrSlab() }

val compilableSymbols: List<CompilableSymbol> by lazy {
slab.scope.internalSymbols.map { symbol ->
CompilableSymbol(this, symbol)
Expand All @@ -18,4 +23,13 @@ class CompilableSlab(val compiler: Compiler, val slab: Slab) {
val scopeSymbol = slab.scope.resolve(symbol) ?: return null
return compiler.resolveOrNull(scopeSymbol)
}

private fun compileIrSlab(): IrSlab {
val definitions = mutableListOf<IrDefinition>()
for (compilableSymbol in compilableSymbols) {
definitions.add(compilableSymbol.compiledIrDefinition)
}
val irSlabLocation = IrSlabLocation(slab.location.form, slab.location.filePath)
return IrSlab(irSlabLocation, definitions)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,62 @@ package gay.pizza.pork.compiler

import gay.pizza.pork.ast.gen.FunctionDefinition
import gay.pizza.pork.ast.gen.LetDefinition
import gay.pizza.pork.ast.gen.NativeFunctionDescriptor
import gay.pizza.pork.ast.gen.visit
import gay.pizza.pork.bir.IrCodeBlock
import gay.pizza.pork.bir.IrDefinition
import gay.pizza.pork.bir.IrDefinitionType
import gay.pizza.pork.bir.IrSymbolTag
import gay.pizza.pork.frontend.scope.ScopeSymbol

class CompilableSymbol(val compilableSlab: CompilableSlab, val scopeSymbol: ScopeSymbol) {
val compiledIrDefinition: IrDefinition by lazy { compileIrDefinition() }
val compiledStubOps: CompiledSymbolResult by lazy { compile() }

val usedSymbols: List<ScopeSymbol>
get() = scopeSymbol.scope.usedSymbols

private fun compile(): CompiledSymbolResult {
val emitter = StubOpEmitter(compilableSlab.compiler, this)
emitter.enter()
val code = CodeBuilder(this)
val ir = compiledIrDefinition
val emitter = IrStubOpEmitter(ir, code)
emitter.visit(ir.code)
emitter.final()
return emitter.code.build()
}

private fun compileIrDefinition(): IrDefinition {
val compiler = compilableSlab.compiler
val functionSymbol = compiler.irSymbolWorld.create(scopeSymbol, IrSymbolTag.Function)
val irCodeEmitter = IrCodeEmitter(
self = functionSymbol,
irSymbolWorld = compiler.irSymbolWorld,
irSymbolAssignment = compiler.irSymbolAssignment,
scope = compilableSlab.slab.scope
)
irCodeEmitter.enterLocalScope()
val what = if (scopeSymbol.definition is FunctionDefinition) {
val functionDefinition = scopeSymbol.definition as FunctionDefinition
emitter.allocateOuterScope(functionDefinition)
irCodeEmitter.createFunctionArguments(functionDefinition)
functionDefinition.block ?: functionDefinition.nativeFunctionDescriptor!!
} else {
val letDefinition = scopeSymbol.definition as LetDefinition
letDefinition.value
}
emitter.visit(what)
emitter.exit()
return emitter.code.build()
val type = if (what is NativeFunctionDescriptor) {
IrDefinitionType.NativeFunction
} else IrDefinitionType.CodeFunction
val irCodeElement = irCodeEmitter.visit(what)
val irCodeBlock = if (irCodeElement is IrCodeBlock) {
irCodeElement
} else IrCodeBlock(listOf(irCodeElement))
irCodeEmitter.exitLocalScope()
return IrDefinition(
symbol = functionSymbol,
type = type,
arguments = irCodeEmitter.functionArguments,
code = irCodeBlock
)
}

val id: String
Expand Down
4 changes: 4 additions & 0 deletions compiler/src/main/kotlin/gay/pizza/pork/compiler/Compiler.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package gay.pizza.pork.compiler

import gay.pizza.pork.bir.IrSymbolAssignment
import gay.pizza.pork.bytecode.CompiledWorld
import gay.pizza.pork.bytecode.MutableConstantPool
import gay.pizza.pork.frontend.Slab
Expand All @@ -11,6 +12,9 @@ class Compiler {
CompilableSlab(this, slab)
}

val irSymbolAssignment: IrSymbolAssignment = IrSymbolAssignment()
val irSymbolWorld: IrSymbolWorld<Any> = IrSymbolWorld(irSymbolAssignment)

fun resolveOrNull(scopeSymbol: ScopeSymbol): CompilableSymbol? {
val compiledSlab = compilableSlabs.of(scopeSymbol.slabScope.slab)
return compiledSlab.resolve(scopeSymbol.symbol)
Expand Down
Loading

0 comments on commit 8951c3c

Please sign in to comment.