diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt index 7e6e0318754..da4eb98f44a 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt @@ -133,7 +133,8 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction ?.firstChild) 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()) } @@ -153,19 +154,19 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction } 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 left = evaluateExpression(expr.firstChild, scopeDepth) as LLVMSingleValue? ?: throw UnsupportedOperationException("Wrong binary exception") + val right = evaluateExpression(expr.lastChild, scopeDepth) as LLVMSingleValue? ?: throw UnsupportedOperationException("Wrong binary exception") val operator = expr.operationToken - - return codeBuilder.addPrimitiveBinaryOperation(operator, left, right) + val newVar = codeBuilder.getNewVariable(LLVMIntType()) + return codeBuilder.addPrimitiveBinaryOperation(operator, newVar, left, right) } - private fun evaluateConstantExpression(expr: KtConstantExpression): LLVMVariable { + private fun evaluateConstantExpression(expr: KtConstantExpression): LLVMConstant { 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) { is LeafPsiElement -> evaluateLeafPsiElement(element, scopeDepth) is KtConstantExpression -> evaluateConstantExpression(element) @@ -194,16 +195,22 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction assignExpression.kotlinName = identifier!!.text assignExpression.pointer = false 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 } private fun evaluateReturnInstruction(element: LeafPsiElement, scopeDepth: Int): LLVMVariable? { val next = element.getNextSiblingIgnoringWhitespaceAndComments() - val retVar = evaluateExpression(next, scopeDepth) as LLVMVariable + val retVar = evaluateExpression(next, scopeDepth) as LLVMSingleValue codeBuilder.addReturnOperator(retVar) return null 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 c44f9c08f6c..22fb5403ce2 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMBuilder.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMBuilder.kt @@ -2,16 +2,15 @@ package org.kotlinnative.translator.llvm import com.intellij.psi.tree.IElementType import org.jetbrains.kotlin.lexer.KtTokens -import org.kotlinnative.translator.llvm.types.LLVMIntType import org.kotlinnative.translator.llvm.types.LLVMType class LLVMBuilder { private var llvmCode: StringBuilder = StringBuilder() private var variableCount = 0 - fun getNewVariable(type: LLVMType?, pointer: Boolean = false): LLVMVariable { + fun getNewVariable(type: LLVMType?, pointer: Boolean = false, kotlinName: String? = null): LLVMVariable { variableCount++ - return LLVMVariable("%var$variableCount", type, "", pointer) + return LLVMVariable("%var$variableCount", type, kotlinName = kotlinName, pointer = pointer) } fun addLLVMCode(code: String) { @@ -26,18 +25,29 @@ class LLVMBuilder { llvmCode.appendln("}") } - fun addPrimitiveBinaryOperation(operation: IElementType, firstOp: LLVMVariable, secondOp: LLVMVariable): LLVMVariable { - val newVar = getNewVariable(LLVMIntType()) + fun receiveNativeValue(firstOp: LLVMSingleValue) = when (firstOp) { + 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) { - 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.PLUS -> firstOp.type!!.operatorPlus(resultOp, firstNativeOp, secondNativeOp) + KtTokens.MINUS -> firstOp.type!!.operatorMinus(resultOp, firstNativeOp, secondNativeOp) + KtTokens.MUL -> firstOp.type!!.operatorTimes(resultOp, firstNativeOp, secondNativeOp) + KtTokens.EQ -> return resultOp else -> throw UnsupportedOperationException("Unknown binary operator") } - addAssignment(newVar, llvmExpression) + addAssignment(resultOp, llvmExpression) - return newVar + return resultOp } fun clean() { @@ -48,7 +58,7 @@ class LLVMBuilder { llvmCode.appendln("$llvmVariable = $rhs") } - fun addReturnOperator(llvmVariable: LLVMVariable) { + fun addReturnOperator(llvmVariable: LLVMSingleValue) { llvmCode.appendln("ret ${llvmVariable.type} $llvmVariable") } @@ -56,6 +66,16 @@ class LLVMBuilder { 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) { addVariableByRef(LLVMVariable("${llvmVariable.label}.addr", llvmVariable.type, llvmVariable.kotlinName, true), llvmVariable, store) } @@ -65,16 +85,6 @@ class LLVMBuilder { 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}") @@ -83,18 +93,22 @@ class LLVMBuilder { } } - fun addVariableByValue(targetVariable: LLVMVariable, sourceVariable: LLVMVariable) { - 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}") - llvmCode.appendln("$targetVariable = load ${targetVariable.type}, ${tmp.getType()} $tmp, align ${targetVariable.type?.align}") - + fun addVariableByValue(targetVariable: LLVMVariable, sourceVariable: LLVMVariable, allocVariable: LLVMVariable) { + 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("$targetVariable = load ${targetVariable.type}, ${allocVariable.getType()} $allocVariable, align ${targetVariable.type?.align}") } - fun addConstant(sourceVariable: LLVMVariable): LLVMVariable { - val target = getNewVariable(sourceVariable.type, sourceVariable.pointer) - addVariableByValue(target, sourceVariable) + fun addConstant(allocVariable: LLVMVariable, constantValue: LLVMConstant) { + llvmCode.appendln("$allocVariable = alloca ${allocVariable.type}, align ${allocVariable.type?.align}") + 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 } @@ -104,15 +118,15 @@ class LLVMBuilder { } fun bitcast(dst: LLVMVariable, llvmType: LLVMType): LLVMVariable { - var empty = getNewVariable(llvmType, true) - var code = "$empty = bitcast ${dst.getType()} $dst to $llvmType*" + val empty = getNewVariable(llvmType, true) + val 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)" + fun memcpy(castedDst: LLVMVariable, castedSrc: LLVMVariable, size: Int, align: Int = 4, volatile: Boolean = false) { + val code = "call void @llvm.memcpy.p0i8.p0i8.i64(i8* $castedDst, i8* $castedSrc, i64 $size, i32 $align, i1 $volatile)" llvmCode.appendln(code) } diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMConstant.kt b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMConstant.kt new file mode 100644 index 00000000000..0e0cdf38b2b --- /dev/null +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMConstant.kt @@ -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 +} \ No newline at end of file diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMSingleValue.kt b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMSingleValue.kt new file mode 100644 index 00000000000..82bc27c8682 --- /dev/null +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMSingleValue.kt @@ -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() +} diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMVariable.kt b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMVariable.kt index 4e0fec41040..7bc2816c44c 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMVariable.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMVariable.kt @@ -2,9 +2,9 @@ package org.kotlinnative.translator.llvm 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 } \ 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 d5943bf85c9..de51a510510 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 @@ -1,21 +1,22 @@ package org.kotlinnative.translator.llvm.types import org.kotlinnative.translator.llvm.LLVMExpression +import org.kotlinnative.translator.llvm.LLVMSingleValue import org.kotlinnative.translator.llvm.LLVMVariable class LLVMDoubleType() : LLVMType() { //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") //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") //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") override val align = 8 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 34d3dbf49d5..c9d6864c215 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 @@ -1,21 +1,22 @@ package org.kotlinnative.translator.llvm.types import org.kotlinnative.translator.llvm.LLVMExpression +import org.kotlinnative.translator.llvm.LLVMSingleValue import org.kotlinnative.translator.llvm.LLVMVariable class LLVMIntType() : LLVMType() { //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") //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") //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") override val align = 4 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 68a9c5435a8..b390d5fa61a 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 @@ -2,13 +2,14 @@ package org.kotlinnative.translator.llvm.types import org.kotlinnative.translator.exceptions.UnimplementedException import org.kotlinnative.translator.llvm.LLVMExpression +import org.kotlinnative.translator.llvm.LLVMSingleValue import org.kotlinnative.translator.llvm.LLVMVariable 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() + open fun operatorPlus(result: LLVMVariable, firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression = throw UnimplementedException() + open fun operatorTimes(result: LLVMVariable, firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression = throw UnimplementedException() + open fun operatorMinus(result: LLVMVariable, firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression = throw UnimplementedException() fun makeClone() = clone()