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 state = parseAndAnalyze(args.asList(), disposer, true)
val state = parseAndAnalyze(args.asList(), disposer, arm = false)
val files = state.environment.getSourceFiles()
if (files.isEmpty()) {
@@ -67,6 +67,7 @@ class ClassCodegen(val state: TranslationState, val clazz: KtClass, val codeBuil
val argFields = ArrayList<LLVMVariable>()
val refType = type.makeClone() as LLVMReferenceType
refType.addParam("sret")
refType.isReturn = 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) {
var name = function.fqName.toString()
var returnType: LLVMType
var args: List<LLVMVariable>?
var returnType: LLVMVariable
var args = ArrayList<LLVMVariable>()
val variableManager = state.variableManager
init {
val descriptor = state.bindingContext.get(BindingContext.FUNCTION, function)!!
args = descriptor.valueParameters.map {
args.addAll(descriptor.valueParameters.map {
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() {
@@ -41,7 +54,7 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction
evaluateCodeBlock(function.bodyExpression)
if (returnType is LLVMVoidType) {
if (returnType.type is LLVMVoidType) {
codeBuilder.addVoidReturn()
}
@@ -51,6 +64,13 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction
private fun generateDeclaration(): Boolean {
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
while (keyword != null) {
if (keyword.text == "external") {
@@ -61,15 +81,29 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction
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
}
private fun generateLoadArguments() {
args?.forEach {
val loadVariable = LLVMVariable(it.label, it.type, it.label, LLVMLocalScope(), false)
val allocVar = codeBuilder.loadArgument(loadVariable)
variableManager.addVariable(it.label, allocVar, 2)
args.forEach {
if (it.type !is LLVMReferenceType || (it.type as LLVMReferenceType).isReturn) {
val loadVariable = LLVMVariable("${it.label}", it.type, it.label, LLVMLocalScope(), pointer = false)
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 KtProperty -> evaluateLeafPsiElement(expr.firstChild as LeafPsiElement, scopeDepth)
is KtBinaryExpression -> evaluateBinaryExpression(expr, scopeDepth)
is KtCallExpression -> {
val expression = evaluateCallExpression(expr, scopeDepth) as LLVMCall
codeBuilder.addLLVMCode(expression.toString())
}
is KtCallExpression -> evaluateCallExpression(expr, scopeDepth)
is PsiElement -> evaluateExpression(expr.firstChild, scopeDepth + 1)
null -> {
variableManager.pullUpwardsLevel(scopeDepth)
@@ -104,9 +135,10 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction
is KtBinaryExpression -> evaluateBinaryExpression(expr, scopeDepth)
is KtConstantExpression -> evaluateConstantExpression(expr)
is KtCallExpression -> evaluateCallExpression(expr, scopeDepth)
is KtCallableReferenceExpression -> evaluateCallableReferenceExpression(expr)
is KtReferenceExpression -> evaluateReferenceExpression(expr)
is KtIfExpression -> evaluateIfOperator(expr.firstChild as LeafPsiElement, scopeDepth + 1, true)
is KtDotQualifiedExpression -> evaluateDotExpression(expr, scopeDepth)
is KtDotQualifiedExpression -> evaluateDotExpression(expr)
is PsiWhiteSpace -> null
is KtStringTemplateExpression -> evaluateStringTemplateExpression(expr, scopeDepth + 1)
is PsiElement -> evaluatePsiElement(expr, scopeDepth)
@@ -124,7 +156,12 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction
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 selectorName = expr.selectorExpression!!.text
@@ -161,31 +198,90 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction
val function = expr.firstChild.firstChild
val descriptor = state.classes[function.text] ?: return null
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()
return LLVMConstructorCall(
descriptor.type, fun(thisVar): LLVMCall {
val args = ArrayList<LLVMVariable>()
args.add(thisVar)
args.addAll(names)
return LLVMCall(LLVMVoidType(), descriptor.constructorName, args)
})
val result = codeBuilder.getNewVariable(returnType.type)
codeBuilder.allocVar(result)
result.pointer = true
val args = ArrayList<LLVMSingleValue>()
args.add(result)
args.addAll(names)
codeBuilder.addLLVMCode(LLVMCall(
LLVMVoidType(),
descriptor.constructorName,
args
).toString())
return result
}
private fun evaluateFunctionCallExpression(expr: KtCallExpression, scopeDepth: Int): LLVMSingleValue? {
val function = expr.firstChild.firstChild
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 {
i: Int, variable: LLVMVariable ->
LLVMVariable(names[i].toString(), variable.type, pointer = variable.pointer)
} ?: listOf())
if (result.pointer && !descriptor.args[i].pointer) {
result = codeBuilder.getNewVariable(descriptor.args[i].type)
codeBuilder.loadVariable(result, llvmSingleValue as LLVMVariable)
}
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 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? {
val conditionLable = codeBuilder.getNewLabel(prefix = "while")
val bodyLable = codeBuilder.getNewLabel(prefix = "while")
val exitLable = codeBuilder.getNewLabel(prefix = "while")
val conditionLabel = codeBuilder.getNewLabel(prefix = "while")
val bodyLabel = codeBuilder.getNewLabel(prefix = "while")
val exitLabel = codeBuilder.getNewLabel(prefix = "while")
codeBuilder.addUnconditionJump(conditionLable)
codeBuilder.markWithLabel(conditionLable)
codeBuilder.addUnconditionJump(conditionLabel)
codeBuilder.markWithLabel(conditionLabel)
val conditionResult = evaluateBinaryExpression(condition, scopeDepth + 1)
codeBuilder.addCondition(conditionResult, bodyLable, exitLable)
evaluateCodeBlock(bodyExpression, bodyLable, conditionLable, scopeDepth + 1)
codeBuilder.markWithLabel(exitLable)
codeBuilder.addCondition(conditionResult, bodyLabel, exitLabel)
evaluateCodeBlock(bodyExpression, bodyLabel, conditionLabel, scopeDepth + 1)
codeBuilder.markWithLabel(exitLabel)
return null
}
@@ -338,15 +434,8 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction
codeBuilder.addConstant(newVar, assignExpression)
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 -> {
codeBuilder.addAssignment(LLVMVariable(identifier!!.text, LLVMIntType(), identifier.text, LLVMLocalScope()), assignExpression)
throw UnsupportedOperationException()
}
}
return null
@@ -355,9 +444,21 @@ class FunctionCodegen(val state: TranslationState, val function: KtNamedFunction
private fun evaluateReturnInstruction(element: LeafPsiElement, scopeDepth: Int): LLVMVariable? {
val next = element.getNextSiblingIgnoringWhitespaceAndComments()
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
}
}
@@ -190,11 +190,10 @@ class LLVMBuilder(val arm: Boolean) {
llvmLocalCode.appendln(code)
}
fun bitcast(dst: LLVMVariable, llvmType: LLVMType): LLVMVariable {
fun bitcast(src: LLVMVariable, llvmType: LLVMType): LLVMVariable {
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)
return empty
}
@@ -2,8 +2,8 @@ package org.kotlinnative.translator.llvm
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 =
"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) =
"${if (declare) "declare" else "define"} $returnType @$name(${
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 ""}"
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() == "Double" -> LLVMVariable(name, LLVMDoubleType(), type.toString())
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.*
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 size: Byte = 4
override fun toString() = "%$prefix.$type"
override fun toString() = "%$prefix${if (prefix.length > 0) "." else ""}$type"
private val params = ArrayList<String>()