translator: add string constants, LLVMStringType, split local and global code generation in LLVMBuilder
This commit is contained in:
@@ -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]"
|
||||
}
|
||||
Reference in New Issue
Block a user