translator: function struct arguments, resolve references

This commit is contained in:
e5l
2016-07-14 15:35:11 +03:00
parent afc351604b
commit 64c88ffe03
8 changed files with 170 additions and 119 deletions
+8 -59
View File
@@ -1,60 +1,9 @@
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1)
attributes #0 = { nounwind "stack-protector-buffer-size"="8" "target-cpu"="cortex-m3" "target-features"="+hwdiv,+strict-align" }
declare void @wait(i32 %loops) #0
define void @programRotationRight() #0
{
call void @engine_turn_right()
call void @wait(i32 10)
ret void
}
define void @setCurProgram(i32 %program) #0
{
%program.addr = alloca i32, align 4
store i32 %program, i32* %program.addr, align 4
ret void
}
define void @programBackward() #0
{
call void @engine_backward()
call void @wait(i32 10)
ret void
}
declare void @leds_init() #0
define void @programForward(i32 %delay) #0
{
%delay.addr = alloca i32, align 4
store i32 %delay, i32* %delay.addr, align 4
call void @engine_forward()
call void @wait(i32 10)
ret void
}
define void @procNextProgramPending() #0
{
ret void
}
declare void @engine_init() #0
declare void @user_btn_init(void ()* %program) #0
define void @setNextProgramPending() #0
{
ret void
}
declare void @engine_backward() #0
define void @programRotationLeft() #0
{
call void @engine_turn_left()
call void @wait(i32 10)
ret void
}
define void @kotlin_main() #0
{
call void @leds_init()
call void @engine_init()
call void @user_btn_init(void ()* @setNextProgramPending)
call void @setCurProgram(i32 0)
ret void
}
declare void @engine_stop() #0
declare void @engine_forward() #0
declare void @engine_turn_left() #0
declare void @engine_turn_right() #0
Exception in thread "main" org.kotlinnative.translator.exceptions.TranslationException
at org.kotlinnative.translator.TranslationStateKt.parseAndAnalyze(TranslationState.kt:50)
at MainKt.main(main.kt:13)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
+1 -1
View File
@@ -10,7 +10,7 @@ fun main(args: Array<String>) {
} }
val disposer = Disposer.newDisposable() val disposer = Disposer.newDisposable()
val state = parseAndAnalyze(args.asList(), disposer, true) val state = parseAndAnalyze(args.asList(), disposer, arm = false)
val files = state.environment.getSourceFiles() val files = state.environment.getSourceFiles()
if (files.isEmpty()) { if (files.isEmpty()) {
@@ -67,6 +67,7 @@ class ClassCodegen(val state: TranslationState, val clazz: KtClass, val codeBuil
val argFields = ArrayList<LLVMVariable>() val argFields = ArrayList<LLVMVariable>()
val refType = type.makeClone() as LLVMReferenceType val refType = type.makeClone() as LLVMReferenceType
refType.addParam("sret") refType.addParam("sret")
refType.isReturn = true
val thisField = LLVMVariable("instance", refType, clazz.name, pointer = true) val thisField = LLVMVariable("instance", refType, clazz.name, pointer = true)
@@ -18,17 +18,30 @@ import java.util.*
class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction, val codeBuilder: LLVMBuilder) { class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction, val codeBuilder: LLVMBuilder) {
var name = function.fqName.toString() var name = function.fqName.toString()
var returnType: LLVMType var returnType: LLVMVariable
var args: List<LLVMVariable>? var args = ArrayList<LLVMVariable>()
val variableManager = state.variableManager val variableManager = state.variableManager
init { init {
val descriptor = state.bindingContext.get(BindingContext.FUNCTION, function)!! val descriptor = state.bindingContext.get(BindingContext.FUNCTION, function)!!
args = descriptor.valueParameters.map { args.addAll(descriptor.valueParameters.map {
LLVMMapStandardType(it.name.toString(), it.type) LLVMMapStandardType(it.name.toString(), it.type)
} })
returnType = LLVMMapStandardType("", descriptor.returnType!!).type returnType = LLVMMapStandardType("instance", descriptor.returnType!!)
val retType = returnType.type
when (retType) {
is LLVMReferenceType -> {
if (state.classes.containsKey(retType.type)) {
retType.prefix = "class"
}
retType.isReturn = true
}
}
if (retType is LLVMReferenceType && state.classes.containsKey(retType.type)) {
retType.prefix = "class"
}
} }
fun generate() { fun generate() {
@@ -41,7 +54,7 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction
evaluateCodeBlock(function.bodyExpression) evaluateCodeBlock(function.bodyExpression)
if (returnType is LLVMVoidType) { if (returnType.type is LLVMVoidType) {
codeBuilder.addVoidReturn() codeBuilder.addVoidReturn()
} }
@@ -51,6 +64,13 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction
private fun generateDeclaration(): Boolean { private fun generateDeclaration(): Boolean {
var external = false var external = false
args.forEach {
val type = it.type
if (type is LLVMReferenceType && state.classes.containsKey(type.type)) {
type.prefix = "class"
}
}
var keyword = function.firstChild var keyword = function.firstChild
while (keyword != null) { while (keyword != null) {
if (keyword.text == "external") { if (keyword.text == "external") {
@@ -61,15 +81,29 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction
keyword = keyword.getNextSiblingIgnoringWhitespaceAndComments() keyword = keyword.getNextSiblingIgnoringWhitespaceAndComments()
} }
codeBuilder.addLLVMCode(LLVMFunctionDescriptor(function.fqName.toString(), args, returnType, external, state.arm)) var actualReturnType: LLVMType = returnType.type
val actualArgs = ArrayList<LLVMVariable>()
if (returnType.pointer) {
actualReturnType = LLVMVoidType()
actualArgs.add(returnType)
}
actualArgs.addAll(args)
codeBuilder.addLLVMCode(LLVMFunctionDescriptor(function.fqName.toString(), actualArgs, actualReturnType, external, state.arm))
return external return external
} }
private fun generateLoadArguments() { private fun generateLoadArguments() {
args?.forEach { args.forEach {
val loadVariable = LLVMVariable(it.label, it.type, it.label, LLVMLocalScope(), false) if (it.type !is LLVMReferenceType || (it.type as LLVMReferenceType).isReturn) {
val allocVar = codeBuilder.loadArgument(loadVariable) val loadVariable = LLVMVariable("${it.label}", it.type, it.label, LLVMLocalScope(), pointer = false)
variableManager.addVariable(it.label, allocVar, 2) val allocVar = codeBuilder.loadArgument(loadVariable)
variableManager.addVariable(it.label, allocVar, 2)
} else {
variableManager.addVariable(it.label, LLVMVariable(it.label, it.type, it.label, LLVMLocalScope(), pointer = true), 2)
}
} }
} }
@@ -84,10 +118,7 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction
is KtBlockExpression -> expressionWalker(expr.firstChild, scopeDepth + 1) is KtBlockExpression -> expressionWalker(expr.firstChild, scopeDepth + 1)
is KtProperty -> evaluateLeafPsiElement(expr.firstChild as LeafPsiElement, scopeDepth) is KtProperty -> evaluateLeafPsiElement(expr.firstChild as LeafPsiElement, scopeDepth)
is KtBinaryExpression -> evaluateBinaryExpression(expr, scopeDepth) is KtBinaryExpression -> evaluateBinaryExpression(expr, scopeDepth)
is KtCallExpression -> { is KtCallExpression -> evaluateCallExpression(expr, scopeDepth)
val expression = evaluateCallExpression(expr, scopeDepth) as LLVMCall
codeBuilder.addLLVMCode(expression.toString())
}
is PsiElement -> evaluateExpression(expr.firstChild, scopeDepth + 1) is PsiElement -> evaluateExpression(expr.firstChild, scopeDepth + 1)
null -> { null -> {
variableManager.pullUpwardsLevel(scopeDepth) variableManager.pullUpwardsLevel(scopeDepth)
@@ -104,9 +135,10 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction
is KtBinaryExpression -> evaluateBinaryExpression(expr, scopeDepth) is KtBinaryExpression -> evaluateBinaryExpression(expr, scopeDepth)
is KtConstantExpression -> evaluateConstantExpression(expr) is KtConstantExpression -> evaluateConstantExpression(expr)
is KtCallExpression -> evaluateCallExpression(expr, scopeDepth) is KtCallExpression -> evaluateCallExpression(expr, scopeDepth)
is KtCallableReferenceExpression -> evaluateCallableReferenceExpression(expr)
is KtReferenceExpression -> evaluateReferenceExpression(expr) is KtReferenceExpression -> evaluateReferenceExpression(expr)
is KtIfExpression -> evaluateIfOperator(expr.firstChild as LeafPsiElement, scopeDepth + 1, true) is KtIfExpression -> evaluateIfOperator(expr.firstChild as LeafPsiElement, scopeDepth + 1, true)
is KtDotQualifiedExpression -> evaluateDotExpression(expr, scopeDepth) is KtDotQualifiedExpression -> evaluateDotExpression(expr)
is PsiWhiteSpace -> null is PsiWhiteSpace -> null
is KtStringTemplateExpression -> evaluateStringTemplateExpression(expr, scopeDepth + 1) is KtStringTemplateExpression -> evaluateStringTemplateExpression(expr, scopeDepth + 1)
is PsiElement -> evaluatePsiElement(expr, scopeDepth) is PsiElement -> evaluatePsiElement(expr, scopeDepth)
@@ -124,7 +156,12 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction
return variable return variable
} }
private fun evaluateDotExpression(expr: KtDotQualifiedExpression, scopeDepth: Int): LLVMSingleValue? { private fun evaluateCallableReferenceExpression(expr: KtCallableReferenceExpression): LLVMSingleValue? {
val kotlinType = state.bindingContext.get(BindingContext.EXPRESSION_TYPE_INFO, expr)!!.type!!
return LLVMMapStandardType(expr.text.substring(2), kotlinType)
}
private fun evaluateDotExpression(expr: KtDotQualifiedExpression): LLVMSingleValue? {
val receiverName = expr.receiverExpression.text val receiverName = expr.receiverExpression.text
val selectorName = expr.selectorExpression!!.text val selectorName = expr.selectorExpression!!.text
@@ -161,31 +198,90 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction
val function = expr.firstChild.firstChild val function = expr.firstChild.firstChild
val descriptor = state.classes[function.text] ?: return null val descriptor = state.classes[function.text] ?: return null
val names = parseArgList(expr, scopeDepth).mapIndexed { i: Int, v: LLVMSingleValue -> val names = parseArgList(expr, scopeDepth).mapIndexed { i: Int, v: LLVMSingleValue ->
LLVMVariable(v.toString(), descriptor.fields[i].type, pointer = descriptor.fields[i].pointer) when (v) {
is LLVMVariable -> LLVMVariable(v.toString(), descriptor.fields[i].type, pointer = descriptor.fields[i].pointer)
else -> v
}
}.toList() }.toList()
return LLVMConstructorCall( val result = codeBuilder.getNewVariable(returnType.type)
descriptor.type, fun(thisVar): LLVMCall { codeBuilder.allocVar(result)
val args = ArrayList<LLVMVariable>() result.pointer = true
args.add(thisVar)
args.addAll(names) val args = ArrayList<LLVMSingleValue>()
return LLVMCall(LLVMVoidType(), descriptor.constructorName, args) args.add(result)
}) args.addAll(names)
codeBuilder.addLLVMCode(LLVMCall(
LLVMVoidType(),
descriptor.constructorName,
args
).toString())
return result
} }
private fun evaluateFunctionCallExpression(expr: KtCallExpression, scopeDepth: Int): LLVMSingleValue? { private fun evaluateFunctionCallExpression(expr: KtCallExpression, scopeDepth: Int): LLVMSingleValue? {
val function = expr.firstChild.firstChild val function = expr.firstChild.firstChild
val descriptor = state.functions[function.text] ?: return null val descriptor = state.functions[function.text] ?: return null
val names = parseArgList(expr, scopeDepth) val names = parseArgList(expr, scopeDepth).mapIndexed(fun(i: Int, llvmSingleValue: LLVMSingleValue): LLVMSingleValue {
var result = llvmSingleValue
return LLVMCall(descriptor.returnType, "@${descriptor.name}", descriptor.args?.mapIndexed { if (result.pointer && !descriptor.args[i].pointer) {
i: Int, variable: LLVMVariable -> result = codeBuilder.getNewVariable(descriptor.args[i].type)
LLVMVariable(names[i].toString(), variable.type, pointer = variable.pointer) codeBuilder.loadVariable(result, llvmSingleValue as LLVMVariable)
} ?: listOf()) }
return result
}).toList()
val returnType = descriptor.returnType.type
when (returnType) {
is LLVMVoidType -> {
codeBuilder.addLLVMCode(LLVMCall(
LLVMVoidType(),
"@${descriptor.name}",
names
).toString())
}
is LLVMReferenceType -> {
val result = codeBuilder.getNewVariable(returnType)
codeBuilder.allocVar(result)
result.pointer = true
val args = ArrayList<LLVMSingleValue>()
args.add(result)
args.addAll(names)
codeBuilder.addLLVMCode(LLVMCall(
LLVMVoidType(),
"@${descriptor.name}",
args
).toString())
return result
}
else -> {
val result = codeBuilder.getNewVariable(returnType)
codeBuilder.addAssignment(result, LLVMCall(
returnType,
"@${descriptor.name}",
names
))
val resultPtr = codeBuilder.getNewVariable(returnType)
codeBuilder.allocVar(resultPtr)
resultPtr.pointer = true
codeBuilder.storeVariable(resultPtr, result)
return resultPtr
}
}
return null
} }
private fun parseArgList(expr: KtCallExpression, scopeDepth: Int): List<LLVMSingleValue> { private fun parseArgList(expr: KtCallExpression, scopeDepth: Int): ArrayList<LLVMSingleValue> {
val args = expr.getValueArgumentsInParentheses() val args = expr.getValueArgumentsInParentheses()
val result = ArrayList<LLVMSingleValue>() val result = ArrayList<LLVMSingleValue>()
@@ -247,17 +343,17 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction
} }
private fun executeWhileBlock(condition: KtBinaryExpression, bodyExpression: PsiElement, scopeDepth: Int): LLVMVariable? { private fun executeWhileBlock(condition: KtBinaryExpression, bodyExpression: PsiElement, scopeDepth: Int): LLVMVariable? {
val conditionLable = codeBuilder.getNewLabel(prefix = "while") val conditionLabel = codeBuilder.getNewLabel(prefix = "while")
val bodyLable = codeBuilder.getNewLabel(prefix = "while") val bodyLabel = codeBuilder.getNewLabel(prefix = "while")
val exitLable = codeBuilder.getNewLabel(prefix = "while") val exitLabel = codeBuilder.getNewLabel(prefix = "while")
codeBuilder.addUnconditionJump(conditionLable) codeBuilder.addUnconditionJump(conditionLabel)
codeBuilder.markWithLabel(conditionLable) codeBuilder.markWithLabel(conditionLabel)
val conditionResult = evaluateBinaryExpression(condition, scopeDepth + 1) val conditionResult = evaluateBinaryExpression(condition, scopeDepth + 1)
codeBuilder.addCondition(conditionResult, bodyLable, exitLable) codeBuilder.addCondition(conditionResult, bodyLabel, exitLabel)
evaluateCodeBlock(bodyExpression, bodyLable, conditionLable, scopeDepth + 1) evaluateCodeBlock(bodyExpression, bodyLabel, conditionLabel, scopeDepth + 1)
codeBuilder.markWithLabel(exitLable) codeBuilder.markWithLabel(exitLabel)
return null return null
} }
@@ -338,15 +434,8 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction
codeBuilder.addConstant(newVar, assignExpression) codeBuilder.addConstant(newVar, assignExpression)
variableManager.addVariable(identifier.text, newVar, scopeDepth) variableManager.addVariable(identifier.text, newVar, scopeDepth)
} }
is LLVMConstructorCall -> {
val result = variableManager.receiveVariable(identifier!!.text, assignExpression.type, LLVMLocalScope(), pointer = false)
codeBuilder.allocVar(result)
result.pointer = true
codeBuilder.addLLVMCode(assignExpression.call(result).toString())
variableManager.addVariable(identifier.text, result, scopeDepth)
}
else -> { else -> {
codeBuilder.addAssignment(LLVMVariable(identifier!!.text, LLVMIntType(), identifier.text, LLVMLocalScope()), assignExpression) throw UnsupportedOperationException()
} }
} }
return null return null
@@ -355,9 +444,21 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction
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 LLVMSingleValue val retVar = evaluateExpression(next, scopeDepth) as LLVMSingleValue
val retNativeValue = codeBuilder.receiveNativeValue(retVar)
codeBuilder.addReturnOperator(retNativeValue) when (returnType.type) {
is LLVMReferenceType -> {
val src = codeBuilder.bitcast(retVar as LLVMVariable, LLVMCharType())
val dst = codeBuilder.bitcast(returnType, LLVMCharType())
val size = state.classes[(retVar.type as LLVMReferenceType).type]!!.size
codeBuilder.memcpy(dst, src, size)
codeBuilder.addVoidReturn()
}
else -> {
val retNativeValue = codeBuilder.receiveNativeValue(retVar)
codeBuilder.addReturnOperator(retNativeValue)
}
}
return null return null
} }
} }
@@ -190,11 +190,10 @@ class LLVMBuilder(val arm: Boolean) {
llvmLocalCode.appendln(code) llvmLocalCode.appendln(code)
} }
fun bitcast(dst: LLVMVariable, llvmType: LLVMType): LLVMVariable { fun bitcast(src: LLVMVariable, llvmType: LLVMType): LLVMVariable {
val empty = getNewVariable(llvmType, true) val empty = getNewVariable(llvmType, true)
val code = "$empty = bitcast ${dst.getType()} $dst to $llvmType*" val code = "$empty = bitcast ${src.getType()} $src to $llvmType*"
llvmLocalCode.appendln(code) llvmLocalCode.appendln(code)
return empty return empty
} }
@@ -2,8 +2,8 @@ package org.kotlinnative.translator.llvm
import org.kotlinnative.translator.llvm.types.LLVMType import org.kotlinnative.translator.llvm.types.LLVMType
class LLVMCall(val returnType: LLVMType, val name: String, val arguments: List<LLVMVariable>) : LLVMSingleValue(returnType) { class LLVMCall(val returnType: LLVMType, val name: String, val arguments: List<LLVMSingleValue>) : LLVMSingleValue(returnType) {
override fun toString(): String = override fun toString(): String =
"call $returnType $name(${arguments.joinToString { "${it.getType()} ${it.label}" }})" "call $returnType $name(${arguments.joinToString { "${it.getType()} ${it.toString()}" }})"
} }
@@ -9,7 +9,7 @@ import org.kotlinnative.translator.llvm.types.*
fun LLVMFunctionDescriptor(name: String, argTypes: List<LLVMVariable>?, returnType: LLVMType, declare: Boolean = false, arm: Boolean = false) = fun LLVMFunctionDescriptor(name: String, argTypes: List<LLVMVariable>?, returnType: LLVMType, declare: Boolean = false, arm: Boolean = false) =
"${if (declare) "declare" else "define"} $returnType @$name(${ "${if (declare) "declare" else "define"} $returnType @$name(${
argTypes?.mapIndexed { i: Int, s: LLVMVariable -> argTypes?.mapIndexed { i: Int, s: LLVMVariable ->
"${s.getType()} %${s.label}" "${s.getType()} ${if (s.type is LLVMReferenceType && !(s.type as LLVMReferenceType).isReturn) "byval" else ""} %${s.label}"
}?.joinToString() }) ${ if (arm) "#0" else ""}" }?.joinToString() }) ${ if (arm) "#0" else ""}"
fun LLVMMapStandardType(name: String, type: KotlinType): LLVMVariable = when { fun LLVMMapStandardType(name: String, type: KotlinType): LLVMVariable = when {
@@ -17,5 +17,5 @@ fun LLVMMapStandardType(name: String, type: KotlinType): LLVMVariable = when {
type.toString() == "Int" -> LLVMVariable(name, LLVMIntType(), type.toString()) type.toString() == "Int" -> LLVMVariable(name, LLVMIntType(), type.toString())
type.toString() == "Double" -> LLVMVariable(name, LLVMDoubleType(), type.toString()) type.toString() == "Double" -> LLVMVariable(name, LLVMDoubleType(), type.toString())
type.isUnit() -> LLVMVariable("", LLVMVoidType()) type.isUnit() -> LLVMVariable("", LLVMVoidType())
else -> LLVMVariable(name, LLVMReferenceType("%$type"), name, pointer = true) else -> LLVMVariable(name, LLVMReferenceType("$type"), name, pointer = true)
} }
@@ -2,12 +2,13 @@ package org.kotlinnative.translator.llvm.types
import java.util.* import java.util.*
class LLVMReferenceType(val type: String, val prefix: String = "") : LLVMType() { class LLVMReferenceType(val type: String, var prefix: String = "", var isReturn: Boolean = false) : LLVMType() {
override val defaultValue: String = ""
override val defaultValue = throw UnsupportedOperationException()
override val align = 4 override val align = 4
override val size: Byte = 4 override val size: Byte = 4
override fun toString() = "%$prefix.$type" override fun toString() = "%$prefix${if (prefix.length > 0) "." else ""}$type"
private val params = ArrayList<String>() private val params = ArrayList<String>()