Change code structure by adding explicit epilogue. (#150)

This commit is contained in:
Nikolay Igotti
2016-12-21 14:20:57 +03:00
committed by GitHub
parent 16079ce6af
commit 8ec62ba474
4 changed files with 78 additions and 41 deletions
@@ -61,7 +61,7 @@ internal final class Context(val config: KonanConfig,
fun printDescriptors() {
separator("Descriptors after: ${phase?.description}")
moduleDescriptor!!.deepPrint()
moduleDescriptor.deepPrint()
}
fun verifyIr() {
@@ -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<LLVMBasicBlockRef, LLVMValueRef> = 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<PropertyDescriptor> = 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
@@ -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
@@ -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>): 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)