Skip to content
This repository has been archived by the owner on Feb 16, 2025. It is now read-only.

Commit

Permalink
perf(new-llvm): heavy llvm purity/redundancy optimizations
Browse files Browse the repository at this point in the history
  • Loading branch information
SrGaabriel committed Sep 9, 2024
1 parent bf1765c commit 434132d
Show file tree
Hide file tree
Showing 27 changed files with 184 additions and 55 deletions.
5 changes: 5 additions & 0 deletions analysis/src/commonMain/kotlin/Errors.kt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ sealed class AnalysisError(val message: String, val node: SyntaxTreeNode) {
node
)

class ImpureFunctionCall(node: CallNode, impure: String, from: String) : AnalysisError(
"impure function call from pure function: $impure() from $from",
node
)

class InvalidCondition(node: SyntaxTreeNode, type: SeleneType) : AnalysisError(
"invalid condition: condition must be a boolean expression, got ${type.signature}",
node
Expand Down
8 changes: 8 additions & 0 deletions analysis/src/commonMain/kotlin/SymbolBlock.kt
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,14 @@ class SymbolBlock(
}
}

fun findCurrentFunction(): FunctionNode? {
return when {
id is FunctionNode -> id
parent != null -> parent.findCurrentFunction()
else -> null
}
}

override fun toString(): String {
return "SymbolBlock(module='$module', self=$self)"
}
Expand Down
10 changes: 10 additions & 0 deletions analysis/src/commonMain/kotlin/analyzers/impl/CallAnalyzer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,16 @@ class CallAnalyzer: SingleNodeAnalyzer<CallNode>(CallNode::class) {
functionModule = function.module
))
}
val currentFunction = block.findCurrentFunction()
if (currentFunction == null) {
// TODO: add compiler error
error("No current function found")
}

if (function.modifiers.contains(Modifiers.IMPURE) && currentFunction != null && !currentFunction.modifiers.contains(Modifiers.IMPURE)) {
currentFunction.modifiers.add(Modifiers.IMPURE)
}

return block
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class TraitAnalyzer: SingleNodeAnalyzer<TraitNode>(TraitNode::class) {
it.type = treatedType
}
},
modifiers = emptyList()
modifiers = emptySet()
)
}
)
Expand Down
2 changes: 1 addition & 1 deletion analysis/src/commonMain/kotlin/signature/Signatures.kt
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ data class SignatureFunction(
val name: String,
val returnType: SeleneType,
val parameters: List<SeleneType>,
val modifiers: List<Modifiers>
val modifiers: Set<Modifiers>
)

@Serializable
Expand Down
4 changes: 2 additions & 2 deletions backend/common/src/commonMain/kotlin/SeleneCompilerBackend.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package me.gabriel.selene.backend.common

import me.gabriel.selene.backend.common.intrinsic.IntrinsicFunctionRepository

