diff --git a/car_llvmkot/src/kotlin_main.ll b/car_llvmkot/src/kotlin_main.ll index a5ffb321776..042ddd43419 100644 --- a/car_llvmkot/src/kotlin_main.ll +++ b/car_llvmkot/src/kotlin_main.ll @@ -1,60 +1,9 @@ -declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1) -attributes #0 = { nounwind "stack-protector-buffer-size"="8" "target-cpu"="cortex-m3" "target-features"="+hwdiv,+strict-align" } -declare void @wait(i32 %loops) #0 -define void @programRotationRight() #0 -{ -call void @engine_turn_right() -call void @wait(i32 10) -ret void -} -define void @setCurProgram(i32 %program) #0 -{ -%program.addr = alloca i32, align 4 -store i32 %program, i32* %program.addr, align 4 -ret void -} -define void @programBackward() #0 -{ -call void @engine_backward() -call void @wait(i32 10) -ret void -} -declare void @leds_init() #0 -define void @programForward(i32 %delay) #0 -{ -%delay.addr = alloca i32, align 4 -store i32 %delay, i32* %delay.addr, align 4 -call void @engine_forward() -call void @wait(i32 10) -ret void -} -define void @procNextProgramPending() #0 -{ -ret void -} -declare void @engine_init() #0 -declare void @user_btn_init(void ()* %program) #0 -define void @setNextProgramPending() #0 -{ -ret void -} -declare void @engine_backward() #0 -define void @programRotationLeft() #0 -{ -call void @engine_turn_left() -call void @wait(i32 10) -ret void -} -define void @kotlin_main() #0 -{ -call void @leds_init() -call void @engine_init() -call void @user_btn_init(void ()* @setNextProgramPending) -call void @setCurProgram(i32 0) -ret void -} -declare void @engine_stop() #0 -declare void @engine_forward() #0 -declare void @engine_turn_left() #0 -declare void @engine_turn_right() #0 +Exception in thread "main" org.kotlinnative.translator.exceptions.TranslationException + at org.kotlinnative.translator.TranslationStateKt.parseAndAnalyze(TranslationState.kt:50) + at MainKt.main(main.kt:13) + at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) + at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.lang.reflect.Method.invoke(Method.java:498) + at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147) diff --git a/translator/src/main/kotlin/main.kt b/translator/src/main/kotlin/main.kt index 350babc2643..74d15cdca22 100644 --- a/translator/src/main/kotlin/main.kt +++ b/translator/src/main/kotlin/main.kt @@ -10,7 +10,7 @@ fun main(args: Array) { } val disposer = Disposer.newDisposable() - val state = parseAndAnalyze(args.asList(), disposer, true) + val state = parseAndAnalyze(args.asList(), disposer, arm = false) val files = state.environment.getSourceFiles() if (files.isEmpty()) { diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/ClassCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/ClassCodegen.kt index 8967cef7c63..18d99263583 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/ClassCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/ClassCodegen.kt @@ -67,6 +67,7 @@ class ClassCodegen(val state: TranslationState, val clazz: KtClass, val codeBuil val argFields = ArrayList() val refType = type.makeClone() as LLVMReferenceType refType.addParam("sret") + refType.isReturn = true val thisField = LLVMVariable("instance", refType, clazz.name, pointer = true) diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt index 0903962783b..5e9bd499f90 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt @@ -18,17 +18,30 @@ import java.util.* class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction, val codeBuilder: LLVMBuilder) { var name = function.fqName.toString() - var returnType: LLVMType - var args: List? + var returnType: LLVMVariable + var args = ArrayList() val variableManager = state.variableManager init { val descriptor = state.bindingContext.get(BindingContext.FUNCTION, function)!! - args = descriptor.valueParameters.map { + args.addAll(descriptor.valueParameters.map { LLVMMapStandardType(it.name.toString(), it.type) - } + }) - returnType = LLVMMapStandardType("", descriptor.returnType!!).type + returnType = LLVMMapStandardType("instance", descriptor.returnType!!) + val retType = returnType.type + when (retType) { + is LLVMReferenceType -> { + if (state.classes.containsKey(retType.type)) { + retType.prefix = "class" + } + + retType.isReturn = true + } + } + if (retType is LLVMReferenceType && state.classes.containsKey(retType.type)) { + retType.prefix = "class" + } } fun generate() { @@ -41,7 +54,7 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction evaluateCodeBlock(function.bodyExpression) - if (returnType is LLVMVoidType) { + if (returnType.type is LLVMVoidType) { codeBuilder.addVoidReturn() } @@ -51,6 +64,13 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction private fun generateDeclaration(): Boolean { var external = false + args.forEach { + val type = it.type + if (type is LLVMReferenceType && state.classes.containsKey(type.type)) { + type.prefix = "class" + } + } + var keyword = function.firstChild while (keyword != null) { if (keyword.text == "external") { @@ -61,15 +81,29 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction keyword = keyword.getNextSiblingIgnoringWhitespaceAndComments() } - codeBuilder.addLLVMCode(LLVMFunctionDescriptor(function.fqName.toString(), args, returnType, external, state.arm)) + var actualReturnType: LLVMType = returnType.type + val actualArgs = ArrayList() + + if (returnType.pointer) { + actualReturnType = LLVMVoidType() + actualArgs.add(returnType) + } + + actualArgs.addAll(args) + + codeBuilder.addLLVMCode(LLVMFunctionDescriptor(function.fqName.toString(), actualArgs, actualReturnType, external, state.arm)) return external } private fun generateLoadArguments() { - args?.forEach { - val loadVariable = LLVMVariable(it.label, it.type, it.label, LLVMLocalScope(), false) - val allocVar = codeBuilder.loadArgument(loadVariable) - variableManager.addVariable(it.label, allocVar, 2) + args.forEach { + if (it.type !is LLVMReferenceType || (it.type as LLVMReferenceType).isReturn) { + val loadVariable = LLVMVariable("${it.label}", it.type, it.label, LLVMLocalScope(), pointer = false) + val allocVar = codeBuilder.loadArgument(loadVariable) + variableManager.addVariable(it.label, allocVar, 2) + } else { + variableManager.addVariable(it.label, LLVMVariable(it.label, it.type, it.label, LLVMLocalScope(), pointer = true), 2) + } } } @@ -84,10 +118,7 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction is KtBlockExpression -> expressionWalker(expr.firstChild, scopeDepth + 1) is KtProperty -> evaluateLeafPsiElement(expr.firstChild as LeafPsiElement, scopeDepth) is KtBinaryExpression -> evaluateBinaryExpression(expr, scopeDepth) - is KtCallExpression -> { - val expression = evaluateCallExpression(expr, scopeDepth) as LLVMCall - codeBuilder.addLLVMCode(expression.toString()) - } + is KtCallExpression -> evaluateCallExpression(expr, scopeDepth) is PsiElement -> evaluateExpression(expr.firstChild, scopeDepth + 1) null -> { variableManager.pullUpwardsLevel(scopeDepth) @@ -104,9 +135,10 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction is KtBinaryExpression -> evaluateBinaryExpression(expr, scopeDepth) is KtConstantExpression -> evaluateConstantExpression(expr) is KtCallExpression -> evaluateCallExpression(expr, scopeDepth) + is KtCallableReferenceExpression -> evaluateCallableReferenceExpression(expr) is KtReferenceExpression -> evaluateReferenceExpression(expr) is KtIfExpression -> evaluateIfOperator(expr.firstChild as LeafPsiElement, scopeDepth + 1, true) - is KtDotQualifiedExpression -> evaluateDotExpression(expr, scopeDepth) + is KtDotQualifiedExpression -> evaluateDotExpression(expr) is PsiWhiteSpace -> null is KtStringTemplateExpression -> evaluateStringTemplateExpression(expr, scopeDepth + 1) is PsiElement -> evaluatePsiElement(expr, scopeDepth) @@ -124,7 +156,12 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction return variable } - private fun evaluateDotExpression(expr: KtDotQualifiedExpression, scopeDepth: Int): LLVMSingleValue? { + private fun evaluateCallableReferenceExpression(expr: KtCallableReferenceExpression): LLVMSingleValue? { + val kotlinType = state.bindingContext.get(BindingContext.EXPRESSION_TYPE_INFO, expr)!!.type!! + return LLVMMapStandardType(expr.text.substring(2), kotlinType) + } + + private fun evaluateDotExpression(expr: KtDotQualifiedExpression): LLVMSingleValue? { val receiverName = expr.receiverExpression.text val selectorName = expr.selectorExpression!!.text @@ -161,31 +198,90 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction val function = expr.firstChild.firstChild val descriptor = state.classes[function.text] ?: return null val names = parseArgList(expr, scopeDepth).mapIndexed { i: Int, v: LLVMSingleValue -> - LLVMVariable(v.toString(), descriptor.fields[i].type, pointer = descriptor.fields[i].pointer) + when (v) { + is LLVMVariable -> LLVMVariable(v.toString(), descriptor.fields[i].type, pointer = descriptor.fields[i].pointer) + else -> v + } }.toList() - return LLVMConstructorCall( - descriptor.type, fun(thisVar): LLVMCall { - val args = ArrayList() - args.add(thisVar) - args.addAll(names) - return LLVMCall(LLVMVoidType(), descriptor.constructorName, args) - }) + val result = codeBuilder.getNewVariable(returnType.type) + codeBuilder.allocVar(result) + result.pointer = true + + val args = ArrayList() + args.add(result) + args.addAll(names) + + codeBuilder.addLLVMCode(LLVMCall( + LLVMVoidType(), + descriptor.constructorName, + args + ).toString()) + + return result } private fun evaluateFunctionCallExpression(expr: KtCallExpression, scopeDepth: Int): LLVMSingleValue? { val function = expr.firstChild.firstChild val descriptor = state.functions[function.text] ?: return null - val names = parseArgList(expr, scopeDepth) + val names = parseArgList(expr, scopeDepth).mapIndexed(fun(i: Int, llvmSingleValue: LLVMSingleValue): LLVMSingleValue { + var result = llvmSingleValue - return LLVMCall(descriptor.returnType, "@${descriptor.name}", descriptor.args?.mapIndexed { - i: Int, variable: LLVMVariable -> - LLVMVariable(names[i].toString(), variable.type, pointer = variable.pointer) - } ?: listOf()) + if (result.pointer && !descriptor.args[i].pointer) { + result = codeBuilder.getNewVariable(descriptor.args[i].type) + codeBuilder.loadVariable(result, llvmSingleValue as LLVMVariable) + } + + return result + }).toList() + + val returnType = descriptor.returnType.type + when (returnType) { + is LLVMVoidType -> { + codeBuilder.addLLVMCode(LLVMCall( + LLVMVoidType(), + "@${descriptor.name}", + names + ).toString()) + } + is LLVMReferenceType -> { + val result = codeBuilder.getNewVariable(returnType) + codeBuilder.allocVar(result) + result.pointer = true + + val args = ArrayList() + args.add(result) + args.addAll(names) + + codeBuilder.addLLVMCode(LLVMCall( + LLVMVoidType(), + "@${descriptor.name}", + args + ).toString()) + + return result + } + else -> { + val result = codeBuilder.getNewVariable(returnType) + codeBuilder.addAssignment(result, LLVMCall( + returnType, + "@${descriptor.name}", + names + )) + + val resultPtr = codeBuilder.getNewVariable(returnType) + codeBuilder.allocVar(resultPtr) + resultPtr.pointer = true + codeBuilder.storeVariable(resultPtr, result) + return resultPtr + } + } + + return null } - private fun parseArgList(expr: KtCallExpression, scopeDepth: Int): List { + private fun parseArgList(expr: KtCallExpression, scopeDepth: Int): ArrayList { val args = expr.getValueArgumentsInParentheses() val result = ArrayList() @@ -247,17 +343,17 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction } private fun executeWhileBlock(condition: KtBinaryExpression, bodyExpression: PsiElement, scopeDepth: Int): LLVMVariable? { - val conditionLable = codeBuilder.getNewLabel(prefix = "while") - val bodyLable = codeBuilder.getNewLabel(prefix = "while") - val exitLable = codeBuilder.getNewLabel(prefix = "while") + val conditionLabel = codeBuilder.getNewLabel(prefix = "while") + val bodyLabel = codeBuilder.getNewLabel(prefix = "while") + val exitLabel = codeBuilder.getNewLabel(prefix = "while") - codeBuilder.addUnconditionJump(conditionLable) - codeBuilder.markWithLabel(conditionLable) + codeBuilder.addUnconditionJump(conditionLabel) + codeBuilder.markWithLabel(conditionLabel) val conditionResult = evaluateBinaryExpression(condition, scopeDepth + 1) - codeBuilder.addCondition(conditionResult, bodyLable, exitLable) - evaluateCodeBlock(bodyExpression, bodyLable, conditionLable, scopeDepth + 1) - codeBuilder.markWithLabel(exitLable) + codeBuilder.addCondition(conditionResult, bodyLabel, exitLabel) + evaluateCodeBlock(bodyExpression, bodyLabel, conditionLabel, scopeDepth + 1) + codeBuilder.markWithLabel(exitLabel) return null } @@ -338,15 +434,8 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction codeBuilder.addConstant(newVar, assignExpression) variableManager.addVariable(identifier.text, newVar, scopeDepth) } - is LLVMConstructorCall -> { - val result = variableManager.receiveVariable(identifier!!.text, assignExpression.type, LLVMLocalScope(), pointer = false) - codeBuilder.allocVar(result) - result.pointer = true - codeBuilder.addLLVMCode(assignExpression.call(result).toString()) - variableManager.addVariable(identifier.text, result, scopeDepth) - } else -> { - codeBuilder.addAssignment(LLVMVariable(identifier!!.text, LLVMIntType(), identifier.text, LLVMLocalScope()), assignExpression) + throw UnsupportedOperationException() } } return null @@ -355,9 +444,21 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction private fun evaluateReturnInstruction(element: LeafPsiElement, scopeDepth: Int): LLVMVariable? { val next = element.getNextSiblingIgnoringWhitespaceAndComments() val retVar = evaluateExpression(next, scopeDepth) as LLVMSingleValue - val retNativeValue = codeBuilder.receiveNativeValue(retVar) - codeBuilder.addReturnOperator(retNativeValue) + when (returnType.type) { + is LLVMReferenceType -> { + val src = codeBuilder.bitcast(retVar as LLVMVariable, LLVMCharType()) + val dst = codeBuilder.bitcast(returnType, LLVMCharType()) + val size = state.classes[(retVar.type as LLVMReferenceType).type]!!.size + codeBuilder.memcpy(dst, src, size) + codeBuilder.addVoidReturn() + } + else -> { + val retNativeValue = codeBuilder.receiveNativeValue(retVar) + codeBuilder.addReturnOperator(retNativeValue) + } + } + return null } } \ No newline at end of file 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 7cf917f6069..3a8daf181ca 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMBuilder.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMBuilder.kt @@ -190,11 +190,10 @@ class LLVMBuilder(val arm: Boolean) { llvmLocalCode.appendln(code) } - fun bitcast(dst: LLVMVariable, llvmType: LLVMType): LLVMVariable { + fun bitcast(src: LLVMVariable, llvmType: LLVMType): LLVMVariable { val empty = getNewVariable(llvmType, true) - val code = "$empty = bitcast ${dst.getType()} $dst to $llvmType*" + val code = "$empty = bitcast ${src.getType()} $src to $llvmType*" llvmLocalCode.appendln(code) - return empty } diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMCall.kt b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMCall.kt index bd3baa5965a..02a435b1290 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMCall.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMCall.kt @@ -2,8 +2,8 @@ package org.kotlinnative.translator.llvm import org.kotlinnative.translator.llvm.types.LLVMType -class LLVMCall(val returnType: LLVMType, val name: String, val arguments: List) : LLVMSingleValue(returnType) { +class LLVMCall(val returnType: LLVMType, val name: String, val arguments: List) : LLVMSingleValue(returnType) { override fun toString(): String = - "call $returnType $name(${arguments.joinToString { "${it.getType()} ${it.label}" }})" + "call $returnType $name(${arguments.joinToString { "${it.getType()} ${it.toString()}" }})" } 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 4a7b201f7a7..d02bf2110a4 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/generators.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/generators.kt @@ -9,7 +9,7 @@ import org.kotlinnative.translator.llvm.types.* fun LLVMFunctionDescriptor(name: String, argTypes: List?, returnType: LLVMType, declare: Boolean = false, arm: Boolean = false) = "${if (declare) "declare" else "define"} $returnType @$name(${ argTypes?.mapIndexed { i: Int, s: LLVMVariable -> - "${s.getType()} %${s.label}" + "${s.getType()} ${if (s.type is LLVMReferenceType && !(s.type as LLVMReferenceType).isReturn) "byval" else ""} %${s.label}" }?.joinToString() }) ${ if (arm) "#0" else ""}" fun LLVMMapStandardType(name: String, type: KotlinType): LLVMVariable = when { @@ -17,5 +17,5 @@ fun LLVMMapStandardType(name: String, type: KotlinType): LLVMVariable = when { type.toString() == "Int" -> LLVMVariable(name, LLVMIntType(), type.toString()) type.toString() == "Double" -> LLVMVariable(name, LLVMDoubleType(), type.toString()) type.isUnit() -> LLVMVariable("", LLVMVoidType()) - else -> LLVMVariable(name, LLVMReferenceType("%$type"), name, pointer = true) + else -> LLVMVariable(name, LLVMReferenceType("$type"), name, pointer = true) } \ No newline at end of file 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 07cc486c633..ffa1014611d 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 @@ -2,12 +2,13 @@ package org.kotlinnative.translator.llvm.types import java.util.* -class LLVMReferenceType(val type: String, val prefix: String = "") : LLVMType() { +class LLVMReferenceType(val type: String, var prefix: String = "", var isReturn: Boolean = false) : LLVMType() { + + override val defaultValue: String = "" - override val defaultValue = throw UnsupportedOperationException() override val align = 4 override val size: Byte = 4 - override fun toString() = "%$prefix.$type" + override fun toString() = "%$prefix${if (prefix.length > 0) "." else ""}$type" private val params = ArrayList()