[K/N] Implement bitcode generation for constant objects
This commit is contained in:
+86
@@ -997,6 +997,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
|||||||
return evaluateSuspendableExpression (value)
|
return evaluateSuspendableExpression (value)
|
||||||
is IrSuspensionPoint -> return evaluateSuspensionPoint (value)
|
is IrSuspensionPoint -> return evaluateSuspensionPoint (value)
|
||||||
is IrClassReference -> return evaluateClassReference (value)
|
is IrClassReference -> return evaluateClassReference (value)
|
||||||
|
is IrConstantValue -> return evaluateConstantValue (value).llvm
|
||||||
else -> {
|
else -> {
|
||||||
TODO(ir2string(value))
|
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 {
|
private fun evaluateReturn(expression: IrReturn): LLVMValueRef {
|
||||||
context.log{"evaluateReturn : ${ir2string(expression)}"}
|
context.log{"evaluateReturn : ${ir2string(expression)}"}
|
||||||
val value = expression.value
|
val value = expression.value
|
||||||
|
|||||||
Reference in New Issue
Block a user