-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: ryujin, a better llvm library & dsl
- Loading branch information
1 parent
a78fd91
commit aec92c9
Showing
13 changed files
with
369 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
plugins { | ||
kotlin("multiplatform") | ||
} | ||
|
||
repositories { | ||
mavenCentral() | ||
} | ||
|
||
kotlin { | ||
jvm() | ||
mingwX64() | ||
linuxX64() | ||
iosArm64() | ||
macosX64() | ||
js().browser() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package me.gabriel.ryujin | ||
|
||
import me.gabriel.ryujin.function.DragonFunction | ||
import me.gabriel.ryujin.struct.Dependency | ||
|
||
// Yes, I will be using the dragon prefix. | ||
// Blame camelCase/PascalCase for being so shitty. (LLVMModule... seriously?) | ||
interface DragonModule { | ||
val functions: MutableSet<DragonFunction> | ||
val dependencies: MutableSet<Dependency> | ||
|
||
fun addDependency(dependency: Dependency) { | ||
dependencies.add(dependency) | ||
} | ||
|
||
fun addDependencies(vararg dependencies: Dependency) { | ||
this.dependencies.addAll(dependencies) | ||
} | ||
|
||
fun removeDependency(dependency: Dependency) { | ||
dependencies.remove(dependency) | ||
} | ||
|
||
fun removeDependencies(vararg dependencies: Dependency) { | ||
this.dependencies.removeAll(dependencies) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package me.gabriel.ryujin.dsl | ||
|
||
import me.gabriel.ryujin.function.DragonFunction | ||
import me.gabriel.ryujin.statement.DragonStatement | ||
|
||
class FunctionScopeDsl( | ||
val module: ModuleScopeDsl, | ||
val function: DragonFunction | ||
) { | ||
fun statement(statement: DragonStatement) { | ||
function.statements.add(statement) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
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 | ||
|
||
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 | ||
) { | ||
val function = DragonFunction( | ||
module = this, | ||
name = name, | ||
parameters = parameters, | ||
returnType = returnType | ||
) | ||
FunctionScopeDsl( | ||
module = this, | ||
function = function | ||
).apply(block) | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package me.gabriel.ryujin.function | ||
|
||
import me.gabriel.ryujin.DragonModule | ||
import me.gabriel.ryujin.statement.DragonStatement | ||
import me.gabriel.ryujin.struct.DragonType | ||
|
||
class DragonFunction( | ||
val module: DragonModule, | ||
val name: String, | ||
val parameters: Map<String, DragonType>, | ||
val returnType: DragonType | ||
) { | ||
val statements = mutableListOf<DragonStatement>() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package me.gabriel.ryujin.statement | ||
|
||
import me.gabriel.ryujin.struct.DragonType | ||
import me.gabriel.ryujin.struct.Value | ||
|
||
interface DragonStatement { | ||
val memoryDependencies: Set<Value> | ||
|
||
fun isValid(): Boolean = true | ||
|
||
fun llvm(): String | ||
} | ||
|
||
interface TypedDragonStatement : DragonStatement { | ||
val type: DragonType | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package me.gabriel.ryujin.statement | ||
|
||
import me.gabriel.ryujin.struct.DragonType | ||
import me.gabriel.ryujin.struct.Memory | ||
import me.gabriel.ryujin.struct.Value | ||
import me.gabriel.ryujin.struct.descendOneLevel | ||
|
||
class StoreStatement( | ||
val value: Value, | ||
val target: Memory | ||
): DragonStatement { | ||
override val memoryDependencies: Set<Value> = setOf(value, target) | ||
|
||
override fun llvm(): String = | ||
"store ${value.type.llvm} ${value.llvm()}, ${target.type.llvm} ${target.llvm()}" | ||
} | ||
|
||
class GetElementPointerStatement( | ||
val struct: Memory, | ||
override val type: DragonType, | ||
val index: Value, | ||
val total: Boolean = true, | ||
val inbounds: Boolean = true | ||
): TypedDragonStatement { | ||
override val memoryDependencies: Set<Value> = setOf(index, struct) | ||
|
||
val originalType = if (struct.type !is DragonType.Pointer) { | ||
struct.type | ||
} else { | ||
(struct.type as DragonType.Pointer).type | ||
} | ||
val pointerType = DragonType.Pointer(originalType) | ||
|
||
override fun llvm(): String = | ||
"getelementptr " + | ||
(if (inbounds) { | ||
"inbounds " | ||
} else { | ||
"" | ||
}) + | ||
"${originalType.llvm}, ${pointerType.llvm} ${struct.llvm()}" + (if (total) { | ||
", i32 0" | ||
} else { | ||
"" | ||
}) + ", i32 ${index.llvm()}" | ||
} | ||
|
||
class LoadStatement( | ||
val target: Memory | ||
): TypedDragonStatement { | ||
override val memoryDependencies: Set<Value> = setOf(target) | ||
|
||
override fun isValid(): Boolean = | ||
target.type is DragonType.Pointer | ||
|
||
override val type: DragonType = target.type.descendOneLevel() | ||
|
||
override fun llvm(): String { | ||
require(isValid()) { "Cannot load from non-pointer type" } | ||
return "load ${type.llvm}, ${target.type.llvm} ${target.llvm()}" | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package me.gabriel.ryujin.struct | ||
|
||
sealed interface Dependency { | ||
data class Function( | ||
val name: String, | ||
val returnType: DragonType, | ||
val parameters: List<DragonType> | ||
): Dependency { | ||
override fun asType(): DragonType = DragonType.Void | ||
} | ||
|
||
data class Struct( | ||
val name: String, | ||
val types: Collection<DragonType> | ||
): Dependency { | ||
override fun asType(): DragonType = DragonType.Struct(name, types) | ||
} | ||
|
||
data class Constant( | ||
val name: String, | ||
val type: DragonType, | ||
val value: Value | ||
): Dependency { | ||
override fun asType(): DragonType = type | ||
} | ||
|
||
fun asType(): DragonType | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package me.gabriel.ryujin.struct | ||
|
||
sealed class DragonType( | ||
val llvm: String, | ||
val defaultAlignment: Int, | ||
val size: Int | ||
) { | ||
data object Void : DragonType("void", 0, 0) | ||
data object Int1 : DragonType("i1", 1, 1) | ||
data object Int8 : DragonType("i8", 1, 1) | ||
data object Int16 : DragonType("i16", 2, 2) | ||
data object Int32 : DragonType("i32", 4, 4) | ||
data object Int64 : DragonType("i64", 8, 8) | ||
|
||
data object Float32 : DragonType("float", 4, 4) | ||
data object Float64 : DragonType("double", 8, 8) | ||
|
||
data class Array(val type: DragonType, val length: Int) : DragonType("[$length x ${type.llvm}]", type.defaultAlignment, type.size * length) | ||
|
||
data object Ptr : DragonType("ptr", 1, 1) | ||
data class Pointer(val type: DragonType) : DragonType(if (type == Void) type.llvm else "${type.llvm}*", 8, 8) | ||
|
||
data class Struct( | ||
val name: String, | ||
val types: Collection<DragonType> | ||
) : DragonType("%$name", 8, types.sumOf { it.size }) | ||
|
||
data class Trait( | ||
val name: String, | ||
val types: Collection<DragonType> | ||
) : DragonType("%$name", 8, 0) | ||
|
||
data class Dynamic( | ||
val types: List<DragonType> | ||
): DragonType(types.joinToString( | ||
prefix = "<{", | ||
postfix = "}>", | ||
separator = ", " | ||
) { it.llvm }, 8, types.sumOf { it.size }) | ||
|
||
override fun toString(): String = llvm | ||
} | ||
|
||
fun DragonType.extractPrimitiveType() = when (this) { | ||
is DragonType.Array -> this.type | ||
is DragonType.Pointer -> this.type | ||
else -> this | ||
} | ||
|
||
fun DragonType.descendOneLevel(): DragonType = when (this) { | ||
is DragonType.Array -> this.type | ||
is DragonType.Pointer -> this.type | ||
else -> error("Cannot descend one level on type $this") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package me.gabriel.ryujin.struct | ||
|
||
sealed interface Value { | ||
val type: DragonType | ||
|
||
fun llvm(): String | ||
} | ||
|
||
data object Void : Value { | ||
override val type: DragonType = DragonType.Int1 | ||
|
||
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 = """ | ||
|<{ | ||
${values.joinToString(",\n") { "|${it.type.llvm} ${it.llvm()}" }} | ||
|}> | ||
""".trimMargin() | ||
} | ||
|
||
sealed class Memory( | ||
val register: Int, | ||
override val type: DragonType | ||
): Value { | ||
class Sized(register: Int, type: DragonType, val size: Int) : Memory(register, type) | ||
|
||
class Unsized(register: Int, type: DragonType) : Memory(register, type) | ||
|
||
override fun llvm(): String = "%$register" | ||
} |
54 changes: 54 additions & 0 deletions
54
ryujin/src/commonMain/kotlin/transcript/DefaultDragonIrTranscriber.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package me.gabriel.ryujin.transcript | ||
|
||
import me.gabriel.ryujin.DragonModule | ||
import me.gabriel.ryujin.function.DragonFunction | ||
import me.gabriel.ryujin.struct.Dependency | ||
|
||
class DefaultDragonIrTranscriber: DragonIrTranscriber { | ||
override fun transcribe(module: DragonModule): String { | ||
val dependencies = module.dependencies.joinToString("\n") { transcribeDependency(it) } | ||
val functions = module.functions.joinToString("\n") { transcribeFunction(it) } | ||
|
||
return """ | ||
|$dependencies | ||
| | ||
|$functions | ||
""".trimMargin(marginPrefix = "|") | ||
} | ||
|
||
override fun transcribeDependency(dependency: Dependency): String { | ||
return when (dependency) { | ||
is Dependency.Constant -> transcribeConstantDependency(dependency) | ||
is Dependency.Struct -> transcribeStructDependency(dependency) | ||
is Dependency.Function -> transcribeFunctionDependency(dependency) | ||
} | ||
} | ||
|
||
override fun transcribeFunction(function: DragonFunction): String { | ||
return buildString { | ||
append("define ${function.returnType} @${function.name}(") | ||
append(function.parameters.entries.joinToString(", ") { "${it.value} %${it.key}" }) | ||
append(") {\n") | ||
function.statements.forEach { append(" $it\n") } | ||
append("}") | ||
} | ||
} | ||
|
||
private fun transcribeConstantDependency(dependency: Dependency.Constant): String { | ||
return """ | ||
|@${dependency.name} = unnamed_addr constant ${dependency.type} ${dependency.value.llvm()} | ||
""".trimMargin(marginPrefix = "|") | ||
} | ||
|
||
private fun transcribeStructDependency(dependency: Dependency.Struct): String { | ||
return """ | ||
|%${dependency.name} = type { ${dependency.types.joinToString(", ") {it.llvm}} } | ||
""".trimMargin(marginPrefix = "|") | ||
} | ||
|
||
private fun transcribeFunctionDependency(dependency: Dependency.Function): String { | ||
return """ | ||
|declare ${dependency.returnType} @${dependency.name}(${dependency.parameters.joinToString(", ") {it.llvm}}) | ||
""".trimMargin(marginPrefix = "|") | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
ryujin/src/commonMain/kotlin/transcript/DragonIrTranscriber.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package me.gabriel.ryujin.transcript | ||
|
||
import me.gabriel.ryujin.DragonModule | ||
import me.gabriel.ryujin.function.DragonFunction | ||
import me.gabriel.ryujin.struct.Dependency | ||
|
||
interface DragonIrTranscriber { | ||
fun transcribe(module: DragonModule): String | ||
|
||
fun transcribeDependency(dependency: Dependency): String | ||
|
||
fun transcribeFunction(function: DragonFunction): String | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,4 +17,5 @@ include("analysis") | |
include("compiler") | ||
include("tools") | ||
|
||
include("ryujin") | ||
include("runestone") |