[codegen][debug info] codegerator uses start/end location encapsulated in IrElement

This commit is contained in:
Vasily Levchenko
2019-06-28 16:28:34 +03:00
parent 360dc2c9b4
commit c8af53e58b
4 changed files with 61 additions and 35 deletions
@@ -155,6 +155,11 @@ private inline fun <R> generateFunctionBody(
functionGenerationContext.resetDebugLocation() functionGenerationContext.resetDebugLocation()
} }
/**
* There're cases when we don't need end position or it is meaningless.
*/
internal data class LocationInfoRange(var start: LocationInfo, var end: LocationInfo?)
internal class FunctionGenerationContext(val function: LLVMValueRef, internal class FunctionGenerationContext(val function: LLVMValueRef,
val codegen: CodeGenerator, val codegen: CodeGenerator,
startLocation: LocationInfo?, startLocation: LocationInfo?,
@@ -163,11 +168,11 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
override val context = codegen.context override val context = codegen.context
val vars = VariableManager(this) val vars = VariableManager(this)
private val basicBlockToLastLocation = mutableMapOf<LLVMBasicBlockRef, LocationInfo>() private val basicBlockToLastLocation = mutableMapOf<LLVMBasicBlockRef, LocationInfoRange>()
private fun update(block:LLVMBasicBlockRef, locationInfo: LocationInfo?) { private fun update(block:LLVMBasicBlockRef, locationInfo: LocationInfo?, endLocation: LocationInfo? = null) {
locationInfo ?: return locationInfo ?: return
basicBlockToLastLocation.put(block, locationInfo) basicBlockToLastLocation.put(block, LocationInfoRange(locationInfo, endLocation))
} }
var returnType: LLVMTypeRef? = LLVMGetReturnType(getFunctionType(function)) var returnType: LLVMTypeRef? = LLVMGetReturnType(getFunctionType(function))
@@ -209,9 +214,9 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
return bb return bb
} }
fun basicBlock(name:String = "label_" , locationInfo:LocationInfo?): LLVMBasicBlockRef { fun basicBlock(name:String = "label_", startLocationInfo:LocationInfo?, endLocationInfo: LocationInfo? = null): LLVMBasicBlockRef {
val result = LLVMInsertBasicBlock(this.currentBlock, name)!! val result = LLVMInsertBasicBlock(this.currentBlock, name)!!
update(result, locationInfo) update(result, startLocationInfo, endLocationInfo)
LLVMMoveBasicBlockAfter(result, this.currentBlock) LLVMMoveBasicBlockAfter(result, this.currentBlock)
return result return result
} }
@@ -375,8 +380,11 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
} }
} }
val success = basicBlock("call_success", position()) val position = position()
val endLocation = position?.start.let { position?.end }
val success = basicBlock("call_success", endLocation)
val result = LLVMBuildInvoke(builder, llvmFunction, rargs, args.size, success, unwind, "")!! val result = LLVMBuildInvoke(builder, llvmFunction, rargs, args.size, success, unwind, "")!!
update(success, endLocation, endLocation)
positionAtEnd(success) positionAtEnd(success)
return result return result
} }
@@ -526,15 +534,15 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
} }
fun filteringExceptionHandler(codeContext: CodeContext): ExceptionHandler { fun filteringExceptionHandler(codeContext: CodeContext): ExceptionHandler {
val lpBlock = basicBlockInFunction("filteringExceptionHandler", position()) val lpBlock = basicBlockInFunction("filteringExceptionHandler", position()?.start)
appendingTo(lpBlock) { appendingTo(lpBlock) {
val landingpad = gxxLandingpad(2) val landingpad = gxxLandingpad(2)
LLVMAddClause(landingpad, kotlinExceptionRtti.llvm) LLVMAddClause(landingpad, kotlinExceptionRtti.llvm)
LLVMAddClause(landingpad, LLVMConstNull(kInt8Ptr)) LLVMAddClause(landingpad, LLVMConstNull(kInt8Ptr))
val fatalForeignExceptionBlock = basicBlock("fatalForeignException", position()) val fatalForeignExceptionBlock = basicBlock("fatalForeignException", position()?.start)
val forwardKotlinExceptionBlock = basicBlock("forwardKotlinException", position()) val forwardKotlinExceptionBlock = basicBlock("forwardKotlinException", position()?.start)
val isKotlinException = icmpEq( val isKotlinException = icmpEq(
extractValue(landingpad, 1), extractValue(landingpad, 1),
@@ -565,7 +573,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
call(context.llvm.cxxStdTerminate, emptyList()) call(context.llvm.cxxStdTerminate, emptyList())
// Note: unreachable instruction to be generated here, but debug information is improper in this case. // Note: unreachable instruction to be generated here, but debug information is improper in this case.
val loopBlock = basicBlock("loop", position()) val loopBlock = basicBlock("loop", position()?.start)
br(loopBlock) br(loopBlock)
appendingTo(loopBlock) { appendingTo(loopBlock) {
br(loopBlock) br(loopBlock)
@@ -626,12 +634,14 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
): LLVMValueRef { ): LLVMValueRef {
val resultType = thenValue.type val resultType = thenValue.type
val bbExit = basicBlock(locationInfo = position()) val position = position()
val endPosition = position()?.end
val bbExit = basicBlock(startLocationInfo = endPosition, endLocationInfo = endPosition)
val resultPhi = appendingTo(bbExit) { val resultPhi = appendingTo(bbExit) {
phi(resultType) phi(resultType)
} }
val bbElse = basicBlock(locationInfo = position()) val bbElse = basicBlock(startLocationInfo = position?.start, endLocationInfo = endPosition)
condBr(condition, bbExit, bbElse) condBr(condition, bbExit, bbElse)
assignPhis(resultPhi to thenValue) assignPhis(resultPhi to thenValue)
@@ -647,8 +657,9 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
} }
inline fun ifThen(condition: LLVMValueRef, thenBlock: () -> Unit) { inline fun ifThen(condition: LLVMValueRef, thenBlock: () -> Unit) {
val bbExit = basicBlock(locationInfo = position()) val endPosition = position()?.end
val bbThen = basicBlock(locationInfo = position()) val bbExit = basicBlock(startLocationInfo = endPosition, endLocationInfo = endPosition)
val bbThen = basicBlock(startLocationInfo = endPosition, endLocationInfo = endPosition)
condBr(condition, bbThen, bbExit) condBr(condition, bbThen, bbExit)
@@ -660,10 +671,10 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
positionAtEnd(bbExit) positionAtEnd(bbExit)
} }
internal fun debugLocation(locationInfo: LocationInfo): DILocationRef? { internal fun debugLocation(startLocationInfo: LocationInfo, endLocation: LocationInfo?): DILocationRef? {
if (!context.shouldContainDebugInfo()) return null if (!context.shouldContainDebugInfo()) return null
update(currentBlock, locationInfo) update(currentBlock, startLocationInfo, endLocation)
val debugLocation = codegen.generateLocationInfo(locationInfo) val debugLocation = codegen.generateLocationInfo(startLocationInfo)
currentPositionHolder.setBuilderDebugLocation(debugLocation) currentPositionHolder.setBuilderDebugLocation(debugLocation)
return debugLocation return debugLocation
} }
@@ -741,7 +752,8 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
fun getObjectValue( fun getObjectValue(
irClass: IrClass, irClass: IrClass,
exceptionHandler: ExceptionHandler, exceptionHandler: ExceptionHandler,
locationInfo: LocationInfo? startLocationInfo: LocationInfo?,
endLocationInfo: LocationInfo? = null
): LLVMValueRef { ): LLVMValueRef {
if (irClass.isUnit()) { if (irClass.isUnit()) {
return codegen.theUnitInstanceRef.llvm return codegen.theUnitInstanceRef.llvm
@@ -763,8 +775,8 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
val shared = irClass.objectIsShared && context.config.threadsAreAllowed val shared = irClass.objectIsShared && context.config.threadsAreAllowed
val objectPtr = codegen.getObjectInstanceStorage(irClass, shared) val objectPtr = codegen.getObjectInstanceStorage(irClass, shared)
val bbInit = basicBlock("label_init", locationInfo) val bbInit = basicBlock("label_init", startLocationInfo, endLocationInfo)
val bbExit = basicBlock("label_continue", locationInfo) val bbExit = basicBlock("label_continue", startLocationInfo, endLocationInfo)
val objectVal = loadSlot(objectPtr, false) val objectVal = loadSlot(objectPtr, false)
val objectInitialized = icmpUGt(ptrToInt(objectVal, codegen.intPtrType), codegen.immOneIntPtrType) val objectInitialized = icmpUGt(ptrToInt(objectVal, codegen.intPtrType), codegen.immOneIntPtrType)
val bbCurrent = currentBlock val bbCurrent = currentBlock
@@ -1034,7 +1046,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
fun positionAtEnd(block: LLVMBasicBlockRef) { fun positionAtEnd(block: LLVMBasicBlockRef) {
LLVMPositionBuilderAtEnd(builder, block) LLVMPositionBuilderAtEnd(builder, block)
basicBlockToLastLocation[block]?.let{ debugLocation(it) } basicBlockToLastLocation[block]?.let{ debugLocation(it.start, it.end) }
val lastInstr = LLVMGetLastInstruction(block) val lastInstr = LLVMGetLastInstruction(block)
isAfterTerminator = lastInstr != null && (LLVMIsATerminatorInst(lastInstr) != null) isAfterTerminator = lastInstr != null && (LLVMIsATerminatorInst(lastInstr) != null)
} }
@@ -467,7 +467,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private inner class LoopScope(val loop: IrLoop) : InnerScopeImpl() { private inner class LoopScope(val loop: IrLoop) : InnerScopeImpl() {
val loopExit = functionGenerationContext.basicBlock("loop_exit", loop.condition.startLocation) val loopExit = functionGenerationContext.basicBlock("loop_exit", loop.endLocation)
val loopCheck = functionGenerationContext.basicBlock("loop_check", loop.condition.startLocation) val loopCheck = functionGenerationContext.basicBlock("loop_check", loop.condition.startLocation)
override fun genBreak(destination: IrBreak) { override fun genBreak(destination: IrBreak) {
@@ -806,7 +806,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
functionGenerationContext.getObjectValue( functionGenerationContext.getObjectValue(
value.symbol.owner, value.symbol.owner,
currentCodeContext.exceptionHandler, currentCodeContext.exceptionHandler,
value.startLocation value.startLocation,
value.endLocation
) )
@@ -1052,7 +1053,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val needsPhi = isUnconditional(expression.branches.last()) && !expression.type.isUnit() val needsPhi = isUnconditional(expression.branches.last()) && !expression.type.isUnit()
val llvmType = codegen.getLLVMType(expression.type) val llvmType = codegen.getLLVMType(expression.type)
val bbExit = lazy { functionGenerationContext.basicBlock("when_exit", expression.startLocation) } val bbExit = lazy { functionGenerationContext.basicBlock("when_exit", expression.endLocation) }
val resultPhi = lazy { val resultPhi = lazy {
functionGenerationContext.appendingTo(bbExit.value) { functionGenerationContext.appendingTo(bbExit.value) {
@@ -1070,7 +1071,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val bbNext = if (it == expression.branches.last()) val bbNext = if (it == expression.branches.last())
null null
else else
functionGenerationContext.basicBlock("when_next", it.startLocation) functionGenerationContext.basicBlock("when_next", it.startLocation, it.endLocation)
generateWhenCase(whenEmittingContext, it, bbNext) generateWhenCase(whenEmittingContext, it, bbNext)
} }
@@ -1089,7 +1090,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val brResult = if (isUnconditional(branch)) val brResult = if (isUnconditional(branch))
evaluateExpression(branch.result) evaluateExpression(branch.result)
else { else {
val bbCase = functionGenerationContext.basicBlock("when_case", branch.startLocation) val bbCase = functionGenerationContext.basicBlock("when_case", branch.startLocation, branch.endLocation)
val condition = evaluateExpression(branch.condition) val condition = evaluateExpression(branch.condition)
functionGenerationContext.condBr(condition, bbCase, bbNext ?: whenEmittingContext.bbExit.value) functionGenerationContext.condBr(condition, bbCase, bbNext ?: whenEmittingContext.bbExit.value)
functionGenerationContext.positionAtEnd(bbCase) functionGenerationContext.positionAtEnd(bbCase)
@@ -1558,9 +1559,17 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
var bbExit : LLVMBasicBlockRef? = null var bbExit : LLVMBasicBlockRef? = null
var resultPhi : LLVMValueRef? = null var resultPhi : LLVMValueRef? = null
private val functionScope: DIScopeOpaqueRef?
get() = returnableBlock.inlineFunctionSymbol?.owner?.scope()
private val outerScope = currentCodeContext.scope()
private fun getExit(): LLVMBasicBlockRef { private fun getExit(): LLVMBasicBlockRef {
if (bbExit == null) bbExit = functionGenerationContext.basicBlock("returnable_block_exit", returnableBlock.startLocation) val location = returnableBlock.inlineFunctionSymbol?.let {
location(it.owner.endLine(), it.owner.endColumn())
} ?: returnableBlock.statements.lastOrNull()?.let {
location(it.endLine(), it.endColumn())
}
if (bbExit == null) bbExit = functionGenerationContext.basicBlock("returnable_block_exit", location)
return bbExit!! return bbExit!!
} }
@@ -1591,13 +1600,19 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
override fun location(line: Int, column: Int): LocationInfo? { override fun location(line: Int, column: Int): LocationInfo? {
return if (returnableBlock.inlineFunctionSymbol != null) { return if (returnableBlock.inlineFunctionSymbol != null) {
val diScope = returnableBlock.inlineFunctionSymbol?.owner?.scope() ?: return null val diScope = functionScope ?: return null
LocationInfo(diScope, line, column, outerContext.location(returnableBlock.startLine(), returnableBlock.endLine())) val outerFileEntry = outerFileEntry()
val inlinedAt = outerContext.location(outerFileEntry.line(returnableBlock.startOffset), outerFileEntry.column(returnableBlock.startOffset))
LocationInfo(diScope, line, column, inlinedAt)
} else { } else {
outerContext.location(line, column) outerContext.location(line, column)
} }
} }
private fun outerFileEntry() =
(outerContext.fileScope() as? FileScope)?.file?.fileEntry
?: error("returnable block should be inlined at some file")
/** /**
* Note: DILexicalBlocks aren't nested, they should be scoped with the parent function. * Note: DILexicalBlocks aren't nested, they should be scoped with the parent function.
@@ -1736,10 +1751,9 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun file() = (currentCodeContext.fileScope() as FileScope).file private fun file() = (currentCodeContext.fileScope() as FileScope).file
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private fun updateBuilderDebugLocation(element: IrElement): DILocationRef? { private fun updateBuilderDebugLocation(element: IrElement) {
if (!context.shouldContainDebugInfo() || currentCodeContext.functionScope() == null) return null if (!context.shouldContainDebugInfo() || currentCodeContext.functionScope() == null || element.startLocation == null) return
@Suppress("UNCHECKED_CAST") functionGenerationContext.debugLocation(element.startLocation!!, element.endLocation!!)
return element.startLocation?.let { functionGenerationContext.debugLocation(it) }
} }
private val IrElement.startLocation: LocationInfo? private val IrElement.startLocation: LocationInfo?
@@ -330,7 +330,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
functionType(kObjHeaderPtr, false, kObjHeaderPtrPtr), functionType(kObjHeaderPtr, false, kObjHeaderPtrPtr),
"" ""
) { ) {
ret(getObjectValue(value, ExceptionHandler.Caller, locationInfo = null)) ret(getObjectValue(value, ExceptionHandler.Caller, startLocationInfo = null))
} }
Struct(runtime.associatedObjectTableRecordType, key.typeInfoPtr, constPointer(associatedObjectGetter)) Struct(runtime.associatedObjectTableRecordType, key.typeInfoPtr, constPointer(associatedObjectGetter))
@@ -1148,7 +1148,7 @@ private fun ObjCExportCodeGenerator.createObjectInstanceAdapter(
return generateObjCToKotlinSyntheticGetter(selector) { return generateObjCToKotlinSyntheticGetter(selector) {
initRuntimeIfNeeded() // For instance methods it gets called when allocating. initRuntimeIfNeeded() // For instance methods it gets called when allocating.
val value = getObjectValue(irClass, locationInfo = null, exceptionHandler = ExceptionHandler.Caller) val value = getObjectValue(irClass, startLocationInfo = null, exceptionHandler = ExceptionHandler.Caller)
ret(kotlinToObjC(value, ReferenceBridge)) ret(kotlinToObjC(value, ReferenceBridge))
} }
} }