Rework variable management for memory management's sake. (#156)
This commit is contained in:
+7
-2
@@ -8,7 +8,6 @@ import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
|||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
internal class CodeGenerator(override val context: Context) : ContextUtils {
|
internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||||
@@ -17,6 +16,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
|||||||
val returns: MutableMap<LLVMBasicBlockRef, LLVMValueRef> = mutableMapOf()
|
val returns: MutableMap<LLVMBasicBlockRef, LLVMValueRef> = mutableMapOf()
|
||||||
// TODO: remove, to make CodeGenerator descriptor-agnostic.
|
// TODO: remove, to make CodeGenerator descriptor-agnostic.
|
||||||
var constructedClass: ClassDescriptor? = null
|
var constructedClass: ClassDescriptor? = null
|
||||||
|
val vars = VariableManager(this)
|
||||||
|
|
||||||
fun prologue(descriptor: FunctionDescriptor) {
|
fun prologue(descriptor: FunctionDescriptor) {
|
||||||
prologue(llvmFunction(descriptor),
|
prologue(llvmFunction(descriptor),
|
||||||
@@ -46,10 +46,14 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
|||||||
|
|
||||||
appendingTo(epilogueBb!!) {
|
appendingTo(epilogueBb!!) {
|
||||||
when {
|
when {
|
||||||
returnType == voidType -> LLVMBuildRetVoid(builder)
|
returnType == voidType -> {
|
||||||
|
vars.releaseVars()
|
||||||
|
LLVMBuildRetVoid(builder)
|
||||||
|
}
|
||||||
returns.size > 0 -> {
|
returns.size > 0 -> {
|
||||||
val returnPhi = phi(returnType!!)
|
val returnPhi = phi(returnType!!)
|
||||||
addPhiIncoming(returnPhi, *returns.toList().toTypedArray())
|
addPhiIncoming(returnPhi, *returns.toList().toTypedArray())
|
||||||
|
vars.releaseVars()
|
||||||
LLVMBuildRet(builder, returnPhi)
|
LLVMBuildRet(builder, returnPhi)
|
||||||
}
|
}
|
||||||
// Do nothing, all paths throw.
|
// Do nothing, all paths throw.
|
||||||
@@ -58,6 +62,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
returns.clear()
|
returns.clear()
|
||||||
|
vars.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
private var prologueBb: LLVMBasicBlockRef? = null
|
private var prologueBb: LLVMBasicBlockRef? = null
|
||||||
|
|||||||
+86
-103
@@ -12,14 +12,12 @@ import org.jetbrains.kotlin.ir.IrElement
|
|||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltinOperatorDescriptorBase
|
import org.jetbrains.kotlin.ir.descriptors.IrBuiltinOperatorDescriptorBase
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBinaryPrimitiveImpl
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrSetterCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrSetterCallImpl
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
@@ -116,6 +114,47 @@ internal class MetadatorVisitor(val context: Context) : IrElementVisitorVoid {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines how to generate context-dependent operations.
|
||||||
|
*/
|
||||||
|
interface CodeContext {
|
||||||
|
|
||||||
|
fun genReturn(target: CallableDescriptor, value: LLVMValueRef?)
|
||||||
|
|
||||||
|
fun genBreak(destination: IrBreak)
|
||||||
|
|
||||||
|
fun genContinue(destination: IrContinue)
|
||||||
|
|
||||||
|
fun genCall(function: LLVMValueRef, args: List<LLVMValueRef>): LLVMValueRef
|
||||||
|
|
||||||
|
fun genThrow(exception: LLVMValueRef)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declares the variable.
|
||||||
|
* @return index of declared variable.
|
||||||
|
*/
|
||||||
|
fun genDeclareVariable(descriptor: VariableDescriptor, value: LLVMValueRef?): Int
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return index of variable declared before, or -1 if no such variable has been declared yet.
|
||||||
|
*/
|
||||||
|
fun getDeclaredVariable(descriptor: VariableDescriptor): Int
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the code to obtain a value available in this context.
|
||||||
|
*
|
||||||
|
* @return the requested value
|
||||||
|
*/
|
||||||
|
fun genGetValue(descriptor: ValueDescriptor): LLVMValueRef
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns owning function scope.
|
||||||
|
*
|
||||||
|
* @return the requested value
|
||||||
|
*/
|
||||||
|
fun functionScope(): CodeContext
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
@@ -128,47 +167,6 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
// TODO: consider eliminating mutable state
|
// TODO: consider eliminating mutable state
|
||||||
private var currentCodeContext: CodeContext = TopLevelCodeContext
|
private var currentCodeContext: CodeContext = TopLevelCodeContext
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines how to generate context-dependent operations.
|
|
||||||
*/
|
|
||||||
private interface CodeContext {
|
|
||||||
|
|
||||||
fun genReturn(target: CallableDescriptor, value: LLVMValueRef?)
|
|
||||||
|
|
||||||
fun genBreak(destination: IrBreak)
|
|
||||||
|
|
||||||
fun genContinue(destination: IrContinue)
|
|
||||||
|
|
||||||
fun genCall(function: LLVMValueRef, args: List<LLVMValueRef>): LLVMValueRef
|
|
||||||
|
|
||||||
fun genThrow(exception: LLVMValueRef)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Declares the variable.
|
|
||||||
* @return pointer to the declared variable.
|
|
||||||
*/
|
|
||||||
fun genDeclareVariable(descriptor: VariableDescriptor): LLVMValueRef
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return pointer to the variable declared before, or `null` if no such variable has been declared yet.
|
|
||||||
*/
|
|
||||||
fun getDeclaredVariable(descriptor: VariableDescriptor): LLVMValueRef?
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates the code to obtain a value available in this context.
|
|
||||||
*
|
|
||||||
* @return the requested value
|
|
||||||
*/
|
|
||||||
fun genGetValue(descriptor: ValueDescriptor, result: String = ""): LLVMValueRef
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns owning function scope.
|
|
||||||
*
|
|
||||||
* @return the requested value
|
|
||||||
*/
|
|
||||||
fun functionScope(): CodeContext
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fake [CodeContext] that doesn't support any operation.
|
* Fake [CodeContext] that doesn't support any operation.
|
||||||
@@ -188,11 +186,11 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
|
|
||||||
override fun genThrow(exception: LLVMValueRef) = unsupported()
|
override fun genThrow(exception: LLVMValueRef) = unsupported()
|
||||||
|
|
||||||
override fun genDeclareVariable(descriptor: VariableDescriptor) = unsupported(descriptor)
|
override fun genDeclareVariable(descriptor: VariableDescriptor, value: LLVMValueRef?) = unsupported(descriptor)
|
||||||
|
|
||||||
override fun getDeclaredVariable(descriptor: VariableDescriptor) = null
|
override fun getDeclaredVariable(descriptor: VariableDescriptor) = -1
|
||||||
|
|
||||||
override fun genGetValue(descriptor: ValueDescriptor, result: String) = unsupported(descriptor)
|
override fun genGetValue(descriptor: ValueDescriptor) = unsupported(descriptor)
|
||||||
|
|
||||||
override fun functionScope(): CodeContext = unsupported()
|
override fun functionScope(): CodeContext = unsupported()
|
||||||
}
|
}
|
||||||
@@ -294,6 +292,8 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
|
|
||||||
if (context.llvm.fileInitializers.isEmpty())
|
if (context.llvm.fileInitializers.isEmpty())
|
||||||
return
|
return
|
||||||
|
|
||||||
|
// Create global initialization records.
|
||||||
val fileName = declaration.name.takeLastWhile { it != '/' }.dropLastWhile { it != '.' }.dropLast(1)
|
val fileName = declaration.name.takeLastWhile { it != '/' }.dropLastWhile { it != '.' }.dropLast(1)
|
||||||
val initName = "${fileName}_init_${context.llvm.globalInitIndex}"
|
val initName = "${fileName}_init_${context.llvm.globalInitIndex}"
|
||||||
val nodeName = "${fileName}_node_${context.llvm.globalInitIndex}"
|
val nodeName = "${fileName}_node_${context.llvm.globalInitIndex}"
|
||||||
@@ -324,14 +324,14 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
val loopExit = codegen.basicBlock()
|
val loopExit = codegen.basicBlock()
|
||||||
|
|
||||||
override fun genBreak(destination: IrBreak) {
|
override fun genBreak(destination: IrBreak) {
|
||||||
if (destination.label == loop.label)
|
if (destination.label == null || destination.label == loop.label)
|
||||||
codegen.br(loopExit)
|
codegen.br(loopExit)
|
||||||
else
|
else
|
||||||
super.genBreak(destination)
|
super.genBreak(destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun genContinue(destination: IrContinue) {
|
override fun genContinue(destination: IrContinue) {
|
||||||
if (destination.label == loop.label)
|
if (destination.label == null || destination.label == loop.label)
|
||||||
codegen.br(loopCheck)
|
codegen.br(loopCheck)
|
||||||
else
|
else
|
||||||
super.genContinue(destination)
|
super.genContinue(destination)
|
||||||
@@ -380,7 +380,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
|
|
||||||
using(FunctionScope(constructorDeclaration)) {
|
using(FunctionScope(constructorDeclaration)) {
|
||||||
|
|
||||||
val thisPtr = currentCodeContext.genGetValue(classDescriptor.thisAsReceiverParameter, "this")
|
val thisPtr = currentCodeContext.genGetValue(classDescriptor.thisAsReceiverParameter)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IR for kotlin.Any is:
|
* IR for kotlin.Any is:
|
||||||
@@ -494,30 +494,21 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
*/
|
*/
|
||||||
private inner class VariableScope : InnerScopeImpl() {
|
private inner class VariableScope : InnerScopeImpl() {
|
||||||
|
|
||||||
private val variables = mutableMapOf<ValueDescriptor, LLVMValueRef>()
|
override fun genDeclareVariable(descriptor: VariableDescriptor, value: LLVMValueRef?): Int {
|
||||||
|
return codegen.vars.createVariable(descriptor to this, value)
|
||||||
override fun genDeclareVariable(descriptor: VariableDescriptor): 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: VariableDescriptor): LLVMValueRef? {
|
override fun getDeclaredVariable(descriptor: VariableDescriptor): Int {
|
||||||
return variables[descriptor] ?: super.getDeclaredVariable(descriptor)
|
val index = codegen.vars.indexOf(descriptor to this)
|
||||||
|
return if (index < 0) super.getDeclaredVariable(descriptor) else return index
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun genGetValue(descriptor: ValueDescriptor, result: String): LLVMValueRef {
|
override fun genGetValue(descriptor: ValueDescriptor): LLVMValueRef {
|
||||||
val variable = variables[descriptor]
|
val index = codegen.vars.indexOf(descriptor to this)
|
||||||
if (variable != null) {
|
if (index < 0) {
|
||||||
return codegen.load(variable, result)
|
return super.genGetValue(descriptor)
|
||||||
} else {
|
} else {
|
||||||
return super.genGetValue(descriptor, result)
|
return codegen.vars.load(index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -526,23 +517,24 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
* The scope of parameter visibility.
|
* The scope of parameter visibility.
|
||||||
*/
|
*/
|
||||||
private open inner class ParameterScope(
|
private open inner class ParameterScope(
|
||||||
private val parameters: Map<ParameterDescriptor, LLVMValueRef>): InnerScopeImpl() {
|
parameters: Map<ParameterDescriptor, LLVMValueRef>): InnerScopeImpl() {
|
||||||
|
|
||||||
// Note: it is possible to generate access to a parameter without any variables,
|
// Note: it is possible to generate access to a parameter without any variables,
|
||||||
// however variables are named and thus the resulting bitcode can be more readable.
|
// however variables are named and thus the resulting bitcode can be more readable.
|
||||||
|
|
||||||
private val parameterVars = parameters.map { (descriptor, value) ->
|
init {
|
||||||
val variable = codegen.alloca(descriptor.type, descriptor.name.asString())
|
parameters.map { (descriptor, value) ->
|
||||||
codegen.store(value, variable)
|
codegen.vars.createImmutable(descriptor to this, value)
|
||||||
descriptor to variable
|
}
|
||||||
}.toMap()
|
|
||||||
|
|
||||||
override fun genGetValue(descriptor: ValueDescriptor, result: String): LLVMValueRef {
|
}
|
||||||
val variable = parameterVars[descriptor]
|
|
||||||
if (variable != null) {
|
override fun genGetValue(descriptor: ValueDescriptor): LLVMValueRef {
|
||||||
return codegen.load(variable, result)
|
val index = codegen.vars.indexOf(descriptor to this)
|
||||||
|
if (index < 0) {
|
||||||
|
return super.genGetValue(descriptor)
|
||||||
} else {
|
} else {
|
||||||
return super.genGetValue(descriptor, result)
|
return codegen.vars.load(index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1082,7 +1074,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
|
|
||||||
codegen.appendingTo(body) {
|
codegen.appendingTo(body) {
|
||||||
using(VariableScope()) {
|
using(VariableScope()) {
|
||||||
createVariable(it.parameter, exception)
|
currentCodeContext.genDeclareVariable(it.parameter, exception)
|
||||||
evaluateExpressionAndJump(it.result, success)
|
evaluateExpressionAndJump(it.result, success)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1250,7 +1242,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
val isUnit = KotlinBuiltIns.isUnit(expression.type)
|
val isUnit = KotlinBuiltIns.isUnit(expression.type)
|
||||||
val isNothing = KotlinBuiltIns.isNothing(expression.type)
|
val isNothing = KotlinBuiltIns.isNothing(expression.type)
|
||||||
val neitherUnitNorNothing = !isNothing && !isUnit
|
val neitherUnitNorNothing = !isNothing && !isUnit
|
||||||
val tmpLlvmVariablePtr = if (!isUnit) codegen.alloca(expression.type) else null
|
val tmpLlvmVariable = if (!isUnit) codegen.vars.createAnonymousMutable(expression.type) else -1
|
||||||
|
|
||||||
expression.branches.forEach { // Iterate through "when" branches (clauses).
|
expression.branches.forEach { // Iterate through "when" branches (clauses).
|
||||||
var bbNext = bbExit // For last clause bbNext coincides with bbExit.
|
var bbNext = bbExit // For last clause bbNext coincides with bbExit.
|
||||||
@@ -1258,10 +1250,10 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
bbNext = codegen.basicBlock() // Create new basic block for next clause.
|
bbNext = codegen.basicBlock() // Create new basic block for next clause.
|
||||||
val isUnitBranch = KotlinBuiltIns.isUnit(it.result.type)
|
val isUnitBranch = KotlinBuiltIns.isUnit(it.result.type)
|
||||||
val isNothingBranch = KotlinBuiltIns.isNothing(it.result.type)
|
val isNothingBranch = KotlinBuiltIns.isNothing(it.result.type)
|
||||||
generateWhenCase(isUnitBranch, isNothingBranch, tmpLlvmVariablePtr, it, bbNext, bbExit) // Generate code for current clause.
|
generateWhenCase(isUnitBranch, isNothingBranch, tmpLlvmVariable, it, bbNext, bbExit) // Generate code for current clause.
|
||||||
}
|
}
|
||||||
if (neitherUnitNorNothing) // If result hasn't Unit type and block doesn't end with return
|
if (neitherUnitNorNothing) // If result hasn't Unit type and block doesn't end with return
|
||||||
return codegen.load(tmpLlvmVariablePtr!!) // load value from variable.
|
return codegen.vars.load(tmpLlvmVariable) // load value from variable.
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1319,8 +1311,8 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
private fun evaluateSetVariable(value: IrSetVariable): LLVMValueRef? {
|
private fun evaluateSetVariable(value: IrSetVariable): LLVMValueRef? {
|
||||||
context.log("evaluateSetVariable : ${ir2string(value)}")
|
context.log("evaluateSetVariable : ${ir2string(value)}")
|
||||||
val ret = evaluateExpression(value.value)!!
|
val ret = evaluateExpression(value.value)!!
|
||||||
val variable = currentCodeContext.getDeclaredVariable(value.descriptor)!!
|
val variable = currentCodeContext.getDeclaredVariable(value.descriptor)
|
||||||
codegen.store(ret, variable)
|
codegen.vars.store(ret, variable)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1329,20 +1321,10 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
private fun evaluateVariable(value: IrVariable): LLVMValueRef? {
|
private fun evaluateVariable(value: IrVariable): LLVMValueRef? {
|
||||||
context.log("evaluateVariable : ${ir2string(value)}")
|
context.log("evaluateVariable : ${ir2string(value)}")
|
||||||
val ret = value.initializer?.let { evaluateExpression(it)!! }
|
val ret = value.initializer?.let { evaluateExpression(it)!! }
|
||||||
createVariable(value.descriptor, ret)
|
currentCodeContext.genDeclareVariable(value.descriptor, ret)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createVariable(descriptor: VariableDescriptor, value: LLVMValueRef? = null): LLVMValueRef {
|
|
||||||
|
|
||||||
val newVariable = currentCodeContext.genDeclareVariable(descriptor)
|
|
||||||
|
|
||||||
if (value != null) {
|
|
||||||
codegen.store(value, newVariable)
|
|
||||||
}
|
|
||||||
return newVariable
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
private fun evaluateTypeOperator(value: IrTypeOperatorCall): LLVMValueRef? {
|
private fun evaluateTypeOperator(value: IrTypeOperatorCall): LLVMValueRef? {
|
||||||
@@ -1366,23 +1348,23 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
val bbExit = codegen.basicBlock()
|
val bbExit = codegen.basicBlock()
|
||||||
|
|
||||||
val resultLlvmType = codegen.getLLVMType(value.type)
|
val resultLlvmType = codegen.getLLVMType(value.type)
|
||||||
val result = codegen.alloca(resultLlvmType)
|
val result = codegen.vars.createAnonymousMutable(resultLlvmType)
|
||||||
|
|
||||||
val condition = evaluateInstanceOf(value)
|
val condition = evaluateInstanceOf(value)
|
||||||
codegen.condBr(condition, bbTrue, bbFalse)
|
codegen.condBr(condition, bbTrue, bbFalse)
|
||||||
|
|
||||||
codegen.positionAtEnd(bbTrue)
|
codegen.positionAtEnd(bbTrue)
|
||||||
val castResult = evaluateExpression(value.argument)
|
val castResult = evaluateExpression(value.argument)
|
||||||
codegen.store(castResult!!, result)
|
codegen.vars.store(castResult!!, result)
|
||||||
codegen.br(bbExit)
|
codegen.br(bbExit)
|
||||||
|
|
||||||
codegen.positionAtEnd(bbFalse)
|
codegen.positionAtEnd(bbFalse)
|
||||||
val nullResult = LLVMConstNull(resultLlvmType)!!
|
val nullResult = LLVMConstNull(resultLlvmType)!!
|
||||||
codegen.store(nullResult, result)
|
codegen.vars.store(nullResult, result)
|
||||||
codegen.br(bbExit)
|
codegen.br(bbExit)
|
||||||
|
|
||||||
codegen.positionAtEnd(bbExit)
|
codegen.positionAtEnd(bbExit)
|
||||||
return codegen.load(result)
|
return codegen.vars.load(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
@@ -1870,13 +1852,14 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
private fun generateWhenCase(isUnit:Boolean, isNothing:Boolean, resultPtr: LLVMValueRef?, branch: IrBranch, bbNext: LLVMBasicBlockRef?, bbExit: LLVMBasicBlockRef?) {
|
private fun generateWhenCase(isUnit:Boolean, isNothing:Boolean, resultPtr: Int,
|
||||||
|
branch: IrBranch, bbNext: LLVMBasicBlockRef?, bbExit: LLVMBasicBlockRef?) {
|
||||||
val neitherUnitNorNothing = !isNothing && !isUnit // If branches doesn't end with 'return' either result hasn't got 'unit' type.
|
val neitherUnitNorNothing = !isNothing && !isUnit // If branches doesn't end with 'return' either result hasn't got 'unit' type.
|
||||||
val branchResult = branch.result
|
val branchResult = branch.result
|
||||||
if (isUnconditional(branch)) { // It is the "else" clause.
|
if (isUnconditional(branch)) { // It is the "else" clause.
|
||||||
val brResult = evaluateExpression(branchResult) // Generate clause body.
|
val brResult = evaluateExpression(branchResult) // Generate clause body.
|
||||||
if (neitherUnitNorNothing) // If nor unit neither result ends with return
|
if (neitherUnitNorNothing) // If nor unit neither result ends with return
|
||||||
codegen.store(brResult!!, resultPtr!!) // we store result to temporal variable.
|
codegen.vars.store(brResult!!, resultPtr) // we store result to temporal variable.
|
||||||
if (bbExit == null) return // If 'bbExit' isn't defined just return
|
if (bbExit == null) return // If 'bbExit' isn't defined just return
|
||||||
codegen.br(bbExit) // Generate branch to bbExit.
|
codegen.br(bbExit) // Generate branch to bbExit.
|
||||||
codegen.positionAtEnd(bbExit) // Switch generation to bbExit.
|
codegen.positionAtEnd(bbExit) // Switch generation to bbExit.
|
||||||
@@ -1887,7 +1870,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
codegen.positionAtEnd(bbCurr) // Switch generation to block for clause body.
|
codegen.positionAtEnd(bbCurr) // Switch generation to block for clause body.
|
||||||
val brResult = evaluateExpression(branch.result) // Generate clause body.
|
val brResult = evaluateExpression(branch.result) // Generate clause body.
|
||||||
if (neitherUnitNorNothing) // If nor unit neither result ends with return
|
if (neitherUnitNorNothing) // If nor unit neither result ends with return
|
||||||
codegen.store(brResult!!, resultPtr!!) // we store result to temporal variable.
|
codegen.vars.store(brResult!!, resultPtr) // we store result to temporal variable.
|
||||||
if (!isNothing) // If basic block doesn't end with 'return'
|
if (!isNothing) // If basic block doesn't end with 'return'
|
||||||
codegen.br(bbExit!!) // generate branch to bbExit.
|
codegen.br(bbExit!!) // generate branch to bbExit.
|
||||||
codegen.positionAtEnd(bbNext!!) // Switch generation to bbNextClause.
|
codegen.positionAtEnd(bbNext!!) // Switch generation to bbNextClause.
|
||||||
|
|||||||
+125
@@ -0,0 +1,125 @@
|
|||||||
|
package org.jetbrains.kotlin.backend.konan.llvm
|
||||||
|
|
||||||
|
import llvm.*
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.types.*
|
||||||
|
|
||||||
|
|
||||||
|
internal class VariableManager(val codegen: CodeGenerator) {
|
||||||
|
internal interface Record {
|
||||||
|
fun load() : LLVMValueRef
|
||||||
|
fun store(value: LLVMValueRef)
|
||||||
|
fun address() : LLVMValueRef
|
||||||
|
fun isRefSlot() : Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class SlotRecord(val address: LLVMValueRef, val refSlot: Boolean) : Record {
|
||||||
|
override fun load() : LLVMValueRef {
|
||||||
|
return codegen.load(address)
|
||||||
|
}
|
||||||
|
override fun store(value: LLVMValueRef) {
|
||||||
|
codegen.store(value, address)
|
||||||
|
}
|
||||||
|
override fun address() : LLVMValueRef {
|
||||||
|
return this.address
|
||||||
|
}
|
||||||
|
override fun isRefSlot() = this.refSlot
|
||||||
|
|
||||||
|
override fun toString() = (if (refSlot) "refslot" else "slot") + " for ${address}"
|
||||||
|
}
|
||||||
|
|
||||||
|
class ValueRecord(val value: LLVMValueRef, val descriptor: ValueDescriptor) : Record {
|
||||||
|
override fun load() : LLVMValueRef {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
override fun store(value: LLVMValueRef) {
|
||||||
|
throw Error("writing to immutable: ${descriptor}")
|
||||||
|
}
|
||||||
|
override fun address() : LLVMValueRef {
|
||||||
|
throw Error("no address for: ${descriptor}")
|
||||||
|
}
|
||||||
|
override fun isRefSlot() : Boolean = false
|
||||||
|
|
||||||
|
override fun toString() = "value of ${value} from ${descriptor}"
|
||||||
|
}
|
||||||
|
|
||||||
|
val variables: ArrayList<Record> = arrayListOf()
|
||||||
|
val descriptors: HashMap<Pair<ValueDescriptor, CodeContext>, Int> = hashMapOf()
|
||||||
|
|
||||||
|
// Clears inner state of variable manager.
|
||||||
|
fun clear() {
|
||||||
|
variables.clear()
|
||||||
|
descriptors.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun releaseVars() {
|
||||||
|
// This function is called by codegen to cleanup local references when leaving frame.
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createVariable(scoped: Pair<VariableDescriptor, CodeContext>, value: LLVMValueRef? = null) : Int {
|
||||||
|
// TODO: fix, due to the bug in frontend, we shall always create stack slot for variable now.
|
||||||
|
// Note that we always create slot for object references for memory management.
|
||||||
|
val descriptor = scoped.first
|
||||||
|
if (descriptor.isVar() || isObjectType(codegen.getLLVMType(descriptor.type)) || true) {
|
||||||
|
return createMutable(scoped, value)
|
||||||
|
} else {
|
||||||
|
return createImmutable(scoped, value!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createMutable(scoped: Pair<VariableDescriptor, CodeContext>, value: LLVMValueRef? = null) : Int {
|
||||||
|
val descriptor = scoped.first
|
||||||
|
assert(descriptors.get(scoped) == null)
|
||||||
|
val index = variables.size
|
||||||
|
val type = codegen.getLLVMType(descriptor.type)
|
||||||
|
val slot = codegen.alloca(type, descriptor.name.asString())
|
||||||
|
if (value != null)
|
||||||
|
codegen.store(value, slot)
|
||||||
|
variables.add(SlotRecord(slot, isObjectType(type)))
|
||||||
|
descriptors[scoped] = index
|
||||||
|
return index
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates anonymous mutable variable.
|
||||||
|
fun createAnonymousMutable(type: KotlinType, value: LLVMValueRef? = null) : Int {
|
||||||
|
return createAnonymousMutable(codegen.getLLVMType(type), value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createAnonymousMutable(type: LLVMTypeRef, value: LLVMValueRef? = null) : Int {
|
||||||
|
val index = variables.size
|
||||||
|
val slot = codegen.alloca(type)
|
||||||
|
if (value != null)
|
||||||
|
codegen.store(value, slot)
|
||||||
|
variables.add(SlotRecord(slot, isObjectType(type)))
|
||||||
|
return index
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createImmutable(scoped: Pair<ValueDescriptor, CodeContext>, value: LLVMValueRef) : Int {
|
||||||
|
val descriptor = scoped.first
|
||||||
|
assert(descriptors.get(scoped) == null)
|
||||||
|
val index = variables.size
|
||||||
|
variables.add(ValueRecord(value, descriptor))
|
||||||
|
descriptors[scoped] = index
|
||||||
|
return index
|
||||||
|
}
|
||||||
|
|
||||||
|
fun indexOf(scoped: Pair<ValueDescriptor, CodeContext>) : Int {
|
||||||
|
return descriptors.getOrElse(scoped) { -1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addressOf(index: Int): LLVMValueRef {
|
||||||
|
return variables[index].address()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun load(index: Int): LLVMValueRef {
|
||||||
|
return variables[index].load()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun store(value: LLVMValueRef, index: Int) {
|
||||||
|
variables[index].store(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isObjectType(type: LLVMTypeRef) : Boolean {
|
||||||
|
return type == codegen.kObjHeaderPtr || type == codegen.kArrayHeaderPtr
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user