translator: add string constants, LLVMStringType, split local and global code generation in LLVMBuilder

This commit is contained in:
Alexey Stepanov
2016-07-14 13:15:14 +03:00
parent 8a0c6112d7
commit b6f2445d6f
4 changed files with 79 additions and 40 deletions
@@ -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())
@@ -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)
}
}
@@ -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<LLVMVariable>) {
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()
}
@@ -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]"
}