also track ir reg types

This commit is contained in:
Irmen de Jong 2023-04-07 22:03:13 +02:00
parent b8178c6c8d
commit 5665a7f0cb
7 changed files with 111 additions and 63 deletions

View File

@ -66,6 +66,9 @@ class IRCodeGen(
errors.report()
irProg.linkChunks() // re-link
} else {
val optimizer = IRPeepholeOptimizer(irProg)
optimizer.optimizeOnlyJoinChunks()
}
irProg.validate()

View File

@ -3,6 +3,14 @@ package prog8.codegen.intermediate
import prog8.intermediate.*
internal class IRPeepholeOptimizer(private val irprog: IRProgram) {
fun optimizeOnlyJoinChunks() {
irprog.blocks.asSequence().flatMap { it.children.filterIsInstance<IRSubroutine>() }.forEach { sub ->
removeEmptyChunks(sub)
joinChunks(sub)
}
irprog.linkChunks() // re-link
}
fun optimize() {
irprog.blocks.asSequence().flatMap { it.children.filterIsInstance<IRSubroutine>() }.forEach { sub ->
removeEmptyChunks(sub)

View File

@ -1,31 +1,15 @@
%import textio
%import floats
%zeropage basicsafe
main {
sub calc(ubyte x, ubyte y) -> uword {
repeat x+y {
x++
}
return x as uword * y
}
sub start() {
ubyte[] ba = [11,22,33]
uword[] wa = [1111,2222,3333]
float[] fa = [1.1, 2.2, 3.3]
txt.print_ub(ba[1])
txt.nl()
txt.print_uw(wa[1])
txt.nl()
floats.print_f(fa[1])
txt.nl()
ubyte index=1
ubyte calc=1
ba[index] += 1
wa[index] += 1
fa[index] += 1
txt.print_ub(ba[1])
txt.nl()
txt.print_uw(wa[1])
txt.nl()
floats.print_f(fa[1])
txt.nl()
txt.print_uw(calc(22, 33))
}
}

View File

@ -9,6 +9,7 @@ import java.nio.file.Path
import javax.xml.stream.XMLEventReader
import javax.xml.stream.XMLInputFactory
import javax.xml.stream.XMLStreamException
import javax.xml.stream.events.XMLEvent
import kotlin.io.path.Path
import kotlin.io.path.inputStream

View File

@ -124,6 +124,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
private fun writeCodeChunk(chunk: IRCodeChunk) {
xml.writeStartElement("CODE")
chunk.label?.let { xml.writeAttribute("LABEL", chunk.label) }
xml.writeAttribute("used-registers", chunk.usedRegisters().toString())
xml.writeCharacters("\n")
chunk.instructions.forEach { instr ->
numInstr++

View File

@ -767,37 +767,76 @@ data class IRInstruction(
}
fun addUsedRegistersCounts(
readRegs: MutableMap<Int, Int>,
writeRegs: MutableMap<Int, Int>,
readFpRegs: MutableMap<Int, Int>,
writeFpRegs: MutableMap<Int, Int>
readRegsCounts: MutableMap<Int, Int>,
writeRegsCounts: MutableMap<Int, Int>,
readFpRegsCounts: MutableMap<Int, Int>,
writeFpRegsCounts: MutableMap<Int, Int>,
regsTypes: MutableMap<Int, MutableSet<IRDataType>>
) {
when (this.reg1direction) {
OperandDirection.UNUSED -> {}
OperandDirection.READ -> readRegs[this.reg1!!] = readRegs.getValue(this.reg1)+1
OperandDirection.WRITE -> writeRegs[this.reg1!!] = writeRegs.getValue(this.reg1)+1
OperandDirection.READ -> {
readRegsCounts[this.reg1!!] = readRegsCounts.getValue(this.reg1)+1
if(type!=null) {
var types = regsTypes[this.reg1]
if(types==null) types = mutableSetOf()
types += type
regsTypes[this.reg1] = types
}
}
OperandDirection.WRITE -> {
writeRegsCounts[this.reg1!!] = writeRegsCounts.getValue(this.reg1)+1
if(type!=null) {
var types = regsTypes[this.reg1]
if(types==null) types = mutableSetOf()
types += type
regsTypes[this.reg1] = types
}
}
OperandDirection.READWRITE -> {
readRegs[this.reg1!!] = readRegs.getValue(this.reg1)+1
writeRegs[this.reg1] = writeRegs.getValue(this.reg1)+1
readRegsCounts[this.reg1!!] = readRegsCounts.getValue(this.reg1)+1
if(type!=null) {
var types = regsTypes[this.reg1]
if(types==null) types = mutableSetOf()
types += type
regsTypes[this.reg1] = types
}
writeRegsCounts[this.reg1] = writeRegsCounts.getValue(this.reg1)+1
if(type!=null) {
var types = regsTypes[this.reg1]
if(types==null) types = mutableSetOf()
types += type
regsTypes[this.reg1] = types
}
}
}
when (this.reg2direction) {
OperandDirection.UNUSED -> {}
OperandDirection.READ -> writeRegs[this.reg2!!] = writeRegs.getValue(this.reg2)+1
OperandDirection.READ -> {
writeRegsCounts[this.reg2!!] = writeRegsCounts.getValue(this.reg2)+1
if(type!=null) {
var types = regsTypes[this.reg2]
if(types==null) types = mutableSetOf()
types += type
regsTypes[this.reg2] = types
}
}
else -> throw IllegalArgumentException("reg2 can only be read")
}
when (this.fpReg1direction) {
OperandDirection.UNUSED -> {}
OperandDirection.READ -> readFpRegs[this.fpReg1!!] = readFpRegs.getValue(this.fpReg1)+1
OperandDirection.WRITE -> writeFpRegs[this.fpReg1!!] = writeFpRegs.getValue(this.fpReg1)+1
OperandDirection.READ -> {
readFpRegsCounts[this.fpReg1!!] = readFpRegsCounts.getValue(this.fpReg1)+1
}
OperandDirection.WRITE -> writeFpRegsCounts[this.fpReg1!!] = writeFpRegsCounts.getValue(this.fpReg1)+1
OperandDirection.READWRITE -> {
readFpRegs[this.fpReg1!!] = readFpRegs.getValue(this.fpReg1)+1
writeFpRegs[this.fpReg1] = writeFpRegs.getValue(this.fpReg1)+1
readFpRegsCounts[this.fpReg1!!] = readFpRegsCounts.getValue(this.fpReg1)+1
writeFpRegsCounts[this.fpReg1] = writeFpRegsCounts.getValue(this.fpReg1)+1
}
}
when (this.fpReg2direction) {
OperandDirection.UNUSED -> {}
OperandDirection.READ -> readFpRegs[this.fpReg2!!] = readFpRegs.getValue(this.fpReg2)+1
OperandDirection.READ -> readFpRegsCounts[this.fpReg2!!] = readFpRegsCounts.getValue(this.fpReg2)+1
else -> throw IllegalArgumentException("fpReg2 can only be read")
}
}

View File

@ -199,19 +199,29 @@ class IRProgram(val name: String,
}
fun registersUsed(): RegistersUsed {
val readRegs = mutableMapOf<Int, Int>().withDefault { 0 }
val readFpRegs = mutableMapOf<Int, Int>().withDefault { 0 }
val writeRegs = mutableMapOf<Int, Int>().withDefault { 0 }
val writeFpRegs = mutableMapOf<Int, Int>().withDefault { 0 }
val readRegsCounts = mutableMapOf<Int, Int>().withDefault { 0 }
val regsTypes = mutableMapOf<Int, MutableSet<IRDataType>>()
val readFpRegsCounts = mutableMapOf<Int, Int>().withDefault { 0 }
val writeRegsCounts = mutableMapOf<Int, Int>().withDefault { 0 }
val writeFpRegsCounts = mutableMapOf<Int, Int>().withDefault { 0 }
fun addUsed(usedRegisters: RegistersUsed) {
usedRegisters.readRegs.forEach{ (reg, count) -> readRegs[reg] = readRegs.getValue(reg) + count }
usedRegisters.writeRegs.forEach{ (reg, count) -> writeRegs[reg] = writeRegs.getValue(reg) + count }
usedRegisters.readFpRegs.forEach{ (reg, count) -> readFpRegs[reg] = readFpRegs.getValue(reg) + count }
usedRegisters.writeFpRegs.forEach{ (reg, count) -> writeFpRegs[reg] = writeFpRegs.getValue(reg) + count }
usedRegisters.readRegs.forEach{ (reg, count) -> readRegsCounts[reg] = readRegsCounts.getValue(reg) + count }
usedRegisters.writeRegs.forEach{ (reg, count) -> writeRegsCounts[reg] = writeRegsCounts.getValue(reg) + count }
usedRegisters.readFpRegs.forEach{ (reg, count) -> readFpRegsCounts[reg] = readFpRegsCounts.getValue(reg) + count }
usedRegisters.writeFpRegs.forEach{ (reg, count) -> writeFpRegsCounts[reg] = writeFpRegsCounts.getValue(reg) + count }
usedRegisters.regsTypes.forEach{ (reg, types) ->
var t = regsTypes[reg]
if(t==null) t = mutableSetOf()
t += types
regsTypes[reg] = t
}
}
globalInits.instructions.forEach {
it.addUsedRegistersCounts(readRegsCounts, writeRegsCounts, readFpRegsCounts, writeFpRegsCounts, regsTypes)
}
globalInits.instructions.forEach { it.addUsedRegistersCounts(readRegs, writeRegs, readFpRegs, writeFpRegs) }
blocks.forEach {block ->
block.children.forEach { child ->
when(child) {
@ -223,8 +233,7 @@ class IRProgram(val name: String,
}
}
}
return RegistersUsed(readRegs, writeRegs, readFpRegs, writeFpRegs)
return RegistersUsed(readRegsCounts, writeRegsCounts, readFpRegsCounts, writeFpRegsCounts, regsTypes)
}
}
@ -333,12 +342,13 @@ class IRCodeChunk(label: String?, next: IRCodeChunkBase?): IRCodeChunkBase(label
override fun isEmpty() = instructions.isEmpty()
override fun isNotEmpty() = instructions.isNotEmpty()
override fun usedRegisters(): RegistersUsed {
val readRegs = mutableMapOf<Int, Int>().withDefault { 0 }
val readFpRegs = mutableMapOf<Int, Int>().withDefault { 0 }
val writeRegs = mutableMapOf<Int, Int>().withDefault { 0 }
val writeFpRegs = mutableMapOf<Int, Int>().withDefault { 0 }
instructions.forEach { it.addUsedRegistersCounts(readRegs, writeRegs, readFpRegs, writeFpRegs) }
return RegistersUsed(readRegs, writeRegs, readFpRegs, writeFpRegs)
val readRegsCounts = mutableMapOf<Int, Int>().withDefault { 0 }
val regsTypes = mutableMapOf<Int, MutableSet<IRDataType>>()
val readFpRegsCounts = mutableMapOf<Int, Int>().withDefault { 0 }
val writeRegsCounts = mutableMapOf<Int, Int>().withDefault { 0 }
val writeFpRegsCounts = mutableMapOf<Int, Int>().withDefault { 0 }
instructions.forEach { it.addUsedRegistersCounts(readRegsCounts, writeRegsCounts, readFpRegsCounts, writeFpRegsCounts, regsTypes) }
return RegistersUsed(readRegsCounts, writeRegsCounts, readFpRegsCounts, writeFpRegsCounts, regsTypes)
}
operator fun plusAssign(ins: IRInstruction) {
@ -373,7 +383,7 @@ class IRInlineBinaryChunk(label: String?,
// note: no instructions, data is in the property
override fun isEmpty() = data.isEmpty()
override fun isNotEmpty() = data.isNotEmpty()
override fun usedRegisters() = RegistersUsed(emptyMap(), emptyMap(), emptyMap(), emptyMap())
override fun usedRegisters() = RegistersUsed(emptyMap(), emptyMap(), emptyMap(), emptyMap(), emptyMap())
}
typealias IRCodeChunks = List<IRCodeChunkBase>
@ -384,9 +394,11 @@ class RegistersUsed(
val writeRegs: Map<Int, Int>,
val readFpRegs: Map<Int, Int>,
val writeFpRegs: Map<Int, Int>,
val regsTypes: Map<Int, Set<IRDataType>>
) {
override fun toString(): String {
return "read=$readRegs, write=$writeRegs, readFp=$readFpRegs, writeFp=$writeFpRegs"
return "read=$readRegs, write=$writeRegs, readFp=$readFpRegs, writeFp=$writeFpRegs, types=$regsTypes"
}
fun isEmpty() = readRegs.isEmpty() && writeRegs.isEmpty() && readFpRegs.isEmpty() && writeFpRegs.isEmpty()
@ -394,20 +406,20 @@ class RegistersUsed(
}
private fun registersUsedInAssembly(isIR: Boolean, assembly: String): RegistersUsed {
val readRegs = mutableMapOf<Int, Int>().withDefault { 0 }
val readFpRegs = mutableMapOf<Int, Int>().withDefault { 0 }
val writeRegs = mutableMapOf<Int, Int>().withDefault { 0 }
val writeFpRegs = mutableMapOf<Int, Int>().withDefault { 0 }
val readRegsCounts = mutableMapOf<Int, Int>().withDefault { 0 }
val regsTypes = mutableMapOf<Int, MutableSet<IRDataType>>()
val readFpRegsCounts = mutableMapOf<Int, Int>().withDefault { 0 }
val writeRegsCounts = mutableMapOf<Int, Int>().withDefault { 0 }
val writeFpRegsCounts = mutableMapOf<Int, Int>().withDefault { 0 }
if(isIR) {
assembly.lineSequence().forEach { line ->
val result = parseIRCodeLine(line.trim(), null, mutableMapOf())
result.fold(
ifLeft = { it.addUsedRegistersCounts(readRegs, writeRegs, readFpRegs, writeFpRegs) },
ifLeft = { it.addUsedRegistersCounts(readRegsCounts, writeRegsCounts,readFpRegsCounts, writeFpRegsCounts, regsTypes) },
ifRight = { /* labels can be skipped */ }
)
}
}
return RegistersUsed(readRegs, writeRegs, readFpRegs, writeFpRegs)
return RegistersUsed(readRegsCounts, writeRegsCounts, readFpRegsCounts, writeFpRegsCounts, regsTypes)
}