Skip to content

Commit

Permalink
feat(ryujin): virtual tables, analyzers, more statements, etc...
Browse files Browse the repository at this point in the history
  • Loading branch information
SrGaabriel committed Sep 7, 2024
1 parent aec92c9 commit 8d59af2
Show file tree
Hide file tree
Showing 18 changed files with 307 additions and 38 deletions.
8 changes: 0 additions & 8 deletions compiler/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,6 @@ kotlin {
executable()
}
}
watchosX64("watchosX64") {
binaries {
executable()
}
}
iosArm64("iosArm64") {
binaries {
executable()
Expand Down Expand Up @@ -66,9 +61,6 @@ kotlin {
val windowsX64Main by getting {
dependsOn(nativeMain)
}
val watchosX64Main by getting {
dependsOn(nativeMain)
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ kotlinx-html-js = { module = "org.jetbrains.kotlinx:kotlinx-html-js", version.re
kotlinx-serialization-core = { module = "org.jetbrains.kotlinx:kotlinx-serialization-core", version.ref = "serialization-json" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "serialization-json" }

kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }

[plugins]
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
Expand Down
8 changes: 8 additions & 0 deletions ryujin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,12 @@ kotlin {
iosArm64()
macosX64()
js().browser()

sourceSets {
val commonTest by getting {
dependencies {
implementation(libs.kotlin.test)
}
}
}
}
16 changes: 16 additions & 0 deletions ryujin/src/commonMain/kotlin/DragonModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,20 @@ interface DragonModule {
fun removeDependencies(vararg dependencies: Dependency) {
this.dependencies.removeAll(dependencies)
}

fun addFunction(function: DragonFunction) {
functions.add(function)
}

fun addFunctions(vararg functions: DragonFunction) {
this.functions.addAll(functions)
}

fun removeFunction(function: DragonFunction) {
functions.remove(function)
}

fun removeFunctions(vararg functions: DragonFunction) {
this.functions.removeAll(functions)
}
}
8 changes: 8 additions & 0 deletions ryujin/src/commonMain/kotlin/analyzer/RyujinAnalysisError.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package me.gabriel.ryujin.analyzer

import me.gabriel.ryujin.statement.DragonStatement

data class RyujinAnalysisError(
val statement: DragonStatement,
val message: String
)
13 changes: 13 additions & 0 deletions ryujin/src/commonMain/kotlin/analyzer/RyujinAnalyzer.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package me.gabriel.ryujin.analyzer

import me.gabriel.ryujin.DragonModule
import me.gabriel.ryujin.statement.DragonStatement

/**
* This analyzer is responsible for catching obvious flaws in LLVM IR.
* It should be used to catch errors that are either not caught by the parser, or way too obvious to go unnoticed.
*/
interface RyujinAnalyzer {
fun analyze(module: DragonModule): List<RyujinAnalysisError >
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package me.gabriel.ryujin.analyzer.impl

import me.gabriel.ryujin.DragonModule
import me.gabriel.ryujin.analyzer.RyujinAnalysisError
import me.gabriel.ryujin.analyzer.RyujinAnalyzer
import me.gabriel.ryujin.statement.DragonStatement
import me.gabriel.ryujin.statement.StoreStatement
import me.gabriel.ryujin.struct.DragonType

/**
* This is a balanced analyzer: neither too thorough nor too shallow, as to
* provide a good balance between performance and error detection.
*/
class BalancedRyujinAnalyzer: RyujinAnalyzer {
override fun analyze(module: DragonModule): List<RyujinAnalysisError> {
val errors = mutableListOf<RyujinAnalysisError>()
module.functions.asSequence().flatMap { it.statements }.forEach {
errors.addAll(analyzeStatement(it))
}
return errors
}

private fun analyzeStatement(statement: DragonStatement): List<RyujinAnalysisError> = when (statement) {
is StoreStatement -> analyzeStoreStatement(statement)
else -> emptyList()
}

private fun analyzeStoreStatement(statement: StoreStatement): List<RyujinAnalysisError> {
val errors = mutableListOf<RyujinAnalysisError>()
if (statement.target.type !is DragonType.Pointer) {
errors.add(
RyujinAnalysisError(
statement = statement,
message = "Target is not a pointer: ${statement.target.type}"
)
)
}
return errors
}
}
35 changes: 34 additions & 1 deletion ryujin/src/commonMain/kotlin/dsl/FunctionScopeDsl.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,46 @@
package me.gabriel.ryujin.dsl

import me.gabriel.ryujin.function.DragonFunction
import me.gabriel.ryujin.statement.DragonStatement
import me.gabriel.ryujin.statement.*
import me.gabriel.ryujin.struct.Memory
import me.gabriel.ryujin.struct.Value

class FunctionScopeDsl(
val module: ModuleScopeDsl,
val function: DragonFunction
) {
var register = function.parameters.size

fun statement(statement: DragonStatement) {
if (!statement.isValid()) {
throw IllegalArgumentException("Invalid statement: $statement")
}
function.statements.add(statement)
}

fun load(target: Memory): LoadStatement =
LoadStatement(target)

fun add(left: Value, right: Value): AddStatement =
AddStatement(left, right)

fun assignment(target: Memory, value: TypedDragonStatement) {
statement(AssignStatement(target, value))
}

fun assign(value: (FunctionScopeDsl) -> TypedDragonStatement): Memory =
value(this).assign()

fun TypedDragonStatement.ignore() =
statement(this)

fun TypedDragonStatement.assign(): Memory {
val memory = Memory.Sized(
type = type,
size = type.size,
register = register++
)
statement(AssignStatement(memory, this))
return memory
}
}
38 changes: 31 additions & 7 deletions ryujin/src/commonMain/kotlin/dsl/ModuleScopeDsl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,53 @@ package me.gabriel.ryujin.dsl

import me.gabriel.ryujin.DragonModule
import me.gabriel.ryujin.function.DragonFunction
import me.gabriel.ryujin.struct.Dependency
import me.gabriel.ryujin.struct.DragonType
import me.gabriel.ryujin.struct.*

class ModuleScopeDsl: DragonModule {
override val functions: MutableSet<DragonFunction> = mutableSetOf()
override val dependencies: MutableSet<Dependency> = mutableSetOf()

fun function(
name: String,
parameters: Map<String, DragonType>,
returnType: DragonType,
block: FunctionScopeDsl.() -> Unit
parameters: Collection<DragonType> = emptyList(),
block: FunctionScopeDsl.(Collection<Memory>) -> Unit
) {
val parameterMemoryUnits = parameters.mapIndexed { index, dragonType ->
Memory.Sized(
type = dragonType,
size = dragonType.size,
register = index
)
}

val function = DragonFunction(
module = this,
name = name,
parameters = parameters,
parameters = parameterMemoryUnits,
returnType = returnType
)
FunctionScopeDsl(
functions.add(function)
val dsl = FunctionScopeDsl(
module = this,
function = function
).apply(block)
)
dsl.block(parameterMemoryUnits)
}

fun virtualTable(
name: String,
values: Collection<Value>
) {
dependencies.add(Dependency.Constant(
name = name,
value = Constant.VirtualTable(values)
))
}
}

fun ryujinModule(block: ModuleScopeDsl.() -> Unit): ModuleScopeDsl {
val module = ModuleScopeDsl()
module.apply(block)
return module
}
3 changes: 2 additions & 1 deletion ryujin/src/commonMain/kotlin/function/DragonFunction.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ package me.gabriel.ryujin.function
import me.gabriel.ryujin.DragonModule
import me.gabriel.ryujin.statement.DragonStatement
import me.gabriel.ryujin.struct.DragonType
import me.gabriel.ryujin.struct.Memory

class DragonFunction(
val module: DragonModule,
val name: String,
val parameters: Map<String, DragonType>,
val parameters: Collection<Memory>,
val returnType: DragonType
) {
val statements = mutableListOf<DragonStatement>()
Expand Down
2 changes: 1 addition & 1 deletion ryujin/src/commonMain/kotlin/statement/DragonStatement.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package me.gabriel.ryujin.statement
import me.gabriel.ryujin.struct.DragonType
import me.gabriel.ryujin.struct.Value

interface DragonStatement {
sealed interface DragonStatement {
val memoryDependencies: Set<Value>

fun isValid(): Boolean = true
Expand Down
21 changes: 21 additions & 0 deletions ryujin/src/commonMain/kotlin/statement/Math.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package me.gabriel.ryujin.statement

import me.gabriel.ryujin.struct.DragonType
import me.gabriel.ryujin.struct.Value

class AddStatement(
val left: Value,
val right: Value
) : TypedDragonStatement {
override val memoryDependencies: Set<Value>
get() = setOf(left, right)

override fun isValid(): Boolean {
return left.type == right.type
}

override val type: DragonType get() = left.type

override fun llvm(): String =
"add ${type.llvm} ${left.llvm()}, ${right.llvm()}"
}
10 changes: 10 additions & 0 deletions ryujin/src/commonMain/kotlin/statement/Pointers.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ import me.gabriel.ryujin.struct.Memory
import me.gabriel.ryujin.struct.Value
import me.gabriel.ryujin.struct.descendOneLevel

class AssignStatement(
val memory: Memory,
val value: TypedDragonStatement
): DragonStatement {
override val memoryDependencies: Set<Value> = setOf(memory) + value.memoryDependencies

override fun llvm(): String =
"%${memory.register} = ${value.llvm()}"
}

class StoreStatement(
val value: Value,
val target: Memory
Expand Down
3 changes: 1 addition & 2 deletions ryujin/src/commonMain/kotlin/struct/Dependency.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,9 @@ sealed interface Dependency {

data class Constant(
val name: String,
val type: DragonType,
val value: Value
): Dependency {
override fun asType(): DragonType = type
override fun asType(): DragonType = value.type
}

fun asType(): DragonType
Expand Down
6 changes: 3 additions & 3 deletions ryujin/src/commonMain/kotlin/struct/Type.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ sealed class DragonType(
val types: Collection<DragonType>
) : DragonType("%$name", 8, 0)

data class Dynamic(
data class VirtualTable(
val types: List<DragonType>
): DragonType(types.joinToString(
prefix = "<{",
postfix = "}>",
prefix = "<{ ",
postfix = " }>",
separator = ", "
) { it.llvm }, 8, types.sumOf { it.size })

Expand Down
45 changes: 34 additions & 11 deletions ryujin/src/commonMain/kotlin/struct/Value.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,43 @@ data object Void : Value {
override fun llvm(): String = "void"
}

data class Constant<T : Any>(val value: T, override val type: DragonType): Value {
override fun llvm(): String = value.toString()
}

data class VirtualTable(
val values: List<Value>
): Value {
override val type: DragonType = DragonType.Dynamic(listOf())

override fun llvm(): String = """
abstract class Constant(override val type: DragonType): Value {
abstract override fun llvm(): kotlin.String

class Number(
val value: Long,
type: DragonType
): Constant(type) {
override fun llvm(): kotlin.String = "$value"
}

class FunctionPtr(
val name: kotlin.String,
): Constant(
type = DragonType.Ptr
) {
override fun llvm(): kotlin.String = "@$name"
}

data class String(
val value: kotlin.String
): Constant(
type = DragonType.Array(DragonType.Int8, value.length + 1)
) {
override fun llvm(): kotlin.String = "c\"$value\\00\""
}

data class VirtualTable(
val values: Collection<Value>
): Constant(
type = DragonType.VirtualTable(values.map { it.type })
) {
override fun llvm(): kotlin.String = """
|<{
${values.joinToString(",\n") { "|${it.type.llvm} ${it.llvm()}" }}
${values.joinToString(",\n") { "| ${it.type.llvm} ${it.llvm()}" }}
|}>
""".trimMargin()
}
}

sealed class Memory(
Expand Down
Loading

0 comments on commit 8d59af2

Please sign in to comment.