diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt index dfb9c73c3..8340304a8 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt @@ -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().any {it.opcode in OpcodesThatBranch } + } + return false + } + + val chunks = mutableListOf() + 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>): Boolean { // push followed by pop to same target, or different target->replace with load var changed = false diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 042aa2436..e3dd1f001 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -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\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("\n") it.chunks.forEach { chunk -> + numChunks++ if(chunk is IRInlineAsmChunk) { writeInlineAsm(chunk) } else { out.write("\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("\n") } }