[K/N] Support -Xsave-llvm-ir-after compiler option
This commit is contained in:
@@ -182,7 +182,7 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
|
|||||||
arguments.manifestFile ?.let{ put(MANIFEST_FILE, it) }
|
arguments.manifestFile ?.let{ put(MANIFEST_FILE, it) }
|
||||||
arguments.runtimeFile ?.let{ put(RUNTIME_FILE, it) }
|
arguments.runtimeFile ?.let{ put(RUNTIME_FILE, it) }
|
||||||
arguments.temporaryFilesDir?.let { put(TEMPORARY_FILES_DIR, 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(LIST_TARGETS, arguments.listTargets)
|
||||||
put(OPTIMIZATION, arguments.optimization)
|
put(OPTIMIZATION, arguments.optimization)
|
||||||
|
|||||||
+2
-2
@@ -255,8 +255,8 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
|
|||||||
@Argument(value = "-Xtemporary-files-dir", deprecatedName = "--temporary_files_dir", valueDescription = "<path>", description = "Save temporary files to the given directory")
|
@Argument(value = "-Xtemporary-files-dir", deprecatedName = "--temporary_files_dir", valueDescription = "<path>", description = "Save temporary files to the given directory")
|
||||||
var temporaryFilesDir: String? = null
|
var temporaryFilesDir: String? = null
|
||||||
|
|
||||||
@Argument(value = "-Xsave-llvm-ir", description = "Save result of Kotlin IR to LLVM IR translation to the temporary files directory.")
|
@Argument(value = "-Xsave-llvm-ir-after", description = "Save result of Kotlin IR to LLVM IR translation to the temporary files directory.")
|
||||||
var saveLlvmIr: Boolean = false
|
var saveLlvmIrAfter: Array<String> = emptyArray()
|
||||||
|
|
||||||
@Argument(value = "-Xverify-bitcode", deprecatedName = "--verify_bitcode", description = "Verify llvm bitcode after each method")
|
@Argument(value = "-Xverify-bitcode", deprecatedName = "--verify_bitcode", description = "Verify llvm bitcode after each method")
|
||||||
var verifyBitCode: Boolean = false
|
var verifyBitCode: Boolean = false
|
||||||
|
|||||||
+17
-11
@@ -9,10 +9,13 @@ import kotlinx.cinterop.memScoped
|
|||||||
import kotlinx.cinterop.ptr
|
import kotlinx.cinterop.ptr
|
||||||
import kotlinx.cinterop.toKStringFromUtf8
|
import kotlinx.cinterop.toKStringFromUtf8
|
||||||
import llvm.*
|
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.KlibIrVersion
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataVersion
|
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataVersion
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.*
|
import org.jetbrains.kotlin.backend.konan.llvm.*
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.objc.linkObjC
|
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.CURRENT
|
||||||
import org.jetbrains.kotlin.konan.CompilerVersion
|
import org.jetbrains.kotlin.konan.CompilerVersion
|
||||||
import org.jetbrains.kotlin.konan.file.isBitcode
|
import org.jetbrains.kotlin.konan.file.isBitcode
|
||||||
@@ -47,6 +50,20 @@ val CompilerOutputKind.involvesLinkStage: Boolean
|
|||||||
val CompilerOutputKind.isCache: Boolean
|
val CompilerOutputKind.isCache: Boolean
|
||||||
get() = (this == CompilerOutputKind.STATIC_CACHE || this == CompilerOutputKind.DYNAMIC_CACHE)
|
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<size_tVar>()
|
||||||
|
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) {
|
internal fun produceCStubs(context: Context) {
|
||||||
val llvmModule = context.llvmModule!!
|
val llvmModule = context.llvmModule!!
|
||||||
context.cStubsManager.compile(
|
context.cStubsManager.compile(
|
||||||
@@ -56,17 +73,6 @@ internal fun produceCStubs(context: Context) {
|
|||||||
).forEach {
|
).forEach {
|
||||||
parseAndLinkBitcodeFile(context, llvmModule, it.absolutePath)
|
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<size_tVar>()
|
|
||||||
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<String>) {
|
private fun linkAllDependencies(context: Context, generatedBitcodeFiles: List<String>) {
|
||||||
|
|||||||
+1
-1
@@ -134,7 +134,7 @@ class KonanConfigKeys {
|
|||||||
= CompilerConfigurationKey.create("target we compile for")
|
= CompilerConfigurationKey.create("target we compile for")
|
||||||
val TEMPORARY_FILES_DIR: CompilerConfigurationKey<String?>
|
val TEMPORARY_FILES_DIR: CompilerConfigurationKey<String?>
|
||||||
= CompilerConfigurationKey.create("directory for temporary files")
|
= CompilerConfigurationKey.create("directory for temporary files")
|
||||||
val SAVE_LLVM_IR: CompilerConfigurationKey<Boolean>
|
val SAVE_LLVM_IR: CompilerConfigurationKey<List<String>>
|
||||||
= CompilerConfigurationKey.create("save LLVM IR")
|
= CompilerConfigurationKey.create("save LLVM IR")
|
||||||
val VERIFY_BITCODE: CompilerConfigurationKey<Boolean>
|
val VERIFY_BITCODE: CompilerConfigurationKey<Boolean>
|
||||||
= CompilerConfigurationKey.create("verify bitcode")
|
= CompilerConfigurationKey.create("verify bitcode")
|
||||||
|
|||||||
+16
-2
@@ -1,5 +1,11 @@
|
|||||||
package org.jetbrains.kotlin.backend.konan
|
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.*
|
||||||
import org.jetbrains.kotlin.backend.common.lower.*
|
import org.jetbrains.kotlin.backend.common.lower.*
|
||||||
import org.jetbrains.kotlin.backend.common.lower.StringConcatenationLowering
|
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
|
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||||
|
|
||||||
private val validateAll = false
|
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(
|
private fun makeKonanFileLoweringPhase(
|
||||||
lowering: (Context) -> FileLoweringPass,
|
lowering: (Context) -> FileLoweringPass,
|
||||||
|
|||||||
@@ -5955,7 +5955,7 @@ pluginTest("runtime_basic_init", "nopPlugin") {
|
|||||||
Task fileCheckTest(String name, Closure<FileCheckTest> configureClosure) {
|
Task fileCheckTest(String name, Closure<FileCheckTest> configureClosure) {
|
||||||
return project.tasks.create(name, FileCheckTest) { task ->
|
return project.tasks.create(name, FileCheckTest) { task ->
|
||||||
task.configure(configureClosure)
|
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) {
|
if (task.enabled) {
|
||||||
konanArtifacts {
|
konanArtifacts {
|
||||||
def lib = task.interop
|
def lib = task.interop
|
||||||
@@ -5971,7 +5971,8 @@ Task fileCheckTest(String name, Closure<FileCheckTest> configureClosure) {
|
|||||||
srcFiles task.annotatedSource
|
srcFiles task.annotatedSource
|
||||||
baseDir "$testOutputFileCheck/$name"
|
baseDir "$testOutputFileCheck/$name"
|
||||||
extraOpts project.globalTestArgs
|
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) {
|
if (lib != null) {
|
||||||
libraries {
|
libraries {
|
||||||
artifact lib
|
artifact lib
|
||||||
@@ -5984,7 +5985,9 @@ Task fileCheckTest(String name, Closure<FileCheckTest> configureClosure) {
|
|||||||
srcFiles task.annotatedSource
|
srcFiles task.annotatedSource
|
||||||
baseDir "$testOutputFileCheck/$name"
|
baseDir "$testOutputFileCheck/$name"
|
||||||
extraOpts project.globalTestArgs
|
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) {
|
if (lib != null) {
|
||||||
libraries {
|
libraries {
|
||||||
artifact lib
|
artifact lib
|
||||||
|
|||||||
@@ -61,6 +61,12 @@ open class FileCheckTest : DefaultTask() {
|
|||||||
@Optional
|
@Optional
|
||||||
var checkPrefix: String? = null
|
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?
|
* Should we generate framework instead of an executable?
|
||||||
* This option is useful for, well, checking framework-specific code.
|
* This option is useful for, well, checking framework-specific code.
|
||||||
|
|||||||
Reference in New Issue
Block a user