ir: join code chunks

This commit is contained in:
Irmen de Jong 2022-09-30 02:47:33 +02:00
parent 43e31765e5
commit 94f0f3e966
3 changed files with 50 additions and 5 deletions

View File

@ -5,6 +5,7 @@ import prog8.intermediate.*
internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
fun optimize() {
irprog.blocks.asSequence().flatMap { it.subroutines }.forEach { sub ->
joinChunks(sub)
sub.chunks.forEach { chunk ->
// we don't optimize Inline Asm chunks here.
if(chunk is IRCodeChunk) {
@ -26,6 +27,40 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
}
}
private fun joinChunks(sub: IRSubroutine) {
/*
Subroutine contains a list of chunks.
Some can be joined into one.
TODO: this has to be changed later...
*/
if(sub.chunks.isEmpty())
return
fun mayJoin(previous: IRCodeChunkBase, chunk: IRCodeChunkBase): Boolean {
if(previous is IRCodeChunk && chunk is IRCodeChunk) {
if(chunk.lines.any{ it is IRCodeInlineBinary})
return false
return true
// TODO: only if all instructions are non-branching, allow it to join?
// return !chunk.lines.filterIsInstance<IRInstruction>().any {it.opcode in OpcodesThatBranch }
}
return false
}
val chunks = mutableListOf<IRCodeChunkBase>()
chunks += sub.chunks[0]
for(ix in 1 until sub.chunks.size) {
if(mayJoin(chunks.last(), sub.chunks[ix]))
chunks.last().lines += sub.chunks[ix].lines
else
chunks += sub.chunks[ix]
}
sub.chunks.clear()
sub.chunks += chunks
}
private fun cleanupPushPop(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<IRInstruction>>): Boolean {
// push followed by pop to same target, or different target->replace with load
var changed = false

View File

@ -18,10 +18,11 @@ Future Things and Ideas
Compiler:
- create BSS section in output program and put StStaticVariables in there with bss=true. Don't forget to add init code to zero out everything that was put in bss. If array in bss->only zero ONCE! So requires self-modifying code
- vm: Jumps go to a code block rather than a specific address(label) -> also helps future dead code elimination?
- vm: the above means that every label introduces a new code block. This eliminates the use of actual labels altogether during execution/translation.
- vm: add more optimizations in IRPeepholeOptimizer
- vm: how to remove all unused subroutines? (the 6502 assembly codegen relies on 64tass solve this for us)
- ir: Jumps go to a code block rather than a specific address(label) -> also helps future dead code elimination?
- ir: the above means that every label introduces a new code block. This eliminates the use of actual labels altogether during execution/translation.
- ir: joinChunks() in the IR optimizer should be changed accordingly
- ir: add more optimizations in IRPeepholeOptimizer
- ir: how to remove all unused subroutines? (the 6502 assembly codegen relies on 64tass solve this for us)
- see if we can let for loops skip the loop if end<start, like other programming languages. Without adding a lot of code size/duplicating the loop condition.
this is documented behavior to now loop around but it's too easy to forget about!
Lot of work because of so many special cases in ForLoopsAsmgen.....

View File

@ -10,6 +10,9 @@ import kotlin.io.path.div
class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
private val outfile = outfileOverride ?: (irProgram.options.outputDir / ("${irProgram.name}.p8ir"))
private val out = outfile.bufferedWriter()
private var numChunks = 0
private var numLines = 0
fun write(): Path {
println("Writing intermediate representation to $outfile")
@ -28,6 +31,8 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
writeBlocks()
out.write("</PROGRAM>\n")
out.close()
println("$numChunks code chunks and $numLines lines.")
return outfile
}
@ -43,13 +48,17 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
it.parameters.forEach { param -> out.write("${getTypeString(param.dt)} ${param.name}\n") }
out.write("</PARAMS>\n")
it.chunks.forEach { chunk ->
numChunks++
if(chunk is IRInlineAsmChunk) {
writeInlineAsm(chunk)
} else {
out.write("<C>\n")
if (chunk.lines.isEmpty())
throw InternalCompilerException("empty code chunk in ${it.name} ${it.position}")
chunk.lines.forEach { line -> out.writeLine(line) }
chunk.lines.forEach { line ->
numLines++
out.writeLine(line)
}
out.write("</C>\n")
}
}