Move more intrinsics under TypedIntrinsic annotation (#2474)
This commit is contained in:
@@ -18,37 +18,40 @@ package kotlinx.cinterop
|
||||
|
||||
import kotlin.native.*
|
||||
import kotlin.native.internal.Intrinsic
|
||||
import kotlin.native.internal.TypedIntrinsic
|
||||
import kotlin.native.internal.IntrinsicType
|
||||
|
||||
@PublishedApi
|
||||
internal inline val pointerSize: Int
|
||||
get() = getPointerSize()
|
||||
|
||||
@PublishedApi
|
||||
@Intrinsic internal external fun getPointerSize(): Int
|
||||
@TypedIntrinsic(IntrinsicType.GET_POINTER_SIZE)
|
||||
internal external fun getPointerSize(): Int
|
||||
|
||||
// TODO: do not use singleton because it leads to init-check on any access.
|
||||
@PublishedApi
|
||||
internal object nativeMemUtils {
|
||||
@Intrinsic external fun getByte(mem: NativePointed): Byte
|
||||
@Intrinsic external fun putByte(mem: NativePointed, value: Byte)
|
||||
@TypedIntrinsic(IntrinsicType.READ_PRIMITIVE) external fun getByte(mem: NativePointed): Byte
|
||||
@TypedIntrinsic(IntrinsicType.WRITE_PRIMITIVE) external fun putByte(mem: NativePointed, value: Byte)
|
||||
|
||||
@Intrinsic external fun getShort(mem: NativePointed): Short
|
||||
@Intrinsic external fun putShort(mem: NativePointed, value: Short)
|
||||
@TypedIntrinsic(IntrinsicType.READ_PRIMITIVE) external fun getShort(mem: NativePointed): Short
|
||||
@TypedIntrinsic(IntrinsicType.WRITE_PRIMITIVE) external fun putShort(mem: NativePointed, value: Short)
|
||||
|
||||
@Intrinsic external fun getInt(mem: NativePointed): Int
|
||||
@Intrinsic external fun putInt(mem: NativePointed, value: Int)
|
||||
@TypedIntrinsic(IntrinsicType.READ_PRIMITIVE) external fun getInt(mem: NativePointed): Int
|
||||
@TypedIntrinsic(IntrinsicType.WRITE_PRIMITIVE) external fun putInt(mem: NativePointed, value: Int)
|
||||
|
||||
@Intrinsic external fun getLong(mem: NativePointed): Long
|
||||
@Intrinsic external fun putLong(mem: NativePointed, value: Long)
|
||||
@TypedIntrinsic(IntrinsicType.READ_PRIMITIVE) external fun getLong(mem: NativePointed): Long
|
||||
@TypedIntrinsic(IntrinsicType.WRITE_PRIMITIVE) external fun putLong(mem: NativePointed, value: Long)
|
||||
|
||||
@Intrinsic external fun getFloat(mem: NativePointed): Float
|
||||
@Intrinsic external fun putFloat(mem: NativePointed, value: Float)
|
||||
@TypedIntrinsic(IntrinsicType.READ_PRIMITIVE) external fun getFloat(mem: NativePointed): Float
|
||||
@TypedIntrinsic(IntrinsicType.WRITE_PRIMITIVE) external fun putFloat(mem: NativePointed, value: Float)
|
||||
|
||||
@Intrinsic external fun getDouble(mem: NativePointed): Double
|
||||
@Intrinsic external fun putDouble(mem: NativePointed, value: Double)
|
||||
@TypedIntrinsic(IntrinsicType.READ_PRIMITIVE) external fun getDouble(mem: NativePointed): Double
|
||||
@TypedIntrinsic(IntrinsicType.WRITE_PRIMITIVE) external fun putDouble(mem: NativePointed, value: Double)
|
||||
|
||||
@Intrinsic external fun getNativePtr(mem: NativePointed): NativePtr
|
||||
@Intrinsic external fun putNativePtr(mem: NativePointed, value: NativePtr)
|
||||
@TypedIntrinsic(IntrinsicType.READ_PRIMITIVE) external fun getNativePtr(mem: NativePointed): NativePtr
|
||||
@TypedIntrinsic(IntrinsicType.WRITE_PRIMITIVE) external fun putNativePtr(mem: NativePointed, value: NativePtr)
|
||||
|
||||
// TODO: optimize
|
||||
fun getByteArray(source: NativePointed, dest: ByteArray, length: Int) {
|
||||
@@ -151,5 +154,7 @@ private external fun malloc(size: Long, align: Int): NativePtr
|
||||
@SymbolName("Kotlin_interop_free")
|
||||
private external fun cfree(ptr: NativePtr)
|
||||
|
||||
@Intrinsic external fun readBits(ptr: NativePtr, offset: Long, size: Int, signed: Boolean): Long
|
||||
@Intrinsic external fun writeBits(ptr: NativePtr, offset: Long, size: Int, value: Long)
|
||||
@TypedIntrinsic(IntrinsicType.READ_BITS)
|
||||
external fun readBits(ptr: NativePtr, offset: Long, size: Int, signed: Boolean): Long
|
||||
@TypedIntrinsic(IntrinsicType.WRITE_BITS)
|
||||
external fun writeBits(ptr: NativePtr, offset: Long, size: Int, value: Long)
|
||||
@@ -20,6 +20,8 @@ import kotlin.native.internal.getNativeNullPtr
|
||||
import kotlin.native.internal.reinterpret
|
||||
import kotlin.native.internal.Intrinsic
|
||||
import kotlin.native.internal.VolatileLambda
|
||||
import kotlin.native.internal.TypedIntrinsic
|
||||
import kotlin.native.internal.IntrinsicType
|
||||
|
||||
typealias NativePtr = kotlin.native.internal.NativePtr
|
||||
internal typealias NonNullNativePtr = kotlin.native.internal.NonNullNativePtr
|
||||
@@ -37,16 +39,20 @@ fun <T : CVariable> typeOf(): CVariable.Type = throw Error("typeOf() is called w
|
||||
*
|
||||
* @param T must not be abstract
|
||||
*/
|
||||
@Intrinsic external fun <T : NativePointed> interpretNullablePointed(ptr: NativePtr): T?
|
||||
@TypedIntrinsic(IntrinsicType.IDENTITY)
|
||||
external fun <T : NativePointed> interpretNullablePointed(ptr: NativePtr): T?
|
||||
|
||||
/**
|
||||
* Performs type cast of the [CPointer] from the given raw pointer.
|
||||
*/
|
||||
@Intrinsic external fun <T : CPointed> interpretCPointer(rawValue: NativePtr): CPointer<T>?
|
||||
@TypedIntrinsic(IntrinsicType.IDENTITY)
|
||||
external fun <T : CPointed> interpretCPointer(rawValue: NativePtr): CPointer<T>?
|
||||
|
||||
@Intrinsic external fun NativePointed.getRawPointer(): NativePtr
|
||||
@TypedIntrinsic(IntrinsicType.IDENTITY)
|
||||
external fun NativePointed.getRawPointer(): NativePtr
|
||||
|
||||
@Intrinsic external fun CPointer<*>.getRawValue(): NativePtr
|
||||
@TypedIntrinsic(IntrinsicType.IDENTITY)
|
||||
external fun CPointer<*>.getRawValue(): NativePtr
|
||||
|
||||
internal fun CPointer<*>.cPointerToString() = "CPointer(raw=$rawValue)"
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
package kotlinx.cinterop
|
||||
import kotlin.native.*
|
||||
import kotlin.native.internal.ExportTypeInfo
|
||||
import kotlin.native.internal.TypedIntrinsic
|
||||
import kotlin.native.internal.IntrinsicType
|
||||
|
||||
interface ObjCObject
|
||||
interface ObjCClass : ObjCObject
|
||||
@@ -91,7 +93,8 @@ var <T : Any?> ObjCNotImplementedVar<T>.value: T
|
||||
typealias ObjCStringVarOf<T> = ObjCNotImplementedVar<T>
|
||||
typealias ObjCBlockVar<T> = ObjCNotImplementedVar<T>
|
||||
|
||||
@kotlin.native.internal.Intrinsic external fun getReceiverOrSuper(receiver: NativePtr, superClass: NativePtr): COpaquePointer?
|
||||
@TypedIntrinsic(IntrinsicType.OBJC_GET_RECEIVER_OR_SUPER)
|
||||
external fun getReceiverOrSuper(receiver: NativePtr, superClass: NativePtr): COpaquePointer?
|
||||
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
@@ -146,12 +149,14 @@ private fun allocObjCObject(clazz: NativePtr): NativePtr {
|
||||
return rawResult
|
||||
}
|
||||
|
||||
@kotlin.native.internal.Intrinsic
|
||||
@TypedIntrinsic(IntrinsicType.OBJC_GET_OBJC_CLASS)
|
||||
@kotlin.native.internal.ExportForCompiler
|
||||
private external fun <T : ObjCObject> getObjCClass(): NativePtr
|
||||
|
||||
@kotlin.native.internal.Intrinsic external fun getMessenger(superClass: NativePtr): COpaquePointer?
|
||||
@kotlin.native.internal.Intrinsic external fun getMessengerStret(superClass: NativePtr): COpaquePointer?
|
||||
@TypedIntrinsic(IntrinsicType.OBJC_GET_MESSENGER)
|
||||
external fun getMessenger(superClass: NativePtr): COpaquePointer?
|
||||
@TypedIntrinsic(IntrinsicType.OBJC_GET_MESSENGER_STRET)
|
||||
external fun getMessengerStret(superClass: NativePtr): COpaquePointer?
|
||||
|
||||
|
||||
internal class ObjCWeakReferenceImpl : kotlin.native.ref.WeakReferenceImpl() {
|
||||
|
||||
-2
@@ -277,8 +277,6 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
|
||||
private val packageScope by lazy { builtIns.builtInsModule.getPackage(KonanFqNames.internalPackageName).memberScope }
|
||||
|
||||
val nativePtr by lazy { packageScope.getContributedClassifier(NATIVE_PTR_NAME) as ClassDescriptor }
|
||||
val nativePtrPlusLong by lazy { nativePtr.unsubstitutedMemberScope.getContributedFunctions("plus").single() }
|
||||
val nativePtrToLong by lazy { nativePtr.unsubstitutedMemberScope.getContributedFunctions("toLong").single() }
|
||||
val getNativeNullPtr by lazy { packageScope.getContributedFunctions("getNativeNullPtr").single() }
|
||||
val immutableBlobOf by lazy {
|
||||
builtIns.builtInsModule.getPackage(KonanFqNames.packageName).memberScope.getContributedFunctions("immutableBlobOf").single()
|
||||
|
||||
-28
@@ -31,8 +31,6 @@ internal class InteropBuiltIns(builtIns: KonanBuiltIns, vararg konanPrimitives:
|
||||
|
||||
val packageScope = builtIns.builtInsModule.getPackage(InteropFqNames.packageName).memberScope
|
||||
|
||||
val getPointerSize = packageScope.getContributedFunctions("getPointerSize").single()
|
||||
|
||||
val nativePointed = packageScope.getContributedClass(InteropFqNames.nativePointedName)
|
||||
|
||||
val cPointer = this.packageScope.getContributedClass(InteropFqNames.cPointerName)
|
||||
@@ -54,26 +52,8 @@ internal class InteropBuiltIns(builtIns: KonanBuiltIns, vararg konanPrimitives:
|
||||
TypeUtils.getClassDescriptor(extensionReceiverParameter.type) == nativePointed
|
||||
}
|
||||
|
||||
val interpretNullablePointed = packageScope.getContributedFunctions("interpretNullablePointed").single()
|
||||
|
||||
val interpretCPointer = packageScope.getContributedFunctions("interpretCPointer").single()
|
||||
|
||||
val typeOf = packageScope.getContributedFunctions("typeOf").single()
|
||||
|
||||
val nativeMemUtils = packageScope.getContributedClass("nativeMemUtils")
|
||||
|
||||
private val primitives = arrayOf(
|
||||
arrayOf(builtIns.byte, builtIns.short, builtIns.int, builtIns.long, builtIns.float, builtIns.double),
|
||||
konanPrimitives).flatten()
|
||||
|
||||
val readPrimitive = primitives.map {
|
||||
nativeMemUtils.unsubstitutedMemberScope.getContributedFunctions("get" + it.name).single()
|
||||
}.toSet()
|
||||
|
||||
val writePrimitive = primitives.map {
|
||||
nativeMemUtils.unsubstitutedMemberScope.getContributedFunctions("put" + it.name).single()
|
||||
}.toSet()
|
||||
|
||||
val bitsToFloat = packageScope.getContributedFunctions("bitsToFloat").single()
|
||||
|
||||
val bitsToDouble = packageScope.getContributedFunctions("bitsToDouble").single()
|
||||
@@ -93,9 +73,6 @@ internal class InteropBuiltIns(builtIns: KonanBuiltIns, vararg konanPrimitives:
|
||||
|
||||
val convert = packageScope.getContributedFunctions("convert").toSet()
|
||||
|
||||
val readBits = packageScope.getContributedFunctions("readBits").single()
|
||||
val writeBits = packageScope.getContributedFunctions("writeBits").single()
|
||||
|
||||
val cFunctionPointerInvokes = packageScope.getContributedFunctions(OperatorNameConventions.INVOKE.asString())
|
||||
.filter {
|
||||
val extensionReceiverParameter = it.extensionReceiverParameter
|
||||
@@ -135,11 +112,6 @@ internal class InteropBuiltIns(builtIns: KonanBuiltIns, vararg konanPrimitives:
|
||||
|
||||
val objCObjectRawPtr = packageScope.getContributedFunctions("objcPtr").single()
|
||||
|
||||
val getObjCReceiverOrSuper = packageScope.getContributedFunctions("getReceiverOrSuper").single()
|
||||
|
||||
val getObjCMessenger = packageScope.getContributedFunctions("getMessenger").single()
|
||||
val getObjCMessengerStret = packageScope.getContributedFunctions("getMessengerStret").single()
|
||||
|
||||
val interpretObjCPointerOrNull = packageScope.getContributedFunctions("interpretObjCPointerOrNull").single()
|
||||
val interpretObjCPointer = packageScope.getContributedFunctions("interpretObjCPointer").single()
|
||||
|
||||
|
||||
+329
-51
@@ -1,9 +1,14 @@
|
||||
package org.jetbrains.kotlin.backend.konan.llvm
|
||||
|
||||
import kotlinx.cinterop.cValuesOf
|
||||
import llvm.*
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.TypedIntrinsic
|
||||
import org.jetbrains.kotlin.backend.konan.reportCompilationError
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrVararg
|
||||
import org.jetbrains.kotlin.ir.expressions.getTypeArgument
|
||||
import org.jetbrains.kotlin.ir.types.getClass
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
private enum class IntrinsicType {
|
||||
@@ -36,11 +41,35 @@ private enum class IntrinsicType {
|
||||
SIGNED_COMPARE_TO,
|
||||
UNSIGNED_COMPARE_TO,
|
||||
NOT,
|
||||
TO_BITS,
|
||||
FROM_BITS
|
||||
REINTERPRET,
|
||||
ARE_EQUAL_BY_VALUE,
|
||||
IEEE_754_EQUALS,
|
||||
// OBJC
|
||||
OBJC_GET_MESSENGER,
|
||||
OBJC_GET_MESSENGER_STRET,
|
||||
OBJC_GET_OBJC_CLASS,
|
||||
OBJC_GET_RECEIVER_OR_SUPER,
|
||||
// Other
|
||||
GET_CLASS_TYPE_INFO,
|
||||
READ_BITS,
|
||||
WRITE_BITS,
|
||||
CREATE_UNINITIALIZED_INSTANCE,
|
||||
LIST_OF_INTERNAL,
|
||||
IDENTITY,
|
||||
GET_CONTINUATION,
|
||||
// Interop
|
||||
READ_PRIMITIVE,
|
||||
WRITE_PRIMITIVE,
|
||||
GET_POINTER_SIZE,
|
||||
NATIVE_PTR_TO_LONG,
|
||||
NATIVE_PTR_PLUS_LONG,
|
||||
GET_NATIVE_NULL_PTR
|
||||
}
|
||||
|
||||
internal class IntrinsicGenerator(val codegen: CodeGenerator) {
|
||||
internal class IntrinsicGenerator(private val codegen: CodeGenerator,
|
||||
private val lifetimeCalculator: (IrElement) -> Lifetime,
|
||||
private val continuationProvider: () -> LLVMValueRef,
|
||||
private val exceptionHandlerProvider: () -> ExceptionHandler) {
|
||||
|
||||
private val context = codegen.context
|
||||
|
||||
@@ -54,48 +83,297 @@ internal class IntrinsicGenerator(val codegen: CodeGenerator) {
|
||||
return IntrinsicType.valueOf(value)
|
||||
}
|
||||
|
||||
fun evaluateCall(callSite: IrCall, args: List<LLVMValueRef>, generationContext: FunctionGenerationContext, exceptionHandler: ExceptionHandler): LLVMValueRef =
|
||||
generationContext.evaluateCall(callSite, args, exceptionHandler)
|
||||
fun evaluateCall(callSite: IrCall, args: List<LLVMValueRef>, generationContext: FunctionGenerationContext): LLVMValueRef =
|
||||
generationContext.evaluateCall(callSite, args)
|
||||
|
||||
// Assuming that we checked for `TypedIntrinsic` annotation presence.
|
||||
private fun FunctionGenerationContext.evaluateCall(callSite: IrCall, args: List<LLVMValueRef>, exceptionHandler: ExceptionHandler): LLVMValueRef {
|
||||
val result = when (getIntrinsicType(callSite)) {
|
||||
IntrinsicType.PLUS -> emitPlus(args)
|
||||
IntrinsicType.MINUS -> emitMinus(args)
|
||||
IntrinsicType.TIMES -> emitTimes(args)
|
||||
IntrinsicType.SIGNED_DIV -> emitSignedDiv(args, exceptionHandler)
|
||||
IntrinsicType.SIGNED_REM -> emitSignedRem(args, exceptionHandler)
|
||||
IntrinsicType.UNSIGNED_DIV -> emitUnsignedDiv(args, exceptionHandler)
|
||||
IntrinsicType.UNSIGNED_REM -> emitUnsignedRem(args, exceptionHandler)
|
||||
IntrinsicType.INC -> emitInc(args)
|
||||
IntrinsicType.DEC -> emitDec(args)
|
||||
IntrinsicType.UNARY_PLUS -> emitUnaryPlus(args)
|
||||
IntrinsicType.UNARY_MINUS -> emitUnaryMinus(args)
|
||||
IntrinsicType.SHL -> emitShl(args)
|
||||
IntrinsicType.SHR -> emitShr(args)
|
||||
IntrinsicType.USHR -> emitUshr(args)
|
||||
IntrinsicType.AND -> emitAnd(args)
|
||||
IntrinsicType.OR -> emitOr(args)
|
||||
IntrinsicType.XOR -> emitXor(args)
|
||||
IntrinsicType.INV -> emitInv(args)
|
||||
IntrinsicType.SIGNED_COMPARE_TO -> emitSignedCompareTo(args)
|
||||
IntrinsicType.UNSIGNED_COMPARE_TO -> emitUnsignedCompareTo(args)
|
||||
IntrinsicType.NOT -> emitNot(args)
|
||||
IntrinsicType.FROM_BITS -> emitReinterpret(callSite, args)
|
||||
IntrinsicType.TO_BITS -> emitReinterpret(callSite, args)
|
||||
IntrinsicType.SIGN_EXTEND -> emitSignExtend(callSite, args)
|
||||
IntrinsicType.ZERO_EXTEND -> emitZeroExtend(callSite, args)
|
||||
IntrinsicType.INT_TRUNCATE -> emitIntTruncate(callSite, args)
|
||||
IntrinsicType.SIGNED_TO_FLOAT -> emitSignedToFloat(callSite, args)
|
||||
IntrinsicType.UNSIGNED_TO_FLOAT -> emitUnsignedToFloat(callSite, args)
|
||||
IntrinsicType.FLOAT_TO_SIGNED -> emitFloatToSigned(callSite, args)
|
||||
IntrinsicType.FLOAT_EXTEND -> emitFloatExtend(callSite, args)
|
||||
IntrinsicType.FLOAT_TRUNCATE -> emitFloatTruncate(callSite, args)
|
||||
private fun FunctionGenerationContext.evaluateCall(callSite: IrCall, args: List<LLVMValueRef>): LLVMValueRef =
|
||||
when (getIntrinsicType(callSite)) {
|
||||
IntrinsicType.PLUS -> emitPlus(args)
|
||||
IntrinsicType.MINUS -> emitMinus(args)
|
||||
IntrinsicType.TIMES -> emitTimes(args)
|
||||
IntrinsicType.SIGNED_DIV -> emitSignedDiv(args)
|
||||
IntrinsicType.SIGNED_REM -> emitSignedRem(args)
|
||||
IntrinsicType.UNSIGNED_DIV -> emitUnsignedDiv(args)
|
||||
IntrinsicType.UNSIGNED_REM -> emitUnsignedRem(args)
|
||||
IntrinsicType.INC -> emitInc(args)
|
||||
IntrinsicType.DEC -> emitDec(args)
|
||||
IntrinsicType.UNARY_PLUS -> emitUnaryPlus(args)
|
||||
IntrinsicType.UNARY_MINUS -> emitUnaryMinus(args)
|
||||
IntrinsicType.SHL -> emitShl(args)
|
||||
IntrinsicType.SHR -> emitShr(args)
|
||||
IntrinsicType.USHR -> emitUshr(args)
|
||||
IntrinsicType.AND -> emitAnd(args)
|
||||
IntrinsicType.OR -> emitOr(args)
|
||||
IntrinsicType.XOR -> emitXor(args)
|
||||
IntrinsicType.INV -> emitInv(args)
|
||||
IntrinsicType.SIGNED_COMPARE_TO -> emitSignedCompareTo(args)
|
||||
IntrinsicType.UNSIGNED_COMPARE_TO -> emitUnsignedCompareTo(args)
|
||||
IntrinsicType.NOT -> emitNot(args)
|
||||
IntrinsicType.REINTERPRET -> emitReinterpret(callSite, args)
|
||||
IntrinsicType.SIGN_EXTEND -> emitSignExtend(callSite, args)
|
||||
IntrinsicType.ZERO_EXTEND -> emitZeroExtend(callSite, args)
|
||||
IntrinsicType.INT_TRUNCATE -> emitIntTruncate(callSite, args)
|
||||
IntrinsicType.SIGNED_TO_FLOAT -> emitSignedToFloat(callSite, args)
|
||||
IntrinsicType.UNSIGNED_TO_FLOAT -> emitUnsignedToFloat(callSite, args)
|
||||
IntrinsicType.FLOAT_TO_SIGNED -> emitFloatToSigned(callSite, args)
|
||||
IntrinsicType.FLOAT_EXTEND -> emitFloatExtend(callSite, args)
|
||||
IntrinsicType.FLOAT_TRUNCATE -> emitFloatTruncate(callSite, args)
|
||||
IntrinsicType.ARE_EQUAL_BY_VALUE -> emitAreEqualByValue(args)
|
||||
IntrinsicType.IEEE_754_EQUALS -> emitIeee754Equals(args)
|
||||
IntrinsicType.OBJC_GET_MESSENGER -> emitObjCGetMessenger(args, isStret = false)
|
||||
IntrinsicType.OBJC_GET_MESSENGER_STRET -> emitObjCGetMessenger(args, isStret = true)
|
||||
IntrinsicType.OBJC_GET_OBJC_CLASS -> emitGetObjCClass(callSite)
|
||||
IntrinsicType.OBJC_GET_RECEIVER_OR_SUPER -> emitGetReceiverOrSuper(args)
|
||||
IntrinsicType.GET_CLASS_TYPE_INFO -> emitGetClassTypeInfo(callSite)
|
||||
IntrinsicType.READ_BITS -> emitReadBits(args)
|
||||
IntrinsicType.WRITE_BITS -> emitWriteBits(args)
|
||||
IntrinsicType.READ_PRIMITIVE -> emitReadPrimitive(callSite, args)
|
||||
IntrinsicType.WRITE_PRIMITIVE -> emitWritePrimitive(callSite, args)
|
||||
IntrinsicType.GET_POINTER_SIZE -> emitGetPointerSize()
|
||||
IntrinsicType.CREATE_UNINITIALIZED_INSTANCE -> emitCreateUninitializedInstance(callSite)
|
||||
IntrinsicType.NATIVE_PTR_TO_LONG -> emitNativePtrToLong(callSite, args)
|
||||
IntrinsicType.NATIVE_PTR_PLUS_LONG -> emitNativePtrPlusLong(args)
|
||||
IntrinsicType.GET_NATIVE_NULL_PTR -> emitGetNativeNullPtr()
|
||||
IntrinsicType.LIST_OF_INTERNAL -> emitListOfInternal(callSite, args)
|
||||
IntrinsicType.IDENTITY -> emitIdentity(args)
|
||||
IntrinsicType.GET_CONTINUATION -> emitGetContinuation()
|
||||
}
|
||||
|
||||
private fun FunctionGenerationContext.emitGetContinuation(): LLVMValueRef =
|
||||
continuationProvider()
|
||||
|
||||
private fun FunctionGenerationContext.emitIdentity(args: List<LLVMValueRef>): LLVMValueRef =
|
||||
args.single()
|
||||
|
||||
private fun FunctionGenerationContext.emitListOfInternal(callSite: IrCall, args: List<LLVMValueRef>): LLVMValueRef {
|
||||
val varargExpression = callSite.getValueArgument(0) as IrVararg
|
||||
val vararg = args.single()
|
||||
|
||||
val length = varargExpression.elements.size
|
||||
// TODO: store length in `vararg` itself when more abstract types will be used for values.
|
||||
|
||||
val array = constPointer(vararg)
|
||||
// Note: dirty hack here: `vararg` has type `Array<out E>`, but `createConstArrayList` expects `Array<E>`;
|
||||
// however `vararg` is immutable, and in current implementation it has type `Array<E>`,
|
||||
// so let's ignore this mismatch currently for simplicity.
|
||||
|
||||
return context.llvm.staticData.createConstArrayList(array, length).llvm
|
||||
}
|
||||
|
||||
private fun FunctionGenerationContext.emitGetNativeNullPtr(): LLVMValueRef =
|
||||
kNullInt8Ptr
|
||||
|
||||
private fun FunctionGenerationContext.emitNativePtrPlusLong(args: List<LLVMValueRef>): LLVMValueRef =
|
||||
gep(args[0], args[1])
|
||||
|
||||
private fun FunctionGenerationContext.emitNativePtrToLong(callSite: IrCall, args: List<LLVMValueRef>): LLVMValueRef {
|
||||
val intPtrValue = ptrToInt(args.single(), codegen.intPtrType)
|
||||
val resultType = callSite.llvmReturnType
|
||||
return if (resultType == intPtrValue.type) {
|
||||
intPtrValue
|
||||
} else {
|
||||
LLVMBuildSExt(builder, intPtrValue, resultType, "")!!
|
||||
}
|
||||
assert(result.type == callSite.llvmReturnType) {
|
||||
"Substitution of ${callSite.symbol.owner.functionName} has wrong result type"
|
||||
}
|
||||
|
||||
private fun FunctionGenerationContext.emitCreateUninitializedInstance(callSite: IrCall): LLVMValueRef {
|
||||
val typeParameterT = context.ir.symbols.createUninitializedInstance.descriptor.typeParameters[0]
|
||||
val enumClass = callSite.getTypeArgument(typeParameterT)!!
|
||||
val enumIrClass = enumClass.getClass()!!
|
||||
return allocInstance(enumIrClass, lifetimeCalculator(callSite))
|
||||
}
|
||||
|
||||
private fun FunctionGenerationContext.emitGetPointerSize(): LLVMValueRef =
|
||||
Int32(LLVMPointerSize(codegen.llvmTargetData)).llvm
|
||||
|
||||
private fun FunctionGenerationContext.emitReadPrimitive(callSite: IrCall, args: List<LLVMValueRef>): LLVMValueRef {
|
||||
val pointerType = pointerType(callSite.llvmReturnType)
|
||||
val rawPointer = args.last()
|
||||
val pointer = bitcast(pointerType, rawPointer)
|
||||
return load(pointer)
|
||||
}
|
||||
|
||||
private fun FunctionGenerationContext.emitWritePrimitive(callSite: IrCall, args: List<LLVMValueRef>): LLVMValueRef {
|
||||
val function = callSite.symbol.owner
|
||||
val pointerType = pointerType(codegen.getLLVMType(function.valueParameters.last().type))
|
||||
val rawPointer = args[1]
|
||||
val pointer = bitcast(pointerType, rawPointer)
|
||||
store(args[2], pointer)
|
||||
return codegen.theUnitInstanceRef.llvm
|
||||
}
|
||||
|
||||
private fun FunctionGenerationContext.emitReadBits(args: List<LLVMValueRef>): LLVMValueRef {
|
||||
val ptr = args[0]
|
||||
assert(ptr.type == int8TypePtr)
|
||||
|
||||
val offset = extractConstUnsignedInt(args[1])
|
||||
val size = extractConstUnsignedInt(args[2]).toInt()
|
||||
val signed = extractConstUnsignedInt(args[3]) != 0L
|
||||
|
||||
val prefixBitsNum = (offset % 8).toInt()
|
||||
val suffixBitsNum = (8 - ((size + offset) % 8).toInt()) % 8
|
||||
|
||||
// Note: LLVM allows to read without padding tail up to byte boundary, but the result seems to be incorrect.
|
||||
|
||||
val bitsWithPaddingNum = prefixBitsNum + size + suffixBitsNum
|
||||
val bitsWithPaddingType = LLVMIntType(bitsWithPaddingNum)!!
|
||||
|
||||
val bitsWithPaddingPtr = bitcast(org.jetbrains.kotlin.backend.konan.llvm.pointerType(bitsWithPaddingType), gep(ptr, org.jetbrains.kotlin.backend.konan.llvm.Int64(offset / 8).llvm))
|
||||
val bitsWithPadding = load(bitsWithPaddingPtr).setUnaligned()
|
||||
|
||||
val bits = shr(
|
||||
shl(bitsWithPadding, suffixBitsNum),
|
||||
prefixBitsNum + suffixBitsNum, signed
|
||||
)
|
||||
return when {
|
||||
bitsWithPaddingNum == 64 -> bits
|
||||
bitsWithPaddingNum > 64 -> trunc(bits, org.jetbrains.kotlin.backend.konan.llvm.int64Type)
|
||||
else -> ext(bits, org.jetbrains.kotlin.backend.konan.llvm.int64Type, signed)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun FunctionGenerationContext.emitWriteBits(args: List<LLVMValueRef>): LLVMValueRef {
|
||||
val ptr = args[0]
|
||||
assert(ptr.type == int8TypePtr)
|
||||
|
||||
val offset = extractConstUnsignedInt(args[1])
|
||||
val size = extractConstUnsignedInt(args[2]).toInt()
|
||||
|
||||
val value = args[3]
|
||||
assert(value.type == int64Type)
|
||||
|
||||
val bitsType = LLVMIntType(size)!!
|
||||
|
||||
val prefixBitsNum = (offset % 8).toInt()
|
||||
val suffixBitsNum = (8 - ((size + offset) % 8).toInt()) % 8
|
||||
|
||||
val bitsWithPaddingNum = prefixBitsNum + size + suffixBitsNum
|
||||
val bitsWithPaddingType = LLVMIntType(bitsWithPaddingNum)!!
|
||||
|
||||
// 0011111000:
|
||||
val discardBitsMask = LLVMConstShl(
|
||||
LLVMConstZExt(
|
||||
LLVMConstAllOnes(bitsType), // 11111
|
||||
bitsWithPaddingType
|
||||
), // 1111100000
|
||||
LLVMConstInt(bitsWithPaddingType, prefixBitsNum.toLong(), 0)
|
||||
)
|
||||
|
||||
val preservedBitsMask = LLVMConstNot(discardBitsMask)!!
|
||||
|
||||
val bitsWithPaddingPtr = bitcast(pointerType(bitsWithPaddingType), gep(ptr, Int64(offset / 8).llvm))
|
||||
|
||||
val bits = trunc(value, bitsType)
|
||||
|
||||
val bitsToStore = if (prefixBitsNum == 0 && suffixBitsNum == 0) {
|
||||
bits
|
||||
} else {
|
||||
val previousValue = load(bitsWithPaddingPtr).setUnaligned()
|
||||
val preservedBits = and(previousValue, preservedBitsMask)
|
||||
val bitsWithPadding = shl(zext(bits, bitsWithPaddingType), prefixBitsNum)
|
||||
|
||||
or(bitsWithPadding, preservedBits)
|
||||
}
|
||||
llvm.LLVMBuildStore(builder, bitsToStore, bitsWithPaddingPtr)!!.setUnaligned()
|
||||
return codegen.theUnitInstanceRef.llvm
|
||||
}
|
||||
|
||||
private fun extractConstUnsignedInt(value: LLVMValueRef): Long {
|
||||
assert(LLVMIsConstant(value) != 0)
|
||||
return LLVMConstIntGetZExtValue(value)
|
||||
}
|
||||
|
||||
private fun FunctionGenerationContext.emitGetClassTypeInfo(callSite: IrCall): LLVMValueRef {
|
||||
val typeArgument = callSite.getTypeArgument(0)!!
|
||||
val typeArgumentClass = typeArgument.getClass()
|
||||
return if (typeArgumentClass == null) {
|
||||
// Should not happen anymore, but it is safer to handle this case.
|
||||
unreachable()
|
||||
kNullInt8Ptr
|
||||
} else {
|
||||
val typeInfo = codegen.typeInfoValue(typeArgumentClass)
|
||||
LLVMConstBitCast(typeInfo, kInt8Ptr)!!
|
||||
}
|
||||
}
|
||||
|
||||
private fun FunctionGenerationContext.emitGetReceiverOrSuper(args: List<LLVMValueRef>): LLVMValueRef {
|
||||
assert(args.size == 2)
|
||||
val receiver = args[0]
|
||||
val superClass = args[1]
|
||||
|
||||
val superClassIsNull = icmpEq(superClass, kNullInt8Ptr)
|
||||
|
||||
return ifThenElse(superClassIsNull, receiver) {
|
||||
val structType = structType(kInt8Ptr, kInt8Ptr)
|
||||
val ptr = alloca(structType)
|
||||
store(receiver, LLVMBuildGEP(builder, ptr, cValuesOf(kImmZero, kImmZero), 2, "")!!)
|
||||
store(superClass, LLVMBuildGEP(builder, ptr, cValuesOf(kImmZero, kImmOne), 2, "")!!)
|
||||
bitcast(int8TypePtr, ptr)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Find better place for these guys.
|
||||
private val kImmZero = LLVMConstInt(LLVMInt32Type(), 0, 1)!!
|
||||
private val kImmOne = LLVMConstInt(LLVMInt32Type(), 1, 1)!!
|
||||
|
||||
private fun FunctionGenerationContext.emitGetObjCClass(callSite: IrCall): LLVMValueRef {
|
||||
val descriptor = callSite.descriptor.original
|
||||
val typeArgument = callSite.getTypeArgument(descriptor.typeParameters.single())
|
||||
return getObjCClass(typeArgument!!.getClass()!!, exceptionHandlerProvider())
|
||||
}
|
||||
|
||||
private fun FunctionGenerationContext.emitObjCGetMessenger(args: List<LLVMValueRef>, isStret: Boolean): LLVMValueRef {
|
||||
val messengerNameSuffix = if (isStret) "_stret" else ""
|
||||
|
||||
val functionType = functionType(int8TypePtr, true, int8TypePtr, int8TypePtr)
|
||||
|
||||
val libobjc = context.standardLlvmSymbolsOrigin
|
||||
val normalMessenger = context.llvm.externalFunction(
|
||||
"objc_msgSend$messengerNameSuffix",
|
||||
functionType,
|
||||
origin = libobjc
|
||||
)
|
||||
val superMessenger = context.llvm.externalFunction(
|
||||
"objc_msgSendSuper$messengerNameSuffix",
|
||||
functionType,
|
||||
origin = libobjc
|
||||
)
|
||||
|
||||
val superClass = args.single()
|
||||
val messenger = LLVMBuildSelect(builder,
|
||||
If = icmpEq(superClass, kNullInt8Ptr),
|
||||
Then = normalMessenger,
|
||||
Else = superMessenger,
|
||||
Name = ""
|
||||
)!!
|
||||
|
||||
return bitcast(int8TypePtr, messenger)
|
||||
}
|
||||
|
||||
private fun FunctionGenerationContext.emitAreEqualByValue(args: List<LLVMValueRef>): LLVMValueRef {
|
||||
val (first, second) = args
|
||||
assert (first.type == second.type) { "Types are different: '${llvmtype2string(first.type)}' and '${llvmtype2string(second.type)}'" }
|
||||
|
||||
return when (val typeKind = LLVMGetTypeKind(first.type)) {
|
||||
llvm.LLVMTypeKind.LLVMFloatTypeKind, llvm.LLVMTypeKind.LLVMDoubleTypeKind -> {
|
||||
val numBits = llvm.LLVMSizeOfTypeInBits(codegen.llvmTargetData, first.type).toInt()
|
||||
val integerType = llvm.LLVMIntType(numBits)!!
|
||||
icmpEq(bitcast(integerType, first), bitcast(integerType, second))
|
||||
}
|
||||
llvm.LLVMTypeKind.LLVMIntegerTypeKind, llvm.LLVMTypeKind.LLVMPointerTypeKind -> icmpEq(first, second)
|
||||
else -> error(typeKind)
|
||||
}
|
||||
}
|
||||
|
||||
private fun FunctionGenerationContext.emitIeee754Equals(args: List<LLVMValueRef>): LLVMValueRef {
|
||||
val (first, second) = args
|
||||
assert (first.type == second.type)
|
||||
{ "Types are different: '${llvmtype2string(first.type)}' and '${llvmtype2string(second.type)}'" }
|
||||
val type = LLVMGetTypeKind(first.type)
|
||||
assert (type == LLVMTypeKind.LLVMFloatTypeKind || type == LLVMTypeKind.LLVMDoubleTypeKind)
|
||||
{ "Should be of floating point kind, not: '${llvmtype2string(first.type)}'"}
|
||||
return fcmpEq(first, second)
|
||||
}
|
||||
|
||||
private fun FunctionGenerationContext.emitReinterpret(callSite: IrCall, args: List<LLVMValueRef>) =
|
||||
@@ -196,18 +474,18 @@ internal class IntrinsicGenerator(val codegen: CodeGenerator) {
|
||||
}!!
|
||||
}
|
||||
|
||||
private fun FunctionGenerationContext.emitThrowIfZero(divider: LLVMValueRef, exceptionHandler: ExceptionHandler) {
|
||||
private fun FunctionGenerationContext.emitThrowIfZero(divider: LLVMValueRef) {
|
||||
ifThen(icmpEq(divider, Zero(divider.type).llvm)) {
|
||||
val throwArithExc = codegen.llvmFunction(context.ir.symbols.throwArithmeticException.owner)
|
||||
call(throwArithExc, emptyList(), Lifetime.GLOBAL, exceptionHandler)
|
||||
call(throwArithExc, emptyList(), Lifetime.GLOBAL, exceptionHandlerProvider())
|
||||
unreachable()
|
||||
}
|
||||
}
|
||||
|
||||
private fun FunctionGenerationContext.emitSignedDiv(args: List<LLVMValueRef>, exceptionHandler: ExceptionHandler): LLVMValueRef {
|
||||
private fun FunctionGenerationContext.emitSignedDiv(args: List<LLVMValueRef>): LLVMValueRef {
|
||||
val (first, second) = args
|
||||
if (!second.type.isFloatingPoint()) {
|
||||
emitThrowIfZero(second, exceptionHandler)
|
||||
emitThrowIfZero(second)
|
||||
}
|
||||
return if (first.type.isFloatingPoint()) {
|
||||
LLVMBuildFDiv(builder, first, second, "")
|
||||
@@ -216,10 +494,10 @@ internal class IntrinsicGenerator(val codegen: CodeGenerator) {
|
||||
}!!
|
||||
}
|
||||
|
||||
private fun FunctionGenerationContext.emitSignedRem(args: List<LLVMValueRef>, exceptionHandler: ExceptionHandler): LLVMValueRef {
|
||||
private fun FunctionGenerationContext.emitSignedRem(args: List<LLVMValueRef>): LLVMValueRef {
|
||||
val (first, second) = args
|
||||
if (!second.type.isFloatingPoint()) {
|
||||
emitThrowIfZero(second, exceptionHandler)
|
||||
emitThrowIfZero(second)
|
||||
}
|
||||
return if (first.type.isFloatingPoint()) {
|
||||
LLVMBuildFRem(builder, first, second, "")
|
||||
@@ -228,15 +506,15 @@ internal class IntrinsicGenerator(val codegen: CodeGenerator) {
|
||||
}!!
|
||||
}
|
||||
|
||||
private fun FunctionGenerationContext.emitUnsignedDiv(args: List<LLVMValueRef>, exceptionHandler: ExceptionHandler): LLVMValueRef {
|
||||
private fun FunctionGenerationContext.emitUnsignedDiv(args: List<LLVMValueRef>): LLVMValueRef {
|
||||
val (first, second) = args
|
||||
emitThrowIfZero(second, exceptionHandler)
|
||||
emitThrowIfZero(second)
|
||||
return LLVMBuildUDiv(builder, first, second, "")!!
|
||||
}
|
||||
|
||||
private fun FunctionGenerationContext.emitUnsignedRem(args: List<LLVMValueRef>, exceptionHandler: ExceptionHandler): LLVMValueRef {
|
||||
private fun FunctionGenerationContext.emitUnsignedRem(args: List<LLVMValueRef>): LLVMValueRef {
|
||||
val (first, second) = args
|
||||
emitThrowIfZero(second, exceptionHandler)
|
||||
emitThrowIfZero(second)
|
||||
return LLVMBuildURem(builder, first, second, "")!!
|
||||
}
|
||||
|
||||
|
||||
+7
-287
@@ -291,13 +291,12 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
|
||||
val codegen = CodeGenerator(context)
|
||||
|
||||
val intrinsicGenerator = IntrinsicGenerator(codegen)
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
// TODO: consider eliminating mutable state
|
||||
private var currentCodeContext: CodeContext = TopLevelCodeContext
|
||||
|
||||
private val intrinsicGenerator = IntrinsicGenerator(codegen,
|
||||
::resultLifetime, ::getContinuation, { currentCodeContext.exceptionHandler })
|
||||
|
||||
|
||||
/**
|
||||
* Fake [CodeContext] that doesn't support any operation.
|
||||
@@ -1799,8 +1798,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
return codegen.theUnitInstanceRef.llvm
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
// TODO: should be unified with other intrinsics
|
||||
private fun evaluateSpecialIntrinsicCall(expression: IrFunctionAccessExpression): LLVMValueRef? {
|
||||
val function = expression.symbol.owner
|
||||
|
||||
@@ -2097,8 +2095,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
args + getContinuation()
|
||||
else args
|
||||
return when {
|
||||
function.isTypedIntrinsic -> intrinsicGenerator.evaluateCall(callee, args, functionGenerationContext, currentCodeContext.exceptionHandler)
|
||||
function.isIntrinsic -> evaluateIntrinsicCall(callee, argsWithContinuationIfNeeded)
|
||||
function.isTypedIntrinsic -> intrinsicGenerator.evaluateCall(callee, args, functionGenerationContext)
|
||||
function.isIntrinsic -> context.reportCompilationError("Unexpected @Intrinsic function: ${function.name.asString()}")
|
||||
function.origin == IrDeclarationOrigin.IR_BUILTINS_STUB -> evaluateOperatorCall(callee, argsWithContinuationIfNeeded)
|
||||
function is ConstructorDescriptor -> evaluateConstructorCall(callee, argsWithContinuationIfNeeded)
|
||||
else -> evaluateSimpleFunctionCall(function, argsWithContinuationIfNeeded, resultLifetime, callee.superQualifierSymbol?.owner)
|
||||
@@ -2198,233 +2196,6 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
// TODO: Move to [IntrinsicsGenerator]
|
||||
private fun evaluateIntrinsicCall(callee: IrCall, args: List<LLVMValueRef>): LLVMValueRef {
|
||||
val descriptor = callee.descriptor.original
|
||||
val function = callee.symbol.owner
|
||||
val name = descriptor.fqNameUnsafe.asString()
|
||||
|
||||
when (name) {
|
||||
"kotlin.native.internal.areEqualByValue" -> {
|
||||
val arg0 = args[0]
|
||||
val arg1 = args[1]
|
||||
assert (arg0.type == arg1.type,
|
||||
{ "Types are different: '${llvmtype2string(arg0.type)}' and '${llvmtype2string(arg1.type)}'" })
|
||||
|
||||
val typeKind = LLVMGetTypeKind(arg0.type)
|
||||
with (functionGenerationContext) {
|
||||
return when (typeKind) {
|
||||
LLVMTypeKind.LLVMFloatTypeKind, LLVMTypeKind.LLVMDoubleTypeKind -> {
|
||||
val numBits = LLVMSizeOfTypeInBits(codegen.llvmTargetData, arg0.type).toInt()
|
||||
val integerType = LLVMIntType(numBits)!!
|
||||
icmpEq(bitcast(integerType, arg0), bitcast(integerType, arg1))
|
||||
}
|
||||
|
||||
LLVMTypeKind.LLVMIntegerTypeKind, LLVMTypeKind.LLVMPointerTypeKind -> icmpEq(arg0, arg1)
|
||||
|
||||
else -> error(typeKind)
|
||||
}
|
||||
}
|
||||
}
|
||||
"kotlin.native.internal.ieee754Equals" -> {
|
||||
val arg0 = args[0]
|
||||
val arg1 = args[1]
|
||||
assert (arg0.type == arg1.type,
|
||||
{ "Types are different: '${llvmtype2string(arg0.type)}' and '${llvmtype2string(arg1.type)}'" })
|
||||
val type = LLVMGetTypeKind(arg0.type)
|
||||
assert (type == LLVMTypeKind.LLVMFloatTypeKind || type == LLVMTypeKind.LLVMDoubleTypeKind,
|
||||
{ "Should be of floating point kind, not: '${llvmtype2string(arg0.type)}'"})
|
||||
return functionGenerationContext.fcmpEq(arg0, arg1)
|
||||
|
||||
}
|
||||
"kotlin.native.internal.getContinuation" -> return getContinuation()
|
||||
}
|
||||
|
||||
val interop = context.interopBuiltIns
|
||||
|
||||
return when (descriptor) {
|
||||
interop.interpretNullablePointed, interop.interpretCPointer,
|
||||
interop.nativePointedGetRawPointer, interop.cPointerGetRawValue, // TODO: implement through `reinterpret`
|
||||
context.ir.symbols.reinterpret.descriptor -> args.single()
|
||||
|
||||
in interop.readPrimitive -> {
|
||||
val pointerType = pointerType(codegen.getLLVMType(function.returnType))
|
||||
val rawPointer = args.last()
|
||||
val pointer = functionGenerationContext.bitcast(pointerType, rawPointer)
|
||||
functionGenerationContext.load(pointer)
|
||||
}
|
||||
in interop.writePrimitive -> {
|
||||
val pointerType = pointerType(codegen.getLLVMType(function.valueParameters.last().type))
|
||||
val rawPointer = args[1]
|
||||
val pointer = functionGenerationContext.bitcast(pointerType, rawPointer)
|
||||
functionGenerationContext.store(args[2], pointer)
|
||||
codegen.theUnitInstanceRef.llvm
|
||||
}
|
||||
context.nativePtrPlusLong -> functionGenerationContext.gep(args[0], args[1])
|
||||
context.getNativeNullPtr -> kNullInt8Ptr
|
||||
interop.getPointerSize -> Int32(LLVMPointerSize(codegen.llvmTargetData)).llvm
|
||||
context.nativePtrToLong -> {
|
||||
val intPtrValue = functionGenerationContext.ptrToInt(args.single(), codegen.intPtrType)
|
||||
val resultType = functionGenerationContext.getLLVMType(function.returnType)
|
||||
|
||||
if (resultType == intPtrValue.type) {
|
||||
intPtrValue
|
||||
} else {
|
||||
LLVMBuildSExt(functionGenerationContext.builder, intPtrValue, resultType, "")!!
|
||||
}
|
||||
}
|
||||
|
||||
interop.getObjCReceiverOrSuper -> {
|
||||
genGetObjCReceiverOrSuper(args)
|
||||
}
|
||||
|
||||
interop.getObjCClass -> {
|
||||
val typeArgument = callee.getTypeArgument(descriptor.typeParameters.single())
|
||||
val irClass = typeArgument!!.getClass()!!
|
||||
genGetObjCClass(irClass)
|
||||
}
|
||||
|
||||
interop.getObjCMessenger -> {
|
||||
genGetObjCMessenger(args, isStret = false)
|
||||
}
|
||||
interop.getObjCMessengerStret -> {
|
||||
genGetObjCMessenger(args, isStret = true)
|
||||
}
|
||||
|
||||
interop.readBits -> genReadBits(args)
|
||||
interop.writeBits -> genWriteBits(args)
|
||||
|
||||
context.ir.symbols.getClassTypeInfo.descriptor -> {
|
||||
val typeArgument = callee.getTypeArgument(0)!!
|
||||
val typeArgumentClass = typeArgument.getClass()
|
||||
if (typeArgumentClass == null) {
|
||||
// Should not happen anymore, but it is safer to handle this case.
|
||||
functionGenerationContext.unreachable()
|
||||
kNullInt8Ptr
|
||||
} else {
|
||||
val typeInfo = codegen.typeInfoValue(typeArgumentClass)
|
||||
LLVMConstBitCast(typeInfo, kInt8Ptr)!!
|
||||
}
|
||||
}
|
||||
|
||||
context.ir.symbols.createUninitializedInstance.descriptor -> {
|
||||
val typeParameterT = context.ir.symbols.createUninitializedInstance.descriptor.typeParameters[0]
|
||||
val enumClass = callee.getTypeArgument(typeParameterT)!!
|
||||
val enumIrClass = enumClass.getClass()!!
|
||||
functionGenerationContext.allocInstance(enumIrClass, resultLifetime(callee))
|
||||
}
|
||||
|
||||
context.ir.symbols.listOfInternal.descriptor -> {
|
||||
val varargExpression = callee.getValueArgument(0) as IrVararg
|
||||
val vararg = args.single()
|
||||
|
||||
val length = varargExpression.elements.size
|
||||
// TODO: store length in `vararg` itself when more abstract types will be used for values.
|
||||
|
||||
val array = constPointer(vararg)
|
||||
// Note: dirty hack here: `vararg` has type `Array<out E>`, but `createConstArrayList` expects `Array<E>`;
|
||||
// however `vararg` is immutable, and in current implementation it has type `Array<E>`,
|
||||
// so let's ignore this mismatch currently for simplicity.
|
||||
|
||||
return context.llvm.staticData.createConstArrayList(array, length).llvm
|
||||
}
|
||||
|
||||
else -> TODO(callee.descriptor.original.toString())
|
||||
}
|
||||
}
|
||||
|
||||
private fun genReadBits(args: List<LLVMValueRef>): LLVMValueRef {
|
||||
val ptr = args[0]
|
||||
assert(ptr.type == int8TypePtr)
|
||||
|
||||
val offset = extractConstUnsignedInt(args[1])
|
||||
val size = extractConstUnsignedInt(args[2]).toInt()
|
||||
val signed = extractConstUnsignedInt(args[3]) != 0L
|
||||
|
||||
val prefixBitsNum = (offset % 8).toInt()
|
||||
val suffixBitsNum = (8 - ((size + offset) % 8).toInt()) % 8
|
||||
|
||||
// Note: LLVM allows to read without padding tail up to byte boundary, but the result seems to be incorrect.
|
||||
|
||||
val bitsWithPaddingNum = prefixBitsNum + size + suffixBitsNum
|
||||
val bitsWithPaddingType = LLVMIntType(bitsWithPaddingNum)!!
|
||||
|
||||
with (functionGenerationContext) {
|
||||
val bitsWithPaddingPtr = bitcast(pointerType(bitsWithPaddingType), gep(ptr, Int64(offset / 8).llvm))
|
||||
val bitsWithPadding = load(bitsWithPaddingPtr).setUnaligned()
|
||||
|
||||
val bits = shr(
|
||||
shl(bitsWithPadding, suffixBitsNum),
|
||||
prefixBitsNum + suffixBitsNum, signed
|
||||
)
|
||||
|
||||
return if (bitsWithPaddingNum == 64) {
|
||||
bits
|
||||
} else if (bitsWithPaddingNum > 64) {
|
||||
trunc(bits, int64Type)
|
||||
} else {
|
||||
ext(bits, int64Type, signed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun genWriteBits(args: List<LLVMValueRef>): LLVMValueRef {
|
||||
val ptr = args[0]
|
||||
assert(ptr.type == int8TypePtr)
|
||||
|
||||
val offset = extractConstUnsignedInt(args[1])
|
||||
val size = extractConstUnsignedInt(args[2]).toInt()
|
||||
|
||||
val value = args[3]
|
||||
assert(value.type == int64Type)
|
||||
|
||||
val bitsType = LLVMIntType(size)!!
|
||||
|
||||
val prefixBitsNum = (offset % 8).toInt()
|
||||
val suffixBitsNum = (8 - ((size + offset) % 8).toInt()) % 8
|
||||
|
||||
val bitsWithPaddingNum = prefixBitsNum + size + suffixBitsNum
|
||||
val bitsWithPaddingType = LLVMIntType(bitsWithPaddingNum)!!
|
||||
|
||||
// 0011111000:
|
||||
val discardBitsMask = LLVMConstShl(
|
||||
LLVMConstZExt(
|
||||
LLVMConstAllOnes(bitsType), // 11111
|
||||
bitsWithPaddingType
|
||||
), // 1111100000
|
||||
LLVMConstInt(bitsWithPaddingType, prefixBitsNum.toLong(), 0)
|
||||
)
|
||||
|
||||
val preservedBitsMask = LLVMConstNot(discardBitsMask)!!
|
||||
|
||||
with (functionGenerationContext) {
|
||||
val bitsWithPaddingPtr = bitcast(pointerType(bitsWithPaddingType), gep(ptr, Int64(offset / 8).llvm))
|
||||
|
||||
val bits = trunc(value, bitsType)
|
||||
|
||||
val bitsToStore = if (prefixBitsNum == 0 && suffixBitsNum == 0) {
|
||||
bits
|
||||
} else {
|
||||
val previousValue = load(bitsWithPaddingPtr).setUnaligned()
|
||||
val preservedBits = and(previousValue, preservedBitsMask)
|
||||
val bitsWithPadding = shl(zext(bits, bitsWithPaddingType), prefixBitsNum)
|
||||
|
||||
or(bitsWithPadding, preservedBits)
|
||||
}
|
||||
|
||||
LLVMBuildStore(builder, bitsToStore, bitsWithPaddingPtr)!!.setUnaligned()
|
||||
}
|
||||
|
||||
return codegen.theUnitInstanceRef.llvm
|
||||
}
|
||||
|
||||
private fun extractConstUnsignedInt(value: LLVMValueRef): Long {
|
||||
assert(LLVMIsConstant(value) != 0)
|
||||
return LLVMConstIntGetZExtValue(value)
|
||||
}
|
||||
|
||||
private fun genGetObjCClass(classDescriptor: ClassDescriptor): LLVMValueRef {
|
||||
return functionGenerationContext.getObjCClass(classDescriptor, currentCodeContext.exceptionHandler)
|
||||
}
|
||||
@@ -2446,64 +2217,13 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
return call(protocolGetter, emptyList())
|
||||
}
|
||||
|
||||
private fun genGetObjCMessenger(args: List<LLVMValueRef>, isStret: Boolean): LLVMValueRef {
|
||||
val gen = functionGenerationContext
|
||||
|
||||
val messengerNameSuffix = if (isStret) "_stret" else ""
|
||||
|
||||
val functionType = functionType(int8TypePtr, true, int8TypePtr, int8TypePtr)
|
||||
|
||||
val libobjc = context.standardLlvmSymbolsOrigin
|
||||
val normalMessenger = context.llvm.externalFunction(
|
||||
"objc_msgSend$messengerNameSuffix",
|
||||
functionType,
|
||||
origin = libobjc
|
||||
)
|
||||
val superMessenger = context.llvm.externalFunction(
|
||||
"objc_msgSendSuper$messengerNameSuffix",
|
||||
functionType,
|
||||
origin = libobjc
|
||||
)
|
||||
|
||||
val superClass = args.single()
|
||||
val messenger = LLVMBuildSelect(gen.builder,
|
||||
If = gen.icmpEq(superClass, kNullInt8Ptr),
|
||||
Then = normalMessenger,
|
||||
Else = superMessenger,
|
||||
Name = ""
|
||||
)!!
|
||||
|
||||
return gen.bitcast(int8TypePtr, messenger)
|
||||
}
|
||||
|
||||
private fun genGetObjCReceiverOrSuper(args: List<LLVMValueRef>): LLVMValueRef {
|
||||
val gen = functionGenerationContext
|
||||
|
||||
assert(args.size == 2)
|
||||
val receiver = args[0]
|
||||
val superClass = args[1]
|
||||
|
||||
val superClassIsNull = gen.icmpEq(superClass, kNullInt8Ptr)
|
||||
|
||||
return gen.ifThenElse(superClassIsNull, receiver) {
|
||||
val structType = structType(kInt8Ptr, kInt8Ptr)
|
||||
val ptr = gen.alloca(structType)
|
||||
gen.store(receiver,
|
||||
LLVMBuildGEP(gen.builder, ptr, cValuesOf(kImmZero, kImmZero), 2, "")!!)
|
||||
|
||||
gen.store(superClass,
|
||||
LLVMBuildGEP(gen.builder, ptr, cValuesOf(kImmZero, kImmOne), 2, "")!!)
|
||||
|
||||
gen.bitcast(int8TypePtr, ptr)
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
private val kImmZero = LLVMConstInt(LLVMInt32Type(), 0, 1)!!
|
||||
private val kImmOne = LLVMConstInt(LLVMInt32Type(), 1, 1)!!
|
||||
private val kTrue = LLVMConstInt(LLVMInt1Type(), 1, 1)!!
|
||||
private val kFalse = LLVMConstInt(LLVMInt1Type(), 0, 1)!!
|
||||
|
||||
// TODO: Intrinsify?
|
||||
private fun evaluateOperatorCall(callee: IrCall, args: List<LLVMValueRef>): LLVMValueRef {
|
||||
context.log{"evaluateOperatorCall : origin:${ir2string(callee)}"}
|
||||
val descriptor = callee.symbol.owner
|
||||
|
||||
@@ -71,7 +71,7 @@ public actual inline fun Double.toRawBits(): Long = bits()
|
||||
public actual inline fun Double.Companion.fromBits(bits: Long): Double = kotlin.fromBits(bits)
|
||||
|
||||
@PublishedApi
|
||||
@TypedIntrinsic(IntrinsicType.FROM_BITS)
|
||||
@TypedIntrinsic(IntrinsicType.REINTERPRET)
|
||||
external internal fun fromBits(bits: Long): Double
|
||||
|
||||
/**
|
||||
@@ -99,5 +99,5 @@ public actual inline fun Float.toRawBits(): Int = bits()
|
||||
public actual inline fun Float.Companion.fromBits(bits: Int): Float = kotlin.fromBits(bits)
|
||||
|
||||
@PublishedApi
|
||||
@TypedIntrinsic(IntrinsicType.FROM_BITS)
|
||||
@TypedIntrinsic(IntrinsicType.REINTERPRET)
|
||||
external internal fun fromBits(bits: Int): Float
|
||||
|
||||
@@ -1174,7 +1174,7 @@ public final class Float private constructor(private val value: kotlin.native.in
|
||||
return bits()
|
||||
}
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.TO_BITS)
|
||||
@TypedIntrinsic(IntrinsicType.REINTERPRET)
|
||||
@PublishedApi
|
||||
external internal fun bits(): Int
|
||||
}
|
||||
@@ -1396,7 +1396,7 @@ public final class Double private constructor(private val value: kotlin.native.i
|
||||
|
||||
public override fun hashCode(): Int = bits().hashCode()
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.TO_BITS)
|
||||
@TypedIntrinsic(IntrinsicType.REINTERPRET)
|
||||
@PublishedApi
|
||||
external internal fun bits(): Long
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import kotlin.coroutines.intrinsics.*
|
||||
internal inline suspend fun <T> suspendCoroutineUninterceptedOrReturn(crossinline block: (Continuation<T>) -> Any?): T =
|
||||
returnIfSuspended<T>(block(getContinuation<T>()))
|
||||
|
||||
@Intrinsic
|
||||
@TypedIntrinsic(IntrinsicType.GET_CONTINUATION)
|
||||
@PublishedApi
|
||||
internal external fun <T> getContinuation(): Continuation<T>
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package kotlin.native.internal
|
||||
|
||||
class IntrinsicType {
|
||||
companion object {
|
||||
// Arithmetic
|
||||
const val PLUS = "PLUS"
|
||||
const val MINUS = "MINUS"
|
||||
const val TIMES = "TIMES"
|
||||
@@ -31,7 +32,30 @@ class IntrinsicType {
|
||||
const val SIGNED_COMPARE_TO = "SIGNED_COMPARE_TO"
|
||||
const val UNSIGNED_COMPARE_TO = "UNSIGNED_COMPARE_TO"
|
||||
const val NOT = "NOT"
|
||||
const val TO_BITS = "TO_BITS"
|
||||
const val FROM_BITS = "FROM_BITS"
|
||||
const val REINTERPRET = "REINTERPRET"
|
||||
const val ARE_EQUAL_BY_VALUE = "ARE_EQUAL_BY_VALUE"
|
||||
const val IEEE_754_EQUALS = "IEEE_754_EQUALS"
|
||||
// ObjC related stuff
|
||||
const val OBJC_GET_MESSENGER = "OBJC_GET_MESSENGER"
|
||||
const val OBJC_GET_MESSENGER_STRET = "OBJC_GET_MESSENGER_STRET"
|
||||
const val OBJC_GET_OBJC_CLASS = "OBJC_GET_OBJC_CLASS"
|
||||
const val OBJC_GET_RECEIVER_OR_SUPER = "OBJC_GET_RECEIVER_OR_SUPER"
|
||||
|
||||
// Other
|
||||
const val GET_CLASS_TYPE_INFO = "GET_CLASS_TYPE_INFO"
|
||||
const val READ_BITS = "READ_BITS"
|
||||
const val WRITE_BITS = "WRITE_BITS"
|
||||
const val CREATE_UNINITIALIZED_INSTANCE = "CREATE_UNINITIALIZED_INSTANCE"
|
||||
const val LIST_OF_INTERNAL = "LIST_OF_INTERNAL"
|
||||
const val IDENTITY = "IDENTITY"
|
||||
const val GET_CONTINUATION = "GET_CONTINUATION"
|
||||
|
||||
// Interop
|
||||
const val READ_PRIMITIVE = "READ_PRIMITIVE"
|
||||
const val WRITE_PRIMITIVE = "WRITE_PRIMITIVE"
|
||||
const val GET_POINTER_SIZE = "GET_POINTER_SIZE"
|
||||
const val NATIVE_PTR_TO_LONG = "NATIVE_PTR_TO_LONG"
|
||||
const val NATIVE_PTR_PLUS_LONG = "NATIVE_PTR_PLUS_LONG"
|
||||
const val GET_NATIVE_NULL_PTR = "GET_NATIVE_NULL_PTR"
|
||||
}
|
||||
}
|
||||
@@ -9,20 +9,23 @@ import kotlinx.cinterop.CPointer
|
||||
import kotlinx.cinterop.NativePointed
|
||||
import kotlinx.cinterop.NativePtr
|
||||
|
||||
@Intrinsic @PublishedApi external internal fun areEqualByValue(first: Boolean, second: Boolean): Boolean
|
||||
@Intrinsic @PublishedApi external internal fun areEqualByValue(first: Byte, second: Byte): Boolean
|
||||
@Intrinsic @PublishedApi external internal fun areEqualByValue(first: Short, second: Short): Boolean
|
||||
@Intrinsic @PublishedApi external internal fun areEqualByValue(first: Int, second: Int): Boolean
|
||||
@Intrinsic @PublishedApi external internal fun areEqualByValue(first: Long, second: Long): Boolean
|
||||
@Intrinsic @PublishedApi external internal fun areEqualByValue(first: NativePtr, second: NativePtr): Boolean
|
||||
import kotlin.native.internal.TypedIntrinsic
|
||||
import kotlin.native.internal.IntrinsicType
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.ARE_EQUAL_BY_VALUE) @PublishedApi external internal fun areEqualByValue(first: Boolean, second: Boolean): Boolean
|
||||
@TypedIntrinsic(IntrinsicType.ARE_EQUAL_BY_VALUE) @PublishedApi external internal fun areEqualByValue(first: Byte, second: Byte): Boolean
|
||||
@TypedIntrinsic(IntrinsicType.ARE_EQUAL_BY_VALUE) @PublishedApi external internal fun areEqualByValue(first: Short, second: Short): Boolean
|
||||
@TypedIntrinsic(IntrinsicType.ARE_EQUAL_BY_VALUE) @PublishedApi external internal fun areEqualByValue(first: Int, second: Int): Boolean
|
||||
@TypedIntrinsic(IntrinsicType.ARE_EQUAL_BY_VALUE) @PublishedApi external internal fun areEqualByValue(first: Long, second: Long): Boolean
|
||||
@TypedIntrinsic(IntrinsicType.ARE_EQUAL_BY_VALUE) @PublishedApi external internal fun areEqualByValue(first: NativePtr, second: NativePtr): Boolean
|
||||
|
||||
// Bitwise equality:
|
||||
@Intrinsic @PublishedApi external internal fun areEqualByValue(first: Float, second: Float): Boolean
|
||||
@Intrinsic @PublishedApi external internal fun areEqualByValue(first: Double, second: Double): Boolean
|
||||
@TypedIntrinsic(IntrinsicType.ARE_EQUAL_BY_VALUE) @PublishedApi external internal fun areEqualByValue(first: Float, second: Float): Boolean
|
||||
@TypedIntrinsic(IntrinsicType.ARE_EQUAL_BY_VALUE) @PublishedApi external internal fun areEqualByValue(first: Double, second: Double): Boolean
|
||||
|
||||
// IEEE754 equality:
|
||||
@Intrinsic @PublishedApi external internal fun ieee754Equals(first: Float, second: Float): Boolean
|
||||
@Intrinsic @PublishedApi external internal fun ieee754Equals(first: Double, second: Double): Boolean
|
||||
@TypedIntrinsic(IntrinsicType.IEEE_754_EQUALS) @PublishedApi external internal fun ieee754Equals(first: Float, second: Float): Boolean
|
||||
@TypedIntrinsic(IntrinsicType.IEEE_754_EQUALS) @PublishedApi external internal fun ieee754Equals(first: Double, second: Double): Boolean
|
||||
|
||||
// Reinterprets this value from T to R having the same binary representation (e.g. to unwrap inline class).
|
||||
@Intrinsic @PublishedApi external internal fun <T, R> T.reinterpret(): R
|
||||
@TypedIntrinsic(IntrinsicType.IDENTITY) @PublishedApi external internal fun <T, R> T.reinterpret(): R
|
||||
|
||||
@@ -62,7 +62,7 @@ internal class KClassUnsupportedImpl(private val message: String) : KClass<Any>
|
||||
internal external fun getObjectTypeInfo(obj: Any): NativePtr
|
||||
|
||||
@ExportForCompiler
|
||||
@Intrinsic
|
||||
@TypedIntrinsic(IntrinsicType.GET_CLASS_TYPE_INFO)
|
||||
internal external inline fun <reified T : Any> getClassTypeInfo(): NativePtr
|
||||
|
||||
@SymbolName("Kotlin_TypeInfo_getPackageName")
|
||||
|
||||
@@ -7,16 +7,19 @@
|
||||
|
||||
package kotlin.native.internal
|
||||
|
||||
@Intrinsic external fun getNativeNullPtr(): NativePtr
|
||||
@TypedIntrinsic(IntrinsicType.GET_NATIVE_NULL_PTR)
|
||||
external fun getNativeNullPtr(): NativePtr
|
||||
|
||||
class NativePtr @PublishedApi internal constructor(private val value: NonNullNativePtr?) {
|
||||
companion object {
|
||||
val NULL = getNativeNullPtr()
|
||||
}
|
||||
|
||||
@Intrinsic external operator fun plus(offset: Long): NativePtr
|
||||
@TypedIntrinsic(IntrinsicType.NATIVE_PTR_PLUS_LONG)
|
||||
external operator fun plus(offset: Long): NativePtr
|
||||
|
||||
@Intrinsic external fun toLong(): Long
|
||||
@TypedIntrinsic(IntrinsicType.NATIVE_PTR_TO_LONG)
|
||||
external fun toLong(): Long
|
||||
|
||||
override fun equals(other: Any?) = (other is NativePtr) && kotlin.native.internal.areEqualByValue(this, other)
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ fun <T: Enum<T>> valuesForEnum(values: Array<T>): Array<T> {
|
||||
return result as Array<T>
|
||||
}
|
||||
|
||||
@Intrinsic
|
||||
@TypedIntrinsic(IntrinsicType.CREATE_UNINITIALIZED_INSTANCE)
|
||||
internal external fun <T> createUninitializedInstance(): T
|
||||
|
||||
@Intrinsic
|
||||
@@ -150,7 +150,7 @@ fun KonanObjectToUtf8Array(value: Any?): ByteArray {
|
||||
return string.toUtf8()
|
||||
}
|
||||
|
||||
@Intrinsic
|
||||
@TypedIntrinsic(IntrinsicType.LIST_OF_INTERNAL)
|
||||
@PublishedApi
|
||||
internal fun <T> listOfInternal(vararg elements: T): List<T> {
|
||||
val result = ArrayList<T>(elements.size)
|
||||
|
||||
@@ -203,7 +203,7 @@ internal fun SearchPathResolverWithTarget.libraryMatch(candidate: KonanLibraryIm
|
||||
val candidateAbiVersion = candidate.versions.abiVersion
|
||||
val candidateLibraryVersion = candidate.versions.libraryVersion
|
||||
|
||||
if (resolverTarget != null && !candidate.targetList.contains(resolverTarget.visibleName)) {
|
||||
if (!candidate.targetList.contains(resolverTarget.visibleName)) {
|
||||
logger("skipping $candidatePath. The target doesn't match. Expected '$resolverTarget', found ${candidate.targetList}")
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user