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? {
|
||||
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())
|
||||
}
|
||||
|
||||
|
||||
|
||||
+37
-13
@@ -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.
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
Reference in New Issue
Block a user