diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/CodeGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/CodeGenerator.kt index f5416fbd781..ac00f7d5306 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/CodeGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/CodeGenerator.kt @@ -76,7 +76,8 @@ internal class CodeGenerator(override val context:Context) : ContextUtils { private fun prolog(declaration: IrFunction): LLVMOpaqueValue? { - index = 0 + variableIndex = 0 + labelIndex = 0 currentFunction = declaration.descriptor val fn = declaration.descriptor.llvmFunction.getLlvmValue() val block = LLVMAppendBasicBlock(fn, "entry") @@ -90,12 +91,18 @@ internal class CodeGenerator(override val context:Context) : ContextUtils { val variablesGlobal = mapOf() fun variable(varName:String):LLVMOpaqueValue? = currentFunction!!.variable(varName) - var index:Int = 0 + private var variableIndex:Int = 0 private var FunctionDescriptor.tmpVariableIndex: Int - get() = index - set(i:Int){ index = i} + get() = variableIndex + set(i:Int) { variableIndex = i} - fun FunctionDescriptor.tmpVariable():String = "tmp${tmpVariableIndex++}" + private var labelIndex:Int = 0 + private var FunctionDescriptor.bbLabelIndex: Int + get() = labelIndex + set(i:Int) { labelIndex = i} + + fun FunctionDescriptor.tmpVariable():String = "tmp_${tmpVariableIndex++}" + fun FunctionDescriptor.bbLabel():String = "label_${bbLabelIndex++}" fun registerVariable(varName: String, value:LLVMOpaqueValue) = currentFunction!!.registerVariable(varName, value) @@ -117,6 +124,7 @@ internal class CodeGenerator(override val context:Context) : ContextUtils { fun minus(arg0: LLVMOpaqueValue, arg1: LLVMOpaqueValue, result: String): LLVMOpaqueValue = LLVMBuildSub (context.llvmBuilder, arg0, arg1, result)!! fun div (arg0: LLVMOpaqueValue, arg1: LLVMOpaqueValue, result: String): LLVMOpaqueValue = LLVMBuildSDiv(context.llvmBuilder, arg0, arg1, result)!! fun srem (arg0: LLVMOpaqueValue, arg1: LLVMOpaqueValue, result: String): LLVMOpaqueValue = LLVMBuildSRem(context.llvmBuilder, arg0, arg1, result)!! + fun icmpEq(arg0: LLVMOpaqueValue, arg1: LLVMOpaqueValue, result: String): LLVMOpaqueValue = LLVMBuildICmp(context.llvmBuilder, LLVMIntPredicate.LLVMIntEQ, arg0!!, arg1!!, result)!! fun bitcast(type: LLVMOpaqueType?, value: LLVMOpaqueValue, result: String) = LLVMBuildBitCast(context.llvmBuilder, value, type, result) @@ -166,6 +174,9 @@ internal class CodeGenerator(override val context:Context) : ContextUtils { fun param(fn: FunctionDescriptor?, i: Int): LLVMOpaqueValue? = LLVMGetParam(fn!!.llvmFunction.getLlvmValue(), i) fun indexInClass(p:PropertyDescriptor):Int = currentClass!!.fields.indexOf(p) + + fun basicBlock(): LLVMOpaqueBasicBlock? = LLVMAppendBasicBlock(currentFunction!!.llvmFunction.getLlvmValue(), currentFunction!!.bbLabel()) + fun lastBasicBlock(): LLVMOpaqueBasicBlock? = LLVMGetLastBasicBlock(currentFunction!!.llvmFunction.getLlvmValue()) } 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 b581bd69c2e..7be136ade0a 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 @@ -72,7 +72,6 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid val generator = CodeGenerator(context) val logger = Logger(generator, context) - //-------------------------------------------------------------------------// override fun visitElement(element: IrElement) { @@ -81,6 +80,22 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid //-------------------------------------------------------------------------// + override fun visitWhen(expression: IrWhen) { + logger.log("visitWhen : ${ir2string(expression)}") + var bbExit:LLVMOpaqueBasicBlock? = null // By default "when" does not have "exit" + if (!KotlinBuiltIns.isNothing(expression.type)) // If "when" has "exit". + bbExit = generator.basicBlock() // Create basic block to process "exit". + + expression.branches.forEach { // Iterate through "when" branches (clauses). + var bbNext = bbExit // For last clause bbNext coincides with bbExit. + if (it != expression.branches.last()) // If it is not last clause. + bbNext = generator.basicBlock() // Create new basic block for next clause. + generateWhenCase(it, bbNext, bbExit) // Generate code for current clause. + } + } + + //-------------------------------------------------------------------------// + override fun visitConstructor(declaration: IrConstructor) { generator.initFunction(declaration) val thisValue = generator.variable("this") @@ -149,8 +164,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid 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) + val newVariable = generator.alloca(variableType, variableName) // Create LLVM variable. + generator.registerVariable(variableName, newVariable) // Map variableName -> LLVM variable. + evaluateExpression(variableName, declaration.initializer) // Generate initialization code. } //-------------------------------------------------------------------------// @@ -317,7 +333,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid private fun evaluateFunctionCall(tmpVariableName: String, callee: IrCall, args: MutableList): LLVMOpaqueValue? { val descriptor:FunctionDescriptor = callee.descriptor as FunctionDescriptor when { - descriptor.isOperator -> return evaluateOperatorCall(tmpVariableName, callee, args) + descriptor.isOperator || descriptor is IrBuiltinOperatorDescriptorBase -> return evaluateOperatorCall(tmpVariableName, callee, args) descriptor is ClassConstructorDescriptor -> return evaluateConstructorCall(tmpVariableName, callee, args) else -> { return evaluateSimpleFunctionCall(tmpVariableName, callee, args) @@ -342,7 +358,6 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid //-------------------------------------------------------------------------// - private fun evaluateOperatorCall(tmpVariableName: String, callee: IrCall, args: MutableList): LLVMOpaqueValue { logger.log("evaluateCall $tmpVariableName = ${ir2string(callee)}") when (callee.origin) { @@ -351,6 +366,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid 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) + IrStatementOrigin.EQEQ -> return generator.icmpEq(args[0]!!, args[1]!!, tmpVariableName) else -> { TODO() } @@ -359,14 +375,22 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid //-------------------------------------------------------------------------// - 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. + private fun generateWhenCase(branch: IrBranch, bbNext: LLVMOpaqueBasicBlock?, bbExit: LLVMOpaqueBasicBlock?) { + if (isUnconditional(branch)) { // It is the "else" clause. + evaluateExpression(generator.tmpVariable(), branch.result) // Generate clause body. + if (bbExit == null) return // If "when" does not have exit - return. + LLVMBuildBr(context.llvmBuilder, bbExit) // Generate branch to bbExit. + LLVMPositionBuilderAtEnd(context.llvmBuilder, bbExit) // Switch generation to bbExit. + } else { // It is conditional clause. + val bbCurr = generator.basicBlock() // Create block for clause body. + val condition = evaluateExpression(generator.tmpVariable(), branch.condition) // Generate cmp instruction. + LLVMBuildCondBr(context.llvmBuilder, condition, bbCurr, bbNext) // Conditional branch depending on cmp result. + LLVMPositionBuilderAtEnd(context.llvmBuilder, bbCurr) // Switch generation to block for clause body. + evaluateExpression(generator.tmpVariable(), branch.result) // Generate clause body. + if (!KotlinBuiltIns.isNothing(branch.result.type)) // If clause code does not contain "return". + LLVMBuildBr(context.llvmBuilder, bbExit) // Generate branch to bbExit. + LLVMPositionBuilderAtEnd(context.llvmBuilder, bbNext) // Switch generation to bbNextClause. + } } //-------------------------------------------------------------------------//