From c97f4a4d20041998376bbcbb22be17b85f243e15 Mon Sep 17 00:00:00 2001 From: Pavel Kunyavskiy Date: Mon, 20 Dec 2021 14:07:12 +0300 Subject: [PATCH] [K/N] Support -Xsave-llvm-ir-after compiler option --- .../org/jetbrains/kotlin/cli/bc/K2Native.kt | 2 +- .../cli/bc/K2NativeCompilerArguments.kt | 4 +-- .../kotlin/backend/konan/CompilerOutput.kt | 28 +++++++++++-------- .../backend/konan/KonanConfigurationKeys.kt | 2 +- .../backend/konan/KonanLoweringPhases.kt | 18 ++++++++++-- .../backend.native/tests/build.gradle | 9 ++++-- .../org/jetbrains/kotlin/FileCheckTest.kt | 6 ++++ 7 files changed, 49 insertions(+), 20 deletions(-) diff --git a/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt b/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt index 86d7d56e400..81a9213e406 100644 --- a/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt +++ b/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt @@ -182,7 +182,7 @@ class K2Native : CLICompiler() { arguments.manifestFile ?.let{ put(MANIFEST_FILE, it) } arguments.runtimeFile ?.let{ put(RUNTIME_FILE, it) } arguments.temporaryFilesDir?.let { put(TEMPORARY_FILES_DIR, it) } - put(SAVE_LLVM_IR, arguments.saveLlvmIr) + put(SAVE_LLVM_IR, arguments.saveLlvmIrAfter.toList()) put(LIST_TARGETS, arguments.listTargets) put(OPTIMIZATION, arguments.optimization) diff --git a/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt b/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt index f756d6c6976..2010cff7723 100644 --- a/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt +++ b/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt @@ -255,8 +255,8 @@ class K2NativeCompilerArguments : CommonCompilerArguments() { @Argument(value = "-Xtemporary-files-dir", deprecatedName = "--temporary_files_dir", valueDescription = "", description = "Save temporary files to the given directory") var temporaryFilesDir: String? = null - @Argument(value = "-Xsave-llvm-ir", description = "Save result of Kotlin IR to LLVM IR translation to the temporary files directory.") - var saveLlvmIr: Boolean = false + @Argument(value = "-Xsave-llvm-ir-after", description = "Save result of Kotlin IR to LLVM IR translation to the temporary files directory.") + var saveLlvmIrAfter: Array = emptyArray() @Argument(value = "-Xverify-bitcode", deprecatedName = "--verify_bitcode", description = "Verify llvm bitcode after each method") var verifyBitCode: Boolean = false diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CompilerOutput.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CompilerOutput.kt index cdee94ed6a9..baeb4797253 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CompilerOutput.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CompilerOutput.kt @@ -9,10 +9,13 @@ import kotlinx.cinterop.memScoped import kotlinx.cinterop.ptr import kotlinx.cinterop.toKStringFromUtf8 import llvm.* +import org.jetbrains.kotlin.backend.common.phaser.ActionState +import org.jetbrains.kotlin.backend.common.phaser.BeforeOrAfter import org.jetbrains.kotlin.backend.common.serialization.KlibIrVersion import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataVersion import org.jetbrains.kotlin.backend.konan.llvm.* import org.jetbrains.kotlin.backend.konan.llvm.objc.linkObjC +import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.konan.CURRENT import org.jetbrains.kotlin.konan.CompilerVersion import org.jetbrains.kotlin.konan.file.isBitcode @@ -47,6 +50,20 @@ val CompilerOutputKind.involvesLinkStage: Boolean val CompilerOutputKind.isCache: Boolean get() = (this == CompilerOutputKind.STATIC_CACHE || this == CompilerOutputKind.DYNAMIC_CACHE) +internal fun llvmIrDumpCallback(state: ActionState, module: IrModuleFragment, context: Context) { + module.let{} + if (state.beforeOrAfter == BeforeOrAfter.AFTER && state.phase.name in context.configuration.getList(KonanConfigKeys.SAVE_LLVM_IR)) { + val moduleName: String = memScoped { + val sizeVar = alloc() + LLVMGetModuleIdentifier(context.llvmModule, sizeVar.ptr)!!.toKStringFromUtf8() + } + val output = context.config.tempFiles.create("$moduleName.${state.phase.name}", ".ll") + if (LLVMPrintModuleToFile(context.llvmModule, output.absolutePath, null) != 0) { + error("Can't dump LLVM IR to ${output.absolutePath}") + } + } +} + internal fun produceCStubs(context: Context) { val llvmModule = context.llvmModule!! context.cStubsManager.compile( @@ -56,17 +73,6 @@ internal fun produceCStubs(context: Context) { ).forEach { parseAndLinkBitcodeFile(context, llvmModule, it.absolutePath) } - // TODO: Consider adding LLVM_IR compiler output kind. - if (context.configuration.getBoolean(KonanConfigKeys.SAVE_LLVM_IR)) { - val moduleName: String = memScoped { - val sizeVar = alloc() - LLVMGetModuleIdentifier(context.llvmModule, sizeVar.ptr)!!.toKStringFromUtf8() - } - val output = context.config.tempFiles.create(moduleName,".ll") - if (LLVMPrintModuleToFile(context.llvmModule, output.absolutePath, null) != 0) { - error("Can't dump LLVM IR to ${output.absolutePath}") - } - } } private fun linkAllDependencies(context: Context, generatedBitcodeFiles: List) { diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt index 29e13b50c4a..5c18e97cd12 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt @@ -134,7 +134,7 @@ class KonanConfigKeys { = CompilerConfigurationKey.create("target we compile for") val TEMPORARY_FILES_DIR: CompilerConfigurationKey = CompilerConfigurationKey.create("directory for temporary files") - val SAVE_LLVM_IR: CompilerConfigurationKey + val SAVE_LLVM_IR: CompilerConfigurationKey> = CompilerConfigurationKey.create("save LLVM IR") val VERIFY_BITCODE: CompilerConfigurationKey = CompilerConfigurationKey.create("verify bitcode") diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLoweringPhases.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLoweringPhases.kt index b9cab4544ff..39586de7511 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLoweringPhases.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLoweringPhases.kt @@ -1,5 +1,11 @@ package org.jetbrains.kotlin.backend.konan +import kotlinx.cinterop.alloc +import kotlinx.cinterop.memScoped +import kotlinx.cinterop.ptr +import kotlinx.cinterop.toKStringFromUtf8 +import llvm.LLVMGetModuleIdentifier +import llvm.LLVMPrintModuleToFile import org.jetbrains.kotlin.backend.common.* import org.jetbrains.kotlin.backend.common.lower.* import org.jetbrains.kotlin.backend.common.lower.StringConcatenationLowering @@ -20,8 +26,16 @@ import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrModuleFragment private val validateAll = false -private val filePhaseActions = if (validateAll) setOf(defaultDumper, ::fileValidationCallback) else setOf(defaultDumper) -private val modulePhaseActions = if (validateAll) setOf(defaultDumper, ::moduleValidationCallback) else setOf(defaultDumper) + +private val filePhaseActions = setOfNotNull( + defaultDumper, + ::fileValidationCallback.takeIf { validateAll } +) +private val modulePhaseActions = setOfNotNull( + defaultDumper, + ::llvmIrDumpCallback, + ::moduleValidationCallback.takeIf { validateAll } +) private fun makeKonanFileLoweringPhase( lowering: (Context) -> FileLoweringPass, diff --git a/kotlin-native/backend.native/tests/build.gradle b/kotlin-native/backend.native/tests/build.gradle index 1f9a7703c44..89ce349e5c1 100644 --- a/kotlin-native/backend.native/tests/build.gradle +++ b/kotlin-native/backend.native/tests/build.gradle @@ -5955,7 +5955,7 @@ pluginTest("runtime_basic_init", "nopPlugin") { Task fileCheckTest(String name, Closure configureClosure) { return project.tasks.create(name, FileCheckTest) { task -> task.configure(configureClosure) - task.llvmIr = project.file("$testOutputFileCheck/$name/$target/out.ll") + task.llvmIr = project.file("$testOutputFileCheck/$name/$target/out.${task.phaseToCheck}.ll") if (task.enabled) { konanArtifacts { def lib = task.interop @@ -5971,7 +5971,8 @@ Task fileCheckTest(String name, Closure configureClosure) { srcFiles task.annotatedSource baseDir "$testOutputFileCheck/$name" extraOpts project.globalTestArgs - extraOpts "-Xtemporary-files-dir=$testOutputFileCheck/$name/$target", "-Xsave-llvm-ir" + extraOpts "-Xtemporary-files-dir=$testOutputFileCheck/$name/$target" + extraOpts "-Xsave-llvm-ir-after=${task.phaseToCheck}" if (lib != null) { libraries { artifact lib @@ -5984,7 +5985,9 @@ Task fileCheckTest(String name, Closure configureClosure) { srcFiles task.annotatedSource baseDir "$testOutputFileCheck/$name" extraOpts project.globalTestArgs - extraOpts "-Xtemporary-files-dir=$testOutputFileCheck/$name/$target", "-Xsave-llvm-ir", "-Xmeaningful-bridge-names" + extraOpts "-Xtemporary-files-dir=$testOutputFileCheck/$name/$target", "-Xmeaningful-bridge-names" + extraOpts "-Xsave-llvm-ir-after=${task.phaseToCheck}" + if (lib != null) { libraries { artifact lib diff --git a/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/FileCheckTest.kt b/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/FileCheckTest.kt index bc00b4432ba..03bb3f28073 100644 --- a/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/FileCheckTest.kt +++ b/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/FileCheckTest.kt @@ -61,6 +61,12 @@ open class FileCheckTest : DefaultTask() { @Optional var checkPrefix: String? = null + /** + * Compiler pipeline phase name, after which check should be done + */ + @Input + var phaseToCheck: String = "CStubs" + /** * Should we generate framework instead of an executable? * This option is useful for, well, checking framework-specific code.