translator: function struct arguments, resolve references
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
+4
-3
@@ -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>()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user