interface SeleneCompilerBackend<Context : Any, Value : Any> {
val intrinsics: IntrinsicFunctionRepository<Context, Value>
interface SeleneCompilerBackend<Context : Any, Module : Any, Value : Any> {
val intrinsics: IntrinsicFunctionRepository<Context, Module, Value>

fun compile(
module: SeleneCompilerModule
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package me.gabriel.selene.backend.common.intrinsic

abstract class IntrinsicFunctionExecutor<Context : Any, Value : Any> {
abstract class IntrinsicFunctionExecutor<Context : Any, Module : Any, Value : Any> {
open fun setup(module: Module) {}

abstract fun onCall(context: Context): Value
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package me.gabriel.selene.backend.common.intrinsic

abstract class IntrinsicFunctionRepository<Context : Any, Value : Any> {
abstract val intrinsics: MutableMap<String, IntrinsicFunctionExecutor<Context, Value>>
abstract class IntrinsicFunctionRepository<Context : Any, Module : Any, Value : Any> {
abstract val intrinsics: MutableMap<String, IntrinsicFunctionExecutor<Context, Module, Value>>

fun register(name: String, executor: IntrinsicFunctionExecutor<Context, Value>) {
fun register(name: String, executor: IntrinsicFunctionExecutor<Context, Module, Value>) {
intrinsics[name] = executor
}

fun find(name: String): IntrinsicFunctionExecutor<Context, Value>? {
fun find(name: String): IntrinsicFunctionExecutor<Context, Module, Value>? {
return intrinsics[name]
}

Expand Down
5 changes: 3 additions & 2 deletions backend/llvm/src/commonMain/kotlin/DragonCompilerBackend.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package me.gabriel.selene.backend.llvm

import me.gabriel.ryujin.dsl.ModuleScopeDsl
import me.gabriel.ryujin.struct.Value
import me.gabriel.ryujin.transcript.DefaultDragonIrTranscriber
import me.gabriel.ryujin.transcript.DragonIrTranscriber
Expand All @@ -9,10 +10,10 @@ import me.gabriel.selene.backend.common.intrinsic.IntrinsicFunctionRepository
import me.gabriel.selene.backend.llvm.intrinsic.DragonIntrinsicFunctionRepository
import me.gabriel.selene.backend.llvm.session.SeleneDragonCompilingSession

class DragonCompilerBackend: SeleneCompilerBackend<DragonHookContext, Value> {
class DragonCompilerBackend: SeleneCompilerBackend<DragonHookContext, ModuleScopeDsl, Value> {
var irTranscriber: DragonIrTranscriber = DefaultDragonIrTranscriber()

override val intrinsics: IntrinsicFunctionRepository<DragonHookContext, Value> = DragonIntrinsicFunctionRepository()
override val intrinsics: IntrinsicFunctionRepository<DragonHookContext, ModuleScopeDsl, Value> = DragonIntrinsicFunctionRepository()

override fun compile(module: SeleneCompilerModule): String {
val session = SeleneDragonCompilingSession(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package me.gabriel.selene.backend.llvm.intrinsic

import me.gabriel.ryujin.dsl.ModuleScopeDsl
import me.gabriel.ryujin.struct.Value
import me.gabriel.selene.backend.common.intrinsic.IntrinsicFunctionExecutor
import me.gabriel.selene.backend.common.intrinsic.IntrinsicFunctionRepository
import me.gabriel.selene.backend.llvm.DragonHookContext

class DragonIntrinsicFunctionRepository: IntrinsicFunctionRepository<DragonHookContext, Value>() {
override val intrinsics: MutableMap<String, IntrinsicFunctionExecutor<DragonHookContext, Value>> = mutableMapOf(
class DragonIntrinsicFunctionRepository: IntrinsicFunctionRepository<DragonHookContext, ModuleScopeDsl, Value>() {
override val intrinsics: MutableMap<String, IntrinsicFunctionExecutor<DragonHookContext, ModuleScopeDsl, Value>> = mutableMapOf(
"println" to PrintlnIntrinsicFunctionExecutor()
)
}
11 changes: 7 additions & 4 deletions backend/llvm/src/commonMain/kotlin/intrinsic/Print.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package me.gabriel.selene.backend.llvm.intrinsic

import me.gabriel.ryujin.dsl.ModuleScopeDsl
import me.gabriel.ryujin.struct.DragonType
import me.gabriel.ryujin.struct.NullMemory
import me.gabriel.ryujin.struct.Value
import me.gabriel.ryujin.struct.extractPrimitiveType
import me.gabriel.selene.backend.common.intrinsic.IntrinsicFunctionExecutor
import me.gabriel.selene.backend.llvm.DragonHookContext

class PrintlnIntrinsicFunctionExecutor : IntrinsicFunctionExecutor<DragonHookContext, Value>() {
class PrintlnIntrinsicFunctionExecutor : IntrinsicFunctionExecutor<DragonHookContext, ModuleScopeDsl, Value>() {
override fun onCall(context: DragonHookContext): Value {
val singleType = context.argumentValues.map { it.type }.distinct().single()
val (formatName, formatCode) = when (singleType.extractPrimitiveType()) {
Expand All @@ -24,19 +25,21 @@ class PrintlnIntrinsicFunctionExecutor : IntrinsicFunctionExecutor<DragonHookCon
functionName = "printf",
returnType = DragonType.Int32,
arguments = listOf(context.argumentValues.single()),
definition = listOf(DragonType.Pointer(DragonType.Int8))
definition = listOf(DragonType.Pointer(DragonType.Int8)),
pure = false
).ignore()
}
return NullMemory
}

context.functionDsl.run {
val format = useFormat(formatName, formatCode).assign()
val format = useFormat(formatName, formatCode).assign(constantOverride = true)
callExternal(
functionName = "printf",
returnType = DragonType.Int32,
arguments = listOf(format) + context.argumentValues,
definition = listOf(DragonType.Pointer(DragonType.Int8), DragonType.Vararg)
definition = listOf(DragonType.Pointer(DragonType.Int8), DragonType.Vararg),
pure = false
).ignore()
}
return NullMemory
Expand Down
24 changes: 24 additions & 0 deletions backend/llvm/src/commonMain/kotlin/intrinsic/Readln.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package me.gabriel.selene.backend.llvm.intrinsic

import me.gabriel.ryujin.dsl.ModuleScopeDsl
import me.gabriel.ryujin.struct.DragonType
import me.gabriel.ryujin.struct.Value
import me.gabriel.selene.backend.common.intrinsic.IntrinsicFunctionExecutor
import me.gabriel.selene.backend.llvm.DragonHookContext

class ReadlnIntrinsicFunctionExecutor: IntrinsicFunctionExecutor<DragonHookContext, ModuleScopeDsl, Value>() {
override fun onCall(context: DragonHookContext): Value {
TODO("Not yet implemented")
}

override fun setup(module: ModuleScopeDsl) {
module.run {
function(
name = "readln",
returnType = DragonType.Pointer(DragonType.Int8),
parameters = emptyList()
) {
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ import me.gabriel.selene.frontend.parsing.*

class SeleneDragonCompilingSession(
val compilerModule: SeleneCompilerModule,
val intrinsicFunctionRepository: IntrinsicFunctionRepository<DragonHookContext, Value>
val intrinsicFunctionRepository: IntrinsicFunctionRepository<DragonHookContext, ModuleScopeDsl, Value>
) {
private val dsl = ryujinModule {}
private val root = compilerModule.astTree.root
val dsl = ryujinModule {}
val root = compilerModule.astTree.root

// todo: remove
var developmentMode: Boolean = true
Expand All @@ -33,7 +33,7 @@ class SeleneDragonCompilingSession(
}
}

private fun ModuleScopeDsl.generateModuleLevelDeclarations() {
fun ModuleScopeDsl.generateModuleLevelDeclarations() {
for (child in root.getChildren()) {
when (child) {
is FunctionNode -> generateFunction(child)
Expand All @@ -42,8 +42,14 @@ class SeleneDragonCompilingSession(
}
}

private fun ModuleScopeDsl.generateFunction(node: FunctionNode) {
if (node.modifiers.contains(Modifiers.INTRINSIC)) return
fun ModuleScopeDsl.generateFunction(node: FunctionNode) {
if (node.modifiers.contains(Modifiers.INTRINSIC)) {
val intrinsic = intrinsicFunctionRepository.find(node.name)
?: if (developmentMode) return else error("Intrinsic function not found: ${node.name}")

intrinsic.setup(this)
return
}

val returnType = addPointerToStructs(node.returnType.asDragonType())
val parameterTypes = node.parameters.map { addPointerToStructs(it.type.asDragonType()) }
Expand All @@ -62,7 +68,7 @@ class SeleneDragonCompilingSession(
}
}

private fun FunctionScopeDsl.generateInstruction(
fun FunctionScopeDsl.generateInstruction(
block: SymbolBlock,
node: SyntaxTreeNode,
statement: Boolean = false
Expand All @@ -76,13 +82,13 @@ class SeleneDragonCompilingSession(
}
}

private fun FunctionScopeDsl.generateReturn(block: SymbolBlock, node: ReturnNode): Value? {
fun FunctionScopeDsl.generateReturn(block: SymbolBlock, node: ReturnNode): Value? {
val value = generateInstruction(block, node.expression)
`return`(value ?: Void)
return null
}

private fun FunctionScopeDsl.generateCall(
fun FunctionScopeDsl.generateCall(
block: SymbolBlock,
node: CallNode,
statement: Boolean
Expand All @@ -108,19 +114,22 @@ class SeleneDragonCompilingSession(
?: error("Intrinsic function not found: ${node.name}")
return intrinsics.onCall(context)
}
val pure = !signature.modifiers.contains(Modifiers.IMPURE)

val call =
if (signature.module != compilerModule.name) {
callExternal(
functionName = node.name,
returnType = signature.returnType.asDragonType(),
arguments = arguments
arguments = arguments,
pure = pure
)
} else {
call(
functionName = node.name,
returnType = signature.returnType.asDragonType(),
arguments = arguments
arguments = arguments,
pure = pure
)
}
if (statement || signature.returnType == SeleneType.Void) {
Expand All @@ -130,14 +139,14 @@ class SeleneDragonCompilingSession(
return call.assign()
}

private fun FunctionScopeDsl.generateNumber(node: NumberNode): Value {
fun FunctionScopeDsl.generateNumber(node: NumberNode): Value {
return Constant.Number(
type = node.type.asDragonType(),
value = node.value
)
}

private fun FunctionScopeDsl.generateString(node: StringNode): Value {
fun FunctionScopeDsl.generateString(node: StringNode): Value {
val text = (node.segments.single() as StringNode.Segment.Text).text
val format = useFormat("str_${node.hashCode()}", text)
return format.assign()
Expand Down
Loading

0 comments on commit 434132d

Please sign in to comment.