[codegen][DI][inline] generation debug info for inlined functions. (#1251)

- We use DILexicalBlock and DILexicalBlockFile for generation debug info for kotlin inline (macro substituion by nature).
-- Note: DILexicalBlock aren't nested in opposite to inline function in C meaning.
- Changed DICompileUnit generation practise, now it generated for each file.
- added DI LLVM bindings.
This commit is contained in:
Vasily Levchenko
2018-02-01 20:43:21 +03:00
committed by GitHub
parent a818be1281
commit 0236868012
4 changed files with 160 additions and 84 deletions
@@ -47,11 +47,10 @@ internal object DWARF {
}
internal class DebugInfo internal constructor(override val context: Context):ContextUtils {
val files = mutableMapOf<IrFile, DIFileRef>()
val subprograms = mutableMapOf<FunctionDescriptor, DISubprogramRef>()
val files = mutableMapOf<String, DIFileRef>()
val subprograms = mutableMapOf<LLVMValueRef, DISubprogramRef>()
var builder: DIBuilderRef? = null
var module: DIModuleRef? = null
var compilationModule: DICompileUnitRef? = null
var types = mutableMapOf<KotlinType, DITypeOpaqueRef>()
val llvmTypes = mapOf<KotlinType, LLVMTypeRef>(
@@ -110,15 +109,6 @@ internal fun generateDebugInfoHeader(context: Context) {
configurationMacro = "",
includePath = "",
iSysRoot = "")
context.debugInfo.compilationModule = DICreateCompilationUnit(
builder = context.debugInfo.builder,
lang = DwarfLanguage.DW_LANG_Kotlin.value,
File = path.file,
dir = path.folder,
producer = DWARF.producer,
isOptimized = 0,
flags = "",
rv = DWARF.runtimeVersion)
/* TODO: figure out what here 2 means:
*
* 0:b-backend-dwarf:minamoto@minamoto-osx(0)# cat /dev/null | clang -xc -S -emit-llvm -g -o - -
@@ -158,7 +148,8 @@ internal fun KotlinType.dwarfType(context:Context, targetData:LLVMTargetDataRef)
classDescriptor != null -> {
val type = DICreateStructType(
refBuilder = context.debugInfo.builder,
scope = context.debugInfo.compilationModule as DIScopeOpaqueRef,
// TODO: here should be DIFile as scope.
scope = null,
name = "ObjHeader",
file = null,
lineNumber = 0,
@@ -217,10 +208,15 @@ internal fun KotlinType.encoding(context:Context):DwarfTypeKind = when {
internal fun alignTo(value:Long, align:Long):Long = (value + align - 1) / align * align
internal fun FunctionDescriptor.subroutineType(context: Context, llvmTargetData: LLVMTargetDataRef): DISubroutineTypeRef {
val types = this@subroutineType.types
return subroutineType(context, llvmTargetData, types)
}
internal fun subroutineType(context: Context, llvmTargetData: LLVMTargetDataRef, types: List<KotlinType>): DISubroutineTypeRef {
return memScoped {
DICreateSubroutineType(context.debugInfo.builder, allocArrayOf(
this@subroutineType.types.map { it.diType(context, llvmTargetData) }),
this@subroutineType.types.size)!!
types.map { it.diType(context, llvmTargetData) }),
types.size)!!
}
}
@@ -209,6 +209,23 @@ internal interface CodeContext {
fun classScope(): CodeContext?
fun addResumePoint(bbLabel: LLVMBasicBlockRef): Int
/**
* Returns owning returnable block scope [ReturnableBlockScope].
*
* @returns the requested value if in the returnableBlockScope scope or null.
*/
fun returnableBlockScope(): CodeContext?
/**
* Returns location information for given source location [LocationInfo].
*/
fun location(line:Int, column: Int): LocationInfo?
/**
* Returns [DIScopeOpaqueRef] instance for corresponding scope.
*/
fun scope(): DIScopeOpaqueRef?
}
//-------------------------------------------------------------------------//
@@ -254,6 +271,12 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
override fun classScope(): CodeContext? = null
override fun addResumePoint(bbLabel: LLVMBasicBlockRef) = unsupported(bbLabel)
override fun returnableBlockScope(): CodeContext? = null
override fun location(line: Int, column: Int): LocationInfo? = unsupported()
override fun scope(): DIScopeOpaqueRef? = unsupported()
}
/**
@@ -319,7 +342,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun createInitBody(initName: String): LLVMValueRef {
val initFunction = LLVMAddFunction(context.llvmModule, initName, kInitFuncType)!! // create LLVM function
generateFunction(codegen, initFunction) {
using(FunctionScope(initFunction, it)) {
using(FunctionScope(initFunction, initName, it)) {
val bbInit = basicBlock("init", null)
val bbDeinit = basicBlock("deinit", null)
condBr(functionGenerationContext.icmpEq(LLVMGetParam(initFunction, 0)!!, kImmZero), bbDeinit, bbInit)
@@ -541,15 +564,17 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private inner class FunctionScope (val declaration: IrFunction?, val functionGenerationContext: FunctionGenerationContext) : InnerScopeImpl() {
constructor(llvmFunction:LLVMValueRef, functionGenerationContext: FunctionGenerationContext):this(null, functionGenerationContext) {
constructor(llvmFunction:LLVMValueRef, name:String, functionGenerationContext: FunctionGenerationContext):this(null, functionGenerationContext) {
this.llvmFunction = llvmFunction
this.name = name
}
var llvmFunction:LLVMValueRef? = declaration?.let{
codegen.llvmFunction(declaration.descriptor)
}
private var name:String? = declaration?.descriptor?.name?.asString()
override fun genReturn(target: CallableDescriptor, value: LLVMValueRef?) {
if (declaration == null || target == declaration.descriptor) {
if (target.returnsUnit()) {
@@ -576,6 +601,17 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
override fun functionScope(): CodeContext = this
private val scope by lazy {
if (!context.shouldContainDebugInfo())
return@lazy null
declaration?.scope() ?: llvmFunction!!.scope(0, subroutineType(context, codegen.llvmTargetData, listOf(context.builtIns.intType)))
}
override fun location(line: Int, column: Int) = scope?.let { LocationInfo(it, line, column) }
override fun scope() = scope
}
private val functionGenerationContext
@@ -601,17 +637,9 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
if (declaration.descriptor.isExternal) return
if (body == null) return
val scope = declaration.scope()
val startLine = declaration.startLine()
val startLocationInfo = LocationInfo(
scope = scope,
line = startLine,
column = declaration.startColumn())
val endLocationInfo = LocationInfo(
scope = scope,
line = declaration.endLine(),
column = declaration.endColumn())
generateFunction(codegen, declaration.descriptor, startLocationInfo, endLocationInfo) {
generateFunction(codegen, declaration.descriptor,
declaration.location(declaration.startLine(), declaration.startColumn()),
declaration.location(declaration.endLine(), declaration.endColumn())) {
using(FunctionScope(declaration, it)) {
val parameterScope = ParameterScope(declaration, functionGenerationContext)
using(parameterScope) {
@@ -637,6 +665,13 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
"${declaration.descriptor.containingDeclaration}::${ir2string(declaration)}")
}
private fun IrFunction.location(line: Int, column:Int) =
if (context.shouldContainDebugInfo()) LocationInfo(
scope = scope()!!,
line = line,
column = column)
else null
//-------------------------------------------------------------------------//
override fun visitClass(declaration: IrClass) {
@@ -863,13 +898,12 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
}
private inline fun endLocationInfoFromScope(): LocationInfo? {
private fun endLocationInfoFromScope(): LocationInfo? {
val functionScope = currentCodeContext.functionScope()
val irFunction = functionScope?.let {
(functionScope as FunctionScope).declaration
}
val locationInfo = irFunction?.endLocation
return locationInfo
return irFunction?.endLocation
}
private fun jumpToHandler(exception: LLVMValueRef) {
@@ -1106,16 +1140,14 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------//
private fun debugInfoIfNeeded(function: IrFunction?, element: IrElement): VariableDebugLocation? {
if (function == null || element.startLocation == null || !context.shouldContainDebugInfo()) return null
val functionScope = function.scope()
if (functionScope == null || !element.needDebugInfo(context)) return null
val locationInfo = element.startLocation!!
if (function == null || !element.needDebugInfo(context) || currentCodeContext.scope() == null) return null
val locationInfo = element.startLocation ?: return null
val location = codegen.generateLocationInfo(locationInfo)
val file = (currentCodeContext.fileScope() as FileScope).file.file()
return when (element) {
is IrVariable -> debugInfoLocalVariableLocation(
builder = context.debugInfo.builder,
functionScope = functionScope,
functionScope = locationInfo.scope,
diType = element.descriptor.type.diType(context, codegen.llvmTargetData),
name = element.descriptor.name,
file = file,
@@ -1123,7 +1155,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
location = location)
is IrValueParameter -> debugInfoParameterLocation(
builder = context.debugInfo.builder,
functionScope = functionScope,
functionScope = locationInfo.scope,
diType = element.descriptor.type.diType(context, codegen.llvmTargetData),
name = element.descriptor.name,
argNo = (element.descriptor as? ValueParameterDescriptor)?.index ?: 0,
@@ -1413,7 +1445,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
NaiveSourceBasedFileEntryImpl(sourceFileName)
}
private inner class ReturnableBlockScope(val returnableBlock: IrReturnableBlockImpl) :
private inner class ReturnableBlockScope(val returnableBlock: IrReturnableBlock) :
FileScope(IrFileImpl(getFileEntry(returnableBlock.sourceFileName))) {
var bbExit : LLVMBasicBlockRef? = null
@@ -1446,12 +1478,39 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
functionGenerationContext.assignPhis(getResult() to value!!) // Assign return value to result PHI node.
}
}
override fun returnableBlockScope(): CodeContext? = this
/**
* Note: DILexicalBlocks aren't nested, they should be scoped with the parent function.
*/
private val scope by lazy {
if (!context.shouldContainDebugInfo())
return@lazy null
val lexicalBlockFile = DICreateLexicalBlockFile(context.debugInfo.builder, functionScope()!!.scope(), super.file.file())
DICreateLexicalBlock(context.debugInfo.builder, lexicalBlockFile, super.file.file(), returnableBlock.startLine(), returnableBlock.startColumn())!!
}
override fun scope() = scope
}
//-------------------------------------------------------------------------//
private open inner class FileScope(val file:IrFile) : InnerScopeImpl() {
override fun fileScope(): CodeContext? = this
override fun location(line: Int, column: Int) = scope()?.let {LocationInfo(it, line, column) }
@Suppress("UNCHECKED_CAST")
private val scope by lazy {
if (!context.shouldContainDebugInfo())
return@lazy null
file.file() as DIScopeOpaqueRef?
}
override fun scope() = scope
}
//-------------------------------------------------------------------------//
@@ -1466,7 +1525,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
DICreateReplaceableCompositeType(
tag = DwarfTag.DW_TAG_structure_type.value,
refBuilder = context.debugInfo.builder,
refScope = context.debugInfo.compilationModule as DIScopeOpaqueRef,
refScope = (currentCodeContext.fileScope() as FileScope)!!.file.file() as DIScopeOpaqueRef,
name = clazz.descriptor.typeInfoSymbolName,
refFile = file().file(),
line = clazz.startLine()) as DITypeOpaqueRef
@@ -1476,7 +1535,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------//
private fun evaluateReturnableBlock(value: IrReturnableBlockImpl): LLVMValueRef {
private fun evaluateReturnableBlock(value: IrReturnableBlock): LLVMValueRef {
context.log{"evaluateReturnableBlock : ${value.statements.forEach { ir2string(it) }}"}
val returnableBlockScope = ReturnableBlockScope(value)
@@ -1635,28 +1694,17 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun file() = (currentCodeContext.fileScope() as FileScope).file
//-------------------------------------------------------------------------//
private fun updateBuilderDebugLocation(element: IrElement?):DILocationRef? {
if (!context.shouldContainDebugInfo() || element == null) return null
private fun updateBuilderDebugLocation(element: IrElement):DILocationRef? {
if (!context.shouldContainDebugInfo() || currentCodeContext.functionScope() == null) return null
@Suppress("UNCHECKED_CAST")
return element.startLocation?.let{functionGenerationContext.debugLocation(it)}
}
private val IrElement.startLocation: LocationInfo?
get() = location(startLine(), startColumn())
get() = currentCodeContext.location(startLine(), startColumn())
private val IrElement.endLocation: LocationInfo?
get() = location(endLine(), endColumn())
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)
}
get() = currentCodeContext.location(endLine(), endColumn())
//-------------------------------------------------------------------------//
private fun IrElement.startLine() = file().fileEntry.line(this.startOffset)
@@ -1697,37 +1745,60 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------//
private fun IrFile.file(): DIFileRef {
return context.debugInfo.files.getOrPut(this) {
return context.debugInfo.files.getOrPut(this.fileEntry.name) {
val path = this.fileEntry.name.toFileAndFolder()
DICreateCompilationUnit(
builder = context.debugInfo.builder,
lang = DwarfLanguage.DW_LANG_Kotlin.value,
File = path.file,
dir = path.folder,
producer = DWARF.producer,
isOptimized = 0,
flags = "",
rv = DWARF.runtimeVersion)
DICreateFile(context.debugInfo.builder, path.file, path.folder)!!
}
}
//-------------------------------------------------------------------------//
private fun IrFunction.scope():DIScopeOpaqueRef? = descriptor.scope(startLine())
@Suppress("UNCHECKED_CAST")
private fun IrFunction.scope():DIScopeOpaqueRef? {
if (!context.shouldContainDebugInfo()) return null
return context.debugInfo.subprograms.getOrPut(descriptor) {
private fun FunctionDescriptor.scope(startLine:Int): DIScopeOpaqueRef? {
if (codegen.isExternal(this) || !context.shouldContainDebugInfo())
return null
return context.debugInfo.subprograms.getOrPut(codegen.llvmFunction(this)) {
memScoped {
val subroutineType = descriptor.subroutineType(context, codegen.llvmTargetData)
val functionLlvmValue = codegen.functionLlvmValue(descriptor)
val linkageName = LLVMGetValueName(functionLlvmValue)!!.toKString()
val diFunction = DICreateFunction(
builder = context.debugInfo.builder,
scope = context.debugInfo.compilationModule as DIScopeOpaqueRef,
name = descriptor.name.asString(),
linkageName = linkageName,
file = file().file(),
lineNo = startLine(),
type = subroutineType,
//TODO: need more investigations.
isLocal = 0,
isDefinition = 1,
scopeLine = 0)
DIFunctionAddSubprogram(functionLlvmValue , diFunction)
diFunction!!
val subroutineType = subroutineType(context, codegen.llvmTargetData)
val functionLlvmValue = codegen.llvmFunction(this@scope)
diFunctionScope(name.asString(), functionLlvmValue.name!!, startLine, subroutineType, functionLlvmValue)
}
} as DIScopeOpaqueRef
} as DIScopeOpaqueRef
}
@Suppress("UNCHECKED_CAST")
private fun LLVMValueRef.scope(startLine:Int, subroutineType: DISubroutineTypeRef): DIScopeOpaqueRef? {
return context.debugInfo.subprograms.getOrPut(this) {
diFunctionScope(name!!, name!!, startLine, subroutineType, this)
} as DIScopeOpaqueRef
}
private fun diFunctionScope(name: String, linkageName: String, startLine: Int, subroutineType: DISubroutineTypeRef, functionLlvmValue: LLVMValueRef): DISubprogramRef {
@Suppress("UNCHECKED_CAST")
val diFunction = DICreateFunction(
builder = context.debugInfo.builder,
scope = (currentCodeContext.fileScope() as FileScope).file.file() as DIScopeOpaqueRef,
name = name,
linkageName = linkageName,
file = file().file(),
lineNo = startLine,
type = subroutineType,
//TODO: need more investigations.
isLocal = 0,
isDefinition = 1,
scopeLine = 0)
DIFunctionAddSubprogram(functionLlvmValue, diFunction)
return diFunction!!
}
//-------------------------------------------------------------------------//
@@ -2434,6 +2505,6 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
}
internal data class LocationInfo(val scope:DIScopeOpaqueRef?,
internal data class LocationInfo(val scope:DIScopeOpaqueRef,
val line:Int,
val column:Int)
val column:Int)
+9 -3
View File
@@ -22,8 +22,6 @@
#include <llvm/IR/Instruction.h>
#include <llvm/Support/Casting.h>
#include "DebugInfoC.h"
/**
* c++ --std=c++11 llvmDebugInfoC/src/DebugInfoC.cpp -IllvmDebugInfoC/include/ -Idependencies/all/clang+llvm-3.9.0-darwin-macos/include -Ldependencies/all/clang+llvm-3.9.0-darwin-macos/lib -lLLVMCore -lLLVMSupport -lncurses -shared -o libLLVMDebugInfoC.dylib
*/
@@ -102,6 +100,15 @@ DISubprogramRef DICreateFunction(DIBuilderRef builder, DIScopeOpaqueRef scope,
scopeLine));
}
DIScopeOpaqueRef DICreateLexicalBlockFile(DIBuilderRef builderRef, DIScopeOpaqueRef scopeRef, DIFileRef fileRef) {
return llvm::wrap(llvm::unwrap(builderRef)->createLexicalBlockFile(llvm::unwrap(scopeRef), llvm::unwrap(fileRef)));
}
DIScopeOpaqueRef DICreateLexicalBlock(DIBuilderRef builderRef, DIScopeOpaqueRef scopeRef, DIFileRef fileRef, int line, int column) {
return llvm::wrap(llvm::unwrap(builderRef)->createLexicalBlock(llvm::unwrap(scopeRef), llvm::unwrap(fileRef), line, column));
}
DICompositeTypeRef DICreateStructType(DIBuilderRef refBuilder,
DIScopeOpaqueRef scope, const char *name,
DIFileRef file, unsigned lineNumber,
@@ -277,6 +284,5 @@ const char *DIGetSubprogramLinkName(DISubprogramRef sp) {
int DISubprogramDescribesFunction(DISubprogramRef sp, LLVMValueRef fn) {
return llvm::unwrap(sp)->describes(llvm::cast<llvm::Function>(llvm::unwrap(fn)));
}
} /* extern "C" */
+4 -1
View File
@@ -84,6 +84,10 @@ DIModuleRef DICreateModule(DIBuilderRef builder, DIScopeOpaqueRef scope,
const char* name, const char* configurationMacro,
const char* includePath, const char *iSysRoot);
DIScopeOpaqueRef DICreateLexicalBlockFile(DIBuilderRef builderRef, DIScopeOpaqueRef scopeRef, DIFileRef fileRef);
DIScopeOpaqueRef DICreateLexicalBlock(DIBuilderRef builderRef, DIScopeOpaqueRef scopeRef, DIFileRef fileRef, int line, int column);
DISubprogramRef DICreateFunction(DIBuilderRef builder, DIScopeOpaqueRef scope,
const char* name, const char *linkageName,
DIFileRef file, unsigned lineNo,
@@ -107,7 +111,6 @@ const char* LLVMBuilderGetCurrentBbName(LLVMBuilderRef builder);
const char *DIGetSubprogramLinkName(DISubprogramRef sp);
LLVMValueRef LLVMBuilderGetCurrentFunction(LLVMBuilderRef builder);
int DISubprogramDescribesFunction(DISubprogramRef sp, LLVMValueRef fn);
//void DIScopeDump(DIScopeOpaqueRef scope);
# ifdef __cplusplus
}
# endif