Merge pull request #34 from JetBrains/ir-processing-refactoring
Ir processing refactoring
This commit is contained in:
+139
-88
@@ -16,7 +16,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrSetVariableImpl
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
|
||||
|
||||
|
||||
fun emitLLVM(module: IrModuleFragment, runtimeFile: String, outFile: String) {
|
||||
@@ -28,6 +28,7 @@ fun emitLLVM(module: IrModuleFragment, runtimeFile: String, outFile: String) {
|
||||
val context = Context(module, runtime, llvmModule) // TODO: dispose
|
||||
|
||||
module.acceptVoid(RTTIGeneratorVisitor(context))
|
||||
println("\n--- Generate bitcode ------------------------------------------------------\n")
|
||||
module.acceptVoid(CodeGeneratorVisitor(context))
|
||||
memScoped {
|
||||
val errorRef = alloc(Int8Box.ref)
|
||||
@@ -69,6 +70,16 @@ internal class RTTIGeneratorVisitor(context: Context) : IrElementVisitorVoid {
|
||||
internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid {
|
||||
|
||||
val generator = CodeGenerator(context)
|
||||
val logger = Logger(generator, context)
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
override fun visitConstructor(declaration: IrConstructor) {
|
||||
generator.initFunction(declaration)
|
||||
@@ -82,33 +93,42 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
* ret i8* %tmp0
|
||||
*/
|
||||
LLVMBuildRet(context.llvmBuilder, generator.load(thisValue!!, generator.tmpVariable()))
|
||||
logger.log("visitConstructor : ${ir2string(declaration)}")
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
override fun visitBlockBody(body: IrBlockBody) {
|
||||
super.visitBlockBody(body)
|
||||
if (KotlinBuiltIns.isUnit(generator.currentFunction!!.returnType!!)) {
|
||||
LLVMBuildRet(context.llvmBuilder, null)
|
||||
}
|
||||
logger.log("visitBlockBody : ${ir2string(body)}")
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall) {
|
||||
evaluateCall(generator.tmpVariable(), expression)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
override fun visitCall(expression: IrCall) {
|
||||
logger.log("visitCall ${ir2string(expression)}")
|
||||
val isUnit = KotlinBuiltIns.isUnit(expression.descriptor.returnType!!)
|
||||
val tmpVariable = if (isUnit) "" else generator.tmpVariable()
|
||||
evaluateExpression(tmpVariable, expression)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
override fun visitFunction(declaration: IrFunction) {
|
||||
generator.function(declaration)
|
||||
declaration.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
if (declaration.descriptor.kind == ClassKind.ANNOTATION_CLASS) {
|
||||
@@ -120,87 +140,59 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
// do not generate any code for intrinsic classes as they require special handling
|
||||
return
|
||||
}
|
||||
|
||||
super.visitClass(declaration)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
// Create new variable in LLVM ir
|
||||
|
||||
override fun visitVariable(declaration: IrVariable) {
|
||||
logger.log("visitVariable : ${ir2string(declaration)}")
|
||||
val variableName = declaration.descriptor.name.asString()
|
||||
val variableType = declaration.descriptor.type
|
||||
generator.registerVariable(variableName, generator.alloca(variableType, variableName))
|
||||
evaluateExpression(variableName, declaration.initializer)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
override fun visitReturn(expression: IrReturn) {
|
||||
logger.log("visitReturn : ${ir2string(expression)}")
|
||||
val tmpVarName = generator.tmpVariable() // Generate new tmp name.
|
||||
val value = evaluateExpression(tmpVarName, expression.value) //
|
||||
LLVMBuildRet(context.llvmBuilder, value)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
override fun visitSetVariable(expression: IrSetVariable) {
|
||||
logger.log("visitSetVariable : ${ir2string(expression)}")
|
||||
val value = evaluateExpression(generator.tmpVariable(), expression.value)
|
||||
generator.store(value!!, generator.variable(expression.descriptor.name.asString())!!)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun evaluateExpression(tmpVariableName: String, value: IrElement?): LLVMOpaqueValue? {
|
||||
when (value) {
|
||||
is IrCall -> return evaluateCall(tmpVariableName, value)
|
||||
is IrGetValue -> {
|
||||
when (value.descriptor) {
|
||||
is LocalVariableDescriptor, is ValueParameterDescriptor -> {
|
||||
val variable = generator.variable(value.descriptor.name.asString())
|
||||
return generator.load(variable!!, tmpVariableName)
|
||||
}
|
||||
is LazyClassReceiverParameterDescriptor -> {
|
||||
if (value.descriptor.name.asString() == "<this>") {
|
||||
return generator.load(generator.thisVariable(), tmpVariableName)
|
||||
}
|
||||
TODO()
|
||||
}
|
||||
else -> {
|
||||
TODO()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
is IrSetVariable -> {
|
||||
val ret = evaluateExpression(generator.tmpVariable(), value.value)
|
||||
return generator.store(ret!!, generator.variable(value.descriptor.name.asString())!!)
|
||||
}
|
||||
is IrVariable -> {
|
||||
val ret = evaluateExpression(generator.tmpVariable(), value.initializer)
|
||||
val variableName = value.descriptor.name.asString()
|
||||
val variable = generator.alloca(LLVMTypeOf(ret), variableName)
|
||||
generator.registerVariable(variableName, ret!!)
|
||||
return generator.store(ret, variable)
|
||||
}
|
||||
is IrGetField -> {
|
||||
if (value.descriptor.dispatchReceiverParameter != null) {
|
||||
val thisPtr = generator.load(generator.thisVariable(), generator.tmpVariable())
|
||||
val typedPtr = generator.bitcast(pointerType(generator.classType(generator.currentClass!!)), thisPtr, generator.tmpVariable())
|
||||
val fieldPtr = LLVMBuildStructGEP(generator.context.llvmBuilder, typedPtr, generator.indexInClass(value.descriptor), generator.tmpVariable())
|
||||
return generator.load(fieldPtr!!, generator.tmpVariable())
|
||||
}
|
||||
TODO()
|
||||
}
|
||||
|
||||
is IrConst<*> -> when (value.kind) {
|
||||
IrConstKind.Null -> TODO() // LLVMConstPointerNull
|
||||
IrConstKind.Boolean -> TODO()
|
||||
IrConstKind.Char -> TODO()
|
||||
IrConstKind.Byte -> return LLVMConstInt(LLVMInt32Type(), (value.value as Byte).toLong(), 1)
|
||||
IrConstKind.Short -> return LLVMConstInt(LLVMInt32Type(), (value.value as Short).toLong(), 1)
|
||||
IrConstKind.Int -> return LLVMConstInt(LLVMInt32Type(), (value.value as Int).toLong(), 1)
|
||||
IrConstKind.Long -> return LLVMConstInt(LLVMInt64Type(), value.value as Long, 1)
|
||||
IrConstKind.String -> TODO()
|
||||
IrConstKind.Float -> TODO()
|
||||
IrConstKind.Double -> TODO()
|
||||
}
|
||||
|
||||
is IrBlock -> {
|
||||
|
||||
value.statements.dropLast(1).forEach {
|
||||
evaluateExpression(generator.tmpVariable(), it)
|
||||
}
|
||||
return evaluateExpression(generator.tmpVariable(), value.statements.lastOrNull())
|
||||
}
|
||||
|
||||
null -> return null
|
||||
else -> {
|
||||
is IrCall -> return evaluateCall (tmpVariableName, value)
|
||||
is IrGetValue -> return evaluateGetValue (tmpVariableName, value)
|
||||
is IrSetVariable -> return evaluateSetVariable( value)
|
||||
is IrVariable -> return evaluateVariable ( value)
|
||||
is IrGetField -> return evaluateGetField ( value)
|
||||
is IrConst<*> -> return evaluateConst ( value)
|
||||
is IrReturn -> return evaluateReturn ( value)
|
||||
is IrBlock -> return evaluateBlock ( value)
|
||||
null -> return null
|
||||
else -> {
|
||||
TODO()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun evaluateCall(tmpVariableName: String, value: IrMemberAccessExpression?): LLVMOpaqueValue? {
|
||||
logger.log("evaluateCall : $tmpVariableName = ${ir2string(value)}")
|
||||
val args = mutableListOf<LLVMOpaqueValue?>()
|
||||
value!!.acceptChildrenVoid(object:IrElementVisitorVoid{
|
||||
override fun visitElement(element: IrElement) {
|
||||
@@ -220,6 +212,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun evaluateGetValue(tmpVariableName: String, value: IrGetValue): LLVMOpaqueValue {
|
||||
logger.log("evaluateGetValue : $tmpVariableName = ${ir2string(value)}")
|
||||
when (value.descriptor) {
|
||||
is LocalVariableDescriptor,
|
||||
is ValueParameterDescriptor,
|
||||
@@ -242,6 +235,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun evaluateSetVariable(value: IrSetVariable): LLVMOpaqueValue {
|
||||
logger.log("evaluateSetVariable : ${ir2string(value)}")
|
||||
val ret = evaluateExpression(generator.tmpVariable(), value.value)
|
||||
return generator.store(ret!!, generator.variable(value.descriptor.name.asString())!!)
|
||||
}
|
||||
@@ -249,6 +243,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun evaluateVariable(value: IrVariable): LLVMOpaqueValue {
|
||||
logger.log("evaluateVariable : ${ir2string(value)}")
|
||||
val ret = evaluateExpression(generator.tmpVariable(), value.initializer)
|
||||
val variableName = value.descriptor.name.asString()
|
||||
val variable = generator.alloca(LLVMTypeOf(ret), variableName)
|
||||
@@ -259,6 +254,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun evaluateGetField(value: IrGetField): LLVMOpaqueValue {
|
||||
logger.log("evaluateGetField : ${ir2string(value)}")
|
||||
if (value.descriptor.dispatchReceiverParameter != null) {
|
||||
val thisPtr = generator.load(generator.thisVariable(), generator.tmpVariable())
|
||||
val typedPtr = generator.bitcast(pointerType(generator.classType(generator.currentClass!!)), thisPtr, generator.tmpVariable())
|
||||
@@ -268,10 +264,54 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
TODO()
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun evaluateConst(value: IrConst<*>): LLVMOpaqueValue? {
|
||||
logger.log("evaluateConst : ${ir2string(value)}")
|
||||
when (value.kind) {
|
||||
IrConstKind.Null -> TODO() // LLVMConstPointerNull
|
||||
IrConstKind.Boolean -> when (value.value) {
|
||||
true -> return LLVMConstInt(LLVMInt1Type(), 1, 1)
|
||||
false -> return LLVMConstInt(LLVMInt1Type(), 0, 1)
|
||||
}
|
||||
IrConstKind.Char -> TODO()
|
||||
IrConstKind.Byte -> return LLVMConstInt(LLVMInt32Type(), (value.value as Byte).toLong(), 1)
|
||||
IrConstKind.Short -> return LLVMConstInt(LLVMInt32Type(), (value.value as Short).toLong(), 1)
|
||||
IrConstKind.Int -> return LLVMConstInt(LLVMInt32Type(), (value.value as Int).toLong(), 1)
|
||||
IrConstKind.Long -> return LLVMConstInt(LLVMInt64Type(), value.value as Long, 1)
|
||||
IrConstKind.String -> TODO()
|
||||
IrConstKind.Float -> TODO()
|
||||
IrConstKind.Double -> TODO()
|
||||
}
|
||||
TODO()
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun evaluateReturn(value: IrReturn): LLVMOpaqueValue? {
|
||||
logger.log("evaluateReturn : ${ir2string(value)}")
|
||||
val ret = evaluateExpression(generator.tmpVariable(), value.value)
|
||||
return LLVMBuildRet(context.llvmBuilder, ret)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun evaluateBlock(value: IrBlock): LLVMOpaqueValue? {
|
||||
logger.log("evaluateBlock : ${ir2string(value)}")
|
||||
value.statements.dropLast(1).forEach {
|
||||
evaluateExpression(generator.tmpVariable(), it)
|
||||
}
|
||||
return evaluateExpression(generator.tmpVariable(), value.statements.lastOrNull())
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun evaluateSimpleFunctionCall(tmpVariableName: String, value: IrCall, args: MutableList<LLVMOpaqueValue?>): LLVMOpaqueValue? {
|
||||
logger.log("evaluateSimpleFunctionCall : $tmpVariableName = ${ir2string(value)}")
|
||||
return generator.call(value.descriptor as FunctionDescriptor, args, tmpVariableName)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun evaluateFunctionCall(tmpVariableName: String, callee: IrCall, args: MutableList<LLVMOpaqueValue?>): LLVMOpaqueValue? {
|
||||
val descriptor:FunctionDescriptor = callee.descriptor as FunctionDescriptor
|
||||
@@ -284,12 +324,14 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun evaluateConstructorCall(variableName: String, callee: IrCall, args: MutableList<LLVMOpaqueValue?>): LLVMOpaqueValue? {
|
||||
logger.log("evaluateConstructorCall : $variableName = ${ir2string(callee)}")
|
||||
memScoped {
|
||||
val params = allocNativeArrayOf(LLVMOpaqueValue, generator.typeInfoValue((callee.descriptor as ClassConstructorDescriptor).containingDeclaration), Int32(1).getLlvmValue())
|
||||
val thisValue = LLVMBuildCall(context.llvmBuilder, context.allocInstanceFunction, params[0], 2, variableName)
|
||||
|
||||
|
||||
val constructorParams: MutableList<LLVMOpaqueValue?> = mutableListOf()
|
||||
constructorParams += thisValue
|
||||
constructorParams += args
|
||||
@@ -297,31 +339,40 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
|
||||
private fun evaluateOperatorCall(tmpVariableName: String, callee: IrCall, args: MutableList<LLVMOpaqueValue?>): LLVMOpaqueValue {
|
||||
when (callee!!.origin) {
|
||||
IrStatementOrigin.PLUS -> return generator.plus(args[0]!!, args[1]!!, tmpVariableName)
|
||||
IrStatementOrigin.MINUS -> return generator.minus(args[0]!!, args[1]!!, tmpVariableName)
|
||||
IrStatementOrigin.MUL -> return generator.mul(args[0]!!, args[1]!!, tmpVariableName)
|
||||
IrStatementOrigin.DIV -> return generator.div(args[0]!!, args[1]!!, tmpVariableName)
|
||||
IrStatementOrigin.PERC -> return generator.srem(args[0]!!, args[1]!!, tmpVariableName)
|
||||
logger.log("evaluateCall $tmpVariableName = ${ir2string(callee)}")
|
||||
when (callee.origin) {
|
||||
IrStatementOrigin.PLUS -> return generator.plus (args[0]!!, args[1]!!, tmpVariableName)
|
||||
IrStatementOrigin.MINUS -> return generator.minus (args[0]!!, args[1]!!, tmpVariableName)
|
||||
IrStatementOrigin.MUL -> return generator.mul (args[0]!!, args[1]!!, tmpVariableName)
|
||||
IrStatementOrigin.DIV -> return generator.div (args[0]!!, args[1]!!, tmpVariableName)
|
||||
IrStatementOrigin.PERC -> return generator.srem (args[0]!!, args[1]!!, tmpVariableName)
|
||||
else -> {
|
||||
TODO()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitVariable(declaration: IrVariable) {
|
||||
val variableName = declaration.descriptor.name.asString()
|
||||
val variableType = declaration.descriptor.type
|
||||
generator.registerVariable(variableName, generator.alloca(variableType, variableName))
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
evaluateExpression(variableName, declaration.initializer)
|
||||
private fun generateWhenCase(branch: IrBranch, bbTrue: LLVMOpaqueBasicBlock?, bbFalse: LLVMOpaqueBasicBlock?, bbExit: LLVMOpaqueBasicBlock?) {
|
||||
val condition = evaluateExpression(generator.tmpVariable(), branch.condition) // Get boolean cmp result.
|
||||
LLVMBuildCondBr(context.llvmBuilder, condition, bbTrue, bbFalse) // Conditional branch depending on cmp result.
|
||||
LLVMPositionBuilderAtEnd(context.llvmBuilder, bbTrue) // Switch generation to bbTrue.
|
||||
evaluateExpression(generator.tmpVariable(), branch.result) // Generate clause expression.
|
||||
if (bbExit != null) // If clause code contains "return".
|
||||
LLVMBuildBr(context.llvmBuilder, bbExit) // Do not generate branch to bbExit.
|
||||
LLVMPositionBuilderAtEnd(context.llvmBuilder, bbFalse) // Switch generation to bbFalse.
|
||||
}
|
||||
|
||||
override fun visitReturn(expression: IrReturn) {
|
||||
val tmpVarName = generator.tmpVariable()
|
||||
val value:LLVMOpaqueValue?
|
||||
value = evaluateExpression(tmpVarName, expression.value)
|
||||
LLVMBuildRet(context.llvmBuilder, value)
|
||||
}
|
||||
//-------------------------------------------------------------------------//
|
||||
// Checks if the branch is unconditional
|
||||
|
||||
private fun isUnconditional(branch: IrBranch): Boolean =
|
||||
branch.condition is IrConst<*> // If branch condition is constant.
|
||||
&& (branch.condition as IrConst<*>).value as Boolean // If condition is "true"
|
||||
|
||||
}
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package org.jetbrains.kotlin.backend.native.llvm
|
||||
|
||||
import kotlin_native.interop.asCString
|
||||
import llvm.LLVMPrintModuleToString
|
||||
import llvm.LLVMPrintValueToString
|
||||
import org.jetbrains.kotlin.backend.native.llvm.Context
|
||||
import org.jetbrains.kotlin.backend.native.llvm.ContextUtils
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.util.DumpIrTreeVisitor
|
||||
import java.io.StringWriter
|
||||
|
||||
internal class Logger(val generator: CodeGenerator, override val context: Context) : ContextUtils {
|
||||
private var logcounter: Int = LLVMPrintModuleToString(context.llvmModule)!!.asCString().toString().lines().size
|
||||
|
||||
//---------------------------------------------------------------------------//
|
||||
|
||||
fun log(msg: String) {
|
||||
logIr()
|
||||
println(msg)
|
||||
}
|
||||
|
||||
fun logIr() {
|
||||
val function = generator.currentFunction ?: return
|
||||
|
||||
val irFunctionDeclaration = LLVMPrintValueToString(function.llvmFunction.getLlvmValue())!!.asCString().toString()
|
||||
irFunctionDeclaration.lines().forEach { println(" $it") }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
fun ir2string(ir: IrElement?): String {
|
||||
val strWriter = StringWriter()
|
||||
|
||||
ir?.accept(DumpIrTreeVisitor(strWriter), "")
|
||||
return strWriter.toString().takeWhile { it != '\n' }
|
||||
}
|
||||
@@ -129,9 +129,9 @@ task sum (type:UnitKonanTest) {
|
||||
source = "codegen/function/sum.kt"
|
||||
}
|
||||
|
||||
task objectInitialization(type: UnitKonanTest) {
|
||||
/*task objectInitialization(type: UnitKonanTest) {
|
||||
source = "codegen/object/initialization.kt"
|
||||
}
|
||||
}*/
|
||||
|
||||
/* task objectBasic(type: KonanTest) {
|
||||
source = "$codegen/klass/basic.kt"
|
||||
|
||||
Reference in New Issue
Block a user