From 6972a4d65848dc8a062070a93d64e501caeefec7 Mon Sep 17 00:00:00 2001 From: e5l Date: Tue, 12 Jul 2016 18:14:25 +0300 Subject: [PATCH] translator: add default constructors --- .../kotlinnative/translator/ClassCodegen.kt | 53 ++++++++++++--- .../translator/FunctionCodegen.kt | 4 +- .../translator/llvm/LLVMBuilder.kt | 67 +++++++++++-------- .../translator/llvm/LLVMClassVariable.kt | 2 +- .../translator/llvm/generators.kt | 2 +- .../translator/llvm/types/LLVMCharType.kt | 3 +- .../llvm/types/LLVMReferenceType.kt | 8 ++- .../translator/llvm/types/LLVMShortType.kt | 3 +- .../translator/llvm/types/LLVMType.kt | 4 +- .../translator/llvm/types/LLVMVoidType.kt | 4 +- 10 files changed, 101 insertions(+), 49 deletions(-) diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/ClassCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/ClassCodegen.kt index 32a696c0865..1a1c91abb2c 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/ClassCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/ClassCodegen.kt @@ -12,9 +12,7 @@ import org.kotlinnative.translator.llvm.LLVMBuilder import org.kotlinnative.translator.llvm.LLVMClassVariable import org.kotlinnative.translator.llvm.LLVMFunctionDescriptor import org.kotlinnative.translator.llvm.LLVMVariable -import org.kotlinnative.translator.llvm.types.LLVMType -import org.kotlinnative.translator.llvm.types.LLVMVoidType -import org.kotlinnative.translator.llvm.types.parseLLVMType +import org.kotlinnative.translator.llvm.types.* import java.util.* 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 native: Boolean val fields = ArrayList() + val name = "%class.${clazz.name}" + val type: LLVMType = parseLLVMType(name) val size: Int init { @@ -35,8 +35,7 @@ class ClassCodegen(val state: TranslationState, val clazz: KtClass, val codeBuil if (!annotation) { for (field in parameterList) { val type = getNativeType(field) ?: parseLLVMType((field.typeReference?.typeElement as KtUserType).referencedName!!) - val field = LLVMClassVariable(field.name!!, type, offset) - fields.add(field) + fields.add(LLVMClassVariable(field.name!!, type, offset)) currentSize += type.size offset++ @@ -63,20 +62,56 @@ class ClassCodegen(val state: TranslationState, val clazz: KtClass, val codeBuil } private fun generateDefaultConstructor() { - codeBuilder.addLLVMCode(LLVMFunctionDescriptor(clazz.name!!, fields, LLVMVoidType())) + val argFields = ArrayList() + 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() - generateLoadArguments() + generateLoadArguments(thisField) + generateAssignments() + generateReturn() + codeBuilder.addVoidReturn() 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 { 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? { for (annotation in field.annotationEntries) { val annotationDescriptor = state.bindingContext.get(BindingContext.ANNOTATION, annotation) diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt index 455e0a58127..7e6e0318754 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt @@ -65,8 +65,8 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction private fun generateLoadArguments() { args?.forEach { - val loadVariable = LLVMVariable("%${it.label}", it.type, it.label, true) - codeBuilder.loadVariable(loadVariable) + val loadVariable = LLVMVariable("%${it.label}", it.type, it.label, false) + codeBuilder.loadArgument(loadVariable) variableManager.addVariable(it.label, loadVariable, 2) } } diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMBuilder.kt b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMBuilder.kt index dc58c09573b..c44f9c08f6c 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMBuilder.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMBuilder.kt @@ -11,7 +11,7 @@ class LLVMBuilder { fun getNewVariable(type: LLVMType?, pointer: Boolean = false): LLVMVariable { variableCount++ - return LLVMVariable("%var$variableCount", type, pointer = pointer) + return LLVMVariable("%var$variableCount", type, "", pointer) } fun addLLVMCode(code: String) { @@ -32,7 +32,6 @@ class LLVMBuilder { KtTokens.PLUS -> firstOp.type!!.operatorPlus(newVar, firstOp, secondOp) KtTokens.MINUS -> firstOp.type!!.operatorMinus(newVar, firstOp, secondOp) KtTokens.MUL -> firstOp.type!!.operatorTimes(newVar, firstOp, secondOp) - KtTokens.EQ -> return moveVariableValue(secondOp, firstOp) else -> throw UnsupportedOperationException("Unknown binary operator") } @@ -41,21 +40,6 @@ class LLVMBuilder { 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() { llvmCode = StringBuilder() } @@ -72,17 +56,35 @@ class LLVMBuilder { llvmCode.appendln("ret void") } - fun loadVariable(llvmVariable: LLVMVariable) { - addVariableByRef(llvmVariable, LLVMVariable("${llvmVariable.label}.addr", llvmVariable.type, llvmVariable.kotlinName, true)) + fun loadArgument(llvmVariable: LLVMVariable, store: Boolean = true) { + addVariableByRef(LLVMVariable("${llvmVariable.label}.addr", llvmVariable.type, llvmVariable.kotlinName, true), llvmVariable, store) } - fun addVariableByRef(targetVariable: LLVMVariable, sourceVariable: LLVMVariable) { - llvmCode.appendln("$sourceVariable = alloca ${sourceVariable.type}, align ${sourceVariable.type?.align}") - llvmCode.appendln("store ${sourceVariable.type} $targetVariable, ${targetVariable.getType()} $sourceVariable, align ${targetVariable.type?.align}") + fun loadVariable(target: LLVMVariable, source: LLVMVariable) { + val code = "$target = load ${target.type}, ${source.getType()} $source, align ${target.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) { - 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("store ${tmp.type} $sourceVariable, ${tmp.getType()} $tmp, align ${tmp.type?.align}") @@ -91,17 +93,28 @@ class LLVMBuilder { } fun addConstant(sourceVariable: LLVMVariable): LLVMVariable { - val target = getNewVariable(sourceVariable.type, pointer = sourceVariable.pointer) + val target = getNewVariable(sourceVariable.type, sourceVariable.pointer) addVariableByValue(target, sourceVariable) return target } - fun createClass(name: String, fields: List) { - 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) } override fun toString() = llvmCode.toString() - } \ No newline at end of file diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMClassVariable.kt b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMClassVariable.kt index 3763c79e6dd..329341343f1 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMClassVariable.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMClassVariable.kt @@ -3,4 +3,4 @@ package org.kotlinnative.translator.llvm 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) diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/generators.kt b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/generators.kt index d408c76d6d8..8f5319e65a6 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/generators.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/generators.kt @@ -6,7 +6,7 @@ import org.kotlinnative.translator.llvm.types.* fun LLVMFunctionDescriptor(name: String, argTypes: List?, returnType: LLVMType, declare: Boolean = false) = "${if (declare) "declare" else "define"} $returnType @$name(${ argTypes?.mapIndexed { i: Int, s: LLVMVariable -> - "${s.type} %${s.label}" + "${s.getType()} %${s.label}" }?.joinToString() })" fun LLVMMapStandardType(type: String): LLVMType = when (type) { diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMCharType.kt b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMCharType.kt index 3a109c02d5c..e482a73c499 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMCharType.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMCharType.kt @@ -2,8 +2,7 @@ package org.kotlinnative.translator.llvm.types class LLVMCharType() : LLVMType() { - override fun toString(): String = "i8" override val align = 1 - override val size: Byte = 1 + override fun toString(): String = "i8" } diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMReferenceType.kt b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMReferenceType.kt index abdca17eb1b..5b7deaaed4f 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMReferenceType.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMReferenceType.kt @@ -1,10 +1,16 @@ package org.kotlinnative.translator.llvm.types +import java.util.* + class LLVMReferenceType(val type: String) : LLVMType() { override val align = 4 override val size: Byte = 4 + override fun toString() = "$type" - override fun toString() = type + private val params = ArrayList() + fun addParam(param: String) { + params.add(param) + } } \ No newline at end of file diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMShortType.kt b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMShortType.kt index b90f6d68e2d..1d5c11f7ca8 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMShortType.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMShortType.kt @@ -3,7 +3,6 @@ package org.kotlinnative.translator.llvm.types class LLVMShortType() : LLVMType() { override val size: Byte = 2 - override val align = 1 - + override val align = 2 override fun toString(): String = "i16" } diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMType.kt b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMType.kt index 84556d91af3..68a9c5435a8 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMType.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMType.kt @@ -4,12 +4,14 @@ import org.kotlinnative.translator.exceptions.UnimplementedException import org.kotlinnative.translator.llvm.LLVMExpression 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 operatorTimes(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 size: Byte } diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMVoidType.kt b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMVoidType.kt index 92845eaa37d..4790c3674b0 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMVoidType.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMVoidType.kt @@ -3,8 +3,6 @@ package org.kotlinnative.translator.llvm.types class LLVMVoidType() : LLVMType() { override val align = 0 - - override fun toString(): String = "void" override val size: Byte = 0 - + override fun toString(): String = "void" }