translator: add resolving variable, LLVMConstant and LLVMSingleValue

This commit is contained in:
Alexey Stepanov
2016-07-12 18:32:12 +03:00
parent 6972a4d658
commit 9e2b593a57
8 changed files with 100 additions and 57 deletions
@@ -133,7 +133,8 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction
?.firstChild) ?.firstChild)
return LLVMCall(descriptor.returnType, "@${function.text}", descriptor.args?.mapIndexed { return LLVMCall(descriptor.returnType, "@${function.text}", descriptor.args?.mapIndexed {
i: Int, variable: LLVMVariable -> LLVMVariable(names[i], variable.type) i: Int, variable: LLVMVariable ->
LLVMVariable(names[i], variable.type)
} ?: listOf()) } ?: listOf())
} }
@@ -153,19 +154,19 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction
} }
private fun evaluateBinaryExpression(expr: KtBinaryExpression, scopeDepth: Int): LLVMNode { private fun evaluateBinaryExpression(expr: KtBinaryExpression, scopeDepth: Int): LLVMNode {
val left = evaluateExpression(expr.firstChild, scopeDepth) as LLVMVariable? ?: throw UnsupportedOperationException("Wrong binary exception") val left = evaluateExpression(expr.firstChild, scopeDepth) as LLVMSingleValue? ?: throw UnsupportedOperationException("Wrong binary exception")
val right = evaluateExpression(expr.lastChild, scopeDepth) as LLVMVariable? ?: throw UnsupportedOperationException("Wrong binary exception") val right = evaluateExpression(expr.lastChild, scopeDepth) as LLVMSingleValue? ?: throw UnsupportedOperationException("Wrong binary exception")
val operator = expr.operationToken val operator = expr.operationToken
val newVar = codeBuilder.getNewVariable(LLVMIntType())
return codeBuilder.addPrimitiveBinaryOperation(operator, left, right) return codeBuilder.addPrimitiveBinaryOperation(operator, newVar, left, right)
} }
private fun evaluateConstantExpression(expr: KtConstantExpression): LLVMVariable { private fun evaluateConstantExpression(expr: KtConstantExpression): LLVMConstant {
val node = expr.node val node = expr.node
return codeBuilder.addConstant(LLVMVariable(node.firstChildNode.text, LLVMIntType(), pointer = false)) return LLVMConstant(node.firstChildNode.text, LLVMIntType(), pointer = false)
} }
private fun evaluatePsiElement(element: PsiElement, scopeDepth: Int): LLVMVariable? { private fun evaluatePsiElement(element: PsiElement, scopeDepth: Int): LLVMSingleValue? {
return when (element) { return when (element) {
is LeafPsiElement -> evaluateLeafPsiElement(element, scopeDepth) is LeafPsiElement -> evaluateLeafPsiElement(element, scopeDepth)
is KtConstantExpression -> evaluateConstantExpression(element) is KtConstantExpression -> evaluateConstantExpression(element)
@@ -194,16 +195,22 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction
assignExpression.kotlinName = identifier!!.text assignExpression.kotlinName = identifier!!.text
assignExpression.pointer = false assignExpression.pointer = false
variableManager.addVariable(identifier.text, assignExpression, scopeDepth) variableManager.addVariable(identifier.text, assignExpression, scopeDepth)
return null }
is LLVMConstant -> {
val newVar = LLVMVariable("%${identifier!!.text}.addr", type = LLVMIntType(), kotlinName = identifier.text, pointer = true)
codeBuilder.addConstant(newVar, assignExpression)
variableManager.addVariable(identifier.text, newVar, scopeDepth)
}
else -> {
codeBuilder.addAssignment(LLVMVariable("%${identifier!!.text}", null, identifier.text), assignExpression)
} }
} }
codeBuilder.addAssignment(LLVMVariable("%${identifier!!.text}", null, identifier.text), assignExpression)
return null return null
} }
private fun evaluateReturnInstruction(element: LeafPsiElement, scopeDepth: Int): LLVMVariable? { private fun evaluateReturnInstruction(element: LeafPsiElement, scopeDepth: Int): LLVMVariable? {
val next = element.getNextSiblingIgnoringWhitespaceAndComments() val next = element.getNextSiblingIgnoringWhitespaceAndComments()
val retVar = evaluateExpression(next, scopeDepth) as LLVMVariable val retVar = evaluateExpression(next, scopeDepth) as LLVMSingleValue
codeBuilder.addReturnOperator(retVar) codeBuilder.addReturnOperator(retVar)
return null return null
@@ -2,16 +2,15 @@ package org.kotlinnative.translator.llvm
import com.intellij.psi.tree.IElementType import com.intellij.psi.tree.IElementType
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.kotlinnative.translator.llvm.types.LLVMIntType
import org.kotlinnative.translator.llvm.types.LLVMType import org.kotlinnative.translator.llvm.types.LLVMType
class LLVMBuilder { class LLVMBuilder {
private var llvmCode: StringBuilder = StringBuilder() private var llvmCode: StringBuilder = StringBuilder()
private var variableCount = 0 private var variableCount = 0
fun getNewVariable(type: LLVMType?, pointer: Boolean = false): LLVMVariable { fun getNewVariable(type: LLVMType?, pointer: Boolean = false, kotlinName: String? = null): LLVMVariable {
variableCount++ variableCount++
return LLVMVariable("%var$variableCount", type, "", pointer) return LLVMVariable("%var$variableCount", type, kotlinName = kotlinName, pointer = pointer)
} }
fun addLLVMCode(code: String) { fun addLLVMCode(code: String) {
@@ -26,18 +25,29 @@ class LLVMBuilder {
llvmCode.appendln("}") llvmCode.appendln("}")
} }
fun addPrimitiveBinaryOperation(operation: IElementType, firstOp: LLVMVariable, secondOp: LLVMVariable): LLVMVariable { fun receiveNativeValue(firstOp: LLVMSingleValue) = when (firstOp) {
val newVar = getNewVariable(LLVMIntType()) is LLVMConstant -> firstOp
is LLVMVariable -> when (firstOp.pointer) {
false -> firstOp
else -> loadAndGetVariable(firstOp)
}
else -> throw UnsupportedOperationException()
}
fun addPrimitiveBinaryOperation(operation: IElementType, resultOp: LLVMVariable, firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMVariable {
val firstNativeOp = receiveNativeValue(firstOp)
val secondNativeOp = receiveNativeValue(secondOp)
val llvmExpression = when (operation) { val llvmExpression = when (operation) {
KtTokens.PLUS -> firstOp.type!!.operatorPlus(newVar, firstOp, secondOp) KtTokens.PLUS -> firstOp.type!!.operatorPlus(resultOp, firstNativeOp, secondNativeOp)
KtTokens.MINUS -> firstOp.type!!.operatorMinus(newVar, firstOp, secondOp) KtTokens.MINUS -> firstOp.type!!.operatorMinus(resultOp, firstNativeOp, secondNativeOp)
KtTokens.MUL -> firstOp.type!!.operatorTimes(newVar, firstOp, secondOp) KtTokens.MUL -> firstOp.type!!.operatorTimes(resultOp, firstNativeOp, secondNativeOp)
KtTokens.EQ -> return resultOp
else -> throw UnsupportedOperationException("Unknown binary operator") else -> throw UnsupportedOperationException("Unknown binary operator")
} }
addAssignment(newVar, llvmExpression) addAssignment(resultOp, llvmExpression)
return newVar return resultOp
} }
fun clean() { fun clean() {
@@ -48,7 +58,7 @@ class LLVMBuilder {
llvmCode.appendln("$llvmVariable = $rhs") llvmCode.appendln("$llvmVariable = $rhs")
} }
fun addReturnOperator(llvmVariable: LLVMVariable) { fun addReturnOperator(llvmVariable: LLVMSingleValue) {
llvmCode.appendln("ret ${llvmVariable.type} $llvmVariable") llvmCode.appendln("ret ${llvmVariable.type} $llvmVariable")
} }
@@ -56,6 +66,16 @@ class LLVMBuilder {
llvmCode.appendln("ret void") llvmCode.appendln("ret void")
} }
fun loadClassField(target: LLVMVariable, source: LLVMVariable, offset: Int) {
val code = "$target = getelementptr inbounds ${source.type}, ${source.type}* $source, i32 0, i32 $offset"
llvmCode.appendln(code)
}
fun storeVariable(target: LLVMVariable, source: LLVMVariable) {
val code = "store ${source.type} $source, ${target.getType()} $target, align ${source.type?.align!!}"
llvmCode.appendln(code)
}
fun loadArgument(llvmVariable: LLVMVariable, store: Boolean = true) { fun loadArgument(llvmVariable: LLVMVariable, store: Boolean = true) {
addVariableByRef(LLVMVariable("${llvmVariable.label}.addr", llvmVariable.type, llvmVariable.kotlinName, true), llvmVariable, store) addVariableByRef(LLVMVariable("${llvmVariable.label}.addr", llvmVariable.type, llvmVariable.kotlinName, true), llvmVariable, store)
} }
@@ -65,16 +85,6 @@ class LLVMBuilder {
llvmCode.appendln(code) 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) { fun addVariableByRef(targetVariable: LLVMVariable, sourceVariable: LLVMVariable, store: Boolean) {
llvmCode.appendln("$targetVariable = alloca ${sourceVariable.type}, align ${sourceVariable.type?.align}") llvmCode.appendln("$targetVariable = alloca ${sourceVariable.type}, align ${sourceVariable.type?.align}")
@@ -83,18 +93,22 @@ class LLVMBuilder {
} }
} }
fun addVariableByValue(targetVariable: LLVMVariable, sourceVariable: LLVMVariable) { fun addVariableByValue(targetVariable: LLVMVariable, sourceVariable: LLVMVariable, allocVariable: LLVMVariable) {
val tmp = getNewVariable(targetVariable.type, true) llvmCode.appendln("$allocVariable = alloca ${allocVariable.type}, align ${allocVariable.type?.align}")
llvmCode.appendln("store ${allocVariable.type} $sourceVariable, ${allocVariable.getType()} $allocVariable, align ${allocVariable.type?.align}")
llvmCode.appendln("$tmp = alloca ${tmp.type}, align ${tmp.type?.align}") llvmCode.appendln("$targetVariable = load ${targetVariable.type}, ${allocVariable.getType()} $allocVariable, align ${targetVariable.type?.align}")
llvmCode.appendln("store ${tmp.type} $sourceVariable, ${tmp.getType()} $tmp, align ${tmp.type?.align}")
llvmCode.appendln("$targetVariable = load ${targetVariable.type}, ${tmp.getType()} $tmp, align ${targetVariable.type?.align}")
} }
fun addConstant(sourceVariable: LLVMVariable): LLVMVariable { fun addConstant(allocVariable: LLVMVariable, constantValue: LLVMConstant) {
val target = getNewVariable(sourceVariable.type, sourceVariable.pointer) llvmCode.appendln("$allocVariable = alloca ${allocVariable.type}, align ${allocVariable.type?.align}")
addVariableByValue(target, sourceVariable) llvmCode.appendln("store ${allocVariable.type} $constantValue, ${allocVariable.getType()} $allocVariable, align ${allocVariable.type?.align}")
}
fun loadAndGetVariable(source: LLVMVariable): LLVMVariable {
assert(!source.pointer)
val target = getNewVariable(type = source.type, pointer = source.pointer, kotlinName = source.kotlinName)
val code = "$target = load ${target.type}, ${source.getType()} $source, align ${target.type?.align!!}"
llvmCode.appendln(code)
return target return target
} }
@@ -104,15 +118,15 @@ class LLVMBuilder {
} }
fun bitcast(dst: LLVMVariable, llvmType: LLVMType): LLVMVariable { fun bitcast(dst: LLVMVariable, llvmType: LLVMType): LLVMVariable {
var empty = getNewVariable(llvmType, true) val empty = getNewVariable(llvmType, true)
var code = "$empty = bitcast ${dst.getType()} $dst to $llvmType*" val code = "$empty = bitcast ${dst.getType()} $dst to $llvmType*"
llvmCode.appendln(code) llvmCode.appendln(code)
return empty return empty
} }
fun memcpy(castedDst: LLVMVariable, castedSrc: LLVMVariable, size: Int, align: Int = 4, volatile: Boolean = false) { 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)" val code = "call void @llvm.memcpy.p0i8.p0i8.i64(i8* $castedDst, i8* $castedSrc, i64 $size, i32 $align, i1 $volatile)"
llvmCode.appendln(code) llvmCode.appendln(code)
} }
@@ -0,0 +1,10 @@
package org.kotlinnative.translator.llvm
import org.kotlinnative.translator.llvm.types.LLVMType
open class LLVMConstant(val value: String, override val type: LLVMType? = null, override var pointer: Boolean = false) : LLVMSingleValue(type, pointer) {
override fun getType(): String = type.toString() + if (pointer) "*" else " "
override fun toString(): String = value
}
@@ -0,0 +1,9 @@
package org.kotlinnative.translator.llvm
import org.kotlinnative.translator.exceptions.UnimplementedException
import org.kotlinnative.translator.llvm.types.LLVMType
open class LLVMSingleValue(open val type: LLVMType? = null, open var pointer: Boolean = false) : LLVMNode() {
open fun getType(): String = throw UnimplementedException()
}
@@ -2,9 +2,9 @@ package org.kotlinnative.translator.llvm
import org.kotlinnative.translator.llvm.types.LLVMType import org.kotlinnative.translator.llvm.types.LLVMType
open class LLVMVariable(val label: String, val type: LLVMType? = null, var kotlinName: String? = null, var pointer: Boolean = false) : LLVMNode() { open class LLVMVariable(val label: String, override val type: LLVMType? = null, var kotlinName: String? = null, override var pointer: Boolean = false) : LLVMSingleValue() {
fun getType(): String = type.toString() + if (pointer) "*" else "" override fun getType(): String = type.toString() + if (pointer) "*" else ""
override fun toString(): String = label override fun toString(): String = label
} }
@@ -1,21 +1,22 @@
package org.kotlinnative.translator.llvm.types package org.kotlinnative.translator.llvm.types
import org.kotlinnative.translator.llvm.LLVMExpression import org.kotlinnative.translator.llvm.LLVMExpression
import org.kotlinnative.translator.llvm.LLVMSingleValue
import org.kotlinnative.translator.llvm.LLVMVariable import org.kotlinnative.translator.llvm.LLVMVariable
class LLVMDoubleType() : LLVMType() { class LLVMDoubleType() : LLVMType() {
//TODO switch by types: int + double = int //TODO switch by types: int + double = int
override fun operatorMinus(result: LLVMVariable, firstOp: LLVMVariable, secondOp: LLVMVariable): LLVMExpression = override fun operatorMinus(result: LLVMVariable, firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression =
LLVMExpression(LLVMDoubleType(), "fsub double i32 $firstOp, $secondOp") LLVMExpression(LLVMDoubleType(), "fsub double i32 $firstOp, $secondOp")
//TODO switch by types: int + double = int //TODO switch by types: int + double = int
override fun operatorTimes(result: LLVMVariable, firstOp: LLVMVariable, secondOp: LLVMVariable): LLVMExpression = override fun operatorTimes(result: LLVMVariable, firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression =
LLVMExpression(LLVMDoubleType(), "fmul double i32 $firstOp, $secondOp") LLVMExpression(LLVMDoubleType(), "fmul double i32 $firstOp, $secondOp")
//TODO switch by types: int + double = int //TODO switch by types: int + double = int
override fun operatorPlus(result: LLVMVariable, firstOp: LLVMVariable, secondOp: LLVMVariable): LLVMExpression = override fun operatorPlus(result: LLVMVariable, firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression =
LLVMExpression(LLVMDoubleType(), "fadd double $firstOp, $secondOp") LLVMExpression(LLVMDoubleType(), "fadd double $firstOp, $secondOp")
override val align = 8 override val align = 8
@@ -1,21 +1,22 @@
package org.kotlinnative.translator.llvm.types package org.kotlinnative.translator.llvm.types
import org.kotlinnative.translator.llvm.LLVMExpression import org.kotlinnative.translator.llvm.LLVMExpression
import org.kotlinnative.translator.llvm.LLVMSingleValue
import org.kotlinnative.translator.llvm.LLVMVariable import org.kotlinnative.translator.llvm.LLVMVariable
class LLVMIntType() : LLVMType() { class LLVMIntType() : LLVMType() {
//TODO switch by types: int + double = int //TODO switch by types: int + double = int
override fun operatorMinus(result: LLVMVariable, firstOp: LLVMVariable, secondOp: LLVMVariable): LLVMExpression = override fun operatorMinus(result: LLVMVariable, firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression =
LLVMExpression(LLVMIntType(), "sub nsw i32 $firstOp, $secondOp") LLVMExpression(LLVMIntType(), "sub nsw i32 $firstOp, $secondOp")
//TODO switch by types: int + double = int //TODO switch by types: int + double = int
override fun operatorTimes(result: LLVMVariable, firstOp: LLVMVariable, secondOp: LLVMVariable): LLVMExpression = override fun operatorTimes(result: LLVMVariable, firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression =
LLVMExpression(LLVMIntType(), "mul nsw i32 $firstOp, $secondOp") LLVMExpression(LLVMIntType(), "mul nsw i32 $firstOp, $secondOp")
//TODO switch by types: int + double = int //TODO switch by types: int + double = int
override fun operatorPlus(result: LLVMVariable, firstOp: LLVMVariable, secondOp: LLVMVariable): LLVMExpression = override fun operatorPlus(result: LLVMVariable, firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression =
LLVMExpression(LLVMIntType(), "add nsw i32 $firstOp, $secondOp") LLVMExpression(LLVMIntType(), "add nsw i32 $firstOp, $secondOp")
override val align = 4 override val align = 4
@@ -2,13 +2,14 @@ package org.kotlinnative.translator.llvm.types
import org.kotlinnative.translator.exceptions.UnimplementedException import org.kotlinnative.translator.exceptions.UnimplementedException
import org.kotlinnative.translator.llvm.LLVMExpression import org.kotlinnative.translator.llvm.LLVMExpression
import org.kotlinnative.translator.llvm.LLVMSingleValue
import org.kotlinnative.translator.llvm.LLVMVariable import org.kotlinnative.translator.llvm.LLVMVariable
abstract class LLVMType() : Cloneable { abstract class LLVMType() : Cloneable {
open fun operatorPlus(result: LLVMVariable, firstOp: LLVMVariable, secondOp: LLVMVariable): LLVMExpression = throw UnimplementedException() open fun operatorPlus(result: LLVMVariable, firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression = throw UnimplementedException()
open fun operatorTimes(result: LLVMVariable, firstOp: LLVMVariable, secondOp: LLVMVariable): LLVMExpression = throw UnimplementedException() open fun operatorTimes(result: LLVMVariable, firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression = throw UnimplementedException()
open fun operatorMinus(result: LLVMVariable, firstOp: LLVMVariable, secondOp: LLVMVariable): LLVMExpression = throw UnimplementedException() open fun operatorMinus(result: LLVMVariable, firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression = throw UnimplementedException()
fun makeClone() = clone() fun makeClone() = clone()