object initialization and properties access

This commit is contained in:
Vasily Levchenko
2016-10-21 05:32:30 +03:00
parent 0523505354
commit 09ee81b7a3
4 changed files with 170 additions and 32 deletions
@@ -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)
}
@@ -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)
@@ -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)
}
}
@@ -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()