[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:
Vasily Levchenko
2017-06-23 13:34:15 +03:00
committed by vvlevchenko
parent 2a64d2bec5
commit 27517b0db1
4 changed files with 614 additions and 591 deletions
@@ -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)
}
}
@@ -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))
}
}
+2
View File
@@ -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')
}