IR: binarydata fixes

This commit is contained in:
Irmen de Jong 2023-05-03 22:31:04 +02:00
parent 3fc49c001e
commit add8a777d8
6 changed files with 42 additions and 39 deletions

View File

@ -24,6 +24,7 @@ class IRPeepholeOptimizer(private val irprog: IRProgram) {
private fun optimizeOnlyJoinChunks() {
irprog.blocks.asSequence().flatMap { it.children.filterIsInstance<IRSubroutine>() }.forEach { sub ->
joinChunks(sub)
removeEmptyChunks(sub)
joinChunks(sub)
}
@ -32,6 +33,7 @@ class IRPeepholeOptimizer(private val irprog: IRProgram) {
private fun peepholeOptimize() {
irprog.blocks.asSequence().flatMap { it.children.filterIsInstance<IRSubroutine>() }.forEach { sub ->
joinChunks(sub)
removeEmptyChunks(sub)
joinChunks(sub)
sub.chunks.withIndex().forEach { (index, chunk1) ->
@ -112,7 +114,7 @@ class IRPeepholeOptimizer(private val irprog: IRProgram) {
if(sub.chunks.isEmpty())
return
fun mayJoin(previous: IRCodeChunkBase, chunk: IRCodeChunkBase): Boolean {
fun mayJoinCodeChunks(previous: IRCodeChunkBase, chunk: IRCodeChunkBase): Boolean {
if(chunk.label!=null)
return false
if(previous is IRCodeChunk && chunk is IRCodeChunk) {
@ -129,12 +131,39 @@ class IRPeepholeOptimizer(private val irprog: IRProgram) {
chunks += sub.chunks[0]
for(ix in 1 until sub.chunks.size) {
val lastChunk = chunks.last()
if(mayJoin(lastChunk, sub.chunks[ix])) {
lastChunk.instructions += sub.chunks[ix].instructions
lastChunk.next = sub.chunks[ix].next
val candidate = sub.chunks[ix]
when(candidate) {
is IRCodeChunk -> {
if(mayJoinCodeChunks(lastChunk, candidate)) {
lastChunk.instructions += candidate.instructions
lastChunk.next = candidate.next
}
else
chunks += candidate
}
is IRInlineAsmChunk -> {
if(candidate.label!=null)
chunks += candidate
else if(lastChunk.isEmpty()) {
val label = lastChunk.label
if(label!=null)
chunks += IRInlineAsmChunk(label, candidate.assembly, candidate.isIR, candidate.next)
else
chunks += candidate
}
}
is IRInlineBinaryChunk -> {
if(candidate.label!=null)
chunks += candidate
else if(lastChunk.isEmpty()) {
val label = lastChunk.label
if(label!=null)
chunks += IRInlineBinaryChunk(label, candidate.data, candidate.next)
else
chunks += candidate
}
}
}
else
chunks += sub.chunks[ix]
}
sub.chunks.clear()
sub.chunks += chunks

View File

@ -140,7 +140,6 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
private fun writeInlineBytes(chunk: IRInlineBinaryChunk) {
xml.writeStartElement("BYTES")
chunk.label?.let { xml.writeAttribute("LABEL", chunk.label) }
xml.writeCharacters("\n")
chunk.data.withIndex().forEach {(index, byte) ->
xml.writeCharacters(byte.toString(16).padStart(2,'0'))
if(index and 63 == 63 && index < chunk.data.size-1)

View File

@ -213,7 +213,6 @@ msig [b, w] reg1, reg2 - reg1 becomes the most significant by
concat [b, w] reg1, reg2 - reg1 = concatenated lsb/lsw of reg1 (as lsb) and lsb/lsw of reg2 (as msb) into word or int (int not yet implemented; requires 32bits regs)
push [b, w, f] reg1 - push value in reg1 on the stack
pop [b, w, f] reg1 - pop value from stack into reg1
binarydata - 'instruction' to hold inlined binary data bytes
*/
enum class Opcode {
@ -371,8 +370,7 @@ enum class Opcode {
POP,
MSIG,
CONCAT,
BREAKPOINT,
BINARYDATA
BREAKPOINT
}
val OpcodesThatJump = setOf(
@ -650,7 +648,6 @@ val instructionFormats = mutableMapOf(
Opcode.CLC to InstructionFormat.from("N"),
Opcode.SEC to InstructionFormat.from("N"),
Opcode.BREAKPOINT to InstructionFormat.from("N"),
Opcode.BINARYDATA to InstructionFormat.from("N"),
)
@ -664,9 +661,8 @@ data class IRInstruction(
val immediate: Int?=null, // 0-$ff or $ffff if word
val immediateFp: Float?=null,
val address: Int?=null, // 0-$ffff
val labelSymbol: String?=null, // symbolic label name as alternative to value (so only for Branch/jump/call Instructions!)
val binaryData: Collection<UByte>?=null,
var branchTarget: IRCodeChunkBase? = null // will be linked after loading
val labelSymbol: String?=null, // symbolic label name as alternative to address (so only for Branch/jump/call Instructions!)
var branchTarget: IRCodeChunkBase? = null // Will be linked after loading in IRProgram.linkChunks()! This is the chunk that the branch labelSymbol points to.
) {
// reg1 and fpreg1 can be IN/OUT/INOUT (all others are readonly INPUT)
// This knowledge is useful in IL assembly optimizers to see how registers are used.
@ -683,10 +679,6 @@ data class IRInstruction(
require(fpReg2==null || fpReg2 in 0..65536) {"fpReg2 out of bounds"}
if(reg1!=null && reg2!=null) require(reg1!=reg2) {"reg1 must not be same as reg2"} // note: this is ok for fpRegs as these are always the same type
require((opcode==Opcode.BINARYDATA && binaryData!=null) || (opcode!=Opcode.BINARYDATA && binaryData==null)) {
"binarydata inconsistency"
}
val formats = instructionFormats.getValue(opcode)
require (type != null || formats.containsKey(null)) { "missing type" }

View File

@ -284,7 +284,6 @@ class VirtualMachine(irProgram: IRProgram) {
Opcode.BREAKPOINT -> InsBREAKPOINT()
Opcode.CLC -> { statusCarry = false; nextPc() }
Opcode.SEC -> { statusCarry = true; nextPc() }
Opcode.BINARYDATA -> TODO("BINARYDATA not yet supported in VM")
Opcode.LOADCPU -> InsLOADCPU(ins)
Opcode.STORECPU -> InsSTORECPU(ins)
Opcode.STOREZCPU -> InsSTOREZCPU(ins)

View File

@ -46,7 +46,7 @@ class VmProgramLoader {
is IRCodeChunk -> programChunks += child
is IRInlineAsmChunk -> {
val replacement = addAssemblyToProgram(child, programChunks, variableAddresses)
chunkReplacements += replacement
chunkReplacements += Pair(child, replacement)
}
is IRInlineBinaryChunk -> throw IRParseException("inline binary data not yet supported in the VM") // TODO
is IRSubroutine -> {
@ -55,7 +55,7 @@ class VmProgramLoader {
when (chunk) {
is IRInlineAsmChunk -> {
val replacement = addAssemblyToProgram(chunk, programChunks, variableAddresses)
chunkReplacements += replacement
chunkReplacements += Pair(chunk, replacement)
}
is IRInlineBinaryChunk -> throw IRParseException("inline binary data not yet supported in the VM") // TODO
is IRCodeChunk -> programChunks += chunk
@ -339,7 +339,7 @@ class VmProgramLoader {
asmChunk: IRInlineAsmChunk,
chunks: MutableList<IRCodeChunk>,
symbolAddresses: MutableMap<String, Int>,
): Pair<IRCodeChunkBase, IRCodeChunk> {
): IRCodeChunk {
if(asmChunk.isIR) {
val chunk = IRCodeChunk(asmChunk.label, asmChunk.next)
asmChunk.assembly.lineSequence().forEach {
@ -350,7 +350,7 @@ class VmProgramLoader {
)
}
chunks += chunk
return Pair(asmChunk, chunk)
return chunk
} else {
throw IRParseException("vm currently does not support real inlined assembly (only IR): ${asmChunk.label}")
}

View File

@ -70,22 +70,6 @@ class TestVm: FunSpec( {
vm.stepCount shouldBe code.instructions.size
}
test("vm asmbinary not supported") {
val program = IRProgram("test", IRSymbolTable(null), getTestOptions(), VMTarget())
val block = IRBlock("testmain", null, false, false, IRBlock.BlockAlignment.NONE, Position.DUMMY)
val startSub = IRSubroutine("testmain.testsub", emptyList(), null, Position.DUMMY)
val code = IRCodeChunk(startSub.label, null)
code += IRInstruction(Opcode.BINARYDATA, binaryData = listOf(1u,2u,3u))
code += IRInstruction(Opcode.RETURN)
startSub += code
block += startSub
program.addBlock(block)
val vm = VirtualMachine(program)
shouldThrowWithMessage<NotImplementedError>("An operation is not implemented: BINARYDATA not yet supported in VM") {
vm.run()
}
}
test("asmsub not supported in vm even with IR") {
val program = IRProgram("test", IRSymbolTable(null), getTestOptions(), VMTarget())
val block = IRBlock("main", null, false, false, IRBlock.BlockAlignment.NONE, Position.DUMMY)