vm: implementing rol/ror

This commit is contained in:
Irmen de Jong
2022-04-09 00:49:23 +02:00
parent a8cf9f5cc4
commit a0face4a28
7 changed files with 192 additions and 42 deletions
@@ -1,10 +1,7 @@
package prog8.codegen.virtual
import prog8.code.StStaticVariable
import prog8.code.ast.PtBuiltinFunctionCall
import prog8.code.ast.PtIdentifier
import prog8.code.ast.PtNumber
import prog8.code.ast.PtString
import prog8.code.ast.*
import prog8.code.core.DataType
import prog8.vm.Opcode
import prog8.vm.Syscall
@@ -154,6 +151,10 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
code += VmCodeInstruction(Opcode.SYSCALL, value=sortSyscall.ordinal)
}
"rol" -> RolRor2(Opcode.ROXL, call, resultRegister, code)
"ror" -> RolRor2(Opcode.ROXR, call, resultRegister, code)
"rol2" -> RolRor2(Opcode.ROL, call, resultRegister, code)
"ror2" -> RolRor2(Opcode.ROR, call, resultRegister, code)
else -> {
TODO("builtinfunc ${call.name}")
// code += VmCodeInstruction(Opcode.NOP))
@@ -179,4 +180,17 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
return code
}
private fun RolRor2(opcode: Opcode, call: PtBuiltinFunctionCall, resultRegister: Int, code: VmCodeChunk) {
// bit rotate left without carry, in-place
val vmDt = codeGen.vmType(call.args[0].type)
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 += codeGen.translateNode(assignment)
}
}
@@ -57,7 +57,7 @@ class CodeGen(internal val program: PtProgram,
}
private fun translateNode(node: PtNode): VmCodeChunk {
internal fun translateNode(node: PtNode): VmCodeChunk {
val code = when(node) {
is PtBlock -> translate(node)
is PtSub -> translate(node)
@@ -80,6 +80,7 @@ class CodeGen(internal val program: PtProgram,
is PtRepeatLoop -> translate(node)
is PtLabel -> VmCodeChunk(VmCodeLabel(node.scopedName))
is PtBreakpoint -> VmCodeChunk(VmCodeInstruction(Opcode.BREAKPOINT))
is PtConditionalBranch -> translate(node)
is PtAddressOf,
is PtContainmentCheck,
is PtMemoryByte,
@@ -99,7 +100,6 @@ class CodeGen(internal val program: PtProgram,
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")
}
if(code.lines.isNotEmpty() && node.position.line!=0)
@@ -107,6 +107,33 @@ class CodeGen(internal val program: PtProgram,
return code
}
private fun translate(branch: PtConditionalBranch): VmCodeChunk {
val code = VmCodeChunk()
val elseLabel = createLabelName()
when(branch.condition) {
BranchCondition.CS -> {
code += VmCodeInstruction(Opcode.BSTCC, symbol = elseLabel)
}
BranchCondition.CC -> {
code += VmCodeInstruction(Opcode.BSTCS, symbol = elseLabel)
}
else -> {
throw AssemblyError("conditional branch ${branch.condition} not supported in vm target due to lack of cpu flags ${branch.position}")
}
}
code += translateNode(branch.trueScope)
if(branch.falseScope.children.isNotEmpty()) {
val endLabel = createLabelName()
code += VmCodeInstruction(Opcode.JUMP, symbol = endLabel)
code += VmCodeLabel(elseLabel)
code += translateNode(branch.falseScope)
code += VmCodeLabel(endLabel)
} else {
code += VmCodeLabel(elseLabel)
}
return code
}
private fun translate(whenStmt: PtWhen): VmCodeChunk {
if(whenStmt.choices.children.isEmpty())
return VmCodeChunk()