translator: refactor variable allocation

This commit is contained in:
Alexey Stepanov
2016-08-29 11:27:29 +03:00
parent ad71f38061
commit cec8344c14
7 changed files with 80 additions and 78 deletions
+8 -4
View File
@@ -7,11 +7,15 @@ lightRed = '\033[1;31m'
orange = '\033[0;33m'
nc = '\033[0m'
stdlib:
cd ../kotstd && make clean && make
%.out: %.txt
%.out: stdlib %.txt
@./run_one_test.sh $(@:.out=.txt)
all: $(OBJECTS)
@echo "ok"
tests: stdlib $(OBJECTS)
@date
.PHONY: all
.DEFAULT_GOAL := tests
.PHONY: tests, stdlib
@@ -43,7 +43,6 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
if (result.pointer == 1 && result.type !is LLVMReferenceType) {
result = codeBuilder.loadAndGetVariable(result)
}
if (result.type is LLVMReferenceType) {
genReferenceReturn(result)
} else {
@@ -119,7 +118,6 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
fun evaluateConstructorDelegationReferenceExpression(expr: KtConstructorDelegationReferenceExpression, structCodegen: StructCodegen, constructorArguments: List<LLVMVariable>, scopeDepth: Int): LLVMSingleValue? {
val targetCall = state.bindingContext.get(BindingContext.CALL, expr)
val names = parseValueArguments(targetCall!!.valueArguments, scopeDepth)
val args = codeBuilder.loadArgsIfRequired(names, constructorArguments)
return evaluateConstructorCallExpression(LLVMVariable(structCodegen.fullName + LLVMType.mangleFunctionArguments(names), structCodegen.type, scope = LLVMVariableScope()), args)
@@ -157,9 +155,8 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
expectedType.prefix = "class"
}
val result = codeBuilder.getNewVariable(expectedType, pointer = 1)
codeBuilder.allocStaticVar(result)
result.pointer++
val result = codeBuilder.getNewVariable(expectedType, pointer = 2)
codeBuilder.allocStaticVar(result, pointer = true)
val condition = left.type!!.operatorEq(loadedLeft, LLVMVariable("", LLVMNullType()))
val thenLabel = codeBuilder.getNewLabel(prefix = "safe.access")
@@ -168,8 +165,8 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
val conditionResult = codeBuilder.getNewVariable(condition.variableType)
codeBuilder.addAssignment(conditionResult, condition)
codeBuilder.addCondition(conditionResult, thenLabel, elseLabel)
codeBuilder.markWithLabel(thenLabel)
codeBuilder.storeNull(result)
codeBuilder.addUnconditionalJump(endLabel)
@@ -201,7 +198,6 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
is KtBinaryExpression -> evaluateExpression(receiverExpr, scopeDepth) as LLVMVariable
is KtDotQualifiedExpression -> {
val codegen = resolveCodegenByName(receiverName, receiverName.split("."))
if (codegen != null) null else evaluateExpression(receiverExpr, scopeDepth) as LLVMVariable
}
is KtNameReferenceExpression -> {
@@ -251,19 +247,20 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
val targetFunction = state.bindingContext.get(BindingContext.CALL, selector.calleeExpression)
val resolvedCall = state.bindingContext.get(BindingContext.RESOLVED_CALL, targetFunction)
val targetFunctionName = resolvedCall!!.candidateDescriptor.fqNameSafe.asString().removeSuffix(".<init>")
val targetFunctionName = resolvedCall!!.candidateDescriptor.fqNameSafe.convertToNativeName()
val nameWithoutMangling = resolvedCall.candidateDescriptor.name.asString().replace(Regex("""(.?)<init>"""), "")
val packageNameFirst = targetFunction?.calleeExpression?.getContainingKtFile()?.packageFqName?.asString()?.removeSuffix(".<init>") ?: ""
val packageNameSecond = resolvedCall.candidateDescriptor.containingDeclaration.fqNameSafe.asString().removeSuffix(".<init>")
val packageNameFirst = targetFunction?.calleeExpression?.getContainingKtFile()?.packageFqName?.convertToNativeName() ?: ""
val packageNameSecond = resolvedCall.candidateDescriptor.containingDeclaration.fqNameSafe.convertToNativeName()
val names = parseArgList(selector, scopeDepth)
val type = if (names.size > 0) LLVMType.mangleFunctionArguments(names) else ""
val constructedFunctionName = standardType.mangle() + nameWithoutMangling.addBeforeIfNotEmpty(".") + type
val targetExtension = state.extensionFunctions[standardType.toString()]
val extensionCodegen = state.extensionFunctions[standardType.toString()]?.get(packageNameFirst.addAfterIfNotEmpty(".") + constructedFunctionName) ?:
state.extensionFunctions[standardType.toString()]?.get(packageNameSecond.addAfterIfNotEmpty(".") + constructedFunctionName) ?:
state.extensionFunctions[standardType.toString()]?.get(targetFunctionName)
val extensionCodegen = targetExtension?.get(packageNameFirst.addAfterIfNotEmpty(".") + constructedFunctionName) ?:
targetExtension?.get(packageNameSecond.addAfterIfNotEmpty(".") + constructedFunctionName) ?:
targetExtension?.get(targetFunctionName)
?: throw UnexpectedException(constructedFunctionName)
val receiverExpression = receiverExpressionArgument ?: evaluateExpression(receiver, scopeDepth + 1)!!
@@ -373,7 +370,7 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
}
private fun evaluateReferenceExpression(expr: KtReferenceExpression, scopeDepth: Int, classScope: StructCodegen? = null): LLVMSingleValue? {
val targetName = state.bindingContext.get(BindingContext.REFERENCE_TARGET, expr)?.fqNameSafe?.asString()?.replace(".<init>", "")
val targetName = state.bindingContext.get(BindingContext.REFERENCE_TARGET, expr)?.fqNameSafe?.convertToNativeName()
return when {
expr is KtArrayAccessExpression -> evaluateArrayAccessExpression(expr, scopeDepth + 1)
isEnumClassField(expr, classScope) -> resolveEnumClassField(expr, classScope)
@@ -438,7 +435,8 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
if (resolvedCall is VariableAsFunctionResolvedCallImpl) {
resolvedCall = resolvedCall.variableCall
}
val targetFunctionName = resolvedCall!!.candidateDescriptor.fqNameSafe.asString().removeSuffix(".<init>")
val targetFunctionName = resolvedCall!!.candidateDescriptor.fqNameSafe.convertToNativeName()
val functionDescriptor = expr.getFunctionResolvedCallWithAssert(state.bindingContext).candidateDescriptor
val arguments = resolvedCall.valueArguments.toSortedMap(compareBy { it.index }).values
@@ -530,9 +528,8 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
codeBuilder.addLLVMCode(LLVMCall(LLVMVoidType(), function.toString(), names).toString())
}
is LLVMReferenceType -> {
val returnVar = codeBuilder.getNewVariable(returnType, pointer = 1)
codeBuilder.allocStaticVar(returnVar)
returnVar.pointer++
val returnVar = codeBuilder.getNewVariable(returnType, pointer = 2)
codeBuilder.allocStaticVar(returnVar, pointer = true)
val args = ArrayList<LLVMSingleValue>()
args.add(returnVar)
@@ -549,9 +546,8 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
val result = codeBuilder.getNewVariable(returnType)
codeBuilder.addAssignment(result, LLVMCall(returnType, function.toString(), names))
val resultPtr = codeBuilder.getNewVariable(returnType)
codeBuilder.allocStackVar(resultPtr)
resultPtr.pointer = 1
val resultPtr = codeBuilder.getNewVariable(returnType, pointer = 1)
codeBuilder.allocStackVar(resultPtr, pointer = true)
codeBuilder.storeVariable(resultPtr, result)
return resultPtr
}
@@ -561,14 +557,11 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
}
private fun evaluateConstructorCallExpression(function: LLVMVariable, names: List<LLVMSingleValue>): LLVMSingleValue? {
val store = codeBuilder.getNewVariable(function.type)
codeBuilder.allocStaticVar(store)
store.pointer++
val result = codeBuilder.getNewVariable(function.type, pointer = 1)
codeBuilder.allocStackVar(result)
result.pointer++
val store = codeBuilder.getNewVariable(function.type, pointer = 1)
codeBuilder.allocStaticVar(store, pointer = true)
val result = codeBuilder.getNewVariable(function.type, pointer = 2)
codeBuilder.allocStackVar(result, pointer = true)
codeBuilder.storeVariable(result, store)
val args = ArrayList<LLVMSingleValue>()
@@ -595,6 +588,7 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
for (arg in args) {
result.add(parseOneValueArgument(arg, scopeDepth))
}
return result
}
@@ -616,6 +610,7 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
private fun evaluateBinaryExpression(expr: KtBinaryExpression, scopeDepth: Int): LLVMVariable? {
val operator = expr.operationToken
if (operator == KtTokens.ELVIS) {
return evaluateElvisOperator(expr, scopeDepth)
}
@@ -628,20 +623,24 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
}
}
left ?: throw UnsupportedOperationException("Wrong binary exception: ${expr.text}")
val right = evaluateExpression(expr.right, scopeDepth) ?: throw UnsupportedOperationException("Wrong binary exception: ${expr.text}")
left ?: throw UnsupportedOperationException("Wrong binary expression: ${expr.text}")
val right = evaluateExpression(expr.right, scopeDepth)
?: throw UnsupportedOperationException("Wrong binary expression: ${expr.text}")
return executeBinaryExpression(operator, expr.operationReference, left, right)
}
private fun evaluatePostfixExpression(expr: KtPostfixExpression, scopeDepth: Int): LLVMSingleValue? {
val operator = expr.operationToken
val left = evaluateExpression(expr.baseExpression, scopeDepth) ?: throw UnsupportedOperationException("Wrong binary exception: ${expr.text}")
val left = evaluateExpression(expr.baseExpression, scopeDepth)
?: throw UnsupportedOperationException("Wrong binary expression: ${expr.text}")
return executePostfixExpression(operator, left as LLVMVariable)
}
private fun evaluatePrefixExpression(expr: KtPrefixExpression, scopeDepth: Int): LLVMSingleValue? {
val operator = expr.operationToken
val left = evaluateExpression(expr.baseExpression, scopeDepth) ?: throw UnsupportedOperationException("Wrong binary exception")
val left = evaluateExpression(expr.baseExpression, scopeDepth)
?: throw UnsupportedOperationException("Wrong binary expression")
return executePrefixExpression(operator, expr.operationReference, left)
}
@@ -713,7 +712,8 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
= addPrimitiveBinaryOperation(operator, referenceName, left, right)
private fun evaluateElvisOperator(expr: KtBinaryExpression, scopeDepth: Int): LLVMVariable {
val left = evaluateExpression(expr.firstChild, scopeDepth) ?: throw UnsupportedOperationException("Wrong binary exception")
val left = evaluateExpression(expr.firstChild, scopeDepth)
?: throw UnsupportedOperationException("Wrong binary expression")
val lptr = codeBuilder.loadAndGetVariable(left as LLVMVariable)
val condition = lptr.type.operatorEq(lptr, LLVMVariable("", LLVMNullType()))
@@ -726,7 +726,6 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
val endLabel = codeBuilder.getNewLabel(prefix = "elvis")
codeBuilder.addCondition(conditionResult, elseLabel, thenLabel)
codeBuilder.markWithLabel(thenLabel)
codeBuilder.addUnconditionalJump(endLabel)
@@ -738,8 +737,8 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
}
codeBuilder.addUnconditionalJump(endLabel)
codeBuilder.markWithLabel(endLabel)
return left
}
@@ -881,16 +880,16 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
return firstOp
}
val result = firstOp as LLVMVariable
val sourceArgument: LLVMSingleValue
if (secondOp.type!!.isPrimitive() && (secondOp.pointer == 0) && (firstOp.pointer == 2)) {
sourceArgument = codeBuilder.getNewVariable(secondOp.type!!, 1)
codeBuilder.allocStaticVar(sourceArgument, true)
codeBuilder.allocStaticVar(sourceArgument, asValue = true)
codeBuilder.storeVariable(sourceArgument, secondOp)
} else {
sourceArgument = if (result.pointer == secondOp.pointer + 1) secondOp else secondNativeOp
}
codeBuilder.storeVariable(result, sourceArgument)
codeBuilder.addComment("end variable assignment")
return result
@@ -960,11 +959,9 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
val loopParameter = state.bindingContext.get(BindingContext.VALUE_PARAMETER, expr.loopParameter!!)?.fqNameSafe?.asString() ?: expr.loopParameter!!.name!!
val allocVar = variableManager.receiveVariable(loopParameter, nextDescriptor.returnType!!.type, LLVMRegisterScope(), pointer =
nextDescriptor.returnType!!.pointer)
nextDescriptor.returnType!!.pointer+1)
variableManager.addVariable(loopParameter, allocVar, scopeDepth + 1)
codeBuilder.allocStackVar(allocVar)
allocVar.pointer++
allocVar.kotlinName = loopParameter
codeBuilder.allocStackVar(allocVar, pointer = true)
addPrimitiveBinaryOperation(KtTokens.EQ, null, allocVar, currentParameter)
@@ -1128,17 +1125,15 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va
private fun evaluateValExpression(element: KtProperty, scopeDepth: Int): LLVMVariable? {
val variable = state.bindingContext.get(BindingContext.VARIABLE, element)!!
val identifier = variable.fqNameSafe.asString().replace(".<init>", "")
val identifier = variable.fqNameSafe.convertToNativeName()
val assignExpression = evaluateExpression(element.delegateExpressionOrInitializer, scopeDepth)
val expectedExpressionType = LLVMInstanceOfStandardType("", variable.type, state = state)
val primitivePointer = LLVMMapStandardType(variable.type, state) !is LLVMReferred
val allocVar = variableManager.receiveVariable(identifier, expectedExpressionType.type, LLVMRegisterScope(), pointer = expectedExpressionType.pointer)
codeBuilder.allocStackVar(allocVar)
allocVar.pointer++
allocVar.kotlinName = identifier
val allocVar = variableManager.receiveVariable(identifier, expectedExpressionType.type, LLVMRegisterScope(), pointer = expectedExpressionType.pointer+1)
codeBuilder.allocStackVar(allocVar, pointer = true)
variableManager.addVariable(identifier, allocVar, scopeDepth)
if (assignExpression != null) {
@@ -68,5 +68,4 @@ class ProjectTranslator(val files: List<KtFile>, val state: TranslationState) {
}
}
}
}
@@ -146,7 +146,7 @@ abstract class StructCodegen(val state: TranslationState,
variableManager.addVariable("this", classVal, 0)
val secondaryConstructorArguments = descriptor!!.valueParameters.map {
LLVMInstanceOfStandardType(it.fqNameSafe.asString().replace(".<init>", ""), it.type, state = state)
LLVMInstanceOfStandardType(it.fqNameSafe.convertToNativeName(), it.type, state = state)
}
argFields.add(classVal)
@@ -222,7 +222,7 @@ abstract class StructCodegen(val state: TranslationState,
val blockCodegen = object : BlockCodegen(state, variableManager, codeBuilder) {}
val receiverThis = LLVMVariable("classvariable.this.addr", type, scope = LLVMRegisterScope(), pointer = 1)
codeBuilder.addComment("field initilizers starts")
codeBuilder.addComment("field initializers starts")
variableManager.addVariable("this", receiverThis, 2)
for ((variable, initializer) in initializedFields) {
@@ -235,7 +235,7 @@ abstract class StructCodegen(val state: TranslationState,
}
variableManager.pullOneUpwardLevelVariable("this")
codeBuilder.addComment("field initilizers ends")
codeBuilder.addComment("field initializers ends")
}
private fun generateReturn(src: LLVMVariable) {
@@ -249,7 +249,7 @@ abstract class StructCodegen(val state: TranslationState,
protected fun resolveType(field: KtNamedDeclaration, ktType: KotlinType): LLVMClassVariable {
val annotations = parseFieldAnnotations(field)
val fieldName = state.bindingContext.get(BindingContext.VALUE_PARAMETER, field as?KtParameter)?.fqNameSafe?.asString()?.replace(".<init>", "")
val fieldName = state.bindingContext.get(BindingContext.VALUE_PARAMETER, field as?KtParameter)?.fqNameSafe?.convertToNativeName()
?: field.fqName?.asString() ?: field.name!!
val result = LLVMInstanceOfStandardType(fieldName, ktType, LLVMRegisterScope(), state = state)
@@ -14,7 +14,7 @@ class LLVMBuilder(val arm: Boolean = false) {
object UniqueGenerator {
private var unique = 0
fun generateUniqueString(): String {
unique += 1
unique++
return ".unique." + unique
}
}
@@ -66,11 +66,12 @@ class LLVMBuilder(val arm: Boolean = false) {
localCode.appendln("}")
}
fun receiveNativeValue(firstOp: LLVMSingleValue): LLVMSingleValue = when (firstOp) {
is LLVMConstant -> firstOp
is LLVMVariable -> if (firstOp.pointer == 0) firstOp else loadAndGetVariable(firstOp)
else -> throw UnsupportedOperationException()
}
fun receiveNativeValue(firstOp: LLVMSingleValue): LLVMSingleValue =
when (firstOp) {
is LLVMConstant -> firstOp
is LLVMVariable -> if (firstOp.pointer == 0) firstOp else loadAndGetVariable(firstOp)
else -> throw UnsupportedOperationException()
}
fun loadArgsIfRequired(names: List<LLVMSingleValue>, args: List<LLVMVariable>) =
names.mapIndexed(fun(i: Int, value: LLVMSingleValue): LLVMSingleValue {
@@ -157,10 +158,6 @@ class LLVMBuilder(val arm: Boolean = false) {
localCode.appendln("${label.label}:")
}
fun addNopInstruction() {
localCode.appendln(getNewVariable(LLVMIntType()).toString() + " = add i1 0, 0 ; nop instruction")
}
fun storeVariable(target: LLVMSingleValue, source: LLVMSingleValue) {
if ((source.type is LLVMStringType) && (!(source.type as LLVMStringType).isLoaded)) {
storeString(target as LLVMVariable, source as LLVMVariable, 0)
@@ -220,18 +217,19 @@ class LLVMBuilder(val arm: Boolean = false) {
localCode.appendln(code)
}
fun allocStackVar(target: LLVMVariable, asValue: Boolean = false) {
localCode.appendln("$target = alloca ${if (asValue) target.type.toString() else target.getType()}, align ${target.type.align}")
fun allocStackVar(target: LLVMVariable, asValue: Boolean = false, pointer: Boolean = false) {
val type = if (asValue) target.type.toString() else target.getType()
localCode.appendln("$target = alloca ${if (pointer) type.removeSuffix("*") else type}, align ${target.type.align}")
}
fun allocStaticVar(target: LLVMVariable, asValue: Boolean = false) {
fun allocStaticVar(target: LLVMVariable, asValue: Boolean = false, pointer: Boolean = false) {
val allocated = getNewVariable(LLVMCharType(), pointer = 1)
val size = if (target.pointer > 0) TranslationState.pointerSize else target.type.size
val size = if ((target.pointer >= 2) || (target.pointer >= 1 && !pointer)) TranslationState.pointerSize else target.type.size
val alloc = "$allocated = call i8* @malloc_heap(i32 $size)"
localCode.appendln(alloc)
val cast = "$target = bitcast ${allocated.getType()} $allocated to ${if (asValue) target.type.toString() else target.getType()}*"
val cast = "$target = bitcast ${allocated.getType()} $allocated to ${if (asValue) target.type.toString() else target.getType()}" + if (pointer) "" else "*"
localCode.appendln(cast)
}
@@ -3,6 +3,7 @@ package org.kotlinnative.translator.llvm
import org.jetbrains.kotlin.builtins.isFunctionTypeOrSubtype
import org.jetbrains.kotlin.cfg.pseudocode.getSubtypesPredicate
import org.jetbrains.kotlin.js.descriptorUtils.nameIfStandardType
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isUnit
@@ -52,10 +53,13 @@ fun LLVMInstanceOfStandardType(name: String, type: KotlinType, scope: LLVMScope
fun LLVMMapStandardType(type: KotlinType, state: TranslationState): LLVMType =
LLVMInstanceOfStandardType("type", type, LLVMRegisterScope(), state).type
fun String.addBeforeIfNotEmpty(add: String): String {
return if (this.length > 0) add + this else this
}
fun String.addBeforeIfNotEmpty(add: String): String =
if (this.length > 0) add + this else this
fun String.addAfterIfNotEmpty(add: String): String {
return if (this.length > 0) this + add else this
}
fun String.addAfterIfNotEmpty(add: String): String =
if (this.length > 0) this + add else this
fun FqName.convertToNativeName(): String =
this.asString().replace(".<init>", "")
@@ -15,9 +15,11 @@ fun bytearray_1_array(): Int {
}
val newInstance = z.clone()
ind = 0
var result = true
while(ind < size){
assert(newInstance[ind] == ind.toByte())
result = result and (newInstance[ind] == ind.toByte())
ind += 1
}
assert(result)
return 1
}