[K/N][codegen] Refactored debug info building

This commit is contained in:
Igor Chevdar
2022-08-25 07:59:15 +03:00
committed by Space Team
parent 9b63dde1c3
commit 05016596df
5 changed files with 223 additions and 249 deletions
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.backend.konan
import llvm.*
import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.backend.konan.llvm.DWARF
import org.jetbrains.kotlin.backend.konan.llvm.DebugInfo
import org.jetbrains.kotlin.backend.konan.llvm.Llvm
import org.jetbrains.kotlin.backend.konan.llvm.LlvmDeclarations
@@ -23,7 +22,6 @@ import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.konan.TempFiles
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.utils.addToStdlib.cast
internal class InlineFunctionOriginInfo(val irFunction: IrFunction, val irFile: IrFile, val startOffset: Int, val endOffset: Int)
@@ -64,25 +62,7 @@ internal class NativeGenerationState(private val context: Context) {
private val runtimeDelegate = lazy { Runtime(config.distribution.compilerInterface(config.target)) }
private val llvmDelegate = lazy { Llvm(context, LLVMModuleCreateWithNameInContext("out", llvmContext)!!) }
private val debugInfoDelegate = lazy {
DebugInfo(context).also {
it.builder = LLVMCreateDIBuilder(llvm.module)
// we don't split path to filename and directory to provide enough level uniquely for dsymutil to avoid symbol
// clashing, which happens on linking with libraries produced from intercepting sources.
val filePath = outputFile.toFileAndFolder(context).path()
it.compilationUnit = if (context.shouldContainLocationDebugInfo()) DICreateCompilationUnit(
builder = it.builder,
lang = DWARF.language(config),
File = filePath,
dir = "",
producer = DWARF.producer,
isOptimized = 0,
flags = "",
rv = DWARF.runtimeVersion(config)
).cast()
else null
}
}
private val debugInfoDelegate = lazy { DebugInfo(context) }
val llvmImports = Llvm.ImportsImpl(context)
val runtime by runtimeDelegate
@@ -91,6 +71,8 @@ internal class NativeGenerationState(private val context: Context) {
val cStubsManager = CStubsManager(config.target)
lateinit var llvmDeclarations: LlvmDeclarations
fun hasDebugInfo() = debugInfoDelegate.isInitialized()
fun verifyBitCode() {
if (!llvmDelegate.isInitialized()) return
verifyModule(llvm.module)
@@ -106,7 +88,7 @@ internal class NativeGenerationState(private val context: Context) {
fun dispose() {
if (isDisposed) return
if (debugInfoDelegate.isInitialized()) {
if (hasDebugInfo()) {
LLVMDisposeDIBuilder(debugInfo.builder)
}
if (llvmDelegate.isInitialized()) {
@@ -406,10 +406,8 @@ internal val bitcodePhase = NamedCompilerPhase(
createLLVMDeclarationsPhase then
ghaPhase then
RTTIPhase then
generateDebugInfoHeaderPhase then
escapeAnalysisPhase then
codegenPhase then
finalizeDebugInfoPhase then
cStubsPhase
)
@@ -544,10 +542,6 @@ internal fun PhaseConfig.konanPhasesConfig(config: KonanConfig) {
disableUnless(rewriteExternalCallsCheckerGlobals, getBoolean(KonanConfigKeys.CHECK_EXTERNAL_CALLS))
disableUnless(stringConcatenationTypeNarrowingPhase, config.optimizationsEnabled)
disableUnless(optimizeTLSDataLoadsPhase, config.optimizationsEnabled)
if (!config.debug && !config.lightDebug) {
disable(generateDebugInfoHeaderPhase)
disable(finalizeDebugInfoPhase)
}
if (!config.involvesLinkStage) {
disable(bitcodePostprocessingPhase)
disable(linkBitcodeDependenciesPhase)
@@ -40,12 +40,6 @@ internal val RTTIPhase = makeKonanModuleOpPhase(
}
)
internal val generateDebugInfoHeaderPhase = makeKonanModuleOpPhase(
name = "GenerateDebugInfoHeader",
description = "Generate debug info header",
op = { context, _ -> generateDebugInfoHeader(context) }
)
internal val buildDFGPhase = makeKonanModuleOpPhase(
name = "BuildDFG",
description = "Data flow graph building",
@@ -253,13 +247,12 @@ internal val escapeAnalysisPhase = makeKonanModuleOpPhase(
internal val codegenPhase = makeKonanModuleOpPhase(
name = "Codegen",
description = "Code generation",
op = { context, irModule -> irModule.acceptVoid(CodeGeneratorVisitor(context, context.lifetimes)) }
)
op = { context, irModule ->
irModule.acceptVoid(CodeGeneratorVisitor(context, context.lifetimes))
internal val finalizeDebugInfoPhase = makeKonanModuleOpPhase(
name = "FinalizeDebugInfo",
description = "Finalize debug info",
op = { context, _ -> DIFinalize(context.generationState.debugInfo.builder) }
if (context.generationState.hasDebugInfo())
DIFinalize(context.generationState.debugInfo.builder)
}
)
internal val cStubsPhase = makeKonanModuleOpPhase(
@@ -22,14 +22,15 @@ import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.konan.CURRENT
import org.jetbrains.kotlin.konan.CompilerVersion
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.utils.addToStdlib.cast
internal object DWARF {
val producer = "konanc ${CompilerVersion.CURRENT} / kotlin-compiler: ${KotlinVersion.CURRENT}"
val producer = "konanc ${CompilerVersion.CURRENT} / kotlin-compiler: ${KotlinVersion.CURRENT}"
/* TODO: from LLVM sources is unclear what runtimeVersion corresponds to term in terms of dwarf specification. */
val dwarfVersionMetaDataNodeName get() = "Dwarf Version".mdString()
val dwarfVersionMetaDataNodeName get() = "Dwarf Version".mdString()
val dwarfDebugInfoMetaDataNodeName get() = "Debug Info Version".mdString()
const val debugInfoVersion = 3 /* TODO: configurable? */
/**
* This is the value taken from [DIFlags.FlagFwdDecl], to mark type declaration as
* forward one.
@@ -46,7 +47,7 @@ internal object DWARF {
* Note: Kotlin language constant appears in DWARF v6, while modern linker fails to links DWARF other then [2;4],
* that why we emit version 4 actually.
*/
fun dwarfVersion(config : KonanConfig) = when (config.debugInfoVersion()) {
fun dwarfVersion(config: KonanConfig) = when (config.debugInfoVersion()) {
1 -> 2
2 -> 4 /* likely the most of the future kotlin native debug info format versions will emit DWARF v4 */
else -> TODO("unsupported debug info format version")
@@ -58,37 +59,170 @@ internal object DWARF {
}
}
fun KonanConfig.debugInfoVersion():Int = configuration[KonanConfigKeys.DEBUG_INFO_VERSION] ?: 1
fun KonanConfig.debugInfoVersion(): Int = configuration[KonanConfigKeys.DEBUG_INFO_VERSION] ?: 1
internal class DebugInfo(override val context: Context) : ContextUtils {
private val config = context.config
val builder: DIBuilderRef = LLVMCreateDIBuilder(llvm.module)!!
val compilationUnit: DIScopeOpaqueRef
val module: DIModuleRef
val objHeaderPointerType: DITypeOpaqueRef
init {
val path = context.generationState.outputFile.toFileAndFolder(config)
compilationUnit = DICreateCompilationUnit(
builder = builder,
lang = DWARF.language(config),
// we don't split path to filename and directory to provide enough level uniquely for dsymutil to avoid symbol
// clashing, which happens on linking with libraries produced from intercepting sources.
File = path.path(),
dir = "",
producer = DWARF.producer,
isOptimized = 0,
flags = "",
rv = DWARF.runtimeVersion(config)
)!!.reinterpret()
module = DICreateModule(
builder = builder,
scope = null,
name = path.path(),
configurationMacro = "",
includePath = "",
iSysRoot = "")!!
/* 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 - -
* ; ModuleID = '-'
* source_filename = "-"
* target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
* target triple = "x86_64-apple-macosx10.12.0"
*
* !llvm.dbg.cu = !{!0}
* !llvm.module.flags = !{!3, !4, !5}
* !llvm.ident = !{!6}
*
* !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "Apple LLVM version 8.0.0 (clang-800.0.38)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
* !1 = !DIFile(filename: "-", directory: "/Users/minamoto/ws/.git-trees/backend-dwarf")
* !2 = !{}
* !3 = !{i32 2, !"Dwarf Version", i32 2} ; <-
* !4 = !{i32 2, !"Debug Info Version", i32 700000003} ; <-
* !5 = !{i32 1, !"PIC Level", i32 2}
* !6 = !{!"Apple LLVM version 8.0.0 (clang-800.0.38)"}
*/
val llvmTwo = Int32(2).llvm
val dwarfVersion = node(llvmTwo, DWARF.dwarfVersionMetaDataNodeName, Int32(DWARF.dwarfVersion(config)).llvm)
val nodeDebugInfoVersion = node(llvmTwo, DWARF.dwarfDebugInfoMetaDataNodeName, Int32(DWARF.debugInfoVersion).llvm)
val llvmModuleFlags = "llvm.module.flags"
LLVMAddNamedMetadataOperand(llvm.module, llvmModuleFlags, dwarfVersion)
LLVMAddNamedMetadataOperand(llvm.module, llvmModuleFlags, nodeDebugInfoVersion)
val objHeaderType: DITypeOpaqueRef = DICreateStructType(
refBuilder = builder,
// TODO: here should be DIFile as scope.
scope = null,
name = "ObjHeader",
file = null,
lineNumber = 0,
sizeInBits = 0,
alignInBits = 0,
flags = DWARF.flagsForwardDeclaration,
derivedFrom = null,
elements = null,
elementsCount = 0,
refPlace = null
)!!.reinterpret()
objHeaderPointerType = dwarfPointerType(objHeaderType)
}
internal class DebugInfo internal constructor(override val context: Context):ContextUtils {
val files = mutableMapOf<String, DIFileRef>()
val subprograms = mutableMapOf<LLVMValueRef, DISubprogramRef>()
/* Some functions are inlined on all callsites and body is eliminated by DCE, so there's no LLVM value */
val inlinedSubprograms = mutableMapOf<IrFunction, DISubprogramRef>()
var builder: DIBuilderRef? = null
var module: DIModuleRef? = null
var compilationUnit: DIScopeOpaqueRef? = null
var objHeaderPointerType: DITypeOpaqueRef? = null
var types = mutableMapOf<IrType, DITypeOpaqueRef>()
val types = mutableMapOf<IrType, DITypeOpaqueRef>()
val llvmTypes = mapOf<IrType, LLVMTypeRef>(
private val llvmTypes = mapOf(
context.irBuiltIns.booleanType to llvm.llvmInt8,
context.irBuiltIns.byteType to llvm.llvmInt8,
context.irBuiltIns.charType to llvm.llvmInt16,
context.irBuiltIns.shortType to llvm.llvmInt16,
context.irBuiltIns.intType to llvm.llvmInt32,
context.irBuiltIns.longType to llvm.llvmInt64,
context.irBuiltIns.floatType to llvm.llvmFloat,
context.irBuiltIns.doubleType to llvm.llvmDouble)
val llvmTypeSizes = llvmTypes.map { it.key to LLVMSizeOfTypeInBits(llvmTargetData, it.value) }.toMap()
val llvmTypeAlignments = llvmTypes.map {it.key to LLVMPreferredAlignmentOfType(llvmTargetData, it.value)}.toMap()
val otherLlvmType = LLVMPointerType(int64Type, 0)!!
val otherTypeSize = LLVMSizeOfTypeInBits(llvmTargetData, otherLlvmType)
val otherTypeAlignment = LLVMPreferredAlignmentOfType(llvmTargetData, otherLlvmType)
context.irBuiltIns.byteType to llvm.llvmInt8,
context.irBuiltIns.charType to llvm.llvmInt16,
context.irBuiltIns.shortType to llvm.llvmInt16,
context.irBuiltIns.intType to llvm.llvmInt32,
context.irBuiltIns.longType to llvm.llvmInt64,
context.irBuiltIns.floatType to llvm.llvmFloat,
context.irBuiltIns.doubleType to llvm.llvmDouble)
private val llvmTypeSizes = llvmTypes.map { it.key to LLVMSizeOfTypeInBits(llvmTargetData, it.value) }.toMap()
private val llvmTypeAlignments = llvmTypes.map { it.key to LLVMPreferredAlignmentOfType(llvmTargetData, it.value) }.toMap()
private val otherLlvmType = LLVMPointerType(int64Type, 0)!!
private val otherTypeSize = LLVMSizeOfTypeInBits(llvmTargetData, otherLlvmType)
private val otherTypeAlignment = LLVMPreferredAlignmentOfType(llvmTargetData, otherLlvmType)
val compilerGeneratedFile by lazy {
DICreateFile(builder, "<compiler-generated>", "")!!
val compilerGeneratedFile by lazy { DICreateFile(builder, "<compiler-generated>", "")!! }
val IrType.size: Long
get() = llvmTypeSizes.getOrDefault(this, otherTypeSize)
val IrType.alignment: Long
get() = llvmTypeAlignments.getOrDefault(this, otherTypeAlignment).toLong()
fun IrType.diType(llvmTargetData: LLVMTargetDataRef): DITypeOpaqueRef =
types.getOrPut(this) { dwarfType(llvmTargetData) }
fun IrFunction.subroutineType(llvmTargetData: LLVMTargetDataRef): DISubroutineTypeRef =
subroutineType(llvmTargetData, this@subroutineType.types)
fun subroutineType(llvmTargetData: LLVMTargetDataRef, types: List<IrType>): DISubroutineTypeRef = memScoped {
DICreateSubroutineType(builder, allocArrayOf(types.map { it.diType(llvmTargetData) }), types.size)!!
}
private fun dwarfPointerType(type: DITypeOpaqueRef): DITypeOpaqueRef =
DICreatePointerType(builder, type)!!.reinterpret()
private fun IrType.dwarfType(targetData: LLVMTargetDataRef) = when {
this.computePrimitiveBinaryTypeOrNull() != null ->
debugInfoBaseType(targetData, render(), llvmType(), encoding().value.toInt())
classOrNull != null || isTypeParameter() -> objHeaderPointerType
else -> TODO("$this: Does this case really exist?")
}
private fun debugInfoBaseType(targetData: LLVMTargetDataRef, typeName: String, type: LLVMTypeRef, encoding: Int): DITypeOpaqueRef =
DICreateBasicType(
builder, typeName,
LLVMSizeOfTypeInBits(targetData, type),
LLVMPreferredAlignmentOfType(targetData, type).toLong(), encoding
)!!.reinterpret()
private fun IrType.llvmType(): LLVMTypeRef = llvmTypes.getOrElse(this@llvmType) {
when (computePrimitiveBinaryTypeOrNull()) {
PrimitiveBinaryType.BOOLEAN -> llvm.llvmInt1
PrimitiveBinaryType.BYTE -> llvm.llvmInt8
PrimitiveBinaryType.SHORT -> llvm.llvmInt16
PrimitiveBinaryType.INT -> llvm.llvmInt32
PrimitiveBinaryType.LONG -> llvm.llvmInt64
PrimitiveBinaryType.FLOAT -> llvm.llvmFloat
PrimitiveBinaryType.DOUBLE -> llvm.llvmDouble
PrimitiveBinaryType.VECTOR128 -> llvm.llvmVector128
else -> otherLlvmType
}
}
private fun IrType.encoding(): DwarfTypeKind = when (computePrimitiveBinaryTypeOrNull()) {
PrimitiveBinaryType.FLOAT -> DwarfTypeKind.DW_ATE_float
PrimitiveBinaryType.DOUBLE -> DwarfTypeKind.DW_ATE_float
PrimitiveBinaryType.BOOLEAN -> DwarfTypeKind.DW_ATE_boolean
PrimitiveBinaryType.POINTER -> DwarfTypeKind.DW_ATE_address
else -> {
//TODO: not recursive.
if (this.isUnsigned()) DwarfTypeKind.DW_ATE_unsigned
else DwarfTypeKind.DW_ATE_signed
}
}
private val IrFunction.types: List<IrType>
get() {
val parameters = valueParameters.map { it.type }
return listOf(returnType, *parameters.toTypedArray())
}
}
/**
@@ -111,178 +245,45 @@ internal fun IrFileEntry.column(offset: Int) = location(offset, this::getColumnN
internal data class FileAndFolder(val file: String, val folder: String) {
companion object {
val NOFILE = FileAndFolder("-", "")
val NOFILE = FileAndFolder("-", "")
}
fun path() = if (this == NOFILE) file else "$folder/$file"
}
internal fun String?.toFileAndFolder(context: Context):FileAndFolder {
internal fun String?.toFileAndFolder(config: KonanConfig): FileAndFolder {
this ?: return FileAndFolder.NOFILE
val file = File(this).absoluteFile
var parent = file.parent
context.configuration.get(KonanConfigKeys.DEBUG_PREFIX_MAP)?.let { debugPrefixMap ->
for ((key, value) in debugPrefixMap) {
if (parent.startsWith(key)) {
parent = value + parent.removePrefix(key)
config.configuration.get(KonanConfigKeys.DEBUG_PREFIX_MAP)?.let { debugPrefixMap ->
for ((key, value) in debugPrefixMap) {
if (parent.startsWith(key)) {
parent = value + parent.removePrefix(key)
}
}
}
}
return FileAndFolder(file.name, parent)
}
internal fun generateDebugInfoHeader(context: Context) {
val debugInfo = context.generationState.debugInfo
val module = context.generationState.llvm.module
val path = context.generationState.outputFile.toFileAndFolder(context)
@Suppress("UNCHECKED_CAST")
debugInfo.module = DICreateModule(
builder = debugInfo.builder,
scope = null,
name = path.path(),
configurationMacro = "",
includePath = "",
iSysRoot = "")
/* 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 - -
* ; ModuleID = '-'
* source_filename = "-"
* target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
* target triple = "x86_64-apple-macosx10.12.0"
*
* !llvm.dbg.cu = !{!0}
* !llvm.module.flags = !{!3, !4, !5}
* !llvm.ident = !{!6}
*
* !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "Apple LLVM version 8.0.0 (clang-800.0.38)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
* !1 = !DIFile(filename: "-", directory: "/Users/minamoto/ws/.git-trees/backend-dwarf")
* !2 = !{}
* !3 = !{i32 2, !"Dwarf Version", i32 2} ; <-
* !4 = !{i32 2, !"Debug Info Version", i32 700000003} ; <-
* !5 = !{i32 1, !"PIC Level", i32 2}
* !6 = !{!"Apple LLVM version 8.0.0 (clang-800.0.38)"}
*/
val llvmTwo = Int32(2).llvm
val dwarfVersion = node(llvmTwo, DWARF.dwarfVersionMetaDataNodeName, Int32(DWARF.dwarfVersion(context.config)).llvm)
val nodeDebugInfoVersion = node(llvmTwo, DWARF.dwarfDebugInfoMetaDataNodeName, Int32(DWARF.debugInfoVersion).llvm)
val llvmModuleFlags = "llvm.module.flags"
LLVMAddNamedMetadataOperand(module, llvmModuleFlags, dwarfVersion)
LLVMAddNamedMetadataOperand(module, llvmModuleFlags, nodeDebugInfoVersion)
val objHeaderType = DICreateStructType(
refBuilder = debugInfo.builder,
// TODO: here should be DIFile as scope.
scope = null,
name = "ObjHeader",
file = null,
lineNumber = 0,
sizeInBits = 0,
alignInBits = 0,
flags = DWARF.flagsForwardDeclaration,
derivedFrom = null,
elements = null,
elementsCount = 0,
refPlace = null).cast<DITypeOpaqueRef>()
debugInfo.objHeaderPointerType = dwarfPointerType(context, objHeaderType)
}
@Suppress("UNCHECKED_CAST")
internal fun IrType.dwarfType(context: Context, targetData: LLVMTargetDataRef): DITypeOpaqueRef {
when {
this.computePrimitiveBinaryTypeOrNull() != null -> return debugInfoBaseType(context, targetData, this.render(), llvmType(context), encoding().value.toInt())
else -> {
return when {
classOrNull != null || this.isTypeParameter() -> context.generationState.debugInfo.objHeaderPointerType!!
else -> TODO("$this: Does this case really exist?")
}
}
}
}
internal fun IrType.diType(context: Context, llvmTargetData: LLVMTargetDataRef): DITypeOpaqueRef =
context.generationState.debugInfo.types.getOrPut(this) {
dwarfType(context, llvmTargetData)
}
@Suppress("UNCHECKED_CAST")
private fun debugInfoBaseType(context:Context, targetData:LLVMTargetDataRef, typeName:String, type:LLVMTypeRef, encoding:Int) = DICreateBasicType(
context.generationState.debugInfo.builder, typeName,
LLVMSizeOfTypeInBits(targetData, type),
LLVMPreferredAlignmentOfType(targetData, type).toLong(), encoding) as DITypeOpaqueRef
internal val IrFunction.types:List<IrType>
get() {
val parameters = valueParameters.map { it.type }
return listOf(returnType, *parameters.toTypedArray())
}
internal fun IrType.size(context:Context) = context.generationState.debugInfo.llvmTypeSizes.getOrDefault(this, context.generationState.debugInfo.otherTypeSize)
internal fun IrType.alignment(context:Context) = context.generationState.debugInfo.llvmTypeAlignments.getOrDefault(this, context.generationState.debugInfo.otherTypeAlignment).toLong()
internal fun IrType.llvmType(context:Context): LLVMTypeRef = with(context.generationState) {
debugInfo.llvmTypes.getOrElse(this@llvmType) {
when(computePrimitiveBinaryTypeOrNull()) {
PrimitiveBinaryType.BOOLEAN -> llvm.llvmInt1
PrimitiveBinaryType.BYTE -> llvm.llvmInt8
PrimitiveBinaryType.SHORT -> llvm.llvmInt16
PrimitiveBinaryType.INT -> llvm.llvmInt32
PrimitiveBinaryType.LONG -> llvm.llvmInt64
PrimitiveBinaryType.FLOAT -> llvm.llvmFloat
PrimitiveBinaryType.DOUBLE -> llvm.llvmDouble
PrimitiveBinaryType.VECTOR128 -> llvm.llvmVector128
else -> debugInfo.otherLlvmType
}
}
}
internal fun IrType.encoding(): DwarfTypeKind = when(computePrimitiveBinaryTypeOrNull()) {
PrimitiveBinaryType.FLOAT -> DwarfTypeKind.DW_ATE_float
PrimitiveBinaryType.DOUBLE -> DwarfTypeKind.DW_ATE_float
PrimitiveBinaryType.BOOLEAN -> DwarfTypeKind.DW_ATE_boolean
PrimitiveBinaryType.POINTER -> DwarfTypeKind.DW_ATE_address
else -> {
//TODO: not recursive.
if (this.isUnsigned()) DwarfTypeKind.DW_ATE_unsigned
else DwarfTypeKind.DW_ATE_signed
}
}
internal fun alignTo(value:Long, align:Long):Long = (value + align - 1) / align * align
internal fun IrFunction.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<IrType>): DISubroutineTypeRef {
return memScoped {
DICreateSubroutineType(context.generationState.debugInfo.builder, allocArrayOf(
types.map { it.diType(context, llvmTargetData) }),
types.size)!!
}
}
@Suppress("UNCHECKED_CAST")
private fun dwarfPointerType(context: Context, type: DITypeOpaqueRef) =
DICreatePointerType(context.generationState.debugInfo.builder, type) as DITypeOpaqueRef
internal fun alignTo(value: Long, align: Long): Long = (value + align - 1) / align * align
internal fun setupBridgeDebugInfo(context: Context, function: LLVMValueRef): LocationInfo? {
if (!context.shouldContainLocationDebugInfo()) {
return null
}
val file = context.generationState.debugInfo.compilerGeneratedFile
val debugInfo = context.generationState.debugInfo
val file = debugInfo.compilerGeneratedFile
// TODO: can we share the scope among all bridges?
val scope: DIScopeOpaqueRef = DICreateFunction(
builder = context.generationState.debugInfo.builder,
builder = debugInfo.builder,
scope = file.reinterpret(),
name = function.name,
linkageName = function.name,
file = file,
lineNo = 0,
type = subroutineType(context, context.generationState.runtime.targetData, emptyList()), // TODO: use proper type.
type = debugInfo.subroutineType(context.generationState.runtime.targetData, emptyList()), // TODO: use proper type.
isLocal = 0,
isDefinition = 1,
scopeLine = 0
@@ -759,7 +759,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private val scope by lazy {
if (!context.shouldContainLocationDebugInfo() || declaration == null)
return@lazy null
declaration.scope() ?: llvmFunction.scope(0, subroutineType(context, codegen.llvmTargetData, listOf(context.irBuiltIns.intType)))
declaration.scope() ?: llvmFunction.scope(0, debugInfo.subroutineType(codegen.llvmTargetData, listOf(context.irBuiltIns.intType)))
}
private val fileScope = (fileScope() as? FileScope)
@@ -1453,7 +1453,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
is IrVariable -> if (shouldGenerateDebugInfo(element)) debugInfoLocalVariableLocation(
builder = debugInfo.builder,
functionScope = locationInfo.scope,
diType = element.type.diType(context, codegen.llvmTargetData),
diType = with(debugInfo) { element.type.diType(codegen.llvmTargetData) },
name = element.debugNameConversion(),
file = file,
line = locationInfo.line,
@@ -1462,7 +1462,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
is IrValueParameter -> debugInfoParameterLocation(
builder = debugInfo.builder,
functionScope = locationInfo.scope,
diType = element.type.diType(context, codegen.llvmTargetData),
diType = with(debugInfo) { element.type.diType(codegen.llvmTargetData) },
name = element.debugNameConversion(),
argNo = function.allParameters.indexOf(element) + 1,
file = file,
@@ -2188,31 +2188,33 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun debugFieldDeclaration(expression: IrField) {
val scope = currentCodeContext.classScope() as? ClassScope ?: return
if (!scope.isExported || !context.shouldContainDebugInfo()) return
val irFile = (currentCodeContext.fileScope() as FileScope).file
val sizeInBits = expression.type.size(context)
scope.offsetInBits += sizeInBits
val alignInBits = expression.type.alignment(context)
scope.offsetInBits = alignTo(scope.offsetInBits, alignInBits)
@Suppress("UNCHECKED_CAST")
scope.members.add(DICreateMemberType(
refBuilder = debugInfo.builder,
refScope = scope.scope as DIScopeOpaqueRef,
name = expression.computeSymbolName(),
file = irFile.file(),
lineNum = expression.startLine(),
sizeInBits = sizeInBits,
alignInBits = alignInBits,
offsetInBits = scope.offsetInBits,
flags = 0,
type = expression.type.diType(context, codegen.llvmTargetData)
)!!)
with(debugInfo) {
val irFile = (currentCodeContext.fileScope() as FileScope).file
val sizeInBits = expression.type.size
scope.offsetInBits += sizeInBits
val alignInBits = expression.type.alignment
scope.offsetInBits = alignTo(scope.offsetInBits, alignInBits)
@Suppress("UNCHECKED_CAST")
scope.members.add(DICreateMemberType(
refBuilder = builder,
refScope = scope.scope as DIScopeOpaqueRef,
name = expression.computeSymbolName(),
file = irFile.file(),
lineNum = expression.startLine(),
sizeInBits = sizeInBits,
alignInBits = alignInBits,
offsetInBits = scope.offsetInBits,
flags = 0,
type = expression.type.diType(codegen.llvmTargetData)
)!!)
}
}
//-------------------------------------------------------------------------//
private fun IrFile.file(): DIFileRef {
return debugInfo.files.getOrPut(this.fileEntry.name) {
val path = this.fileEntry.name.toFileAndFolder(context)
val path = this.fileEntry.name.toFileAndFolder(context.config)
DICreateFile(debugInfo.builder, path.file, path.folder)!!
}
}
@@ -2244,23 +2246,25 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
this is IrSimpleFunction && isSuspend -> this.getOrCreateFunctionWithContinuationStub(context).let { codegen.llvmFunctionOrNull(it)?.llvmValue }
else -> codegen.llvmFunctionOrNull(this)?.llvmValue
}
return if (functionLlvmValue != null) {
debugInfo.subprograms.getOrPut(functionLlvmValue) {
memScoped {
val subroutineType = subroutineType(context, codegen.llvmTargetData)
diFunctionScope(name.asString(), functionLlvmValue.name!!, startLine, subroutineType).also {
if (!this@scope.isInline)
DIFunctionAddSubprogram(functionLlvmValue, it)
return with(debugInfo) {
if (functionLlvmValue != null) {
subprograms.getOrPut(functionLlvmValue) {
memScoped {
val subroutineType = subroutineType(codegen.llvmTargetData)
diFunctionScope(name.asString(), functionLlvmValue.name!!, startLine, subroutineType).also {
if (!this@scope.isInline)
DIFunctionAddSubprogram(functionLlvmValue, it)
}
}
}
} as DIScopeOpaqueRef
} else {
debugInfo.inlinedSubprograms.getOrPut(this) {
memScoped {
val subroutineType = subroutineType(context, codegen.llvmTargetData)
diFunctionScope(name.asString(), "<inlined-out:$name>", startLine, subroutineType)
}
} as DIScopeOpaqueRef
} as DIScopeOpaqueRef
} else {
inlinedSubprograms.getOrPut(this@scope) {
memScoped {
val subroutineType = subroutineType(codegen.llvmTargetData)
diFunctionScope(name.asString(), "<inlined-out:$name>", startLine, subroutineType)
}
} as DIScopeOpaqueRef
}
}
}