[K/N] Implement bitcode generation for constant objects

This commit is contained in:
Pavel Kunyavskiy
2021-08-04 17:08:57 +03:00
committed by Space
parent c7f182adbf
commit e6b9531b6c
@@ -997,6 +997,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
return evaluateSuspendableExpression (value)
is IrSuspensionPoint -> return evaluateSuspensionPoint (value)
is IrClassReference -> return evaluateClassReference (value)
is IrConstantValue -> return evaluateConstantValue (value).llvm
else -> {
TODO(ir2string(value))
}
@@ -1810,6 +1811,91 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------//
private class IrConstValueCacheKey(val value: IrConstantValue) {
override fun equals(other: Any?): Boolean {
if (other !is IrConstValueCacheKey) return false
return value.contentEquals(other.value)
}
override fun hashCode(): Int {
return value.contentHashCode()
}
}
private val constantValuesCache = mutableMapOf<IrConstValueCacheKey, ConstValue>()
private fun evaluateConstantValue(value: IrConstantValue): ConstValue =
constantValuesCache.getOrPut(IrConstValueCacheKey(value)) {
evaluateConstantValueImpl(value)
}
private fun evaluateConstantValueImpl(value: IrConstantValue): ConstValue {
val symbols = context.ir.symbols
return when (value) {
is IrConstantPrimitive -> {
val constructedType = value.value.type
if (context.ir.symbols.getTypeConversion(constructedType, value.type) != null) {
if (value.value.kind == IrConstKind.Null) {
Zero(codegen.getLLVMType(value.type))
} else {
require(codegen.getLLVMType(value.type) == codegen.kObjHeaderPtr) {
"Can't wrap ${value.value.kind.asString} constant to type ${value.type.render()}"
}
context.llvm.staticData.createConstKotlinObject(
constructedType.getClass()!!,
evaluateConst(value.value)
)
}
} else {
evaluateConst(value.value)
}
}
is IrConstantArray -> {
val clazz = value.type.getClass()!!
require(clazz.symbol == symbols.array || clazz.symbol in symbols.primitiveTypesToPrimitiveArrays.values) {
"Statically initialized array should have array type"
}
context.llvm.staticData.createConstKotlinArray(
value.type.getClass()!!,
value.elements.map { evaluateConstantValue(it) }
)
}
is IrConstantObject -> {
val constructedType = value.constructor.owner.constructedClassType
val constructedClass = constructedType.getClass()!!
val needUnBoxing = constructedType.getInlinedClassNative() != null &&
context.ir.symbols.getTypeConversion(constructedType, value.type) == null
if (needUnBoxing) {
val unboxed = value.valueArguments.singleOrNull()
?: error("Inlined class should have exactly one constructor argument")
return evaluateConstantValue(unboxed)
}
val fields = if (value.constructor.owner.isConstantConstructorIntrinsic) {
intrinsicGenerator.evaluateConstantConstructorFields(value, value.valueArguments.map { evaluateConstantValue(it) })
} else {
context.getLayoutBuilder(constructedClass).fields.map { field ->
val index = value.constructor.owner.valueParameters
.indexOfFirst { it.name.toString() == field.name }
.takeIf { it >= 0 }
?: error("Bad statically initialized object: field ${field.name} value not set in ${constructedClass.name}")
evaluateConstantValue(value.valueArguments[index])
}.also {
require(it.size == value.valueArguments.size) { "Bad statically initialized object: too many fields" }
}
}
require(codegen.getLLVMType(value.type) == codegen.kObjHeaderPtr) { "Constant object is not an object, but ${value.type.render()}" }
context.llvm.staticData.createConstKotlinObject(
constructedClass,
*fields.toTypedArray()
)
}
else -> TODO("Unimplemented IrConstantValue subclass ${value::class.qualifiedName}")
}
}
//-------------------------------------------------------------------------//
private fun evaluateReturn(expression: IrReturn): LLVMValueRef {
context.log{"evaluateReturn : ${ir2string(expression)}"}
val value = expression.value