diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/FileTranslator.kt b/translator/src/main/kotlin/org/kotlinnative/translator/FileTranslator.kt index ea4288641ba..f7e77676d8a 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/FileTranslator.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/FileTranslator.kt @@ -3,7 +3,9 @@ package org.kotlinnative.translator import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtNamedFunction import org.kotlinnative.translator.llvm.LLVMBuilder +import org.kotlinnative.translator.llvm.LLVMVariable import org.kotlinnative.translator.utils.FunctionDescriptor +import java.util.* class FileTranslator(val state: TranslationState, val file: KtFile) { diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt index f95bf58fbfe..ab1985e495a 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt @@ -9,7 +9,8 @@ import org.jetbrains.kotlin.psi.psiUtil.getNextSiblingIgnoringWhitespaceAndComme import org.jetbrains.kotlin.resolve.BindingContext import org.kotlinnative.translator.llvm.* import org.kotlinnative.translator.llvm.types.LLVMIntType -import org.kotlinnative.translator.llvm.types.parseLLVMType +import org.kotlinnative.translator.llvm.types.LLVMType +import org.kotlinnative.translator.llvm.types.LLVMVoidType import org.kotlinnative.translator.utils.FunctionArgument import java.util.* @@ -17,8 +18,9 @@ import java.util.* class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction, val codeBuilder: LLVMBuilder) { var name = function.fqName.toString() - var returnType: String + var returnType: LLVMType var args: List? + val variableManager = state.variableManager init { val descriptor = state.bindingContext.get(BindingContext.FUNCTION, function) @@ -35,9 +37,10 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction } codeBuilder.addStartExpression() + generateLoadArguments(function) expressionWalker(function.bodyExpression) - if (returnType == "void") { + if (returnType is LLVMVoidType) { codeBuilder.addVoidReturn() } @@ -61,31 +64,47 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction return external } - private fun expressionWalker(expr: PsiElement?) { + private fun generateLoadArguments(function: KtNamedFunction) { + args?.forEach { + val loadVariable = LLVMVariable("%${it.name}", it.type) + codeBuilder.loadVariable(loadVariable) + variableManager.addVariable(it.name, loadVariable, 2) + } + } + + private fun expressionWalker(expr: PsiElement?, scopeDepth: Int = 0) { when (expr) { - is KtBlockExpression -> expressionWalker(expr.firstChild) - is KtProperty -> evaluateLeafPsiElement(expr.firstChild as LeafPsiElement) - is KtCallExpression -> codeBuilder.addLLVMCode(evaluateCallExpression(expr).toString()) - is PsiElement -> evaluateExpression(expr.firstChild) - null -> return + is KtBlockExpression -> expressionWalker(expr.firstChild, scopeDepth + 1) + is KtProperty -> evaluateLeafPsiElement(expr.firstChild as LeafPsiElement, scopeDepth) + is PsiElement -> evaluateExpression(expr.firstChild, scopeDepth + 1) + null -> { + variableManager.pullUpwardsLevel(scopeDepth) + return + } else -> UnsupportedOperationException() } - expressionWalker(expr.getNextSiblingIgnoringWhitespaceAndComments()) + expressionWalker(expr.getNextSiblingIgnoringWhitespaceAndComments(), scopeDepth) } - private fun evaluateExpression(expr: PsiElement?): LLVMNode? { + private fun evaluateExpression(expr: PsiElement?, scopeDepth: Int): LLVMNode? { return when (expr) { - is KtBinaryExpression -> evaluateBinaryExpression(expr) + is KtBinaryExpression -> evaluateBinaryExpression(expr, scopeDepth) is KtConstantExpression -> evaluateConstantExpression(expr) is KtCallExpression -> evaluateCallExpression(expr) + is KtReferenceExpression -> evaluateReferenceExpression(expr) is PsiWhiteSpace -> null - is PsiElement -> evaluatePsiElement(expr) + is PsiElement -> evaluatePsiElement(expr, scopeDepth) null -> null else -> throw UnsupportedOperationException() } } + private fun evaluateReferenceExpression(expr: KtReferenceExpression): LLVMNode? { + val variableName = expr.firstChild.text + return variableManager.getLLVMvalue(variableName) + } + private fun evaluateCallExpression(expr: KtCallExpression): LLVMNode? { val function = expr.firstChild.firstChild val descriptor = state.functions[function.text] ?: return null @@ -94,7 +113,7 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction .getNextSiblingIgnoringWhitespaceAndComments() ?.firstChild) - return LLVMCall(descriptor.returnType, "@${function.text}", descriptor.argTypes.mapIndexed { i: Int, type: String -> LLVMVariable(names[i], parseLLVMType(type)) }) + return LLVMCall(descriptor.returnType, "@${function.text}", descriptor.argTypes.mapIndexed { i: Int, type: LLVMType -> LLVMVariable(names[i], type) }) } private fun parseArgList(argumentList: PsiElement?): List { @@ -112,9 +131,9 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction return args } - private fun evaluateBinaryExpression(expr: KtBinaryExpression): LLVMNode { - val left = evaluateExpression(expr.firstChild) as LLVMVariable? ?: throw UnsupportedOperationException("Wrong binary exception") - val right = evaluateExpression(expr.lastChild) as LLVMVariable? ?: throw UnsupportedOperationException("Wrong binary exception") + private fun evaluateBinaryExpression(expr: KtBinaryExpression, scopeDepth: Int): LLVMNode { + val left = evaluateExpression(expr.firstChild, scopeDepth) as LLVMVariable? ?: throw UnsupportedOperationException("Wrong binary exception") + val right = evaluateExpression(expr.lastChild, scopeDepth) as LLVMVariable? ?: throw UnsupportedOperationException("Wrong binary exception") val operator = expr.operationToken return codeBuilder.addPrimitiveBinaryOperation(operator, left, right) @@ -125,36 +144,39 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction return LLVMVariable(node.firstChildNode.text, ::LLVMIntType.invoke()) } - private fun evaluatePsiElement(element: PsiElement): LLVMVariable? { + private fun evaluatePsiElement(element: PsiElement, scopeDepth: Int): LLVMVariable? { return when (element) { - is LeafPsiElement -> evaluateLeafPsiElement(element) + is LeafPsiElement -> evaluateLeafPsiElement(element, scopeDepth) is KtConstantExpression -> evaluateConstantExpression(element) KtTokens.INTEGER_LITERAL -> null else -> null } } - private fun evaluateLeafPsiElement(element: LeafPsiElement): LLVMVariable? { + private fun evaluateLeafPsiElement(element: LeafPsiElement, scopeDepth: Int): LLVMVariable? { return when (element.elementType) { - KtTokens.RETURN_KEYWORD -> evaluateReturnInstruction(element) - KtTokens.VAL_KEYWORD -> evaluateValExpression(element) - KtTokens.VAR_KEYWORD -> evaluateValExpression(element) + KtTokens.RETURN_KEYWORD -> evaluateReturnInstruction(element, scopeDepth) + KtTokens.VAL_KEYWORD -> evaluateValExpression(element, scopeDepth) + KtTokens.VAR_KEYWORD -> evaluateValExpression(element, scopeDepth) else -> null } } - private fun evaluateValExpression(element: LeafPsiElement): LLVMVariable? { + private fun evaluateValExpression(element: LeafPsiElement, scopeDepth: Int): LLVMVariable? { val identifier = element.getNextSiblingIgnoringWhitespaceAndComments() val eq = identifier?.getNextSiblingIgnoringWhitespaceAndComments() ?: return null - val assignExpression = evaluateExpression(eq.getNextSiblingIgnoringWhitespaceAndComments()) ?: return null + val assignExpression = evaluateExpression(eq.getNextSiblingIgnoringWhitespaceAndComments(), scopeDepth) ?: return null + when (assignExpression) { + is LLVMVariable -> variableManager.addVariable(identifier!!.text, assignExpression, scopeDepth); + } codeBuilder.addAssignment(LLVMVariable("%${identifier!!.text}"), assignExpression) return null } - private fun evaluateReturnInstruction(element: LeafPsiElement): LLVMVariable? { + private fun evaluateReturnInstruction(element: LeafPsiElement, scopeDepth: Int): LLVMVariable? { var next = element.getNextSiblingIgnoringWhitespaceAndComments() - val retVar = evaluateExpression(next) as LLVMVariable + val retVar = evaluateExpression(next, scopeDepth) as LLVMVariable codeBuilder.addReturnOperator(retVar) return null diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/TranslationState.kt b/translator/src/main/kotlin/org/kotlinnative/translator/TranslationState.kt index 3ce29666312..ac4819ef97c 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/TranslationState.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/TranslationState.kt @@ -18,6 +18,7 @@ import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM import org.jetbrains.kotlin.utils.PathUtil import org.kotlinnative.translator.exceptions.TranslationException +import org.kotlinnative.translator.llvm.LLVMVariable import org.kotlinnative.translator.utils.FunctionDescriptor import java.util.* @@ -27,6 +28,7 @@ class TranslationState(sources: List, disposer: Disposable) { val environment: KotlinCoreEnvironment val bindingContext: BindingContext var functions = HashMap() + val variableManager = VariableManager() init { val configuration = CompilerConfiguration() diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/VariableManager.kt b/translator/src/main/kotlin/org/kotlinnative/translator/VariableManager.kt new file mode 100644 index 00000000000..868f536dba8 --- /dev/null +++ b/translator/src/main/kotlin/org/kotlinnative/translator/VariableManager.kt @@ -0,0 +1,25 @@ +package org.kotlinnative.translator + +import org.kotlinnative.translator.llvm.LLVMVariable +import java.util.* + +class VariableManager { + + private var fileVariableCollectionTree = HashMap>>() + private var globalVariableCollection = HashMap() + + fun getLLVMvalue(variableName: String): LLVMVariable? { + return fileVariableCollectionTree.get(variableName)?.peek()?.first ?: globalVariableCollection.get(variableName) + } + + fun pullUpwardsLevel(level: Int) { + fileVariableCollectionTree.forEach { s, stack -> if (!stack.empty() && stack.peek().second >= level) stack.pop() else Unit } + } + + fun addVariable(name: String, variable: LLVMVariable, level: Int){ + val stack = fileVariableCollectionTree.getOrDefault(String, Stack>()); + stack.push(Pair(variable, level)); + fileVariableCollectionTree.put(name, stack) + } + +} \ 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 f0e1ec063fc..42792ac6d9f 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMBuilder.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMBuilder.kt @@ -32,7 +32,7 @@ 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) - else -> throw UnsupportedOperationException("Unkbown binary operator") + else -> throw UnsupportedOperationException("Unknown binary operator") } addAssignment(newVar, llvmExpression) @@ -60,6 +60,11 @@ class LLVMBuilder { llvmCode.appendln("ret void") } + fun loadVariable(llvmVariable: LLVMVariable) { + llvmCode.appendln("$llvmVariable.addr = alloca ${llvmVariable.type}, align ${llvmVariable.type?.getAlign()}") + llvmCode.appendln("store ${llvmVariable.type} $llvmVariable, ${llvmVariable.type}* ${llvmVariable.type}.addr, align ${llvmVariable.type?.getAlign()}") + } + override fun toString(): String { return llvmCode.toString() } 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 80e1f598378..53822c85ec2 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMCall.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMCall.kt @@ -1,6 +1,8 @@ package org.kotlinnative.translator.llvm -class LLVMCall(val returnType: String, val name: String, val arguments: List) : LLVMNode() { +import org.kotlinnative.translator.llvm.types.LLVMType + +class LLVMCall(val returnType: LLVMType, val name: String, val arguments: List) : LLVMNode() { override fun toString(): String { return "call $returnType $name(${arguments.joinToString { "${it.type} ${it.label}" }})" 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 a73c923115e..04e21709d3e 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/generators.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/generators.kt @@ -1,15 +1,18 @@ package org.kotlinnative.translator.llvm +import org.kotlinnative.translator.llvm.types.* import org.kotlinnative.translator.utils.FunctionArgument -fun LLVMFunctionDescriptor(name: String, argTypes: List?, returnType: String, declare: Boolean = false) = - "${ if (declare) "declare" else "define"} $returnType @$name(${ - argTypes?.mapIndexed { i: Int, s: FunctionArgument -> "${s.type} %tmp.${s.name}" - }?.joinToString() ?: "" })" +fun LLVMFunctionDescriptor(name: String, argTypes: List?, returnType: LLVMType, declare: Boolean = false) = + "${if (declare) "declare" else "define"} $returnType @$name(${ + argTypes?.mapIndexed { i: Int, s: FunctionArgument -> + "${s.type} %tmp.${s.name}" + }?.joinToString() ?: ""})" -fun LLVMMapStandardType(type: String) = when(type) { - "Int" -> "i32" - "Unit" -> "void" - else -> "%$type*" +fun LLVMMapStandardType(type: String): LLVMType = when (type) { + "Int" -> LLVMIntType() + "Double" -> LLVMDoubleType() + "Unit" -> LLVMVoidType() + else -> LLVMReferenceType("%$type*") } \ No newline at end of file diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMDoubleType.kt b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMDoubleType.kt index 460d86215cd..5df7b170031 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMDoubleType.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMDoubleType.kt @@ -18,8 +18,7 @@ class LLVMDoubleType() : LLVMType() { override fun operatorPlus(result: LLVMVariable, firstOp: LLVMVariable, secondOp: LLVMVariable): LLVMExpression = LLVMExpression(LLVMDoubleType(), "fadd double $firstOp, $secondOp") - override fun toString(): String { - return "double" - } + override fun toString() = "double" + override fun getAlign() = 8 } \ No newline at end of file diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMIntType.kt b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMIntType.kt index 1f9e1e88ecb..b4fc963f892 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMIntType.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMIntType.kt @@ -20,4 +20,5 @@ class LLVMIntType() : LLVMType() { override fun toString() = "i32" + override fun getAlign() = 4 } \ 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 new file mode 100644 index 00000000000..c80146dce64 --- /dev/null +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMReferenceType.kt @@ -0,0 +1,24 @@ +package org.kotlinnative.translator.llvm.types + +import org.kotlinnative.translator.llvm.LLVMExpression +import org.kotlinnative.translator.llvm.LLVMVariable + +class LLVMReferenceType(val type: String) : LLVMType() { + override fun operatorTimes(result: LLVMVariable, firstOp: LLVMVariable, secondOp: LLVMVariable): LLVMExpression { + throw UnsupportedOperationException("not implemented") + } + + override fun operatorMinus(result: LLVMVariable, firstOp: LLVMVariable, secondOp: LLVMVariable): LLVMExpression { + throw UnsupportedOperationException("not implemented") + } + + override fun getAlign(): Int { + throw UnsupportedOperationException("not implemented") + } + + override fun operatorPlus(result: LLVMVariable, firstOp: LLVMVariable, secondOp: LLVMVariable): LLVMExpression { + throw UnsupportedOperationException("not implemented") + } + override fun toString() = type + +} \ No newline at end of file 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 4dac8131376..a778afa6039 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 @@ -10,6 +10,8 @@ abstract class LLVMType() { 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() + + abstract fun getAlign(): Int } fun parseLLVMType(type: String): LLVMType = when (type) { 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 d633fe75c2d..5544f2636bf 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 @@ -2,6 +2,7 @@ package org.kotlinnative.translator.llvm.types class LLVMVoidType() : LLVMType() { + override fun getAlign(): Int = 0 override fun toString(): String = "void" } diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/utils/types.kt b/translator/src/main/kotlin/org/kotlinnative/translator/utils/types.kt index 0183303e8df..3be04314af9 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/utils/types.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/utils/types.kt @@ -1,5 +1,7 @@ package org.kotlinnative.translator.utils -data class FunctionArgument(val type: String, val name: String) +import org.kotlinnative.translator.llvm.types.LLVMType -data class FunctionDescriptor(val returnType: String, val argTypes: List) +data class FunctionArgument(val type: LLVMType, val name: String) + +data class FunctionDescriptor(val returnType: LLVMType, val argTypes: List)