[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
This commit is contained in:
committed by
vvlevchenko
parent
2a64d2bec5
commit
27517b0db1
+290
-254
@@ -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<LLVMBasicBlockRef, LLVMValueRef> = 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<R> 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<R> generateFunction(codegen: CodeGenerator, function: LLVMValueRef, code:FunctionGenerationContext.(FunctionGenerationContext) -> R) {
|
||||
generateFunctionBody(FunctionGenerationContext(function, codegen), code)
|
||||
}
|
||||
|
||||
inline private fun <R> 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<LLVMBasicBlockRef, LocationInfo>()
|
||||
|
||||
private fun update(block:LLVMBasicBlockRef, locationInfo: LocationInfo?) {
|
||||
locationInfo ?: return
|
||||
basicBlockToLastLocation.put(block, locationInfo)
|
||||
}
|
||||
|
||||
var returnType: LLVMTypeRef? = LLVMGetReturnType(getFunctionType(function))
|
||||
private val returns: MutableMap<LLVMBasicBlockRef, LLVMValueRef> = 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<LLVMValueRef>,
|
||||
lifetime: Lifetime) =
|
||||
call(llvmFunction, args, lifetime, this::cleanupLandingpad)
|
||||
call(llvmFunction, args, lifetime, { cleanupLandingpad })
|
||||
|
||||
fun call(llvmFunction: LLVMValueRef, args: List<LLVMValueRef>,
|
||||
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<LLVMValueRef>,
|
||||
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<LLVMValueRef, LLVMValueRef>) {
|
||||
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<LLVMBasicBlockRef>): 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<LLVMBasicBlockRef>): 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 <R> preservingPosition(code: () -> R): R {
|
||||
inline private fun <R> 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 <R> appendingTo(block: LLVMBasicBlockRef, code: CodeGenerator.() -> R) = preservingPosition {
|
||||
inline fun <R> 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)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
+308
-323
File diff suppressed because it is too large
Load Diff
+14
-14
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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')
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user