translator: add default constructors

This commit is contained in:
e5l
2016-07-12 18:14:25 +03:00
parent 08eeafa977
commit 6972a4d658
10 changed files with 101 additions and 49 deletions
@@ -12,9 +12,7 @@ import org.kotlinnative.translator.llvm.LLVMBuilder
import org.kotlinnative.translator.llvm.LLVMClassVariable import org.kotlinnative.translator.llvm.LLVMClassVariable
import org.kotlinnative.translator.llvm.LLVMFunctionDescriptor import org.kotlinnative.translator.llvm.LLVMFunctionDescriptor
import org.kotlinnative.translator.llvm.LLVMVariable import org.kotlinnative.translator.llvm.LLVMVariable
import org.kotlinnative.translator.llvm.types.LLVMType import org.kotlinnative.translator.llvm.types.*
import org.kotlinnative.translator.llvm.types.LLVMVoidType
import org.kotlinnative.translator.llvm.types.parseLLVMType
import java.util.* import java.util.*
class ClassCodegen(val state: TranslationState, val clazz: KtClass, val codeBuilder: LLVMBuilder) { class ClassCodegen(val state: TranslationState, val clazz: KtClass, val codeBuilder: LLVMBuilder) {
@@ -22,6 +20,8 @@ class ClassCodegen(val state: TranslationState, val clazz: KtClass, val codeBuil
val annotation: Boolean val annotation: Boolean
val native: Boolean val native: Boolean
val fields = ArrayList<LLVMVariable>() val fields = ArrayList<LLVMVariable>()
val name = "%class.${clazz.name}"
val type: LLVMType = parseLLVMType(name)
val size: Int val size: Int
init { init {
@@ -35,8 +35,7 @@ class ClassCodegen(val state: TranslationState, val clazz: KtClass, val codeBuil
if (!annotation) { if (!annotation) {
for (field in parameterList) { for (field in parameterList) {
val type = getNativeType(field) ?: parseLLVMType((field.typeReference?.typeElement as KtUserType).referencedName!!) val type = getNativeType(field) ?: parseLLVMType((field.typeReference?.typeElement as KtUserType).referencedName!!)
val field = LLVMClassVariable(field.name!!, type, offset) fields.add(LLVMClassVariable(field.name!!, type, offset))
fields.add(field)
currentSize += type.size currentSize += type.size
offset++ offset++
@@ -63,20 +62,56 @@ class ClassCodegen(val state: TranslationState, val clazz: KtClass, val codeBuil
} }
private fun generateDefaultConstructor() { private fun generateDefaultConstructor() {
codeBuilder.addLLVMCode(LLVMFunctionDescriptor(clazz.name!!, fields, LLVMVoidType())) val argFields = ArrayList<LLVMVariable>()
val refType = type.makeClone() as LLVMReferenceType
refType.addParam("sret")
val thisField = LLVMVariable("instance", refType, clazz.name, true)
argFields.add(thisField)
argFields.addAll(fields)
codeBuilder.addLLVMCode(LLVMFunctionDescriptor(clazz.name!!, argFields, LLVMVoidType()))
codeBuilder.addStartExpression() codeBuilder.addStartExpression()
generateLoadArguments() generateLoadArguments(thisField)
generateAssignments()
generateReturn()
codeBuilder.addVoidReturn()
codeBuilder.addEndExpression() codeBuilder.addEndExpression()
} }
private fun generateLoadArguments() { private fun generateLoadArguments(thisField: LLVMVariable) {
val thisVariable = LLVMVariable("%${thisField.label}", thisField.type, thisField.label, true)
codeBuilder.loadArgument(thisVariable, false)
fields.forEach { fields.forEach {
val loadVariable = LLVMVariable("%${it.label}", it.type, it.label) val loadVariable = LLVMVariable("%${it.label}", it.type, it.label)
codeBuilder.loadVariable(loadVariable) codeBuilder.loadArgument(loadVariable)
} }
} }
private fun generateAssignments() {
fields.forEach {
val argument = codeBuilder.getNewVariable(it.type)
codeBuilder.loadVariable(argument, LLVMVariable("%${it.label}.addr", it.type, "", true))
val classField = codeBuilder.getNewVariable(it.type, true)
codeBuilder.loadClassField(classField, LLVMVariable("%instance.addr", type, "", true), (it as LLVMClassVariable).offset)
codeBuilder.storeVariable(classField, argument)
}
}
private fun generateReturn() {
val dst = LLVMVariable("%instance", type, "", true)
val src = LLVMVariable("%instance.addr", type, "", true)
val castedDst = codeBuilder.bitcast(dst, LLVMCharType())
val castedSrc = codeBuilder.bitcast(src, LLVMCharType())
codeBuilder.memcpy(castedDst, castedSrc, size)
}
private fun getNativeType(field: KtParameter): LLVMType? { private fun getNativeType(field: KtParameter): LLVMType? {
for (annotation in field.annotationEntries) { for (annotation in field.annotationEntries) {
val annotationDescriptor = state.bindingContext.get(BindingContext.ANNOTATION, annotation) val annotationDescriptor = state.bindingContext.get(BindingContext.ANNOTATION, annotation)
@@ -65,8 +65,8 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction
private fun generateLoadArguments() { private fun generateLoadArguments() {
args?.forEach { args?.forEach {
val loadVariable = LLVMVariable("%${it.label}", it.type, it.label, true) val loadVariable = LLVMVariable("%${it.label}", it.type, it.label, false)
codeBuilder.loadVariable(loadVariable) codeBuilder.loadArgument(loadVariable)
variableManager.addVariable(it.label, loadVariable, 2) variableManager.addVariable(it.label, loadVariable, 2)
} }
} }
@@ -11,7 +11,7 @@ class LLVMBuilder {
fun getNewVariable(type: LLVMType?, pointer: Boolean = false): LLVMVariable { fun getNewVariable(type: LLVMType?, pointer: Boolean = false): LLVMVariable {
variableCount++ variableCount++
return LLVMVariable("%var$variableCount", type, pointer = pointer) return LLVMVariable("%var$variableCount", type, "", pointer)
} }
fun addLLVMCode(code: String) { fun addLLVMCode(code: String) {
@@ -32,7 +32,6 @@ class LLVMBuilder {
KtTokens.PLUS -> firstOp.type!!.operatorPlus(newVar, firstOp, secondOp) KtTokens.PLUS -> firstOp.type!!.operatorPlus(newVar, firstOp, secondOp)
KtTokens.MINUS -> firstOp.type!!.operatorMinus(newVar, firstOp, secondOp) KtTokens.MINUS -> firstOp.type!!.operatorMinus(newVar, firstOp, secondOp)
KtTokens.MUL -> firstOp.type!!.operatorTimes(newVar, firstOp, secondOp) KtTokens.MUL -> firstOp.type!!.operatorTimes(newVar, firstOp, secondOp)
KtTokens.EQ -> return moveVariableValue(secondOp, firstOp)
else -> throw UnsupportedOperationException("Unknown binary operator") else -> throw UnsupportedOperationException("Unknown binary operator")
} }
@@ -41,21 +40,6 @@ class LLVMBuilder {
return newVar return newVar
} }
private fun moveVariableValue(from: LLVMVariable, to: LLVMVariable): LLVMVariable {
//%0 = load i32, i32* %y, align 4
//store i32 %0, i32* %z, align 4
//%1 = load i32, i32* %z, align 4
llvmCode.appendln("VARIABLE from $from TO $to")
/*
val tmp1 = getNewVariable(from.type)
val tmp2 = getNewVariable(to.type)
llvmCode.appendln("$tmp1 = load ${tmp1.type}, ${tmp1.type}* $from, align ${tmp1.type?.align}")
llvmCode.appendln("store ${tmp1.type} $tmp1, ${to.type}* $to, align ${to.type?.align}")
llvmCode.appendln("$tmp2 = load ${tmp2.type}, ${tmp2.type}* $to, align ${to.type?.align}")*/
return from
}
fun clean() { fun clean() {
llvmCode = StringBuilder() llvmCode = StringBuilder()
} }
@@ -72,17 +56,35 @@ class LLVMBuilder {
llvmCode.appendln("ret void") llvmCode.appendln("ret void")
} }
fun loadVariable(llvmVariable: LLVMVariable) { fun loadArgument(llvmVariable: LLVMVariable, store: Boolean = true) {
addVariableByRef(llvmVariable, LLVMVariable("${llvmVariable.label}.addr", llvmVariable.type, llvmVariable.kotlinName, true)) addVariableByRef(LLVMVariable("${llvmVariable.label}.addr", llvmVariable.type, llvmVariable.kotlinName, true), llvmVariable, store)
} }
fun addVariableByRef(targetVariable: LLVMVariable, sourceVariable: LLVMVariable) { fun loadVariable(target: LLVMVariable, source: LLVMVariable) {
llvmCode.appendln("$sourceVariable = alloca ${sourceVariable.type}, align ${sourceVariable.type?.align}") val code = "$target = load ${target.type}, ${source.getType()} $source, align ${target.type?.align!!}"
llvmCode.appendln("store ${sourceVariable.type} $targetVariable, ${targetVariable.getType()} $sourceVariable, align ${targetVariable.type?.align}") llvmCode.appendln(code)
}
fun loadClassField(target: LLVMVariable, source: LLVMVariable, offset: Int) {
var code = "$target = getelementptr inbounds ${source.type}, ${source.type}* $source, i32 0, i32 $offset"
llvmCode.appendln(code)
}
fun storeVariable(target: LLVMVariable, source: LLVMVariable) {
var code = "store ${source.type} $source, ${target.getType()} $target, align ${source.type?.align!!}"
llvmCode.appendln(code)
}
fun addVariableByRef(targetVariable: LLVMVariable, sourceVariable: LLVMVariable, store: Boolean) {
llvmCode.appendln("$targetVariable = alloca ${sourceVariable.type}, align ${sourceVariable.type?.align}")
if (store) {
llvmCode.appendln("store ${sourceVariable.getType()} $sourceVariable, ${targetVariable.getType()} $targetVariable, align ${targetVariable.type?.align}")
}
} }
fun addVariableByValue(targetVariable: LLVMVariable, sourceVariable: LLVMVariable) { fun addVariableByValue(targetVariable: LLVMVariable, sourceVariable: LLVMVariable) {
val tmp = getNewVariable(targetVariable.type, pointer = true) val tmp = getNewVariable(targetVariable.type, true)
llvmCode.appendln("$tmp = alloca ${tmp.type}, align ${tmp.type?.align}") llvmCode.appendln("$tmp = alloca ${tmp.type}, align ${tmp.type?.align}")
llvmCode.appendln("store ${tmp.type} $sourceVariable, ${tmp.getType()} $tmp, align ${tmp.type?.align}") llvmCode.appendln("store ${tmp.type} $sourceVariable, ${tmp.getType()} $tmp, align ${tmp.type?.align}")
@@ -91,17 +93,28 @@ class LLVMBuilder {
} }
fun addConstant(sourceVariable: LLVMVariable): LLVMVariable { fun addConstant(sourceVariable: LLVMVariable): LLVMVariable {
val target = getNewVariable(sourceVariable.type, pointer = sourceVariable.pointer) val target = getNewVariable(sourceVariable.type, sourceVariable.pointer)
addVariableByValue(target, sourceVariable) addVariableByValue(target, sourceVariable)
return target return target
} }
fun createClass(name: String, fields: List<LLVMVariable>) { fun createClass(name: String, fields: List<LLVMVariable>) {
val code = "@class.$name = type { ${fields.map { it.type }.joinToString()} }" val code = "%class.$name = type { ${fields.map { it.type }.joinToString()} }"
llvmCode.appendln(code)
}
fun bitcast(dst: LLVMVariable, llvmType: LLVMType): LLVMVariable {
var empty = getNewVariable(llvmType, true)
var code = "$empty = bitcast ${dst.getType()} $dst to $llvmType*"
llvmCode.appendln(code)
return empty
}
fun memcpy(castedDst: LLVMVariable, castedSrc: LLVMVariable, size: Int, align: Int = 4, volatile: Boolean = false) {
var code = "call void @llvm.memcpy.p0i8.p0i8.i64(i8* $castedDst, i8* $castedSrc, i64 $size, i32 $align, i1 $volatile)"
llvmCode.appendln(code) llvmCode.appendln(code)
} }
override fun toString() = llvmCode.toString() override fun toString() = llvmCode.toString()
} }
@@ -3,4 +3,4 @@ package org.kotlinnative.translator.llvm
import org.kotlinnative.translator.llvm.types.LLVMType import org.kotlinnative.translator.llvm.types.LLVMType
class LLVMClassVariable(label: String, type: LLVMType? = null, offset: Int = 0) : LLVMVariable(label, type) class LLVMClassVariable(label: String, type: LLVMType? = null, val offset: Int = 0) : LLVMVariable(label, type)
@@ -6,7 +6,7 @@ import org.kotlinnative.translator.llvm.types.*
fun LLVMFunctionDescriptor(name: String, argTypes: List<LLVMVariable>?, returnType: LLVMType, declare: Boolean = false) = fun LLVMFunctionDescriptor(name: String, argTypes: List<LLVMVariable>?, returnType: LLVMType, declare: Boolean = false) =
"${if (declare) "declare" else "define"} $returnType @$name(${ "${if (declare) "declare" else "define"} $returnType @$name(${
argTypes?.mapIndexed { i: Int, s: LLVMVariable -> argTypes?.mapIndexed { i: Int, s: LLVMVariable ->
"${s.type} %${s.label}" "${s.getType()} %${s.label}"
}?.joinToString() })" }?.joinToString() })"
fun LLVMMapStandardType(type: String): LLVMType = when (type) { fun LLVMMapStandardType(type: String): LLVMType = when (type) {
@@ -2,8 +2,7 @@ package org.kotlinnative.translator.llvm.types
class LLVMCharType() : LLVMType() { class LLVMCharType() : LLVMType() {
override fun toString(): String = "i8"
override val align = 1 override val align = 1
override val size: Byte = 1 override val size: Byte = 1
override fun toString(): String = "i8"
} }
@@ -1,10 +1,16 @@
package org.kotlinnative.translator.llvm.types package org.kotlinnative.translator.llvm.types
import java.util.*
class LLVMReferenceType(val type: String) : LLVMType() { class LLVMReferenceType(val type: String) : LLVMType() {
override val align = 4 override val align = 4
override val size: Byte = 4 override val size: Byte = 4
override fun toString() = "$type"
override fun toString() = type private val params = ArrayList<String>()
fun addParam(param: String) {
params.add(param)
}
} }
@@ -3,7 +3,6 @@ package org.kotlinnative.translator.llvm.types
class LLVMShortType() : LLVMType() { class LLVMShortType() : LLVMType() {
override val size: Byte = 2 override val size: Byte = 2
override val align = 1 override val align = 2
override fun toString(): String = "i16" override fun toString(): String = "i16"
} }
@@ -4,12 +4,14 @@ import org.kotlinnative.translator.exceptions.UnimplementedException
import org.kotlinnative.translator.llvm.LLVMExpression import org.kotlinnative.translator.llvm.LLVMExpression
import org.kotlinnative.translator.llvm.LLVMVariable import org.kotlinnative.translator.llvm.LLVMVariable
abstract class LLVMType() { abstract class LLVMType() : Cloneable {
open fun operatorPlus(result: LLVMVariable, firstOp: LLVMVariable, secondOp: LLVMVariable): LLVMExpression = throw UnimplementedException() open fun operatorPlus(result: LLVMVariable, firstOp: LLVMVariable, secondOp: LLVMVariable): LLVMExpression = throw UnimplementedException()
open fun operatorTimes(result: LLVMVariable, firstOp: LLVMVariable, secondOp: LLVMVariable): LLVMExpression = throw UnimplementedException() open fun operatorTimes(result: LLVMVariable, firstOp: LLVMVariable, secondOp: LLVMVariable): LLVMExpression = throw UnimplementedException()
open fun operatorMinus(result: LLVMVariable, firstOp: LLVMVariable, secondOp: LLVMVariable): LLVMExpression = throw UnimplementedException() open fun operatorMinus(result: LLVMVariable, firstOp: LLVMVariable, secondOp: LLVMVariable): LLVMExpression = throw UnimplementedException()
fun makeClone() = clone()
abstract val align: Int abstract val align: Int
abstract val size: Byte abstract val size: Byte
} }
@@ -3,8 +3,6 @@ package org.kotlinnative.translator.llvm.types
class LLVMVoidType() : LLVMType() { class LLVMVoidType() : LLVMType() {
override val align = 0 override val align = 0
override fun toString(): String = "void"
override val size: Byte = 0 override val size: Byte = 0
override fun toString(): String = "void"
} }