mirror of
https://github.com/irmen/prog8.git
synced 2025-01-11 13:29:45 +00:00
also track ir reg types
This commit is contained in:
parent
b8178c6c8d
commit
5665a7f0cb
@ -66,6 +66,9 @@ class IRCodeGen(
|
||||
errors.report()
|
||||
|
||||
irProg.linkChunks() // re-link
|
||||
} else {
|
||||
val optimizer = IRPeepholeOptimizer(irProg)
|
||||
optimizer.optimizeOnlyJoinChunks()
|
||||
}
|
||||
|
||||
irProg.validate()
|
||||
|
@ -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)
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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++
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user