diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/IrToBitcode.kt index 2c48f301ba8..9ea49cf4dd0 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/IrToBitcode.kt @@ -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() == "") { - 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() 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? { + 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? { 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? { + 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 = 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 { - 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" + } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/Logger.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/Logger.kt new file mode 100644 index 00000000000..4c228f315a8 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/Logger.kt @@ -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' } +}