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:
Vasily Levchenko
2016-11-02 11:15:55 +03:00
committed by vvlevchenko
parent 147de5d3ad
commit 76ee79adc0
2 changed files with 53 additions and 18 deletions
@@ -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<String, LLVMOpaqueValue?>()
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())
}
@@ -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?>): 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?>): 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.
}
}
//-------------------------------------------------------------------------//