codegen: fix implementation of branch generation to generate 'ternary' operator
for code:
--------8<--------
> cat ../backend.native/tests/runtime/basic/hello4.kt
fun main(args : Array<String>) {
val x = 2
println(if (x == 2) "Hello" else "Привет")
println(if (x == 3) "Bye" else "Пока")
}
--------8<--------
code generator produces:
--------8<--------
> llvm-dis-mp-3.8 ../backend.native/tests/runtime/basic/hello4.kt.bc -o -
; ModuleID = '../backend.native/tests/runtime/basic/hello4.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 void @"kfun:main(Array<String>)"(i8*) {
entry:
%args = alloca i8*
store i8* %0, i8** %args
%x = alloca i32
store i32 2, i32* %x
%tmp_1 = alloca i8* ; allocation of temporal variable (0)
%tmp_3 = load i32, i32* %x
%tmp_2 = icmp eq i32 %tmp_3, 2
br i1 %tmp_2, label %label_2, label %label_1
label_0: ; preds = %label_2, %label_1
%tmp_0 = load i8*, i8** %tmp_1 ; load value from tmp_1 (2)
call void @Kotlin_io_Console_println(i8* %tmp_0)
%tmp_8 = alloca i8*
%tmp_10 = load i32, i32* %x
%tmp_9 = icmp eq i32 %tmp_10, 3
br i1 %tmp_9, label %label_5, label %label_4
label_1: ; preds = %entry store value to tmp_1 (1)
store i8* @"kstr:KAWujn4S8YITX5L7kIQ7sQgNO+g=", i8** %tmp_1
br label %label_0
label_2: ; preds = %entry
store i8* @"kstr:9/+ei3uy4Jtwk1pdeF4MxdnQq/A=", i8** %tmp_1
br label %label_0
label_3: ; preds = %label_5, %label_4
%tmp_7 = load i8*, i8** %tmp_8
call void @Kotlin_io_Console_println(i8* %tmp_7)
ret void
label_4: ; preds = %label_0
store i8* @"kstr:q9lt9dN14ItE52B0fKxQuwMq4cc=", i8** %tmp_8
br label %label_3
label_5: ; preds = %label_0
store i8* @"kstr:95JCQGTQyhp9FO/gWI8QwFLSjmk=", i8** %tmp_8
br label %label_3
}
...
--------8<--------
This commit is contained in:
committed by
vvlevchenko
parent
c54e786c33
commit
cf466e0cd7
+25
-11
@@ -96,7 +96,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
|
||||
override fun visitWhen(expression: IrWhen) {
|
||||
logger.log("visitWhen : ${ir2string(expression)}")
|
||||
evaluateWhen(expression)
|
||||
evaluateWhen("", expression)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
@@ -326,7 +326,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
is IrReturn -> return evaluateReturn ( value)
|
||||
is IrBlock -> return evaluateBlock ( value)
|
||||
is IrExpressionBody -> return evaluateExpression (tmpVariableName, value.expression)
|
||||
is IrWhen -> return evaluateWhen ( value)
|
||||
is IrWhen -> return evaluateWhen (tmpVariableName, value)
|
||||
null -> return null
|
||||
else -> {
|
||||
TODO()
|
||||
@@ -336,17 +336,26 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun evaluateWhen(expression: IrWhen): LLVMOpaqueValue? {
|
||||
var bbExit:LLVMOpaqueBasicBlock? = null // By default "when" does not have "exit"
|
||||
private fun evaluateWhen(tmpVariableName:String, expression: IrWhen): LLVMOpaqueValue? {
|
||||
logger.log("evaluateWhen : ${ir2string(expression)}")
|
||||
var bbExit:LLVMOpaqueBasicBlock? = null // By default "when" does not have "exit".
|
||||
if (!KotlinBuiltIns.isNothing(expression.type)) // If "when" has "exit".
|
||||
bbExit = codegen.basicBlock() // Create basic block to process "exit".
|
||||
|
||||
val isUnit = KotlinBuiltIns.isUnit(expression.type)
|
||||
val isNothing = KotlinBuiltIns.isNothing(expression.type)
|
||||
val neitherUnitNorNothing = !isNothing && !isUnit
|
||||
val tmpVariable = if (!isUnit) codegen.newVar() else null
|
||||
val tmpLlvmVariablePtr = if (!isUnit) codegen.alloca(expression.type, tmpVariable!!) else null
|
||||
|
||||
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 = codegen.basicBlock() // Create new basic block for next clause.
|
||||
generateWhenCase(it, bbNext, bbExit) // Generate code for current clause.
|
||||
generateWhenCase(isUnit, isNothing, tmpLlvmVariablePtr, it, bbNext, bbExit) // Generate code for current clause.
|
||||
}
|
||||
if (neitherUnitNorNothing) // If result hasn't Unit type and block doesn't end with return
|
||||
return codegen.load(tmpLlvmVariablePtr!!, tmpVariableName) // load value from variable.
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -717,10 +726,13 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun generateWhenCase(branch: IrBranch, bbNext: LLVMOpaqueBasicBlock?, bbExit: LLVMOpaqueBasicBlock?) {
|
||||
private fun generateWhenCase(isUnit:Boolean, isNothing:Boolean, resultPtr:LLVMOpaqueValue?, branch: IrBranch, bbNext: LLVMOpaqueBasicBlock?, bbExit: LLVMOpaqueBasicBlock?) {
|
||||
val neitherUnitNorNothing = !isNothing && !isUnit // If branches doesn't end with 'return' either result hasn't got 'unit' type.
|
||||
if (isUnconditional(branch)) { // It is the "else" clause.
|
||||
evaluateExpression(codegen.newVar(), branch.result) // Generate clause body.
|
||||
if (bbExit == null) return // If "when" does not have exit - return.
|
||||
val brResult = evaluateExpression(codegen.newVar(), branch.result) // Generate clause body.
|
||||
if (neitherUnitNorNothing) // If nor unit neither result ends with return
|
||||
codegen.store(brResult!!, resultPtr!!) // we store result to temporal variable.
|
||||
if (bbExit == null) return // If 'bbExit' isn't defined just return
|
||||
codegen.br(bbExit) // Generate branch to bbExit.
|
||||
codegen.positionAtEnd(bbExit) // Switch generation to bbExit.
|
||||
} else { // It is conditional clause.
|
||||
@@ -728,9 +740,11 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
val condition = evaluateExpression(codegen.newVar(), branch.condition) // Generate cmp instruction.
|
||||
codegen.condBr(condition, bbCurr, bbNext) // Conditional branch depending on cmp result.
|
||||
codegen.positionAtEnd(bbCurr!!) // Switch generation to block for clause body.
|
||||
evaluateExpression(codegen.newVar(), branch.result) // Generate clause body.
|
||||
if (!KotlinBuiltIns.isNothing(branch.result.type)) // If clause code does not contain "return".
|
||||
codegen.br(bbExit!!) // Generate branch to bbExit.
|
||||
val brResult = evaluateExpression(codegen.newVar(), branch.result) // Generate clause body.
|
||||
if (neitherUnitNorNothing) // If nor unit neither result ends with return
|
||||
codegen.store(brResult!!, resultPtr!!) // we store result to temporal variable.
|
||||
if (!isNothing) // If basic block doesn't end with 'return'
|
||||
codegen.br(bbExit!!) // generate branch to bbExit.
|
||||
codegen.positionAtEnd(bbNext!!) // Switch generation to bbNextClause.
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user