mirror of
https://github.com/irmen/prog8.git
synced 2026-04-19 20:16:51 +00:00
vm: added swap()
This commit is contained in:
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user