working on vm

This commit is contained in:
Irmen de Jong
2022-03-25 20:22:41 +01:00
parent 3e44620966
commit 0307f6b42c
6 changed files with 223 additions and 152 deletions
@@ -27,9 +27,9 @@ class CodeGen(internal val program: PtProgram,
// collect global variables initializers
program.allBlocks().forEach {
val chunk = VmCodeChunk()
it.children.filterIsInstance<PtAssignment>().forEach { assign -> chunk += translate(assign, RegisterUsage(0)) }
vmprog.addGlobalInits(chunk)
val code = VmCodeChunk()
it.children.filterIsInstance<PtAssignment>().forEach { assign -> code += translate(assign, RegisterUsage(0)) }
vmprog.addGlobalInits(code)
}
val regUsage = RegisterUsage(0)
@@ -42,7 +42,7 @@ class CodeGen(internal val program: PtProgram,
private fun translateNode(node: PtNode, regUsage: RegisterUsage): VmCodeChunk {
val chunk = when(node) {
val code = when(node) {
is PtBlock -> translate(node, regUsage)
is PtSub -> translate(node, regUsage)
is PtScopeVarsDecls -> VmCodeChunk() // vars should be looked up via symbol table
@@ -56,13 +56,12 @@ class CodeGen(internal val program: PtProgram,
is PtNop -> VmCodeChunk()
is PtReturn -> translate(node)
is PtJump -> translate(node)
is PtConditionalBranch -> TODO()
is PtWhen -> TODO()
is PtPipe -> TODO()
is PtForLoop -> TODO()
is PtIfElse -> TODO()
is PtIfElse -> translate(node, regUsage)
is PtPostIncrDecr -> translate(node, regUsage)
is PtRepeatLoop -> translate(node, regUsage)
is PtWhen -> TODO()
is PtLabel -> VmCodeChunk(VmCodeLabel(node.scopedName))
is PtBreakpoint -> VmCodeChunk(VmCodeInstruction(Instruction(Opcode.BREAKPOINT)))
is PtAddressOf,
@@ -80,18 +79,60 @@ class CodeGen(internal val program: PtProgram,
is PtSubroutineParameter,
is PtNumber,
is PtArrayLiteral,
is PtString -> throw AssemblyError("$node should not occur as separate statement node")
is PtAsmSub -> throw AssemblyError("asmsub not supported on virtual machine target")
is PtInlineAssembly -> throw AssemblyError("inline assembly not supported on virtual machine target")
is PtIncludeBinary -> throw AssemblyError("inline binary data not supported on virtual machine target")
is PtString -> throw AssemblyError("strings should not occur as separate statement node ${node.position}")
is PtAsmSub -> throw AssemblyError("asmsub not supported on virtual machine target ${node.position}")
is PtInlineAssembly -> throw AssemblyError("inline assembly not supported on virtual machine target ${node.position}")
is PtIncludeBinary -> throw AssemblyError("inline binary data not supported on virtual machine target ${node.position}")
is PtConditionalBranch -> throw AssemblyError("conditional branches not supported in vm target due to lack of cpu flags ${node.position}")
else -> TODO("missing codegen for $node")
}
chunk.lines.add(0, VmCodeComment(node.position.toString()))
return chunk
code.lines.add(0, VmCodeComment(node.position.toString()))
return code
}
private fun translate(ifElse: PtIfElse, regUsage: RegisterUsage): VmCodeChunk {
var branch = Opcode.BZ
var condition = ifElse.condition
val cond = ifElse.condition as? PtBinaryExpression
if((cond?.right as? PtNumber)?.number==0.0) {
if(cond.operator == "==") {
// if X==0 ... so we branch on Not-zero instead.
branch = Opcode.BNZ
condition = cond.left
}
else if(cond.operator == "!=") {
// if X!=0 ... so we keep branching on Zero.
condition = cond.left
}
}
val conditionReg = regUsage.nextFree()
val vmDt = vmType(condition.type)
val code = VmCodeChunk()
code += expressionEval.translateExpression(condition, conditionReg, regUsage)
if(ifElse.elseScope.children.isNotEmpty()) {
// if and else parts
val elseLabel = createLabelName()
val afterIfLabel = createLabelName()
code += VmCodeInstruction(Instruction(branch, vmDt, reg1=conditionReg), labelArg = elseLabel)
code += translateNode(ifElse.ifScope, regUsage)
code += VmCodeInstruction(Instruction(Opcode.JUMP), labelArg = afterIfLabel)
code += VmCodeLabel(elseLabel)
code += translateNode(ifElse.elseScope, regUsage)
code += VmCodeLabel(afterIfLabel)
} else {
// only if part
val afterIfLabel = createLabelName()
code += VmCodeInstruction(Instruction(branch, vmDt, reg1=conditionReg), labelArg = afterIfLabel)
code += translateNode(ifElse.ifScope, regUsage)
code += VmCodeLabel(afterIfLabel)
}
return code
}
private fun translate(postIncrDecr: PtPostIncrDecr, regUsage: RegisterUsage): VmCodeChunk {
val chunk = VmCodeChunk()
val code = VmCodeChunk()
val operation = when(postIncrDecr.operator) {
"++" -> Opcode.INC
"--" -> Opcode.DEC
@@ -104,21 +145,21 @@ class CodeGen(internal val program: PtProgram,
val resultReg = regUsage.nextFree()
if(ident!=null) {
val address = allocations.get(ident.targetName)
chunk += VmCodeInstruction(Instruction(Opcode.LOADM, vmDt, reg1=resultReg, value = address))
chunk += VmCodeInstruction(Instruction(operation, vmDt, reg1=resultReg))
chunk += VmCodeInstruction(Instruction(Opcode.STOREM, vmDt, reg1=resultReg, value = address))
code += VmCodeInstruction(Instruction(Opcode.LOADM, vmDt, reg1=resultReg, value = address))
code += VmCodeInstruction(Instruction(operation, vmDt, reg1=resultReg))
code += VmCodeInstruction(Instruction(Opcode.STOREM, vmDt, reg1=resultReg, value = address))
} else if(memory!=null) {
val addressReg = regUsage.nextFree()
chunk += expressionEval.translateExpression(memory.address, addressReg, regUsage)
chunk += VmCodeInstruction(Instruction(Opcode.LOADI, vmDt, reg1=resultReg, reg2=addressReg))
chunk += VmCodeInstruction(Instruction(operation, vmDt, reg1=resultReg))
chunk += VmCodeInstruction(Instruction(Opcode.STOREI, vmDt, reg1=resultReg, reg2=addressReg))
code += expressionEval.translateExpression(memory.address, addressReg, regUsage)
code += VmCodeInstruction(Instruction(Opcode.LOADI, vmDt, reg1=resultReg, reg2=addressReg))
code += VmCodeInstruction(Instruction(operation, vmDt, reg1=resultReg))
code += VmCodeInstruction(Instruction(Opcode.STOREI, vmDt, reg1=resultReg, reg2=addressReg))
} else if (array!=null) {
TODO("postincrdecr array")
} else
throw AssemblyError("weird assigntarget")
return chunk
return code
}
private fun translate(repeat: PtRepeatLoop, regUsage: RegisterUsage): VmCodeChunk {
@@ -131,43 +172,43 @@ class CodeGen(internal val program: PtProgram,
repeat.children[0] = PtNumber(DataType.UBYTE, 0.0, repeat.count.position)
}
val chunk = VmCodeChunk()
val code = VmCodeChunk()
val counterReg = regUsage.nextFree()
val vmDt = vmType(repeat.count.type)
chunk += expressionEval.translateExpression(repeat.count, counterReg, regUsage)
code += expressionEval.translateExpression(repeat.count, counterReg, regUsage)
val repeatLabel = createLabelName()
chunk += VmCodeLabel(repeatLabel)
chunk += translateNode(repeat.statements, regUsage)
chunk += VmCodeInstruction(Instruction(Opcode.DEC, vmDt, reg1=counterReg))
chunk += VmCodeInstruction(Instruction(Opcode.BNZ, vmDt, reg1=counterReg), labelArg = repeatLabel)
return chunk
code += VmCodeLabel(repeatLabel)
code += translateNode(repeat.statements, regUsage)
code += VmCodeInstruction(Instruction(Opcode.DEC, vmDt, reg1=counterReg))
code += VmCodeInstruction(Instruction(Opcode.BNZ, vmDt, reg1=counterReg), labelArg = repeatLabel)
return code
}
private fun translate(jump: PtJump): VmCodeChunk {
val chunk = VmCodeChunk()
val code = VmCodeChunk()
if(jump.address!=null)
throw AssemblyError("cannot jump to memory location in the vm target")
chunk += if(jump.generatedLabel!=null)
code += if(jump.generatedLabel!=null)
VmCodeInstruction(Instruction(Opcode.JUMP), labelArg = listOf(jump.generatedLabel!!))
else if(jump.identifier!=null)
VmCodeInstruction(Instruction(Opcode.JUMP), labelArg = jump.identifier!!.targetName)
else
throw AssemblyError("weird jump")
return chunk
return code
}
private fun translateGroup(group: List<PtNode>, regUsage: RegisterUsage): VmCodeChunk {
val chunk = VmCodeChunk()
group.forEach { chunk += translateNode(it, regUsage) }
return chunk
val code = VmCodeChunk()
group.forEach { code += translateNode(it, regUsage) }
return code
}
private fun translate(assignment: PtAssignment, regUsage: RegisterUsage): VmCodeChunk {
// TODO optimize in-place assignments (assignment.augmentable = true)
// TODO can in-place assignments (assignment.augmentable = true) be optimized more?
val chunk = VmCodeChunk()
val code = VmCodeChunk()
val resultRegister = regUsage.nextFree()
chunk += expressionEval.translateExpression(assignment.value, resultRegister, regUsage)
code += expressionEval.translateExpression(assignment.value, resultRegister, regUsage)
val ident = assignment.target.identifier
val memory = assignment.target.memory
val array = assignment.target.array
@@ -175,7 +216,7 @@ class CodeGen(internal val program: PtProgram,
if(ident!=null) {
val address = allocations.get(ident.targetName)
val ins = Instruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=address)
chunk += VmCodeInstruction(ins)
code += VmCodeInstruction(ins)
}
else if(array!=null) {
TODO("assign to array")
@@ -186,48 +227,48 @@ class CodeGen(internal val program: PtProgram,
Instruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt())
} else {
val addressRegister = regUsage.nextFree()
chunk += expressionEval.translateExpression(assignment.value, addressRegister, regUsage)
code += expressionEval.translateExpression(assignment.value, addressRegister, regUsage)
Instruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressRegister)
}
chunk += VmCodeInstruction(ins)
code += VmCodeInstruction(ins)
}
else
throw AssemblyError("weird assigntarget")
return chunk
return code
}
private fun translate(ret: PtReturn): VmCodeChunk {
val chunk = VmCodeChunk()
val code = VmCodeChunk()
val value = ret.value
if(value!=null) {
// Call Convention: return value is always returned in r0
chunk += expressionEval.translateExpression(value, 0, RegisterUsage(1))
code += expressionEval.translateExpression(value, 0, RegisterUsage(1))
}
chunk += VmCodeInstruction(Instruction(Opcode.RETURN))
return chunk
code += VmCodeInstruction(Instruction(Opcode.RETURN))
return code
}
private fun translate(sub: PtSub, regUsage: RegisterUsage): VmCodeChunk {
// TODO actually inline subroutines marked as inline
val chunk = VmCodeChunk()
chunk += VmCodeComment("SUB: ${sub.scopedName} -> ${sub.returntype}")
chunk += VmCodeLabel(sub.scopedName)
val code = VmCodeChunk()
code += VmCodeComment("SUB: ${sub.scopedName} -> ${sub.returntype}")
code += VmCodeLabel(sub.scopedName)
for (child in sub.children) {
chunk += translateNode(child, regUsage)
code += translateNode(child, regUsage)
}
chunk += VmCodeComment("SUB-END '${sub.name}'")
return chunk
code += VmCodeComment("SUB-END '${sub.name}'")
return code
}
private fun translate(block: PtBlock, regUsage: RegisterUsage): VmCodeChunk {
val chunk = VmCodeChunk()
chunk += VmCodeComment("BLOCK '${block.name}' addr=${block.address} lib=${block.library}")
val code = VmCodeChunk()
code += VmCodeComment("BLOCK '${block.name}' addr=${block.address} lib=${block.library}")
for (child in block.children) {
if(child !is PtAssignment) // global variable initialization is done elsewhere
chunk += translateNode(child, regUsage)
code += translateNode(child, regUsage)
}
chunk += VmCodeComment("BLOCK-END '${block.name}'")
return chunk
code += VmCodeComment("BLOCK-END '${block.name}'")
return code
}
@@ -23,16 +23,16 @@ internal class ExpressionGen(val codeGen: CodeGen) {
fun translateExpression(expr: PtExpression, resultRegister: Int, regUsage: RegisterUsage): VmCodeChunk {
require(regUsage.firstFree > resultRegister)
val chunk = VmCodeChunk()
val code = VmCodeChunk()
val vmDt = codeGen.vmType(expr.type)
when (expr) {
is PtNumber -> {
chunk += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=expr.number.toInt()))
code += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=expr.number.toInt()))
}
is PtIdentifier -> {
val mem = codeGen.allocations.get(expr.targetName)
chunk += if(expr.type in PassByValueDatatypes) {
code += if(expr.type in PassByValueDatatypes) {
VmCodeInstruction(Instruction(Opcode.LOADM, vmDt, reg1=resultRegister, value=mem))
} else {
// for strings and arrays etc., load the *address* of the value instead
@@ -41,19 +41,19 @@ internal class ExpressionGen(val codeGen: CodeGen) {
}
is PtAddressOf -> {
val mem = codeGen.allocations.get(expr.identifier.targetName)
chunk += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=mem))
code += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=mem))
}
is PtMemoryByte -> {
val addressRegister = regUsage.nextFree()
val addressExprCode = translateExpression(expr.address, addressRegister, regUsage)
chunk += addressExprCode
code += addressExprCode
}
is PtTypeCast -> chunk += translate(expr, resultRegister, regUsage)
is PtPrefix -> chunk += translate(expr, resultRegister, regUsage)
is PtArrayIndexer -> chunk += translate(expr, resultRegister, regUsage)
is PtBinaryExpression -> chunk += translate(expr, resultRegister, regUsage)
is PtBuiltinFunctionCall -> chunk += translate(expr, resultRegister, regUsage)
is PtFunctionCall -> chunk += translate(expr, resultRegister, regUsage)
is PtTypeCast -> code += translate(expr, resultRegister, regUsage)
is PtPrefix -> code += translate(expr, resultRegister, regUsage)
is PtArrayIndexer -> code += translate(expr, resultRegister, regUsage)
is PtBinaryExpression -> code += translate(expr, resultRegister, regUsage)
is PtBuiltinFunctionCall -> code += translate(expr, resultRegister, regUsage)
is PtFunctionCall -> code += translate(expr, resultRegister, regUsage)
is PtContainmentCheck -> TODO()
is PtPipe -> TODO()
is PtRange,
@@ -61,60 +61,59 @@ internal class ExpressionGen(val codeGen: CodeGen) {
is PtString -> throw AssemblyError("range/arrayliteral/string should no longer occur as expression")
else -> throw AssemblyError("weird expression")
}
return chunk
return code
}
private fun translate(arrayIx: PtArrayIndexer, resultRegister: Int, regUsage: RegisterUsage): VmCodeChunk {
val eltSize = codeGen.program.memsizer.memorySize(arrayIx.type)
val vmDt = codeGen.vmType(arrayIx.type)
val chunk = VmCodeChunk()
val code = VmCodeChunk()
val idxReg = regUsage.nextFree()
chunk += translateExpression(arrayIx.index, idxReg, regUsage)
code += translateExpression(arrayIx.index, idxReg, regUsage)
if(eltSize>1) {
val factorReg = regUsage.nextFree()
chunk += VmCodeInstruction(Instruction(Opcode.LOAD, VmDataType.BYTE, reg1=factorReg, value=eltSize))
chunk += VmCodeInstruction(Instruction(Opcode.MUL, VmDataType.BYTE, reg1=idxReg, reg2=factorReg))
code += VmCodeInstruction(Instruction(Opcode.LOAD, VmDataType.BYTE, reg1=factorReg, value=eltSize))
code += VmCodeInstruction(Instruction(Opcode.MUL, VmDataType.BYTE, reg1=idxReg, reg2=factorReg))
}
val arrayLocation = codeGen.allocations.get(arrayIx.variable.targetName)
chunk += VmCodeInstruction(Instruction(Opcode.LOADX, vmDt, reg1=resultRegister, reg2=idxReg, value = arrayLocation))
return chunk
code += VmCodeInstruction(Instruction(Opcode.LOADX, vmDt, reg1=resultRegister, reg2=idxReg, value = arrayLocation))
return code
}
private fun translate(expr: PtPrefix, resultRegister: Int, regUsage: RegisterUsage): VmCodeChunk {
// operator can be: +, -, ~, not
val chunk = VmCodeChunk()
chunk += translateExpression(expr.value, resultRegister, regUsage)
val code = VmCodeChunk()
code += translateExpression(expr.value, resultRegister, regUsage)
val vmDt = codeGen.vmType(expr.type)
when(expr.operator) {
"+" -> { }
"-" -> {
chunk += VmCodeInstruction(Instruction(Opcode.NEG, vmDt, reg1=resultRegister))
code += VmCodeInstruction(Instruction(Opcode.NEG, vmDt, reg1=resultRegister))
}
"~" -> {
val regMask = regUsage.nextFree()
val mask = if(vmDt==VmDataType.BYTE) 0x00ff else 0xffff
chunk += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=regMask, value=mask))
chunk += VmCodeInstruction(Instruction(Opcode.XOR, vmDt, reg1=resultRegister, reg2=resultRegister, reg3=regMask))
code += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=regMask, value=mask))
code += VmCodeInstruction(Instruction(Opcode.XOR, vmDt, reg1=resultRegister, reg2=resultRegister, reg3=regMask))
}
"not" -> {
val label = codeGen.createLabelName()
chunk += VmCodeInstruction(Instruction(Opcode.BZ, vmDt, reg1=resultRegister), labelArg = label)
chunk += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=1))
chunk += VmCodeLabel(label)
code += VmCodeInstruction(Instruction(Opcode.BZ, vmDt, reg1=resultRegister), labelArg = label)
code += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=1))
code += VmCodeLabel(label)
val regMask = regUsage.nextFree()
chunk += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=regMask, value=1))
chunk += VmCodeInstruction(Instruction(Opcode.XOR, vmDt, reg1=resultRegister, reg2=resultRegister, reg3=regMask))
code += VmCodeInstruction(Instruction(Opcode.LOAD, vmDt, reg1=regMask, value=1))
code += VmCodeInstruction(Instruction(Opcode.XOR, vmDt, reg1=resultRegister, reg2=resultRegister, reg3=regMask))
}
else -> throw AssemblyError("weird prefix operator")
}
return chunk
return code
}
private fun translate(cast: PtTypeCast, resultRegister: Int, regUsage: RegisterUsage): VmCodeChunk {
val chunk = VmCodeChunk()
val code = VmCodeChunk()
if(cast.type==cast.value.type)
return chunk
chunk += translateExpression(cast.value, resultRegister, regUsage)
return code
code += translateExpression(cast.value, resultRegister, regUsage)
when(cast.type) {
DataType.UBYTE -> {
when(cast.value.type) {
@@ -138,11 +137,11 @@ internal class ExpressionGen(val codeGen: CodeGen) {
when(cast.value.type) {
DataType.BYTE -> {
// byte -> uword: sign extend
chunk += VmCodeInstruction(Instruction(Opcode.EXTS, type = VmDataType.BYTE, reg1 = resultRegister))
code += VmCodeInstruction(Instruction(Opcode.EXTS, type = VmDataType.BYTE, reg1 = resultRegister))
}
DataType.UBYTE -> {
// ubyte -> uword: sign extend
chunk += VmCodeInstruction(Instruction(Opcode.EXT, type = VmDataType.BYTE, reg1 = resultRegister))
code += VmCodeInstruction(Instruction(Opcode.EXT, type = VmDataType.BYTE, reg1 = resultRegister))
}
DataType.WORD -> { }
DataType.FLOAT -> {
@@ -155,11 +154,11 @@ internal class ExpressionGen(val codeGen: CodeGen) {
when(cast.value.type) {
DataType.BYTE -> {
// byte -> word: sign extend
chunk += VmCodeInstruction(Instruction(Opcode.EXTS, type = VmDataType.BYTE, reg1 = resultRegister))
code += VmCodeInstruction(Instruction(Opcode.EXTS, type = VmDataType.BYTE, reg1 = resultRegister))
}
DataType.UBYTE -> {
// byte -> word: sign extend
chunk += VmCodeInstruction(Instruction(Opcode.EXT, type = VmDataType.BYTE, reg1 = resultRegister))
code += VmCodeInstruction(Instruction(Opcode.EXT, type = VmDataType.BYTE, reg1 = resultRegister))
}
DataType.UWORD -> { }
DataType.FLOAT -> {
@@ -188,105 +187,126 @@ internal class ExpressionGen(val codeGen: CodeGen) {
}
else -> throw AssemblyError("weird cast type")
}
return chunk
return code
}
private fun translate(binExpr: PtBinaryExpression, resultRegister: Int, regUsage: RegisterUsage): VmCodeChunk {
val chunk = VmCodeChunk()
val code = VmCodeChunk()
val leftResultReg = regUsage.nextFree()
val rightResultReg = regUsage.nextFree()
val leftCode = translateExpression(binExpr.left, leftResultReg, regUsage)
val rightCode = translateExpression(binExpr.right, rightResultReg, regUsage)
chunk += leftCode
chunk += rightCode
// TODO: optimized codegen when left or right operand is known 0 or 1 or whatever.
code += leftCode
code += rightCode
val vmDt = codeGen.vmType(binExpr.type)
when(binExpr.operator) {
"+" -> {
chunk += VmCodeInstruction(Instruction(Opcode.ADD, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
code += VmCodeInstruction(Instruction(Opcode.ADD, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
}
"-" -> {
chunk += VmCodeInstruction(Instruction(Opcode.SUB, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
code += VmCodeInstruction(Instruction(Opcode.SUB, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
}
"*" -> {
chunk += VmCodeInstruction(Instruction(Opcode.MUL, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
code += VmCodeInstruction(Instruction(Opcode.MUL, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
}
"/" -> {
chunk += VmCodeInstruction(Instruction(Opcode.DIV, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
code += VmCodeInstruction(Instruction(Opcode.DIV, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
}
"%" -> {
chunk += VmCodeInstruction(Instruction(Opcode.MOD, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
code += VmCodeInstruction(Instruction(Opcode.MOD, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
}
"|", "or" -> {
code += VmCodeInstruction(Instruction(Opcode.OR, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
}
"&", "and" -> {
code += VmCodeInstruction(Instruction(Opcode.AND, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
}
"^", "xor" -> {
code += VmCodeInstruction(Instruction(Opcode.XOR, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
}
"<<" -> {
// TODO check if shift amount works
code += VmCodeInstruction(Instruction(Opcode.LSL, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
}
">>" -> {
// TODO check if shift amount works
code += VmCodeInstruction(Instruction(Opcode.LSR, vmDt, reg1=resultRegister, reg2=leftResultReg, reg3=rightResultReg))
}
"**" -> throw AssemblyError("** operator requires floating point ${binExpr.position}")
// TODO the other operators: "<<", ">>", "==", "!=", "<", ">", "<=", ">="
else -> TODO("operator ${binExpr.operator}")
}
return chunk
return code
}
fun translate(fcall: PtFunctionCall, resultRegister: Int, regUsage: RegisterUsage): VmCodeChunk {
val subroutine = codeGen.symbolTable.flat.getValue(fcall.functionName) as StSub
val chunk = VmCodeChunk()
val code = VmCodeChunk()
for ((arg, parameter) in fcall.args.zip(subroutine.parameters)) {
val argReg = regUsage.nextFree()
chunk += translateExpression(arg, argReg, regUsage)
code += translateExpression(arg, argReg, regUsage)
val vmDt = codeGen.vmType(parameter.type)
val mem = codeGen.allocations.get(fcall.functionName + parameter.name)
chunk += VmCodeInstruction(Instruction(Opcode.STOREM, vmDt, reg1=argReg, value=mem))
code += VmCodeInstruction(Instruction(Opcode.STOREM, vmDt, reg1=argReg, value=mem))
}
chunk += VmCodeInstruction(Instruction(Opcode.CALL), labelArg=fcall.functionName)
code += VmCodeInstruction(Instruction(Opcode.CALL), labelArg=fcall.functionName)
if(!fcall.void && resultRegister!=0) {
// Call convention: result value is in r0, so put it in the required register instead.
chunk += VmCodeInstruction(Instruction(Opcode.LOADR, codeGen.vmType(fcall.type), reg1=resultRegister, reg2=0))
code += VmCodeInstruction(Instruction(Opcode.LOADR, codeGen.vmType(fcall.type), reg1=resultRegister, reg2=0))
}
return chunk
return code
}
fun translate(call: PtBuiltinFunctionCall, resultRegister: Int, regUsage: RegisterUsage): VmCodeChunk {
val chunk = VmCodeChunk()
val code = VmCodeChunk()
when(call.name) {
"syscall" -> {
val vExpr = call.args.single() as PtNumber
chunk += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=vExpr.number.toInt()))
code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=vExpr.number.toInt()))
}
"syscall1" -> {
chunk += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.BYTE, reg1 = 0))
code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.BYTE, reg1 = 0))
val callNr = (call.args[0] as PtNumber).number.toInt()
chunk += translateExpression(call.args[1], 0, regUsage)
chunk += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=callNr))
chunk += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.BYTE, reg1 = 0))
code += translateExpression(call.args[1], 0, regUsage)
code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=callNr))
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.BYTE, reg1 = 0))
}
"syscall2" -> {
chunk += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.BYTE, reg1 = 0))
chunk += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.WORD, reg1 = 1))
code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.BYTE, reg1 = 0))
code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.WORD, reg1 = 1))
while(regUsage.firstFree<2) {
regUsage.nextFree()
}
val callNr = (call.args[0] as PtNumber).number.toInt()
chunk += translateExpression(call.args[1], 0, regUsage)
chunk += translateExpression(call.args[2], 1, regUsage)
chunk += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=callNr))
chunk += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.WORD, reg1 = 1))
chunk += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.BYTE, reg1 = 0))
code += translateExpression(call.args[1], 0, regUsage)
code += translateExpression(call.args[2], 1, regUsage)
code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=callNr))
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.WORD, reg1 = 1))
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.BYTE, reg1 = 0))
}
"syscall3" -> {
chunk += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.BYTE, reg1 = 0))
chunk += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.WORD, reg1 = 1))
chunk += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.WORD, reg1 = 2))
code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.BYTE, reg1 = 0))
code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.WORD, reg1 = 1))
code += VmCodeInstruction(Instruction(Opcode.PUSH, VmDataType.WORD, reg1 = 2))
while(regUsage.firstFree<3) {
regUsage.nextFree()
}
val callNr = (call.args[0] as PtNumber).number.toInt()
chunk += translateExpression(call.args[1], 0, regUsage)
chunk += translateExpression(call.args[2], 1, regUsage)
chunk += translateExpression(call.args[3], 2, regUsage)
chunk += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=callNr))
chunk += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.WORD, reg1 = 2))
chunk += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.WORD, reg1 = 1))
chunk += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.BYTE, reg1 = 0))
code += translateExpression(call.args[1], 0, regUsage)
code += translateExpression(call.args[2], 1, regUsage)
code += translateExpression(call.args[3], 2, regUsage)
code += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=callNr))
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.WORD, reg1 = 2))
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.WORD, reg1 = 1))
code += VmCodeInstruction(Instruction(Opcode.POP, VmDataType.BYTE, reg1 = 0))
}
else -> {
// TODO builtin functions...
TODO("builtinfunc ${call.name}")
}
}
return chunk
return code
}
}