From 8ec62ba474daf19c877766a949384930d39f95df Mon Sep 17 00:00:00 2001 From: Nikolay Igotti Date: Wed, 21 Dec 2016 14:20:57 +0300 Subject: [PATCH] Change code structure by adding explicit epilogue. (#150) --- .../jetbrains/kotlin/backend/konan/Context.kt | 2 +- .../backend/konan/llvm/CodeGenerator.kt | 78 ++++++++++++++----- .../kotlin/backend/konan/llvm/DataLayout.kt | 2 + .../kotlin/backend/konan/llvm/IrToBitcode.kt | 37 +++++---- 4 files changed, 78 insertions(+), 41 deletions(-) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt index 1c9d09f5ff5..231cff7f324 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt @@ -61,7 +61,7 @@ internal final class Context(val config: KonanConfig, fun printDescriptors() { separator("Descriptors after: ${phase?.description}") - moduleDescriptor!!.deepPrint() + moduleDescriptor.deepPrint() } fun verifyIr() { diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt index 4774260a3ed..0954b1aa59b 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt @@ -4,6 +4,7 @@ package org.jetbrains.kotlin.backend.konan.llvm import kotlinx.cinterop.* import llvm.* import org.jetbrains.kotlin.backend.konan.Context +import org.jetbrains.kotlin.descriptors.ConstructorDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor @@ -11,31 +12,57 @@ import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.types.KotlinType internal class CodeGenerator(override val context: Context) : ContextUtils { - var currentFunction:FunctionDescriptor? = null + var function: LLVMValueRef? = null + var returnType: LLVMTypeRef? = null + val returns: MutableMap = mutableMapOf() + // TODO: remove, to make CodeGenerator descriptor-agnostic. + var constructedClass: ClassDescriptor? = null - fun prologue(declaration: IrFunction) { - assert(declaration.body != null) - - val descriptor = declaration.descriptor - if (currentFunction == descriptor) return - currentFunction = declaration.descriptor - val fn = declaration.descriptor.llvmFunction - prologueBb = LLVMAppendBasicBlock(fn, "prologue") - entryBb = LLVMAppendBasicBlock(fn, "entry") - positionAtEnd(entryBb!!) - } - - - fun epilogue(declaration: IrFunction) { - appendingTo(prologueBb!!) { - br(entryBb!!) + fun prologue(descriptor: FunctionDescriptor) { + prologue(llvmFunction(descriptor), + LLVMGetReturnType(getLlvmFunctionType(descriptor))!!) + if (descriptor is ConstructorDescriptor) { + constructedClass = descriptor.constructedClass } } - fun fields(descriptor: ClassDescriptor):List = descriptor.fields + fun prologue(function:LLVMValueRef, returnType:LLVMTypeRef) { + assert(returns.size == 0) + + assert(this.function != function) + this.function = function + this.returnType = returnType + this.constructedClass = null + prologueBb = LLVMAppendBasicBlock(function, "prologue") + entryBb = LLVMAppendBasicBlock(function, "entry") + epilogueBb = LLVMAppendBasicBlock(function, "epilogue") + positionAtEnd(entryBb!!) + } + + fun epilogue() { + appendingTo(prologueBb!!) { + br(entryBb!!) + } + + appendingTo(epilogueBb!!) { + when { + returnType == voidType -> LLVMBuildRetVoid(builder) + returns.size > 0 -> { + val returnPhi = phi(returnType!!) + addPhiIncoming(returnPhi, *returns.toList().toTypedArray()) + LLVMBuildRet(builder, returnPhi) + } + // Do nothing, all paths throw. + else -> LLVMBuildUnreachable(builder) + } + } + + returns.clear() + } private var prologueBb: LLVMBasicBlockRef? = null private var entryBb: LLVMBasicBlockRef? = null + private var epilogueBb: LLVMBasicBlockRef? = null fun setName(value: LLVMValueRef, name: String) = LLVMSetValueName(value, name) @@ -138,7 +165,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils { fun basicBlock(function: LLVMValueRef, name: String = "label_"): LLVMBasicBlockRef = LLVMAppendBasicBlock(function, name)!! - fun lastBasicBlock(): LLVMBasicBlockRef? = LLVMGetLastBasicBlock(currentFunction!!.llvmFunction) + fun lastBasicBlock(): LLVMBasicBlockRef? = LLVMGetLastBasicBlock(function) fun functionLlvmValue(descriptor: FunctionDescriptor) = descriptor.llvmFunction fun functionEntryPointAddress(descriptor: FunctionDescriptor) = descriptor.entryPointAddress.llvm @@ -157,7 +184,16 @@ internal class CodeGenerator(override val context: Context) : ContextUtils { } fun ret(value: LLVMValueRef?): LLVMValueRef { - val res = LLVMBuildRet(builder, value)!! + val res = LLVMBuildBr(builder, epilogueBb)!! + + if (returns.get(currentBlock) != null) { + // TODO: enable error throwing. + throw Error("ret() in the same basic block twice!") + } + + if (value != null) + returns[currentBlock] = value + currentPositionHolder.setAfterTerminator() return res } @@ -181,7 +217,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils { fun getBuilder(): LLVMBuilderRef { if (isAfterTerminator) { - positionAtEnd(basicBlock(currentFunction!!.llvmFunction, "unreachable")) + positionAtEnd(basicBlock(function!!, "unreachable")) } return builder diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/DataLayout.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/DataLayout.kt index 86cc3387f0d..0f80fb3e007 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/DataLayout.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/DataLayout.kt @@ -16,6 +16,8 @@ internal fun ContextUtils.getLLVMType(type: KotlinType): LLVMTypeRef { KotlinBuiltIns.isInt(type) -> LLVMInt32Type() KotlinBuiltIns.isLong(type) -> LLVMInt64Type() KotlinBuiltIns.isUnit(type) -> LLVMVoidType() // TODO: handle Unit parameter case + // TODO: stdlib have methods taking Nothing, such as kotlin.collections.EmptySet.contains(). + // KotlinBuiltIns.isNothing(type) -> LLVMVoidType() KotlinBuiltIns.isFloat(type) -> LLVMFloatType() KotlinBuiltIns.isDouble(type) -> LLVMDoubleType() !KotlinBuiltIns.isPrimitiveType(type) -> this.kObjHeaderPtr 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 7dff7977e30..53532069190 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 @@ -244,12 +244,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid fun createInitBody(initName: String) { val initFunction = LLVMAddFunction(context.llvmModule, initName, kVoidFuncType)!! // create LLVM function + codegen.prologue(initFunction, voidType) using(FunctionScope(initFunction)) { - val bbEnter = LLVMAppendBasicBlock(initFunction, "label_enter")!! - codegen.positionAtEnd(bbEnter) - - context.llvm.fileInitializers.forEachIndexed { - i, it -> + context.llvm.fileInitializers.forEach { val irField = it as IrField val descriptor = irField.descriptor val initialization = evaluateExpression(irField.initializer) @@ -258,6 +255,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid } codegen.ret(null) } + codegen.epilogue() } //-------------------------------------------------------------------------// @@ -277,12 +275,11 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid fun createInitCtor(ctorName: String, nodeName: String) { val ctorFunction = LLVMAddFunction(context.llvmModule, ctorName, kVoidFuncType)!! // Create constructor function. - val bbEnter = LLVMAppendBasicBlock(ctorFunction, "label_enter")!! // Create basic block. - - codegen.positionAtEnd(bbEnter) + codegen.prologue(ctorFunction, voidType) val initNodePtr = LLVMGetNamedGlobal(context.llvmModule, nodeName)!! // Get LLVM function initializing globals of current file. codegen.call(context.llvm.appendToInitalizersTail, initNodePtr.singletonList(), "") // Add node to the tail of initializers list. codegen.ret(null) + codegen.epilogue() context.llvm.staticInitializers.add(ctorFunction) // Push newly created constructor in staticInitializers list. } @@ -374,7 +371,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid return } - codegen.prologue(constructorDeclaration) + + codegen.prologue(constructorDeclaration.descriptor) + val constructorDescriptor = constructorDeclaration.descriptor val classDescriptor = constructorDescriptor.constructedClass @@ -433,7 +432,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid codegen.ret(thisPtr) } - codegen.epilogue(constructorDeclaration) + codegen.epilogue() context.log("visitConstructor : ${ir2string(constructorDeclaration)}") } @@ -448,9 +447,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid override fun visitBlockBody(body: IrBlockBody) { using(VariableScope()) { super.visitBlockBody(body) - val function = codegen.currentFunction!! - if (function !is ConstructorDescriptor && !codegen.isAfterTerminator()) { - if (function.returnType!!.isUnit()) { + // TODO: write it properly! + if (codegen.constructedClass == null && !codegen.isAfterTerminator()) { + if (codegen.returnType == voidType) { codegen.ret(null) } else { codegen.unreachable() @@ -470,7 +469,6 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid override fun visitCall(expression: IrCall) { context.log("visitCall : ${ir2string(expression)}") - val isUnit = KotlinBuiltIns.isUnit(expression.descriptor.returnType!!) evaluateExpression(expression) } @@ -606,15 +604,17 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid if (declaration.descriptor.modality == Modality.ABSTRACT || declaration.body == null) return - codegen.prologue(declaration) + + codegen.prologue(declaration.descriptor) using(FunctionScope(declaration)) { declaration.acceptChildrenVoid(this) } - codegen.epilogue(declaration) + codegen.epilogue() - verifyModule(context.llvmModule!!, ir2string(declaration)) + verifyModule(context.llvmModule!!, + "${declaration.descriptor.containingDeclaration}::${ir2string(declaration)}") } //-------------------------------------------------------------------------// @@ -1923,7 +1923,6 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid arg0: LLVMValueRef, arg1: LLVMValueRef): LLVMValueRef { val arg0Type = callee.argument0.type - val arg1Type = callee.argument1.type return when { KotlinBuiltIns.isPrimitiveType(arg0Type) -> TODO("${ir2string(callee)}") @@ -2009,7 +2008,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid fun delegatingConstructorCall(descriptor: ClassConstructorDescriptor, args: List): LLVMValueRef { - val constructedClass = (codegen.currentFunction!! as ConstructorDescriptor).constructedClass + val constructedClass = codegen.constructedClass!! val thisPtr = currentCodeContext.genGetValue(constructedClass.thisAsReceiverParameter) val thisPtrArgType = codegen.getLLVMType(descriptor.allValueParameters[0].type)