mirror of
https://github.com/irmen/prog8.git
synced 2025-02-18 05:30:34 +00:00
ir: join code chunks
This commit is contained in:
parent
43e31765e5
commit
94f0f3e966
@ -5,6 +5,7 @@ import prog8.intermediate.*
|
|||||||
internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
||||||
fun optimize() {
|
fun optimize() {
|
||||||
irprog.blocks.asSequence().flatMap { it.subroutines }.forEach { sub ->
|
irprog.blocks.asSequence().flatMap { it.subroutines }.forEach { sub ->
|
||||||
|
joinChunks(sub)
|
||||||
sub.chunks.forEach { chunk ->
|
sub.chunks.forEach { chunk ->
|
||||||
// we don't optimize Inline Asm chunks here.
|
// we don't optimize Inline Asm chunks here.
|
||||||
if(chunk is IRCodeChunk) {
|
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 {
|
private fun cleanupPushPop(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<IRInstruction>>): Boolean {
|
||||||
// push followed by pop to same target, or different target->replace with load
|
// push followed by pop to same target, or different target->replace with load
|
||||||
var changed = false
|
var changed = false
|
||||||
|
@ -18,10 +18,11 @@ Future Things and Ideas
|
|||||||
Compiler:
|
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
|
- 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?
|
- ir: 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.
|
- ir: 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
|
- ir: joinChunks() in the IR optimizer should be changed accordingly
|
||||||
- vm: how to remove all unused subroutines? (the 6502 assembly codegen relies on 64tass solve this for us)
|
- 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.
|
- 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!
|
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.....
|
Lot of work because of so many special cases in ForLoopsAsmgen.....
|
||||||
|
@ -10,6 +10,9 @@ import kotlin.io.path.div
|
|||||||
class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
||||||
private val outfile = outfileOverride ?: (irProgram.options.outputDir / ("${irProgram.name}.p8ir"))
|
private val outfile = outfileOverride ?: (irProgram.options.outputDir / ("${irProgram.name}.p8ir"))
|
||||||
private val out = outfile.bufferedWriter()
|
private val out = outfile.bufferedWriter()
|
||||||
|
private var numChunks = 0
|
||||||
|
private var numLines = 0
|
||||||
|
|
||||||
|
|
||||||
fun write(): Path {
|
fun write(): Path {
|
||||||
println("Writing intermediate representation to $outfile")
|
println("Writing intermediate representation to $outfile")
|
||||||
@ -28,6 +31,8 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
|||||||
writeBlocks()
|
writeBlocks()
|
||||||
out.write("</PROGRAM>\n")
|
out.write("</PROGRAM>\n")
|
||||||
out.close()
|
out.close()
|
||||||
|
|
||||||
|
println("$numChunks code chunks and $numLines lines.")
|
||||||
return outfile
|
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") }
|
it.parameters.forEach { param -> out.write("${getTypeString(param.dt)} ${param.name}\n") }
|
||||||
out.write("</PARAMS>\n")
|
out.write("</PARAMS>\n")
|
||||||
it.chunks.forEach { chunk ->
|
it.chunks.forEach { chunk ->
|
||||||
|
numChunks++
|
||||||
if(chunk is IRInlineAsmChunk) {
|
if(chunk is IRInlineAsmChunk) {
|
||||||
writeInlineAsm(chunk)
|
writeInlineAsm(chunk)
|
||||||
} else {
|
} else {
|
||||||
out.write("<C>\n")
|
out.write("<C>\n")
|
||||||
if (chunk.lines.isEmpty())
|
if (chunk.lines.isEmpty())
|
||||||
throw InternalCompilerException("empty code chunk in ${it.name} ${it.position}")
|
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")
|
out.write("</C>\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user