From b6f2445d6f6fa1181e02074c8342a2025dfdab62 Mon Sep 17 00:00:00 2001 From: Alexey Stepanov Date: Thu, 14 Jul 2016 13:15:14 +0300 Subject: [PATCH] translator: add string constants, LLVMStringType, split local and global code generation in LLVMBuilder --- .../translator/FunctionCodegen.kt | 24 +++++- .../translator/VariableManager.kt | 6 +- .../translator/llvm/LLVMBuilder.kt | 79 +++++++++++-------- .../translator/llvm/types/LLVMString.kt | 10 +++ 4 files changed, 79 insertions(+), 40 deletions(-) create mode 100644 translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMString.kt diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt index 12ffbd59b17..0903962783b 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getNextSiblingIgnoringWhitespaceAndComments import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.calls.callUtil.getValueArgumentsInParentheses +import org.jetbrains.kotlin.resolve.constants.TypedCompileTimeConstant import org.kotlinnative.translator.llvm.* import org.kotlinnative.translator.llvm.types.* import java.util.* @@ -107,12 +108,22 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction is KtIfExpression -> evaluateIfOperator(expr.firstChild as LeafPsiElement, scopeDepth + 1, true) is KtDotQualifiedExpression -> evaluateDotExpression(expr, scopeDepth) is PsiWhiteSpace -> null + is KtStringTemplateExpression -> evaluateStringTemplateExpression(expr, scopeDepth + 1) is PsiElement -> evaluatePsiElement(expr, scopeDepth) null -> null else -> throw UnsupportedOperationException() } } + fun evaluateStringTemplateExpression(expr: KtStringTemplateExpression, scope: Int): LLVMSingleValue? { + val receiveValue = state.bindingContext.get(BindingContext.COMPILE_TIME_VALUE, expr) + val type = (receiveValue as TypedCompileTimeConstant).type + val value = receiveValue.getValue(type) ?: return null + val variable = variableManager.receiveVariable(".str", LLVMStringType(value.toString().length), LLVMGlobalScope(), pointer = false) + codeBuilder.addStringConstant(variable, value.toString()) + return variable + } + private fun evaluateDotExpression(expr: KtDotQualifiedExpression, scopeDepth: Int): LLVMSingleValue? { val receiverName = expr.receiverExpression.text val selectorName = expr.selectorExpression!!.text @@ -303,6 +314,11 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction return null } + private fun copyVariable(from: LLVMVariable, to: LLVMVariable) = when (from.type) { + is LLVMStringType -> codeBuilder.storeString(to, from, 0) + else -> codeBuilder.copyVariableValue(to, from) + } + private fun evaluateValExpression(element: LeafPsiElement, scopeDepth: Int): LLVMVariable? { val identifier = element.getNextSiblingIgnoringWhitespaceAndComments() val eq = identifier?.getNextSiblingIgnoringWhitespaceAndComments() ?: return null @@ -311,19 +327,19 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction when (assignExpression) { is LLVMVariable -> { - val allocVar = variableManager.receiveVariable(identifier!!.text, LLVMIntType(), pointer = true) + val allocVar = variableManager.receiveVariable(identifier!!.text, assignExpression.type, LLVMLocalScope(), pointer = true) codeBuilder.allocVar(allocVar) variableManager.addVariable(identifier.text, allocVar, scopeDepth) - codeBuilder.copyVariableValue(assignExpression, allocVar) + copyVariable(assignExpression, allocVar) } is LLVMConstant -> { - val newVar = variableManager.receiveVariable(identifier!!.text, LLVMIntType(), pointer = true) + val newVar = variableManager.receiveVariable(identifier!!.text, LLVMIntType(), LLVMLocalScope(), pointer = true) codeBuilder.addConstant(newVar, assignExpression) variableManager.addVariable(identifier.text, newVar, scopeDepth) } is LLVMConstructorCall -> { - val result = variableManager.receiveVariable(identifier!!.text, assignExpression.type, pointer = false) + val result = variableManager.receiveVariable(identifier!!.text, assignExpression.type, LLVMLocalScope(), pointer = false) codeBuilder.allocVar(result) result.pointer = true codeBuilder.addLLVMCode(assignExpression.call(result).toString()) diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/VariableManager.kt b/translator/src/main/kotlin/org/kotlinnative/translator/VariableManager.kt index 4e84ed2293c..5dcbd9d0960 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/VariableManager.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/VariableManager.kt @@ -1,6 +1,6 @@ package org.kotlinnative.translator -import org.kotlinnative.translator.llvm.LLVMLocalScope +import org.kotlinnative.translator.llvm.LLVMScope import org.kotlinnative.translator.llvm.LLVMVariable import org.kotlinnative.translator.llvm.types.LLVMType import java.util.* @@ -29,11 +29,11 @@ class VariableManager { globalVariableCollection.put(name, variable) } - fun receiveVariable(name: String, type: LLVMType, pointer: Boolean): LLVMVariable { + fun receiveVariable(name: String, type: LLVMType, scope: LLVMScope, pointer: Boolean): LLVMVariable { val ourVersion = variableVersion.getOrDefault(name, 0) + 1 variableVersion.put(name, ourVersion) - return LLVMVariable("managed.$name.$ourVersion", type, name, LLVMLocalScope(), pointer) + return LLVMVariable("managed.$name.$ourVersion", type, name, scope, pointer) } } \ 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 340cbebf124..7cf917f6069 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMBuilder.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMBuilder.kt @@ -3,10 +3,12 @@ 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.LLVMStringType import org.kotlinnative.translator.llvm.types.LLVMType class LLVMBuilder(val arm: Boolean) { - private var llvmCode: StringBuilder = StringBuilder() + private var llvmLocalCode: StringBuilder = StringBuilder() + private var llvmGlobalCode: StringBuilder = StringBuilder() private var variableCount = 0 private var labelCount = 0 @@ -17,10 +19,10 @@ class LLVMBuilder(val arm: Boolean) { private fun initBuilder() { val memcpy = "declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1)" val funcAttributes = """attributes #0 = { nounwind "stack-protector-buffer-size"="8" "target-cpu"="cortex-m3" "target-features"="+hwdiv,+strict-align" }""" - llvmCode.appendln(memcpy) + llvmLocalCode.appendln(memcpy) if (arm) { - llvmCode.appendln(funcAttributes) + llvmLocalCode.appendln(funcAttributes) } } @@ -35,15 +37,15 @@ class LLVMBuilder(val arm: Boolean) { } fun addLLVMCode(code: String) { - llvmCode.appendln(code) + llvmLocalCode.appendln(code) } fun addStartExpression() { - llvmCode.appendln("{") + llvmLocalCode.appendln("{") } fun addEndExpression() { - llvmCode.appendln("}") + llvmLocalCode.appendln("}") } fun receiveNativeValue(firstOp: LLVMSingleValue): LLVMSingleValue = when (firstOp) { @@ -82,46 +84,57 @@ class LLVMBuilder(val arm: Boolean) { } fun clean() { - llvmCode = StringBuilder() + llvmLocalCode = StringBuilder() initBuilder() } fun addAssignment(llvmVariable: LLVMVariable, rhs: LLVMNode) { - llvmCode.appendln("$llvmVariable = $rhs") + llvmLocalCode.appendln("$llvmVariable = $rhs") } fun addReturnOperator(llvmVariable: LLVMSingleValue) { - llvmCode.appendln("ret ${llvmVariable.type} $llvmVariable") + llvmLocalCode.appendln("ret ${llvmVariable.type} $llvmVariable") } fun addVoidReturn() { - llvmCode.appendln("ret void") + llvmLocalCode.appendln("ret void") + } + + fun addStringConstant(variable: LLVMVariable, value: String) { + val type = variable.type as LLVMStringType + llvmGlobalCode.appendln("$variable = private unnamed_addr constant ${type.fullType()} c\"$value\\00\", align 1") + } + + fun storeString(target: LLVMVariable, source: LLVMVariable, offset: Int) { + val stringType = source.type as LLVMStringType + val code = "store ${target.type} getelementptr inbounds (${stringType.fullType()}, " + + "${stringType.fullType()}* $source, i32 0, i32 $offset), ${target.getType()} $target, align ${stringType.align}" + llvmLocalCode.appendln(code) } 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) + llvmLocalCode.appendln(code) } fun markWithLabel(label: LLVMLabel?) { if (label != null) - llvmCode.appendln("${label.label}:") + llvmLocalCode.appendln("${label.label}:") } fun addNopInstruction() { - llvmCode.appendln(getNewVariable(LLVMIntType()).toString() + " = add i1 0, 0 ; nop instruction") + llvmLocalCode.appendln(getNewVariable(LLVMIntType()).toString() + " = add i1 0, 0 ; nop instruction") } fun storeVariable(target: LLVMVariable, source: LLVMSingleValue) { val code = "store ${source.type} $source, ${target.getType()} $target, align ${source.type?.align!!}" - llvmCode.appendln(code) + llvmLocalCode.appendln(code) } - fun copyVariableValue(from: LLVMVariable, to: LLVMVariable) { - val tmp = getNewVariable(from.type, from.pointer) - llvmCode.appendln("$tmp = load ${tmp.type}, ${from.getType()} $from, align ${tmp.type.align}") - llvmCode.appendln("store ${to.type} $tmp, ${to.getType()} $to, align ${tmp.type.align}") - + fun copyVariableValue(target: LLVMVariable, source: LLVMVariable) { + val tmp = getNewVariable(source.type, source.pointer) + llvmLocalCode.appendln("$tmp = load ${tmp.type}, ${source.getType()} $source, align ${tmp.type.align}") + llvmLocalCode.appendln("store ${target.type} $tmp, ${target.getType()} $target, align ${tmp.type.align}") } fun loadArgument(llvmVariable: LLVMVariable, store: Boolean = true): LLVMVariable { @@ -132,63 +145,63 @@ class LLVMBuilder(val arm: Boolean) { fun loadVariable(target: LLVMVariable, source: LLVMVariable) { val code = "$target = load ${target.type}, ${source.getType()} $source, align ${target.type.align}" - llvmCode.appendln(code) + llvmLocalCode.appendln(code) } fun allocVar(target: LLVMVariable) { - llvmCode.appendln("$target = alloca ${target.type}, align ${target.type.align}") + llvmLocalCode.appendln("$target = alloca ${target.type}, align ${target.type.align}") } fun addVariableByRef(targetVariable: LLVMVariable, sourceVariable: LLVMVariable, store: Boolean) { - llvmCode.appendln("$targetVariable = alloca ${sourceVariable.type}, align ${sourceVariable.type.align}") + llvmLocalCode.appendln("$targetVariable = alloca ${sourceVariable.type}, align ${sourceVariable.type.align}") if (store) { - llvmCode.appendln("store ${sourceVariable.getType()} $sourceVariable, ${targetVariable.getType()} $targetVariable, align ${targetVariable.type.align}") + llvmLocalCode.appendln("store ${sourceVariable.getType()} $sourceVariable, ${targetVariable.getType()} $targetVariable, align ${targetVariable.type.align}") } } 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}") + llvmLocalCode.appendln("$allocVariable = alloca ${allocVariable.type}, align ${allocVariable.type.align}") + llvmLocalCode.appendln("store ${allocVariable.type} $constantValue, ${allocVariable.getType()} $allocVariable, align ${allocVariable.type.align}") } fun declareGlovalVariable(variable: LLVMVariable, defaultValue: String = variable.type.defaultValue) { - llvmCode.appendln("$variable = global ${variable.type} $defaultValue, align ${variable.type.align}") + llvmLocalCode.appendln("$variable = global ${variable.type} $defaultValue, align ${variable.type.align}") } fun loadAndGetVariable(source: LLVMVariable): LLVMVariable { assert(!source.pointer) val target = getNewVariable(source.type, source.pointer, source.kotlinName) val code = "$target = load ${target.type}, ${source.getType()} $source, align ${target.type.align}" - llvmCode.appendln(code) + llvmLocalCode.appendln(code) return target } fun addCondition(condition: LLVMSingleValue, thenLabel: LLVMLabel, elseLabel: LLVMLabel) { - llvmCode.appendln("br ${condition.getType()} $condition, label $thenLabel, label $elseLabel") + llvmLocalCode.appendln("br ${condition.getType()} $condition, label $thenLabel, label $elseLabel") } fun addUnconditionJump(label: LLVMLabel) { - llvmCode.appendln("br label $label") + llvmLocalCode.appendln("br label $label") } fun createClass(name: String, fields: List) { val code = "%class.$name = type { ${fields.map { it.type }.joinToString()} }" - llvmCode.appendln(code) + llvmLocalCode.appendln(code) } fun bitcast(dst: LLVMVariable, llvmType: LLVMType): LLVMVariable { val empty = getNewVariable(llvmType, true) val code = "$empty = bitcast ${dst.getType()} $dst to $llvmType*" - llvmCode.appendln(code) + llvmLocalCode.appendln(code) return empty } 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) + llvmLocalCode.appendln(code) } - override fun toString() = llvmCode.toString() + override fun toString() = llvmGlobalCode.toString() + llvmLocalCode.toString() } \ No newline at end of file diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMString.kt b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMString.kt new file mode 100644 index 00000000000..04825564e8c --- /dev/null +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMString.kt @@ -0,0 +1,10 @@ +package org.kotlinnative.translator.llvm.types + +class LLVMStringType(val length : Int) : LLVMType() { + override val size: Byte = 1 + override val align = 8 + override val defaultValue = "" + + override fun toString(): String = "i8*" + fun fullType() = "[${length+1} x i8]" +}