mirror of
https://github.com/irmen/prog8.git
synced 2024-09-07 19:54:26 +00:00
ir: fix syscall numbers and more
This commit is contained in:
parent
30ee65fd14
commit
585009ac5c
@ -74,7 +74,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
result += exprGen.translateExpression(call.args[0], 0, -1)
|
result += exprGen.translateExpression(call.args[0], 0, -1)
|
||||||
result += IRCodeChunk(null, call.position, null).also {
|
result += IRCodeChunk(null, call.position, null).also {
|
||||||
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length)
|
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length)
|
||||||
it += IRInstruction(Opcode.SYSCALL, value = syscall.ordinal)
|
it += IRInstruction(Opcode.SYSCALL, value = syscall.number)
|
||||||
if (resultRegister != 0)
|
if (resultRegister != 0)
|
||||||
it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1 = resultRegister, reg2 = 0)
|
it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1 = resultRegister, reg2 = 0)
|
||||||
}
|
}
|
||||||
@ -97,7 +97,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
result += exprGen.translateExpression(call.args[0], 0, -1)
|
result += exprGen.translateExpression(call.args[0], 0, -1)
|
||||||
result += IRCodeChunk(null, call.position, null).also {
|
result += IRCodeChunk(null, call.position, null).also {
|
||||||
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length)
|
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length)
|
||||||
it += IRInstruction(Opcode.SYSCALL, value = syscall.ordinal)
|
it += IRInstruction(Opcode.SYSCALL, value = syscall.number)
|
||||||
if (resultRegister != 0)
|
if (resultRegister != 0)
|
||||||
it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1 = resultRegister, reg2 = 0)
|
it += IRInstruction(Opcode.LOADR, IRDataType.BYTE, reg1 = resultRegister, reg2 = 0)
|
||||||
}
|
}
|
||||||
@ -216,7 +216,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
result += exprGen.translateExpression(call.args[0], 0, -1)
|
result += exprGen.translateExpression(call.args[0], 0, -1)
|
||||||
result += IRCodeChunk(null, call.position, null).also {
|
result += IRCodeChunk(null, call.position, null).also {
|
||||||
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length)
|
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length)
|
||||||
it += IRInstruction(Opcode.SYSCALL, value = syscall.ordinal)
|
it += IRInstruction(Opcode.SYSCALL, value = syscall.number)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@ -238,7 +238,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
result += exprGen.translateExpression(call.args[0], 0, -1)
|
result += exprGen.translateExpression(call.args[0], 0, -1)
|
||||||
result += IRCodeChunk(null, call.position, null).also {
|
result += IRCodeChunk(null, call.position, null).also {
|
||||||
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length)
|
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = 1, value = array.length)
|
||||||
it += IRInstruction(Opcode.SYSCALL, value = syscall.ordinal)
|
it += IRInstruction(Opcode.SYSCALL, value = syscall.number)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,13 @@ TODO
|
|||||||
For next release
|
For next release
|
||||||
^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^
|
||||||
- vm: program is list of chunks, fix dispatcher
|
- vm: program is list of chunks, fix dispatcher
|
||||||
- ir: see TODO replace IM syscalls by their VM Syscall equivalent
|
- maybe?: make sure last %ir chunk in a subroutine ends with a jump or a return instruction
|
||||||
- ir: fix JUMP, RETURN and all branching instructions to reference a chunk + index instead of just a single programcounter index
|
|
||||||
- ir: fix removeWeirdBranches in IR optimizer
|
|
||||||
- ir: fix unit tests
|
- ir: fix unit tests
|
||||||
- ir: fix joinChunks() in the IR optimizer - there are WAY too many chunks with 1 instruction in them only
|
- ir: fix joinChunks() in the IR optimizer - there are WAY too many chunks with 1 instruction in them only
|
||||||
|
- ir: fix removeWeirdBranches in IR optimizer
|
||||||
- ir: next in IRCodeChunk can also be a Asm Chunk which can have next as well
|
- ir: next in IRCodeChunk can also be a Asm Chunk which can have next as well
|
||||||
- add cx16diskio.vload_raw() to load headerless files into vram
|
- add cx16diskio.vload_raw() to load headerless files into vram
|
||||||
|
- mention the syntax highlighting files in the readme and the docs, and add note to the IDEA one that it can also be used in Rider
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
%import textio
|
%import textio
|
||||||
|
|
||||||
main {
|
main {
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
ubyte aa = 42
|
ubyte aa = 42
|
||||||
ubyte bb = 99
|
ubyte bb = 99
|
||||||
|
@ -4,18 +4,18 @@ package prog8.intermediate
|
|||||||
// these use the SYSCALL instruction instead.
|
// these use the SYSCALL instruction instead.
|
||||||
// Note that in the VM these are translated into whatever the corresponding Syscall number in the VM is.
|
// Note that in the VM these are translated into whatever the corresponding Syscall number in the VM is.
|
||||||
|
|
||||||
enum class IMSyscall {
|
enum class IMSyscall(val number: Int) {
|
||||||
SORT_UBYTE,
|
SORT_UBYTE(10000),
|
||||||
SORT_BYTE,
|
SORT_BYTE(10001),
|
||||||
SORT_UWORD,
|
SORT_UWORD(10002),
|
||||||
SORT_WORD,
|
SORT_WORD(10003),
|
||||||
ANY_BYTE,
|
ANY_BYTE(10004),
|
||||||
ANY_WORD,
|
ANY_WORD(10005),
|
||||||
ANY_FLOAT,
|
ANY_FLOAT(10006),
|
||||||
ALL_BYTE,
|
ALL_BYTE(10007),
|
||||||
ALL_WORD,
|
ALL_WORD(10008),
|
||||||
ALL_FLOAT,
|
ALL_FLOAT(10009),
|
||||||
REVERSE_BYTES,
|
REVERSE_BYTES(10010),
|
||||||
REVERSE_WORDS,
|
REVERSE_WORDS(10011),
|
||||||
REVERSE_FLOATS
|
REVERSE_FLOATS(10012)
|
||||||
}
|
}
|
@ -46,6 +46,7 @@ class IRFileReader {
|
|||||||
|
|
||||||
program.linkChunks()
|
program.linkChunks()
|
||||||
program.validate()
|
program.validate()
|
||||||
|
|
||||||
return program
|
return program
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,6 +357,8 @@ val OpcodesThatBranch = setOf(
|
|||||||
Opcode.JUMP,
|
Opcode.JUMP,
|
||||||
Opcode.JUMPA,
|
Opcode.JUMPA,
|
||||||
Opcode.RETURN,
|
Opcode.RETURN,
|
||||||
|
Opcode.CALL,
|
||||||
|
Opcode.SYSCALL,
|
||||||
Opcode.BSTCC,
|
Opcode.BSTCC,
|
||||||
Opcode.BSTCS,
|
Opcode.BSTCS,
|
||||||
Opcode.BSTEQ,
|
Opcode.BSTEQ,
|
||||||
|
@ -116,8 +116,10 @@ class IRProgram(val name: String,
|
|||||||
chunk.instructions.forEach {
|
chunk.instructions.forEach {
|
||||||
if(it.opcode in OpcodesThatBranch && it.opcode!=Opcode.RETURN && it.labelSymbol!=null) {
|
if(it.opcode in OpcodesThatBranch && it.opcode!=Opcode.RETURN && it.labelSymbol!=null) {
|
||||||
val targetChunk = labeledChunks.getValue(it.labelSymbol)
|
val targetChunk = labeledChunks.getValue(it.labelSymbol)
|
||||||
require(targetChunk is IRCodeChunk) { "target $targetChunk with label ${targetChunk.label} has to be a code chunk" }
|
if(targetChunk is IRCodeChunk)
|
||||||
it.branchTarget = targetChunk
|
it.branchTarget = targetChunk
|
||||||
|
else
|
||||||
|
println("TODO: branchTarget to non-codechunk $targetChunk with label ${targetChunk.label}") // TODO
|
||||||
}
|
}
|
||||||
// note: branches with an address value cannot be linked to something...
|
// note: branches with an address value cannot be linked to something...
|
||||||
}
|
}
|
||||||
@ -147,8 +149,16 @@ class IRProgram(val name: String,
|
|||||||
require(sub.chunks.first().label == sub.name) { "first chunk in subroutine should have sub name as its label" }
|
require(sub.chunks.first().label == sub.name) { "first chunk in subroutine should have sub name as its label" }
|
||||||
}
|
}
|
||||||
sub.chunks.forEach { chunk ->
|
sub.chunks.forEach { chunk ->
|
||||||
if (chunk is IRCodeChunk) require(chunk.instructions.isNotEmpty() || chunk.label!=null)
|
if (chunk is IRCodeChunk)
|
||||||
else require(chunk.instructions.isEmpty())
|
require(chunk.instructions.isNotEmpty() || chunk.label!=null)
|
||||||
|
else
|
||||||
|
require(chunk.instructions.isEmpty())
|
||||||
|
chunk.instructions.forEach {
|
||||||
|
if(it.labelSymbol!=null && it.opcode in OpcodesThatBranch) {
|
||||||
|
if(it.branchTarget==null) println("TODO: fix branching instruction to label ${it.labelSymbol} should have branchTarget set") // TODO
|
||||||
|
// TODO require(it.branchTarget != null) { "branching instruction to label should have branchTarget set" }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,12 +122,14 @@ class VirtualMachine(irProgram: IRProgram) {
|
|||||||
if(pcIndex>=pcChunk.instructions.size) {
|
if(pcIndex>=pcChunk.instructions.size) {
|
||||||
pcIndex = 0
|
pcIndex = 0
|
||||||
if(pcChunk.next==null)
|
if(pcChunk.next==null)
|
||||||
TODO("huh no next chunk in $pcChunk")
|
TODO("no next chunk in $pcChunk (remove this check)")
|
||||||
pcChunk = pcChunk.next!!
|
pcChunk = pcChunk.next!!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun branchTo(i: IRInstruction) {
|
private fun branchTo(i: IRInstruction) {
|
||||||
|
if(i.branchTarget==null)
|
||||||
|
TODO("no branchtarget in $i (remove this check)")
|
||||||
pcChunk = i.branchTarget!!
|
pcChunk = i.branchTarget!!
|
||||||
pcIndex = 0
|
pcIndex = 0
|
||||||
}
|
}
|
||||||
|
@ -33,15 +33,24 @@ class VmProgramLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// load rest of the program into the list
|
// load rest of the program into the list
|
||||||
|
val chunkReplacements = mutableListOf<Pair<IRCodeChunkBase, IRCodeChunk>>()
|
||||||
irProgram.blocks.forEach { block ->
|
irProgram.blocks.forEach { block ->
|
||||||
if(block.address!=null)
|
if(block.address!=null)
|
||||||
throw IRParseException("blocks cannot have a load address for vm: ${block.name}")
|
throw IRParseException("blocks cannot have a load address for vm: ${block.name}")
|
||||||
|
|
||||||
block.inlineAssembly.forEach { addAssemblyToProgram(it, programChunks, variableAddresses) }
|
block.inlineAssembly.forEach {
|
||||||
|
val replacement = addAssemblyToProgram(it, programChunks, variableAddresses)
|
||||||
|
if(replacement!=null)
|
||||||
|
chunkReplacements += replacement
|
||||||
|
}
|
||||||
block.subroutines.forEach {
|
block.subroutines.forEach {
|
||||||
it.chunks.forEach { chunk ->
|
it.chunks.forEach { chunk ->
|
||||||
when (chunk) {
|
when (chunk) {
|
||||||
is IRInlineAsmChunk -> addAssemblyToProgram(chunk, programChunks, variableAddresses)
|
is IRInlineAsmChunk -> {
|
||||||
|
val replacement = addAssemblyToProgram(chunk, programChunks, variableAddresses)
|
||||||
|
if(replacement!=null)
|
||||||
|
chunkReplacements += replacement
|
||||||
|
}
|
||||||
is IRInlineBinaryChunk -> TODO("inline binary data not yet supported in the VM")
|
is IRInlineBinaryChunk -> TODO("inline binary data not yet supported in the VM")
|
||||||
is IRCodeChunk -> programChunks += chunk
|
is IRCodeChunk -> programChunks += chunk
|
||||||
else -> throw AssemblyError("weird chunk type")
|
else -> throw AssemblyError("weird chunk type")
|
||||||
@ -52,11 +61,74 @@ class VmProgramLoader {
|
|||||||
throw IRParseException("vm currently does not support asmsubs: ${block.asmSubroutines.first().name}")
|
throw IRParseException("vm currently does not support asmsubs: ${block.asmSubroutines.first().name}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pass2translateSyscalls(programChunks)
|
||||||
pass2replaceLabelsByProgIndex(programChunks, variableAddresses)
|
pass2replaceLabelsByProgIndex(programChunks, variableAddresses)
|
||||||
|
phase2relinkReplacedChunks(chunkReplacements, programChunks)
|
||||||
|
|
||||||
|
programChunks.forEach {
|
||||||
|
it.instructions.forEach { ins ->
|
||||||
|
if (ins.labelSymbol != null && ins.opcode !in OpcodesThatBranch)
|
||||||
|
require(ins.value != null) { "instruction with labelSymbol for a var should have value set to var's memory address" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return programChunks
|
return programChunks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun phase2relinkReplacedChunks(
|
||||||
|
replacements: MutableList<Pair<IRCodeChunkBase, IRCodeChunk>>,
|
||||||
|
programChunks: MutableList<IRCodeChunk>
|
||||||
|
) {
|
||||||
|
replacements.forEach { (old, new) ->
|
||||||
|
programChunks.forEach { chunk ->
|
||||||
|
if(chunk.next === old) {
|
||||||
|
chunk.next = new
|
||||||
|
}
|
||||||
|
chunk.instructions.forEach { ins ->
|
||||||
|
if(ins.branchTarget === old) {
|
||||||
|
ins.branchTarget = new
|
||||||
|
} else if(ins.branchTarget==null && ins.labelSymbol==new.label) {
|
||||||
|
ins.branchTarget = new
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun pass2translateSyscalls(chunks: MutableList<IRCodeChunk>) {
|
||||||
|
chunks.forEach { chunk ->
|
||||||
|
chunk.instructions.withIndex().forEach { (index, ins) ->
|
||||||
|
if(ins.opcode == Opcode.SYSCALL) {
|
||||||
|
// convert IR Syscall to VM Syscall
|
||||||
|
val vmSyscall = when(ins.value!!) {
|
||||||
|
IMSyscall.SORT_UBYTE.number -> Syscall.SORT_UBYTE
|
||||||
|
IMSyscall.SORT_BYTE.number -> Syscall.SORT_BYTE
|
||||||
|
IMSyscall.SORT_UWORD.number -> Syscall.SORT_UWORD
|
||||||
|
IMSyscall.SORT_WORD.number -> Syscall.SORT_WORD
|
||||||
|
IMSyscall.ANY_BYTE.number -> Syscall.ANY_BYTE
|
||||||
|
IMSyscall.ANY_WORD.number -> Syscall.ANY_WORD
|
||||||
|
IMSyscall.ANY_FLOAT.number -> Syscall.ANY_FLOAT
|
||||||
|
IMSyscall.ALL_BYTE.number -> Syscall.ALL_BYTE
|
||||||
|
IMSyscall.ALL_WORD.number -> Syscall.ALL_WORD
|
||||||
|
IMSyscall.ALL_FLOAT.number -> Syscall.ALL_FLOAT
|
||||||
|
IMSyscall.REVERSE_BYTES.number -> Syscall.REVERSE_BYTES
|
||||||
|
IMSyscall.REVERSE_WORDS.number -> Syscall.REVERSE_WORDS
|
||||||
|
IMSyscall.REVERSE_FLOATS.number -> Syscall.REVERSE_FLOATS
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
if(vmSyscall!=null)
|
||||||
|
chunk.instructions[index] = ins.copy(value = vmSyscall.ordinal)
|
||||||
|
}
|
||||||
|
|
||||||
|
val label = ins.labelSymbol
|
||||||
|
if (label != null && ins.opcode !in OpcodesThatBranch) {
|
||||||
|
placeholders[Pair(chunk, index)] = label
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun pass2replaceLabelsByProgIndex(
|
private fun pass2replaceLabelsByProgIndex(
|
||||||
chunks: MutableList<IRCodeChunk>,
|
chunks: MutableList<IRCodeChunk>,
|
||||||
variableAddresses: MutableMap<String, Int>
|
variableAddresses: MutableMap<String, Int>
|
||||||
@ -87,40 +159,6 @@ class VmProgramLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO replace IM syscalls by their VM Syscall equivalent
|
|
||||||
// private fun addToProgram(
|
|
||||||
// instructions: Iterable<IRInstruction>,
|
|
||||||
// program: MutableList<IRCodeChunk>
|
|
||||||
// ) {
|
|
||||||
// val chunk = IRCodeChunk(null, Position.DUMMY, null)
|
|
||||||
// instructions.map {
|
|
||||||
// it.labelSymbol?.let { symbol -> placeholders[Pair(chunk, chunk.instructions.size)]=symbol }
|
|
||||||
// if(it.opcode==Opcode.SYSCALL) {
|
|
||||||
// // convert IR Syscall to VM Syscall
|
|
||||||
// val vmSyscall = when(it.value!!) {
|
|
||||||
// IMSyscall.SORT_UBYTE.ordinal -> Syscall.SORT_UBYTE
|
|
||||||
// IMSyscall.SORT_BYTE.ordinal -> Syscall.SORT_BYTE
|
|
||||||
// IMSyscall.SORT_UWORD.ordinal -> Syscall.SORT_UWORD
|
|
||||||
// IMSyscall.SORT_WORD.ordinal -> Syscall.SORT_WORD
|
|
||||||
// IMSyscall.ANY_BYTE.ordinal -> Syscall.ANY_BYTE
|
|
||||||
// IMSyscall.ANY_WORD.ordinal -> Syscall.ANY_WORD
|
|
||||||
// IMSyscall.ANY_FLOAT.ordinal -> Syscall.ANY_FLOAT
|
|
||||||
// IMSyscall.ALL_BYTE.ordinal -> Syscall.ALL_BYTE
|
|
||||||
// IMSyscall.ALL_WORD.ordinal -> Syscall.ALL_WORD
|
|
||||||
// IMSyscall.ALL_FLOAT.ordinal -> Syscall.ALL_FLOAT
|
|
||||||
// IMSyscall.REVERSE_BYTES.ordinal -> Syscall.REVERSE_BYTES
|
|
||||||
// IMSyscall.REVERSE_WORDS.ordinal -> Syscall.REVERSE_WORDS
|
|
||||||
// IMSyscall.REVERSE_FLOATS.ordinal -> Syscall.REVERSE_FLOATS
|
|
||||||
// else -> throw IRParseException("invalid IM syscall number $it")
|
|
||||||
// }
|
|
||||||
// chunk += it.copy(value=vmSyscall.ordinal)
|
|
||||||
// } else {
|
|
||||||
// chunk += it
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// program += chunk
|
|
||||||
// }
|
|
||||||
|
|
||||||
private fun varsToMemory(
|
private fun varsToMemory(
|
||||||
program: IRProgram,
|
program: IRProgram,
|
||||||
allocations: VmVariableAllocator,
|
allocations: VmVariableAllocator,
|
||||||
@ -232,7 +270,7 @@ class VmProgramLoader {
|
|||||||
asmChunk: IRInlineAsmChunk,
|
asmChunk: IRInlineAsmChunk,
|
||||||
chunks: MutableList<IRCodeChunk>,
|
chunks: MutableList<IRCodeChunk>,
|
||||||
symbolAddresses: MutableMap<String, Int>,
|
symbolAddresses: MutableMap<String, Int>,
|
||||||
) {
|
): Pair<IRCodeChunkBase, IRCodeChunk> {
|
||||||
if(asmChunk.isIR) {
|
if(asmChunk.isIR) {
|
||||||
val chunk = IRCodeChunk(asmChunk.label, asmChunk.position, null)
|
val chunk = IRCodeChunk(asmChunk.label, asmChunk.position, null)
|
||||||
asmChunk.assembly.lineSequence().forEach {
|
asmChunk.assembly.lineSequence().forEach {
|
||||||
@ -243,6 +281,7 @@ class VmProgramLoader {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
chunks += chunk
|
chunks += chunk
|
||||||
|
return Pair(asmChunk, chunk)
|
||||||
} else {
|
} else {
|
||||||
throw IRParseException("vm currently does not support real inlined assembly (only IR): ${asmChunk.position}")
|
throw IRParseException("vm currently does not support real inlined assembly (only IR): ${asmChunk.position}")
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user