diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/CodeGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/CodeGenerator.kt new file mode 100644 index 00000000000..9f55533c3e8 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/CodeGenerator.kt @@ -0,0 +1,67 @@ +package org.jetbrains.kotlin.backend.native.llvm + +import llvm.* +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.types.KotlinType +import java.util.* + + +/** + * + * Created by minamoto on 07/10/2016. + */ + +internal class CodeGenerator(override val context:Context) : ContextUtils { + var currentFunction:FunctionDescriptor? = null + + fun function(declaration: IrFunction) { + index = 0 + currentFunction = declaration.descriptor + val fn = LLVMAddFunction(context.llvmModule, declaration.descriptor.symbolName, getLlvmFunctionType(declaration.descriptor)) + val block = LLVMAppendBasicBlock(fn, "entry") + LLVMPositionBuilderAtEnd(context.llvmBuilder, block) + function2variables.put(declaration.descriptor, mutableMapOf()) + declaration.descriptor.valueParameters.forEachIndexed { i, descriptor -> + val name = descriptor.name.asString() + val type = descriptor.type + val v = alloca(type, name) + store(LLVMGetParam(fn, i)!!, v) + currentFunction!!.registerVariable(name, v) + } + + } + + fun tmpVariable():String = currentFunction!!.tmpVariable() + + val variablesGlobal = mapOf() + fun variable(varName:String):LLVMOpaqueValue? = currentFunction!!.variable(varName) + + fun FunctionDescriptor.param(num:Int):LLVMOpaqueValue? = LLVMGetParam(llvmFunction.getLlvmValue(), num) + + var index:Int = 0 + private var FunctionDescriptor.tmpVariableIndex: Int + get() = index + set(i:Int){ index = i} + + fun FunctionDescriptor.tmpVariable():String = "tmp${tmpVariableIndex++}" + + fun registerVariable(varName: String, value:LLVMOpaqueValue) = currentFunction!!.registerVariable(varName, value) + + val function2variables = mutableMapOf>() + + + val FunctionDescriptor.variables: MutableMap + get() = this@CodeGenerator.function2variables[this]!! + + + fun FunctionDescriptor.registerVariable(varName: String, value:LLVMOpaqueValue?) = variables.put(varName, value) + private fun FunctionDescriptor.variable(varName: String): LLVMOpaqueValue? = variables[varName] + + fun plus(arg0:LLVMOpaqueValue, arg1:LLVMOpaqueValue, result:String):LLVMOpaqueValue = LLVMBuildAdd(context.llvmBuilder, arg0, arg1, result)!! + fun alloca(type: KotlinType, varName: String):LLVMOpaqueValue = LLVMBuildAlloca(context.llvmBuilder, getLLVMType(type), varName)!! + fun load(value:LLVMOpaqueValue, varName: String):LLVMOpaqueValue = LLVMBuildLoad(context.llvmBuilder, value, varName)!! + fun store(value:LLVMOpaqueValue, ptr:LLVMOpaqueValue):LLVMOpaqueValue = LLVMBuildStore(context.llvmBuilder, value, ptr)!! +} + + diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/IrToBitcode.kt index f3dd316e968..7fc5e0448d1 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/native/llvm/IrToBitcode.kt @@ -3,7 +3,10 @@ package org.jetbrains.kotlin.backend.native.llvm import llvm.* import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.declarations.IrClass +import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrModuleFragment +import org.jetbrains.kotlin.ir.declarations.IrVariable +import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid @@ -16,6 +19,7 @@ fun emitLLVM(module: IrModuleFragment, runtimeFile: String, outFile: String) { val context = Context(module, runtime, llvmModule) // TODO: dispose module.accept(RTTIGeneratorVisitor(context), null) + module.accept(CodeGeneratorVisitor(context), null) LLVMWriteBitcodeToFile(llvmModule, outFile) } @@ -31,4 +35,71 @@ internal class RTTIGeneratorVisitor(context: Context) : IrElementVisitorVoid { generator.generate(declaration.descriptor) } -} \ No newline at end of file +} + +/** + * TODO: split CodeGeneratorVisitor on Visitor and Generator :) + */ +internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid { + val generator = CodeGenerator(context) + override fun visitFunction(declaration: IrFunction) { + generator.function(declaration) + declaration.acceptChildrenVoid(this) + } + + override fun visitElement(element: IrElement) { + element.acceptChildrenVoid(this) + } + + override fun visitSetVariable(expression: IrSetVariable) { + val value = evaluateExpression(generator.tmpVariable(), expression.value) + generator.store(value!!, generator.variable(expression.descriptor.name.asString())!!) + } + + private fun evaluateExpression(tmpVariableName: String, value: IrExpression?): LLVMOpaqueValue? { + when (value) { + is IrCall -> return evaluateCall(tmpVariableName, value) + is IrGetValue -> return generator.load(generator.variable(value.descriptor.name.asString())!!, tmpVariableName) + null -> return null + else -> { + TODO() + } + } + } + + private fun evaluateCall(tmpVariableName: String, value: IrCall?): LLVMOpaqueValue? { + /* TODO: should we count on receiver? + * val tmp = tmpVar() + * val lhs = evaluateExpression(tmp, value.dispatchReceiver!!) + */ + val args = mutableListOf() + value!!.acceptChildrenVoid(object:IrElementVisitorVoid{ + override fun visitElement(element: IrElement) { + val tmp = generator.tmpVariable() + args.add(evaluateExpression(tmp, element as IrExpression)) + } + }) + when (value!!.origin) { + IrStatementOrigin.PLUS -> return generator.plus(args[0]!!, args[1]!!, tmpVariableName) + else -> { + TODO() + } + } + TODO() + } + + override fun visitVariable(declaration: IrVariable) { + val variableName = declaration.descriptor.name.asString() + val variableType = declaration.descriptor.type + generator.registerVariable(variableName, generator.alloca(variableType, variableName)) + + evaluateExpression(variableName, declaration.initializer) + } + + override fun visitReturn(expression: IrReturn) { + val tmpVarName = generator.tmpVariable() + val value:LLVMOpaqueValue? + value = evaluateExpression(tmpVarName, expression.value) + LLVMBuildRet(context.llvmBuilder, value) + } +} diff --git a/backend.native/tests/Makefile b/backend.native/tests/Makefile new file mode 100644 index 00000000000..33df8c2c53f --- /dev/null +++ b/backend.native/tests/Makefile @@ -0,0 +1,43 @@ +TESTS := sum + +BIN_TESTS=$(foreach t, ${TESTS},${t}_test) + +VPATH=codegen/function + +LLC=llc-mp-3.8 +CC=clang-mp-3.8 +JAVA=java + +TOP=../.. +RUNTIME=${TOP}/runtime +BACKEND=${TOP}/backend.native +BACKEND_CLASSES=${TOP}/backend.native/build/classes +KOTLIN_DIST=${BACKEND}/kotlin-ir/dist +KOTLIN_NATIVE_CLASSPATH=${BACKEND_CLASSES}/bc_frontend:${BACKEND_CLASSES}/cli_bc:${BACKEND_CLASSES}/compiler:${KOTLIN_DIST}/kotlinc/lib/kotlin-reflect.jar:${KOTLIN_DIST}kotlinc/lib/kotlin-stdlib.jar:${KOTLIN_DIST}/kotlinc/lib/kotlin-compiler.jar:${KOTLIN_DIST}/kotlinc/lib/kotlin-runtime.jar:${TOP}/Interop/Runtime/build/classes/main + + +define PROTO +$(1)_test: main.c $1-test.c $1.S + $(CC) -o $$@ $$^ + +${1}_run:${1}_test + ./${1}_test +endef + +$(foreach test,${TESTS},$(eval $(call PROTO,$(test)))) + +all:${BIN_TESTS} + +run:$(foreach test,${TESTS},${test}_run) + +clean: + ${RM} *.o *.S *.BCkt ${BIN_TESTS} + + +%.S:%.BCkt + ${LLC} -o $@ $< + + +%.BCkt:%.kt + ${JAVA} -cp ${KOTLIN_NATIVE_CLASSPATH} -Djava.library.path=${BACKEND}/build/nativelibs org.jetbrains.kotlin.cli.bc.K2NativeKt -output $@ -runtime ${RUNTIME}/build/runtime.bc $< + diff --git a/backend.native/tests/codegen/function/sum-test.c b/backend.native/tests/codegen/function/sum-test.c new file mode 100644 index 00000000000..2658fe58131 --- /dev/null +++ b/backend.native/tests/codegen/function/sum-test.c @@ -0,0 +1,10 @@ +extern void *resolve_symbol(const char*); + +int +run_test() { + int (*sum)(int, int) = resolve_symbol("kfun:sum"); + + if (sum(2, 3) != 5) return 1; + + return 0; +} diff --git a/backend.native/tests/codegen/function/sum.kt b/backend.native/tests/codegen/function/sum.kt new file mode 100644 index 00000000000..38215fdce2d --- /dev/null +++ b/backend.native/tests/codegen/function/sum.kt @@ -0,0 +1 @@ +fun sum(a:Int, b:Int) = a + b \ No newline at end of file diff --git a/backend.native/tests/codegen/function/sum_func.kt b/backend.native/tests/codegen/function/sum_func.kt new file mode 100644 index 00000000000..24a5ca9713a --- /dev/null +++ b/backend.native/tests/codegen/function/sum_func.kt @@ -0,0 +1,3 @@ +fun foo():Int = 1 +//fun bar():Int = 2 +//fun sum():Int = foo() + bar() \ No newline at end of file diff --git a/backend.native/tests/codegen/function/sum_silly.kt b/backend.native/tests/codegen/function/sum_silly.kt new file mode 100644 index 00000000000..89087067188 --- /dev/null +++ b/backend.native/tests/codegen/function/sum_silly.kt @@ -0,0 +1,5 @@ +fun sum(a:Int, b:Int):Int { + var c:Int + c = a + b + return c +} \ No newline at end of file diff --git a/backend.native/tests/main.c b/backend.native/tests/main.c new file mode 100644 index 00000000000..e6f0c27defd --- /dev/null +++ b/backend.native/tests/main.c @@ -0,0 +1,19 @@ +#include +#include +/** + * > llc-mp-3.8 b.out -o b.S + * > /opt/local/libexec/llvm-3.8/bin/clang main.c b.S -o sum-test + */ + +extern int run_test(); + +void * resolve_symbol(char *name) { + /* here we can add here some magic to resolve symbols in kotlin native*/ + return dlsym(RTLD_SELF, name); +} + + +int +main() { + return run_test(); +} diff --git a/sum.c b/sum.c new file mode 100644 index 00000000000..a7f7e84f208 --- /dev/null +++ b/sum.c @@ -0,0 +1,5 @@ +int foo(int a, int b){ + int c; + c = a + b; + return c; +} diff --git a/sum_func.c b/sum_func.c new file mode 100644 index 00000000000..2f7f6f96434 --- /dev/null +++ b/sum_func.c @@ -0,0 +1,3 @@ +int foo() { return 1; } +int bar() {return 2;} +int sum() {return foo() + bar();}