mirror of
https://github.com/irmen/prog8.git
synced 2024-12-24 01:29:28 +00:00
IR: binarydata fixes
This commit is contained in:
parent
3fc49c001e
commit
add8a777d8
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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" }
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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}")
|
||||
}
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user