diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMBuilder.kt b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMBuilder.kt index 783df864547..7f96a8c87b4 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMBuilder.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/LLVMBuilder.kt @@ -18,6 +18,118 @@ class LLVMBuilder(val arm: Boolean = false) { initBuilder() } + fun addLLVMCodeToLocalPlace(code: String) = + localCode.appendln(code) + + fun addLLVMCodeToGlobalPlace(code: String) = + globalCode.appendln(code) + + fun addComment(comment: String) = + addLLVMCodeToLocalPlace("; " + comment) + + fun addStartExpression() = + addLLVMCodeToLocalPlace("{") + + fun addEndExpression() = + addLLVMCodeToLocalPlace("}") + + fun addAssignment(lhs: LLVMVariable, rhs: LLVMNode) = + addLLVMCodeToLocalPlace("$lhs = $rhs") + + fun addReturnOperator(llvmVariable: LLVMSingleValue) = + addLLVMCodeToLocalPlace("ret ${llvmVariable.type} $llvmVariable") + + fun addAnyReturn(type: LLVMType, value: String = type.defaultValue, pointer: Int = 0) = + addLLVMCodeToLocalPlace("ret $type${"*".repeat(pointer)} $value") + + fun addStringConstant(variable: LLVMVariable, value: String) = + addLLVMCodeToGlobalPlace("$variable = private unnamed_addr constant ${(variable.type as LLVMStringType).fullArrayType} c\"${value.replace("\"", "\\\"")}\\00\", align 1") + + fun addVariableByRef(targetVariable: LLVMVariable, sourceVariable: LLVMVariable, store: Boolean) { + addLLVMCodeToLocalPlace("$targetVariable = alloca ${sourceVariable.pointedType}, align ${sourceVariable.type.align}") + + if (store) { + addLLVMCodeToLocalPlace("store ${sourceVariable.pointedType} $sourceVariable, ${targetVariable.pointedType} $targetVariable, align ${targetVariable.type.align}") + } + } + + fun addCondition(condition: LLVMSingleValue, thenLabel: LLVMLabel, elseLabel: LLVMLabel) = + addLLVMCodeToLocalPlace("br ${condition.pointedType} $condition, label $thenLabel, label $elseLabel") + + fun addUnconditionalJump(label: LLVMLabel) = + addLLVMCodeToLocalPlace("br label $label") + + fun addExceptionCall(exceptionName: String) { + val exception = exceptions[exceptionName] + val printResult = getNewVariable(LLVMIntType(), pointer = 0) + addLLVMCodeToLocalPlace("$printResult = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds (${(exception!!.type as LLVMStringType).fullArrayType}* $exception, i32 0, i32 0))") + addFunctionCall(LLVMVariable("abort", LLVMVoidType(), scope = LLVMVariableScope()), emptyList()) + } + + fun addFunctionCall(functionName: LLVMVariable, arguments: List) = + addLLVMCodeToLocalPlace("call ${functionName.type} $functionName(${arguments.joinToString { it -> "${it.type} $it" }})") + + fun allocStackVar(target: LLVMVariable, asValue: Boolean = false, pointer: Boolean = false) { + val type = if (asValue) target.type.toString() else target.pointedType + addLLVMCodeToLocalPlace("$target = alloca ${if (pointer) type.removeSuffix("*") else type}, align ${target.type.align}") + } + + fun allocStaticVar(target: LLVMVariable, asValue: Boolean = false, pointer: Boolean = false) { + val allocated = getNewVariable(LLVMCharType(), pointer = 1) + val size = if ((target.pointer >= 2) || (target.pointer >= 1 && !pointer)) TranslationState.POINTER_SIZE else target.type.size + + addLLVMCodeToLocalPlace("$allocated = call i8* @malloc_heap(i32 $size)") + addLLVMCodeToLocalPlace("$target = bitcast ${allocated.pointedType} $allocated to ${if (asValue) target.type.toString() else target.pointedType}" + if (pointer) "" else "*") + } + + fun addGlobalInitialize(target: LLVMVariable, fields: ArrayList, initializers: Map, classType: LLVMType) { + val code = "$target = internal global $classType { ${ + fields.map { it.pointedType + " " + if (initializers.containsKey(it)) initializers[it] else "0" }.joinToString() + } }, align ${classType.align}" + addLLVMCodeToGlobalPlace(code) + } + + fun bitcast(src: LLVMVariable, llvmType: LLVMVariable): LLVMVariable { + val empty = getNewVariable(llvmType.type, pointer = llvmType.pointer) + addLLVMCodeToLocalPlace("$empty = bitcast ${src.pointedType} $src to ${llvmType.pointedType}") + return empty + } + + fun clean() { + localCode = StringBuilder() + globalCode = StringBuilder() + initBuilder() + } + + fun convertVariableToType(variable: LLVMSingleValue, targetType: LLVMType): LLVMSingleValue { + var resultVariable = variable + if (variable.type != targetType) { + val convertedExpression = targetType.convertFrom(variable) + resultVariable = storeExpression(convertedExpression) + } + return resultVariable + } + + fun copyVariable(from: LLVMVariable, to: LLVMVariable) = + when { + from.type is LLVMStringType && !from.type.isLoaded -> storeString(to, from, 0) + else -> copyVariableValue(to, from) + } + + fun createClass(name: String, fields: List) = + addLLVMCodeToGlobalPlace("%class.$name = type { ${fields.map { it.pointedType }.joinToString()} }") + + fun declareEntryPoint(name: String) { + addLLVMCodeToLocalPlace("define weak void @main()") + addStartExpression() + addFunctionCall(LLVMVariable(name, LLVMVoidType(), scope = LLVMVariableScope()), listOf()) + addAnyReturn(LLVMVoidType()) + addEndExpression() + } + + fun defineGlobalVariable(variable: LLVMVariable, defaultValue: String = variable.type.defaultValue) = + addLLVMCodeToLocalPlace("$variable = global ${variable.pointedType} $defaultValue, align ${variable.type.align}") + fun getNewVariable(type: LLVMType, pointer: Int = 0, kotlinName: String? = null, scope: LLVMScope = LLVMRegisterScope(), prefix: String = "var"): LLVMVariable { variableCount++ return LLVMVariable("$prefix$variableCount", type, kotlinName, scope, pointer) @@ -28,17 +140,47 @@ class LLVMBuilder(val arm: Boolean = false) { return LLVMLabel("label.$prefix.$labelCount", scope) } - fun addLLVMCodeToLocalPlace(code: String) = - localCode.appendln(code) + fun loadArgsIfRequired(names: List, args: List) = + names.mapIndexed(fun(i: Int, value: LLVMSingleValue): LLVMSingleValue { + return receivePointedArgument(value, args[i].pointer) + }).toList() - fun addLLVMCodeToGlobalPlace(code: String) = - globalCode.appendln(code) + fun loadArgument(llvmVariable: LLVMVariable, store: Boolean = true): LLVMVariable { + val allocVar = LLVMVariable("${llvmVariable.label}.addr", llvmVariable.type, llvmVariable.kotlinName, LLVMRegisterScope(), pointer = llvmVariable.pointer + 1) + addVariableByRef(allocVar, llvmVariable, store) + return allocVar + } - fun addStartExpression() = - addLLVMCodeToLocalPlace("{") + fun loadClassField(target: LLVMVariable, source: LLVMVariable, offset: Int) = + addLLVMCodeToLocalPlace("$target = getelementptr inbounds ${source.pointedType} $source, i32 0, i32 $offset") - fun addEndExpression() = - addLLVMCodeToLocalPlace("}") + fun loadVariableOffset(target: LLVMVariable, source: LLVMVariable, index: LLVMConstant) = + addLLVMCodeToLocalPlace("$target = getelementptr inbounds ${source.type} $source, ${index.type} ${index.value}") + + fun loadAndGetVariable(source: LLVMVariable): LLVMVariable { + assert(source.pointer > 0) + val target = getNewVariable(source.type, source.pointer - 1, source.kotlinName) + addLLVMCodeToLocalPlace("$target = load ${source.pointedType} $source, align ${target.type.align}") + return target + } + + fun makeStructInitializer(args: List, values: List) + = "{ ${args.mapIndexed { i: Int, variable: LLVMVariable -> "${variable.type} ${values[i]}" }.joinToString()} }" + + fun markWithLabel(label: LLVMLabel?) { + if (label != null) + addLLVMCodeToLocalPlace("${label.label}:") + } + + fun memcpy(castedDst: LLVMVariable, castedSrc: LLVMVariable, size: Int, align: Int = 4, volatile: Boolean = false) = + addLLVMCodeToLocalPlace("call void @llvm.memcpy.p0i8.p0i8.i64(i8* $castedDst, i8* $castedSrc, i64 $size, i32 $align, i1 $volatile)") + + fun nullCheck(variable: LLVMVariable): LLVMVariable { + val result = getNewVariable(LLVMBooleanType(), pointer = 0) + val loaded = loadAndGetVariable(variable) + addLLVMCodeToLocalPlace("$result = icmp eq ${loaded.pointedType} null, $loaded") + return result + } fun receiveNativeValue(firstOp: LLVMSingleValue): LLVMSingleValue = when { @@ -47,11 +189,6 @@ class LLVMBuilder(val arm: Boolean = false) { else -> throw UnexpectedException("Unknown inheritor of LLVMSingleValue") } - fun loadArgsIfRequired(names: List, args: List) = - names.mapIndexed(fun(i: Int, value: LLVMSingleValue): LLVMSingleValue { - return receivePointedArgument(value, args[i].pointer) - }).toList() - fun receivePointedArgument(value: LLVMSingleValue, pointer: Int): LLVMSingleValue { var result = value @@ -69,53 +206,11 @@ class LLVMBuilder(val arm: Boolean = false) { return result } - fun clean() { - localCode = StringBuilder() - globalCode = StringBuilder() - initBuilder() - } - - fun addAssignment(lhs: LLVMVariable, rhs: LLVMNode) = - addLLVMCodeToLocalPlace("$lhs = $rhs") - - fun addReturnOperator(llvmVariable: LLVMSingleValue) = - addLLVMCodeToLocalPlace("ret ${llvmVariable.type} $llvmVariable") - - fun addAnyReturn(type: LLVMType, value: String = type.defaultValue, pointer: Int = 0) = - addLLVMCodeToLocalPlace("ret $type${"*".repeat(pointer)} $value") - - fun addStringConstant(variable: LLVMVariable, value: String) = - addLLVMCodeToGlobalPlace("$variable = private unnamed_addr constant ${(variable.type as LLVMStringType).fullArrayType} c\"${value.replace("\"", "\\\"")}\\00\", align 1") - - fun convertVariableToType(variable: LLVMSingleValue, targetType: LLVMType): LLVMSingleValue { - var resultVariable = variable - if (variable.type != targetType) { - val convertedExpression = targetType.convertFrom(variable) - resultVariable = storeExpression(convertedExpression) - } - return resultVariable - } - - fun addGlobalInitialize(target: LLVMVariable, fields: ArrayList, initializers: Map, classType: LLVMType) { - val code = "$target = internal global $classType { ${ - fields.map { it.pointedType + " " + if (initializers.containsKey(it)) initializers[it] else "0" }.joinToString() - } }, align ${classType.align}" - globalCode.appendln(code) - } - fun storeString(target: LLVMVariable, source: LLVMVariable, offset: Int) { val code = "store ${target.type} getelementptr inbounds (" + "${(source.type as LLVMStringType).fullArrayType}* $source, i32 0, i32 $offset), ${target.pointedType} $target, align ${source.type.align}" (target.type as LLVMStringType).isLoaded = true - localCode.appendln(code) - } - - fun loadClassField(target: LLVMVariable, source: LLVMVariable, offset: Int) = - addLLVMCodeToLocalPlace("$target = getelementptr inbounds ${source.pointedType} $source, i32 0, i32 $offset") - - fun markWithLabel(label: LLVMLabel?) { - if (label != null) - addLLVMCodeToLocalPlace("${label.label}:") + addLLVMCodeToLocalPlace(code) } fun storeVariable(target: LLVMSingleValue, source: LLVMSingleValue) { @@ -135,106 +230,17 @@ class LLVMBuilder(val arm: Boolean = false) { fun storeNull(result: LLVMVariable) = addLLVMCodeToLocalPlace("store ${result.pointedType.dropLast(1)} null, ${result.pointedType} $result, align ${TranslationState.POINTER_ALIGN}") - fun nullCheck(variable: LLVMVariable): LLVMVariable { - val result = getNewVariable(LLVMBooleanType(), pointer = 0) - val loaded = loadAndGetVariable(variable) - addLLVMCodeToLocalPlace("$result = icmp eq ${loaded.pointedType} null, $loaded") - return result - } - - fun addComment(comment: String) = - addLLVMCodeToLocalPlace("; " + comment) - - fun loadVariableOffset(target: LLVMVariable, source: LLVMVariable, index: LLVMConstant) = - addLLVMCodeToLocalPlace("$target = getelementptr inbounds ${source.type} $source, ${index.type} ${index.value}") - - fun copyVariable(from: LLVMVariable, to: LLVMVariable) = - when { - from.type is LLVMStringType && !from.type.isLoaded -> storeString(to, from, 0) - else -> copyVariableValue(to, from) - } - - fun loadArgument(llvmVariable: LLVMVariable, store: Boolean = true): LLVMVariable { - val allocVar = LLVMVariable("${llvmVariable.label}.addr", llvmVariable.type, llvmVariable.kotlinName, LLVMRegisterScope(), pointer = llvmVariable.pointer + 1) - addVariableByRef(allocVar, llvmVariable, store) - return allocVar - } - - fun allocStackVar(target: LLVMVariable, asValue: Boolean = false, pointer: Boolean = false) { - val type = if (asValue) target.type.toString() else target.pointedType - addLLVMCodeToLocalPlace("$target = alloca ${if (pointer) type.removeSuffix("*") else type}, align ${target.type.align}") - } - - fun allocStaticVar(target: LLVMVariable, asValue: Boolean = false, pointer: Boolean = false) { - val allocated = getNewVariable(LLVMCharType(), pointer = 1) - - val size = if ((target.pointer >= 2) || (target.pointer >= 1 && !pointer)) TranslationState.POINTER_SIZE else target.type.size - addLLVMCodeToLocalPlace("$allocated = call i8* @malloc_heap(i32 $size)") - - addLLVMCodeToLocalPlace("$target = bitcast ${allocated.pointedType} $allocated to ${if (asValue) target.type.toString() else target.pointedType}" + if (pointer) "" else "*") - } - - fun addVariableByRef(targetVariable: LLVMVariable, sourceVariable: LLVMVariable, store: Boolean) { - addLLVMCodeToLocalPlace("$targetVariable = alloca ${sourceVariable.pointedType}, align ${sourceVariable.type.align}") - - if (store) { - addLLVMCodeToLocalPlace("store ${sourceVariable.pointedType} $sourceVariable, ${targetVariable.pointedType} $targetVariable, align ${targetVariable.type.align}") - } - } - - fun defineGlobalVariable(variable: LLVMVariable, defaultValue: String = variable.type.defaultValue) = - addLLVMCodeToLocalPlace("$variable = global ${variable.pointedType} $defaultValue, align ${variable.type.align}") - - fun makeStructInitializer(args: List, values: List) - = "{ ${args.mapIndexed { i: Int, variable: LLVMVariable -> "${variable.type} ${values[i]}" }.joinToString()} }" - - fun loadAndGetVariable(source: LLVMVariable): LLVMVariable { - assert(source.pointer > 0) - val target = getNewVariable(source.type, source.pointer - 1, source.kotlinName) - addLLVMCodeToLocalPlace("$target = load ${source.pointedType} $source, align ${target.type.align}") - return target - } - - fun addCondition(condition: LLVMSingleValue, thenLabel: LLVMLabel, elseLabel: LLVMLabel) = - addLLVMCodeToLocalPlace("br ${condition.pointedType} $condition, label $thenLabel, label $elseLabel") - - fun addUnconditionalJump(label: LLVMLabel) = - addLLVMCodeToLocalPlace("br label $label") - - fun createClass(name: String, fields: List) = - addLLVMCodeToGlobalPlace("%class.$name = type { ${fields.map { it.pointedType }.joinToString()} }") - - fun bitcast(src: LLVMVariable, llvmType: LLVMVariable): LLVMVariable { - val empty = getNewVariable(llvmType.type, pointer = llvmType.pointer) - addLLVMCodeToLocalPlace("$empty = bitcast ${src.pointedType} $src to ${llvmType.pointedType}") - return empty - } - - fun addExceptionCall(exceptionName: String) { - val exception = exceptions[exceptionName] - val printResult = getNewVariable(LLVMIntType(), pointer = 0) - addLLVMCodeToLocalPlace("$printResult = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds (${(exception!!.type as LLVMStringType).fullArrayType}* $exception, i32 0, i32 0))") - addFunctionCall(LLVMVariable("abort", LLVMVoidType(), scope = LLVMVariableScope()), emptyList()) - } - - fun addFunctionCall(functionName: LLVMVariable, arguments: List) = - addLLVMCodeToLocalPlace("call ${functionName.type} $functionName(${arguments.joinToString { it -> "${it.type} $it" }})") - - - fun memcpy(castedDst: LLVMVariable, castedSrc: LLVMVariable, size: Int, align: Int = 4, volatile: Boolean = false) = - addLLVMCodeToLocalPlace("call void @llvm.memcpy.p0i8.p0i8.i64(i8* $castedDst, i8* $castedSrc, i64 $size, i32 $align, i1 $volatile)") - - - fun declareEntryPoint(name: String) { - addLLVMCodeToLocalPlace("define weak void @main()") - addStartExpression() - addFunctionCall(LLVMVariable(name, LLVMVoidType(), scope = LLVMVariableScope()), listOf()) - addAnyReturn(LLVMVoidType()) - addEndExpression() - } - override fun toString() = globalCode.toString() + localCode.toString() + private fun copyVariableValue(target: LLVMVariable, source: LLVMVariable) { + var from = source + if (source.pointer > 0) { + from = getNewVariable(source.type, source.pointer) + addLLVMCodeToLocalPlace("$from = load ${source.pointedType} $source, align ${from.type.align}") + } + addLLVMCodeToLocalPlace("store ${target.type} $from, ${target.pointedType} $target, align ${from.type.align}") + } + private fun initBuilder() { val declares = arrayOf( "declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1)", @@ -260,13 +266,4 @@ class LLVMBuilder(val arm: Boolean = false) { return result } - private fun copyVariableValue(target: LLVMVariable, source: LLVMVariable) { - var from = source - if (source.pointer > 0) { - from = getNewVariable(source.type, source.pointer) - addLLVMCodeToLocalPlace("$from = load ${source.pointedType} $source, align ${from.type.align}") - } - addLLVMCodeToLocalPlace("store ${target.type} $from, ${target.pointedType} $target, align ${from.type.align}") - } - } \ No newline at end of file diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMByteType.kt b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMByteType.kt index 52f88bbf7f4..372b3c1cfe7 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMByteType.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/llvm/types/LLVMByteType.kt @@ -12,25 +12,25 @@ class LLVMByteType() : LLVMType() { override val defaultValue = "0" override val isPrimitive = true - override fun operatorLt(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression = + override fun operatorLt(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) = LLVMExpression(LLVMBooleanType(), "icmp slt i8 $firstOp, $secondOp") - override fun operatorGt(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression = + override fun operatorGt(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) = LLVMExpression(LLVMBooleanType(), "icmp sgt i8 $firstOp, $secondOp") - override fun operatorLeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression = + override fun operatorLeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) = LLVMExpression(LLVMBooleanType(), "icmp sle i8 $firstOp, $secondOp") - override fun operatorGeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression = + override fun operatorGeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) = LLVMExpression(LLVMBooleanType(), "icmp sge i8 $firstOp, $secondOp") - override fun operatorEq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression = + override fun operatorEq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) = LLVMExpression(LLVMBooleanType(), "icmp eq i8" + (if ((firstOp.pointer > 0) || (secondOp.pointer > 0)) "*" else "") + " $firstOp, $secondOp") - override fun operatorNeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression = + override fun operatorNeq(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) = LLVMExpression(LLVMBooleanType(), "icmp ne i8" + (if ((firstOp.pointer > 0) || (secondOp.pointer > 0)) "*" else "") + " $firstOp, $secondOp") - override fun operatorMod(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue): LLVMExpression = + override fun operatorMod(firstOp: LLVMSingleValue, secondOp: LLVMSingleValue) = LLVMExpression(LLVMByteType(), "srem i8 $firstOp, $secondOp") override fun equals(other: Any?) =