From 592f31a969a96d5d06fd6607e8ed45902487f132 Mon Sep 17 00:00:00 2001 From: Sergey Bogolepov <1580082+sbogolepov@users.noreply.github.com> Date: Tue, 1 Oct 2019 19:03:45 +0300 Subject: [PATCH] [watchOS] Add support of watch_arm64 target. (#3404) * [watchOS] Add support of watch_arm64 target. Since there is no support of `arm64_32` in LLVM 8 we compile bitcode that was generated for `watchos_arm32` to `arm64_32-apple-watchos`. --- .../kotlin/native/interop/gen/jvm/main.kt | 10 ++++++- .../kotlin/backend/konan/BitcodeCompiler.kt | 11 +++++++- .../backend/konan/OptimizationPipeline.kt | 6 ++--- .../llvm/objcexport/BlockPointerSupport.kt | 2 +- .../objcexport/ObjCExportCodeGenerator.kt | 12 ++++++--- konan/konan.properties | 27 +++++++++++++++++++ .../kotlin/konan/target/ClangArgs.kt | 4 +-- .../jetbrains/kotlin/konan/target/Platform.kt | 2 +- 8 files changed, 61 insertions(+), 13 deletions(-) diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt index 37e38d60695..f0c4b4a84a4 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.native.interop.gen.wasm.processIdlLib import org.jetbrains.kotlin.native.interop.indexer.* import org.jetbrains.kotlin.native.interop.tool.* import kotlinx.cli.ArgParser +import org.jetbrains.kotlin.konan.target.KonanTarget import java.io.File import java.lang.IllegalArgumentException import java.nio.file.* @@ -219,6 +220,13 @@ private fun processCLib(args: Array, additionalArgs: Map = val (nativeIndex, compilation) = buildNativeIndex(library, verbose) + // Our current approach to arm64_32 support is to compile armv7k version of bitcode + // for arm64_32. That's the reason for this substitution. + // TODO: Add proper support with the next LLVM update. + val target = when (tool.target) { + KonanTarget.WATCHOS_ARM64 -> KonanTarget.WATCHOS_ARM32 + else -> tool.target + } val configuration = InteropConfiguration( library = compilation, pkgName = outKtPkg, @@ -229,7 +237,7 @@ private fun processCLib(args: Array, additionalArgs: Map = noStringConversion = def.config.noStringConversion.toSet(), exportForwardDeclarations = def.config.exportForwardDeclarations, disableDesignatedInitializerChecks = def.config.disableDesignatedInitializerChecks, - target = tool.target + target = target ) outKtFile.parentFile.mkdirs() diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BitcodeCompiler.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BitcodeCompiler.kt index fd6f2e38aa9..5f0405e4dfe 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BitcodeCompiler.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BitcodeCompiler.kt @@ -103,9 +103,18 @@ internal class BitcodeCompiler(val context: Context) { val profilingFlags = llvmProfilingFlags().map { listOf("-mllvm", it) }.flatten() + // LLVM we use does not have support for arm64_32. + // TODO: fix with LLVM update. + val targetTriple = when (context.config.target) { + KonanTarget.WATCHOS_ARM64 -> { + require(configurables is AppleConfigurables) + "arm64_32-apple-watchos${configurables.osVersionMin}" + } + else -> context.llvm.targetTriple + } val flags = mutableListOf().apply { addNonEmpty(configurables.clangFlags) - addNonEmpty(listOf("-triple", context.llvm.targetTriple)) + addNonEmpty(listOf("-triple", targetTriple)) addNonEmpty(when { optimize -> configurables.clangOptFlags debug -> configurables.clangDebugFlags diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/OptimizationPipeline.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/OptimizationPipeline.kt index 1e28eabbfef..1eb8f595f91 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/OptimizationPipeline.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/OptimizationPipeline.kt @@ -41,8 +41,8 @@ private class LlvmPipelineConfiguration(context: Context) { val targetTriple: String = context.llvm.targetTriple - // Most of these values are copied from corresponding runtime.bc - // Which is using "generic" target CPU for many case. + // Some of these values are copied from corresponding runtime.bc + // which is using "generic" target CPU for many case. // This approach is suboptimal because target-cpu="generic" limits // the set of used cpu features. // TODO: refactor KonanTarget so that we can explicitly specify @@ -55,6 +55,7 @@ private class LlvmPipelineConfiguration(context: Context) { KonanTarget.TVOS_X64 -> "core2" KonanTarget.WATCHOS_X86 -> "i386" KonanTarget.WATCHOS_X64 -> "core2" + KonanTarget.WATCHOS_ARM64, KonanTarget.WATCHOS_ARM32 -> "cortex-a7" KonanTarget.LINUX_X64 -> "x86-64" KonanTarget.MINGW_X86 -> "pentium4" @@ -68,7 +69,6 @@ private class LlvmPipelineConfiguration(context: Context) { KonanTarget.ANDROID_X86 -> "i686" KonanTarget.LINUX_MIPS32 -> "mips32r2" KonanTarget.LINUX_MIPSEL32 -> "mips32r2" - KonanTarget.WATCHOS_ARM64, KonanTarget.WASM32, is KonanTarget.ZEPHYR -> error("There is no support for ${target.name} target yet.") } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/BlockPointerSupport.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/BlockPointerSupport.kt index d15ed2682b8..c3d97fc5307 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/BlockPointerSupport.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/BlockPointerSupport.kt @@ -188,7 +188,7 @@ internal class BlockAdapterToFunctionGenerator(val objCExportCodeGenerator: ObjC } fun org.jetbrains.kotlin.backend.konan.Context.LongInt(value: Long) = - if (is64Bit()) Int64(value) else Int32(value.toInt()) + if (is64BitNSInteger()) Int64(value) else Int32(value.toInt()) private fun generateDescriptorForBlockAdapterToFunction(bridge: BlockPointerBridge): ConstValue { val numberOfParameters = bridge.numberOfParameters diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt index 9ea480accdb..e66e5c04d0a 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt @@ -27,6 +27,7 @@ import org.jetbrains.kotlin.ir.util.isInterface import org.jetbrains.kotlin.ir.util.isReal import org.jetbrains.kotlin.ir.util.parentAsClass import org.jetbrains.kotlin.konan.target.Family +import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.name.Name internal fun TypeBridge.makeNothing() = when (this) { @@ -679,7 +680,7 @@ private fun ObjCExportCodeGenerator.generateObjCImp( MethodBridge.ReturnValue.Void -> null MethodBridge.ReturnValue.HashCode -> { val kotlinHashCode = targetResult!! - if (codegen.context.is64Bit()) zext(kotlinHashCode, int64Type) else kotlinHashCode + if (codegen.context.is64BitNSInteger()) zext(kotlinHashCode, int64Type) else kotlinHashCode } is MethodBridge.ReturnValue.Mapped -> kotlinToObjC(targetResult!!, returnBridge.bridge) MethodBridge.ReturnValue.WithError.Success -> Int8(1).llvm // true @@ -781,7 +782,7 @@ private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge( MethodBridge.ReturnValue.Void -> null MethodBridge.ReturnValue.HashCode -> { - if (codegen.context.is64Bit()) { + if (codegen.context.is64BitNSInteger()) { val low = trunc(targetResult, int32Type) val high = trunc(shr(targetResult, 32, signed = false), int32Type) xor(low, high) @@ -1256,7 +1257,7 @@ private val MethodBridgeParameter.objCType: LLVMTypeRef get() = when (this) { private fun MethodBridge.ReturnValue.objCType(context: Context): LLVMTypeRef { return when (this) { MethodBridge.ReturnValue.Void -> voidType - MethodBridge.ReturnValue.HashCode -> if (context.is64Bit()) int64Type else int32Type + MethodBridge.ReturnValue.HashCode -> if (context.is64BitNSInteger()) int64Type else int32Type is MethodBridge.ReturnValue.Mapped -> this.bridge.objCType MethodBridge.ReturnValue.WithError.Success -> ObjCValueType.BOOL.llvmType @@ -1324,4 +1325,7 @@ private val TypeBridge.objCEncoding: String get() = when (this) { is ValueTypeBridge -> this.objCValueType.encoding } -internal fun Context.is64Bit(): Boolean = this.config.target.architecture.bitness == 64 +internal fun Context.is64BitNSInteger(): Boolean = this.config.target.let { + // We work with watchos_arm64 the same as we work with watchos_arm32. + it.architecture.bitness == 64 && it != KonanTarget.WATCHOS_ARM64 +} diff --git a/konan/konan.properties b/konan/konan.properties index dd672988f2b..b3e93cffafe 100644 --- a/konan/konan.properties +++ b/konan/konan.properties @@ -235,6 +235,33 @@ osVersionMinFlagLd.watchos_arm32 = -watchos_version_min osVersionMinFlagClang.watchos_arm32 = -mwatchos-version-min osVersionMin.watchos_arm32 = 5.0 +# watchOS arm64_32 +targetToolchain.macos_x64-watchos_arm64 = target-toolchain-10-macos_x64 +dependencies.macos_x64-watchos_arm64 = \ + libffi-3.2.1-3-darwin-macos \ + clang-llvm-apple-8.0.0-darwin-macos + +target-sysroot-10-watchos_arm64.default = \ + remote:internal + +arch.watchos_arm64 = arm64_32 +targetSysRoot.watchos_arm64 = target-sysroot-10-watchos_arm32 + +clangFlags.watchos_arm64 = -cc1 -emit-obj -disable-llvm-passes -x ir -mllvm -aarch64-watch-bitcode-compatibility \ + -mllvm -arm-bitcode-compatibility -mllvm -fast-isel=false -mllvm -global-isel=false +clangNooptFlags.watchos_arm64 = -O1 +clangOptFlags.watchos_arm64 = -O3 +clangDebugFlags.watchos_arm64 = -O0 +clangDynamicFlags.watchos_arm64 = + +linkerKonanFlags.watchos_arm64 = -lSystem -lc++ -lobjc -framework Foundation -sdk_version 6.0 +linkerOptimizationFlags.watchos_arm64 = -dead_strip +linkerNoDebugFlags.watchos_arm64 = -S +linkerDynamicFlags.watchos_arm64 = -dylib +osVersionMinFlagLd.watchos_arm64 = -watchos_version_min +osVersionMinFlagClang.watchos_arm64 = -mwatchos-version-min +osVersionMin.watchos_arm64 = 5.0 + # Apple's watchOS i386 simulator. targetToolchain.macos_x64-watchos_x86 = target-toolchain-10-macos_x64 dependencies.macos_x64-watchos_x86 = \ diff --git a/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/ClangArgs.kt b/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/ClangArgs.kt index 0181a01eaa2..02e5fff3f61 100644 --- a/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/ClangArgs.kt +++ b/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/ClangArgs.kt @@ -97,13 +97,13 @@ class ClangArgs(private val configurables: Configurables) : Configurables by con KonanTarget.TVOS_X64 -> listOf("-stdlib=libc++", "-isysroot", absoluteTargetSysRoot, "-mtvos-simulator-version-min=$osVersionMin") + KonanTarget.WATCHOS_ARM64, KonanTarget.WATCHOS_ARM32 -> listOf("-stdlib=libc++", "-arch", "armv7k", "-isysroot", absoluteTargetSysRoot, "-mwatchos-version-min=$osVersionMin") KonanTarget.WATCHOS_X86 -> listOf("-stdlib=libc++", "-arch", "i386", "-isysroot", absoluteTargetSysRoot, "-mwatchos-simulator-version-min=$osVersionMin") - KonanTarget.WATCHOS_ARM64 -> TODO("implement me") KonanTarget.WATCHOS_X64 -> TODO("implement me") KonanTarget.ANDROID_ARM32, KonanTarget.ANDROID_ARM64, @@ -261,6 +261,7 @@ class ClangArgs(private val configurables: Configurables) : Configurables by con "-DKONAN_CORE_SYMBOLICATION=1", "-DKONAN_HAS_CXX11_EXCEPTION_FUNCTIONS=1") + KonanTarget.WATCHOS_ARM64, KonanTarget.WATCHOS_ARM32 -> listOf("-DKONAN_OBJC_INTEROP=1", "-DKONAN_WATCHOS", @@ -280,7 +281,6 @@ class ClangArgs(private val configurables: Configurables) : Configurables by con "-DKONAN_CORE_SYMBOLICATION=1", "-DKONAN_HAS_CXX11_EXCEPTION_FUNCTIONS=1") - KonanTarget.WATCHOS_ARM64 -> TODO("implement me") KonanTarget.WATCHOS_X64 -> TODO("implement me") KonanTarget.ANDROID_ARM32 -> diff --git a/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/Platform.kt b/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/Platform.kt index b9ace4c126d..77e3e4d8f08 100644 --- a/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/Platform.kt +++ b/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/Platform.kt @@ -49,6 +49,6 @@ class PlatformManager(distribution: Distribution = Distribution(), experimental: * TODO: Don't forget to delete this field and replace all its usages to `enabled`. */ val filteredOutEnabledButNotSupported - get() = enabled.filterNot { it == KonanTarget.WATCHOS_X64 || it == KonanTarget.WATCHOS_ARM64 } + get() = enabled.filterNot { it == KonanTarget.WATCHOS_X64 } }