From cf466e0cd77bc6ef26810b502b2ac7415564b71f Mon Sep 17 00:00:00 2001 From: Vasily Levchenko Date: Mon, 21 Nov 2016 17:09:53 +0300 Subject: [PATCH] =?UTF-8?q?codegen:=20fix=20implementation=20of=20branch?= =?UTF-8?q?=20generation=20to=20generate=20'ternary'=20operator=20for=20co?= =?UTF-8?q?de:=20--------8<--------=20>=20cat=20../backend.native/tests/ru?= =?UTF-8?q?ntime/basic/hello4.kt=20fun=20main(args=20:=20Array)=20?= =?UTF-8?q?{=20=20=20=20=20val=20x=20=3D=202=20=20=20=20=20println(if=20(x?= =?UTF-8?q?=20=3D=3D=202)=20"Hello"=20else=20"=D0=9F=D1=80=D0=B8=D0=B2?= =?UTF-8?q?=D0=B5=D1=82")=20=20=20=20=20println(if=20(x=20=3D=3D=203)=20"B?= =?UTF-8?q?ye"=20else=20"=D0=9F=D0=BE=D0=BA=D0=B0")=20=20}=20--------8<---?= =?UTF-8?q?-----=20code=20generator=20produces:=20--------8<--------=20>?= =?UTF-8?q?=20llvm-dis-mp-3.8=20../backend.native/tests/runtime/basic/hell?= =?UTF-8?q?o4.kt.bc=20-o=20-=20;=20ModuleID=20=3D=20'../backend.native/tes?= =?UTF-8?q?ts/runtime/basic/hello4.kt.bc'=20target=20datalayout=20=3D=20"e?= =?UTF-8?q?-m:o-i64:64-f80:128-n8:16:32:64-S128"=20target=20triple=20=3D?= =?UTF-8?q?=20"x86=5F64-apple-macosx10.12.0"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... define void @"kfun:main(Array)"(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<-------- --- .../kotlin/backend/konan/llvm/IrToBitcode.kt | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index f5dbc09b6ce..e3393a68d14 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -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. } }