vm: added swap()

This commit is contained in:
Irmen de Jong
2022-04-11 01:31:34 +02:00
parent ec7501782d
commit ec6ac5bf24
7 changed files with 90 additions and 31 deletions
@@ -29,6 +29,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
"cos8u" -> funcCos8u(call, resultRegister)
"sort" -> funcSort(call)
"reverse" -> funcReverse(call)
"swap" -> funcSwap(call)
"rol" -> funcRolRor2(Opcode.ROXL, call, resultRegister)
"ror" -> funcRolRor2(Opcode.ROXR, call, resultRegister)
"rol2" -> funcRolRor2(Opcode.ROL, call, resultRegister)
@@ -57,6 +58,19 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
}
}
private fun funcSwap(call: PtBuiltinFunctionCall): VmCodeChunk {
val left = call.args[0]
val right = call.args[1]
val leftReg = codeGen.vmRegisters.nextFree()
val rightReg = codeGen.vmRegisters.nextFree()
val code = VmCodeChunk()
code += exprGen.translateExpression(left, leftReg)
code += exprGen.translateExpression(right, rightReg)
code += assignRegisterTo(left, rightReg)
code += assignRegisterTo(right, leftReg)
return code
}
private fun funcReverse(call: PtBuiltinFunctionCall): VmCodeChunk {
val arrayName = call.args[0] as PtIdentifier
val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable
@@ -128,7 +142,8 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
val code = VmCodeChunk()
code += exprGen.translateExpression(call.args[0], addressReg)
code += exprGen.translateExpression(call.args[1], valueReg)
code += VmCodeInstruction(Opcode.STOREI, VmDataType.WORD, reg1 = addressReg, reg2=valueReg)
// TODO use STOREM if constant address
code += VmCodeInstruction(Opcode.STOREI, VmDataType.WORD, reg1 = valueReg, reg2=addressReg)
return code
}
@@ -138,7 +153,8 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
val code = VmCodeChunk()
code += exprGen.translateExpression(call.args[0], addressReg)
code += exprGen.translateExpression(call.args[1], valueReg)
code += VmCodeInstruction(Opcode.STOREI, VmDataType.BYTE, reg1 = addressReg, reg2=valueReg)
// TODO use STOREM if constant address
code += VmCodeInstruction(Opcode.STOREI, VmDataType.BYTE, reg1 = valueReg, reg2=addressReg)
return code
}
@@ -146,6 +162,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
val addressReg = codeGen.vmRegisters.nextFree()
val code = VmCodeChunk()
code += exprGen.translateExpression(call.args.single(), addressReg)
// TODO use LOADM if constant address
code += VmCodeInstruction(Opcode.LOADI, VmDataType.WORD, reg1 = resultRegister, reg2=addressReg)
return code
}
@@ -154,6 +171,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
val code = VmCodeChunk()
val addressReg = codeGen.vmRegisters.nextFree()
code += exprGen.translateExpression(call.args.single(), addressReg)
// TODO use LOADM if constant address
code += VmCodeInstruction(Opcode.LOADI, VmDataType.BYTE, reg1 = resultRegister, reg2=addressReg)
return code
}
@@ -252,11 +270,17 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
val code = VmCodeChunk()
code += exprGen.translateExpression(call.args[0], resultRegister)
code += VmCodeInstruction(opcode, vmDt, reg1=resultRegister)
val assignment = PtAssignment(call.position)
val target = PtAssignTarget(call.position)
target.children.add(call.args[0])
assignment.children.add(target)
assignment.children.add(PtIdentifier(listOf(":vmreg-$resultRegister"), listOf(":vmreg-$resultRegister"), call.args[0].type, call.position))
code += assignRegisterTo(call.args[0], resultRegister)
return code
}
private fun assignRegisterTo(target: PtExpression, register: Int): VmCodeChunk {
val code = VmCodeChunk()
val assignment = PtAssignment(target.position)
val assignTarget = PtAssignTarget(target.position)
assignTarget.children.add(target)
assignment.children.add(assignTarget)
assignment.children.add(PtMachineRegister(register, target.type, target.position))
code += codeGen.translateNode(assignment)
return code
}
@@ -96,7 +96,7 @@ class CodeGen(internal val program: PtProgram,
is PtSubroutineParameter,
is PtNumber,
is PtArray,
is PtString -> throw AssemblyError("strings should not occur as separate statement node ${node.position}")
is PtString -> throw AssemblyError("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}")
@@ -461,6 +461,7 @@ class CodeGen(internal val program: PtProgram,
} else if(memory!=null) {
val addressReg = vmRegisters.nextFree()
code += expressionEval.translateExpression(memory.address, addressReg)
// TODO use LOADM/STOREM if address is constant
code += VmCodeInstruction(Opcode.LOADI, vmDt, reg1=resultReg, reg2=addressReg)
code += VmCodeInstruction(operation, vmDt, reg1=resultReg)
code += VmCodeInstruction(Opcode.STOREI, vmDt, reg1=resultReg, reg2=addressReg)
@@ -533,10 +534,16 @@ class CodeGen(internal val program: PtProgram,
private fun translate(assignment: PtAssignment): VmCodeChunk {
// TODO can in-place assignments be optimized more?
if(assignment.target.children.single() is PtMachineRegister)
throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister")
val code = VmCodeChunk()
val resultRegister = vmRegisters.nextFree()
code += expressionEval.translateExpression(assignment.value, resultRegister)
val resultRegister = if(assignment.value is PtMachineRegister) {
(assignment.value as PtMachineRegister).register
} else {
val reg = vmRegisters.nextFree()
code += expressionEval.translateExpression(assignment.value, reg)
reg
}
val ident = assignment.target.identifier
val memory = assignment.target.memory
val array = assignment.target.array
@@ -561,12 +568,13 @@ class CodeGen(internal val program: PtProgram,
}
}
else if(memory!=null) {
require(vmDt==VmDataType.BYTE)
if(memory.address is PtNumber) {
code += VmCodeInstruction(Opcode.STOREM, vmDt, reg1=resultRegister, value=(memory.address as PtNumber).number.toInt())
} else {
val addressRegister = vmRegisters.nextFree()
code += expressionEval.translateExpression(assignment.value, addressRegister)
code += VmCodeInstruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressRegister)
val addressReg = vmRegisters.nextFree()
code += expressionEval.translateExpression(assignment.value, addressReg)
code += VmCodeInstruction(Opcode.STOREI, vmDt, reg1=resultRegister, reg2=addressReg)
}
}
else
@@ -18,24 +18,24 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
val code = VmCodeChunk()
when (expr) {
is PtMachineRegister -> {
if(resultRegister!=expr.register) {
val vmDt = codeGen.vmType(expr.type)
code += VmCodeInstruction(Opcode.LOADR, vmDt, reg1=resultRegister, reg2=expr.register)
}
}
is PtNumber -> {
val vmDt = codeGen.vmType(expr.type)
code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=expr.number.toInt())
}
is PtIdentifier -> {
val vmDt = codeGen.vmType(expr.type)
if(expr.targetName[0].startsWith(":vmreg-")) {
// special direct reference to a register in the VM
val reg = expr.targetName[0].substring(7).toInt()
code += VmCodeInstruction(Opcode.LOADR, vmDt, reg1=resultRegister, reg2=reg)
val mem = codeGen.allocations.get(expr.targetName)
code += if (expr.type in PassByValueDatatypes) {
VmCodeInstruction(Opcode.LOADM, vmDt, reg1 = resultRegister, value = mem)
} else {
val mem = codeGen.allocations.get(expr.targetName)
code += if (expr.type in PassByValueDatatypes) {
VmCodeInstruction(Opcode.LOADM, vmDt, reg1 = resultRegister, value = mem)
} else {
// for strings and arrays etc., load the *address* of the value instead
VmCodeInstruction(Opcode.LOAD, vmDt, reg1 = resultRegister, value = mem)
}
// for strings and arrays etc., load the *address* of the value instead
VmCodeInstruction(Opcode.LOAD, vmDt, reg1 = resultRegister, value = mem)
}
}
is PtAddressOf -> {
@@ -45,8 +45,9 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
}
is PtMemoryByte -> {
val addressRegister = codeGen.vmRegisters.nextFree()
val addressExprCode = translateExpression(expr.address, addressRegister)
code += addressExprCode
code += translateExpression(expr.address, addressRegister)
// TODO use LOADM if adress is constant
code += VmCodeInstruction(Opcode.LOADI, VmDataType.BYTE, reg1=resultRegister, reg2=addressRegister)
}
is PtTypeCast -> code += translate(expr, resultRegister)
is PtPrefix -> code += translate(expr, resultRegister)
@@ -73,12 +74,12 @@ internal class ExpressionGen(private val codeGen: CodeGen) {
return when (segment) {
is PtFunctionCall -> {
val segWithArg = PtFunctionCall(segment.functionName, segment.void, segment.type, segment.position)
segWithArg.children.add(0, PtIdentifier(listOf(":vmreg-$sourceReg"), listOf(":vmreg-$sourceReg"), sourceDt, segment.position))
segWithArg.children.add(0, PtMachineRegister(sourceReg, sourceDt, segment.position))
segWithArg
}
is PtBuiltinFunctionCall -> {
val segWithArg = PtBuiltinFunctionCall(segment.name, segment.void, segment.hasNoSideEffects, segment.type, segment.position)
segWithArg.children.add(0, PtIdentifier(listOf(":vmreg-$sourceReg"), listOf(":vmreg-$sourceReg"), sourceDt, segment.position))
segWithArg.children.add(0, PtMachineRegister(sourceReg, sourceDt, segment.position))
segWithArg
}
else -> throw AssemblyError("weird segment type")