add simpy variable manager, fix some bugs

This commit is contained in:
Alexey Stepanov
2016-07-11 20:11:20 +03:00
parent 33ff4f720a
commit fbfe5dedda
13 changed files with 132 additions and 42 deletions
@@ -3,7 +3,9 @@ package org.kotlinnative.translator
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtNamedFunction import org.jetbrains.kotlin.psi.KtNamedFunction
import org.kotlinnative.translator.llvm.LLVMBuilder import org.kotlinnative.translator.llvm.LLVMBuilder
import org.kotlinnative.translator.llvm.LLVMVariable
import org.kotlinnative.translator.utils.FunctionDescriptor import org.kotlinnative.translator.utils.FunctionDescriptor
import java.util.*
class FileTranslator(val state: TranslationState, val file: KtFile) { class FileTranslator(val state: TranslationState, val file: KtFile) {
@@ -9,7 +9,8 @@ import org.jetbrains.kotlin.psi.psiUtil.getNextSiblingIgnoringWhitespaceAndComme
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.kotlinnative.translator.llvm.* import org.kotlinnative.translator.llvm.*
import org.kotlinnative.translator.llvm.types.LLVMIntType 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 org.kotlinnative.translator.utils.FunctionArgument
import java.util.* import java.util.*
@@ -17,8 +18,9 @@ import java.util.*
class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction, val codeBuilder: LLVMBuilder) { class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction, val codeBuilder: LLVMBuilder) {
var name = function.fqName.toString() var name = function.fqName.toString()
var returnType: String var returnType: LLVMType
var args: List<FunctionArgument>? var args: List<FunctionArgument>?
val variableManager = state.variableManager
init { init {
val descriptor = state.bindingContext.get(BindingContext.FUNCTION, function) val descriptor = state.bindingContext.get(BindingContext.FUNCTION, function)
@@ -35,9 +37,10 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction
} }
codeBuilder.addStartExpression() codeBuilder.addStartExpression()
generateLoadArguments(function)
expressionWalker(function.bodyExpression) expressionWalker(function.bodyExpression)
if (returnType == "void") { if (returnType is LLVMVoidType) {
codeBuilder.addVoidReturn() codeBuilder.addVoidReturn()
} }
@@ -61,31 +64,47 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction
return external 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) { when (expr) {
is KtBlockExpression -> expressionWalker(expr.firstChild) is KtBlockExpression -> expressionWalker(expr.firstChild, scopeDepth + 1)
is KtProperty -> evaluateLeafPsiElement(expr.firstChild as LeafPsiElement) is KtProperty -> evaluateLeafPsiElement(expr.firstChild as LeafPsiElement, scopeDepth)
is KtCallExpression -> codeBuilder.addLLVMCode(evaluateCallExpression(expr).toString()) is PsiElement -> evaluateExpression(expr.firstChild, scopeDepth + 1)
is PsiElement -> evaluateExpression(expr.firstChild) null -> {
null -> return variableManager.pullUpwardsLevel(scopeDepth)
return
}
else -> UnsupportedOperationException() 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) { return when (expr) {
is KtBinaryExpression -> evaluateBinaryExpression(expr) is KtBinaryExpression -> evaluateBinaryExpression(expr, scopeDepth)
is KtConstantExpression -> evaluateConstantExpression(expr) is KtConstantExpression -> evaluateConstantExpression(expr)
is KtCallExpression -> evaluateCallExpression(expr) is KtCallExpression -> evaluateCallExpression(expr)
is KtReferenceExpression -> evaluateReferenceExpression(expr)
is PsiWhiteSpace -> null is PsiWhiteSpace -> null
is PsiElement -> evaluatePsiElement(expr) is PsiElement -> evaluatePsiElement(expr, scopeDepth)
null -> null null -> null
else -> throw UnsupportedOperationException() else -> throw UnsupportedOperationException()
} }
} }
private fun evaluateReferenceExpression(expr: KtReferenceExpression): LLVMNode? {
val variableName = expr.firstChild.text
return variableManager.getLLVMvalue(variableName)
}
private fun evaluateCallExpression(expr: KtCallExpression): LLVMNode? { private fun evaluateCallExpression(expr: KtCallExpression): LLVMNode? {
val function = expr.firstChild.firstChild val function = expr.firstChild.firstChild
val descriptor = state.functions[function.text] ?: return null val descriptor = state.functions[function.text] ?: return null
@@ -94,7 +113,7 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction
.getNextSiblingIgnoringWhitespaceAndComments() .getNextSiblingIgnoringWhitespaceAndComments()
?.firstChild) ?.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<String> { private fun parseArgList(argumentList: PsiElement?): List<String> {
@@ -112,9 +131,9 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction
return args return args
} }
private fun evaluateBinaryExpression(expr: KtBinaryExpression): LLVMNode { private fun evaluateBinaryExpression(expr: KtBinaryExpression, scopeDepth: Int): LLVMNode {
val left = evaluateExpression(expr.firstChild) as LLVMVariable? ?: throw UnsupportedOperationException("Wrong binary exception") val left = evaluateExpression(expr.firstChild, scopeDepth) as LLVMVariable? ?: throw UnsupportedOperationException("Wrong binary exception")
val right = evaluateExpression(expr.lastChild) as LLVMVariable? ?: throw UnsupportedOperationException("Wrong binary exception") val right = evaluateExpression(expr.lastChild, scopeDepth) as LLVMVariable? ?: throw UnsupportedOperationException("Wrong binary exception")
val operator = expr.operationToken val operator = expr.operationToken
return codeBuilder.addPrimitiveBinaryOperation(operator, left, right) 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()) return LLVMVariable(node.firstChildNode.text, ::LLVMIntType.invoke())
} }
private fun evaluatePsiElement(element: PsiElement): LLVMVariable? { private fun evaluatePsiElement(element: PsiElement, scopeDepth: Int): LLVMVariable? {
return when (element) { return when (element) {
is LeafPsiElement -> evaluateLeafPsiElement(element) is LeafPsiElement -> evaluateLeafPsiElement(element, scopeDepth)
is KtConstantExpression -> evaluateConstantExpression(element) is KtConstantExpression -> evaluateConstantExpression(element)
KtTokens.INTEGER_LITERAL -> null KtTokens.INTEGER_LITERAL -> null
else -> null else -> null
} }
} }
private fun evaluateLeafPsiElement(element: LeafPsiElement): LLVMVariable? { private fun evaluateLeafPsiElement(element: LeafPsiElement, scopeDepth: Int): LLVMVariable? {
return when (element.elementType) { return when (element.elementType) {
KtTokens.RETURN_KEYWORD -> evaluateReturnInstruction(element) KtTokens.RETURN_KEYWORD -> evaluateReturnInstruction(element, scopeDepth)
KtTokens.VAL_KEYWORD -> evaluateValExpression(element) KtTokens.VAL_KEYWORD -> evaluateValExpression(element, scopeDepth)
KtTokens.VAR_KEYWORD -> evaluateValExpression(element) KtTokens.VAR_KEYWORD -> evaluateValExpression(element, scopeDepth)
else -> null else -> null
} }
} }
private fun evaluateValExpression(element: LeafPsiElement): LLVMVariable? { private fun evaluateValExpression(element: LeafPsiElement, scopeDepth: Int): LLVMVariable? {
val identifier = element.getNextSiblingIgnoringWhitespaceAndComments() val identifier = element.getNextSiblingIgnoringWhitespaceAndComments()
val eq = identifier?.getNextSiblingIgnoringWhitespaceAndComments() ?: return null 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) codeBuilder.addAssignment(LLVMVariable("%${identifier!!.text}"), assignExpression)
return null return null
} }
private fun evaluateReturnInstruction(element: LeafPsiElement): LLVMVariable? { private fun evaluateReturnInstruction(element: LeafPsiElement, scopeDepth: Int): LLVMVariable? {
var next = element.getNextSiblingIgnoringWhitespaceAndComments() var next = element.getNextSiblingIgnoringWhitespaceAndComments()
val retVar = evaluateExpression(next) as LLVMVariable val retVar = evaluateExpression(next, scopeDepth) as LLVMVariable
codeBuilder.addReturnOperator(retVar) codeBuilder.addReturnOperator(retVar)
return null return null
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM
import org.jetbrains.kotlin.utils.PathUtil import org.jetbrains.kotlin.utils.PathUtil
import org.kotlinnative.translator.exceptions.TranslationException import org.kotlinnative.translator.exceptions.TranslationException
import org.kotlinnative.translator.llvm.LLVMVariable
import org.kotlinnative.translator.utils.FunctionDescriptor import org.kotlinnative.translator.utils.FunctionDescriptor
import java.util.* import java.util.*
@@ -27,6 +28,7 @@ class TranslationState(sources: List<String>, disposer: Disposable) {
val environment: KotlinCoreEnvironment val environment: KotlinCoreEnvironment
val bindingContext: BindingContext val bindingContext: BindingContext
var functions = HashMap<String, FunctionDescriptor>() var functions = HashMap<String, FunctionDescriptor>()
val variableManager = VariableManager()
init { init {
val configuration = CompilerConfiguration() val configuration = CompilerConfiguration()
@@ -0,0 +1,25 @@
package org.kotlinnative.translator
import org.kotlinnative.translator.llvm.LLVMVariable
import java.util.*
class VariableManager {
private var fileVariableCollectionTree = HashMap<String, Stack<Pair<LLVMVariable, Int>>>()
private var globalVariableCollection = HashMap<String, LLVMVariable>()
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<Pair<LLVMVariable, Int>>());
stack.push(Pair(variable, level));
fileVariableCollectionTree.put(name, stack)
}
}
@@ -32,7 +32,7 @@ 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)
else -> throw UnsupportedOperationException("Unkbown binary operator") else -> throw UnsupportedOperationException("Unknown binary operator")
} }
addAssignment(newVar, llvmExpression) addAssignment(newVar, llvmExpression)
@@ -60,6 +60,11 @@ class LLVMBuilder {
llvmCode.appendln("ret void") 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 { override fun toString(): String {
return llvmCode.toString() return llvmCode.toString()
} }
@@ -1,6 +1,8 @@
package org.kotlinnative.translator.llvm package org.kotlinnative.translator.llvm
class LLVMCall(val returnType: String, val name: String, val arguments: List<LLVMVariable>) : LLVMNode() { import org.kotlinnative.translator.llvm.types.LLVMType
class LLVMCall(val returnType: LLVMType, val name: String, val arguments: List<LLVMVariable>) : LLVMNode() {
override fun toString(): String { override fun toString(): String {
return "call $returnType $name(${arguments.joinToString { "${it.type} ${it.label}" }})" return "call $returnType $name(${arguments.joinToString { "${it.type} ${it.label}" }})"
@@ -1,15 +1,18 @@
package org.kotlinnative.translator.llvm package org.kotlinnative.translator.llvm
import org.kotlinnative.translator.llvm.types.*
import org.kotlinnative.translator.utils.FunctionArgument import org.kotlinnative.translator.utils.FunctionArgument
fun LLVMFunctionDescriptor(name: String, argTypes: List<FunctionArgument>?, 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<FunctionArgument>?, 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) { fun LLVMMapStandardType(type: String): LLVMType = when (type) {
"Int" -> "i32" "Int" -> LLVMIntType()
"Unit" -> "void" "Double" -> LLVMDoubleType()
else -> "%$type*" "Unit" -> LLVMVoidType()
else -> LLVMReferenceType("%$type*")
} }
@@ -18,8 +18,7 @@ class LLVMDoubleType() : LLVMType() {
override fun operatorPlus(result: LLVMVariable, firstOp: LLVMVariable, secondOp: LLVMVariable): LLVMExpression = override fun operatorPlus(result: LLVMVariable, firstOp: LLVMVariable, secondOp: LLVMVariable): LLVMExpression =
LLVMExpression(LLVMDoubleType(), "fadd double $firstOp, $secondOp") LLVMExpression(LLVMDoubleType(), "fadd double $firstOp, $secondOp")
override fun toString(): String { override fun toString() = "double"
return "double"
}
override fun getAlign() = 8
} }
@@ -20,4 +20,5 @@ class LLVMIntType() : LLVMType() {
override fun toString() = "i32" override fun toString() = "i32"
override fun getAlign() = 4
} }
@@ -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
}
@@ -10,6 +10,8 @@ abstract class LLVMType() {
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()
abstract fun getAlign(): Int
} }
fun parseLLVMType(type: String): LLVMType = when (type) { fun parseLLVMType(type: String): LLVMType = when (type) {
@@ -2,6 +2,7 @@ package org.kotlinnative.translator.llvm.types
class LLVMVoidType() : LLVMType() { class LLVMVoidType() : LLVMType() {
override fun getAlign(): Int = 0
override fun toString(): String = "void" override fun toString(): String = "void"
} }
@@ -1,5 +1,7 @@
package org.kotlinnative.translator.utils 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<String>) data class FunctionArgument(val type: LLVMType, val name: String)
data class FunctionDescriptor(val returnType: LLVMType, val argTypes: List<LLVMType>)