branching: branch suppport introduced
--------------8<----------------
> cat if_else.kt
fun if_else(b: Boolean): Int {
if (b) return 42
else return 24
}
--------------8<----------------
we've got following bitcode:
--------------8<----------------
; ModuleID = '../backend.native/tests/codegen/branching/if_else.kt.bc'
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.12.0"
...
define i32 @"kfun:if_else"(i1) {
entry:
%b = alloca i1
store i1 %0, i1* %b
%tmp0 = load i1, i1* %b
br i1 %tmp0, label %label_0, label %label_1
label_0: ; preds = %entry
ret i32 42
label_1: ; preds = %entry
ret i32 24
}
...
--------------8<----------------
This commit is contained in:
committed by
vvlevchenko
parent
147de5d3ad
commit
76ee79adc0
+16
-5
@@ -76,7 +76,8 @@ internal class CodeGenerator(override val context:Context) : ContextUtils {
|
|||||||
|
|
||||||
|
|
||||||
private fun prolog(declaration: IrFunction): LLVMOpaqueValue? {
|
private fun prolog(declaration: IrFunction): LLVMOpaqueValue? {
|
||||||
index = 0
|
variableIndex = 0
|
||||||
|
labelIndex = 0
|
||||||
currentFunction = declaration.descriptor
|
currentFunction = declaration.descriptor
|
||||||
val fn = declaration.descriptor.llvmFunction.getLlvmValue()
|
val fn = declaration.descriptor.llvmFunction.getLlvmValue()
|
||||||
val block = LLVMAppendBasicBlock(fn, "entry")
|
val block = LLVMAppendBasicBlock(fn, "entry")
|
||||||
@@ -90,12 +91,18 @@ internal class CodeGenerator(override val context:Context) : ContextUtils {
|
|||||||
val variablesGlobal = mapOf<String, LLVMOpaqueValue?>()
|
val variablesGlobal = mapOf<String, LLVMOpaqueValue?>()
|
||||||
fun variable(varName:String):LLVMOpaqueValue? = currentFunction!!.variable(varName)
|
fun variable(varName:String):LLVMOpaqueValue? = currentFunction!!.variable(varName)
|
||||||
|
|
||||||
var index:Int = 0
|
private var variableIndex:Int = 0
|
||||||
private var FunctionDescriptor.tmpVariableIndex: Int
|
private var FunctionDescriptor.tmpVariableIndex: Int
|
||||||
get() = index
|
get() = variableIndex
|
||||||
set(i:Int){ index = i}
|
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)
|
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 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 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 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)
|
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 param(fn: FunctionDescriptor?, i: Int): LLVMOpaqueValue? = LLVMGetParam(fn!!.llvmFunction.getLlvmValue(), i)
|
||||||
|
|
||||||
fun indexInClass(p:PropertyDescriptor):Int = currentClass!!.fields.indexOf(p)
|
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())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+37
-13
@@ -72,7 +72,6 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
val generator = CodeGenerator(context)
|
val generator = CodeGenerator(context)
|
||||||
val logger = Logger(generator, context)
|
val logger = Logger(generator, context)
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
override fun visitElement(element: IrElement) {
|
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) {
|
override fun visitConstructor(declaration: IrConstructor) {
|
||||||
generator.initFunction(declaration)
|
generator.initFunction(declaration)
|
||||||
val thisValue = generator.variable("this")
|
val thisValue = generator.variable("this")
|
||||||
@@ -149,8 +164,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
logger.log("visitVariable : ${ir2string(declaration)}")
|
logger.log("visitVariable : ${ir2string(declaration)}")
|
||||||
val variableName = declaration.descriptor.name.asString()
|
val variableName = declaration.descriptor.name.asString()
|
||||||
val variableType = declaration.descriptor.type
|
val variableType = declaration.descriptor.type
|
||||||
generator.registerVariable(variableName, generator.alloca(variableType, variableName))
|
val newVariable = generator.alloca(variableType, variableName) // Create LLVM variable.
|
||||||
evaluateExpression(variableName, declaration.initializer)
|
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?>): LLVMOpaqueValue? {
|
private fun evaluateFunctionCall(tmpVariableName: String, callee: IrCall, args: MutableList<LLVMOpaqueValue?>): LLVMOpaqueValue? {
|
||||||
val descriptor:FunctionDescriptor = callee.descriptor as FunctionDescriptor
|
val descriptor:FunctionDescriptor = callee.descriptor as FunctionDescriptor
|
||||||
when {
|
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)
|
descriptor is ClassConstructorDescriptor -> return evaluateConstructorCall(tmpVariableName, callee, args)
|
||||||
else -> {
|
else -> {
|
||||||
return evaluateSimpleFunctionCall(tmpVariableName, callee, args)
|
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?>): LLVMOpaqueValue {
|
private fun evaluateOperatorCall(tmpVariableName: String, callee: IrCall, args: MutableList<LLVMOpaqueValue?>): LLVMOpaqueValue {
|
||||||
logger.log("evaluateCall $tmpVariableName = ${ir2string(callee)}")
|
logger.log("evaluateCall $tmpVariableName = ${ir2string(callee)}")
|
||||||
when (callee.origin) {
|
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.MUL -> return generator.mul (args[0]!!, args[1]!!, tmpVariableName)
|
||||||
IrStatementOrigin.DIV -> return generator.div (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.PERC -> return generator.srem (args[0]!!, args[1]!!, tmpVariableName)
|
||||||
|
IrStatementOrigin.EQEQ -> return generator.icmpEq(args[0]!!, args[1]!!, tmpVariableName)
|
||||||
else -> {
|
else -> {
|
||||||
TODO()
|
TODO()
|
||||||
}
|
}
|
||||||
@@ -359,14 +375,22 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
private fun generateWhenCase(branch: IrBranch, bbTrue: LLVMOpaqueBasicBlock?, bbFalse: LLVMOpaqueBasicBlock?, bbExit: LLVMOpaqueBasicBlock?) {
|
private fun generateWhenCase(branch: IrBranch, bbNext: LLVMOpaqueBasicBlock?, bbExit: LLVMOpaqueBasicBlock?) {
|
||||||
val condition = evaluateExpression(generator.tmpVariable(), branch.condition) // Get boolean cmp result.
|
if (isUnconditional(branch)) { // It is the "else" clause.
|
||||||
LLVMBuildCondBr(context.llvmBuilder, condition, bbTrue, bbFalse) // Conditional branch depending on cmp result.
|
evaluateExpression(generator.tmpVariable(), branch.result) // Generate clause body.
|
||||||
LLVMPositionBuilderAtEnd(context.llvmBuilder, bbTrue) // Switch generation to bbTrue.
|
if (bbExit == null) return // If "when" does not have exit - return.
|
||||||
evaluateExpression(generator.tmpVariable(), branch.result) // Generate clause expression.
|
LLVMBuildBr(context.llvmBuilder, bbExit) // Generate branch to bbExit.
|
||||||
if (bbExit != null) // If clause code contains "return".
|
LLVMPositionBuilderAtEnd(context.llvmBuilder, bbExit) // Switch generation to bbExit.
|
||||||
LLVMBuildBr(context.llvmBuilder, bbExit) // Do not generate branch to bbExit.
|
} else { // It is conditional clause.
|
||||||
LLVMPositionBuilderAtEnd(context.llvmBuilder, bbFalse) // Switch generation to bbFalse.
|
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.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|||||||
Reference in New Issue
Block a user