From 4e5e7d37ee520085cbb778fa58ea80f94959b3d5 Mon Sep 17 00:00:00 2001 From: Konstantin Anisimov Date: Wed, 2 Nov 2016 16:14:55 +0300 Subject: [PATCH] Implemented support for loop codegeneration: "while" and "do-while". for code "while loop": -------------8<------------- > cat ../backend.native/tests/codegen/cycles/cycle.kt fun cycle(cnt: Int): Int { var sum = 1 while (sum == cnt) { sum = sum + 1 } return sum } -------------8<------------- translator generates: -------------8<------------- > llvm-dis-mp-3.8 ../backend.native/tests/codegen/cycles/cycle.kt.bc -o - ; ModuleID = '../backend.native/tests/codegen/cycles/cycle.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:cycle"(i32) { entry: %cnt = alloca i32 store i32 %0, i32* %cnt %sum = alloca i32 store i32 1, i32* %sum br label %label_0 label_0: ; preds = %label_1, %entry %tmp1 = load i32, i32* %sum %tmp2 = load i32, i32* %cnt %tmp0 = icmp eq i32 %tmp1, %tmp2 br i1 %tmp0, label %label_1, label %label_2 label_1: ; preds = %label_0 %tmp6 = load i32, i32* %sum %tmp5 = add i32 %tmp6, 1 store i32 %tmp5, i32* %sum br label %label_0 label_2: ; preds = %label_0 %tmp8 = load i32, i32* %sum ret i32 %tmp8 } -------------8<------------- for "do-while" code: -------------8<------------- > cat ../backend.native/tests/codegen/cycles/cycle_do.kt fun cycle_do(cnt: Int): Int { var sum = 1 do { sum = sum + 2 } while (sum == cnt) return sum } -------------8<------------- translator produces: -------------8<------------- > llvm-dis-mp-3.8 ../backend.native/tests/codegen/cycles/cycle_do.kt.bc -o - ; ModuleID = '../backend.native/tests/codegen/cycles/cycle_do.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:cycle_do"(i32) { entry: %cnt = alloca i32 store i32 %0, i32* %cnt %sum = alloca i32 store i32 1, i32* %sum br label %label_0 label_0: ; preds = %label_1, %entry %tmp3 = load i32, i32* %sum %tmp2 = add i32 %tmp3, 2 store i32 %tmp2, i32* %sum br label %label_1 label_1: ; preds = %label_0 %tmp6 = load i32, i32* %sum %tmp7 = load i32, i32* %cnt %tmp5 = icmp eq i32 %tmp6, %tmp7 br i1 %tmp5, label %label_0, label %label_2 label_2: ; preds = %label_1 %tmp8 = load i32, i32* %sum ret i32 %tmp8 } -------------8<------------- --- .../kotlin/backend/konan/llvm/IrToBitcode.kt | 101 +++++++++++++----- 1 file changed, 74 insertions(+), 27 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 4226eb73548..3c5be011128 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 @@ -97,6 +97,52 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid //-------------------------------------------------------------------------// + override fun visitLoop(loop: IrLoop) { + TODO() + } + + //-------------------------------------------------------------------------// + + override fun visitWhileLoop(loop: IrWhileLoop) { + val loopEnter = generator.basicBlock() + val loopBody = generator.basicBlock() + val loopExit = generator.basicBlock() + + LLVMBuildBr(context.llvmBuilder, loopEnter) + + LLVMPositionBuilderAtEnd(context.llvmBuilder, loopEnter) + val condition = evaluateExpression(generator.tmpVariable(), loop.condition) + LLVMBuildCondBr(context.llvmBuilder, condition, loopBody, loopExit) + + LLVMPositionBuilderAtEnd(context.llvmBuilder, loopBody) + evaluateExpression(generator.tmpVariable(), loop.body) + + LLVMBuildBr(context.llvmBuilder, loopEnter) + LLVMPositionBuilderAtEnd(context.llvmBuilder, loopExit) + } + + //-------------------------------------------------------------------------// + + override fun visitDoWhileLoop(loop: IrDoWhileLoop) { + val loopBody = generator.basicBlock() + val loopCheck = generator.basicBlock() + val loopExit = generator.basicBlock() + + LLVMBuildBr(context.llvmBuilder, loopBody) + + LLVMPositionBuilderAtEnd(context.llvmBuilder, loopBody) + evaluateExpression(generator.tmpVariable(), loop.body) + LLVMBuildBr(context.llvmBuilder, loopCheck) + + LLVMPositionBuilderAtEnd(context.llvmBuilder, loopCheck) + val condition = evaluateExpression(generator.tmpVariable(), loop.condition) + LLVMBuildCondBr(context.llvmBuilder, condition, loopBody, loopExit) + + LLVMPositionBuilderAtEnd(context.llvmBuilder, loopExit) + } + + //-------------------------------------------------------------------------// + override fun visitConstructor(declaration: IrConstructor) { generator.initFunction(declaration) val thisValue = generator.variable("this") @@ -166,9 +212,10 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid logger.log("visitVariable : ${ir2string(declaration)}") val variableName = declaration.descriptor.name.asString() val variableType = declaration.descriptor.type - val newVariable = generator.alloca(variableType, variableName) // Create LLVM variable. - generator.registerVariable(variableName, newVariable) // Map variableName -> LLVM variable. - evaluateExpression(variableName, declaration.initializer) // Generate initialization code. + val newVariable = generator.alloca(variableType, variableName) // Create LLVM variable. + generator.registerVariable(variableName, newVariable) // Map variableName -> LLVM variable. + val value = evaluateExpression(variableName, declaration.initializer) // Generate initialization code. + generator.store(value!!, generator.variable(variableName)!!) // Store init result in the variable } //-------------------------------------------------------------------------// @@ -192,16 +239,16 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid private fun evaluateExpression(tmpVariableName: String, value: IrElement?): LLVMOpaqueValue? { when (value) { - is IrCall -> return evaluateCall (tmpVariableName, value) - is IrGetValue -> return evaluateGetValue (tmpVariableName, value) - is IrSetVariable -> return evaluateSetVariable( value) - is IrVariable -> return evaluateVariable ( value) - is IrGetField -> return evaluateGetField ( value) - is IrConst<*> -> return evaluateConst ( value) - is IrReturn -> return evaluateReturn ( value) - is IrBlock -> return evaluateBlock ( value) - null -> return null - else -> { + is IrCall -> return evaluateCall (tmpVariableName, value) + is IrGetValue -> return evaluateGetValue (tmpVariableName, value) + is IrSetVariable -> return evaluateSetVariable ( value) + is IrVariable -> return evaluateVariable ( value) + is IrGetField -> return evaluateGetField ( value) + is IrConst<*> -> return evaluateConst ( value) + is IrReturn -> return evaluateReturn ( value) + is IrBlock -> return evaluateBlock ( value) + null -> return null + else -> { TODO() } } @@ -211,16 +258,17 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid private fun evaluateCall(tmpVariableName: String, value: IrMemberAccessExpression?): LLVMOpaqueValue? { logger.log("evaluateCall : $tmpVariableName = ${ir2string(value)}") - val args = mutableListOf() - value!!.acceptChildrenVoid(object:IrElementVisitorVoid{ - override fun visitElement(element: IrElement) { - val tmp = generator.tmpVariable() - args.add(evaluateExpression(tmp, element as IrExpression)) + val args = mutableListOf() // Create list of function args. + value!!.acceptChildrenVoid(object: IrElementVisitorVoid { // Iterate args of the function. + override fun visitElement(element: IrElement) { // Visit arg. + val tmp = generator.tmpVariable() // Create variable representing the arg in generator + args.add(evaluateExpression(tmp, element as IrExpression)) // Evaluate expression and get LLVM arg } }) + when { - value is IrDelegatingConstructorCall -> return generator.superCall(tmpVariableName, value.descriptor, args) value.descriptor is FunctionDescriptor -> return evaluateFunctionCall(tmpVariableName, value as IrCall, args) + value is IrDelegatingConstructorCall -> return generator.superCall(tmpVariableName, value.descriptor, args) else -> { TODO() } @@ -335,11 +383,10 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid private fun evaluateFunctionCall(tmpVariableName: String, callee: IrCall, args: MutableList): LLVMOpaqueValue? { val descriptor:FunctionDescriptor = callee.descriptor as FunctionDescriptor when { - descriptor.isOperator || descriptor is IrBuiltinOperatorDescriptorBase -> return evaluateOperatorCall(tmpVariableName, callee, args) - descriptor is ClassConstructorDescriptor -> return evaluateConstructorCall(tmpVariableName, callee, args) - else -> { - return evaluateSimpleFunctionCall(tmpVariableName, callee, args) - } + descriptor.isOperator -> return evaluateOperatorCall(tmpVariableName, callee.origin!!, args) + descriptor is IrBuiltinOperatorDescriptorBase -> return evaluateOperatorCall(tmpVariableName, callee.origin!!, args) + descriptor is ClassConstructorDescriptor -> return evaluateConstructorCall(tmpVariableName, callee, args) + else -> return evaluateSimpleFunctionCall(tmpVariableName, callee, args) } } @@ -360,9 +407,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid //-------------------------------------------------------------------------// - private fun evaluateOperatorCall(tmpVariableName: String, callee: IrCall, args: MutableList): LLVMOpaqueValue { - logger.log("evaluateCall $tmpVariableName = ${ir2string(callee)}") - when (callee.origin) { + private fun evaluateOperatorCall(tmpVariableName: String, origin: IrStatementOrigin, args: MutableList): LLVMOpaqueValue { + logger.log("evaluateCall $tmpVariableName origin:$origin") + when (origin) { IrStatementOrigin.PLUS -> return generator.plus (args[0]!!, args[1]!!, tmpVariableName) IrStatementOrigin.MINUS -> return generator.minus (args[0]!!, args[1]!!, tmpVariableName) IrStatementOrigin.PLUSEQ -> return generator.plus (args[0]!!, args[1]!!, tmpVariableName)