[K/N] Refactor staticData to support several llvm modules

This commit is contained in:
Pavel Kunyavskiy
2022-06-09 14:08:11 +02:00
committed by Space
parent f562c127af
commit ee2340842c
5 changed files with 154 additions and 219 deletions
@@ -157,7 +157,7 @@ internal interface ContextUtils : RuntimeAware {
val llvmTargetData: LLVMTargetDataRef
get() = runtime.targetData
val staticData: StaticData
val staticData: KotlinStaticData
get() = context.llvm.staticData
/**
@@ -427,7 +427,7 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) : Runti
val additionalProducedBitcodeFiles = mutableListOf<String>()
val staticData = StaticData(context)
val staticData = KotlinStaticData(context)
private val target = context.config.target
@@ -0,0 +1,126 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package org.jetbrains.kotlin.backend.konan.llvm
import kotlinx.cinterop.cValuesOf
import llvm.*
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.ir.llvmSymbolOrigin
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.expressions.IrConst
private fun ConstPointer.add(index: Int): ConstPointer {
return constPointer(LLVMConstGEP(llvm, cValuesOf(Int32(index).llvm), 1)!!)
}
internal class KotlinStaticData(override val context: Context) : ContextUtils, StaticData(context.llvmModule!!) {
private val stringLiterals = mutableMapOf<String, ConstPointer>()
// Must match OBJECT_TAG_PERMANENT_CONTAINER in C++.
private fun permanentTag(typeInfo: ConstPointer): ConstPointer {
// Only pointer arithmetic via GEP works on constant pointers in LLVM.
return typeInfo.bitcast(int8TypePtr).add(1).bitcast(kTypeInfoPtr)
}
private fun objHeader(typeInfo: ConstPointer): Struct {
return Struct(runtime.objHeaderType, permanentTag(typeInfo))
}
private fun arrayHeader(typeInfo: ConstPointer, length: Int): Struct {
assert(length >= 0)
return Struct(runtime.arrayHeaderType, permanentTag(typeInfo), Int32(length))
}
private fun createRef(objHeaderPtr: ConstPointer) = objHeaderPtr.bitcast(kObjHeaderPtr)
private fun createKotlinStringLiteral(value: String): ConstPointer {
val elements = value.toCharArray().map(::Char16)
val objRef = createConstKotlinArray(context.ir.symbols.string.owner, elements)
return objRef
}
fun kotlinStringLiteral(value: String) = stringLiterals.getOrPut(value) { createKotlinStringLiteral(value) }
fun createConstKotlinArray(arrayClass: IrClass, elements: List<LLVMValueRef>) =
createConstKotlinArray(arrayClass, elements.map { constValue(it) }).llvm
fun createConstKotlinArray(arrayClass: IrClass, elements: List<ConstValue>): ConstPointer {
val typeInfo = arrayClass.typeInfoPtr
val bodyElementType: LLVMTypeRef = elements.firstOrNull()?.llvmType ?: int8Type
// (use [0 x i8] as body if there are no elements)
val arrayBody = ConstArray(bodyElementType, elements)
val compositeType = structType(runtime.arrayHeaderType, arrayBody.llvmType)
val global = this.createGlobal(compositeType, "")
val objHeaderPtr = global.pointer.getElementPtr(0)
val arrayHeader = arrayHeader(typeInfo, elements.size)
global.setInitializer(Struct(compositeType, arrayHeader, arrayBody))
global.setConstant(true)
global.setUnnamedAddr(true)
return createRef(objHeaderPtr)
}
fun createConstKotlinObject(type: IrClass, vararg fields: ConstValue): ConstPointer {
val typeInfo = type.typeInfoPtr
val objHeader = objHeader(typeInfo)
val global = this.placeGlobal("", Struct(objHeader, *fields))
global.setUnnamedAddr(true)
global.setConstant(true)
val objHeaderPtr = global.pointer.getElementPtr(0)
return createRef(objHeaderPtr)
}
fun createInitializer(type: IrClass, vararg fields: ConstValue): ConstValue =
Struct(objHeader(type.typeInfoPtr), *fields)
fun createUniqueInstance(
kind: UniqueKind, bodyType: LLVMTypeRef, typeInfo: ConstPointer): ConstPointer {
assert(getStructElements(bodyType).size == 1) // ObjHeader only.
val objHeader = when (kind) {
UniqueKind.UNIT -> objHeader(typeInfo)
UniqueKind.EMPTY_ARRAY -> arrayHeader(typeInfo, 0)
}
val global = this.placeGlobal(kind.llvmName, objHeader, isExported = true)
global.setConstant(true)
return global.pointer
}
fun unique(kind: UniqueKind): ConstPointer {
val descriptor = when (kind) {
UniqueKind.UNIT -> context.ir.symbols.unit.owner
UniqueKind.EMPTY_ARRAY -> context.ir.symbols.array.owner
}
return if (isExternal(descriptor)) {
constPointer(importGlobal(
kind.llvmName, context.llvm.runtime.objHeaderType, origin = descriptor.llvmSymbolOrigin
))
} else {
context.llvmDeclarations.forUnique(kind).pointer
}
}
/**
* Creates static instance of `konan.ImmutableByteArray` with given values of elements.
*
* @param args data for constant creation.
*/
fun createImmutableBlob(value: IrConst<String>): LLVMValueRef {
val args = value.value.map { Int8(it.code.toByte()).llvm }
return createConstKotlinArray(context.ir.symbols.immutableBlob.owner, args)
}
}
internal val ContextUtils.theUnitInstanceRef: ConstPointer
get() = staticData.unique(UniqueKind.UNIT)
@@ -7,17 +7,16 @@ package org.jetbrains.kotlin.backend.konan.llvm
import llvm.*
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.ir.expressions.IrConst
/**
* Provides utilities to create static data.
*/
internal class StaticData(override val context: Context): ContextUtils {
internal open class StaticData(val module: LLVMModuleRef) {
/**
* Represents the LLVM global variable.
*/
class Global private constructor(val staticData: StaticData, val llvmGlobal: LLVMValueRef) {
class Global private constructor(val llvmGlobal: LLVMValueRef) {
companion object {
private fun createLlvmGlobal(module: LLVMModuleRef,
@@ -41,20 +40,18 @@ internal class StaticData(override val context: Context): ContextUtils {
}
fun create(staticData: StaticData, type: LLVMTypeRef, name: String, isExported: Boolean): Global {
val module = staticData.context.llvmModule
val isUnnamed = (name == "") // LLVM will select the unique index and represent the global as `@idx`.
if (isUnnamed && isExported) {
throw IllegalArgumentException("unnamed global can't be exported")
}
val llvmGlobal = createLlvmGlobal(module!!, type, name, isExported)
return Global(staticData, llvmGlobal)
val llvmGlobal = createLlvmGlobal(staticData.module, type, name, isExported)
return Global(llvmGlobal)
}
fun get(staticData: StaticData, name: String): Global? {
val llvmGlobal = LLVMGetNamedGlobal(staticData.context.llvmModule, name) ?: return null
return Global(staticData, llvmGlobal)
val llvmGlobal = LLVMGetNamedGlobal(staticData.module, name) ?: return null
return Global(llvmGlobal)
}
}
@@ -97,54 +94,7 @@ internal class StaticData(override val context: Context): ContextUtils {
LLVMSetExternallyInitialized(llvmGlobal, if (value) 1 else 0)
}
val pointer = Pointer.to(this)
}
/**
* Represents the pointer to static data.
* It can be a pointer to either a global or any its element.
*
* TODO: this class is probably should be implemented more optimally
*/
class Pointer private constructor(val global: Global,
private val delegate: ConstPointer,
val offsetInGlobal: Long) : ConstPointer by delegate {
companion object {
fun to(global: Global) = Pointer(global, constPointer(global.llvmGlobal), 0L)
}
private fun getElementOffset(index: Int): Long {
val llvmTargetData = global.staticData.llvmTargetData
val type = LLVMGetElementType(delegate.llvmType)
return when (LLVMGetTypeKind(type)) {
LLVMTypeKind.LLVMStructTypeKind -> LLVMOffsetOfElement(llvmTargetData, type, index)
LLVMTypeKind.LLVMArrayTypeKind -> LLVMABISizeOfType(llvmTargetData, LLVMGetElementType(type)) * index
else -> TODO()
}
}
override fun getElementPtr(index: Int): Pointer {
return Pointer(global, delegate.getElementPtr(index), offsetInGlobal + this.getElementOffset(index))
}
/**
* @return the distance from other pointer to this.
*
* @throws UnsupportedOperationException if it is not possible to represent the distance as [Int] value
*/
fun sub(other: Pointer): Int {
if (this.global != other.global) {
throw UnsupportedOperationException("pointers must belong to the same global")
}
val res = this.offsetInGlobal - other.offsetInGlobal
if (res.toInt().toLong() != res) {
throw UnsupportedOperationException("result doesn't fit into Int")
}
return res.toInt()
}
val pointer : ConstPointer = constPointer(this.llvmGlobal)
}
/**
@@ -179,22 +129,26 @@ internal class StaticData(override val context: Context): ContextUtils {
return global
}
private val stringLiterals = mutableMapOf<String, ConstPointer>()
private val cStringLiterals = mutableMapOf<String, ConstPointer>()
fun cStringLiteral(value: String) =
cStringLiterals.getOrPut(value) { placeCStringLiteral(value) }
internal fun placeGlobalConstArray(name: String,
elemType: LLVMTypeRef,
elements: List<ConstValue>,
isExported: Boolean = false): ConstPointer {
if (elements.isNotEmpty() || isExported) {
val global = placeGlobalArray(name, elemType, elements, isExported)
global.setConstant(true)
return global.pointer.getElementPtr(0)
} else {
return NullPointer(elemType)
}
}
fun kotlinStringLiteral(value: String) =
stringLiterals.getOrPut(value) { createKotlinStringLiteral(value) }
internal fun placeCStringLiteral(value: String) : ConstPointer {
val chars = value.toByteArray(Charsets.UTF_8).map { Int8(it) } + Int8(0)
return placeGlobalConstArray("", int8Type, chars)
}
internal fun cStringLiteral(value: String) = cStringLiterals.getOrPut(value) { placeCStringLiteral(value) }
}
/**
* Creates static instance of `konan.ImmutableByteArray` with given values of elements.
*
* @param args data for constant creation.
*/
internal fun StaticData.createImmutableBlob(value: IrConst<String>): LLVMValueRef {
val args = value.value.map { Int8(it.code.toByte()).llvm }
return createConstKotlinArray(context.ir.symbols.immutableBlob.owner, args)
}
@@ -1,38 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package org.jetbrains.kotlin.backend.konan.llvm
import llvm.*
/**
* Creates const array-typed global with given name and value.
* Returns pointer to the first element of the array.
*
* If [elements] is empty, then null pointer is returned.
*/
internal fun StaticData.placeGlobalConstArray(name: String,
elemType: LLVMTypeRef,
elements: List<ConstValue>,
isExported: Boolean = false): ConstPointer {
if (elements.isNotEmpty() || isExported) {
val global = this.placeGlobalArray(name, elemType, elements, isExported)
global.setConstant(true)
return global.pointer.getElementPtr(0)
} else {
return NullPointer(elemType)
}
}
internal fun StaticData.createAlias(name: String, aliasee: ConstPointer): ConstPointer {
val alias = LLVMAddAlias(context.llvmModule, aliasee.llvmType, aliasee.llvm, name)!!
return constPointer(alias)
}
internal fun StaticData.placeCStringLiteral(value: String): ConstPointer {
val chars = value.toByteArray(Charsets.UTF_8).map { Int8(it) } + Int8(0)
return placeGlobalConstArray("", int8Type, chars)
}
@@ -1,107 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package org.jetbrains.kotlin.backend.konan.llvm
import kotlinx.cinterop.cValuesOf
import llvm.*
import org.jetbrains.kotlin.backend.konan.ir.llvmSymbolOrigin
import org.jetbrains.kotlin.ir.declarations.IrClass
private fun ConstPointer.add(index: Int): ConstPointer {
return constPointer(LLVMConstGEP(llvm, cValuesOf(Int32(index).llvm), 1)!!)
}
// Must match OBJECT_TAG_PERMANENT_CONTAINER in C++.
private fun StaticData.permanentTag(typeInfo: ConstPointer): ConstPointer {
// Only pointer arithmetic via GEP works on constant pointers in LLVM.
return typeInfo.bitcast(int8TypePtr).add(1).bitcast(kTypeInfoPtr)
}
private fun StaticData.objHeader(typeInfo: ConstPointer): Struct {
return Struct(runtime.objHeaderType, permanentTag(typeInfo))
}
private fun StaticData.arrayHeader(typeInfo: ConstPointer, length: Int): Struct {
assert (length >= 0)
return Struct(runtime.arrayHeaderType, permanentTag(typeInfo), Int32(length))
}
internal fun StaticData.createKotlinStringLiteral(value: String): ConstPointer {
val elements = value.toCharArray().map(::Char16)
val objRef = createConstKotlinArray(context.ir.symbols.string.owner, elements)
return objRef
}
private fun StaticData.createRef(objHeaderPtr: ConstPointer) = objHeaderPtr.bitcast(kObjHeaderPtr)
internal fun StaticData.createConstKotlinArray(arrayClass: IrClass, elements: List<LLVMValueRef>) =
createConstKotlinArray(arrayClass, elements.map { constValue(it) }).llvm
internal fun StaticData.createConstKotlinArray(arrayClass: IrClass, elements: List<ConstValue>): ConstPointer {
val typeInfo = arrayClass.typeInfoPtr
val bodyElementType: LLVMTypeRef = elements.firstOrNull()?.llvmType ?: int8Type
// (use [0 x i8] as body if there are no elements)
val arrayBody = ConstArray(bodyElementType, elements)
val compositeType = structType(runtime.arrayHeaderType, arrayBody.llvmType)
val global = this.createGlobal(compositeType, "")
val objHeaderPtr = global.pointer.getElementPtr(0)
val arrayHeader = arrayHeader(typeInfo, elements.size)
global.setInitializer(Struct(compositeType, arrayHeader, arrayBody))
global.setConstant(true)
global.setUnnamedAddr(true)
return createRef(objHeaderPtr)
}
internal fun StaticData.createConstKotlinObject(type: IrClass, vararg fields: ConstValue): ConstPointer {
val typeInfo = type.typeInfoPtr
val objHeader = objHeader(typeInfo)
val global = this.placeGlobal("", Struct(objHeader, *fields))
global.setUnnamedAddr(true)
global.setConstant(true)
val objHeaderPtr = global.pointer.getElementPtr(0)
return createRef(objHeaderPtr)
}
internal fun StaticData.createInitializer(type: IrClass, vararg fields: ConstValue): ConstValue =
Struct(objHeader(type.typeInfoPtr), *fields)
internal fun StaticData.createUniqueInstance(
kind: UniqueKind, bodyType: LLVMTypeRef, typeInfo: ConstPointer): ConstPointer {
assert (getStructElements(bodyType).size == 1) // ObjHeader only.
val objHeader = when (kind) {
UniqueKind.UNIT -> objHeader(typeInfo)
UniqueKind.EMPTY_ARRAY -> arrayHeader(typeInfo, 0)
}
val global = this.placeGlobal(kind.llvmName, objHeader, isExported = true)
global.setConstant(true)
return global.pointer
}
internal fun ContextUtils.unique(kind: UniqueKind): ConstPointer {
val descriptor = when (kind) {
UniqueKind.UNIT -> context.ir.symbols.unit.owner
UniqueKind.EMPTY_ARRAY -> context.ir.symbols.array.owner
}
return if (isExternal(descriptor)) {
constPointer(importGlobal(
kind.llvmName, context.llvm.runtime.objHeaderType, origin = descriptor.llvmSymbolOrigin
))
} else {
context.llvmDeclarations.forUnique(kind).pointer
}
}
internal val ContextUtils.theUnitInstanceRef: ConstPointer
get() = this.unique(UniqueKind.UNIT)