original copy of student's translator

This commit is contained in:
Vasily Levchenko
2016-09-16 16:48:15 +03:00
parent 784dd97f72
commit 3d6013cbf0
38 changed files with 3067 additions and 0 deletions
@@ -0,0 +1,77 @@
package org.kotlinnative.translator
import org.jetbrains.kotlin.psi.*
import org.kotlinnative.translator.codegens.ClassCodegen
import org.kotlinnative.translator.codegens.FunctionCodegen
import org.kotlinnative.translator.codegens.ObjectCodegen
import org.kotlinnative.translator.codegens.PropertyCodegen
class ProjectTranslator(val files: List<KtFile>,
val state: TranslationState) {
private var codeBuilder = state.codeBuilder
fun generateCode(): String {
with(files) {
map { addClassDeclarations(it) }
map { addObjectDeclarations(it) }
map { addFunctionDeclarations(it) }
map { addPropertyDeclarations(it) }
}
generateProjectBody()
return codeBuilder.toString()
}
fun addFunctionDeclarations(file: KtFile) {
val variableManager = VariableManager(state.globalVariableCollection)
for (declaration in file.declarations.filterIsInstance<KtNamedFunction>()) {
val function = FunctionCodegen(state, variableManager, declaration, codeBuilder)
if (function.external) {
state.externalFunctions.put(function.fullName, function)
} else {
state.functions.put(function.fullName, function)
}
}
}
fun addClassDeclarations(file: KtFile) {
val variableManager = VariableManager(state.globalVariableCollection)
for (declaration in file.declarations.filterIsInstance<KtClass>()) {
val codegen = ClassCodegen(state, variableManager, declaration, codeBuilder)
state.classes.put(codegen.structName, codegen)
}
}
fun addPropertyDeclarations(file: KtFile) {
val variableManager = VariableManager(state.globalVariableCollection)
for (declaration in file.declarations.filterIsInstance<KtProperty>()) {
val property = PropertyCodegen(state, variableManager, declaration, codeBuilder)
state.properties.put(declaration.name!!, property)
}
}
fun addObjectDeclarations(file: KtFile) {
val variableManager = VariableManager(state.globalVariableCollection)
for (declaration in file.declarations.filterIsInstance<KtObjectDeclaration>()) {
val codegen = ObjectCodegen(state, variableManager, declaration, codeBuilder)
state.objects.put(codegen.structName, codegen)
}
}
private fun generateProjectBody() {
with(state) {
properties.values.map { it.generate() }
objects.values.map { it.prepareForGenerate() }
classes.values.map { it.prepareForGenerate() }
objects.values.map { it.generate() }
classes.values.map { it.generate() }
externalFunctions.values.map { it.generate() }
functions.values.filter { it.isExtensionDeclaration }.map { it.generate() }
functions.values.filter { !it.isExtensionDeclaration }.map { it.generate() }
}
if (state.mainFunction != "main") {
codeBuilder.declareEntryPoint(state.mainFunction)
}
}
}
@@ -0,0 +1,117 @@
package org.kotlinnative.translator
import com.intellij.openapi.Disposable
import org.jetbrains.kotlin.analyzer.AnalysisResult
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.jvm.compiler.CliLightClassGenerationSupport
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.JvmPackagePartProvider
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.config.getModuleName
import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.addKotlinSourceRoots
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM
import org.jetbrains.kotlin.utils.PathUtil
import org.kotlinnative.translator.codegens.ClassCodegen
import org.kotlinnative.translator.codegens.FunctionCodegen
import org.kotlinnative.translator.codegens.ObjectCodegen
import org.kotlinnative.translator.codegens.PropertyCodegen
import org.kotlinnative.translator.exceptions.TranslationException
import org.kotlinnative.translator.llvm.LLVMBuilder
import org.kotlinnative.translator.llvm.LLVMVariable
import java.util.*
class TranslationState
private constructor
(
val environment: KotlinCoreEnvironment,
val bindingContext: BindingContext,
val mainFunction: String, arm: Boolean
) {
var externalFunctions = HashMap<String, FunctionCodegen>()
var functions = HashMap<String, FunctionCodegen>()
var classes = HashMap<String, ClassCodegen>()
var objects = HashMap<String, ObjectCodegen>()
var properties = HashMap<String, PropertyCodegen>()
val codeBuilder = LLVMBuilder(arm)
val extensionFunctions = HashMap<String, HashMap<String, FunctionCodegen>>()
val globalVariableCollection = HashMap<String, LLVMVariable>()
init {
POINTER_ALIGN = if (arm) 4 else 8
POINTER_SIZE = if (arm) 4 else 8
}
companion object {
var POINTER_ALIGN = 4
var POINTER_SIZE = 4
fun createTranslationState(sources1: List<String>, disposer: Disposable, mainFunction: String, arm: Boolean = false): TranslationState {
val configuration = CompilerConfiguration()
val messageCollector = object : MessageCollector {
private var hasError = false
override fun hasErrors(): Boolean = hasError
override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation) {
if (severity.isError) {
System.err.println("[${severity.toString()}]${location.path} ${location.line}:${location.column} $message")
hasError = true
}
}
}
configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector)
configuration.put(CommonConfigurationKeys.MODULE_NAME, JvmAbi.DEFAULT_MODULE_NAME)
configuration.addKotlinSourceRoots(sources)
val environment = KotlinCoreEnvironment.createForProduction(disposer, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
val bindingContext = analyze(environment)?.bindingContext ?: throw TranslationException("Can't initialize binding context for project")
return TranslationState(environment, bindingContext, mainFunction, arm)
}
private fun analyze(environment: KotlinCoreEnvironment): AnalysisResult? {
val collector = environment.configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
val analyzer = AnalyzerWithCompilerReport(collector)
analyzer.analyzeAndReport(environment.getSourceFiles(), object : AnalyzerWithCompilerReport.Analyzer {
override fun analyze(): AnalysisResult {
val sharedTrace = CliLightClassGenerationSupport.NoScopeRecordCliBindingTrace()
val moduleContext = TopDownAnalyzerFacadeForJVM.createContextWithSealedModule(environment.project, environment.getModuleName())
return TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegrationWithCustomContext(
moduleContext,
environment.getSourceFiles(),
sharedTrace,
environment.configuration.get(JVMConfigurationKeys.MODULES),
environment.configuration.get(JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS),
JvmPackagePartProvider(environment))
}
override fun reportEnvironmentErrors() {
val files = environment.configuration.jvmClasspathRoots
val runtimes = files.map { it.canonicalFile }.filter { it.name == PathUtil.KOTLIN_JAVA_RUNTIME_JAR && it.exists() }
collector.report(CompilerMessageSeverity.ERROR, runtimes.joinToString { it.path }, CompilerMessageLocation.NO_LOCATION)
System.err.println(runtimes.joinToString { it.toString() })
}
})
return if (analyzer.hasErrors()) null else analyzer.analysisResult
}
}
}
@@ -0,0 +1,48 @@
package org.kotlinnative.translator
import org.kotlinnative.translator.llvm.LLVMScope
import org.kotlinnative.translator.llvm.LLVMVariable
import org.kotlinnative.translator.llvm.types.LLVMType
import java.util.*
class VariableManager(val globalVariableCollection: HashMap<String, LLVMVariable>) {
private var fileVariableCollectionTree = HashMap<String, Stack<Pair<LLVMVariable, Int>>>()
private companion object UniqueGenerator {
private var unique = 0
fun generateUniqueString() =
".unique." + unique++
}
operator fun get(variableName: String): LLVMVariable? {
return fileVariableCollectionTree[variableName]?.peek()?.first ?: globalVariableCollection[variableName]
}
operator fun contains(variableName: String): Boolean {
return (fileVariableCollectionTree.contains(variableName) && !fileVariableCollectionTree[variableName]!!.empty()) || globalVariableCollection.containsKey(variableName)
}
fun pullOneUpwardLevelVariable(variableName: String) {
fileVariableCollectionTree[variableName]?.pop()
}
fun pullUpwardsLevel(level: Int) {
fileVariableCollectionTree.forEach { s, stack -> while (!stack.empty() && stack.peek().second >= level) stack.pop() }
}
fun addVariable(name: String, variable: LLVMVariable, level: Int) {
val stack = fileVariableCollectionTree.getOrDefault(name, Stack<Pair<LLVMVariable, Int>>())
stack.push(Pair(variable, level))
fileVariableCollectionTree.put(name, stack)
}
fun addGlobalVariable(name: String, variable: LLVMVariable) {
globalVariableCollection.put(name, variable)
}
fun receiveVariable(name: String, type: LLVMType, scope: LLVMScope, pointer: Int): LLVMVariable {
return LLVMVariable("managed${generateUniqueString()}.$name", type, name, scope, pointer)
}
}
@@ -0,0 +1,84 @@
package org.kotlinnative.translator.codegens
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.resolve.BindingContext
import org.kotlinnative.translator.TranslationState
import org.kotlinnative.translator.VariableManager
import org.kotlinnative.translator.exceptions.TranslationException
import org.kotlinnative.translator.llvm.LLVMBuilder
import org.kotlinnative.translator.llvm.types.LLVMReferenceType
import org.kotlinnative.translator.llvm.types.LLVMType
class ClassCodegen(state: TranslationState,
variableManager: VariableManager,
val clazz: KtClass,
codeBuilder: LLVMBuilder,
parentCodegen: StructCodegen? = null) :
StructCodegen(state, variableManager, clazz, codeBuilder, parentCodegen) {
val annotation: Boolean
val enum: Boolean
var companionObjectCodegen: ObjectCodegen? = null
val descriptor: ClassDescriptor
override var size: Int = 0
override val structName: String = clazz.fqName?.asString()!!
override val type: LLVMReferenceType
init {
type = LLVMReferenceType(structName, "class", align = TranslationState.POINTER_ALIGN, size = TranslationState.POINTER_SIZE, byRef = true)
descriptor = state.bindingContext.get(BindingContext.CLASS, clazz) ?: throw TranslationException("Can't receive descriptor of class " + clazz.name)
annotation = descriptor.kind == ClassKind.ANNOTATION_CLASS
enum = descriptor.kind == ClassKind.ENUM_CLASS
type.align = TranslationState.POINTER_ALIGN
}
override fun prepareForGenerate() {
val parameterList = clazz.getPrimaryConstructorParameterList()?.parameters ?: listOf()
indexFields(parameterList)
generateInnerFields(clazz.declarations)
type.size = calculateTypeSize()
if (annotation) {
return
}
super.prepareForGenerate()
nestedClasses.forEach { x, classCodegen -> classCodegen.prepareForGenerate() }
if (descriptor.companionObjectDescriptor != null) {
val companionObject = clazz.getCompanionObjects().first()
companionObjectCodegen = ObjectCodegen(state, variableManager, companionObject, codeBuilder, this)
companionObjectCodegen!!.prepareForGenerate()
}
}
override fun generate() {
if (annotation) {
return
}
super.generate()
nestedClasses.forEach { x, classCodegen -> classCodegen.generate() }
companionObjectCodegen?.generate()
}
private fun indexFields(parameters: MutableList<KtParameter>) {
if (annotation) {
return
}
val currentConstructorFields = parameters.mapIndexed { i, it -> resolveType(it, state.bindingContext.get(BindingContext.TYPE, it.typeReference)!!, fields.size + i) }
fields.addAll(currentConstructorFields)
fieldsIndex.putAll(currentConstructorFields.map { Pair(it.label, it) })
primaryConstructorIndex = LLVMType.mangleFunctionArguments(currentConstructorFields)
constructorFields.put(primaryConstructorIndex!!, currentConstructorFields)
}
}
@@ -0,0 +1,138 @@
package org.kotlinnative.translator.codegens
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.psiUtil.isExtensionDeclaration
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
import org.kotlinnative.translator.TranslationState
import org.kotlinnative.translator.VariableManager
import org.kotlinnative.translator.llvm.*
import org.kotlinnative.translator.llvm.types.LLVMFunctionType
import org.kotlinnative.translator.llvm.types.LLVMReferenceType
import org.kotlinnative.translator.llvm.types.LLVMType
import org.kotlinnative.translator.llvm.types.LLVMVoidType
import java.util.*
class FunctionCodegen(state: TranslationState,
variableManager: VariableManager,
val function: KtNamedFunction,
codeBuilder: LLVMBuilder) :
BlockCodegen(state, variableManager, codeBuilder) {
var name: String
var args = LinkedList<LLVMVariable>()
val isExtensionDeclaration = function.isExtensionDeclaration()
var functionNamePrefix = ""
val external: Boolean
val defaultValues: List<KtExpression?>
val fullName: String
get() = functionNamePrefix + name
init {
val descriptor = state.bindingContext.get(BindingContext.FUNCTION, function)!!
args.addAll(descriptor.valueParameters.map {
LLVMInstanceOfStandardType(it?.fqNameSafe?.asString() ?: it.name.toString(), it.type, state = state)
})
returnType = LLVMInstanceOfStandardType("instance", descriptor.returnType!!, state = state)
if (returnType!!.type is LLVMReferenceType) {
returnType!!.pointer = 2
}
external = descriptor.isExternal
name = if (external) function.name!! else function.fqName!!.convertToNativeName() + LLVMType.mangleFunctionArguments(args)
if (isExtensionDeclaration) {
name = "${function.name}${if (!external) LLVMType.mangleFunctionArguments(args) else ""}"
val receiverType = descriptor.extensionReceiverParameter!!.type
val translatorType = LLVMMapStandardType(receiverType, state)
val packageName = (function.containingFile as KtFile).packageFqName.asString()
functionNamePrefix = packageName.addAfterIfNotEmpty(".") + translatorType.mangle + "."
val extensionFunctionsOfThisType = state.extensionFunctions.getOrDefault(translatorType.toString(), HashMap())
extensionFunctionsOfThisType.put(fullName, this)
state.extensionFunctions.put(translatorType.toString(), extensionFunctionsOfThisType)
}
defaultValues = descriptor.valueParameters.indices.map {
val parameterDescriptor = descriptor.valueParameters[it]
if (parameterDescriptor.declaresDefaultValue()) {
val initializer = (parameterDescriptor.source as KotlinSourceElement).psi as KtParameter
initializer.defaultValue
} else {
null
}
}
}
fun generate(this_type: LLVMVariable? = null) {
generateDeclaration(this_type)
if (external) {
return
}
codeBuilder.addStartExpression()
generateLoadArguments()
evaluateCodeBlock(function.bodyExpression, scopeDepth = topLevelScopeDepth, isBlock = function.hasBlockBody())
if (returnType?.type is LLVMVoidType){
codeBuilder.addAnyReturn(LLVMVoidType())
}
codeBuilder.addEndExpression()
}
private fun generateDeclaration(this_type: LLVMVariable? = null) {
var actualReturnType: LLVMType = returnType!!.type
val actualArgs = ArrayList<LLVMVariable>()
if (returnType!!.pointer > 0) {
actualReturnType = LLVMVoidType()
actualArgs.add(returnType!!)
}
if (isExtensionDeclaration) {
val receiverParameter = state.bindingContext.get(BindingContext.FUNCTION, function)!!.extensionReceiverParameter!!
val receiverType = receiverParameter.type
val translatorType = LLVMMapStandardType(receiverType, state)
val classVal = when (translatorType) {
is LLVMReferenceType -> LLVMVariable("classvariable.this", translatorType, pointer = 1)
else -> LLVMVariable("type", translatorType, pointer = 0)
}
variableManager.addVariable("this", classVal, level = 0)
actualArgs.add(classVal)
}
if (this_type != null) {
actualArgs.add(this_type)
}
actualArgs.addAll(args)
codeBuilder.addLLVMCodeToLocalPlace(LLVMFunctionDescriptor(fullName, actualArgs, actualReturnType, external))
}
private fun generateLoadArguments() {
args.forEach(fun(it: LLVMVariable) {
if (it.type is LLVMFunctionType || (it.type is LLVMReferenceType && it.type.byRef)) {
variableManager.addVariable(it.label, LLVMVariable(it.label, it.type, it.label, LLVMRegisterScope(), pointer = 1), topLevelScopeDepth)
return
}
if (it.type !is LLVMReferenceType || it.type.byRef) {
val loadVariable = LLVMVariable(it.label, it.type, it.label, LLVMRegisterScope(), pointer = it.pointer)
val allocVar = codeBuilder.loadArgument(loadVariable)
variableManager.addVariable(it.label, allocVar, topLevelScopeDepth)
} else {
variableManager.addVariable(it.label, LLVMVariable(it.label, it.type, it.label, LLVMRegisterScope(), pointer = 0), topLevelScopeDepth)
}
})
}
}
@@ -0,0 +1,43 @@
package org.kotlinnative.translator.codegens
import org.jetbrains.kotlin.psi.KtObjectDeclaration
import org.jetbrains.kotlin.resolve.BindingContext
import org.kotlinnative.translator.TranslationState
import org.kotlinnative.translator.VariableManager
import org.kotlinnative.translator.llvm.LLVMBuilder
import org.kotlinnative.translator.llvm.LLVMVariable
import org.kotlinnative.translator.llvm.LLVMVariableScope
import org.kotlinnative.translator.llvm.types.LLVMReferenceType
import org.kotlinnative.translator.llvm.types.LLVMType
class ObjectCodegen(state: TranslationState,
variableManager: VariableManager,
val objectDeclaration: KtObjectDeclaration,
codeBuilder: LLVMBuilder,
parentCodegen: StructCodegen? = null) :
StructCodegen(state, variableManager, objectDeclaration, codeBuilder, parentCodegen) {
override var size: Int = 0
override val structName: String = objectDeclaration.fqName?.asString()!!
override val type = LLVMReferenceType(structName, "class")
init {
primaryConstructorIndex = LLVMType.mangleFunctionArguments(emptyList())
constructorFields.put(primaryConstructorIndex!!, arrayListOf())
}
override fun prepareForGenerate() {
generateInnerFields(objectDeclaration.declarations)
type.size = calculateTypeSize()
super.prepareForGenerate()
val classInstance = LLVMVariable("object.instance.$structName", type, objectDeclaration.name, LLVMVariableScope(), pointer = 1)
codeBuilder.addGlobalInitialize(classInstance, fields, initializedFields.map {
val type = state.bindingContext.get(BindingContext.EXPRESSION_TYPE_INFO, it.value)!!.type!!
Pair(it.key, state.bindingContext.get(BindingContext.COMPILE_TIME_VALUE, it.value)!!.getValue(type).toString())
}.toMap(), type)
variableManager.addGlobalVariable(structName, classInstance)
}
}
@@ -0,0 +1,33 @@
package org.kotlinnative.translator.codegens
import org.jetbrains.kotlin.js.descriptorUtils.nameIfStandardType
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.resolve.BindingContext
import org.kotlinnative.translator.TranslationState
import org.kotlinnative.translator.VariableManager
import org.kotlinnative.translator.llvm.LLVMBuilder
import org.kotlinnative.translator.llvm.LLVMInstanceOfStandardType
import org.kotlinnative.translator.llvm.LLVMVariable
import org.kotlinnative.translator.llvm.LLVMVariableScope
class PropertyCodegen(val state: TranslationState,
val variableManager: VariableManager,
val property: KtProperty,
val codeBuilder: LLVMBuilder) {
fun generate() {
val varInfo = state.bindingContext.get(BindingContext.VARIABLE, property)?.compileTimeInitializer ?: return
val kotlinType = varInfo.type
val value = varInfo.value
if (kotlinType.nameIfStandardType != null) {
val variableType = LLVMInstanceOfStandardType(property.name ?: return, kotlinType, state = state).type
val variable = LLVMVariable(property.name.toString(), variableType, property.name.toString(), LLVMVariableScope())
variableManager.addGlobalVariable(property.name.toString(), variable)
codeBuilder.defineGlobalVariable(variable, variableType.parseArg(value.toString()))
variable.pointer++
}
}
}
@@ -0,0 +1,252 @@
package org.kotlinnative.translator.codegens
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.types.KotlinType
import org.kotlinnative.translator.TranslationState
import org.kotlinnative.translator.VariableManager
import org.kotlinnative.translator.llvm.*
import org.kotlinnative.translator.llvm.types.LLVMCharType
import org.kotlinnative.translator.llvm.types.LLVMReferenceType
import org.kotlinnative.translator.llvm.types.LLVMType
import org.kotlinnative.translator.llvm.types.LLVMVoidType
import java.util.*
/*
* TODO make high level description of code generation process
* and structure of generated code.
*/
abstract class StructCodegen(val state: TranslationState,
val variableManager: VariableManager,
val classOrObject: KtClassOrObject,
val codeBuilder: LLVMBuilder,
val parentCodegen: StructCodegen? = null) {
val fields = ArrayList<LLVMClassVariable>()
val fieldsIndex = HashMap<String, LLVMClassVariable>()
val nestedClasses = HashMap<String, ClassCodegen>()
val enumFields = HashMap<String, LLVMVariable>()
val constructorFields = HashMap<String, List<LLVMVariable>>()
var primaryConstructorIndex: String? = null
val initializedFields = HashMap<LLVMVariable, KtExpression>()
var methods = HashMap<String, FunctionCodegen>()
abstract val type: LLVMReferenceType
abstract var size: Int
abstract val structName: String
open fun prepareForGenerate() {
generateStruct()
classOrObject.declarations.filterIsInstance<KtNamedFunction>().map {
val function = FunctionCodegen(state, variableManager, it, codeBuilder)
methods.put(function.name, function)
}
}
fun calculateTypeSize(): Int {
val classAlignment = fields.map { it.type.align }.max()?.toInt() ?: 0
var alignmentRemainder = 0
size = 0
for (item in fields) {
val currentFieldSize = if (item.pointer > 0) TranslationState.POINTER_ALIGN else item.type.align
alignmentRemainder -= (alignmentRemainder % currentFieldSize)
if (alignmentRemainder < currentFieldSize) {
size += classAlignment
alignmentRemainder = classAlignment - currentFieldSize
} else {
alignmentRemainder -= currentFieldSize
}
}
return size
}
open fun generate() {
generateEnumFields()
generatePrimaryConstructor()
classOrObject.getSecondaryConstructors().map { generateSecondaryConstructor(it) }
val classVal = LLVMVariable("classvariable.this", type, pointer = if (type.isPrimitive) 0 else 1)
variableManager.addVariable("this", classVal, level = 0)
methods.values.map { it.generate(classVal) }
}
fun generateInnerFields(declarations: List<KtDeclaration>) {
for (declaration in declarations) {
when (declaration) {
is KtProperty -> {
val ktType = state.bindingContext.get(BindingContext.TYPE, declaration.typeReference)
?: state.bindingContext.get(BindingContext.VARIABLE, declaration)!!.type
val field = resolveType(declaration, ktType, fields.size)
if (declaration.initializer != null) {
initializedFields.put(field, declaration.initializer!!)
}
fields.add(field)
fieldsIndex[field.label] = field
}
is KtEnumEntry -> {
val name = declaration.name!!
val field = LLVMVariable("class.$structName.$name", type, scope = LLVMVariableScope(), pointer = 2)
enumFields.put(name, field)
}
is KtClass ->
nestedClasses.put(declaration.fqName!!.asString(),
ClassCodegen(state,
VariableManager(state.globalVariableCollection),
declaration, codeBuilder, this))
}
}
}
private fun generateEnumFields() {
val enumEntries = classOrObject.declarations.filterIsInstance<KtEnumEntry>()
for (declaration in enumEntries) {
val name = declaration.name!!
val initializer = declaration.initializerList!!.initializers[0]
val arguments = (initializer as KtSuperTypeCallEntry).valueArguments.map { it.getArgumentExpression()!!.text }
val field = codeBuilder.getNewVariable(type, scope = LLVMVariableScope())
val enumField = enumFields[name]!!
codeBuilder.defineGlobalVariable(field, codeBuilder.makeStructInitializer(constructorFields[primaryConstructorIndex]!!, arguments))
codeBuilder.defineGlobalVariable(LLVMVariable(enumField.label, enumField.type, enumField.kotlinName, enumField.scope, enumField.pointer - 1), field.toString())
}
}
private fun generateStruct() =
codeBuilder.createClass(structName, fields)
private fun generateSecondaryConstructor(secondaryConstructor: KtSecondaryConstructor) {
val thisCall = secondaryConstructor.getDelegationCall().calleeExpression
val descriptor = state.bindingContext.get(BindingContext.CONSTRUCTOR, secondaryConstructor)
val classVal = LLVMVariable("classvariable.this", type, pointer = 1)
variableManager.addVariable("this", classVal, level = 0)
val secondaryConstructorArguments = descriptor!!.valueParameters.map {
LLVMInstanceOfStandardType(it.fqNameSafe.convertToNativeName(), it.type, state = state)
}
val argFields = mutableListOf(classVal)
argFields.addAll(secondaryConstructorArguments)
val currentConstructorIndex = LLVMType.mangleFunctionArguments(secondaryConstructorArguments)
constructorFields.put(currentConstructorIndex, argFields)
codeBuilder.addLLVMCodeToLocalPlace(LLVMFunctionDescriptor(structName + currentConstructorIndex, argFields, LLVMVoidType()))
codeBuilder.addStartExpression()
secondaryConstructorArguments.map { variableManager.addVariable(it.label, it, level = 2) }
val blockCodegen = object : BlockCodegen(state, variableManager, codeBuilder) {}
val mainConstructorThis = blockCodegen.evaluateConstructorDelegationReferenceExpression(thisCall!!, this, secondaryConstructorArguments, 1) as LLVMVariable
variableManager.addVariable("this", mainConstructorThis, level = 0)
blockCodegen.evaluateCodeBlock(secondaryConstructor.bodyExpression, scopeDepth = 1)
generateReturn(codeBuilder.receivePointedArgument(variableManager["this"]!!, requirePointer = 1) as LLVMVariable)
codeBuilder.addAnyReturn(LLVMVoidType())
codeBuilder.addEndExpression()
}
private fun generatePrimaryConstructor() {
val classVal = LLVMVariable("classvariable.this", type, pointer = 1)
variableManager.addVariable("this", classVal, level = 0)
val argFields = mutableListOf(classVal)
argFields.addAll(constructorFields[primaryConstructorIndex]!!)
codeBuilder.addLLVMCodeToLocalPlace(LLVMFunctionDescriptor(structName + primaryConstructorIndex, argFields, LLVMVoidType()))
codeBuilder.addStartExpression()
generateLoadArguments(classVal)
generateAssignments()
generateReturn(LLVMVariable("classvariable.this.addr", type, scope = LLVMRegisterScope(), pointer = 1))
genClassInitializers()
codeBuilder.addAnyReturn(LLVMVoidType())
codeBuilder.addEndExpression()
}
private fun generateLoadArguments(thisField: LLVMVariable) {
val thisVariable = LLVMVariable(thisField.label, thisField.type, thisField.label, LLVMRegisterScope(), pointer = 0)
codeBuilder.loadArgument(thisVariable, false)
constructorFields[primaryConstructorIndex]!!.filter { it.type !is LLVMReferenceType }.forEach {
val loadVariable = LLVMVariable(it.label, it.type, it.label, LLVMRegisterScope())
codeBuilder.loadArgument(loadVariable)
}
}
private fun generateAssignments() {
constructorFields[primaryConstructorIndex]!!.forEach {
when (it.type) {
is LLVMReferenceType -> {
val classField = codeBuilder.getNewVariable(it.type, pointer = it.pointer + 1)
codeBuilder.loadClassField(classField, LLVMVariable("classvariable.this.addr", type, scope = LLVMRegisterScope(), pointer = 1), (it as LLVMClassVariable).offset)
codeBuilder.storeVariable(classField, it)
}
else -> {
val argument = codeBuilder.loadAndGetVariable(LLVMVariable("${it.label}.addr", it.type, scope = LLVMRegisterScope(), pointer = it.pointer + 1))
val classField = codeBuilder.getNewVariable(it.type, pointer = 1)
codeBuilder.loadClassField(classField, LLVMVariable("classvariable.this.addr", type, scope = LLVMRegisterScope(), pointer = 1), (it as LLVMClassVariable).offset)
codeBuilder.storeVariable(classField, argument)
}
}
}
val blockCodegen = object : BlockCodegen(state, variableManager, codeBuilder) {}
val receiverThis = LLVMVariable("classvariable.this.addr", type, scope = LLVMRegisterScope(), pointer = 1)
variableManager.addVariable("this", receiverThis, level = 2)
for ((variable, initializer) in initializedFields) {
val left = blockCodegen.evaluateMemberMethodOrField(receiverThis, variable.label, blockCodegen.topLevelScopeDepth, call = null)!!
val right = blockCodegen.evaluateExpression(initializer, scopeDepth = blockCodegen.topLevelScopeDepth)!!
blockCodegen.addPrimitiveBinaryOperation(KtTokens.EQ, left, right)
}
variableManager.pullOneUpwardLevelVariable("this")
}
private fun generateReturn(src: LLVMVariable) {
val dst = LLVMVariable("classvariable.this", type, scope = LLVMRegisterScope(), pointer = 1)
val castedDst = codeBuilder.bitcast(dst, LLVMCharType(), pointer = 1)
val castedSrc = codeBuilder.bitcast(src, LLVMCharType(), pointer = 1)
codeBuilder.memcpy(castedDst, castedSrc, size)
}
protected fun resolveType(field: KtNamedDeclaration, ktType: KotlinType, offset: Int): LLVMClassVariable {
val annotations = parseFieldAnnotations(field)
val fieldName = state.bindingContext.get(BindingContext.VALUE_PARAMETER, field as?KtParameter)?.fqNameSafe?.convertToNativeName()
?: field.fqName?.asString()
?: field.name!!
val result = LLVMInstanceOfStandardType(fieldName, ktType, LLVMRegisterScope(), state = state)
if (state.classes.containsKey(field.name!!)) {
return LLVMClassVariable(result.label, state.classes[fieldName]!!.type, result.pointer)
}
if (annotations.contains("Plain")) {
result.pointer = 0
}
return LLVMClassVariable(result.label, result.type, result.pointer, offset)
}
private fun parseFieldAnnotations(field: KtNamedDeclaration): Set<String> =
field.annotationEntries.map { state.bindingContext.get(BindingContext.ANNOTATION, it)?.type.toString() }.toHashSet()
protected fun genClassInitializers() =
classOrObject.getAnonymousInitializers().map {
object : BlockCodegen(state, variableManager, codeBuilder) {
fun generate() = evaluateCodeBlock(it.body, scopeDepth = topLevelScopeDepth)
}
}.map { it.generate() }
}
@@ -0,0 +1,59 @@
package org.kotlinnative.translator.debug
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiWhiteSpace
import com.intellij.psi.impl.source.tree.CompositeElement
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtNamedFunction
fun debugPrintNode(node: Any?, indent: Int = 0): Unit {
if (node == null) {
return
}
for (i in 0..indent) {
print(" ")
}
println(node.toString())
when (node) {
is CompositeElement -> {
debugPrintNode(node.firstChildNode, indent + 2)
debugPrintNode(node.treeNext, indent)
}
is PsiElement -> {
debugPrintNode(node.firstChild, indent + 2)
debugPrintNode(node.nextSibling, indent)
}
is PsiWhiteSpace -> {
debugPrintNode(node.firstChild, indent + 2)
debugPrintNode(node.nextSibling, indent)
}
else -> {
print(" not supported: " + node.javaClass.canonicalName)
}
}
}
fun printFunction(function: KtNamedFunction) {
debugPrintNode(function.node)
}
fun printClass(function: KtClass) {
debugPrintNode(function.node)
}
fun printFile(file: KtFile) {
for (declaration in file.declarations) {
when (declaration) {
is KtNamedFunction -> printFunction(declaration)
is KtClass -> printClass(declaration)
else -> println(declaration.toString())
}
}
}
@@ -0,0 +1,5 @@
package org.kotlinnative.translator.exceptions
import java.lang.Exception
class TranslationException(message: String) : Exception(message)
@@ -0,0 +1,5 @@
package org.kotlinnative.translator.exceptions
import java.lang.Exception
class UnimplementedException() : Exception()
@@ -0,0 +1,252 @@
package org.kotlinnative.translator.llvm
import org.kotlinnative.translator.TranslationState
import org.kotlinnative.translator.llvm.types.*
import java.rmi.UnexpectedException
import java.util.*
class LLVMBuilder(arm: Boolean = false) {
private val localCode: StringBuilder = StringBuilder()
private val globalCode: StringBuilder = StringBuilder()
private var variableCount = 0
private var labelCount = 0
private val exceptions = mapOf(
Pair("KotlinNullPointerException", initializeExceptionString("Exception in thread main kotlin.KotlinNullPointerException")))
init {
val declares = arrayOf(
"declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1)",
"declare i8* @malloc_heap(i32)",
"declare i32 @printf(i8*, ...)",
"declare void @abort()",
"%class.Nothing = type { }")
declares.forEach { addLLVMCodeToGlobalPlace(it) }
if (arm) {
val functionAttributes = """attributes #0 = { nounwind "stack-protector-buffer-size"="8" "target-cpu"="cortex-m3" "target-features"="+hwdiv,+strict-align" }"""
addLLVMCodeToGlobalPlace(functionAttributes)
}
}
fun addLLVMCodeToLocalPlace(code: String) =
localCode.appendln(code)
fun addLLVMCodeToGlobalPlace(code: String) =
globalCode.appendln(code)
fun addComment(comment: String) =
addLLVMCodeToLocalPlace("; " + comment)
fun addStartExpression() =
addLLVMCodeToLocalPlace("{")
fun addEndExpression() =
addLLVMCodeToLocalPlace("unreachable\n}")
fun addAssignment(lhs: LLVMVariable, rhs: LLVMNode) =
addLLVMCodeToLocalPlace("$lhs = $rhs")
fun addReturnOperator(llvmVariable: LLVMSingleValue) =
addLLVMCodeToLocalPlace("ret ${llvmVariable.type} $llvmVariable")
fun addAnyReturn(type: LLVMType, value: String = type.defaultValue, pointer: Int = 0) =
addLLVMCodeToLocalPlace("ret $type${"*".repeat(pointer)} $value")
fun addStringConstant(variable: LLVMVariable, value: String) =
addLLVMCodeToGlobalPlace("$variable = private unnamed_addr constant ${(variable.type as LLVMStringType).fullArrayType} c\"${value.replace("\"", "\\\"")}\\00\", align 1")
fun addCondition(condition: LLVMSingleValue, thenLabel: LLVMLabel, elseLabel: LLVMLabel) =
addLLVMCodeToLocalPlace("br ${condition.pointedType} $condition, label $thenLabel, label $elseLabel")
fun addUnconditionalJump(label: LLVMLabel) =
addLLVMCodeToLocalPlace("br label $label")
fun addExceptionCall(exceptionName: String) {
val exception = exceptions[exceptionName]
val printResult = getNewVariable(LLVMIntType(), pointer = 0)
addLLVMCodeToLocalPlace("$printResult = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds (${(exception!!.type as LLVMStringType).fullArrayType}* $exception, i32 0, i32 0))")
addFunctionCall(LLVMVariable("abort", LLVMVoidType(), scope = LLVMVariableScope()), emptyList())
}
fun addFunctionCall(functionName: LLVMVariable, arguments: List<LLVMVariable>) =
addLLVMCodeToLocalPlace("call ${functionName.type} $functionName(${arguments.joinToString { it -> "${it.type} $it" }})")
fun allocStackVar(target: LLVMVariable, asValue: Boolean = false, pointer: Boolean = false) {
val type = if (asValue) target.type.toString() else target.pointedType
addLLVMCodeToLocalPlace("$target = alloca ${if (pointer) type.removeSuffix("*") else type}, align ${target.type.align}")
}
fun allocStaticVar(target: LLVMVariable, asValue: Boolean = false, pointer: Boolean = false) {
val allocated = getNewVariable(LLVMCharType(), pointer = 1)
val size = if ((target.pointer >= 2) || (target.pointer >= 1 && !pointer)) TranslationState.POINTER_SIZE else target.type.size
addLLVMCodeToLocalPlace("$allocated = call i8* @malloc_heap(i32 $size)")
addLLVMCodeToLocalPlace("$target = bitcast ${allocated.pointedType} $allocated to ${if (asValue) target.type.toString() else target.pointedType}" + if (pointer) "" else "*")
}
fun addGlobalInitialize(target: LLVMVariable, fields: ArrayList<LLVMClassVariable>, initializers: Map<LLVMVariable, String>, classType: LLVMType) {
val code = "$target = internal global $classType { ${
fields.map { it.pointedType + " " + if (initializers.containsKey(it)) initializers[it] else "0" }.joinToString()
} }, align ${classType.align}"
addLLVMCodeToGlobalPlace(code)
}
fun bitcast(src: LLVMVariable, llvmType: LLVMType, pointer: Int): LLVMVariable {
val empty = getNewVariable(llvmType, pointer = pointer)
addLLVMCodeToLocalPlace("$empty = bitcast ${src.pointedType} $src to ${llvmType.toString() + "*".repeat(pointer)}")
return empty
}
fun convertVariableToType(variable: LLVMSingleValue, targetType: LLVMType): LLVMSingleValue {
var resultVariable = variable
if (variable.type != targetType) {
val convertedExpression = targetType.convertFrom(variable)
resultVariable = saveExpression(convertedExpression)
}
return resultVariable
}
fun copyVariable(from: LLVMVariable, to: LLVMVariable) =
when {
from.type is LLVMStringType && !from.type.isLoaded -> storeString(to, from, 0)
else -> copyVariableValue(to, from)
}
fun createClass(name: String, fields: List<LLVMVariable>) =
addLLVMCodeToGlobalPlace("%class.$name = type { ${fields.map { it.pointedType }.joinToString()} }")
fun declareEntryPoint(name: String) {
addLLVMCodeToLocalPlace("define weak void @main()")
addStartExpression()
addFunctionCall(LLVMVariable(name, LLVMVoidType(), scope = LLVMVariableScope()), listOf())
addAnyReturn(LLVMVoidType())
addEndExpression()
}
fun defineGlobalVariable(variable: LLVMVariable, defaultValue: String = variable.type.defaultValue) =
addLLVMCodeToLocalPlace("$variable = global ${variable.pointedType} $defaultValue, align ${variable.type.align}")
fun getNewVariable(type: LLVMType, pointer: Int = 0, kotlinName: String? = null, scope: LLVMScope = LLVMRegisterScope(), prefix: String = "var"): LLVMVariable {
variableCount++
return LLVMVariable("$prefix$variableCount", type, kotlinName, scope, pointer)
}
fun getNewLabel(scope: LLVMScope = LLVMRegisterScope(), prefix: String): LLVMLabel {
labelCount++
return LLVMLabel("label.$prefix.$labelCount", scope)
}
fun loadArgsIfRequired(names: List<LLVMSingleValue>, args: List<LLVMVariable>) =
names.mapIndexed(fun(i: Int, value: LLVMSingleValue): LLVMSingleValue {
return receivePointedArgument(value, args[i].pointer)
}).toList()
fun loadArgument(llvmVariable: LLVMVariable, store: Boolean = true): LLVMVariable {
val allocVar = LLVMVariable("${llvmVariable.label}.addr", llvmVariable.type, llvmVariable.kotlinName, LLVMRegisterScope(), pointer = llvmVariable.pointer + 1)
allocStackVar(allocVar, asValue = false, pointer = true)
if (store) {
storeVariable(allocVar, llvmVariable)
}
return allocVar
}
fun loadClassField(target: LLVMVariable, source: LLVMVariable, offset: Int) =
addLLVMCodeToLocalPlace("$target = getelementptr inbounds ${source.pointedType} $source, i32 0, i32 $offset")
fun loadVariableOffset(target: LLVMVariable, source: LLVMVariable, index: LLVMConstant) =
addLLVMCodeToLocalPlace("$target = getelementptr inbounds ${source.type} $source, ${index.type} ${index.value}")
fun loadAndGetVariable(source: LLVMVariable): LLVMVariable {
assert(source.pointer > 0)
val target = getNewVariable(source.type, source.pointer - 1, source.kotlinName)
addLLVMCodeToLocalPlace("$target = load ${source.pointedType} $source, align ${target.type.align}")
return target
}
fun makeStructInitializer(args: List<LLVMVariable>, values: List<String>)
= "{ ${args.mapIndexed { i: Int, variable: LLVMVariable -> "${variable.type} ${values[i]}" }.joinToString()} }"
fun markWithLabel(label: LLVMLabel?) {
if (label != null)
addLLVMCodeToLocalPlace("${label.label}:")
}
fun memcpy(castedDst: LLVMVariable, castedSrc: LLVMVariable, size: Int, align: Int = 4, volatile: Boolean = false) =
addLLVMCodeToLocalPlace("call void @llvm.memcpy.p0i8.p0i8.i64(i8* $castedDst, i8* $castedSrc, i64 $size, i32 $align, i1 $volatile)")
fun nullCheck(variable: LLVMVariable): LLVMVariable {
val result = getNewVariable(LLVMBooleanType(), pointer = 0)
val loaded = loadAndGetVariable(variable)
addLLVMCodeToLocalPlace("$result = icmp eq ${loaded.pointedType} null, $loaded")
return result
}
fun receiveNativeValue(firstOp: LLVMSingleValue): LLVMSingleValue =
when {
firstOp is LLVMConstant || firstOp.pointer == 0 -> firstOp
firstOp is LLVMVariable -> loadAndGetVariable(firstOp)
else -> throw UnexpectedException("Unknown inheritor of LLVMSingleValue")
}
fun receivePointedArgument(value: LLVMSingleValue, requirePointer: Int): LLVMSingleValue {
var result = value
while (result.pointer > requirePointer) {
result = receiveNativeValue(result)
}
if ((value.type is LLVMStringType) && !(value.type.isLoaded)) {
val newVariable = getNewVariable(value.type, pointer = result.pointer + 1)
allocStackVar(newVariable, asValue = true)
copyVariable(result as LLVMVariable, newVariable)
result = loadAndGetVariable(newVariable)
}
return result
}
fun storeString(target: LLVMVariable, source: LLVMVariable, offset: Int) {
val code = "store ${target.type} getelementptr inbounds (" +
"${(source.type as LLVMStringType).fullArrayType}* $source, i32 0, i32 $offset), ${target.pointedType} $target, align ${source.type.align}"
(target.type as LLVMStringType).isLoaded = true
addLLVMCodeToLocalPlace(code)
}
fun storeVariable(target: LLVMSingleValue, source: LLVMSingleValue) {
if ((source.type is LLVMStringType) && !(source.type.isLoaded)) {
storeString(target as LLVMVariable, source as LLVMVariable, 0)
} else {
addLLVMCodeToLocalPlace("store ${source.pointedType} $source, ${target.pointedType} $target, align ${source.type.align}")
}
}
fun saveExpression(expression: LLVMSingleValue): LLVMVariable {
val resultOp = getNewVariable(expression.type, pointer = expression.pointer)
addAssignment(resultOp, expression)
return resultOp
}
fun storeNull(result: LLVMVariable) =
addLLVMCodeToLocalPlace("store ${result.pointedType.dropLast(1)} null, ${result.pointedType} $result, align ${TranslationState.POINTER_ALIGN}")
override fun toString() = globalCode.toString() + localCode.toString()
private fun copyVariableValue(target: LLVMVariable, source: LLVMVariable) {
var from = source
if (source.pointer > 0) {
from = getNewVariable(source.type, source.pointer)
addLLVMCodeToLocalPlace("$from = load ${source.pointedType} $source, align ${from.type.align}")
}
addLLVMCodeToLocalPlace("store ${target.type} $from, ${target.pointedType} $target, align ${from.type.align}")
}
private fun initializeExceptionString(string: String): LLVMVariable {
val result = getNewVariable(LLVMStringType(string.length), pointer = 0, scope = LLVMVariableScope(), prefix = "exceptions.str.")
addStringConstant(result, string)
return result
}
}
@@ -0,0 +1,11 @@
package org.kotlinnative.translator.llvm
import org.kotlinnative.translator.llvm.types.LLVMType
class LLVMCall(val returnType: LLVMType,
val name: String,
val arguments: Collection<LLVMSingleValue>) : LLVMSingleValue(returnType) {
override fun toString() = "call $returnType $name(${arguments.joinToString { "${it.pointedType} ${it.toString()}" }})"
}
@@ -0,0 +1,8 @@
package org.kotlinnative.translator.llvm
import org.kotlinnative.translator.llvm.types.LLVMType
class LLVMClassVariable(label: String,
type: LLVMType,
pointer: Int = 0,
var offset: Int = 0) : LLVMVariable(label, type, pointer = pointer)
@@ -0,0 +1,13 @@
package org.kotlinnative.translator.llvm
import org.kotlinnative.translator.llvm.types.LLVMType
open class LLVMConstant(value: String,
type: LLVMType,
pointer: Int = 0) : LLVMSingleValue(type, pointer) {
val value = type.parseArg(value)
override fun toString() = value
}
@@ -0,0 +1,9 @@
package org.kotlinnative.translator.llvm
import org.kotlinnative.translator.llvm.types.LLVMType
class LLVMExpression(type: LLVMType, val llvmCode: String, pointer: Int = 0) : LLVMSingleValue(type, pointer) {
override fun toString() = llvmCode
}
@@ -0,0 +1,7 @@
package org.kotlinnative.translator.llvm
class LLVMLabel(val label: String, val scope: LLVMScope) : LLVMNode() {
override fun toString() = "$scope$label"
}
@@ -0,0 +1,3 @@
package org.kotlinnative.translator.llvm
abstract class LLVMNode
@@ -0,0 +1,11 @@
package org.kotlinnative.translator.llvm
abstract class LLVMScope
class LLVMVariableScope : LLVMScope() {
override fun toString() = "@"
}
class LLVMRegisterScope : LLVMScope() {
override fun toString() = "%"
}
@@ -0,0 +1,10 @@
package org.kotlinnative.translator.llvm
import org.kotlinnative.translator.llvm.types.LLVMType
open class LLVMSingleValue(val type: LLVMType, var pointer: Int = 0) : LLVMNode() {
open val pointedType: String
get() = type.toString() + "*".repeat(pointer)
}
@@ -0,0 +1,13 @@
package org.kotlinnative.translator.llvm
import org.kotlinnative.translator.llvm.types.LLVMType
open class LLVMVariable(val label: String,
type: LLVMType,
var kotlinName: String? = null,
val scope: LLVMScope = LLVMRegisterScope(),
pointer: Int = 0) : LLVMSingleValue(type, pointer) {
override fun toString() = "$scope$label"
}
@@ -0,0 +1,63 @@
package org.kotlinnative.translator.llvm
import org.jetbrains.kotlin.builtins.isFunctionTypeOrSubtype
import org.jetbrains.kotlin.js.descriptorUtils.nameIfStandardType
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.kotlinnative.translator.TranslationState
import org.kotlinnative.translator.llvm.types.*
fun LLVMFunctionDescriptor(name: String,
argTypes: List<LLVMVariable>?,
returnType: LLVMType,
declare: Boolean = false) =
"${if (declare) "declare" else "define weak"} $returnType @$name(${
argTypes?.mapIndexed { i: Int, s: LLVMVariable ->
"${s.pointedType} ${if (s.type is LLVMReferenceType && !s.type.byRef) "byval" else ""} %${s.label}"
}?.joinToString()}) #0"
fun LLVMInstanceOfStandardType(name: String,
type: KotlinType,
scope: LLVMScope = LLVMRegisterScope(),
state: TranslationState): LLVMVariable {
val typeName = type.toString().dropLastWhile { it == '?' }
val pointerMark = if (type.isMarkedNullable) 1 else 0
return when {
type.isFunctionTypeOrSubtype -> LLVMVariable(name, LLVMFunctionType(type, state), name, scope, pointer = 1)
typeName == "Boolean" -> LLVMVariable(name, LLVMBooleanType(), name, scope, pointerMark)
typeName == "Byte" -> LLVMVariable(name, LLVMByteType(), name, scope, pointerMark)
typeName == "Char" -> LLVMVariable(name, LLVMCharType(), name, scope, pointerMark)
typeName == "Short" -> LLVMVariable(name, LLVMShortType(), name, scope, pointerMark)
typeName == "Int" -> LLVMVariable(name, LLVMIntType(), name, scope, pointerMark)
typeName == "Long" -> LLVMVariable(name, LLVMLongType(), name, scope, pointerMark)
typeName == "Float" -> LLVMVariable(name, LLVMFloatType(), name, scope, pointerMark)
typeName == "Double" -> LLVMVariable(name, LLVMDoubleType(), name, scope, pointerMark)
typeName == "String" -> LLVMVariable(name, LLVMStringType(0), name, scope, pointerMark)
type.nameIfStandardType.toString() == "Nothing" -> LLVMVariable(name, LLVMNullType(), name, scope)
type.isUnit() -> LLVMVariable("", LLVMVoidType(), name, scope)
type.isMarkedNullable -> LLVMVariable(name, LLVMReferenceType(typeName, prefix = "class"), name, scope, pointer = pointerMark)
else -> {
val declarationDescriptor = type.constructor.declarationDescriptor!!
val refName = declarationDescriptor.fqNameSafe.asString()
val refType = state.classes[type.toString()]?.type ?: LLVMReferenceType(refName, align = TranslationState.POINTER_ALIGN, prefix = "class")
LLVMVariable(name, refType, name, scope, pointer = 1)
}
}
}
fun LLVMMapStandardType(type: KotlinType,
state: TranslationState) =
LLVMInstanceOfStandardType("type", type, LLVMRegisterScope(), state).type
fun String.addBeforeIfNotEmpty(add: String): String =
if (this.length > 0) add + this else this
fun String.addAfterIfNotEmpty(add: String): String =
if (this.length > 0) this + add else this
fun FqName.convertToNativeName(): String =
this.asString().replace(".<init>", "")
@@ -0,0 +1,9 @@
package org.kotlinnative.translator.llvm.types
interface LLVMArray {
val arrayElementType: LLVMType
val fullArrayType: String
val length: Int
}
@@ -0,0 +1,69 @@
package org.kotlinnative.translator.llvm.types
import org.kotlinnative.translator.llvm.LLVMExpression
import org.kotlinnative.translator.llvm.LLVMSingleValue
import java.lang.IllegalArgumentException
class LLVMBooleanType() : LLVMType() {
override val align = 4
override var size: Int = 1
override val defaultValue = "0"
override val mangle = "Boolean"
override val isPrimitive = true
override val typename = "i1"
override fun operatorMinus(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "sub nsw i1 $firstOp, $secondOp")
override fun operatorTimes(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "mul nsw i1 $firstOp, $secondOp")
override fun operatorPlus(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "add nsw i1 $firstOp, $secondOp")
override fun operatorDiv(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "sdiv i1 $firstOp, $secondOp")
override fun operatorLt(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp slt i1 $firstOp, $secondOp")
override fun operatorGt(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp sgt i1 $firstOp, $secondOp")
override fun operatorLeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp sle i1 $firstOp, $secondOp")
override fun operatorGeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp sge i1 $firstOp, $secondOp")
override fun operatorEq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp eq i1" + (if ((firstOp.pointer > 0) || (secondOp.pointer > 0)) "*" else "") + " $firstOp, $secondOp")
override fun operatorNeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp ne i1" + (if ((firstOp.pointer > 0) || (secondOp.pointer > 0)) "*" else "") + " $firstOp, $secondOp")
override fun operatorOr(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "or i1 $firstOp, $secondOp")
override fun operatorAnd(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "and i1 $firstOp, $secondOp")
override fun operatorXor(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "xor i1 $firstOp, $secondOp")
override fun equals(other: Any?) =
other is LLVMBooleanType
override fun parseArg(inputArg: String) =
when (inputArg.toLowerCase()) {
"true" -> "1"
"false" -> "0"
else -> throw IllegalArgumentException("Failed to parse boolean type")
}
override fun hashCode() =
mangle.hashCode()
}
@@ -0,0 +1,42 @@
package org.kotlinnative.translator.llvm.types
import org.kotlinnative.translator.llvm.LLVMExpression
import org.kotlinnative.translator.llvm.LLVMSingleValue
class LLVMByteType() : LLVMType() {
override val align = 1
override var size: Int = 1
override val mangle = "Byte"
override val typename = "i8"
override val defaultValue = "0"
override val isPrimitive = true
override fun operatorLt(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp slt i8 $firstOp, $secondOp")
override fun operatorGt(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp sgt i8 $firstOp, $secondOp")
override fun operatorLeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp sle i8 $firstOp, $secondOp")
override fun operatorGeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp sge i8 $firstOp, $secondOp")
override fun operatorEq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp eq i8" + (if ((firstOp.pointer > 0) || (secondOp.pointer > 0)) "*" else "") + " $firstOp, $secondOp")
override fun operatorNeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp ne i8" + (if ((firstOp.pointer > 0) || (secondOp.pointer > 0)) "*" else "") + " $firstOp, $secondOp")
override fun operatorMod(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMByteType(), "srem i8 $firstOp, $secondOp")
override fun equals(other: Any?) =
other is LLVMByteType
override fun hashCode() =
mangle.hashCode()
}
@@ -0,0 +1,41 @@
package org.kotlinnative.translator.llvm.types
import org.kotlinnative.translator.llvm.LLVMExpression
import org.kotlinnative.translator.llvm.LLVMSingleValue
class LLVMCharType() : LLVMType() {
override val align = 1
override var size: Int = 1
override val mangle = "Char"
override val typename = "i8"
override val defaultValue = "0"
override val isPrimitive = true
override fun parseArg(inputArg: String) = inputArg.first().toInt().toString()
override fun operatorLt(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp slt i8 $firstOp, $secondOp")
override fun operatorGt(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp sgt i8 $firstOp, $secondOp")
override fun operatorLeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp sle i8 $firstOp, $secondOp")
override fun operatorGeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp sge i8 $firstOp, $secondOp")
override fun operatorEq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp eq i8" + (if ((firstOp.pointer > 0) || (secondOp.pointer > 0)) "*" else "") + " $firstOp, $secondOp")
override fun operatorNeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp ne i8" + (if ((firstOp.pointer > 0) || (secondOp.pointer > 0)) "*" else "") + " $firstOp, $secondOp")
override fun equals(other: Any?) =
other is LLVMCharType
override fun hashCode() =
mangle.hashCode()
}
@@ -0,0 +1,61 @@
package org.kotlinnative.translator.llvm.types
import org.kotlinnative.translator.llvm.LLVMExpression
import org.kotlinnative.translator.llvm.LLVMSingleValue
class LLVMDoubleType() : LLVMType() {
override val align = 8
override var size: Int = 8
override val mangle = "Double"
override val typename = "double"
override val defaultValue = "0.0"
override val isPrimitive = true
override fun operatorMinus(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMDoubleType(), "fsub double $firstOp, $secondOp")
override fun operatorTimes(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMDoubleType(), "fmul double $firstOp, $secondOp")
override fun operatorPlus(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMDoubleType(), "fadd double $firstOp, $secondOp")
override fun operatorInc(firstOp: LLVMSingleValue) =
LLVMExpression(LLVMDoubleType(), "fadd double $firstOp, 1.0")
override fun operatorDiv(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMDoubleType(), "fdiv double $firstOp, $secondOp")
override fun operatorDec(firstOp: LLVMSingleValue) =
LLVMExpression(LLVMDoubleType(), "fsub double $firstOp, 1.0")
override fun operatorLt(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "fcmp olt double $firstOp, $secondOp")
override fun operatorGt(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "fcmp ogt double $firstOp, $secondOp")
override fun operatorLeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "fcmp ole double i32 $firstOp, $secondOp")
override fun operatorGeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "fcmp oge double i32 $firstOp, $secondOp")
override fun operatorEq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "fcmp oeq double $firstOp, $secondOp")
override fun operatorNeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "fcmp one double $firstOp, $secondOp")
override fun operatorMod(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMDoubleType(), "frem double $firstOp, $secondOp")
override fun equals(other: Any?) =
other is LLVMDoubleType
override fun hashCode() =
mangle.hashCode()
}
@@ -0,0 +1,61 @@
package org.kotlinnative.translator.llvm.types
import org.kotlinnative.translator.llvm.LLVMExpression
import org.kotlinnative.translator.llvm.LLVMSingleValue
class LLVMFloatType() : LLVMType() {
override val align = 4
override var size: Int = 4
override val mangle = "Float"
override val typename = "float"
override val defaultValue = "0.0"
override val isPrimitive = true
override fun operatorMinus(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMFloatType(), "fsub float $firstOp, $secondOp")
override fun operatorTimes(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMFloatType(), "fmul float $firstOp, $secondOp")
override fun operatorPlus(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMFloatType(), "fadd float $firstOp, $secondOp")
override fun operatorDiv(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMFloatType(), "fdiv float $firstOp, $secondOp")
override fun operatorInc(firstOp: LLVMSingleValue) =
LLVMExpression(LLVMDoubleType(), "fadd float $firstOp, 1.0")
override fun operatorDec(firstOp: LLVMSingleValue) =
LLVMExpression(LLVMDoubleType(), "fsub float $firstOp, 1.0")
override fun operatorLt(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "fcmp olt float $firstOp, $secondOp")
override fun operatorGt(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "fcmp ogt float $firstOp, $secondOp")
override fun operatorLeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "fcmp ole float i32 $firstOp, $secondOp")
override fun operatorGeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "fcmp oge float i32 $firstOp, $secondOp")
override fun operatorEq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "fcmp oeq float" + (if ((firstOp.pointer > 0) || (secondOp.pointer > 0)) "*" else "") + " $firstOp, $secondOp")
override fun operatorNeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "fcmp one float" + (if ((firstOp.pointer > 0) || (secondOp.pointer > 0)) "*" else "") + " $firstOp, $secondOp")
override fun operatorMod(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMFloatType(), "frem float $firstOp, $secondOp")
override fun equals(other: Any?) =
other is LLVMFloatType
override fun hashCode() =
typename.hashCode()
}
@@ -0,0 +1,37 @@
package org.kotlinnative.translator.llvm.types
import org.jetbrains.kotlin.types.KotlinType
import org.kotlinnative.translator.TranslationState
import org.kotlinnative.translator.llvm.LLVMInstanceOfStandardType
import org.kotlinnative.translator.llvm.LLVMVariable
class LLVMFunctionType(type: KotlinType, state: TranslationState) : LLVMType() {
override val defaultValue = ""
override val align: Int = 4
override var size: Int = 4
override val mangle: String
override val typename = "FunctionType"
val arguments: List<LLVMVariable>
val returnType: LLVMVariable
init {
val types = type.arguments.map { LLVMInstanceOfStandardType("", it.type, state = state) }.toList()
returnType = types.last()
arguments = types.dropLast(1)
mangle = "F.${LLVMType.mangleFunctionArguments(arguments)}.EF"
}
fun mangleArgs() = LLVMType.mangleFunctionArguments(arguments)
override fun toString() =
"${returnType.type} (${arguments.map { it.pointedType }.joinToString()})"
override fun equals(other: Any?) =
(other is LLVMFunctionType) && (mangle == other.mangle)
override fun hashCode() =
mangle.hashCode()
}
@@ -0,0 +1,89 @@
package org.kotlinnative.translator.llvm.types
import org.kotlinnative.translator.exceptions.UnimplementedException
import org.kotlinnative.translator.llvm.LLVMExpression
import org.kotlinnative.translator.llvm.LLVMSingleValue
class LLVMIntType() : LLVMType() {
override val align = 4
override var size: Int = 4
override val defaultValue = "0"
override val mangle = "Int"
override val typename = "i32"
override val isPrimitive = true
override fun convertFrom(source: LLVMSingleValue) =
when (source.type) {
is LLVMBooleanType,
is LLVMByteType,
is LLVMCharType,
is LLVMShortType -> LLVMExpression(LLVMIntType(), " sext ${source.type} $source to i32")
else -> throw UnimplementedException()
}
override fun operatorOr(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMIntType(), "or i32 $firstOp, $secondOp")
override fun operatorAnd(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMIntType(), "and i32 $firstOp, $secondOp")
override fun operatorXor(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMIntType(), "xor i32 $firstOp, $secondOp")
override fun operatorShl(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMIntType(), "shl i32 $firstOp, $secondOp")
override fun operatorShr(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMIntType(), "ashr i32 $firstOp, $secondOp")
override fun operatorUshr(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMIntType(), "lshr i32 $firstOp, $secondOp")
override fun operatorMinus(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMIntType(), "sub nsw i32 $firstOp, $secondOp")
override fun operatorTimes(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMIntType(), "mul nsw i32 $firstOp, $secondOp")
override fun operatorPlus(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMIntType(), "add nsw i32 $firstOp, $secondOp")
override fun operatorDiv(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMIntType(), "sdiv i32 $firstOp, $secondOp")
override fun operatorInc(firstOp: LLVMSingleValue) =
LLVMExpression(LLVMIntType(), "add nsw i32 $firstOp, 1")
override fun operatorDec(firstOp: LLVMSingleValue) =
LLVMExpression(LLVMIntType(), "sub nsw i32 $firstOp, 1")
override fun operatorLt(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp slt i32 $firstOp, $secondOp")
override fun operatorGt(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp sgt i32 $firstOp, $secondOp")
override fun operatorLeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp sle i32 $firstOp, $secondOp")
override fun operatorGeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp sge i32 $firstOp, $secondOp")
override fun operatorEq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp eq i32" + (if ((firstOp.pointer > 0) || (secondOp.pointer > 0)) "*" else "") + " $firstOp, $secondOp")
override fun operatorNeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp ne i32" + (if ((firstOp.pointer > 0) || (secondOp.pointer > 0)) "*" else "") + " $firstOp, $secondOp")
override fun operatorMod(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMIntType(), "srem i32 $firstOp, $secondOp")
override fun equals(other: Any?) =
other is LLVMIntType
override fun hashCode() =
mangle.hashCode()
}
@@ -0,0 +1,84 @@
package org.kotlinnative.translator.llvm.types
import org.kotlinnative.translator.exceptions.UnimplementedException
import org.kotlinnative.translator.llvm.LLVMExpression
import org.kotlinnative.translator.llvm.LLVMSingleValue
class LLVMLongType() : LLVMType() {
override val align = 8
override var size = 8
override val defaultValue = "0"
override val typename = "i64"
override val mangle = "Long"
override val isPrimitive = true
override fun convertFrom(source: LLVMSingleValue) =
when (source.type) {
is LLVMBooleanType,
is LLVMByteType,
is LLVMCharType,
is LLVMShortType,
is LLVMIntType -> LLVMExpression(LLVMLongType(), " sext ${source.type} $source to i64")
else -> throw UnimplementedException()
}
override fun operatorOr(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMLongType(), "or i64 $firstOp, $secondOp")
override fun operatorAnd(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMLongType(), "and i64 $firstOp, $secondOp")
override fun operatorXor(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMLongType(), "xor i64 $firstOp, $secondOp")
override fun operatorShl(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMLongType(), "shl i64 $firstOp, $secondOp")
override fun operatorShr(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMLongType(), "ashr i64 $firstOp, $secondOp")
override fun operatorUshr(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMLongType(), "lshr i64 $firstOp, $secondOp")
override fun operatorMinus(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMLongType(), "sub nsw i64 $firstOp, $secondOp")
override fun operatorTimes(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMLongType(), "mul nsw i64 $firstOp, $secondOp")
override fun operatorPlus(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMLongType(), "add nsw i64 $firstOp, $secondOp")
override fun operatorDiv(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMLongType(), "sdiv i64 $firstOp, $secondOp")
override fun operatorLt(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp slt i64 $firstOp, $secondOp")
override fun operatorGt(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp sgt i64 $firstOp, $secondOp")
override fun operatorLeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp sle i64 $firstOp, $secondOp")
override fun operatorGeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp sge i64 $firstOp, $secondOp")
override fun operatorEq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp eq i64" + (if ((firstOp.pointer > 0) || (secondOp.pointer > 0)) "*" else "") + " $firstOp, $secondOp")
override fun operatorNeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp ne i64" + (if ((firstOp.pointer > 0) || (secondOp.pointer > 0)) "*" else "") + " $firstOp, $secondOp")
override fun operatorMod(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMLongType(), "srem i64 $firstOp, $secondOp")
override fun equals(other: Any?) =
other is LLVMLongType
override fun hashCode() =
mangle.hashCode()
}
@@ -0,0 +1,20 @@
package org.kotlinnative.translator.llvm.types
class LLVMNullType(var baseType: LLVMType? = null) : LLVMType() {
override val align = 1
override var size = 0
override val defaultValue = "null"
override val mangle = ""
override val typename = baseType?.typename.orEmpty()
override fun parseArg(inputArg: String) = "null"
override fun toString() = baseType?.toString().orEmpty()
override fun equals(other: Any?) =
other is LLVMNullType
override fun hashCode() =
"null".hashCode()
}
@@ -0,0 +1,32 @@
package org.kotlinnative.translator.llvm.types
import org.kotlinnative.translator.TranslationState
import org.kotlinnative.translator.llvm.LLVMExpression
import org.kotlinnative.translator.llvm.LLVMSingleValue
import org.kotlinnative.translator.llvm.addAfterIfNotEmpty
class LLVMReferenceType(val type: String,
var prefix: String = "",
override var align: Int = TranslationState.POINTER_ALIGN,
override var size: Int = TranslationState.POINTER_SIZE,
var byRef: Boolean = true) : LLVMType() {
override val defaultValue: String = "null"
override val mangle = "Ref_$type"
override val typename = prefix.addAfterIfNotEmpty(".") + type
override fun toString() = "%$typename"
override fun operatorEq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp eq ${firstOp.pointedType} $firstOp, ${if (secondOp.type is LLVMNullType) "null" else "$secondOp"}")
override fun operatorNeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp ne ${firstOp.pointedType} $firstOp, ${if (secondOp.type is LLVMNullType) "null" else "$secondOp"}")
override fun equals(other: Any?) =
(other is LLVMReferenceType) and (typename.equals((other as LLVMReferenceType).typename))
override fun hashCode() =
typename.hashCode()
}
@@ -0,0 +1,45 @@
package org.kotlinnative.translator.llvm.types
import org.kotlinnative.translator.llvm.LLVMExpression
import org.kotlinnative.translator.llvm.LLVMSingleValue
class LLVMShortType() : LLVMType() {
override val align = 2
override var size: Int = 2
override val defaultValue = "0"
override val typename = "i16"
override val mangle = "Short"
override val isPrimitive = true
override fun operatorLt(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp slt i16 $firstOp, $secondOp")
override fun operatorGt(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp sgt i16 $firstOp, $secondOp")
override fun operatorLeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp sle i16 $firstOp, $secondOp")
override fun operatorGeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp sge i16 $firstOp, $secondOp")
override fun operatorEq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp eq i16" + (if ((firstOp.pointer > 0) || (secondOp.pointer > 0)) "*" else "") + " $firstOp, $secondOp")
override fun operatorNeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMBooleanType(), "icmp ne i16" + (if ((firstOp.pointer > 0) || (secondOp.pointer > 0)) "*" else "") + " $firstOp, $secondOp")
override fun operatorMod(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMShortType(), "srem i16 $firstOp, $secondOp")
override fun operatorDiv(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) =
LLVMExpression(LLVMShortType(), "sdiv i16 $firstOp, $secondOp")
override fun equals(other: Any?) =
other is LLVMShortType
override fun hashCode() =
mangle.hashCode()
}
@@ -0,0 +1,23 @@
package org.kotlinnative.translator.llvm.types
class LLVMStringType(override val length: Int, var isLoaded: Boolean = true) : LLVMArray, LLVMType() {
override val align = 8
override var size: Int = 1
override val defaultValue = ""
override val typename = "i8*"
override val mangle = "String"
override val arrayElementType = LLVMCharType()
override val fullArrayType = "[${length + 1} x i8]"
override fun equals(other: Any?) =
when (other) {
is LLVMStringType -> this.length == other.length
else -> false
}
override fun hashCode() =
length * 31 + if (isLoaded) 1 else 0 +
mangle.hashCode()
}
@@ -0,0 +1,55 @@
package org.kotlinnative.translator.llvm.types
import org.kotlinnative.translator.exceptions.UnimplementedException
import org.kotlinnative.translator.llvm.LLVMExpression
import org.kotlinnative.translator.llvm.LLVMSingleValue
abstract class LLVMType() {
companion object {
fun mangleFunctionArguments(names: List<LLVMSingleValue>) =
mangleFunctionTypes(names.map { it.type })
fun mangleFunctionTypes(names: List<LLVMType>) =
if (names.size > 0) "_${names.joinToString(separator = "_", transform = { it.mangle })}" else ""
fun nullOrVoidType(type: LLVMType): Boolean =
(type is LLVMNullType) or (type is LLVMVoidType)
fun isReferredType(type: LLVMType?): Boolean =
(type is LLVMNullType) or (type is LLVMReferenceType)
}
abstract val align: Int
abstract val typename: String
abstract var size: Int
abstract val defaultValue: String
abstract val mangle: String
open val isPrimitive: Boolean = false
open fun parseArg(inputArg: String) = inputArg
open fun convertFrom(source: LLVMSingleValue): LLVMExpression = throw UnimplementedException()
override fun toString() = typename
open fun operatorPlus(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression = throw UnimplementedException()
open fun operatorTimes(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression = throw UnimplementedException()
open fun operatorMinus(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression = throw UnimplementedException()
open fun operatorDiv(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression = throw UnimplementedException()
open fun operatorLt(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression = throw UnimplementedException()
open fun operatorGt(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression = throw UnimplementedException()
open fun operatorLeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression = throw UnimplementedException()
open fun operatorGeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression = throw UnimplementedException()
open fun operatorEq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression = throw UnimplementedException()
open fun operatorNeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression = throw UnimplementedException()
open fun operatorOr(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression = throw UnimplementedException()
open fun operatorAnd(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression = throw UnimplementedException()
open fun operatorXor(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression = throw UnimplementedException()
open fun operatorShl(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression = throw UnimplementedException()
open fun operatorShr(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression = throw UnimplementedException()
open fun operatorUshr(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression = throw UnimplementedException()
open fun operatorMod(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression = throw UnimplementedException()
open fun operatorInc(firstOp: LLVMSingleValue): LLVMExpression = throw UnimplementedException()
open fun operatorDec(firstOp: LLVMSingleValue): LLVMExpression = throw UnimplementedException()
}
@@ -0,0 +1,17 @@
package org.kotlinnative.translator.llvm.types
class LLVMVoidType() : LLVMType() {
override val align = 0
override var size = 0
override val defaultValue = ""
override val typename = "void"
override val mangle = ""
override fun equals(other: Any?) =
other is LLVMVoidType
override fun hashCode() =
typename.hashCode()
}