Use runtime bitcode to get size of primitive types

As an alternative to explicitly setting type size in konan.properties or
backend code we can "ask" LLVM about it.
Unfortunately, there is no Clang/LLVM API for it,
so we use a trivial workaround:
Create dumb function in runtime code, and then extract info about
return type size using LLVM.
This commit is contained in:
Sergey Bogolepov
2021-04-07 15:40:32 +07:00
committed by TeamCityServer
parent 790fea635d
commit 9b1498abad
7 changed files with 49 additions and 54 deletions
@@ -502,6 +502,9 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
val Kotlin_ObjCExport_createContinuationArgument by lazyRtFunction
val Kotlin_ObjCExport_resumeContinuation by lazyRtFunction
private val Kotlin_ObjCExport_NSIntegerTypeProvider by lazyRtFunction
private val Kotlin_longTypeProvider by lazyRtFunction
val Kotlin_mm_safePointFunctionEpilogue by lazyRtFunction
val Kotlin_mm_safePointWhileLoopBody by lazyRtFunction
val Kotlin_mm_safePointExceptionUnwind by lazyRtFunction
@@ -593,6 +596,26 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
val llvmFloat = floatType
val llvmDouble = doubleType
val llvmVector128 = vector128Type
private fun getSizeOfReturnTypeInBits(functionPointer: LLVMValueRef): Long {
// LLVMGetElementType is called because we need to dereference a pointer to function.
val nsIntegerType = LLVMGetReturnType(LLVMGetElementType(functionPointer.type))
return LLVMSizeOfTypeInBits(runtime.targetData, nsIntegerType)
}
/**
* Width of NSInteger in bits.
*/
val nsIntegerTypeWidth: Long by lazy {
getSizeOfReturnTypeInBits(Kotlin_ObjCExport_NSIntegerTypeProvider)
}
/**
* Width of C long type in bits.
*/
val longTypeWidth: Long by lazy {
getSizeOfReturnTypeInBits(Kotlin_longTypeProvider)
}
}
class IrStaticInitializer(val konanLibrary: KotlinLibrary?, val initializer: LLVMValueRef)
@@ -194,7 +194,11 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
}
fun org.jetbrains.kotlin.backend.konan.Context.LongInt(value: Long) =
if (is64BitLong()) Int64(value) else Int32(value.toInt())
when (val longWidth = llvm.longTypeWidth) {
32L -> Int32(value.toInt())
64L -> Int64(value)
else -> error("Unexpected width of long type: $longWidth")
}
private fun generateDescriptorForBlock(blockType: BlockType): ConstValue {
val numberOfParameters = blockType.numberOfParameters
@@ -29,7 +29,7 @@ import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.konan.target.AppleConfigurables
import org.jetbrains.kotlin.konan.target.LinkerOutputKind
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.DFS
@@ -1669,56 +1669,10 @@ private val TypeBridge.objCEncoding: String get() = when (this) {
is ValueTypeBridge -> this.objCValueType.encoding
}
private fun Context.is64BitNSInteger(): Boolean = when (val target = this.config.target) {
KonanTarget.IOS_X64,
KonanTarget.IOS_ARM64,
KonanTarget.TVOS_ARM64,
KonanTarget.TVOS_X64,
KonanTarget.MACOS_X64,
KonanTarget.MACOS_ARM64,
KonanTarget.WATCHOS_X64 -> true
KonanTarget.WATCHOS_ARM64,
KonanTarget.WATCHOS_ARM32,
KonanTarget.WATCHOS_X86,
KonanTarget.IOS_ARM32 -> false
KonanTarget.ANDROID_X64,
KonanTarget.ANDROID_X86,
KonanTarget.ANDROID_ARM32,
KonanTarget.ANDROID_ARM64,
KonanTarget.LINUX_X64,
KonanTarget.MINGW_X86,
KonanTarget.MINGW_X64,
KonanTarget.LINUX_ARM64,
KonanTarget.LINUX_ARM32_HFP,
KonanTarget.LINUX_MIPS32,
KonanTarget.LINUX_MIPSEL32,
KonanTarget.WASM32,
is KonanTarget.ZEPHYR -> error("Target $target has no support for NSInteger type.")
}
internal fun Context.is64BitLong(): Boolean = when (this.config.target) {
KonanTarget.IOS_X64,
KonanTarget.IOS_ARM64,
KonanTarget.TVOS_ARM64,
KonanTarget.TVOS_X64,
KonanTarget.ANDROID_X64,
KonanTarget.ANDROID_ARM64,
KonanTarget.LINUX_ARM64,
KonanTarget.MINGW_X64,
KonanTarget.LINUX_X64,
KonanTarget.MACOS_X64,
KonanTarget.MACOS_ARM64,
KonanTarget.WATCHOS_X64 -> true
KonanTarget.WATCHOS_ARM64,
KonanTarget.WATCHOS_ARM32,
KonanTarget.ANDROID_X86,
KonanTarget.ANDROID_ARM32,
KonanTarget.WATCHOS_X86,
KonanTarget.MINGW_X86,
KonanTarget.LINUX_ARM32_HFP,
KonanTarget.LINUX_MIPS32,
KonanTarget.LINUX_MIPSEL32,
KonanTarget.WASM32,
is KonanTarget.ZEPHYR,
KonanTarget.IOS_ARM32 -> false
private fun Context.is64BitNSInteger(): Boolean {
val configurables = this.config.platform.configurables
require(configurables is AppleConfigurables) {
"Target ${configurables.target} has no support for NSInteger type."
}
return llvm.nsIntegerTypeWidth == 64L
}
@@ -39,6 +39,9 @@ extern "C" OBJ_GETTER(Kotlin_ObjCExport_refFromObjC, id obj);
extern "C" id Kotlin_Interop_CreateNSStringFromKString(KRef str);
extern "C" OBJ_GETTER(Kotlin_Interop_CreateKStringFromNSString, NSString* str);
/// Utility function that is used to determine NSInteger size in compile time.
extern "C" NSInteger Kotlin_ObjCExport_NSIntegerTypeProvider();
#endif // KONAN_OBJC_INTEROP
#endif // RUNTIME_OBJCEXPORT_H
@@ -1090,6 +1090,10 @@ extern "C" void Kotlin_ObjCExport_AbstractMethodCalled(id self, SEL selector) {
class_getName(object_getClass(self)), sel_getName(selector)];
}
extern "C" NSInteger Kotlin_ObjCExport_NSIntegerTypeProvider() {
return 0;
}
#else
extern "C" ALWAYS_INLINE void* Kotlin_Interop_refToObjC(ObjHeader* obj) {
@@ -108,4 +108,8 @@ KVector4f Kotlin_Vector4i32_of(KInt f0, KInt f1, KInt f2, KInt f3) {
return (KVector4f)v4i;
}
long Kotlin_longTypeProvider() {
return 0;
}
} // extern "C"
@@ -124,6 +124,9 @@ void CheckCast(const ObjHeader* obj, const TypeInfo* type_info);
KBoolean IsArray(KConstRef obj) RUNTIME_PURE;
bool IsSubInterface(const TypeInfo* thiz, const TypeInfo* other) RUNTIME_PURE;
/// Utility function that is used to determine long type size in compile time.
long Kotlin_longTypeProvider();
#ifdef __cplusplus
}
#endif