From 27517b0db1d03f0c547f510215b09c4cd54fb2fa Mon Sep 17 00:00:00 2001 From: Vasily Levchenko Date: Fri, 23 Jun 2017 13:34:15 +0300 Subject: [PATCH] [codegen][debug] make runtime debug information friendly to generated one. - inroduced function generation context containing mostly functionality local to function generation - initial debug location is linked with basic block. - then on each expression location is tuned. - removed manual placement of debug location dictations over the place. - refactoring removed unused declarations --- .../backend/konan/llvm/CodeGenerator.kt | 544 ++++++++------- .../kotlin/backend/konan/llvm/IrToBitcode.kt | 631 +++++++++--------- .../backend/konan/llvm/VariableManager.kt | 28 +- runtime/build.gradle | 2 + 4 files changed, 614 insertions(+), 591 deletions(-) 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 30b4eb790f2..ef2ab988fec 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 @@ -20,203 +20,153 @@ package org.jetbrains.kotlin.backend.konan.llvm import kotlinx.cinterop.* import llvm.* import org.jetbrains.kotlin.backend.konan.Context +import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor import org.jetbrains.kotlin.konan.target.KonanTarget -import org.jetbrains.kotlin.descriptors.ConstructorDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.types.KotlinType internal class CodeGenerator(override val context: Context) : ContextUtils { - var function: LLVMValueRef? = null - var returnType: LLVMTypeRef? = null - val returns: MutableMap = mutableMapOf() - // TODO: remove, to make CodeGenerator descriptor-agnostic. - var constructedClass: ClassDescriptor? = null + + fun llvmFunction(function: FunctionDescriptor): LLVMValueRef = function.llvmFunction + val intPtrType = LLVMIntPtrType(llvmTargetData)!! + internal val immOneIntPtrType = LLVMConstInt(intPtrType, 1, 1)!! + + //-------------------------------------------------------------------------// + + /* to class descriptor */ + fun typeInfoValue(descriptor: ClassDescriptor): LLVMValueRef = descriptor.llvmTypeInfoPtr + + fun param(fn: FunctionDescriptor, i: Int): LLVMValueRef { + assert(i >= 0 && i < countParams(fn)) + return LLVMGetParam(fn.llvmFunction, i)!! + } + + private fun countParams(fn: FunctionDescriptor) = LLVMCountParams(fn.llvmFunction) + + fun functionLlvmValue(descriptor: FunctionDescriptor) = descriptor.llvmFunction + fun functionEntryPointAddress(descriptor: FunctionDescriptor) = descriptor.entryPointAddress.llvm + fun functionHash(descriptor: FunctionDescriptor): LLVMValueRef = descriptor.functionName.localHash.llvm +} + +val LLVMValueRef.name:String? + get() = LLVMGetValueName(this)?.toKString() + +val LLVMValueRef.isConst:Boolean + get() = (LLVMIsConstant(this) == 1) + + +internal inline fun generateFunction(codegen: CodeGenerator, + descriptor: FunctionDescriptor, + startLocation: LocationInfo? = null, + endLocation: LocationInfo? = null, + code:FunctionGenerationContext.(FunctionGenerationContext) -> R) { + val llvmFunction = codegen.llvmFunction(descriptor) + + generateFunctionBody(FunctionGenerationContext( + llvmFunction, + codegen, + startLocation, + endLocation, + descriptor), code) +} + + +internal inline fun generateFunction(codegen: CodeGenerator, function: LLVMValueRef, code:FunctionGenerationContext.(FunctionGenerationContext) -> R) { + generateFunctionBody(FunctionGenerationContext(function, codegen), code) +} + +inline private fun generateFunctionBody(functionGenerationContext: FunctionGenerationContext, code: FunctionGenerationContext.(FunctionGenerationContext) -> R) { + functionGenerationContext.prologue() + functionGenerationContext.code(functionGenerationContext) + if (!functionGenerationContext.isAfterTerminator()) { + if (functionGenerationContext.returnType == voidType) + functionGenerationContext.ret(null) + else + functionGenerationContext.unreachable() + } + functionGenerationContext.epilogue() + functionGenerationContext.resetDebugLocation() +} + +internal class FunctionGenerationContext(val function: LLVMValueRef, + val codegen:CodeGenerator, + startLocation:LocationInfo? = null, + endLocation:LocationInfo? = null, + internal val functionDescriptor: FunctionDescriptor? = null):ContextUtils { + override val context = codegen.context val vars = VariableManager(this) - var functionDescriptor: FunctionDescriptor? = null + private val basicBlockToLastLocation = mutableMapOf() + + private fun update(block:LLVMBasicBlockRef, locationInfo: LocationInfo?) { + locationInfo ?: return + basicBlockToLastLocation.put(block, locationInfo) + } + + var returnType: LLVMTypeRef? = LLVMGetReturnType(getFunctionType(function)) + private val returns: MutableMap = mutableMapOf() + // TODO: remove, to make CodeGenerator descriptor-agnostic. + val constructedClass: ClassDescriptor? + get() = (functionDescriptor as? ClassConstructorDescriptor)?.constructedClass private var returnSlot: LLVMValueRef? = null private var slotsPhi: LLVMValueRef? = null private var slotCount = 0 private var localAllocs = 0 private var arenaSlot: LLVMValueRef? = null - val intPtrType = LLVMIntPtrType(llvmTargetData)!! - private val immOneIntPtrType = LLVMConstInt(intPtrType, 1, 1)!! + private val prologueBb = basicBlockInFunction("prologue", startLocation) + private val localsInitBb = basicBlockInFunction("locals_init", startLocation) + private val entryBb = basicBlockInFunction("entry", startLocation) + private val epilogueBb = basicBlockInFunction("epilogue", endLocation) + private val cleanupLandingpad = basicBlockInFunction("cleanup_landingpad", endLocation) - fun prologue(descriptor: FunctionDescriptor, locationInfo: LocationInfo? = null) { - val llvmFunction = llvmFunction(descriptor) - - prologue(llvmFunction, - LLVMGetReturnType(getLlvmFunctionType(descriptor))!!, locationInfo) - - if (!descriptor.isExported()) { - LLVMSetLinkage(llvmFunction, LLVMLinkage.LLVMInternalLinkage) - // (Cannot do this before the function body is created). - } - - if (descriptor is ConstructorDescriptor) { - constructedClass = descriptor.constructedClass - } - functionDescriptor = descriptor - } - - fun prologue(function:LLVMValueRef, returnType:LLVMTypeRef, locationInfo: LocationInfo? = null) { - assert(returns.size == 0) - assert(this.function != function) - - if (isObjectType(returnType)) { - this.returnSlot = LLVMGetParam(function, numParameters(function.type) - 1) - } - this.function = function - this.returnType = returnType - this.constructedClass = null - prologueBb = LLVMAppendBasicBlock(function, "prologue") - localsInitBb = LLVMAppendBasicBlock(function, "locals_init") - entryBb = LLVMAppendBasicBlock(function, "entry") - epilogueBb = LLVMAppendBasicBlock(function, "epilogue") - cleanupLandingpad = LLVMAppendBasicBlock(function, "cleanup_landingpad")!! - positionAtEnd(localsInitBb!!) - locationInfo?.let { - debugLocation(it) - } - slotsPhi = phi(kObjHeaderPtrPtr) - // First slot can be assigned to keep pointer to frame local arena. - slotCount = 1 - localAllocs = 0 - // Is removed by DCE trivially, if not needed. - arenaSlot = intToPtr( - or(ptrToInt(slotsPhi, intPtrType), immOneIntPtrType), kObjHeaderPtrPtr) - positionAtEnd(entryBb!!) - } - - fun epilogue(locationInfo: LocationInfo? = null) { - appendingTo(prologueBb!!) { - val slots = if (needSlots) - LLVMBuildArrayAlloca(builder, kObjHeaderPtr, Int32(slotCount).llvm, "")!! - else - kNullObjHeaderPtrPtr - if (needSlots) { - // Zero-init slots. - val slotsMem = bitcast(kInt8Ptr, slots) - val pointerSize = LLVMABISizeOfType(llvmTargetData, kObjHeaderPtr).toInt() - val alignment = LLVMABIAlignmentOfType(llvmTargetData, kObjHeaderPtr) - locationInfo?.let { - debugLocation(it) - } - call(context.llvm.memsetFunction, - listOf(slotsMem, Int8(0).llvm, - Int32(slotCount * pointerSize).llvm, Int32(alignment).llvm, - Int1(0).llvm)) - } - addPhiIncoming(slotsPhi!!, prologueBb!! to slots) - br(localsInitBb!!) - } - - appendingTo(localsInitBb!!) { - br(entryBb!!) - } - - appendingTo(epilogueBb!!) { - when { - returnType == voidType -> { - releaseVars() - assert(returnSlot == null) - LLVMBuildRetVoid(builder) - } - returns.size > 0 -> { - val returnPhi = phi(returnType!!) - addPhiIncoming(returnPhi, *returns.toList().toTypedArray()) - if (returnSlot != null) { - updateReturnRef(returnPhi, returnSlot!!) - } - releaseVars() - LLVMBuildRet(builder, returnPhi) - } - // Do nothing, all paths throw. - else -> LLVMBuildUnreachable(builder) + init { + functionDescriptor?.let { + if (!functionDescriptor.isExported()) { + LLVMSetLinkage(function, LLVMLinkage.LLVMInternalLinkage) + // (Cannot do this before the function body is created). } } - - appendingTo(cleanupLandingpad!!) { - val landingpad = gxxLandingpad(numClauses = 0) - LLVMSetCleanup(landingpad, 1) - releaseVars() - LLVMBuildResume(builder, landingpad) - } - - returns.clear() - vars.clear() - returnSlot = null - slotsPhi = null } - private val needSlots: Boolean - get() { - return slotCount > 1 || localAllocs > 0 || - // Prevent empty cleanup on mingw to workaround LLVM bug: - context.config.targetManager.target == KonanTarget.MINGW - } - - private fun releaseVars() { - if (needSlots) { - call(context.llvm.leaveFrameFunction, - listOf(slotsPhi!!, Int32(slotCount).llvm)) - } + private fun basicBlockInFunction(name: String, locationInfo: LocationInfo?): LLVMBasicBlockRef { + val bb = LLVMAppendBasicBlock(function, name)!! + update(bb, locationInfo) + return bb } - private var prologueBb: LLVMBasicBlockRef? = null - private var localsInitBb: LLVMBasicBlockRef? = null - private var entryBb: LLVMBasicBlockRef? = null - private var epilogueBb: LLVMBasicBlockRef? = null - private var cleanupLandingpad: LLVMBasicBlockRef? = null - - fun setName(value: LLVMValueRef, name: String) = LLVMSetValueName(value, name) - fun getName(value: LLVMValueRef) = LLVMGetValueName(value)?.toKString() - - fun plus (arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildAdd (builder, arg0, arg1, name)!! - fun mul (arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildMul (builder, arg0, arg1, name)!! - fun minus (arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildSub (builder, arg0, arg1, name)!! - fun div (arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildSDiv(builder, arg0, arg1, name)!! - fun srem (arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildSRem(builder, arg0, arg1, name)!! - - fun or (arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildOr (builder, arg0, arg1, name)!! - - /* integers comparisons */ - fun icmpEq(arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildICmp(builder, LLVMIntPredicate.LLVMIntEQ, arg0, arg1, name)!! - fun icmpGt(arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildICmp(builder, LLVMIntPredicate.LLVMIntSGT, arg0, arg1, name)!! - fun icmpGe(arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildICmp(builder, LLVMIntPredicate.LLVMIntSGE, arg0, arg1, name)!! - fun icmpLt(arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildICmp(builder, LLVMIntPredicate.LLVMIntSLT, arg0, arg1, name)!! - fun icmpLe(arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildICmp(builder, LLVMIntPredicate.LLVMIntSLE, arg0, arg1, name)!! - fun icmpNe(arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildICmp(builder, LLVMIntPredicate.LLVMIntNE, arg0, arg1, name)!! - - fun ucmpGt(arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildICmp(builder, LLVMIntPredicate.LLVMIntUGT, arg0, arg1, name)!! - - /* floating-point comparisons */ - fun fcmpEq(arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildFCmp(builder, LLVMRealPredicate.LLVMRealOEQ, arg0, arg1, name)!! - - fun bitcast(type: LLVMTypeRef?, value: LLVMValueRef, name: String = "") = LLVMBuildBitCast(builder, value, type, name)!! - - fun intToPtr(value: LLVMValueRef?, DestTy: LLVMTypeRef, Name: String = "") = LLVMBuildIntToPtr(builder, value, DestTy, Name)!! - fun ptrToInt(value: LLVMValueRef?, DestTy: LLVMTypeRef, Name: String = "") = LLVMBuildPtrToInt(builder, value, DestTy, Name)!! + fun basicBlock(name:String = "label_" , locationInfo:LocationInfo?):LLVMBasicBlockRef { + val result = LLVMInsertBasicBlock(this.currentBlock, name)!! + update(result, locationInfo) + LLVMMoveBasicBlockAfter(result, this.currentBlock) + return result + } fun alloca(type: LLVMTypeRef?, name: String = ""): LLVMValueRef { if (isObjectType(type!!)) { - appendingTo(localsInitBb!!) { + appendingTo(localsInitBb) { return gep(slotsPhi!!, Int32(slotCount++).llvm, name) } } - appendingTo(prologueBb!!) { + + appendingTo(prologueBb) { return LLVMBuildAlloca(builder, type, name)!! } } - fun allocInstance(typeInfo: LLVMValueRef, lifetime: Lifetime) : LLVMValueRef { - return call(context.llvm.allocInstanceFunction, listOf(typeInfo), lifetime) - } - fun allocArray( - typeInfo: LLVMValueRef, count: LLVMValueRef, lifetime: Lifetime) : LLVMValueRef { - return call(context.llvm.allocArrayFunction, listOf(typeInfo, count), lifetime) + fun ret(value: LLVMValueRef?): LLVMValueRef { + val res = LLVMBuildBr(builder, epilogueBb)!! + if (returns.containsKey(currentBlock)) { + // TODO: enable error throwing. + throw Error("ret() in the same basic block twice! in ${function.name}") + } + + if (value != null) + returns[currentBlock] = value + + currentPositionHolder.setAfterTerminator() + return res } fun load(value: LLVMValueRef, name: String = ""): LLVMValueRef { @@ -225,7 +175,8 @@ internal class CodeGenerator(override val context: Context) : ContextUtils { assert(!isObjectRef(value)) return result } - fun loadSlot(address: LLVMValueRef, isVar: Boolean, name: String = "") : LLVMValueRef { + + fun loadSlot(address: LLVMValueRef, isVar: Boolean, name: String = ""): LLVMValueRef { val value = LLVMBuildLoad(builder, address, name)!! if (isObjectRef(value) && isVar) { val slot = alloca(LLVMTypeOf(value)) @@ -233,11 +184,13 @@ internal class CodeGenerator(override val context: Context) : ContextUtils { } return value } + fun store(value: LLVMValueRef, ptr: LLVMValueRef) { // Use updateRef() or storeAny() API for that. assert(!isObjectRef(value)) LLVMBuildStore(builder, value, ptr) } + fun storeAnyLocal(value: LLVMValueRef, ptr: LLVMValueRef) { if (isObjectRef(value)) { updateRef(value, ptr) @@ -245,6 +198,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils { LLVMBuildStore(builder, value, ptr) } } + fun storeAnyGlobal(value: LLVMValueRef, ptr: LLVMValueRef) { if (isObjectRef(value)) { updateRef(value, ptr) @@ -253,32 +207,26 @@ internal class CodeGenerator(override val context: Context) : ContextUtils { } } - fun gep(base: LLVMValueRef, index: LLVMValueRef, name: String = ""): LLVMValueRef { - return LLVMBuildGEP(builder, base, cValuesOf(index), 1, name)!! - } - - fun updateReturnRef(value: LLVMValueRef, address: LLVMValueRef) { + private fun updateReturnRef(value: LLVMValueRef, address: LLVMValueRef) { call(context.llvm.updateReturnRefFunction, listOf(address, value)) } // Only use ignoreOld, when sure that memory is freshly inited and have no value. - fun updateRef(value: LLVMValueRef, address: LLVMValueRef, ignoreOld: Boolean = false) { + private fun updateRef(value: LLVMValueRef, address: LLVMValueRef, ignoreOld: Boolean = false) { call(if (ignoreOld) context.llvm.setRefFunction else context.llvm.updateRefFunction, listOf(address, value)) } - fun isConst(value: LLVMValueRef): Boolean = (LLVMIsConstant(value) == 1) - //-------------------------------------------------------------------------// fun callAtFunctionScope(llvmFunction: LLVMValueRef, args: List, lifetime: Lifetime) = - call(llvmFunction, args, lifetime, this::cleanupLandingpad) + call(llvmFunction, args, lifetime, { cleanupLandingpad }) fun call(llvmFunction: LLVMValueRef, args: List, resultLifetime: Lifetime = Lifetime.IRRELEVANT, lazyLandingpad: () -> LLVMBasicBlockRef? = { null }): LLVMValueRef { - var callArgs = if (isObjectReturn(llvmFunction.type)) { + val callArgs = if (isObjectReturn(llvmFunction.type)) { // If function returns an object - create slot for the returned value or give local arena. // This allows appropriate rootset accounting by just looking at the stack slots, // along with ability to allocate in appropriate arena. @@ -288,8 +236,8 @@ internal class CodeGenerator(override val context: Context) : ContextUtils { arenaSlot!! } SlotType.RETURN -> returnSlot!! - // TODO: for RETURN_IF_ARENA choose between created slot and arenaSlot - // dynamically. + // TODO: for RETURN_IF_ARENA choose between created slot and arenaSlot + // dynamically. SlotType.ANONYMOUS, SlotType.RETURN_IF_ARENA -> vars.createAnonymousSlot() else -> throw Error("Incorrect slot type") } @@ -301,8 +249,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils { } private fun callRaw(llvmFunction: LLVMValueRef, args: List, - lazyLandingpad: () -> LLVMBasicBlockRef?): LLVMValueRef { - + lazyLandingpad: () -> LLVMBasicBlockRef?): LLVMValueRef { val rargs = args.toCValues() if (LLVMIsAFunction(llvmFunction) != null /* the function declaration */ && (LLVMGetFunctionAttr(llvmFunction) and LLVMNoUnwindAttribute) != 0) { @@ -315,12 +262,12 @@ internal class CodeGenerator(override val context: Context) : ContextUtils { // When calling a function that is not marked as nounwind (can throw an exception), // it is required to specify a landingpad to handle exceptions properly. // Runtime C++ function can be marked as non-throwing using `RUNTIME_NOTHROW`. - val functionName = getName(llvmFunction) + val functionName = llvmFunction.name val message = "no landingpad specified when calling function $functionName without nounwind attr" throw IllegalArgumentException(message) } - val success = basicBlock("call_success") + val success = basicBlock("call_success", position()) val result = LLVMBuildInvoke(builder, llvmFunction, rargs, args.size, success, landingpad, "")!! positionAtEnd(success) return result @@ -343,40 +290,25 @@ internal class CodeGenerator(override val context: Context) : ContextUtils { } fun assignPhis(vararg phiToValue: Pair) { - val currentBlock = this.currentBlock phiToValue.forEach { addPhiIncoming(it.first, currentBlock to it.second) } } - //-------------------------------------------------------------------------// - - /* to class descriptor */ - fun typeInfoValue(descriptor: ClassDescriptor): LLVMValueRef = descriptor.llvmTypeInfoPtr - - /** - * Pointer to type info for given type, or `null` if the type doesn't have corresponding type info. - */ - fun typeInfoValue(type: KotlinType): LLVMValueRef? = type.typeInfoPtr?.llvm - - fun param(fn: FunctionDescriptor, i: Int): LLVMValueRef { - assert (i >= 0 && i < countParams(fn)) - return LLVMGetParam(fn.llvmFunction, i)!! - } - fun countParams(fn: FunctionDescriptor) = LLVMCountParams(fn.llvmFunction) - - fun basicBlock(name: String = "label_"): LLVMBasicBlockRef { - val currentBlock = this.currentBlock - val result = LLVMInsertBasicBlock(currentBlock, name)!! - LLVMMoveBasicBlockAfter(result, currentBlock) - return result + fun allocInstance(typeInfo: LLVMValueRef, lifetime: Lifetime): LLVMValueRef { + return call(context.llvm.allocInstanceFunction, listOf(typeInfo), lifetime) } - fun lastBasicBlock(): LLVMBasicBlockRef? = LLVMGetLastBasicBlock(function) + fun allocArray( + typeInfo: LLVMValueRef, count: LLVMValueRef, lifetime: Lifetime): LLVMValueRef { + return call(context.llvm.allocArrayFunction, listOf(typeInfo, count), lifetime) + } - fun functionLlvmValue(descriptor: FunctionDescriptor) = descriptor.llvmFunction - fun functionEntryPointAddress(descriptor: FunctionDescriptor) = descriptor.entryPointAddress.llvm - fun functionHash(descriptor: FunctionDescriptor): LLVMValueRef = descriptor.functionName.localHash.llvm + fun unreachable(): LLVMValueRef? { + val res = LLVMBuildUnreachable(builder) + currentPositionHolder.setAfterTerminator() + return res + } fun br(bbLabel: LLVMBasicBlockRef): LLVMValueRef { val res = LLVMBuildBr(builder, bbLabel)!! @@ -390,39 +322,31 @@ internal class CodeGenerator(override val context: Context) : ContextUtils { return res } - fun ret(value: LLVMValueRef?): LLVMValueRef { - 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 - } - - fun unreachable(): LLVMValueRef? { - val res = LLVMBuildUnreachable(builder) - currentPositionHolder.setAfterTerminator() - return res - } - fun blockAddress(bbLabel: LLVMBasicBlockRef): LLVMValueRef { return LLVMBlockAddress(function, bbLabel)!! } - fun indirectBr(address: LLVMValueRef, destinations: Collection): LLVMValueRef? { - val indirectBr = LLVMBuildIndirectBr(builder, address, destinations.size) - destinations.forEach { LLVMAddDestination(indirectBr, it) } - currentPositionHolder.setAfterTerminator() - return indirectBr - } + fun or(arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildOr(builder, arg0, arg1, name)!! - //-------------------------------------------------------------------------// + /* integers comparisons */ + fun icmpEq(arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildICmp(builder, LLVMIntPredicate.LLVMIntEQ, arg0, arg1, name)!! + + fun icmpGt(arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildICmp(builder, LLVMIntPredicate.LLVMIntSGT, arg0, arg1, name)!! + fun icmpGe(arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildICmp(builder, LLVMIntPredicate.LLVMIntSGE, arg0, arg1, name)!! + fun icmpLt(arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildICmp(builder, LLVMIntPredicate.LLVMIntSLT, arg0, arg1, name)!! + fun icmpLe(arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildICmp(builder, LLVMIntPredicate.LLVMIntSLE, arg0, arg1, name)!! + fun icmpNe(arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildICmp(builder, LLVMIntPredicate.LLVMIntNE, arg0, arg1, name)!! + + /* floating-point comparisons */ + fun fcmpEq(arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildFCmp(builder, LLVMRealPredicate.LLVMRealOEQ, arg0, arg1, name)!! + + fun bitcast(type: LLVMTypeRef?, value: LLVMValueRef, name: String = "") = LLVMBuildBitCast(builder, value, type, name)!! + + fun intToPtr(value: LLVMValueRef?, DestTy: LLVMTypeRef, Name: String = "") = LLVMBuildIntToPtr(builder, value, DestTy, Name)!! + fun ptrToInt(value: LLVMValueRef?, DestTy: LLVMTypeRef, Name: String = "") = LLVMBuildPtrToInt(builder, value, DestTy, Name)!! + fun gep(base: LLVMValueRef, index: LLVMValueRef, name: String = ""): LLVMValueRef { + return LLVMBuildGEP(builder, base, cValuesOf(index), 1, name)!! + } fun gxxLandingpad(numClauses: Int, name: String = ""): LLVMValueRef { val personalityFunction = LLVMConstBitCast(context.llvm.gxxPersonalityFunction, int8TypePtr) @@ -433,6 +357,105 @@ internal class CodeGenerator(override val context: Context) : ContextUtils { return LLVMBuildLandingPad(builder, landingpadType, personalityFunction, numClauses, name)!! } + internal fun debugLocation(locationInfo: LocationInfo): DILocationRef? { + if (!context.shouldContainDebugInfo()) return null + update(currentBlock, locationInfo) + return LLVMBuilderSetDebugLocation( + builder, + locationInfo.line, + locationInfo.column, + locationInfo.scope) + } + + fun indirectBr(address: LLVMValueRef, destinations: Collection): LLVMValueRef? { + val indirectBr = LLVMBuildIndirectBr(builder, address, destinations.size) + destinations.forEach { LLVMAddDestination(indirectBr, it) } + currentPositionHolder.setAfterTerminator() + return indirectBr + } + fun resetDebugLocation() { + if (!context.shouldContainDebugInfo()) return + if (!currentPositionHolder.isAfterTerminator) + LLVMBuilderResetDebugLocation(builder) + } + + private fun position() = basicBlockToLastLocation[currentBlock] + + + internal fun prologue() { + assert(returns.isEmpty()) + if (isObjectType(returnType!!)) { + this.returnSlot = LLVMGetParam(function, numParameters(function.type) - 1) + } + positionAtEnd(localsInitBb) + slotsPhi = phi(kObjHeaderPtrPtr) + // First slot can be assigned to keep pointer to frame local arena. + slotCount = 1 + localAllocs = 0 + // Is removed by DCE trivially, if not needed. + arenaSlot = intToPtr( + or(ptrToInt(slotsPhi, codegen.intPtrType), codegen.immOneIntPtrType), kObjHeaderPtrPtr) + positionAtEnd(entryBb) + } + + internal fun epilogue() { + appendingTo(prologueBb) { + val slots = if (needSlots) + LLVMBuildArrayAlloca(builder, kObjHeaderPtr, Int32(slotCount).llvm, "")!! + else + kNullObjHeaderPtrPtr + if (needSlots) { + // Zero-init slots. + val slotsMem = bitcast(kInt8Ptr, slots) + val pointerSize = LLVMABISizeOfType(llvmTargetData, kObjHeaderPtr).toInt() + val alignment = LLVMABIAlignmentOfType(llvmTargetData, kObjHeaderPtr) + call(context.llvm.memsetFunction, + listOf(slotsMem, Int8(0).llvm, + Int32(slotCount * pointerSize).llvm, Int32(alignment).llvm, + Int1(0).llvm)) + } + addPhiIncoming(slotsPhi!!, prologueBb to slots) + br(localsInitBb) + } + + appendingTo(localsInitBb) { + br(entryBb) + } + + appendingTo(epilogueBb) { + when { + returnType == voidType -> { + releaseVars() + assert(returnSlot == null) + LLVMBuildRetVoid(builder) + } + returns.isNotEmpty() -> { + val returnPhi = phi(returnType!!) + addPhiIncoming(returnPhi, *returns.toList().toTypedArray()) + if (returnSlot != null) { + updateReturnRef(returnPhi, returnSlot!!) + } + releaseVars() + LLVMBuildRet(builder, returnPhi) + } + // Do nothing, all paths throw. + else -> LLVMBuildUnreachable(builder) + } + } + + appendingTo(cleanupLandingpad) { + val landingpad = gxxLandingpad(numClauses = 0) + LLVMSetCleanup(landingpad, 1) + releaseVars() + LLVMBuildResume(builder, landingpad) + } + + returns.clear() + vars.clear() + returnSlot = null + slotsPhi = null + } + //-------------------------------------------------------------------------// /** @@ -446,7 +469,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils { fun getBuilder(): LLVMBuilderRef { if (isAfterTerminator) { - positionAtEnd(basicBlock("unreachable")) + positionAtEnd(basicBlock("unreachable", null)) } return builder @@ -467,6 +490,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils { fun positionAtEnd(block: LLVMBasicBlockRef) { LLVMPositionBuilderAtEnd(builder, block) + basicBlockToLastLocation[block]?.let(this@PositionHolder::debugLocation) val lastInstr = LLVMGetLastInstruction(block) isAfterTerminator = lastInstr != null && (LLVMIsATerminatorInst(lastInstr) != null) } @@ -474,6 +498,20 @@ internal class CodeGenerator(override val context: Context) : ContextUtils { fun dispose() { LLVMDisposeBuilder(builder) } + + fun debugLocation(locationInfo: LocationInfo): DILocationRef? { + if (!context.shouldContainDebugInfo()) return null + return LLVMBuilderSetDebugLocation( + builder, + locationInfo.line, + locationInfo.column, + locationInfo.scope) + } + + fun resetDebugLocation() { + if (!context.shouldContainDebugInfo()) return + LLVMBuilderResetDebugLocation(builder) + } } private var currentPositionHolder: PositionHolder = PositionHolder() @@ -497,7 +535,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils { fun positionAtEnd(bbLabel: LLVMBasicBlockRef) = currentPositionHolder.positionAtEnd(bbLabel) - inline fun preservingPosition(code: () -> R): R { + inline private fun preservingPosition(code: () -> R): R { val oldPositionHolder = currentPositionHolder val newPositionHolder = PositionHolder() currentPositionHolder = newPositionHolder @@ -509,27 +547,25 @@ internal class CodeGenerator(override val context: Context) : ContextUtils { } } - inline fun appendingTo(block: LLVMBasicBlockRef, code: CodeGenerator.() -> R) = preservingPosition { + inline fun appendingTo(block: LLVMBasicBlockRef, code: FunctionGenerationContext.() -> R) = preservingPosition { positionAtEnd(block) code() } - fun llvmFunction(function: FunctionDescriptor): LLVMValueRef = function.llvmFunction + private val needSlots: Boolean + get() { + return slotCount > 1 || localAllocs > 0 || + // Prevent empty cleanup on mingw to workaround LLVM bug: + context.config.targetManager.target == KonanTarget.MINGW + } - internal fun resetDebugLocation() { - if (!context.shouldContainDebugInfo()) return - LLVMBuilderResetDebugLocation(builder) + private fun releaseVars() { + if (needSlots) { + call(context.llvm.leaveFrameFunction, + listOf(slotsPhi!!, Int32(slotCount).llvm)) + } } - - internal fun debugLocation(locationInfo: LocationInfo):DILocationRef? { - if (!context.shouldContainDebugInfo()) return null - return LLVMBuilderSetDebugLocation( - builder, - locationInfo.line, - locationInfo.column, - locationInfo.scope) - } - } + 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 223d897796c..b3dc8d261df 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 @@ -327,38 +327,37 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid fun createInitBody(initName: String): LLVMValueRef { val initFunction = LLVMAddFunction(context.llvmModule, initName, kInitFuncType)!! // create LLVM function - codegen.prologue(initFunction, voidType) - using(FunctionScope(initFunction)) { - val bbInit = codegen.basicBlock("init") - val bbDeinit = codegen.basicBlock("deinit") - codegen.condBr(codegen.icmpEq(LLVMGetParam(initFunction, 0)!!, kImmZero), bbDeinit, bbInit) + generateFunction(codegen, initFunction) { + using(FunctionScope(initFunction, it)) { + val bbInit = basicBlock("init", null) + val bbDeinit = basicBlock("deinit", null) + condBr(functionGenerationContext.icmpEq(LLVMGetParam(initFunction, 0)!!, kImmZero), bbDeinit, bbInit) - codegen.appendingTo(bbDeinit) { - context.llvm.fileInitializers.forEach { - val irField = it as IrField - val descriptor = irField.descriptor - if (descriptor.type.isValueType()) - return@forEach // Is not a subject for memory management. - val globalPtr = context.llvmDeclarations.forStaticField(descriptor).storage - codegen.storeAnyGlobal(codegen.kNullObjHeaderPtr, globalPtr) + appendingTo(bbDeinit) { + context.llvm.fileInitializers.forEach { + val irField = it as IrField + val descriptor = irField.descriptor + if (descriptor.type.isValueType()) + return@forEach // Is not a subject for memory management. + val globalPtr = context.llvmDeclarations.forStaticField(descriptor).storage + storeAnyGlobal(codegen.kNullObjHeaderPtr, globalPtr) + } + objects.forEach { storeAnyGlobal(codegen.kNullObjHeaderPtr, it) } + ret(null) } - objects.forEach { codegen.storeAnyGlobal(codegen.kNullObjHeaderPtr, it) } - codegen.ret(null) - } - codegen.appendingTo(bbInit) { - context.llvm.fileInitializers.forEach { - val irField = it as IrField - val descriptor = irField.descriptor - val initialization = evaluateExpression(irField.initializer!!.expression) - val globalPtr = context.llvmDeclarations.forStaticField(descriptor).storage - codegen.storeAnyGlobal(initialization, globalPtr) + appendingTo(bbInit) { + context.llvm.fileInitializers.forEach { + val irField = it as IrField + val descriptor = irField.descriptor + val initialization = evaluateExpression(irField.initializer!!.expression) + val globalPtr = context.llvmDeclarations.forStaticField(descriptor).storage + storeAnyGlobal(initialization, globalPtr) + } + ret(null) } - codegen.ret(null) } } - codegen.epilogue() - return initFunction } @@ -376,11 +375,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid fun createInitCtor(ctorName: String, initNodePtr: LLVMValueRef) { val ctorFunction = LLVMAddFunction(context.llvmModule, ctorName, kVoidFuncType)!! // Create constructor function. - codegen.prologue(ctorFunction, voidType) - codegen.call(context.llvm.appendToInitalizersTail, listOf(initNodePtr)) // Add node to the tail of initializers list. - codegen.ret(null) - codegen.epilogue() - + generateFunction(codegen, ctorFunction) { + call(context.llvm.appendToInitalizersTail, listOf(initNodePtr)) // Add node to the tail of initializers list. + } context.llvm.staticInitializers.add(ctorFunction) // Push newly created constructor in staticInitializers list. } @@ -411,19 +408,19 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid //-------------------------------------------------------------------------// private inner class LoopScope(val loop: IrLoop) : InnerScopeImpl() { - val loopExit = codegen.basicBlock("loop_exit") - val loopCheck = codegen.basicBlock("loop_check") + val loopExit = functionGenerationContext.basicBlock("loop_exit", loop.condition.startLocation) + val loopCheck = functionGenerationContext.basicBlock("loop_check", loop.condition.startLocation) override fun genBreak(destination: IrBreak) { if (destination.loop == loop) - codegen.br(loopExit) + functionGenerationContext.br(loopExit) else super.genBreak(destination) } override fun genContinue(destination: IrContinue) { if (destination.loop == loop) - codegen.br(loopCheck) + functionGenerationContext.br(loopCheck) else super.genContinue(destination) } @@ -481,20 +478,20 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid private inner class VariableScope : InnerScopeImpl() { override fun genDeclareVariable(descriptor: VariableDescriptor, value: LLVMValueRef?): Int { - return codegen.vars.createVariable(descriptor, value) + return functionGenerationContext.vars.createVariable(descriptor, value) } override fun getDeclaredVariable(descriptor: VariableDescriptor): Int { - val index = codegen.vars.indexOf(descriptor) + val index = functionGenerationContext.vars.indexOf(descriptor) return if (index < 0) super.getDeclaredVariable(descriptor) else return index } override fun genGetValue(descriptor: ValueDescriptor): LLVMValueRef { - val index = codegen.vars.indexOf(descriptor) + val index = functionGenerationContext.vars.indexOf(descriptor) if (index < 0) { return super.genGetValue(descriptor) } else { - return codegen.vars.load(index) + return functionGenerationContext.vars.load(index) } } } @@ -502,7 +499,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid /** * The scope of parameter visibility. */ - private open inner class ParameterScope( + private open inner class ParameterScope(private val functionGenerationContext: FunctionGenerationContext, parameters: Map): InnerScopeImpl() { // Note: it is possible to generate access to a parameter without any variables, @@ -510,17 +507,17 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid init { parameters.map { (descriptor, value) -> - codegen.vars.createImmutable(descriptor, value) + functionGenerationContext.vars.createImmutable(descriptor, value) } } override fun genGetValue(descriptor: ValueDescriptor): LLVMValueRef { - val index = codegen.vars.indexOf(descriptor) + val index = functionGenerationContext.vars.indexOf(descriptor) if (index < 0) { return super.genGetValue(descriptor) } else { - return codegen.vars.load(index) + return functionGenerationContext.vars.load(index) } } } @@ -528,9 +525,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid /** * The [CodeContext] enclosing the entire function body. */ - private inner class FunctionScope (val declaration: IrFunction?) : - ParameterScope(bindParameters(declaration?.descriptor)) { - constructor(llvmFunction:LLVMValueRef):this(null) { + private inner class FunctionScope (val declaration: IrFunction?, val functionGenerationContext: FunctionGenerationContext) : + ParameterScope(functionGenerationContext, bindParameters(declaration?.descriptor)) { + constructor(llvmFunction:LLVMValueRef, functionGenerationContext: FunctionGenerationContext):this(null, functionGenerationContext) { this.llvmFunction = llvmFunction } @@ -542,9 +539,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid if (declaration == null || target == declaration.descriptor) { if (target.returnsUnit()) { assert (value == null) - codegen.ret(null) + functionGenerationContext.ret(null) } else { - codegen.ret(value!!) + functionGenerationContext.ret(value!!) } } else { super.genReturn(target, value) @@ -552,19 +549,21 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid } override fun genCall(function: LLVMValueRef, args: List, resultLifetime: Lifetime) = - codegen.callAtFunctionScope(function, args, resultLifetime) + functionGenerationContext.callAtFunctionScope(function, args, resultLifetime) override fun genThrow(exception: LLVMValueRef) { - val objHeaderPtr = codegen.bitcast(codegen.kObjHeaderPtr, exception) + val objHeaderPtr = functionGenerationContext.bitcast(codegen.kObjHeaderPtr, exception) val args = listOf(objHeaderPtr) this.genCall(context.llvm.throwExceptionFunction, args, Lifetime.IRRELEVANT) - codegen.unreachable() + functionGenerationContext.unreachable() } override fun functionScope(): CodeContext = this } + private val functionGenerationContext + get() = (currentCodeContext.functionScope() as FunctionScope).functionGenerationContext /** * Binds LLVM function parameters to IR parameter descriptors. */ @@ -586,30 +585,25 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid if (declaration.descriptor.isExternal) return if (body == null) return - using(FunctionScope(declaration)) { - val locationInfo = LocationInfo( - scope = declaration.scope(), - line = declaration.line(), - column = declaration.column()) - codegen.prologue(declaration.descriptor, locationInfo) - - using(VariableScope()) { - when (body) { - is IrBlockBody -> body.statements.forEach { generateStatement(it) } - is IrExpressionBody -> generateStatement(body.expression) - is IrSyntheticBody -> throw AssertionError("Synthetic body ${body.kind} has not been lowered") - else -> TODO(ir2string(body)) + val startLocationInfo = LocationInfo( + scope = declaration.scope(), + line = declaration.startLine(), + column = declaration.startColumn()) + val endLocationInfo = LocationInfo( + scope = declaration.scope(), + line = declaration.endLine(), + column = declaration.endColumn()) + generateFunction(codegen, declaration.descriptor, startLocationInfo, endLocationInfo) { + using(FunctionScope(declaration, it)) { + using(VariableScope()) { + when (body) { + is IrBlockBody -> body.statements.forEach { generateStatement(it) } + is IrExpressionBody -> generateStatement(body.expression) + is IrSyntheticBody -> throw AssertionError("Synthetic body ${body.kind} has not been lowered") + else -> TODO(ir2string(body)) + } } } - codegen.resetDebugLocation() - if (!codegen.isAfterTerminator()) { - if (codegen.returnType == voidType) - codegen.ret(null) - else - codegen.unreachable() - } - - codegen.epilogue(locationInfo) } if (context.shouldVerifyBitCode()) @@ -672,6 +666,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid //-------------------------------------------------------------------------// private fun evaluateExpression(value: IrExpression): LLVMValueRef { + debugLocation(value) when (value) { is IrTypeOperatorCall -> return evaluateTypeOperator (value) is IrCall -> return evaluateCall (value) @@ -724,25 +719,25 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid } val objectPtr = getObjectInstanceStorage(value.descriptor) - val bbCurrent = codegen.currentBlock - val bbInit = codegen.basicBlock("label_init") - val bbExit = codegen.basicBlock("label_continue") - val objectVal = codegen.loadSlot(objectPtr, false) - val condition = codegen.icmpNe(objectVal, codegen.kNullObjHeaderPtr) - codegen.condBr(condition, bbExit, bbInit) + val bbCurrent = functionGenerationContext.currentBlock + val bbInit = functionGenerationContext.basicBlock("label_init", value.startLocation) + val bbExit = functionGenerationContext.basicBlock("label_continue", value.startLocation) + val objectVal = functionGenerationContext.loadSlot(objectPtr, false) + val condition = functionGenerationContext.icmpNe(objectVal, codegen.kNullObjHeaderPtr) + functionGenerationContext.condBr(condition, bbExit, bbInit) - codegen.positionAtEnd(bbInit) + functionGenerationContext.positionAtEnd(bbInit) val typeInfo = codegen.typeInfoValue(value.descriptor) val initFunction = value.descriptor.constructors.first { it.valueParameters.size == 0 } val ctor = codegen.llvmFunction(initFunction) val args = listOf(objectPtr, typeInfo, ctor) val newValue = call(context.llvm.initInstanceFunction, args, Lifetime.GLOBAL) - val bbInitResult = codegen.currentBlock - codegen.br(bbExit) + val bbInitResult = functionGenerationContext.currentBlock + functionGenerationContext.br(bbExit) - codegen.positionAtEnd(bbExit) - val valuePhi = codegen.phi(codegen.getLLVMType(value.type)) - codegen.addPhiIncoming(valuePhi, + functionGenerationContext.positionAtEnd(bbExit) + val valuePhi = functionGenerationContext.phi(codegen.getLLVMType(value.type)) + functionGenerationContext.addPhiIncoming(valuePhi, bbCurrent to objectVal, bbInitResult to newValue) return valuePhi @@ -783,9 +778,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid */ private fun jump(target: ContinuationBlock, value: LLVMValueRef?) { val entry = target.block - codegen.br(entry) + functionGenerationContext.br(entry) if (target.valuePhi != null) { - codegen.assignPhis(target.valuePhi to value!!) + functionGenerationContext.assignPhis(target.valuePhi to value!!) } } @@ -794,14 +789,14 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid * and generates [code] starting from its beginning. */ private fun continuationBlock(type: KotlinType, - code: (ContinuationBlock) -> Unit = {}): ContinuationBlock { - val entry = codegen.basicBlock("continuation_block") + locationInfo: LocationInfo?, code: (ContinuationBlock) -> Unit = {}): ContinuationBlock { + val entry = functionGenerationContext.basicBlock("continuation_block", locationInfo) - codegen.appendingTo(entry) { + functionGenerationContext.appendingTo(entry) { val valuePhi = if (type.isUnit()) { null } else { - codegen.phi(codegen.getLLVMType(type)) + functionGenerationContext.phi(codegen.getLLVMType(type)) } val result = ContinuationBlock(entry, valuePhi) @@ -816,7 +811,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid val elements = value.elements.map { if (it is IrExpression) { val mapped = evaluateExpression(it) - if (codegen.isConst(mapped)) { + if (mapped.isConst) { return@map mapped } } @@ -851,7 +846,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid */ private val landingpad: LLVMBasicBlockRef by lazy { using(outerContext) { - codegen.basicBlock("landingpad") { + functionGenerationContext.basicBlock("landingpad", endLocationInfoFromScope()) { genLandingpad() } } @@ -863,12 +858,21 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid */ private val handler by lazy { using(outerContext) { - continuationBlock(context.builtIns.throwable.defaultType) { + continuationBlock(context.builtIns.throwable.defaultType, endLocationInfoFromScope()) { genHandler(it.value) } } } + private inline fun endLocationInfoFromScope(): LocationInfo? { + val functionScope = currentCodeContext.functionScope() + val irFunction = functionScope?.let { + (functionScope as FunctionScope).declaration + } + val locationInfo = irFunction?.endLocation + return locationInfo + } + private fun jumpToHandler(exception: LLVMValueRef) { jump(this.handler, exception) } @@ -889,15 +893,15 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid * TODO: why does `clang++` check `typeid` even if there is only one catch clause? */ private fun genLandingpad() { - with(codegen) { - val landingpadResult = codegen.gxxLandingpad(numClauses = 1, name = "lp") + with(functionGenerationContext) { + val landingpadResult = gxxLandingpad(numClauses = 1, name = "lp") LLVMAddClause(landingpadResult, LLVMConstNull(kInt8Ptr)) // FIXME: properly handle C++ exceptions: currently C++ exception can be thrown out from try-finally // bypassing the finally block. - val exceptionRecord = LLVMBuildExtractValue(codegen.builder, landingpadResult, 0, "er")!! + val exceptionRecord = LLVMBuildExtractValue(functionGenerationContext.builder, landingpadResult, 0, "er")!! // __cxa_begin_catch returns pointer to C++ exception object. val beginCatch = context.llvm.cxaBeginCatchFunction @@ -908,7 +912,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid // Pointer to Kotlin exception object: // We do need a slot here, as otherwise exception instance could be freed by _cxa_end_catch. - val exceptionPtr = loadSlot(exceptionPtrPtr, true, "exception") + val exceptionPtr = functionGenerationContext.loadSlot(exceptionPtrPtr, true, "exception") // __cxa_end_catch performs some C++ cleanup, including calling `KotlinException` class destructor. val endCatch = context.llvm.cxaEndCatchFunction @@ -920,7 +924,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid // The call inside [CatchingScope] must be configured to dispatch exception to the scope's handler. override fun genCall(function: LLVMValueRef, args: List, resultLifetime: Lifetime): LLVMValueRef { - val res = codegen.call(function, args, resultLifetime, this::landingpad) + val res = functionGenerationContext.call(function, args, resultLifetime, this::landingpad) return res } @@ -955,16 +959,15 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid return // Remaining catch clauses are unreachable. } else { val isInstance = genInstanceOf(exception, catch.parameter.type) - val body = codegen.basicBlock("catch") - val nextCheck = codegen.basicBlock("catchCheck") - codegen.condBr(isInstance, body, nextCheck) + val body = functionGenerationContext.basicBlock("catch", catch.startLocation) + val nextCheck = functionGenerationContext.basicBlock("catchCheck", catch.endLocation) + functionGenerationContext.condBr(isInstance, body, nextCheck) - codegen.appendingTo(body) { + functionGenerationContext.appendingTo(body) { genCatchBlock() } - codegen.positionAtEnd(nextCheck) - + functionGenerationContext.positionAtEnd(nextCheck) } } // rethrow the exception if no clause can handle it. @@ -978,7 +981,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid assert (expression.finallyExpression == null, { "All finally blocks should've been lowered" }) - val continuation = continuationBlock(expression.type) + val continuation = continuationBlock(expression.type, expression.endLocation) val catchScope = if (expression.catches.isEmpty()) null @@ -987,7 +990,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid using(catchScope) { evaluateExpressionAndJump(expression.tryResult, continuation) } - codegen.positionAtEnd(continuation.block) + functionGenerationContext.positionAtEnd(continuation.block) return continuation.value } @@ -1014,27 +1017,26 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid // "When" has exit block if: // its type is not Nothing - we must place phi in the exit block // or it doesn't cover all cases - we may fall through all of them and must create exit block to continue. - if (!isNothing || !coverAllCases) // If "when" has "exit". - bbExit = codegen.basicBlock("when_exit") // Create basic block to process "exit". + if (!isNothing || !coverAllCases) // If "when" has "exit". + bbExit = functionGenerationContext.basicBlock("when_exit", expression.startLocation) // Create basic block to process "exit". val llvmType = codegen.getLLVMType(expression.type) val resultPhi = if (isUnit || isNothing || !coverAllCases) null else - codegen.appendingTo(bbExit!!) { - codegen.phi(llvmType) + functionGenerationContext.appendingTo(bbExit!!) { + functionGenerationContext.phi(llvmType) } expression.branches.forEach { // Iterate through "when" branches (clauses). var bbNext = bbExit // For last clause bbNext coincides with bbExit. - debugLocation(it) - if (it != expression.branches.last()) // If it is not last clause. - bbNext = codegen.basicBlock("when_next") // Create new basic block for next clause. - generateWhenCase(resultPhi, it, bbNext, bbExit) // Generate code for current clause. + if (it != expression.branches.last()) // If it is not last clause. + bbNext = functionGenerationContext.basicBlock("when_next", it.startLocation) // Create new basic block for next clause. + generateWhenCase(resultPhi, it, bbNext, bbExit) // Generate code for current clause. } return when { // FIXME: remove the hacks. - isUnit -> codegen.theUnitInstanceRef.llvm - isNothing -> codegen.kNothingFakeValue + isUnit -> functionGenerationContext.theUnitInstanceRef.llvm + isNothing -> functionGenerationContext.kNothingFakeValue !coverAllCases -> LLVMGetUndef(llvmType)!! else -> resultPhi!! } @@ -1044,26 +1046,24 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid private fun evaluateWhileLoop(loop: IrWhileLoop): LLVMValueRef { val loopScope = LoopScope(loop) - debugInfo(loop) { - using(loopScope) { - val loopBody = codegen.basicBlock("while_loop") - codegen.br(loopScope.loopCheck) + using(loopScope) { + val loopBody = functionGenerationContext.basicBlock("while_loop", loop.startLocation) + functionGenerationContext.br(loopScope.loopCheck) - codegen.positionAtEnd(loopScope.loopCheck) - val condition = evaluateExpression(loop.condition) - codegen.condBr(condition, loopBody, loopScope.loopExit) + functionGenerationContext.positionAtEnd(loopScope.loopCheck) + val condition = evaluateExpression(loop.condition) + functionGenerationContext.condBr(condition, loopBody, loopScope.loopExit) - codegen.positionAtEnd(loopBody) - loop.body?.generate() + functionGenerationContext.positionAtEnd(loopBody) + loop.body?.generate() + + functionGenerationContext.br(loopScope.loopCheck) + functionGenerationContext.positionAtEnd(loopScope.loopExit) - codegen.br(loopScope.loopCheck) - codegen.positionAtEnd(loopScope.loopExit) - } } - assert(loop.type.isUnit()) - return codegen.theUnitInstanceRef.llvm + return functionGenerationContext.theUnitInstanceRef.llvm } //-------------------------------------------------------------------------// @@ -1071,31 +1071,29 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid private fun evaluateDoWhileLoop(loop: IrDoWhileLoop): LLVMValueRef { val loopScope = LoopScope(loop) using(loopScope) { - val loopBody = codegen.basicBlock("do_while_loop") - codegen.br(loopBody) + val loopBody = functionGenerationContext.basicBlock("do_while_loop", loop.body?.startLocation ?: loop.startLocation) + functionGenerationContext.br(loopBody) - codegen.positionAtEnd(loopBody) + functionGenerationContext.positionAtEnd(loopBody) loop.body?.generate() - codegen.br(loopScope.loopCheck) + functionGenerationContext.br(loopScope.loopCheck) - codegen.positionAtEnd(loopScope.loopCheck) + functionGenerationContext.positionAtEnd(loopScope.loopCheck) val condition = evaluateExpression(loop.condition) - codegen.condBr(condition, loopBody, loopScope.loopExit) + functionGenerationContext.condBr(condition, loopBody, loopScope.loopExit) - codegen.positionAtEnd(loopScope.loopExit) + functionGenerationContext.positionAtEnd(loopScope.loopExit) } assert(loop.type.isUnit()) - return codegen.theUnitInstanceRef.llvm + return functionGenerationContext.theUnitInstanceRef.llvm } //-------------------------------------------------------------------------// private fun evaluateGetValue(value: IrGetValue): LLVMValueRef { context.log{"evaluateGetValue : ${ir2string(value)}"} - return debugInfo(value) { - currentCodeContext.genGetValue(value.descriptor) - } + return currentCodeContext.genGetValue(value.descriptor) } //-------------------------------------------------------------------------// @@ -1104,12 +1102,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid context.log{"evaluateSetVariable : ${ir2string(value)}"} val result = evaluateExpression(value.value) val variable = currentCodeContext.getDeclaredVariable(value.descriptor) - debugInfo(value) { - codegen.vars.store(result, variable) - } - + functionGenerationContext.vars.store(result, variable) assert(value.type.isUnit()) - return codegen.theUnitInstanceRef.llvm + return functionGenerationContext.theUnitInstanceRef.llvm } //-------------------------------------------------------------------------// @@ -1123,11 +1118,11 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid val location = debugLocation(value) val functionScope = (currentCodeContext.functionScope() as FunctionScope).declaration?.scope() ?: return val file = (currentCodeContext.fileScope() as FileScope).file.file() - val variable = codegen.vars.load(index) - val line = value.line() - codegen.vars.debugInfoLocalVariableLocation( + val variable = functionGenerationContext.vars.load(index) + val line = value.startLine() + functionGenerationContext.vars.debugInfoLocalVariableLocation( functionScope = functionScope, - diType = variableDescriptor.type.diType(context, codegen.llvmTargetData), + diType = variableDescriptor.type.diType(context, functionGenerationContext.llvmTargetData), name = variableDescriptor.name, variable = variable, file = file, @@ -1139,20 +1134,18 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid //-------------------------------------------------------------------------// private fun evaluateTypeOperator(value: IrTypeOperatorCall): LLVMValueRef { - return debugInfo(value) { - when (value.operator) { - IrTypeOperator.CAST -> evaluateCast(value) - IrTypeOperator.IMPLICIT_INTEGER_COERCION -> evaluateIntegerCoercion(value) - IrTypeOperator.IMPLICIT_CAST -> evaluateExpression(value.argument) - IrTypeOperator.IMPLICIT_NOTNULL -> TODO(ir2string(value)) - IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> { - evaluateExpression(value.argument) - return@debugInfo codegen.theUnitInstanceRef.llvm - } - IrTypeOperator.SAFE_CAST -> throw IllegalStateException("safe cast wasn't lowered") - IrTypeOperator.INSTANCEOF -> evaluateInstanceOf(value) - IrTypeOperator.NOT_INSTANCEOF -> evaluateNotInstanceOf(value) + return when (value.operator) { + IrTypeOperator.CAST -> evaluateCast(value) + IrTypeOperator.IMPLICIT_INTEGER_COERCION -> evaluateIntegerCoercion(value) + IrTypeOperator.IMPLICIT_CAST -> evaluateExpression(value.argument) + IrTypeOperator.IMPLICIT_NOTNULL -> TODO(ir2string(value)) + IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> { + evaluateExpression(value.argument) + functionGenerationContext.theUnitInstanceRef.llvm } + IrTypeOperator.SAFE_CAST -> throw IllegalStateException("safe cast wasn't lowered") + IrTypeOperator.INSTANCEOF -> evaluateInstanceOf(value) + IrTypeOperator.NOT_INSTANCEOF -> evaluateNotInstanceOf(value) } } @@ -1170,16 +1163,14 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid val type = value.typeOperand assert(type.isPrimitiveInteger()) val result = evaluateExpression(value.argument) - return debugInfo(value) { - val llvmSrcType = codegen.getLLVMType(value.argument.type) - val llvmDstType = codegen.getLLVMType(type) - val srcWidth = LLVMGetIntTypeWidth(llvmSrcType) - val dstWidth = LLVMGetIntTypeWidth(llvmDstType) - return@debugInfo when { - srcWidth == dstWidth -> result - srcWidth > dstWidth -> LLVMBuildTrunc(codegen.builder, result, llvmDstType, "")!! - else /* srcWidth < dstWidth */ -> LLVMBuildSExt(codegen.builder, result, llvmDstType, "")!! - } + val llvmSrcType = codegen.getLLVMType(value.argument.type) + val llvmDstType = codegen.getLLVMType(type) + val srcWidth = LLVMGetIntTypeWidth(llvmSrcType) + val dstWidth = LLVMGetIntTypeWidth(llvmDstType) + return when { + srcWidth == dstWidth -> result + srcWidth > dstWidth -> LLVMBuildTrunc(functionGenerationContext.builder, result, llvmDstType, "")!! + else /* srcWidth < dstWidth */ -> LLVMBuildSExt(functionGenerationContext.builder, result, llvmDstType, "")!! } } @@ -1204,9 +1195,8 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid val dstDescriptor = TypeUtils.getClassDescriptor(type) // Get class descriptor for dst type. val dstTypeInfo = codegen.typeInfoValue(dstDescriptor!!) // Get TypeInfo for dst type. val srcArg = evaluateExpression(value.argument) // Evaluate src expression. - val srcObjInfoPtr = codegen.bitcast(codegen.kObjHeaderPtr, srcArg) // Cast src to ObjInfoPtr. + val srcObjInfoPtr = functionGenerationContext.bitcast(codegen.kObjHeaderPtr, srcArg) // Cast src to ObjInfoPtr. val args = listOf(srcObjInfoPtr, dstTypeInfo) // Create arg list. - debugLocation(value) call(context.llvm.checkInstanceFunction, args) // Check if dst is subclass of src. return srcArg } @@ -1219,25 +1209,25 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid val type = value.typeOperand val srcArg = evaluateExpression(value.argument) // Evaluate src expression. - val bbExit = codegen.basicBlock("instance_of_exit") - val bbInstanceOf = codegen.basicBlock("instance_of_notnull") - val bbNull = codegen.basicBlock("instance_of_null") + val bbExit = functionGenerationContext.basicBlock("instance_of_exit", value.startLocation) + val bbInstanceOf = functionGenerationContext.basicBlock("instance_of_notnull", value.startLocation) + val bbNull = functionGenerationContext.basicBlock("instance_of_null", value.startLocation) - val condition = codegen.icmpEq(srcArg, codegen.kNullObjHeaderPtr) - codegen.condBr(condition, bbNull, bbInstanceOf) + val condition = functionGenerationContext.icmpEq(srcArg, codegen.kNullObjHeaderPtr) + functionGenerationContext.condBr(condition, bbNull, bbInstanceOf) - codegen.positionAtEnd(bbNull) + functionGenerationContext.positionAtEnd(bbNull) val resultNull = if (TypeUtils.isNullableType(type)) kTrue else kFalse - codegen.br(bbExit) + functionGenerationContext.br(bbExit) - codegen.positionAtEnd(bbInstanceOf) + functionGenerationContext.positionAtEnd(bbInstanceOf) val resultInstanceOf = genInstanceOf(srcArg, type) - codegen.br(bbExit) - val bbInstanceOfResult = codegen.currentBlock + functionGenerationContext.br(bbExit) + val bbInstanceOfResult = functionGenerationContext.currentBlock - codegen.positionAtEnd(bbExit) - val result = codegen.phi(kBoolean) - codegen.addPhiIncoming(result, bbNull to resultNull, bbInstanceOfResult to resultInstanceOf) + functionGenerationContext.positionAtEnd(bbExit) + val result = functionGenerationContext.phi(kBoolean) + functionGenerationContext.addPhiIncoming(result, bbNull to resultNull, bbInstanceOfResult to resultInstanceOf) return result } @@ -1249,18 +1239,18 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid // Workaround for reified parameters val dstTypeInfo = codegen.typeInfoValue(dstDescriptor) // Get TypeInfo for dst type. - val srcObjInfoPtr = codegen.bitcast(codegen.kObjHeaderPtr, obj) // Cast src to ObjInfoPtr. + val srcObjInfoPtr = functionGenerationContext.bitcast(codegen.kObjHeaderPtr, obj) // Cast src to ObjInfoPtr. val args = listOf(srcObjInfoPtr, dstTypeInfo) // Create arg list. val result = call(context.llvm.isInstanceFunction, args) // Check if dst is subclass of src. - return LLVMBuildTrunc(codegen.builder, result, kInt1, "")!! // Truncate result to boolean + return LLVMBuildTrunc(functionGenerationContext.builder, result, kInt1, "")!! // Truncate result to boolean } //-------------------------------------------------------------------------// private fun evaluateNotInstanceOf(value: IrTypeOperatorCall): LLVMValueRef { val instanceOfResult = evaluateInstanceOf(value) - return LLVMBuildNot(codegen.builder, instanceOfResult, "")!! + return LLVMBuildNot(functionGenerationContext.builder, instanceOfResult, "")!! } //-------------------------------------------------------------------------// @@ -1269,17 +1259,13 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid context.log{"evaluateGetField : ${ir2string(value)}"} if (value.descriptor.dispatchReceiverParameter != null) { val thisPtr = evaluateExpression(value.receiver!!) - return debugInfo(value) { - codegen.loadSlot( - fieldPtrOfClass(thisPtr, value.descriptor), value.descriptor.isVar()) - } + return functionGenerationContext.loadSlot( + fieldPtrOfClass(thisPtr, value.descriptor), value.descriptor.isVar()) } else { assert (value.receiver == null) val ptr = context.llvmDeclarations.forStaticField(value.descriptor).storage - return debugInfo(value) { - codegen.loadSlot(ptr, value.descriptor.isVar()) - } + return functionGenerationContext.loadSlot(ptr, value.descriptor.isVar()) } } @@ -1308,16 +1294,12 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid if (value.descriptor.dispatchReceiverParameter != null) { val thisPtr = evaluateExpression(value.receiver!!) - debugInfo(value) { - codegen.storeAnyGlobal(valueToAssign, fieldPtrOfClass(thisPtr, value.descriptor)) - } + functionGenerationContext.storeAnyGlobal(valueToAssign, fieldPtrOfClass(thisPtr, value.descriptor)) } else { assert (value.receiver == null) val globalValue = context.llvmDeclarations.forStaticField(value.descriptor).storage - debugInfo(value) { - codegen.storeAnyGlobal(valueToAssign, globalValue) - } + functionGenerationContext.storeAnyGlobal(valueToAssign, globalValue) } assert (value.type.isUnit()) @@ -1362,9 +1344,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid val fieldInfo = context.llvmDeclarations.forField(value) val typePtr = pointerType(fieldInfo.classBodyType) - val objectPtr = LLVMBuildGEP(codegen.builder, thisPtr, cValuesOf(kImmOne), 1, "") - val typedObjPtr = codegen.bitcast(typePtr, objectPtr!!) - val fieldPtr = LLVMBuildStructGEP(codegen.builder, typedObjPtr, fieldInfo.index, "") + val objectPtr = LLVMBuildGEP(functionGenerationContext.builder, thisPtr, cValuesOf(kImmOne), 1, "") + val typedObjPtr = functionGenerationContext.bitcast(typePtr, objectPtr!!) + val fieldPtr = LLVMBuildStructGEP(functionGenerationContext.builder, typedObjPtr, fieldInfo.index, "") return fieldPtr!! } @@ -1372,7 +1354,6 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid private fun evaluateConst(value: IrConst<*>): LLVMValueRef { context.log{"evaluateConst : ${ir2string(value)}"} - debugLocation(value) when (value.kind) { IrConstKind.Null -> return codegen.kNullObjHeaderPtr IrConstKind.Boolean -> when (value.value) { @@ -1407,7 +1388,6 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid evaluated } - debugLocation(expression) currentCodeContext.genReturn(target, ret) return codegen.kNothingFakeValue } @@ -1420,16 +1400,16 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid var resultPhi : LLVMValueRef? = null private fun getExit(): LLVMBasicBlockRef { - if (bbExit == null) bbExit = codegen.basicBlock("returnable_block_exit") + if (bbExit == null) bbExit = functionGenerationContext.basicBlock("returnable_block_exit", null) return bbExit!! } private fun getResult(): LLVMValueRef { if (resultPhi == null) { - val bbCurrent = codegen.currentBlock - codegen.positionAtEnd(getExit()) - resultPhi = codegen.phi(codegen.getLLVMType(returnableBlock.type)) - codegen.positionAtEnd(bbCurrent) + val bbCurrent = functionGenerationContext.currentBlock + functionGenerationContext.positionAtEnd(getExit()) + resultPhi = functionGenerationContext.phi(codegen.getLLVMType(returnableBlock.type)) + functionGenerationContext.positionAtEnd(bbCurrent) } return resultPhi!! } @@ -1440,10 +1420,10 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid return } // It is local return from current function. - codegen.br(getExit()) // Generate branch on exit block. + functionGenerationContext.br(getExit()) // Generate branch on exit block. if (!target.returnsUnit()) { // If function returns more then "unit" - codegen.assignPhis(getResult() to value!!) // Assign return value to result PHI node. + functionGenerationContext.assignPhis(getResult() to value!!) // Assign return value to result PHI node. } } } @@ -1469,7 +1449,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid refScope = context.debugInfo.compilationModule as DIScopeOpaqueRef, name = clazz.descriptor.typeInfoSymbolName, refFile = file().file(), - line = clazz.line()) as DITypeOpaqueRef + line = clazz.startLine()) as DITypeOpaqueRef else null override fun classScope(): CodeContext? = this } @@ -1490,14 +1470,14 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid val bbExit = returnableBlockScope.bbExit if (bbExit != null) { - if (!codegen.isAfterTerminator()) { // TODO should we solve this problem once and for all + if (!functionGenerationContext.isAfterTerminator()) { // TODO should we solve this problem once and for all if (returnableBlockScope.resultPhi != null) { - codegen.unreachable() + functionGenerationContext.unreachable() } else { - codegen.br(bbExit) + functionGenerationContext.br(bbExit) } } - codegen.positionAtEnd(bbExit) + functionGenerationContext.positionAtEnd(bbExit) } return returnableBlockScope.resultPhi ?: codegen.theUnitInstanceRef.llvm @@ -1543,7 +1523,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid * Returns `null` on failure. */ private fun compileTimeEvaluate(expression: IrMemberAccessExpression, args: List): LLVMValueRef? { - if (!args.all { codegen.isConst(it) }) { + if (!args.all { it.isConst }) { return null } @@ -1587,17 +1567,16 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid compileTimeEvaluate(value, args)?.let { return it } - debugInfo(value) { - when { - value is IrDelegatingConstructorCall -> - return delegatingConstructorCall(value.descriptor, args) + debugLocation(value) + when { + value is IrDelegatingConstructorCall -> + return delegatingConstructorCall(value.descriptor, args) - value.descriptor is FunctionDescriptor -> - return evaluateFunctionCall( + value.descriptor is FunctionDescriptor -> + return evaluateFunctionCall( value as IrCall, args, resultLifetime(value)) - else -> { - TODO(ir2string(value)) - } + else -> { + TODO(ir2string(value)) } } } @@ -1606,32 +1585,41 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid private fun file() = (currentCodeContext.fileScope() as FileScope).file //-------------------------------------------------------------------------// - private fun debugLocation(element: IrElement):DILocationRef? { - if (!context.shouldContainDebugInfo()) return null - val functionScope = currentCodeContext.functionScope() as? FunctionScope ?: return null - val scope = functionScope.declaration ?: return null - val diScope = scope.scope() + private fun debugLocation(element: IrElement?):DILocationRef? { + if (!context.shouldContainDebugInfo() || element == null) return null @Suppress("UNCHECKED_CAST") - return codegen.debugLocation(LocationInfo( - line = element.line(), - column = element.column(), - scope = diScope as DIScopeOpaqueRef)) + return element.startLocation?.let{functionGenerationContext.debugLocation(it)} } - //-------------------------------------------------------------------------// - private fun IrElement.line() = file().fileEntry.line(this.startOffset) + private val IrElement.startLocation: LocationInfo? + get() = location(startLine(), startColumn()) - //-------------------------------------------------------------------------// - private fun IrElement.column() = file().fileEntry.column(this.startOffset) + private val IrElement.endLocation: LocationInfo? + get() = location(endLine(), endColumn()) - //-------------------------------------------------------------------------// - private inline fun debugInfo(element: IrElement, body:() -> T): T { - debugLocation(element) - val result = body() - codegen.resetDebugLocation() - return result + private inline fun location(line: Int, column: Int): LocationInfo? { + val functionScope = currentCodeContext.functionScope() as? FunctionScope ?: return null + val scope = functionScope.declaration ?: return null + val diScope = scope.scope() ?: return null + return LocationInfo( + line = line, + column = column, + scope = diScope) } + + //-------------------------------------------------------------------------// + private fun IrElement.startLine() = file().fileEntry.line(this.startOffset) + + //-------------------------------------------------------------------------// + private fun IrElement.startColumn() = file().fileEntry.column(this.startOffset) + + //-------------------------------------------------------------------------// + private fun IrElement.endLine() = file().fileEntry.line(this.endOffset) + + //-------------------------------------------------------------------------// + private fun IrElement.endColumn() = file().fileEntry.column(this.endOffset) + //-------------------------------------------------------------------------// @Suppress("UNCHECKED_CAST") private fun debugClassDeclaration(declaration: IrClass, body: () -> Unit): Unit { @@ -1645,7 +1633,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid scope = context.debugInfo.compilationModule as DIScopeOpaqueRef, name = declaration.descriptor.typeInfoSymbolName, file = file().file(), - lineNumber = declaration.line(), + lineNumber = declaration.startLine(), sizeInBits = 64 /* TODO */, alignInBits = 4 /* TODO */, derivedFrom = null, @@ -1672,7 +1660,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid refScope = scope.scope as DIScopeOpaqueRef, name = expression.descriptor.symbolName, file = irFile.file(), - lineNum = expression.line(), + lineNum = expression.startLine(), sizeInBits = sizeInBits, alignInBits = alignInBits, offsetInBits = scope.offsetInBits, @@ -1705,7 +1693,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid name = descriptor.name.asString(), linkageName = linkageName, file = file().file(), - lineNo = line(), + lineNo = startLine(), type = subroutineType, //TODO: need more investigations. isLocal = 0, @@ -1724,7 +1712,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid .getContributedFunctions(Name.identifier("doResume"), NoLookupLocation.FROM_BACKEND).single() private fun getContinuation(): LLVMValueRef { - val caller = codegen.functionDescriptor!! + val caller = functionGenerationContext.functionDescriptor!! return if (caller.isSuspend) codegen.param(caller, caller.allParameters.size) // The last argument. else { @@ -1779,18 +1767,18 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid private fun evaluateSuspendableExpression(expression: IrSuspendableExpression): LLVMValueRef { val suspensionPointId = evaluateExpression(expression.suspensionPointId) - val bbStart = codegen.basicBlock("start") - val bbDispatch = codegen.basicBlock("dispatch") + val bbStart = functionGenerationContext.basicBlock("start", expression.result.startLocation) + val bbDispatch = functionGenerationContext.basicBlock("dispatch", expression.suspensionPointId.startLocation) val resumePoints = mutableListOf() using (SuspendableExpressionScope(resumePoints)) { - codegen.condBr(codegen.icmpEq(suspensionPointId, kNullInt8Ptr), bbStart, bbDispatch) + functionGenerationContext.condBr(functionGenerationContext.icmpEq(suspensionPointId, kNullInt8Ptr), bbStart, bbDispatch) - codegen.positionAtEnd(bbStart) + functionGenerationContext.positionAtEnd(bbStart) val result = evaluateExpression(expression.result) - codegen.appendingTo(bbDispatch) { - codegen.indirectBr(suspensionPointId, resumePoints) + functionGenerationContext.appendingTo(bbDispatch) { + functionGenerationContext.indirectBr(suspensionPointId, resumePoints) } return result } @@ -1800,25 +1788,25 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid val bbResume: LLVMBasicBlockRef): InnerScopeImpl() { override fun genGetValue(descriptor: ValueDescriptor): LLVMValueRef { if (descriptor == suspensionPointId) - return codegen.blockAddress(bbResume) + return functionGenerationContext.blockAddress(bbResume) return super.genGetValue(descriptor) } } private fun evaluateSuspensionPoint(expression: IrSuspensionPoint): LLVMValueRef { - val bbResume = codegen.basicBlock("resume") + val bbResume = functionGenerationContext.basicBlock("resume", expression.resumeResult.startLocation) currentCodeContext.addResumePoint(bbResume) using (SuspensionPointScope(expression.suspensionPointIdParameter.descriptor, bbResume)) { - continuationBlock(expression.type).run { + continuationBlock(expression.type, expression.result.startLocation).run { val normalResult = evaluateExpression(expression.result) jump(this, normalResult) - codegen.positionAtEnd(bbResume) + functionGenerationContext.positionAtEnd(bbResume) val resumeResult = evaluateExpression(expression.resumeResult) jump(this, resumeResult) - codegen.positionAtEnd(this.block) + functionGenerationContext.positionAtEnd(this.block) return this.value } } @@ -1864,23 +1852,23 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid private fun evaluateConstructorCall(callee: IrCall, args: List): LLVMValueRef { context.log{"evaluateConstructorCall : ${ir2string(callee)}"} - memScoped { + return memScoped { val constructedClass = (callee.descriptor as ConstructorDescriptor).constructedClass val thisValue = if (constructedClass.isArray) { assert(args.isNotEmpty() && args[0].type == int32Type) - codegen.allocArray(codegen.typeInfoValue(constructedClass), args[0], + functionGenerationContext.allocArray(codegen.typeInfoValue(constructedClass), args[0], resultLifetime(callee)) } else if (constructedClass == context.builtIns.string) { // TODO: consider returning the empty string literal instead. assert(args.isEmpty()) - codegen.allocArray(codegen.typeInfoValue(constructedClass), count = kImmZero, + functionGenerationContext.allocArray(codegen.typeInfoValue(constructedClass), count = kImmZero, lifetime = resultLifetime(callee)) } else { - codegen.allocInstance(codegen.typeInfoValue(constructedClass), resultLifetime(callee)) + functionGenerationContext.allocInstance(codegen.typeInfoValue(constructedClass), resultLifetime(callee)) } evaluateSimpleFunctionCall(callee.descriptor, listOf(thisValue) + args, Lifetime.IRRELEVANT /* constructor doesn't return anything */) - return thisValue + thisValue } } @@ -1898,10 +1886,10 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid return when (LLVMGetTypeKind(arg0.type)) { LLVMTypeKind.LLVMFloatTypeKind, LLVMTypeKind.LLVMDoubleTypeKind -> - codegen.fcmpEq(arg0, arg1) + functionGenerationContext.fcmpEq(arg0, arg1) else -> - codegen.icmpEq(arg0, arg1) + functionGenerationContext.icmpEq(arg0, arg1) } } "konan.internal.getContinuation" -> return getContinuation() @@ -1916,27 +1904,27 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid in interop.readPrimitive -> { val pointerType = pointerType(codegen.getLLVMType(descriptor.returnType!!)) val rawPointer = args.last() - val pointer = codegen.bitcast(pointerType, rawPointer) - codegen.load(pointer) + val pointer = functionGenerationContext.bitcast(pointerType, rawPointer) + functionGenerationContext.load(pointer) } in interop.writePrimitive -> { val pointerType = pointerType(codegen.getLLVMType(descriptor.valueParameters.last().type)) val rawPointer = args[1] - val pointer = codegen.bitcast(pointerType, rawPointer) - codegen.store(args[2], pointer) + val pointer = functionGenerationContext.bitcast(pointerType, rawPointer) + functionGenerationContext.store(args[2], pointer) codegen.theUnitInstanceRef.llvm } - context.builtIns.nativePtrPlusLong -> codegen.gep(args[0], args[1]) + context.builtIns.nativePtrPlusLong -> functionGenerationContext.gep(args[0], args[1]) context.builtIns.getNativeNullPtr -> kNullInt8Ptr interop.getPointerSize -> Int32(LLVMPointerSize(codegen.llvmTargetData)).llvm context.builtIns.nativePtrToLong -> { - val intPtrValue = codegen.ptrToInt(args.single(), codegen.intPtrType) - val resultType = codegen.getLLVMType(descriptor.returnType!!) + val intPtrValue = functionGenerationContext.ptrToInt(args.single(), codegen.intPtrType) + val resultType = functionGenerationContext.getLLVMType(descriptor.returnType!!) if (resultType == intPtrValue.type) { intPtrValue } else { - LLVMBuildSExt(codegen.builder, intPtrValue, resultType, "")!! + LLVMBuildSExt(functionGenerationContext.builder, intPtrValue, resultType, "")!! } } else -> TODO(callee.descriptor.original.toString()) @@ -1954,12 +1942,12 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid val descriptor = callee.descriptor val ib = context.irModule!!.irBuiltins when (descriptor) { - ib.eqeqeq -> return codegen.icmpEq(args[0], args[1]) - ib.gt0 -> return codegen.icmpGt(args[0], kImmZero) - ib.gteq0 -> return codegen.icmpGe(args[0], kImmZero) - ib.lt0 -> return codegen.icmpLt(args[0], kImmZero) - ib.lteq0 -> return codegen.icmpLe(args[0], kImmZero) - ib.booleanNot -> return codegen.icmpNe(args[0], kTrue) + ib.eqeqeq -> return functionGenerationContext.icmpEq(args[0], args[1]) + ib.gt0 -> return functionGenerationContext.icmpGt(args[0], kImmZero) + ib.gteq0 -> return functionGenerationContext.icmpGe(args[0], kImmZero) + ib.lt0 -> return functionGenerationContext.icmpLt(args[0], kImmZero) + ib.lteq0 -> return functionGenerationContext.icmpLe(args[0], kImmZero) + ib.booleanNot -> return functionGenerationContext.icmpNe(args[0], kTrue) else -> { TODO(descriptor.name.toString()) } @@ -1971,25 +1959,25 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid private fun generateWhenCase(resultPhi: LLVMValueRef?, branch: IrBranch, bbNext: LLVMBasicBlockRef?, bbExit: LLVMBasicBlockRef?) { val branchResult = branch.result - val brResult = if (isUnconditional(branch)) { // It is the "else" clause. - evaluateExpression(branchResult) // Generate clause body. - } else { // It is conditional clause. - val bbCase = codegen.basicBlock("when_case") // Create block for clause body. - val condition = evaluateExpression(branch.condition) // Generate cmp instruction. - codegen.condBr(condition, bbCase, bbNext) // Conditional branch depending on cmp result. - codegen.positionAtEnd(bbCase) // Switch generation to block for clause body. - evaluateExpression(branch.result) // Generate clause body. + val brResult = if (isUnconditional(branch)) { // It is the "else" clause. + evaluateExpression(branchResult) // Generate clause body. + } else { // It is conditional clause. + val bbCase = functionGenerationContext.basicBlock("when_case", branch.startLocation) // Create block for clause body. + val condition = evaluateExpression(branch.condition) // Generate cmp instruction. + functionGenerationContext.condBr(condition, bbCase, bbNext) // Conditional branch depending on cmp result. + functionGenerationContext.positionAtEnd(bbCase) // Switch generation to block for clause body. + evaluateExpression(branch.result) // Generate clause body. } - if (!codegen.isAfterTerminator()) { + if (!functionGenerationContext.isAfterTerminator()) { if (resultPhi != null) - codegen.assignPhis(resultPhi to brResult) + functionGenerationContext.assignPhis(resultPhi to brResult) if (bbExit != null) - codegen.br(bbExit) + functionGenerationContext.br(bbExit) } if (bbNext != null) // Switch generation to next or exit. - codegen.positionAtEnd(bbNext) + functionGenerationContext.positionAtEnd(bbNext) else if (bbExit != null) - codegen.positionAtEnd(bbExit) + functionGenerationContext.positionAtEnd(bbExit) } //-------------------------------------------------------------------------// @@ -2013,8 +2001,8 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid fun callVirtual(descriptor: FunctionDescriptor, args: List, resultLifetime: Lifetime): LLVMValueRef { assert(LLVMTypeOf(args[0]) == codegen.kObjHeaderPtr) - val typeInfoPtrPtr = LLVMBuildStructGEP(codegen.builder, args[0], 0 /* type_info */, "")!! - val typeInfoPtr = codegen.load(typeInfoPtrPtr) + val typeInfoPtrPtr = LLVMBuildStructGEP(functionGenerationContext.builder, args[0], 0 /* type_info */, "")!! + val typeInfoPtr = functionGenerationContext.load(typeInfoPtrPtr) assert (typeInfoPtr.type == codegen.kTypeInfoPtr) val owner = descriptor.containingDeclaration as ClassDescriptor @@ -2022,11 +2010,11 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid // If this is a virtual method of the class - we can call via vtable. val index = context.getVtableBuilder(owner).vtableIndex(descriptor) - val vtablePlace = codegen.gep(typeInfoPtr, Int32(1).llvm) // typeInfoPtr + 1 - val vtable = codegen.bitcast(kInt8PtrPtr, vtablePlace) + val vtablePlace = functionGenerationContext.gep(typeInfoPtr, Int32(1).llvm) // typeInfoPtr + 1 + val vtable = functionGenerationContext.bitcast(kInt8PtrPtr, vtablePlace) - val slot = codegen.gep(vtable, Int32(index).llvm) - codegen.load(slot) + val slot = functionGenerationContext.gep(vtable, Int32(index).llvm) + functionGenerationContext.load(slot) } else { // Otherwise, call by hash. // TODO: optimize by storing interface number in lower bits of 'this' pointer @@ -2037,7 +2025,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid call(context.llvm.lookupOpenMethodFunction, lookupArgs) } val functionPtrType = pointerType(codegen.getLlvmFunctionType(descriptor)) // Construct type of the method to be invoked - val function = codegen.bitcast(functionPtrType, llvmMethod) // Cast method address to the type + val function = functionGenerationContext.bitcast(functionPtrType, llvmMethod) // Cast method address to the type return call(descriptor, function, args, resultLifetime) // Invoke the method } @@ -2051,7 +2039,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid resultLifetime: Lifetime): LLVMValueRef { val result = call(function, args, resultLifetime) if (descriptor.returnType?.isNothing() == true) { - codegen.unreachable() + functionGenerationContext.unreachable() } if (LLVMGetReturnType(getFunctionType(function)) == voidType) { @@ -2070,7 +2058,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid fun delegatingConstructorCall(descriptor: ClassConstructorDescriptor, args: List): LLVMValueRef { - val constructedClass = codegen.constructedClass!! + val constructedClass = functionGenerationContext.constructedClass!! val thisPtr = currentCodeContext.genGetValue(constructedClass.thisAsReceiverParameter) val thisPtrArgType = codegen.getLLVMType(descriptor.allParameters[0].type) @@ -2078,7 +2066,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid thisPtr } else { // e.g. when array constructor calls super (i.e. Any) constructor. - codegen.bitcast(thisPtrArgType, thisPtr) + functionGenerationContext.bitcast(thisPtrArgType, thisPtr) } return callDirect(descriptor, listOf(thisPtrArg) + args, @@ -2108,18 +2096,15 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid assert(LLVMCountParams(entryPoint) == 1) val selector = LLVMAddFunction(context.llvmModule, selectorName, entryPointType)!! - codegen.prologue(selector, voidType) - - // Note, that 'parameter' is an object reference, and as such, shall - // be accounted for in the rootset. However, current object management - // scheme for arguments guarantees, that reference is being held in C++ - // launcher, so we could optimize out creating slot for 'parameter' in - // this function. - val parameter = LLVMGetParam(selector, 0)!! - codegen.callAtFunctionScope(entryPoint, listOf(parameter), Lifetime.IRRELEVANT) - - codegen.ret(null) - codegen.epilogue() + generateFunction(codegen, selector) { + // Note, that 'parameter' is an object reference, and as such, shall + // be accounted for in the rootset. However, current object management + // scheme for arguments guarantees, that reference is being held in C++ + // launcher, so we could optimize out creating slot for 'parameter' in + // this function. + val parameter = LLVMGetParam(selector, 0)!! + callAtFunctionScope(entryPoint, listOf(parameter), Lifetime.IRRELEVANT) + } return selector } @@ -2173,7 +2158,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid //-------------------------------------------------------------------------// - fun CodeGenerator.basicBlock(name: String, code: () -> Unit) = basicBlock(name).apply { + fun FunctionGenerationContext.basicBlock(name: String, locationInfo: LocationInfo?, code: () -> Unit) = functionGenerationContext.basicBlock(name, locationInfo).apply { appendingTo(this) { code() } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/VariableManager.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/VariableManager.kt index 8d6c69ea42a..b562fcd384b 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/VariableManager.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/VariableManager.kt @@ -21,7 +21,7 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.name.Name -internal class VariableManager(val codegen: CodeGenerator) { +internal class VariableManager(val functionGenerationContext: FunctionGenerationContext) { internal interface Record { fun load() : LLVMValueRef fun store(value: LLVMValueRef) @@ -29,8 +29,8 @@ internal class VariableManager(val codegen: CodeGenerator) { } inner class SlotRecord(val address: LLVMValueRef, val refSlot: Boolean, val isVar: Boolean) : Record { - override fun load() : LLVMValueRef = codegen.loadSlot(address, isVar) - override fun store(value: LLVMValueRef) = codegen.storeAnyLocal(value, address) + override fun load() : LLVMValueRef = functionGenerationContext.loadSlot(address, isVar) + override fun store(value: LLVMValueRef) = functionGenerationContext.storeAnyLocal(value, address) override fun address() : LLVMValueRef = this.address override fun toString() = (if (refSlot) "refslot" else "slot") + " for ${address}" } @@ -67,11 +67,11 @@ internal class VariableManager(val codegen: CodeGenerator) { isVar: Boolean, value: LLVMValueRef? = null) : Int { assert(!contextVariablesToIndex.contains(descriptor)) val index = variables.size - val type = codegen.getLLVMType(descriptor.type) - val slot = codegen.alloca(type, descriptor.name.asString()) + val type = functionGenerationContext.getLLVMType(descriptor.type) + val slot = functionGenerationContext.alloca(type, descriptor.name.asString()) if (value != null) - codegen.storeAnyLocal(value, slot) - variables.add(SlotRecord(slot, codegen.isObjectType(type), isVar)) + functionGenerationContext.storeAnyLocal(value, slot) + variables.add(SlotRecord(slot, functionGenerationContext.isObjectType(type), isVar)) contextVariablesToIndex[descriptor] = index return index } @@ -79,16 +79,16 @@ internal class VariableManager(val codegen: CodeGenerator) { // Creates anonymous mutable variable. // Think of slot reuse. fun createAnonymousSlot(value: LLVMValueRef? = null) : LLVMValueRef { - val index = createAnonymousMutable(codegen.kObjHeaderPtr, value) + val index = createAnonymousMutable(functionGenerationContext.kObjHeaderPtr, value) return addressOf(index) } private fun createAnonymousMutable(type: LLVMTypeRef, value: LLVMValueRef? = null) : Int { val index = variables.size - val slot = codegen.alloca(type) + val slot = functionGenerationContext.alloca(type) if (value != null) - codegen.storeAnyLocal(value, slot) - variables.add(SlotRecord(slot, codegen.isObjectType(type), true)) + functionGenerationContext.storeAnyLocal(value, slot) + variables.add(SlotRecord(slot, functionGenerationContext.isObjectType(type), true)) return index } @@ -119,17 +119,17 @@ internal class VariableManager(val codegen: CodeGenerator) { fun debugInfoLocalVariableLocation(functionScope: DIScopeOpaqueRef, diType: DITypeOpaqueRef, name:Name, variable: LLVMValueRef, file: DIFileRef, line: Int, location: DILocationRef?) { val variableDeclaration = DICreateAutoVariable( - builder = codegen.context.debugInfo.builder, + builder = functionGenerationContext.context.debugInfo.builder, scope = functionScope, name = name.asString(), file = file, line = line, type = diType) DIInsertDeclarationWithEmptyExpression( - builder = codegen.context.debugInfo.builder, + builder = functionGenerationContext.context.debugInfo.builder, value = variable, localVariable = variableDeclaration, location = location, - bb = LLVMGetInsertBlock(codegen.builder)) + bb = LLVMGetInsertBlock(functionGenerationContext.builder)) } } diff --git a/runtime/build.gradle b/runtime/build.gradle index 81225120f91..9b98b09ef04 100644 --- a/runtime/build.gradle +++ b/runtime/build.gradle @@ -26,6 +26,7 @@ targetList.each { targetName -> dependsOn "${targetName}Launcher" target targetName compilerArgs targetArgs[targetName] + compilerArgs '-g' compilerArgs '-I' + project.file('../common/src/hash/headers') compilerArgs '-I' + project.file(rootProject.ext.get("${targetName}LibffiDir") + "/include") linkerArgs project.file("../common/build/$targetName/hash.bc").path @@ -38,6 +39,7 @@ targetList.each { targetName -> srcRoot file('src/launcher') target targetName compilerArgs targetArgs[targetName] + compilerArgs '-g' compilerArgs '-I' + project.file('../common/src/hash/headers') compilerArgs '-I' + project.file('src/main/cpp') }