backend: rework variables
* use descriptor instead of name to refer to variables * bind variables to scopes * begin refactoring mapping between LLVM and IR parameters
This commit is contained in:
committed by
SvyatoslavScherbina
parent
e131622ef7
commit
a65aef0198
+17
-4
@@ -1,9 +1,6 @@
|
||||
package org.jetbrains.kotlin.backend.konan
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.resolve.OverridingUtil
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.*
|
||||
|
||||
@@ -64,3 +61,19 @@ internal val ClassDescriptor.isArray: Boolean
|
||||
|
||||
internal val ClassDescriptor.isInterface: Boolean
|
||||
get() = (this.kind == ClassKind.INTERFACE)
|
||||
|
||||
internal val CallableDescriptor.allValueParameters: List<ParameterDescriptor>
|
||||
get() {
|
||||
val constructorReceiver = if (this is ConstructorDescriptor) {
|
||||
this.constructedClass.thisAsReceiverParameter
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
val receivers = listOf(
|
||||
constructorReceiver,
|
||||
this.dispatchReceiverParameter,
|
||||
this.extensionReceiverParameter).filterNotNull()
|
||||
|
||||
return receivers + this.valueParameters
|
||||
}
|
||||
+5
-39
@@ -25,28 +25,6 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
prologueBb = LLVMAppendBasicBlock(fn, "prologue")
|
||||
entryBb = LLVMAppendBasicBlock(fn, "entry")
|
||||
positionAtEnd(entryBb!!)
|
||||
|
||||
function2variables.put(declaration.descriptor, mutableMapOf())
|
||||
|
||||
var indexOffset = 0
|
||||
if (descriptor is ClassConstructorDescriptor
|
||||
|| descriptor.dispatchReceiverParameter != null
|
||||
|| descriptor.extensionReceiverParameter != null) {
|
||||
indexOffset = 1;
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
if (descriptor.usedAnnotation) {
|
||||
context.usedFunctions.add(fn!!)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,9 +38,6 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
|
||||
fun newVar():String = currentFunction!!.tmpVariable()
|
||||
|
||||
val variablesGlobal = mapOf<String, LLVMValueRef?>()
|
||||
fun variable(varName:String): LLVMValueRef? = currentFunction!!.variable(varName)
|
||||
|
||||
private var variableIndex:Int = 0
|
||||
private var FunctionDescriptor.tmpVariableIndex: Int
|
||||
get() = variableIndex
|
||||
@@ -70,20 +45,9 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
|
||||
fun FunctionDescriptor.tmpVariable():String = "tmp_${tmpVariableIndex++}"
|
||||
|
||||
fun registerVariable(varName: String, value: LLVMValueRef) = currentFunction!!.registerVariable(varName, value)
|
||||
|
||||
val function2variables = mutableMapOf<FunctionDescriptor, MutableMap<String, LLVMValueRef?>>()
|
||||
|
||||
private var prologueBb: LLVMBasicBlockRef? = null
|
||||
private var entryBb: LLVMBasicBlockRef? = null
|
||||
|
||||
val FunctionDescriptor.variables: MutableMap<String, LLVMValueRef?>
|
||||
get() = this@CodeGenerator.function2variables[this]!!
|
||||
|
||||
|
||||
fun FunctionDescriptor.registerVariable(varName: String, value: LLVMValueRef?) = variables.put(varName, value)
|
||||
private fun FunctionDescriptor.variable(varName: String): LLVMValueRef? = variables[varName]
|
||||
|
||||
fun plus (arg0: LLVMValueRef, arg1: LLVMValueRef, result: String): LLVMValueRef = LLVMBuildAdd (builder, arg0, arg1, result)!!
|
||||
fun mul (arg0: LLVMValueRef, arg1: LLVMValueRef, result: String): LLVMValueRef = LLVMBuildMul (builder, arg0, arg1, result)!!
|
||||
fun minus (arg0: LLVMValueRef, arg1: LLVMValueRef, result: String): LLVMValueRef = LLVMBuildSub (builder, arg0, arg1, result)!!
|
||||
@@ -161,9 +125,11 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
fun typeInfoType(descriptor: ClassDescriptor): LLVMTypeRef = descriptor.llvmTypeInfoPtr.getLlvmType()
|
||||
fun typeInfoValue(descriptor: ClassDescriptor): LLVMValueRef = descriptor.llvmTypeInfoPtr.getLlvmValue()!!
|
||||
|
||||
fun thisVariable() = LLVMGetParam(currentFunction!!.llvmFunction.getLlvmValue(), 0)!!
|
||||
|
||||
fun param(fn: FunctionDescriptor?, i: Int): LLVMValueRef? = LLVMGetParam(fn!!.llvmFunction.getLlvmValue(), i)
|
||||
fun param(fn: FunctionDescriptor, i: Int): LLVMValueRef {
|
||||
assert (i >= 0 && i < countParams(fn))
|
||||
return LLVMGetParam(fn.llvmFunction.getLlvmValue(), i)!!
|
||||
}
|
||||
fun countParams(fn: FunctionDescriptor) = LLVMCountParams(fn.llvmFunction.getLlvmValue())
|
||||
|
||||
fun indexInClass(p:PropertyDescriptor):Int = (p.containingDeclaration as ClassDescriptor).fields.indexOf(p)
|
||||
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ internal fun ContextUtils.getLLVMType(type: KotlinType): LLVMTypeRef {
|
||||
KotlinBuiltIns.isUnit(type) -> LLVMVoidType() // TODO: handle Unit parameter case
|
||||
KotlinBuiltIns.isFloat(type) -> LLVMFloatType()
|
||||
KotlinBuiltIns.isDouble(type) -> LLVMDoubleType()
|
||||
KotlinBuiltIns.isArray(type) -> this.kArrayHeaderPtr
|
||||
KotlinBuiltIns.isArray(type) || KotlinBuiltIns.isPrimitiveArray(type)-> this.kArrayHeaderPtr
|
||||
!KotlinBuiltIns.isPrimitiveType(type) -> this.kObjHeaderPtr
|
||||
else -> throw NotImplementedError(type.toString() + " is not supported")
|
||||
}!!
|
||||
|
||||
+245
-105
@@ -109,25 +109,50 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
fun genCall(function: LLVMValueRef, args: List<LLVMValueRef>, result: String?): LLVMValueRef
|
||||
|
||||
fun genThrow(exception: LLVMValueRef)
|
||||
|
||||
/**
|
||||
* Declares the variable.
|
||||
* @return pointer to the declared variable.
|
||||
*/
|
||||
fun genDeclareVariable(descriptor: ValueDescriptor): LLVMValueRef
|
||||
|
||||
/**
|
||||
* @return pointer to the variable declared before, or `null` if no such variable has been declared yet.
|
||||
*/
|
||||
fun getDeclaredVariable(descriptor: ValueDescriptor): LLVMValueRef?
|
||||
|
||||
/**
|
||||
* Generates the code to obtain a value available in this context.
|
||||
*
|
||||
* @return the requested value
|
||||
*/
|
||||
fun genGetValue(descriptor: ValueDescriptor, result: String = ""): LLVMValueRef
|
||||
}
|
||||
|
||||
/**
|
||||
* Fake [CodeContext] that doesn't support any operation.
|
||||
*
|
||||
* During function code generation [FunctionScope] should be set up.
|
||||
* During function code generation [FunctionScope] should be set up. See [generatingFunctionCode].
|
||||
*/
|
||||
private object TopLevelCodeContext : CodeContext {
|
||||
|
||||
override fun genReturn(target: CallableDescriptor, value: LLVMValueRef?) = throw UnsupportedOperationException()
|
||||
private fun unsupported(any: Any? = null): Nothing = throw UnsupportedOperationException(any?.toString() ?: "")
|
||||
|
||||
override fun genBreak(loop: IrLoop) = throw UnsupportedOperationException()
|
||||
override fun genReturn(target: CallableDescriptor, value: LLVMValueRef?) = unsupported(target)
|
||||
|
||||
override fun genContinue(loop: IrLoop) = throw UnsupportedOperationException()
|
||||
override fun genBreak(loop: IrLoop) = unsupported(loop)
|
||||
|
||||
override fun genCall(function: LLVMValueRef, args: List<LLVMValueRef>, result: String?)
|
||||
= throw UnsupportedOperationException()
|
||||
override fun genContinue(loop: IrLoop) = unsupported(loop)
|
||||
|
||||
override fun genThrow(exception: LLVMValueRef) = throw UnsupportedOperationException()
|
||||
override fun genCall(function: LLVMValueRef, args: List<LLVMValueRef>, result: String?) = unsupported(function)
|
||||
|
||||
override fun genThrow(exception: LLVMValueRef) = unsupported()
|
||||
|
||||
override fun genDeclareVariable(descriptor: ValueDescriptor) = unsupported(descriptor)
|
||||
|
||||
override fun getDeclaredVariable(descriptor: ValueDescriptor) = null
|
||||
|
||||
override fun genGetValue(descriptor: ValueDescriptor, result: String) = unsupported(descriptor)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -234,9 +259,11 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
|
||||
codegen.prologue(constructorDeclaration)
|
||||
val constructorDescriptor = constructorDeclaration.descriptor
|
||||
val classDescriptor = DescriptorUtils.getContainingClass(constructorDescriptor)
|
||||
val classDescriptor = constructorDescriptor.constructedClass
|
||||
|
||||
using(FunctionScope(constructorDeclaration)) {
|
||||
generatingFunctionCode(constructorDeclaration) {
|
||||
|
||||
val thisPtr = currentCodeContext.genGetValue(classDescriptor.thisAsReceiverParameter, "this")
|
||||
|
||||
/**
|
||||
* IR for kotlin.Any is:
|
||||
@@ -251,7 +278,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
constructorDeclaration.acceptChildrenVoid(this)
|
||||
|
||||
if (constructorDescriptor.isPrimary && !DescriptorUtils.isCompanionObject(constructorDescriptor.constructedClass)) {
|
||||
val irOfCurrentClass = context.moduleIndex.classes[classDescriptor!!.classId]
|
||||
val irOfCurrentClass = context.moduleIndex.classes[classDescriptor.classId]
|
||||
irOfCurrentClass!!.acceptChildrenVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
@@ -260,16 +287,11 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
override fun visitField(fieldDeclaration: IrField) {
|
||||
|
||||
val fieldDescriptor = fieldDeclaration.descriptor
|
||||
val fieldPtr = fieldPtrOfClass(codegen.thisVariable(), fieldDescriptor)
|
||||
var value: LLVMValueRef? = null
|
||||
if (constructorDescriptor.valueParameters.any { it.name == fieldDescriptor.name }) {
|
||||
val variable = codegen.variable(fieldDescriptor.name.asString())
|
||||
value = codegen.load(variable!!, codegen.newVar())
|
||||
} else {
|
||||
value = evaluateExpression(codegen.newVar(), fieldDeclaration.initializer)
|
||||
fieldDeclaration.initializer?.let {
|
||||
val value = evaluateExpression(codegen.newVar(), it)!!
|
||||
val fieldPtr = fieldPtrOfClass(thisPtr, fieldDescriptor)
|
||||
codegen.store(value, fieldPtr)
|
||||
}
|
||||
if (value != null)
|
||||
codegen.store(value, fieldPtr!!)
|
||||
}
|
||||
|
||||
override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer) {
|
||||
@@ -285,14 +307,10 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
codegen.ret(thisPtr)
|
||||
}
|
||||
|
||||
if (KotlinBuiltIns.isArray(constructorDescriptor.returnType)) {
|
||||
val arrayPtr = codegen.bitcast(codegen.kArrayHeaderPtr, codegen.thisVariable(), codegen.newVar())
|
||||
codegen.ret(arrayPtr)
|
||||
} else {
|
||||
codegen.ret(codegen.thisVariable())
|
||||
}
|
||||
codegen.epilogue(constructorDeclaration)
|
||||
logger.log("visitConstructor : ${ir2string(constructorDeclaration)}")
|
||||
}
|
||||
@@ -350,9 +368,48 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
/**
|
||||
* The [CodeContext] enclosing the entire function body.
|
||||
* The scope of variable visibility.
|
||||
*/
|
||||
private inner class FunctionScope(val declaration: IrFunction) : InnerScopeImpl() {
|
||||
private open inner class VariableScope : InnerScopeImpl() {
|
||||
|
||||
private val variables = mutableMapOf<ValueDescriptor, LLVMValueRef>()
|
||||
|
||||
override fun genDeclareVariable(descriptor: ValueDescriptor): LLVMValueRef {
|
||||
// Check that the variable is not declared yet:
|
||||
assert (this.getDeclaredVariable(descriptor) == null)
|
||||
|
||||
val res = codegen.alloca(descriptor.type, descriptor.name.asString())
|
||||
|
||||
val previous = variables.put(descriptor, res)
|
||||
assert (previous == null)
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
override fun getDeclaredVariable(descriptor: ValueDescriptor): LLVMValueRef? {
|
||||
return variables[descriptor] ?: super.getDeclaredVariable(descriptor)
|
||||
}
|
||||
|
||||
override fun genGetValue(descriptor: ValueDescriptor, result: String): LLVMValueRef {
|
||||
val variable = getDeclaredVariable(descriptor)
|
||||
if (variable != null) {
|
||||
return codegen.load(variable, result)
|
||||
} else {
|
||||
return super.genGetValue(descriptor, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The [CodeContext] enclosing the entire function body.
|
||||
*
|
||||
* Note: the function in Kotlin may be declared without having any variable scope,
|
||||
* i.e. [FunctionScope] probably shouldn't be a [VariableScope].
|
||||
* However, function parameters are currently handled as variables,
|
||||
* which need to be declared at function scope.
|
||||
*/
|
||||
private inner class FunctionScope(val declaration: IrFunction) : VariableScope() {
|
||||
|
||||
override fun genReturn(target: CallableDescriptor, value: LLVMValueRef?) {
|
||||
if (target == declaration.descriptor) {
|
||||
codegen.ret(value)
|
||||
@@ -372,6 +429,34 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers function parameters as variables in current [CodeContext].
|
||||
*
|
||||
* Note: it is possible to generate access to a function parameter without any variables,
|
||||
* however variables are named and thus the resulting bitcode can be more readable.
|
||||
*/
|
||||
private fun registerParameters(descriptor: FunctionDescriptor) {
|
||||
val paramDescriptors = descriptor.allValueParameters
|
||||
|
||||
assert(paramDescriptors.size == codegen.countParams(descriptor))
|
||||
|
||||
paramDescriptors.forEachIndexed { i, paramDescriptor ->
|
||||
val param = codegen.param(descriptor, i)
|
||||
assert(codegen.getLLVMType(paramDescriptor.type) == LLVMTypeOf(param))
|
||||
createVariable(paramDescriptor, param)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes [block] supposed to generate function body code having [currentCodeContext] set up correctly.
|
||||
*/
|
||||
private inline fun <R> generatingFunctionCode(declaration: IrFunction, block: () -> R): R {
|
||||
using(FunctionScope(declaration)) {
|
||||
registerParameters(declaration.descriptor)
|
||||
return block()
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitFunction(declaration: IrFunction) {
|
||||
logger.log("visitFunction : ${ir2string(declaration)}")
|
||||
if (declaration.descriptor.modality == Modality.ABSTRACT || declaration.body == null)
|
||||
@@ -380,7 +465,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
codegen.prologue(declaration)
|
||||
metadator.function(declaration)
|
||||
|
||||
using(FunctionScope(declaration)) {
|
||||
generatingFunctionCode(declaration) {
|
||||
declaration.acceptChildrenVoid(this)
|
||||
}
|
||||
codegen.epilogue(declaration)
|
||||
@@ -411,23 +496,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
|
||||
override fun visitVariable(declaration: IrVariable) {
|
||||
logger.log("visitVariable : ${ir2string(declaration)}")
|
||||
val variableName = declaration.descriptor.name.asString()
|
||||
val variableType = declaration.descriptor.type
|
||||
val value = evaluateExpression("", declaration.initializer) // Generate initialization code.
|
||||
createVariable(declaration.descriptor, value) // Create and initialize variable.
|
||||
}
|
||||
|
||||
private fun createVariable(descriptor: VariableDescriptor, value: LLVMValueRef? = null): LLVMValueRef {
|
||||
val name = descriptor.name.asString()
|
||||
val type = descriptor.type
|
||||
|
||||
val newVariable = codegen.alloca(type, name) // Create LLVM variable.
|
||||
codegen.registerVariable(name, newVariable) // Map variableName -> LLVM variable.
|
||||
|
||||
if (value != null) {
|
||||
codegen.store(value, newVariable)
|
||||
}
|
||||
return newVariable
|
||||
evaluateVariable(declaration)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
@@ -441,8 +510,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
|
||||
override fun visitSetVariable(expression: IrSetVariable) {
|
||||
logger.log("visitSetVariable : ${ir2string(expression)}")
|
||||
val value = evaluateExpression(codegen.newVar(), expression.value)
|
||||
codegen.store(value!!, codegen.variable(expression.descriptor.name.asString())!!)
|
||||
evaluateSetVariable(expression)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
@@ -526,7 +594,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
}
|
||||
|
||||
private fun evaluateExpressionAndJump(expression: IrExpression, destination: ContinuationBlock) {
|
||||
val result = evaluateExpression("", expression)
|
||||
val result = evaluateExpression("res", expression)
|
||||
|
||||
if (!codegen.isAfterTerminator()) {
|
||||
jump(destination, result)
|
||||
@@ -866,7 +934,10 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
if (!KotlinBuiltIns.isNothing(expression.type)) // If "when" has "exit".
|
||||
bbExit = codegen.basicBlock() // Create basic block to process "exit".
|
||||
|
||||
// TODO: using empty name is a way to declare unnamed (yet accessible) value in LLVM;
|
||||
// so it doesn't seem to be a good idea to treat empty name as a hint to ignore the result.
|
||||
val isForceUnit = tmpVariableName.isEmpty()
|
||||
|
||||
val isUnit = KotlinBuiltIns.isUnit(expression.type) || isForceUnit
|
||||
val isNothing = KotlinBuiltIns.isNothing(expression.type)
|
||||
val neitherUnitNorNothing = !isNothing && !isUnit
|
||||
@@ -896,43 +967,36 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
|
||||
private fun evaluateGetValue(tmpVariableName: String, value: IrGetValue): LLVMValueRef {
|
||||
logger.log("evaluateGetValue : $tmpVariableName = ${ir2string(value)}")
|
||||
when (value.descriptor) {
|
||||
is LocalVariableDescriptor,
|
||||
is IrTemporaryVariableDescriptor,
|
||||
is ValueParameterDescriptor -> {
|
||||
val variable = codegen.variable(value.descriptor.name.asString())
|
||||
return codegen.load(variable!!, tmpVariableName)
|
||||
}
|
||||
is LazyClassReceiverParameterDescriptor,
|
||||
is ReceiverParameterDescriptor -> {
|
||||
if (value.descriptor.name.asString() == "<this>") {
|
||||
return codegen.thisVariable()
|
||||
}
|
||||
TODO("${ir2string(value)}")
|
||||
}
|
||||
else -> {
|
||||
TODO("${ir2string(value)}")
|
||||
}
|
||||
}
|
||||
return currentCodeContext.genGetValue(value.descriptor, tmpVariableName)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun evaluateSetVariable(value: IrSetVariable): LLVMValueRef {
|
||||
private fun evaluateSetVariable(value: IrSetVariable): LLVMValueRef? {
|
||||
logger.log("evaluateSetVariable : ${ir2string(value)}")
|
||||
val ret = evaluateExpression(codegen.newVar(), value.value)
|
||||
return codegen.store(ret!!, codegen.variable(value.descriptor.name.asString())!!)
|
||||
val ret = evaluateExpression(codegen.newVar(), value.value)!!
|
||||
val variable = currentCodeContext.getDeclaredVariable(value.descriptor)!!
|
||||
codegen.store(ret, variable)
|
||||
return null
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun evaluateVariable(value: IrVariable): LLVMValueRef {
|
||||
private fun evaluateVariable(value: IrVariable): LLVMValueRef? {
|
||||
logger.log("evaluateVariable : ${ir2string(value)}")
|
||||
val ret = evaluateExpression(codegen.newVar(), value.initializer)
|
||||
val variableName = value.descriptor.name.asString()
|
||||
val variable = codegen.alloca(LLVMTypeOf(ret), variableName)
|
||||
codegen.registerVariable(variableName, variable)
|
||||
return codegen.store(ret!!, variable)
|
||||
createVariable(value.descriptor, ret)
|
||||
return null
|
||||
}
|
||||
|
||||
private fun createVariable(descriptor: ValueDescriptor, value: LLVMValueRef? = null): LLVMValueRef {
|
||||
|
||||
val newVariable = currentCodeContext.genDeclareVariable(descriptor)
|
||||
|
||||
if (value != null) {
|
||||
codegen.store(value, newVariable)
|
||||
}
|
||||
return newVariable
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
@@ -953,10 +1017,12 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun evaluateSafeCast(tmpVariableName: String, value: IrTypeOperatorCall): LLVMValueRef? {
|
||||
val bbTrue = codegen.basicBlock()!!
|
||||
val bbFalse = codegen.basicBlock()!!
|
||||
val bbExit = codegen.basicBlock()!!
|
||||
val result = codegen.alloca(codegen.getLLVMType(value.type), codegen.newVar())
|
||||
val bbTrue = codegen.basicBlock()
|
||||
val bbFalse = codegen.basicBlock()
|
||||
val bbExit = codegen.basicBlock()
|
||||
|
||||
val resultLlvmType = codegen.getLLVMType(value.type)
|
||||
val result = codegen.alloca(resultLlvmType, codegen.newVar())
|
||||
|
||||
val condition = evaluateInstanceOf(codegen.newVar(), value)
|
||||
codegen.condBr(condition, bbTrue, bbFalse)
|
||||
@@ -967,8 +1033,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
codegen.br(bbExit)
|
||||
|
||||
codegen.positionAtEnd(bbFalse)
|
||||
val nullResult = if (KotlinBuiltIns.isArray(value.type)) codegen.kNullArrayHeaderPtr
|
||||
else codegen.kNullObjHeaderPtr
|
||||
val nullResult = LLVMConstNull(resultLlvmType)!!
|
||||
codegen.store(nullResult, result)
|
||||
codegen.br(bbExit)
|
||||
|
||||
@@ -1037,8 +1102,8 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
private fun evaluateGetField(value: IrGetField): LLVMValueRef {
|
||||
logger.log("evaluateGetField : ${ir2string(value)}")
|
||||
if (value.descriptor.dispatchReceiverParameter != null) {
|
||||
val thisPtr = codegen.thisVariable()
|
||||
return codegen.load(fieldPtrOfClass(thisPtr, value.descriptor)!!, codegen.newVar())
|
||||
val thisPtr = instanceFieldAccessReceiver(value)
|
||||
return codegen.load(fieldPtrOfClass(thisPtr, value.descriptor), codegen.newVar())
|
||||
}
|
||||
else {
|
||||
val ptr = LLVMGetNamedGlobal(context.llvmModule, value.descriptor.symbolName)!!
|
||||
@@ -1046,19 +1111,31 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
}
|
||||
}
|
||||
|
||||
private fun instanceFieldAccessReceiver(expression: IrFieldAccessExpression): LLVMValueRef {
|
||||
val receiverExpression = expression.receiver
|
||||
if (receiverExpression != null) {
|
||||
return evaluateExpression(codegen.newVar(), receiverExpression)!!
|
||||
} else {
|
||||
val classDescriptor = expression.descriptor.containingDeclaration as ClassDescriptor
|
||||
return currentCodeContext.genGetValue(classDescriptor.thisAsReceiverParameter)
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun evaluateSetField(value: IrSetField): LLVMValueRef {
|
||||
private fun evaluateSetField(value: IrSetField): LLVMValueRef? {
|
||||
logger.log("evaluateSetField : ${ir2string(value)}")
|
||||
val valueToAssign = evaluateExpression(codegen.newVar(), value.value)!!
|
||||
if (value.descriptor.dispatchReceiverParameter != null) {
|
||||
val thisPtr = codegen.thisVariable()
|
||||
return codegen.store(valueToAssign, fieldPtrOfClass(thisPtr, value.descriptor)!!)
|
||||
val thisPtr = instanceFieldAccessReceiver(value)
|
||||
codegen.store(valueToAssign, fieldPtrOfClass(thisPtr, value.descriptor))
|
||||
}
|
||||
else {
|
||||
val globalValue = LLVMGetNamedGlobal(context.llvmModule, value.descriptor.symbolName)
|
||||
return codegen.store(valueToAssign, globalValue!!)
|
||||
codegen.store(valueToAssign, globalValue!!)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
@@ -1095,7 +1172,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
}
|
||||
|
||||
*/
|
||||
private fun fieldPtrOfClass(thisPtr: LLVMValueRef, value: PropertyDescriptor): LLVMValueRef? {
|
||||
private fun fieldPtrOfClass(thisPtr: LLVMValueRef, value: PropertyDescriptor): LLVMValueRef {
|
||||
val objHeaderPtr = codegen.bitcast(codegen.kObjHeaderPtr, thisPtr, codegen.newVar())
|
||||
val typePtr = pointerType(codegen.classType(value.containingDeclaration as ClassDescriptor))
|
||||
memScoped {
|
||||
@@ -1103,7 +1180,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
val objectPtr = LLVMBuildGEP(codegen.builder, objHeaderPtr, args[0].ptr, 1, codegen.newVar())
|
||||
val typedObjPtr = codegen.bitcast(typePtr, objectPtr!!, codegen.newVar())
|
||||
val fieldPtr = LLVMBuildStructGEP(codegen.builder, typedObjPtr, codegen.indexInClass(value), codegen.newVar())
|
||||
return fieldPtr
|
||||
return fieldPtr!!
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1157,26 +1234,32 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
|
||||
private fun evaluateBlock(tmpVariableName: String, value: IrStatementContainer): LLVMValueRef? {
|
||||
logger.log("evaluateBlock : ${value.statements.forEach { ir2string(it) }}")
|
||||
value.statements.dropLast(1).forEach {
|
||||
evaluateExpression(codegen.newVar(), it)
|
||||
|
||||
val scope = if (value is IrContainerExpression && value.isTransparentScope) {
|
||||
null
|
||||
} else {
|
||||
VariableScope()
|
||||
}
|
||||
|
||||
using(scope) {
|
||||
value.statements.dropLast(1).forEach {
|
||||
evaluateExpression(codegen.newVar(), it)
|
||||
}
|
||||
return evaluateExpression(tmpVariableName, value.statements.lastOrNull())
|
||||
}
|
||||
return evaluateExpression(tmpVariableName, value.statements.lastOrNull())
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun evaluateCall(tmpVariableName: String, value: IrMemberAccessExpression?): LLVMValueRef {
|
||||
private fun evaluateCall(tmpVariableName: String, value: IrMemberAccessExpression): LLVMValueRef {
|
||||
logger.log("evaluateCall : $tmpVariableName = ${ir2string(value)}")
|
||||
val args = mutableListOf<LLVMValueRef>() // Create list of function args.
|
||||
value!!.acceptChildrenVoid(object: IrElementVisitorVoid { // Iterate args of the function.
|
||||
override fun visitElement(element: IrElement) { // Visit arg.
|
||||
val tmp = codegen.newVar() // Create variable representing the arg in codegen
|
||||
args.add(evaluateExpression(tmp, element as IrExpression)!!) // Evaluate expression and get LLVM arg
|
||||
}
|
||||
})
|
||||
|
||||
val args = evaluateExplicitParams(value)
|
||||
|
||||
when {
|
||||
value is IrDelegatingConstructorCall -> return superCall(tmpVariableName, value.descriptor, args)
|
||||
value is IrDelegatingConstructorCall ->
|
||||
return delegatingConstructorCall(tmpVariableName, value.descriptor, args)
|
||||
|
||||
value.descriptor is FunctionDescriptor -> return evaluateFunctionCall(tmpVariableName, value as IrCall, args)
|
||||
else -> {
|
||||
TODO("${ir2string(value)}")
|
||||
@@ -1184,6 +1267,48 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the parameters of [expression] explicitly represented in the IR to the parameters of accessed function.
|
||||
* The parameters should be further evaluated in the same order as they appear in the resulting list.
|
||||
*/
|
||||
private fun bindExplicitParams(expression: IrMemberAccessExpression): List<Pair<ParameterDescriptor, IrExpression>> {
|
||||
val res = mutableListOf<Pair<ParameterDescriptor, IrExpression>>()
|
||||
val descriptor = expression.descriptor
|
||||
|
||||
// TODO: ensure the order below corresponds to the one defined in Kotlin specs.
|
||||
|
||||
expression.dispatchReceiver?.let {
|
||||
res += (descriptor.dispatchReceiverParameter!! to it)
|
||||
}
|
||||
|
||||
expression.extensionReceiver?.let {
|
||||
res += (descriptor.extensionReceiverParameter!! to it)
|
||||
}
|
||||
|
||||
descriptor.valueParameters.map {
|
||||
res += (it to expression.getValueArgument(it.index)!!)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates all parameters of [expression] that are explicitly represented in the IR.
|
||||
* Returns results in the same order as LLVM function expects, assuming that all explicit parameters
|
||||
* exactly correspond to a tail of LLVM parameters.
|
||||
*/
|
||||
private fun evaluateExplicitParams(expression: IrMemberAccessExpression): List<LLVMValueRef> {
|
||||
val evaluatedParams = bindExplicitParams(expression).map { (param, paramExpr) ->
|
||||
param to evaluateExpression("arg", paramExpr)!!
|
||||
}.toMap()
|
||||
|
||||
val allValueParameters = expression.descriptor.allValueParameters
|
||||
|
||||
return allValueParameters.dropWhile { it !in evaluatedParams }.map {
|
||||
evaluatedParams[it]!!
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun evaluateFunctionCall(tmpVariableName: String, callee: IrCall, args: List<LLVMValueRef>): LLVMValueRef {
|
||||
@@ -1227,8 +1352,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
val thisValue = if (containingClass.isArray) {
|
||||
assert(args.size == 1 && LLVMTypeOf(args[0]) == LLVMInt32Type())
|
||||
val allocArrayInstanceArgs = listOf(typeInfo, allocHint, args[0])
|
||||
val ptr = currentCodeContext.genCall(context.allocArrayFunction, allocArrayInstanceArgs, variableName)
|
||||
codegen.bitcast(codegen.kObjHeaderPtr, ptr, codegen.newVar())
|
||||
currentCodeContext.genCall(context.allocArrayFunction, allocArrayInstanceArgs, variableName)
|
||||
} else {
|
||||
currentCodeContext.genCall(context.allocInstanceFunction, listOf(typeInfo, allocHint), variableName)
|
||||
}
|
||||
@@ -1412,6 +1536,10 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
// TODO: it seems to be much more reliable to get args as a mapping from parameter descriptor to LLVM value,
|
||||
// instead of a plain list.
|
||||
// In such case it would be possible to check that all args are available and in the correct order.
|
||||
// However, it currently requires some refactoring to be performed.
|
||||
private fun call(descriptor: FunctionDescriptor, function: LLVMValueRef, args: List<LLVMValueRef>, result: String?): LLVMValueRef {
|
||||
return currentCodeContext.genCall(function, args,
|
||||
if (KotlinBuiltIns.isUnit(descriptor.returnType!!)) "" else result)
|
||||
@@ -1419,9 +1547,21 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
fun superCall(result:String, descriptor:ClassConstructorDescriptor, args:List<LLVMValueRef> ): LLVMValueRef {
|
||||
val rargs = listOf(codegen.thisVariable(), *args.toTypedArray())
|
||||
return callDirect(descriptor, rargs, result)
|
||||
fun delegatingConstructorCall(result: String,
|
||||
descriptor: ClassConstructorDescriptor, args: List<LLVMValueRef>): LLVMValueRef {
|
||||
|
||||
val constructedClass = (codegen.currentFunction!! as ConstructorDescriptor).constructedClass
|
||||
val thisPtr = currentCodeContext.genGetValue(constructedClass.thisAsReceiverParameter)
|
||||
|
||||
val thisPtrArgType = codegen.getLLVMType(descriptor.allValueParameters[0].type)
|
||||
val thisPtrArg = if (LLVMTypeOf(thisPtr) == thisPtrArgType) {
|
||||
thisPtr
|
||||
} else {
|
||||
// e.g. when array constructor calls super (i.e. Any) constructor.
|
||||
codegen.bitcast(thisPtrArgType, thisPtr, codegen.newVar())
|
||||
}
|
||||
|
||||
return callDirect(descriptor, listOf(thisPtrArg) + args, result)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
+5
-14
@@ -2,9 +2,8 @@ package org.jetbrains.kotlin.backend.konan.llvm
|
||||
|
||||
import kotlinx.cinterop.*
|
||||
import llvm.*
|
||||
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
||||
import org.jetbrains.kotlin.backend.konan.allValueParameters
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.utils.singletonOrEmptyList
|
||||
|
||||
/**
|
||||
* Represents the value which can be emitted as bitcode const value
|
||||
@@ -128,20 +127,12 @@ internal fun structType(vararg types: LLVMTypeRef?): LLVMTypeRef = memScoped {
|
||||
|
||||
internal fun ContextUtils.getLlvmFunctionType(function: FunctionDescriptor): LLVMTypeRef? {
|
||||
val returnType = getLLVMType(function.returnType!!)
|
||||
val params = function.dispatchReceiverParameter.singletonOrEmptyList() +
|
||||
function.extensionReceiverParameter.singletonOrEmptyList() +
|
||||
function.valueParameters
|
||||
|
||||
var extraParam = listOf<LLVMTypeRef?>()
|
||||
if (function is ClassConstructorDescriptor) {
|
||||
extraParam += kObjHeaderPtr
|
||||
}
|
||||
val paramTypes:List<LLVMTypeRef?> = params.map { getLLVMType(it.type) }
|
||||
extraParam += paramTypes
|
||||
val params = function.allValueParameters
|
||||
val paramTypes = params.map { getLLVMType(it.type) }
|
||||
|
||||
memScoped {
|
||||
val paramTypesPtr = allocArrayOf(extraParam)[0].ptr
|
||||
return LLVMFunctionType(returnType, paramTypesPtr, extraParam.size, 0)
|
||||
val paramTypesPtr = allocArrayOf(paramTypes)[0].ptr
|
||||
return LLVMFunctionType(returnType, paramTypesPtr, paramTypes.size, 0)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -546,13 +546,10 @@ task finally9(type: RunKonanTest) {
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
TODO: enable after improving LLVM variable naming
|
||||
task scope1(type: RunKonanTest) {
|
||||
goldValue = "1\n"
|
||||
source = "codegen/dataflow/scope1.kt"
|
||||
}
|
||||
*/
|
||||
|
||||
task try1(type: RunKonanTest) {
|
||||
goldValue = "5\n"
|
||||
|
||||
Reference in New Issue
Block a user