refactoring: refactoring: reordering, splitting.

(cherry picked from commit 89fc5d6416a6e7075901ac19dea44475f7184fd3)
This commit is contained in:
Konstantin Anisimov
2016-11-01 14:00:30 +03:00
committed by Vasily Levchenko
parent 922cb1f35d
commit fb1652a1d5
2 changed files with 177 additions and 88 deletions
@@ -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"
}
@@ -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' }
}