translator: rearrange functions in LLVMBuilder for readability

This commit is contained in:
Alexey Stepanov
2016-08-31 19:14:48 +03:00
parent 15edcff509
commit 236cae95c3
2 changed files with 167 additions and 170 deletions
@@ -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<LLVMVariable>) =
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<LLVMVariable>, initializers: Map<LLVMVariable, String>, 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<LLVMVariable>) =
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<LLVMSingleValue>, args: List<LLVMVariable>) =
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<LLVMVariable>, values: List<String>)
= "{ ${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<LLVMSingleValue>, args: List<LLVMVariable>) =
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<LLVMVariable>, initializers: Map<LLVMVariable, String>, 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<LLVMVariable>, values: List<String>)
= "{ ${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<LLVMVariable>) =
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<LLVMVariable>) =
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}")
}
}
@@ -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?) =