Merge pull request #12 from JetBrains/object-initialization
Object initialization and field access
This commit is contained in:
+76
-13
@@ -3,7 +3,11 @@ package org.jetbrains.kotlin.backend.native.llvm
|
||||
|
||||
import kotlin_native.interop.*
|
||||
import llvm.*
|
||||
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
@@ -15,20 +19,55 @@ internal class CodeGenerator(override val context:Context) : ContextUtils {
|
||||
return
|
||||
}
|
||||
|
||||
if (currentFunction == declaration.descriptor) return
|
||||
val fn = prolog(declaration)
|
||||
|
||||
var indexOffset = 0
|
||||
if (declaration.descriptor is ClassConstructorDescriptor || declaration.descriptor.dispatchReceiverParameter != null) {
|
||||
val name = "this"
|
||||
val type = pointerType(LLVMInt8Type());
|
||||
val v = alloca(type, name)
|
||||
store(LLVMGetParam(fn, 0)!!, v)
|
||||
currentFunction!!.registerVariable(name, v)
|
||||
indexOffset = 1;
|
||||
}
|
||||
|
||||
declaration.descriptor.valueParameters.forEachIndexed { i, descriptor ->
|
||||
val name = descriptor.name.asString()
|
||||
val type = descriptor.type
|
||||
val v = alloca(type, name)
|
||||
store(LLVMGetParam(fn, indexOffset + i)!!, v)
|
||||
|
||||
currentFunction!!.registerVariable(name, v)
|
||||
}
|
||||
}
|
||||
|
||||
/* HACK: */
|
||||
var currentClass:ClassDescriptor? = null
|
||||
/* constructor */
|
||||
fun initFunction(declaration: IrConstructor) {
|
||||
function(declaration)
|
||||
val thisPtr = bitcast(pointerType(classType(declaration.descriptor.containingDeclaration)), load(thisVariable(), tmpVariable()), tmpVariable())
|
||||
declaration.descriptor.valueParameters.forEachIndexed { i, descriptor ->
|
||||
val name = descriptor.name.asString()
|
||||
val ptr = LLVMBuildStructGEP(context.llvmBuilder, thisPtr, i, tmpVariable())
|
||||
val value = load(variable(name)!!, tmpVariable())
|
||||
|
||||
val typePtr = bitcast(pointerType(LLVMTypeOf(value)), ptr!!, tmpVariable())
|
||||
store(value, typePtr!!)
|
||||
}
|
||||
currentClass = declaration.descriptor.constructedClass
|
||||
}
|
||||
|
||||
|
||||
private fun prolog(declaration: IrFunction): LLVMOpaqueValue? {
|
||||
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)
|
||||
}
|
||||
|
||||
return fn
|
||||
}
|
||||
|
||||
fun tmpVariable():String = currentFunction!!.tmpVariable()
|
||||
@@ -36,8 +75,6 @@ internal class CodeGenerator(override val context:Context) : ContextUtils {
|
||||
val variablesGlobal = mapOf<String, LLVMOpaqueValue?>()
|
||||
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
|
||||
@@ -53,6 +90,9 @@ internal class CodeGenerator(override val context:Context) : ContextUtils {
|
||||
val FunctionDescriptor.variables: MutableMap<String, LLVMOpaqueValue?>
|
||||
get() = this@CodeGenerator.function2variables[this]!!
|
||||
|
||||
val ClassConstructorDescriptor.thisValue:LLVMOpaqueValue?
|
||||
get() = thisValue
|
||||
|
||||
|
||||
fun FunctionDescriptor.registerVariable(varName: String, value:LLVMOpaqueValue?) = variables.put(varName, value)
|
||||
private fun FunctionDescriptor.variable(varName: String): LLVMOpaqueValue? = variables[varName]
|
||||
@@ -62,16 +102,39 @@ internal class CodeGenerator(override val context:Context) : ContextUtils {
|
||||
fun minus(arg0: LLVMOpaqueValue, arg1: LLVMOpaqueValue, result: String): LLVMOpaqueValue = LLVMBuildSub(context.llvmBuilder, arg0, arg1, result)!!
|
||||
fun div(arg0: LLVMOpaqueValue, arg1: LLVMOpaqueValue, result: String): LLVMOpaqueValue = LLVMBuildSDiv(context.llvmBuilder, arg0, arg1, result)!!
|
||||
fun remainder(arg0: LLVMOpaqueValue, arg1: LLVMOpaqueValue, result: String): LLVMOpaqueValue = LLVMBuildSRem(context.llvmBuilder, arg0, arg1, result)!!
|
||||
fun alloca(type: KotlinType, varName: String):LLVMOpaqueValue = LLVMBuildAlloca(context.llvmBuilder, getLLVMType(type), varName)!!
|
||||
fun alloca(type: KotlinType, varName: String):LLVMOpaqueValue = alloca( getLLVMType(type), varName)
|
||||
fun alloca(type: LLVMOpaqueType?, varName: String): LLVMOpaqueValue = LLVMBuildAlloca(context.llvmBuilder, 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)!!
|
||||
fun call(descriptor: FunctionDescriptor, args: MutableList<LLVMOpaqueValue?>, result: String): LLVMOpaqueValue? {
|
||||
if (args.size == 0) return LLVMBuildCall(context.llvmBuilder, descriptor.llvmFunction.getLlvmValue(), null, 0, result)
|
||||
memScoped {
|
||||
val rargs = alloc(array[args.size](Ref to LLVMOpaqueValue))
|
||||
args.forEachIndexed { i, llvmOpaqueValue -> rargs[i].value = args[i] }
|
||||
args.forEachIndexed { i, llvmOpaqueValue -> rargs[i].value = args[i]}
|
||||
return LLVMBuildCall(context.llvmBuilder, descriptor.llvmFunction.getLlvmValue(), rargs[0], args.size, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
fun bitcast(type: LLVMOpaqueType?, value: LLVMOpaqueValue, variable: String) = LLVMBuildBitCast(context.llvmBuilder, value, type, variable)
|
||||
|
||||
/* to class descriptor */
|
||||
fun classType(descriptor: ClassDescriptor):LLVMOpaqueType = LLVMGetTypeByName(context.llvmModule, descriptor.symbolName)!!
|
||||
fun typeInfoType(descriptor: ClassDescriptor): LLVMOpaqueType? = descriptor.llvmTypeInfoPtr.getLlvmType()
|
||||
fun typeInfoValue(descriptor: ClassDescriptor): LLVMOpaqueValue? = descriptor.llvmTypeInfoPtr.getLlvmValue()
|
||||
|
||||
fun superCall(result:String, descriptor:ClassConstructorDescriptor, args:MutableList<LLVMOpaqueValue?> ):LLVMOpaqueValue? {
|
||||
val tmp = load(thisVariable(), tmpVariable())
|
||||
var rargs:MutableList<LLVMOpaqueValue?>? = null
|
||||
if (args.size != 0)
|
||||
rargs = mutableListOf<LLVMOpaqueValue?>(tmp, *args.toTypedArray())
|
||||
else
|
||||
rargs = mutableListOf<LLVMOpaqueValue?>(tmp)
|
||||
return call(descriptor, rargs, result)
|
||||
}
|
||||
|
||||
fun thisVariable() = variable("this")!!
|
||||
fun param(fn: FunctionDescriptor?, i: Int): LLVMOpaqueValue? = LLVMGetParam(fn!!.llvmFunction.getLlvmValue(), i)
|
||||
|
||||
fun indexInClass(p:PropertyDescriptor):Int = currentClass!!.fields.indexOf(p)
|
||||
}
|
||||
|
||||
|
||||
|
||||
+76
-15
@@ -1,15 +1,16 @@
|
||||
package org.jetbrains.kotlin.backend.native.llvm
|
||||
|
||||
import kotlin_native.interop.*
|
||||
import llvm.*
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.LazyClassReceiverParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||
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.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
|
||||
|
||||
fun emitLLVM(module: IrModuleFragment, runtimeFile: String, outFile: String) {
|
||||
@@ -20,8 +21,9 @@ 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)
|
||||
module.acceptVoid(RTTIGeneratorVisitor(context))
|
||||
context.runtime.importRuntime(llvmModule)
|
||||
module.acceptVoid(CodeGeneratorVisitor(context))
|
||||
LLVMWriteBitcodeToFile(llvmModule, outFile)
|
||||
}
|
||||
|
||||
@@ -46,7 +48,31 @@ internal class RTTIGeneratorVisitor(context: Context) : IrElementVisitorVoid {
|
||||
}
|
||||
|
||||
internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid {
|
||||
|
||||
val generator = CodeGenerator(context)
|
||||
|
||||
override fun visitConstructor(declaration: IrConstructor) {
|
||||
generator.initFunction(declaration)
|
||||
val thisValue = generator.variable("this")
|
||||
//super.visitConstructor(declaration)
|
||||
/**
|
||||
* %this = alloca i8*
|
||||
* store i8* %0, i8** %this <- prolog
|
||||
*
|
||||
* %tmp0 = load i8*, i8** %this <- epilog
|
||||
* ret i8* %tmp0
|
||||
*/
|
||||
LLVMBuildRet(context.llvmBuilder, generator.load(thisValue!!, generator.tmpVariable()))
|
||||
}
|
||||
|
||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall) {
|
||||
evaluateCall(generator.tmpVariable(), expression)
|
||||
}
|
||||
|
||||
override fun visitConstructor(declaration: IrConstructor, data: Nothing?) {
|
||||
super.visitConstructor(declaration, data)
|
||||
}
|
||||
|
||||
override fun visitFunction(declaration: IrFunction) {
|
||||
generator.function(declaration)
|
||||
declaration.acceptChildrenVoid(this)
|
||||
@@ -73,7 +99,30 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
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)
|
||||
is IrGetValue -> {
|
||||
when (value.descriptor) {
|
||||
is LocalVariableDescriptor, is ValueParameterDescriptor -> {
|
||||
val variable = generator.variable(value.descriptor.name.asString())
|
||||
return generator.load(variable!!, tmpVariableName)
|
||||
}
|
||||
is LazyClassReceiverParameterDescriptor -> {
|
||||
TODO()
|
||||
}
|
||||
else -> {
|
||||
TODO()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
is IrGetField -> {
|
||||
if (value.descriptor.dispatchReceiverParameter != null) {
|
||||
val thisPtr = generator.load(generator.thisVariable(), generator.tmpVariable())
|
||||
val typedPtr = generator.bitcast(pointerType(generator.classType(generator.currentClass!!)), thisPtr, generator.tmpVariable())
|
||||
val fieldPtr = LLVMBuildStructGEP(generator.context.llvmBuilder, typedPtr, generator.indexInClass(value.descriptor), generator.tmpVariable())
|
||||
return generator.load(fieldPtr!!, generator.tmpVariable())
|
||||
}
|
||||
TODO()
|
||||
}
|
||||
null -> return null
|
||||
else -> {
|
||||
TODO()
|
||||
@@ -81,11 +130,8 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
}
|
||||
}
|
||||
|
||||
private fun evaluateCall(tmpVariableName: String, value: IrCall?): LLVMOpaqueValue? {
|
||||
/* TODO: should we count on receiver?
|
||||
* val tmp = tmpVar()
|
||||
* val lhs = evaluateExpression(tmp, value.dispatchReceiver!!)
|
||||
*/
|
||||
|
||||
private fun evaluateCall(tmpVariableName: String, value: IrMemberAccessExpression?): LLVMOpaqueValue? {
|
||||
val args = mutableListOf<LLVMOpaqueValue?>()
|
||||
value!!.acceptChildrenVoid(object:IrElementVisitorVoid{
|
||||
override fun visitElement(element: IrElement) {
|
||||
@@ -93,8 +139,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
args.add(evaluateExpression(tmp, element as IrExpression))
|
||||
}
|
||||
})
|
||||
when (value.descriptor) {
|
||||
is FunctionDescriptor -> return evaluateFunctionCall(tmpVariableName, value, args)
|
||||
when {
|
||||
value is IrDelegatingConstructorCall -> return generator.superCall(tmpVariableName, value.descriptor, args)
|
||||
value.descriptor is FunctionDescriptor -> return evaluateFunctionCall(tmpVariableName, value as IrCall, args)
|
||||
else -> {
|
||||
TODO()
|
||||
}
|
||||
@@ -104,7 +151,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
}
|
||||
|
||||
private fun evaluateSimpleFunctionCall(tmpVariableName: String, value: IrCall, args: MutableList<LLVMOpaqueValue?>): LLVMOpaqueValue? {
|
||||
return generator.call(value.descriptor as org.jetbrains.kotlin.descriptors.FunctionDescriptor, args, tmpVariableName)
|
||||
return generator.call(value.descriptor as FunctionDescriptor, args, tmpVariableName)
|
||||
}
|
||||
|
||||
|
||||
@@ -112,12 +159,26 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
val descriptor:FunctionDescriptor = callee.descriptor as FunctionDescriptor
|
||||
when {
|
||||
descriptor.isOperator -> return evaluateOperatorCall(tmpVariableName, callee, args)
|
||||
descriptor is ClassConstructorDescriptor -> return evaluateConstructorCall(tmpVariableName, callee, args)
|
||||
else -> {
|
||||
return evaluateSimpleFunctionCall(tmpVariableName, callee, args)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun evaluateConstructorCall(variableName: String, callee: IrCall, args: MutableList<LLVMOpaqueValue?>): LLVMOpaqueValue? {
|
||||
memScoped {
|
||||
val params = allocNativeArrayOf(LLVMOpaqueValue, generator.typeInfoValue((callee.descriptor as ClassConstructorDescriptor).containingDeclaration), Int32(1).getLlvmValue())
|
||||
val thisValue = LLVMBuildCall(context.llvmBuilder, context.runtime.allocInstanceFunction, params[0], 2, variableName)
|
||||
|
||||
|
||||
val constructorParams: MutableList<LLVMOpaqueValue?> = mutableListOf()
|
||||
constructorParams += thisValue
|
||||
constructorParams += args
|
||||
return generator.call(callee.descriptor as FunctionDescriptor, constructorParams, variableName)
|
||||
}
|
||||
}
|
||||
|
||||
private fun evaluateOperatorCall(tmpVariableName: String, callee: IrCall, args: MutableList<LLVMOpaqueValue?>): LLVMOpaqueValue {
|
||||
when (callee!!.origin) {
|
||||
IrStatementOrigin.PLUS -> return generator.plus(args[0]!!, args[1]!!, tmpVariableName)
|
||||
|
||||
+10
-4
@@ -2,6 +2,7 @@ package org.jetbrains.kotlin.backend.native.llvm
|
||||
|
||||
import kotlin_native.interop.*
|
||||
import llvm.*
|
||||
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.utils.singletonOrEmptyList
|
||||
|
||||
@@ -75,12 +76,17 @@ internal fun getLlvmFunctionType(function: FunctionDescriptor): LLVMOpaqueType?
|
||||
function.extensionReceiverParameter.singletonOrEmptyList() +
|
||||
function.valueParameters
|
||||
|
||||
val paramTypes = params.map { getLLVMType(it.type) }.toTypedArray()
|
||||
if (paramTypes.size == 0) return LLVMFunctionType(returnType, null, 0, 0)
|
||||
var extraParam = listOf<LLVMOpaqueType?>()
|
||||
if (function is ClassConstructorDescriptor) {
|
||||
extraParam += pointerType(LLVMInt8Type())
|
||||
}
|
||||
val paramTypes:List<LLVMOpaqueType?> = params.map { getLLVMType(it.type) }
|
||||
extraParam += paramTypes
|
||||
|
||||
if (extraParam.size == 0) return LLVMFunctionType(returnType, null, 0, 0)
|
||||
memScoped {
|
||||
val paramTypesPtr = allocNativeArrayOf(LLVMOpaqueType, *paramTypes)[0]
|
||||
return LLVMFunctionType(returnType, paramTypesPtr, paramTypes.size, 0)
|
||||
val paramTypesPtr = mallocNativeArrayOf(LLVMOpaqueType, *extraParam.toTypedArray())[0] // TODO: dispose
|
||||
return LLVMFunctionType(returnType, paramTypesPtr, extraParam.size, 0)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
@@ -1,6 +1,7 @@
|
||||
package org.jetbrains.kotlin.backend.native.llvm
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind.*
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.constants.StringValue
|
||||
@@ -21,5 +22,12 @@ internal val FunctionDescriptor.symbolName: String
|
||||
return "kfun:" + this.fqNameSafe.toString() // FIXME: add signature
|
||||
}
|
||||
|
||||
internal val ClassDescriptor.symbolName: String
|
||||
get() = when (this.kind) {
|
||||
CLASS -> "kclass:"
|
||||
INTERFACE -> "kinf:"
|
||||
else -> TODO("fixme")
|
||||
} + fqNameSafe
|
||||
|
||||
internal val ClassDescriptor.typeInfoSymbolName: String
|
||||
get() = "ktype:" + this.fqNameSafe.toString()
|
||||
+9
@@ -34,6 +34,15 @@ class Runtime(private val bitcodeFile: String) {
|
||||
val fieldTableRecordType = LLVMGetTypeByName(llvmModule, "struct.FieldTableRecord")
|
||||
val methodTableRecordType = LLVMGetTypeByName(llvmModule, "struct.MethodTableRecord")
|
||||
val globalhHashType = LLVMGetTypeByName(llvmModule, "struct.GlobalHash")
|
||||
val allocInstanceFunction = LLVMGetNamedFunction(llvmModule, "AllocInstance")
|
||||
|
||||
fun importRuntime(module: LLVMOpaqueModule) {
|
||||
memScoped {
|
||||
val params = allocNativeArrayOf(LLVMOpaqueType, pointerType(typeInfoType), LLVMInt32Type())
|
||||
val functionAllocInstanceType = LLVMFunctionType(pointerType(LLVMInt8Type()),params[0], 2, 0)
|
||||
LLVMAddFunction(module, "AllocInstance", functionAllocInstanceType)
|
||||
}
|
||||
}
|
||||
|
||||
val target = LLVMGetTarget(llvmModule)!!.asCString().toString()
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
TESTS := sum \
|
||||
sum_foo_bar \
|
||||
arithmetic
|
||||
arithmetic \
|
||||
initialization
|
||||
|
||||
BIN_TESTS=$(foreach t, ${TESTS},${t}_test)
|
||||
|
||||
VPATH=codegen/function:${TOP}/runtime/build
|
||||
VPATH=codegen/function:codegen/object:${TOP}/runtime/build
|
||||
|
||||
LLC=llc-mp-3.8
|
||||
CC=clang-mp-3.8
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
extern void *resolve_symbol(const char*);
|
||||
|
||||
int
|
||||
run_test() {
|
||||
int (*foo)(int, int) = resolve_symbol("kfun:foo");
|
||||
|
||||
if (foo(2, 3) != 2) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
open class A(val a:Int, val b:Int)
|
||||
|
||||
open class B(val c:Int, d:Int):A(c, d)
|
||||
|
||||
//class C():B(42)
|
||||
|
||||
fun foo(i:Int, j:Int):Int {
|
||||
val b = B(i, j)
|
||||
return b.c
|
||||
}
|
||||
Reference in New Issue
Block a user