diff --git a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt index c5344f241a2..1ad31cc19a9 100644 --- a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt +++ b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt @@ -1,16 +1,16 @@ package org.jetbrains.kotlin.cli.bc +import org.jetbrains.kotlin.backend.konan.* import com.intellij.openapi.Disposable import org.jetbrains.kotlin.analyzer.AnalysisResult -import org.jetbrains.kotlin.backend.konan.llvm.emitLLVM import org.jetbrains.kotlin.cli.common.CLICompiler -import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys -import org.jetbrains.kotlin.cli.common.ExitCode import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport +import org.jetbrains.kotlin.cli.common.ExitCode import org.jetbrains.kotlin.cli.jvm.compiler.CliLightClassGenerationSupport import org.jetbrains.kotlin.cli.jvm.compiler.JvmPackagePartProvider import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.config.CommonConfigurationKeys +import org.jetbrains.kotlin.backend.konan.KonanConfigKeys import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.Services import org.jetbrains.kotlin.config.addKotlinSourceRoots @@ -21,70 +21,65 @@ import org.jetbrains.kotlin.psi.KtFile import java.lang.System.out import java.util.* -class NativeAnalyzer( - val environment: KotlinCoreEnvironment, - val sources: Collection, - val config: KonanConfig) : AnalyzerWithCompilerReport.Analyzer { - - override fun analyze(): AnalysisResult { - return TopDownAnalyzerFacadeForKonan.analyzeFiles(sources, config); - } - - override fun reportEnvironmentErrors() { - } -} - class K2Native : CLICompiler() { - val defaultModuleName = "main"; - override fun doExecute(arguments : K2NativeCompilerArguments, + override fun doExecute(arguments : K2NativeCompilerArguments, configuration : CompilerConfiguration, rootDisposable: Disposable ): ExitCode { - configuration.put(CommonConfigurationKeys.MODULE_NAME, defaultModuleName) - configuration.addKotlinSourceRoots(arguments.freeArgs) - - val libraries = arguments.libraries?.asList() ?: listOf() - configuration.put(KonanConfigurationKeys.LIBRARY_FILES, libraries) - libraries.forEach{println(it)} + configuration.get(KonanConfigKeys.LIBRARY_FILES)?.forEach{ println(it) } val environment = KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, Arrays.asList("extensions/common.xml")) - - val collector = configuration.getNotNull( - CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY) - - val analyzerWithCompilerReport = AnalyzerWithCompilerReport(collector) - val project = environment.project - val config = KonanConfig(project, configuration) + val konanConfig = KonanConfig(project, configuration) - - // Build AST and binding info. - analyzerWithCompilerReport.analyzeAndReport(environment.getSourceFiles(), - NativeAnalyzer(environment, environment.getSourceFiles(), config)) - - // Translate AST to high level IR. - val translator = Psi2IrTranslator(Psi2IrConfiguration(false)) - val module = translator.generateModule( - analyzerWithCompilerReport.analysisResult.moduleDescriptor, - environment.getSourceFiles(), - analyzerWithCompilerReport.analysisResult.bindingContext) - - // Emit LLVM code. - module.accept(DumpIrTreeVisitor(out), "") - emitLLVM(module, arguments.runtimeFile, arguments.outputFile) + runTopLevelPhases(konanConfig, environment) return ExitCode.OK } + fun Array?.toNonNullList(): List { + return this?.asList() ?: listOf() + } + + + // It is executed before doExecute(). override fun setupPlatformSpecificArgumentsAndServices( configuration: CompilerConfiguration, arguments : K2NativeCompilerArguments, - services : Services) {} + services : Services) { + + + configuration.addKotlinSourceRoots(arguments.freeArgs) + + configuration.put(CommonConfigurationKeys.MODULE_NAME, "main") + + val libraries = arguments.libraries.toNonNullList() + configuration.put(KonanConfigKeys.LIBRARY_FILES, + arguments.libraries.toNonNullList()) + configuration.put(KonanConfigKeys.RUNTIME_FILE, arguments.runtimeFile) + configuration.put(KonanConfigKeys.OUTPUT_FILE, arguments.outputFile) + + configuration.put(KonanConfigKeys.PRINT_IR, arguments.printIr) + configuration.put(KonanConfigKeys.PRINT_DESCRIPTORS, arguments.printDescriptors) + configuration.put(KonanConfigKeys.PRINT_BITCODE, arguments.printBitCode) + + configuration.put(KonanConfigKeys.VERIFY_IR, arguments.verifyIr) + configuration.put(KonanConfigKeys.VERIFY_DESCRIPTORS, arguments.verifyDescriptors) + configuration.put(KonanConfigKeys.VERIFY_BITCODE, arguments.verifyBitCode) + + configuration.put(KonanConfigKeys.ENABLED_PHASES, + arguments.enablePhases.toNonNullList()) + configuration.put(KonanConfigKeys.DISABLED_PHASES, + arguments.disablePhases.toNonNullList()) + configuration.put(KonanConfigKeys.VERBOSE_PHASES, + arguments.verbosePhases.toNonNullList()) + configuration.put(KonanConfigKeys.LIST_PHASES, arguments.listPhases) + } override fun createArguments(): K2NativeCompilerArguments { return K2NativeCompilerArguments() diff --git a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.java b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.java index 9b38f2198e9..ffa36736273 100644 --- a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.java +++ b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.java @@ -4,7 +4,6 @@ import com.sampullara.cli.Argument; import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments; import org.jetbrains.kotlin.cli.common.arguments.ValueDescription; - public class K2NativeCompilerArguments extends CommonCompilerArguments { @Argument(value = "output", description = "Output file path") @ValueDescription("") @@ -18,17 +17,37 @@ public class K2NativeCompilerArguments extends CommonCompilerArguments { @ValueDescription("") public String[] libraries; + @Argument(value = "print_ir", description = "Print IR") + public boolean printIr; - public K2NativeCompilerArguments() { - } + @Argument(value = "print_descriptors", description = "Print descriptor tree") + public boolean printDescriptors; - public K2NativeCompilerArguments(K2NativeCompilerArguments arguments) { - this.outputFile = arguments.outputFile; - this.runtimeFile = arguments.runtimeFile; - this.libraries = arguments.libraries; - } + @Argument(value = "print_bitcode", description = "Print llvm bitcode") + public boolean printBitCode; - public CommonCompilerArguments copy() { - return new K2NativeCompilerArguments(this); - } + @Argument(value = "verify_ir", description = "Verify IR") + public boolean verifyIr; + + @Argument(value = "verify_descriptors", description = "Verify descriptor tree") + public boolean verifyDescriptors; + + @Argument(value = "verify_bitcode", description = "Verify llvm bitcode") + public boolean verifyBitCode; + + @Argument(value = "enable", description = "Enable backend phase") + @ValueDescription("") + public String[] enablePhases; + + @Argument(value = "disable", description = "Disable backend phase") + @ValueDescription("") + public String[] disablePhases; + + @Argument(value = "verbose", description = "Trace phase execution") + @ValueDescription("") + public String[] verbosePhases; + + @Argument(value = "list", description = "List all backend phases") + public boolean listPhases; } + diff --git a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/KonanConfigurationKeys.kt b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/KonanConfigurationKeys.kt deleted file mode 100644 index 6bf708bada3..00000000000 --- a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/KonanConfigurationKeys.kt +++ /dev/null @@ -1,17 +0,0 @@ -package org.jetbrains.kotlin.cli.bc; - -import org.jetbrains.kotlin.config.CompilerConfigurationKey; -import org.jetbrains.kotlin.serialization.js.ModuleKind; - -class KonanConfigurationKeys { - companion object { - val LIBRARY_FILES: CompilerConfigurationKey> - = CompilerConfigurationKey.create("library file paths"); - val SOURCE_MAP: CompilerConfigurationKey> - = CompilerConfigurationKey.create("generate source map"); - val META_INFO: CompilerConfigurationKey> - = CompilerConfigurationKey.create("generate metadata"); - val MODULE_KIND: CompilerConfigurationKey - = CompilerConfigurationKey.create("module kind"); - } -} diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt new file mode 100644 index 00000000000..44edae2f604 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt @@ -0,0 +1,125 @@ +package org.jetbrains.kotlin.backend.konan + +import llvm.* +import org.jetbrains.kotlin.backend.konan.llvm.Runtime +import org.jetbrains.kotlin.backend.konan.llvm.getFunctionType +import org.jetbrains.kotlin.backend.konan.llvm.StaticData +import org.jetbrains.kotlin.backend.konan.llvm.Llvm +import org.jetbrains.kotlin.backend.konan.KonanBackendContext +import org.jetbrains.kotlin.backend.konan.KonanPhase +import org.jetbrains.kotlin.backend.konan.ModuleIndex +import org.jetbrains.kotlin.backend.konan.KonanConfig +import org.jetbrains.kotlin.backend.konan.KonanConfigKeys +import org.jetbrains.kotlin.ir.declarations.IrModuleFragment +import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.backend.konan.DeepPrintVisitor +import org.jetbrains.kotlin.backend.konan.PrintVisitor +import org.jetbrains.kotlin.backend.konan.llvm.verifyModule +import org.jetbrains.kotlin.ir.util.DumpIrTreeVisitor +import java.lang.System.out + +internal final class Context(val config: KonanConfig, + // TODO: Need to eliminate when deserialization is fixed. + val bindingContext: BindingContext, + val moduleDescriptor: ModuleDescriptor + ) : KonanBackendContext() { + + var irModule: IrModuleFragment? = null + set(module: IrModuleFragment?) { + if (field != null) { + throw Error("Another IrModule in the context.") + } + field = module!! + + moduleIndex = ModuleIndex(irModule!!) + } + + lateinit var moduleIndex: ModuleIndex + + var llvmModule: LLVMModuleRef? = null + set(module: LLVMModuleRef?) { + if (field != null) { + throw Error("Another LLVMModule in the context.") + } + field = module!! + + llvm = Llvm(this, module) + } + + lateinit var llvm: Llvm + + var phase: KonanPhase? = null + + protected fun separator(title: String) { + println("\n\n--- ${title} ----------------------\n") + } + + fun verifyDescriptors() { + // TODO: Nothing here for now. + } + + fun printDescriptors() { + separator("Descriptors after: ${phase?.description}") + moduleDescriptor!!.accept(DeepPrintVisitor(PrintVisitor()), 0) + } + + fun verifyIr() { + if (irModule == null) return + // TODO: We don't have it yet. + } + + fun printIr() { + if (irModule == null) return + separator("IR after: ${phase?.description}") + irModule!!.accept(DumpIrTreeVisitor(out), "") + } + + fun verifyBitCode() { + if (llvmModule == null) return + verifyModule(llvmModule!!) + } + + fun printBitCode() { + if (llvmModule == null) return + separator("BitCode after: ${phase?.description}") + LLVMDumpModule(llvmModule!!) + } + + fun verify() { + verifyDescriptors() + verifyIr() + verifyBitCode() + } + + fun print() { + printDescriptors() + printIr() + printBitCode() + } + + fun shouldVerifyDescriptors(): Boolean { + return config.configuration.getBoolean(KonanConfigKeys.VERIFY_DESCRIPTORS) + } + + fun shouldVerifyIr(): Boolean { + return config.configuration.getBoolean(KonanConfigKeys.VERIFY_IR) + } + + fun shouldVerifyBitCode(): Boolean { + return config.configuration.getBoolean(KonanConfigKeys.VERIFY_BITCODE) + } + + fun shouldPrintDescriptors(): Boolean { + return config.configuration.getBoolean(KonanConfigKeys.PRINT_DESCRIPTORS) + } + + fun shouldPrintIr(): Boolean { + return config.configuration.getBoolean(KonanConfigKeys.PRINT_IR) + } + + fun shouldPrintBitCode(): Boolean { + return config.configuration.getBoolean(KonanConfigKeys.PRINT_BITCODE) + } +} + diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DeepPrintVisitor.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DeepPrintVisitor.kt new file mode 100644 index 00000000000..49d1707e00f --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DeepPrintVisitor.kt @@ -0,0 +1,73 @@ +package org.jetbrains.kotlin.backend.konan + +import org.jetbrains.kotlin.backend.konan.llvm.* +import org.jetbrains.kotlin.renderer.* + +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl + +public class DeepPrintVisitor(worker: DeclarationDescriptorVisitor): DeepVisitor< Int>(worker) { + + override public fun visitChildren(descriptor: DeclarationDescriptor?, data: Int): Boolean { + return super.visitChildren(descriptor, data+1) + } + + override public fun visitChildren(descriptors: Collection, data: Int): Boolean { + return super.visitChildren(descriptors, data+1) + } +} + +public class PrintVisitor: DeclarationDescriptorVisitor { + + fun printDescriptor(descriptor: DeclarationDescriptor, amount: Int): Boolean { + println(String.format("%1$-${(amount+1)*4}s", "") + descriptor.toString()) + return true; + } + + override fun visitPackageFragmentDescriptor(descriptor: PackageFragmentDescriptor, data: Int): Boolean + = printDescriptor(descriptor, data) + + override fun visitPackageViewDescriptor(descriptor: PackageViewDescriptor, data: Int): Boolean + = printDescriptor(descriptor, data) + + override fun visitVariableDescriptor(descriptor: VariableDescriptor, data: Int): Boolean + = printDescriptor(descriptor, data) + + override fun visitFunctionDescriptor(descriptor: FunctionDescriptor, data: Int): Boolean + = printDescriptor(descriptor, data) + + override fun visitTypeParameterDescriptor(descriptor: TypeParameterDescriptor, data: Int): Boolean + = printDescriptor(descriptor, data) + + override fun visitClassDescriptor(descriptor: ClassDescriptor, data: Int): Boolean + = printDescriptor(descriptor, data) + + override fun visitTypeAliasDescriptor(descriptor: TypeAliasDescriptor, data: Int): Boolean + = printDescriptor(descriptor, data) + + override fun visitModuleDeclaration(descriptor: ModuleDescriptor, data: Int): Boolean + = printDescriptor(descriptor, data) + + override fun visitConstructorDescriptor(descriptor: ConstructorDescriptor, data: Int): Boolean + = printDescriptor(descriptor, data) + + override fun visitScriptDescriptor(descriptor: ScriptDescriptor, data: Int): Boolean + = printDescriptor(descriptor, data) + + override fun visitPropertyDescriptor(descriptor: PropertyDescriptor, data: Int): Boolean + = printDescriptor(descriptor, data) + + override fun visitValueParameterDescriptor(descriptor: ValueParameterDescriptor, data: Int): Boolean + = printDescriptor(descriptor, data) + + override fun visitPropertyGetterDescriptor(descriptor: PropertyGetterDescriptor, data: Int): Boolean + = printDescriptor(descriptor, data) + + override fun visitPropertySetterDescriptor(descriptor: PropertySetterDescriptor, data: Int): Boolean + = printDescriptor(descriptor, data) + + override fun visitReceiverParameterDescriptor(descriptor: ReceiverParameterDescriptor, data: Int): Boolean + = printDescriptor(descriptor, data) +} + + diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DeepVisitor.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DeepVisitor.kt new file mode 100644 index 00000000000..50561be0eec --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DeepVisitor.kt @@ -0,0 +1,100 @@ +package org.jetbrains.kotlin.backend.konan + +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.resolve.DescriptorUtils + + +open class DeepVisitor(val worker: DeclarationDescriptorVisitor) : DeclarationDescriptorVisitor { + + open fun visitChildren(descriptors: Collection, data: D): Boolean { + for (descriptor in descriptors) { + if (!descriptor.accept(this, data)) return false + } + return true + } + + open fun visitChildren(descriptor: DeclarationDescriptor?, data: D): Boolean { + if (descriptor == null) return true + + return descriptor!!.accept(this, data) + } + + fun applyWorker(descriptor: DeclarationDescriptor, data: D): Boolean { + return descriptor.accept(worker, data) + } + + fun processCallable(descriptor: CallableDescriptor, data: D): Boolean { + return applyWorker(descriptor, data) + && visitChildren(descriptor.getTypeParameters(), data) + && visitChildren(descriptor.getExtensionReceiverParameter(), data) + && visitChildren(descriptor.getValueParameters(), data) + } + + override fun visitPackageFragmentDescriptor(descriptor: PackageFragmentDescriptor, data: D): Boolean? { + return applyWorker(descriptor, data) && visitChildren(DescriptorUtils.getAllDescriptors(descriptor.getMemberScope()), data) + } + + override fun visitPackageViewDescriptor(descriptor: PackageViewDescriptor, data: D): Boolean? { + return applyWorker(descriptor, data) && visitChildren(DescriptorUtils.getAllDescriptors(descriptor.memberScope), data) + } + + override fun visitVariableDescriptor(descriptor: VariableDescriptor, data: D): Boolean? { + return processCallable(descriptor, data) + } + + override fun visitPropertyDescriptor(descriptor: PropertyDescriptor, data: D): Boolean? { + return processCallable(descriptor, data) + && visitChildren(descriptor.getter, data) + && visitChildren(descriptor.setter, data) + } + + override fun visitFunctionDescriptor(descriptor: FunctionDescriptor, data: D): Boolean? { + return processCallable(descriptor, data) + } + + override fun visitTypeParameterDescriptor(descriptor: TypeParameterDescriptor, data: D): Boolean? { + return applyWorker(descriptor, data) + } + + override fun visitClassDescriptor(descriptor: ClassDescriptor, data: D): Boolean? { + return applyWorker(descriptor, data) + && visitChildren(descriptor.getThisAsReceiverParameter(), data) + && visitChildren(descriptor.getConstructors(), data) + && visitChildren(descriptor.getTypeConstructor().getParameters(), data) + && visitChildren(DescriptorUtils.getAllDescriptors(descriptor.getDefaultType().memberScope), data) + } + + override fun visitTypeAliasDescriptor(descriptor: TypeAliasDescriptor, data: D): Boolean? { + return applyWorker(descriptor, data) && visitChildren(descriptor.getDeclaredTypeParameters(), data) + } + + override fun visitModuleDeclaration(descriptor: ModuleDescriptor, data: D): Boolean? { + return applyWorker(descriptor, data) && visitChildren(descriptor.getPackage(FqName.ROOT), data) + } + + override fun visitConstructorDescriptor(constructorDescriptor: ConstructorDescriptor, data: D): Boolean? { + return visitFunctionDescriptor(constructorDescriptor, data) + } + + override fun visitScriptDescriptor(scriptDescriptor: ScriptDescriptor, data: D): Boolean? { + return visitClassDescriptor(scriptDescriptor, data) + } + + override fun visitValueParameterDescriptor(descriptor: ValueParameterDescriptor, data: D): Boolean? { + return visitVariableDescriptor(descriptor, data) + } + + override fun visitPropertyGetterDescriptor(descriptor: PropertyGetterDescriptor, data: D): Boolean? { + return visitFunctionDescriptor(descriptor, data) + } + + override fun visitPropertySetterDescriptor(descriptor: PropertySetterDescriptor, data: D): Boolean? { + return visitFunctionDescriptor(descriptor, data) + } + + override fun visitReceiverParameterDescriptor(descriptor: ReceiverParameterDescriptor, data: D): Boolean? { + return applyWorker(descriptor, data) + } +} + diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DescriptorUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DescriptorUtils.kt index 80a399e1521..2f95b5b358c 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DescriptorUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DescriptorUtils.kt @@ -1,6 +1,6 @@ package org.jetbrains.kotlin.backend.konan -import org.jetbrains.kotlin.backend.konan.llvm.KonanBuiltIns +import org.jetbrains.kotlin.backend.konan.KonanBuiltIns import org.jetbrains.kotlin.builtins.isFunctionType import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.incremental.components.NoLookupLocation diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanBackendContext.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanBackendContext.kt index 85bd442c48e..0cef8de535d 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanBackendContext.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanBackendContext.kt @@ -2,7 +2,7 @@ package org.jetbrains.kotlin.backend.konan import org.jetbrains.kotlin.backend.common.BackendContext import org.jetbrains.kotlin.backend.konan.descriptors.KonanSharedVariablesManager -import org.jetbrains.kotlin.backend.konan.llvm.KonanPlatform +import org.jetbrains.kotlin.backend.konan.KonanPlatform open internal class KonanBackendContext : BackendContext { override val builtIns = KonanPlatform.builtIns @@ -12,4 +12,4 @@ open internal class KonanBackendContext : BackendContext { // TODO: investigate this. KonanSharedVariablesManager(builtIns) } -} \ No newline at end of file +} diff --git a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/KonanConfig.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt similarity index 90% rename from backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/KonanConfig.kt rename to backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt index 46e812bfb34..5c889b81600 100644 --- a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/KonanConfig.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt @@ -1,7 +1,7 @@ -package org.jetbrains.kotlin.cli.bc +package org.jetbrains.kotlin.backend.konan import com.intellij.openapi.project.Project -import org.jetbrains.kotlin.backend.konan.llvm.KonanPlatform +import org.jetbrains.kotlin.backend.konan.KonanPlatform import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl @@ -18,13 +18,11 @@ import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.backend.konan.llvm.KotlinKonanMetadata import org.jetbrains.kotlin.backend.konan.llvm.KotlinKonanMetadataUtils -/** - * Base class representing a configuration of translator. - */ class KonanConfig(val project: Project, val configuration: CompilerConfiguration) { + private val storageManager = LockBasedStorageManager() - private val libraries = configuration.getList(KonanConfigurationKeys.LIBRARY_FILES) + private val libraries = configuration.getList(KonanConfigKeys.LIBRARY_FILES) private val metadata = KotlinKonanMetadataUtils.loadLibMetadata(libraries) @@ -32,7 +30,7 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration get() = configuration.getNotNull(CommonConfigurationKeys.MODULE_NAME) val moduleKind: ModuleKind - get() = configuration.get(KonanConfigurationKeys.MODULE_KIND)!! + get() = configuration.get(KonanConfigKeys.MODULE_KIND)!! // We reuse JsModuleDescriptor for serialization for now, as we haven't got one for Konan yet. internal val moduleDescriptors: MutableList> by lazy { diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt new file mode 100644 index 00000000000..e333096667e --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt @@ -0,0 +1,46 @@ +package org.jetbrains.kotlin.backend.konan; + +import org.jetbrains.kotlin.config.CompilerConfigurationKey; +import org.jetbrains.kotlin.serialization.js.ModuleKind; + +class KonanConfigKeys { + companion object { + val LIBRARY_FILES: CompilerConfigurationKey> + = CompilerConfigurationKey.create("library file paths"); + val RUNTIME_FILE: CompilerConfigurationKey + = CompilerConfigurationKey.create("runtime file path"); + val OUTPUT_FILE: CompilerConfigurationKey + = CompilerConfigurationKey.create("output file path"); + + val SOURCE_MAP: CompilerConfigurationKey> + = CompilerConfigurationKey.create("generate source map"); + val META_INFO: CompilerConfigurationKey> + = CompilerConfigurationKey.create("generate metadata"); + val MODULE_KIND: CompilerConfigurationKey + = CompilerConfigurationKey.create("module kind"); + + val VERIFY_IR: CompilerConfigurationKey + = CompilerConfigurationKey.create("verify ir"); + val VERIFY_DESCRIPTORS: CompilerConfigurationKey + = CompilerConfigurationKey.create("verify descriptors"); + val VERIFY_BITCODE: CompilerConfigurationKey + = CompilerConfigurationKey.create("verify bitcode"); + + val PRINT_IR: CompilerConfigurationKey + = CompilerConfigurationKey.create("print ir"); + val PRINT_DESCRIPTORS: CompilerConfigurationKey + = CompilerConfigurationKey.create("print descriptors"); + val PRINT_BITCODE: CompilerConfigurationKey + = CompilerConfigurationKey.create("print bitcode"); + + val ENABLED_PHASES: CompilerConfigurationKey> + = CompilerConfigurationKey.create("enable backend phases"); + val DISABLED_PHASES: CompilerConfigurationKey> + = CompilerConfigurationKey.create("disable backend phases"); + val VERBOSE_PHASES: CompilerConfigurationKey> + = CompilerConfigurationKey.create("verbose backend phases"); + val LIST_PHASES: CompilerConfigurationKey + = CompilerConfigurationKey.create("list backend phases"); + } +} + diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanDriver.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanDriver.kt new file mode 100644 index 00000000000..f8259024d64 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanDriver.kt @@ -0,0 +1,76 @@ +package org.jetbrains.kotlin.backend.konan + +import org.jetbrains.kotlin.analyzer.AnalysisResult +import org.jetbrains.kotlin.backend.konan.llvm.emitLLVM +import org.jetbrains.kotlin.backend.konan.Context +import org.jetbrains.kotlin.cli.common.CLICompiler +import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys +import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport +import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment +import org.jetbrains.kotlin.config.CommonConfigurationKeys +import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.ir.declarations.IrModuleFragment +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration +import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.resolve.BindingContext + +class NativeAnalyzer( + val environment: KotlinCoreEnvironment, + val sources: Collection, + val konanConfig: KonanConfig) : AnalyzerWithCompilerReport.Analyzer { + + override fun analyze(): AnalysisResult { + return TopDownAnalyzerFacadeForKonan.analyzeFiles(sources, konanConfig); + } + + override fun reportEnvironmentErrors() { + } +} + +public fun runTopLevelPhases(konanConfig: KonanConfig, environment: KotlinCoreEnvironment) { + + val config = konanConfig.configuration + + KonanPhases.config(konanConfig) + if (config.get(KonanConfigKeys.LIST_PHASES) ?: false) { + KonanPhases.list() + } + + val collector = config.getNotNull( + CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY) + + val analyzerWithCompilerReport = AnalyzerWithCompilerReport(collector) + + // Build AST and binding info. + analyzerWithCompilerReport.analyzeAndReport(environment.getSourceFiles(), + NativeAnalyzer(environment, environment.getSourceFiles(), konanConfig)) + + val bindingContext = analyzerWithCompilerReport.analysisResult.bindingContext + val moduleDescriptor = analyzerWithCompilerReport.analysisResult.moduleDescriptor + + val context = Context(konanConfig, bindingContext, moduleDescriptor) + + // Translate AST to high level IR. + val translator = Psi2IrTranslator(Psi2IrConfiguration(false)) + val module = translator.generateModule( moduleDescriptor, + environment.getSourceFiles(), bindingContext) + + context.irModule = module + val phaser = PhaseManager(context) + + phaser.phase("Optimizer") { + KonanLower(context).lower(module) + } + + phaser.phase("Bitcode") { + emitLLVM(context) + } + + phaser.phase("Linker") { + //TODO: We don't have it yet. + // invokeLinker() + } +} + diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt index 89874152e06..91e4ada660d 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt @@ -1,5 +1,7 @@ package org.jetbrains.kotlin.backend.konan +import org.jetbrains.kotlin.backend.konan.PhaseManager +import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.common.lower.LocalFunctionsLowering import org.jetbrains.kotlin.backend.common.lower.SharedVariablesLowering import org.jetbrains.kotlin.backend.common.runOnFilePostfix @@ -7,7 +9,7 @@ import org.jetbrains.kotlin.backend.konan.lower.CallableReferenceLowering import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrModuleFragment -internal class KonanLower(val context: KonanBackendContext) { +internal class KonanLower(val context: Context) { fun lower(module: IrModuleFragment) { module.files.forEach { @@ -16,8 +18,16 @@ internal class KonanLower(val context: KonanBackendContext) { } fun lower(irFile: IrFile) { - SharedVariablesLowering(context).runOnFilePostfix(irFile) - LocalFunctionsLowering(context).runOnFilePostfix(irFile) - CallableReferenceLowering(context).runOnFilePostfix(irFile) + val phaser = PhaseManager(context) + + phaser.phase("Lower_shared_variables") { + SharedVariablesLowering(context).runOnFilePostfix(irFile) + } + phaser.phase("Lower_local_functions") { + LocalFunctionsLowering(context).runOnFilePostfix(irFile) + } + phaser.phase("Lower_callables") { + CallableReferenceLowering(context).runOnFilePostfix(irFile) + } } -} \ No newline at end of file +} diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt new file mode 100644 index 00000000000..3ef24fc8fb0 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt @@ -0,0 +1,84 @@ +package org.jetbrains.kotlin.backend.konan + +import org.jetbrains.kotlin.backend.konan.Context + +class KonanPhase (val description: String, + var enabled: Boolean = true, var verbose: Boolean = false) { +} + +object KonanPhases { + val phases = mapOf ( + "Backend" to KonanPhase("All backend"), + "Optimizer" to KonanPhase("IR Optimizer"), + "Lower_shared_variables" to KonanPhase("Shared Variable Lowering"), + "Lower_local_functions" to KonanPhase("Local Function Lowering"), + "Lower_callables" to KonanPhase("Callable references Lowering"), + "Lower" to KonanPhase("IR Lowering"), + "Bitcode" to KonanPhase("LLVM BitCode Generation"), + "RTTI" to KonanPhase("RTTI Generation"), + "Codegen" to KonanPhase("Code Generation"), + "Metadator" to KonanPhase("Metadata Generation"), + "Linker" to KonanPhase("Link Stage") + ) + + fun config(config: KonanConfig) { + val disabled = config.configuration.get(KonanConfigKeys.DISABLED_PHASES) + disabled?.forEach { phases[it]!!.enabled = false } + + val enabled = config.configuration.get(KonanConfigKeys.ENABLED_PHASES) + enabled?.forEach { phases[it]!!.enabled = true } + + val verbose = config.configuration.get(KonanConfigKeys.VERBOSE_PHASES) + verbose?.forEach { phases[it]!!.verbose = true } + } + + fun list() { + phases.forEach { key, phase -> + val enabled = if (phase.enabled) "(Enabled)" else "" + val verbose = if (phase.verbose) "(Verbose)" else "" + + println(String.format("%1$-30s%2$-30s%3$-10s", "${key}:", phase.description, "$enabled $verbose")) + } + } +} + +internal class PhaseManager(val context: Context) { + + internal fun phase(shortName: String, body: () -> Unit) { + + val phase = KonanPhases.phases[shortName] + if (phase == null) throw Error("Unknown backend phase: $shortName") + if (!phase .enabled) return + + val savePhase = context.phase + context.phase = phase + + body() + + with (context) { + if (shouldVerifyDescriptors()) { + verifyDescriptors() + } + if (shouldVerifyIr()) { + verifyIr() + } + if (shouldVerifyBitCode()) { + verifyBitCode() + } + + if (shouldPrintDescriptors()) { + printDescriptors() + } + if (shouldPrintIr()) { + printIr() + } + if (shouldPrintBitCode()) { + printBitCode() + } + } + + context.phase = savePhase + } +} + + diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/KonanPlatform.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPlatform.kt similarity index 93% rename from backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/KonanPlatform.kt rename to backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPlatform.kt index ef834a86e5e..cfdf99c100a 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/KonanPlatform.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPlatform.kt @@ -14,10 +14,10 @@ * limitations under the License. */ -package org.jetbrains.kotlin.backend.konan.llvm +package org.jetbrains.kotlin.backend.konan import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.backend.konan.llvm.KonanPlatformConfigurator +import org.jetbrains.kotlin.backend.konan.KonanPlatformConfigurator import org.jetbrains.kotlin.resolve.ImportPath import org.jetbrains.kotlin.resolve.PlatformConfigurator import org.jetbrains.kotlin.resolve.TargetPlatform diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/KonanPlatformConfigurator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPlatformConfigurator.kt similarity index 97% rename from backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/KonanPlatformConfigurator.kt rename to backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPlatformConfigurator.kt index 170dbaf16ba..ff822379a54 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/KonanPlatformConfigurator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPlatformConfigurator.kt @@ -16,7 +16,7 @@ // Adapted from JS compiler, but everyhing has been switched off for now. -package org.jetbrains.kotlin.backend.konan.llvm +package org.jetbrains.kotlin.backend.konan import org.jetbrains.kotlin.container.StorageComponentContainer import org.jetbrains.kotlin.container.useImpl diff --git a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/TopDownAnalyzerFacadeForKonan.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/TopDownAnalyzerFacadeForKonan.kt similarity index 95% rename from backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/TopDownAnalyzerFacadeForKonan.kt rename to backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/TopDownAnalyzerFacadeForKonan.kt index e3705bdb81b..395bce9ae35 100644 --- a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/TopDownAnalyzerFacadeForKonan.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/TopDownAnalyzerFacadeForKonan.kt @@ -14,11 +14,11 @@ * limitations under the License. */ -package org.jetbrains.kotlin.cli.bc +package org.jetbrains.kotlin.backend.konan import org.jetbrains.kotlin.analyzer.AnalysisResult -import org.jetbrains.kotlin.backend.konan.llvm.KonanBuiltIns -import org.jetbrains.kotlin.backend.konan.llvm.KonanPlatform +import org.jetbrains.kotlin.backend.konan.KonanBuiltIns +import org.jetbrains.kotlin.backend.konan.KonanPlatform import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl import org.jetbrains.kotlin.context.ContextForNewModule diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/KonanSharedVariablesManager.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/KonanSharedVariablesManager.kt index d7a165a9712..2be0e3f3b0a 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/KonanSharedVariablesManager.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/KonanSharedVariablesManager.kt @@ -3,7 +3,7 @@ package org.jetbrains.kotlin.backend.konan.descriptors import org.jetbrains.kotlin.backend.common.descriptors.SharedVariablesManager import org.jetbrains.kotlin.backend.konan.getKonanInternalClass -import org.jetbrains.kotlin.backend.konan.llvm.KonanBuiltIns +import org.jetbrains.kotlin.backend.konan.KonanBuiltIns import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.VariableDescriptor @@ -103,4 +103,4 @@ internal class KonanSharedVariablesManager(val builtIns: KonanBuiltIns) : Shared } } -} \ No newline at end of file +} diff --git a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/injection.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/injection.kt similarity index 96% rename from backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/injection.kt rename to backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/injection.kt index 08cd402103b..6fdd642a4c5 100644 --- a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/injection.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/injection.kt @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jetbrains.kotlin.cli.bc +package org.jetbrains.kotlin.backend.konan -import org.jetbrains.kotlin.backend.konan.llvm.KonanPlatform +import org.jetbrains.kotlin.backend.konan.KonanPlatform import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.container.get import org.jetbrains.kotlin.container.useImpl diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt index 93060642616..caab9b28b75 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt @@ -3,6 +3,7 @@ package org.jetbrains.kotlin.backend.konan.llvm import kotlinx.cinterop.* import llvm.* +import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Context.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Context.kt deleted file mode 100644 index ade63eb27bb..00000000000 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Context.kt +++ /dev/null @@ -1,43 +0,0 @@ -package org.jetbrains.kotlin.backend.konan.llvm - -import llvm.* -import org.jetbrains.kotlin.backend.konan.KonanBackendContext -import org.jetbrains.kotlin.backend.konan.ModuleIndex -import org.jetbrains.kotlin.ir.declarations.IrModuleFragment -import org.jetbrains.kotlin.resolve.BindingContext - -// TODO: module-independent part should probably be extracted -internal class Context(val irModule: IrModuleFragment, - val runtime: Runtime, - val llvmModule: LLVMModuleRef, - val bindingContext: BindingContext) : KonanBackendContext() { - - val moduleIndex = ModuleIndex(irModule) - - private fun importFunction(name: String, otherModule: LLVMModuleRef): LLVMValueRef { - if (LLVMGetNamedFunction(llvmModule, name) != null) { - throw IllegalArgumentException("function $name already exists") - } - - val externalFunction = LLVMGetNamedFunction(otherModule, name)!! - - val functionType = getFunctionType(externalFunction) - return LLVMAddFunction(llvmModule, name, functionType)!! - } - - val staticData = StaticData(this) - - private fun importRtFunction(name: String) = importFunction(name, runtime.llvmModule) - - val allocInstanceFunction = importRtFunction("AllocInstance") - val initInstanceFunction = importRtFunction("InitInstance") - val allocArrayFunction = importRtFunction("AllocArrayInstance") - val setArrayFunction = importRtFunction("Kotlin_Array_set") - val copyImplArrayFunction = importRtFunction("Kotlin_Array_copyImpl") - val lookupFieldOffset = importRtFunction("LookupFieldOffset") - val lookupOpenMethodFunction = importRtFunction("LookupOpenMethod") - val isInstanceFunction = importRtFunction("IsInstance") - val checkInstanceFunction = importRtFunction("CheckInstance") - val throwExceptionFunction = importRtFunction("ThrowException") - val usedFunctions = mutableListOf() -} diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt index b55531974c4..f5e7984d076 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt @@ -2,7 +2,9 @@ package org.jetbrains.kotlin.backend.konan.llvm import kotlinx.cinterop.* import llvm.* +import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.hash.GlobalHash +import org.jetbrains.kotlin.backend.konan.KonanConfigKeys import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor @@ -22,7 +24,7 @@ internal interface ContextUtils { val context: Context val runtime: Runtime - get() = context.runtime + get() = context.llvm.runtime /** * Describes the target platform. @@ -33,7 +35,7 @@ internal interface ContextUtils { get() = runtime.targetData val staticData: StaticData - get() = context.staticData + get() = context.llvm.staticData /** * All fields of the class instance. @@ -161,3 +163,42 @@ internal interface ContextUtils { val FqName.localHash: LocalHash get() = this.toString().localHash } + + +internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) { + + private fun importFunction(name: String, otherModule: LLVMModuleRef): LLVMValueRef { + if (LLVMGetNamedFunction(llvmModule, name) != null) { + throw IllegalArgumentException("function $name already exists") + } + + val externalFunction = LLVMGetNamedFunction(otherModule, name)!! + + val functionType = getFunctionType(externalFunction) + return LLVMAddFunction(llvmModule, name, functionType)!! + } + + val staticData = StaticData(context) + + val runtimeFile = context.config.configuration.get(KonanConfigKeys.RUNTIME_FILE)!! + val runtime = Runtime(runtimeFile) // TODO: dispose + + init { + LLVMSetDataLayout(llvmModule, runtime.dataLayout) + LLVMSetTarget(llvmModule, runtime.target) + } + + private fun importRtFunction(name: String) = importFunction(name, runtime.llvmModule) + + val allocInstanceFunction = importRtFunction("AllocInstance") + val initInstanceFunction = importRtFunction("InitInstance") + val allocArrayFunction = importRtFunction("AllocArrayInstance") + val setArrayFunction = importRtFunction("Kotlin_Array_set") + val copyImplArrayFunction = importRtFunction("Kotlin_Array_copyImpl") + val lookupFieldOffset = importRtFunction("LookupFieldOffset") + val lookupOpenMethodFunction = importRtFunction("LookupOpenMethod") + val isInstanceFunction = importRtFunction("IsInstance") + val checkInstanceFunction = importRtFunction("CheckInstance") + val throwExceptionFunction = importRtFunction("ThrowException") + val usedFunctions = mutableListOf() +} diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index 8dab7a5cba2..4bdfd50528c 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -26,26 +26,32 @@ import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.typeUtil.isNothing import org.jetbrains.kotlin.types.typeUtil.isUnit -fun emitLLVM(module: IrModuleFragment, runtimeFile: String, outFile: String) { - val llvmModule = LLVMModuleCreateWithName("out")!! // TODO: dispose - val runtime = Runtime(runtimeFile) // TODO: dispose - LLVMSetDataLayout(llvmModule, runtime.dataLayout) - LLVMSetTarget(llvmModule, runtime.target) - // TODO: shall we provide better binding context? - val context = Context( - module, runtime, llvmModule, BindingContext.EMPTY) // TODO: dispose +internal fun emitLLVM(context: Context) { - KonanLower(context).lower(module) + val irModule = context.irModule!! + val llvmModule = LLVMModuleCreateWithName("out")!! // TODO: dispose + context.llvmModule = llvmModule - module.acceptVoid(RTTIGeneratorVisitor(context)) - println("\n--- Generate bitcode ------------------------------------------------------\n") - module.acceptVoid(CodeGeneratorVisitor(context)) - verifyModule(llvmModule) - LLVMWriteBitcodeToFile(llvmModule, outFile) + val phaser = PhaseManager(context) + + phaser.phase("RTTI") { + irModule.acceptVoid(RTTIGeneratorVisitor(context)) + } + + phaser.phase("Codegen") { + irModule.acceptVoid(CodeGeneratorVisitor(context)) + } + + phaser.phase("Metadator") { + irModule.acceptVoid(MetadatorVisitor(context)) + } + + val outFile = context.config.configuration.get(KonanConfigKeys.OUTPUT_FILE)!! + LLVMWriteBitcodeToFile(llvmModule, outFile) } -private fun verifyModule(llvmModule: LLVMModuleRef) { +internal fun verifyModule(llvmModule: LLVMModuleRef) { memScoped { val errorRef = allocPointerTo() // TODO: use LLVMDisposeMessage() on errorRef, once possible in interop. @@ -82,13 +88,33 @@ internal class RTTIGeneratorVisitor(context: Context) : IrElementVisitorVoid { } +//-------------------------------------------------------------------------// + +internal class MetadatorVisitor(val context: Context) : IrElementVisitorVoid { + + val metadator = MetadataGenerator(context) + + override fun visitElement(element: IrElement) { + element.acceptChildrenVoid(this) + } + + override fun visitModuleFragment(module: IrModuleFragment) { + module.acceptChildrenVoid(this) + metadator.endModule(module) + } +} + + //-------------------------------------------------------------------------// internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid { val codegen = CodeGenerator(context) - val logger = Logger(codegen, context) - val metadator = MetadataGenerator(context) + val logger = if (context.phase!!.verbose) { + Logger(codegen, context) + } else { + DummyLogger(codegen, context) + } //-------------------------------------------------------------------------// @@ -191,9 +217,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid logger.log("visitModule : ${ir2string(module)}") module.acceptChildrenVoid(this) - appendLlvmUsed(context.usedFunctions) - - metadator.endModule(module) + appendLlvmUsed(context.llvm.usedFunctions) } //-------------------------------------------------------------------------// @@ -459,7 +483,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid override fun genThrow(exception: LLVMValueRef) { val objHeaderPtr = codegen.bitcast(codegen.kObjHeaderPtr, exception, codegen.newVar()) val args = listOf(objHeaderPtr) - codegen.call(context.throwExceptionFunction, args, "") + codegen.call(context.llvm.throwExceptionFunction, args, "") codegen.unreachable() } } @@ -485,14 +509,14 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid return codegen.prologue(declaration) - metadator.function(declaration) using(FunctionScope(declaration)) { declaration.acceptChildrenVoid(this) } + codegen.epilogue(declaration) - verifyModule(context.llvmModule) + verifyModule(context.llvmModule!!) } //-------------------------------------------------------------------------// @@ -641,7 +665,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid val ctor = codegen.llvmFunction(initFunction) val args = listOf(objectPtr, typeInfo, allocHint, ctor) val newValue = currentCodeContext.genCall( - context.initInstanceFunction, args, codegen.newVar()) + context.llvm.initInstanceFunction, args, codegen.newVar()) codegen.br(bbExit) codegen.positionAtEnd(bbExit) @@ -763,14 +787,14 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid val typeInfo = codegen.typeInfoValue(value.type)!! val arrayCreationArgs = listOf(typeInfo, kImmInt32One, finalLength!!) - val array = currentCodeContext.genCall(context.allocArrayFunction, arrayCreationArgs, tmpVariableName) + val array = currentCodeContext.genCall(context.llvm.allocArrayFunction, arrayCreationArgs, tmpVariableName) elements.fold(kImmZero) { sum, (exp, size, isArray) -> if (!isArray) { - currentCodeContext.genCall(context.setArrayFunction, listOf(array, sum, exp), "") + currentCodeContext.genCall(context.llvm.setArrayFunction, listOf(array, sum, exp), "") return@fold codegen.plus(sum, kImmOne, codegen.newVar()) } else { - currentCodeContext.genCall(context.copyImplArrayFunction, listOf(exp, kImmZero, array, sum, size!!), "") + currentCodeContext.genCall(context.llvm.copyImplArrayFunction, listOf(exp, kImmZero, array, sum, size!!), "") return@fold codegen.plus(sum, size, codegen.newVar()) } } @@ -1251,7 +1275,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid val srcArg = evaluateExpression(codegen.newVar(), value.argument)!! // Evaluate src expression. val srcObjInfoPtr = codegen.bitcast(codegen.kObjHeaderPtr, srcArg, codegen.newVar()) // Cast src to ObjInfoPtr. val args = listOf(srcObjInfoPtr, dstTypeInfo) // Create arg list. - currentCodeContext.genCall(context.checkInstanceFunction, args, "") // Check if dst is subclass of src. + currentCodeContext.genCall(context.llvm.checkInstanceFunction, args, "") // Check if dst is subclass of src. return srcArg } @@ -1293,7 +1317,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid val args = listOf(srcObjInfoPtr, dstTypeInfo) // Create arg list. val result = currentCodeContext.genCall( // Check if dst is subclass of src. - context.isInstanceFunction, args, codegen.newVar()) + context.llvm.isInstanceFunction, args, codegen.newVar()) return LLVMBuildTrunc(codegen.builder, result, kInt1, tmpVariableName)!! // Truncate result to boolean } @@ -1422,7 +1446,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid IrConstKind.Int -> return LLVMConstInt(LLVMInt32Type(), (value.value as Int).toLong(), 1) IrConstKind.Long -> return LLVMConstInt(LLVMInt64Type(), value.value as Long, 1) IrConstKind.String -> - return context.staticData.kotlinStringLiteral(value as IrConst).llvm + return context.llvm.staticData.kotlinStringLiteral(value as IrConst).llvm IrConstKind.Float -> return LLVMConstRealOfString(LLVMFloatType(), (value.value as Float).toString()) IrConstKind.Double -> return LLVMConstRealOfString(LLVMDoubleType(), (value.value as Double).toString()) } @@ -1507,7 +1531,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid // however `vararg` is immutable, and in current implementation it has type `Array`, // so let's ignore this mismatch currently for simplicity. - return context.staticData.createArrayList(elementType, array, length).llvm + return context.llvm.staticData.createArrayList(elementType, array, length).llvm } } @@ -1641,9 +1665,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid val thisValue = if (containingClass.isArray) { assert(args.size == 1 && args[0].type == int32Type) val allocArrayInstanceArgs = listOf(typeInfo, allocHint, args[0]) - currentCodeContext.genCall(context.allocArrayFunction, allocArrayInstanceArgs, variableName) + currentCodeContext.genCall(context.llvm.allocArrayFunction, allocArrayInstanceArgs, variableName) } else { - currentCodeContext.genCall(context.allocInstanceFunction, listOf(typeInfo, allocHint), variableName) + currentCodeContext.genCall(context.llvm.allocInstanceFunction, listOf(typeInfo, allocHint), variableName) } val constructorParams: MutableList = mutableListOf() constructorParams += thisValue @@ -1833,7 +1857,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid val methodHash = codegen.functionHash(descriptor) // Calculate hash of the method to be invoked val lookupArgs = listOf(typeInfoPtr, methodHash) // Prepare args for lookup val llvmMethod = currentCodeContext.genCall( - context.lookupOpenMethodFunction, + context.llvm.lookupOpenMethodFunction, lookupArgs, codegen.newVar()) // Get method ptr to be invoked @@ -1897,7 +1921,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid val arrayLength = args.size val argsCasted = args.map { it -> constPointer(it).bitcast(int8TypePtr) } val llvmUsedGlobal = - context.staticData.placeGlobalArray("llvm.used", int8TypePtr, argsCasted) + context.llvm.staticData.placeGlobalArray("llvm.used", int8TypePtr, argsCasted) LLVMSetLinkage(llvmUsedGlobal.llvmGlobal, LLVMLinkage.LLVMAppendingLinkage); LLVMSetSection(llvmUsedGlobal.llvmGlobal, "llvm.metadata"); diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmUtils.kt index 47a1e5a2e0b..3af832c993e 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmUtils.kt @@ -3,6 +3,7 @@ package org.jetbrains.kotlin.backend.konan.llvm import kotlinx.cinterop.* import llvm.* import org.jetbrains.kotlin.backend.konan.allValueParameters +import org.jetbrains.kotlin.backend.konan.KonanPlatform import org.jetbrains.kotlin.descriptors.FunctionDescriptor internal val LLVMValueRef.type: LLVMTypeRef @@ -184,4 +185,4 @@ internal fun functionType(returnType: LLVMTypeRef, isVarArg: Boolean = false, va memScoped { val paramTypesPtr = allocArrayOf(*paramTypes)[0].ptr LLVMFunctionType(returnType, paramTypesPtr, paramTypes.size, if (isVarArg) 1 else 0)!! - } \ No newline at end of file + } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Logger.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Logger.kt index 84a9cd31fcc..2304e5939cd 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Logger.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Logger.kt @@ -2,23 +2,23 @@ package org.jetbrains.kotlin.backend.konan.llvm import kotlinx.cinterop.* import llvm.* +import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.util.DumpIrTreeVisitor import java.io.StringWriter -internal class Logger(val generator: CodeGenerator, override val context: Context) : ContextUtils { +internal open class Logger(val generator: CodeGenerator, override val context: Context) : ContextUtils { private var logcounter: Int = LLVMPrintModuleToString(context.llvmModule)!!.asCString().toString().lines().size //---------------------------------------------------------------------------// - fun log(msg: String) { - // logIr() + open fun log(msg: String) { println(msg) } //---------------------------------------------------------------------------// - fun logIr() { + open fun logIr() { val function = generator.currentFunction ?: return val irFunctionDeclaration = LLVMPrintValueToString(function.llvmFunction)!!.asCString().toString() @@ -48,3 +48,10 @@ fun llvm2string(value: LLVMValueRef?): String { return LLVMPrintValueToString(value)!!.asCString().toString() } + +//-----------------------------------------------------------------------------// + +internal class DummyLogger(generator: CodeGenerator, context: Context) : Logger(generator, context) { + override fun log(msg: String) = Unit + override fun logIr() = Unit +} diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/MetadataGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/MetadataGenerator.kt index d6373e73111..8e63f74c56b 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/MetadataGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/MetadataGenerator.kt @@ -1,10 +1,10 @@ package org.jetbrains.kotlin.backend.konan.llvm - import kotlinx.cinterop.* import llvm.* import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrModuleFragment +import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.llvm.BinaryLinkdata.* import org.jetbrains.kotlin.types.KotlinType @@ -104,7 +104,7 @@ internal class MetadataGenerator(override val context: Context): ContextUtils { } } - private fun metadataFun(fn: LLVMValueRef?, info: String): LLVMValueRef { + private fun metadataFun(fn: LLVMValueRef, info: String): LLVMValueRef { val args = listOf(fn, metadataString(info)); val md = metadataNode(args) return md @@ -146,11 +146,12 @@ internal class MetadataGenerator(override val context: Context): ContextUtils { // Convert it to ProtoBuf's TextFormat representation. // Use TextFormat.merge(str, builder) to parse it back val str = proto.toString() + return str } internal fun function(declaration: IrFunction) { - val fn = declaration.descriptor.llvmFunction + val fn = declaration.descriptor.llvmFunction!! val proto = serializeFunSignature(declaration) @@ -173,6 +174,7 @@ internal class MetadataGenerator(override val context: Context): ContextUtils { } private fun serializeModule(moduleDescriptor: ModuleDescriptor): String { + val description = JsModuleDescriptor( name = "foo", kind = ModuleKind.PLAIN, @@ -197,5 +199,3 @@ internal class MetadataGenerator(override val context: Context): ContextUtils { } } - - diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt index 070f2ba2512..72b9c8498ff 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt @@ -3,6 +3,7 @@ package org.jetbrains.kotlin.backend.konan.llvm import kotlinx.cinterop.* import llvm.* +import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.implementation import org.jetbrains.kotlin.backend.konan.implementedInterfaces import org.jetbrains.kotlin.backend.konan.isInterface diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/StaticData.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/StaticData.kt index 9b06f919f9d..5452676e021 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/StaticData.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/StaticData.kt @@ -2,6 +2,7 @@ package org.jetbrains.kotlin.backend.konan.llvm import llvm.* import org.jetbrains.kotlin.ir.expressions.IrConst +import org.jetbrains.kotlin.backend.konan.Context /** * Provides utilities to create static data. diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/StaticObjects.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/StaticObjects.kt index 97d660d0632..bf1b6b524fc 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/StaticObjects.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/StaticObjects.kt @@ -108,7 +108,7 @@ internal fun StaticData.createKotlinObject(type: KotlinType, body: ConstValue): } private fun StaticData.getArrayListClass(): ClassDescriptor { - val module = context.irModule.descriptor + val module = context.irModule!!.descriptor val pkg = module.getPackage(FqName.fromSegments(listOf("kotlin", "collections"))) val classifier = pkg.memberScope.getContributedClassifier(Name.identifier("ArrayList"), NoLookupLocation.FROM_BACKEND) @@ -138,4 +138,4 @@ internal fun StaticData.createArrayList(elementType: TypeProjection, array: Cons ) return createKotlinObject(type, body) -} \ No newline at end of file +}