ir: count register uses

This commit is contained in:
Irmen de Jong 2022-10-02 15:54:46 +02:00
parent af6be44676
commit e7682119e0
4 changed files with 70 additions and 99 deletions

View File

@ -3,8 +3,6 @@ TODO
For next release For next release
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
- ir: RegistersUsed should actually count the number of times a register is used too?
... ...

View File

@ -33,28 +33,21 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
out.write("</PROGRAM>\n") out.write("</PROGRAM>\n")
out.close() out.close()
val usedRegisters = mutableSetOf<Int>() var usedRegisters = 0
val usedFpRegisters = mutableSetOf<Int>()
irProgram.blocks.forEach { fun addUsed(used: RegistersUsed) {
it.inlineAssembly.forEach { chunk -> used.inputRegs.forEach{ (reg, count) -> usedRegisters+=count }
val used = chunk.usedRegisters() used.outputRegs.forEach{ (reg, count) -> usedRegisters+=count }
usedRegisters += used.inputRegs + used.outputRegs used.inputFpRegs.forEach{ (reg, count) -> usedRegisters+=count }
usedFpRegisters += used.inputFpRegs + used.outputFpRegs used.outputFpRegs.forEach{ (reg, count) -> usedRegisters+=count }
}
it.subroutines.forEach { sub ->
sub.chunks.forEach { chunk ->
val used = chunk.usedRegisters()
usedRegisters += used.inputRegs + used.outputRegs
usedFpRegisters += used.inputFpRegs + used.outputFpRegs
}
}
it.asmSubroutines.forEach { asmsub ->
val used = asmsub.usedRegisters()
usedRegisters += used.inputRegs + used.outputRegs
usedFpRegisters += used.inputFpRegs + used.outputFpRegs
}
} }
println("($numLines lines in $numChunks code chunks, ${usedRegisters.size + usedFpRegisters.size} registers)")
irProgram.blocks.forEach {
it.inlineAssembly.forEach { chunk -> addUsed(chunk.usedRegisters()) }
it.subroutines.flatMap { sub->sub.chunks }.forEach { chunk -> addUsed(chunk.usedRegisters()) }
it.asmSubroutines.forEach { asmsub -> addUsed(asmsub.usedRegisters()) }
}
println("($numLines lines in $numChunks code chunks, $usedRegisters registers)")
return outfile return outfile
} }

View File

@ -676,7 +676,6 @@ data class IRInstruction(
val reg2direction: OperandDirection val reg2direction: OperandDirection
val fpReg1direction: OperandDirection val fpReg1direction: OperandDirection
val fpReg2direction: OperandDirection val fpReg2direction: OperandDirection
private val registersUsed: RegistersUsed
init { init {
require(labelSymbol?.first()!='_') {"label/symbol should not start with underscore $labelSymbol"} require(labelSymbol?.first()!='_') {"label/symbol should not start with underscore $labelSymbol"}
@ -733,45 +732,43 @@ data class IRInstruction(
else else
require(reg1!=reg2) {"$opcode: reg1 and reg2 should be different"} require(reg1!=reg2) {"$opcode: reg1 and reg2 should be different"}
} }
val inputRegs = mutableSetOf<Int>()
val outputRegs = mutableSetOf<Int>()
val inputFpRegs = mutableSetOf<Int>()
val outputFpRegs = mutableSetOf<Int>()
when (reg1direction) {
OperandDirection.UNUSED -> {}
OperandDirection.INPUT -> inputRegs += reg1!!
OperandDirection.OUTPUT -> outputRegs += reg1!!
OperandDirection.INOUT -> {
inputRegs += reg1!!
outputRegs += reg1!!
}
}
when (reg2direction) {
OperandDirection.UNUSED -> {}
OperandDirection.INPUT -> inputRegs += reg2!!
else -> throw IllegalArgumentException("reg2 can only be input")
}
when (fpReg1direction) {
OperandDirection.UNUSED -> {}
OperandDirection.INPUT -> inputFpRegs += fpReg1!!
OperandDirection.OUTPUT -> outputFpRegs += fpReg1!!
OperandDirection.INOUT -> {
inputFpRegs += fpReg1!!
outputFpRegs += fpReg1!!
}
}
when (fpReg2direction) {
OperandDirection.UNUSED -> {}
OperandDirection.INPUT -> inputFpRegs += fpReg2!!
else -> throw IllegalArgumentException("fpReg2 can only be input")
}
registersUsed = RegistersUsed(inputRegs, outputRegs, inputFpRegs, outputFpRegs)
} }
override fun usedRegisters() = registersUsed fun addUsedRegistersCounts(
inputRegs: MutableMap<Int, Int>,
outputRegs: MutableMap<Int, Int>,
inputFpRegs: MutableMap<Int, Int>,
outputFpRegs: MutableMap<Int, Int>
) {
when (this.reg1direction) {
OperandDirection.UNUSED -> {}
OperandDirection.INPUT -> inputRegs[this.reg1!!] = inputRegs.getValue(this.reg1)+1
OperandDirection.OUTPUT -> outputRegs[this.reg1!!] = outputRegs.getValue(this.reg1)+1
OperandDirection.INOUT -> {
inputRegs[this.reg1!!] = inputRegs.getValue(this.reg1)+1
outputRegs[this.reg1] = outputRegs.getValue(this.reg1)+1
}
}
when (this.reg2direction) {
OperandDirection.UNUSED -> {}
OperandDirection.INPUT -> outputRegs[this.reg2!!] = outputRegs.getValue(this.reg2)+1
else -> throw IllegalArgumentException("reg2 can only be input")
}
when (this.fpReg1direction) {
OperandDirection.UNUSED -> {}
OperandDirection.INPUT -> inputFpRegs[this.fpReg1!!] = inputFpRegs.getValue(this.fpReg1)+1
OperandDirection.OUTPUT -> outputFpRegs[this.fpReg1!!] = outputFpRegs.getValue(this.fpReg1)+1
OperandDirection.INOUT -> {
inputFpRegs[this.fpReg1!!] = inputFpRegs.getValue(this.fpReg1)+1
outputFpRegs[this.fpReg1] = outputFpRegs.getValue(this.fpReg1)+1
}
}
when (this.fpReg2direction) {
OperandDirection.UNUSED -> {}
OperandDirection.INPUT -> inputFpRegs[this.fpReg2!!] = inputFpRegs.getValue(this.fpReg2)+1
else -> throw IllegalArgumentException("fpReg2 can only be input")
}
}
override fun toString(): String { override fun toString(): String {
val result = mutableListOf(opcode.name.lowercase()) val result = mutableListOf(opcode.name.lowercase())

View File

@ -144,21 +144,13 @@ class IRAsmSubroutine(
fun usedRegisters() = registersUsed fun usedRegisters() = registersUsed
} }
sealed class IRCodeLine { sealed class IRCodeLine
abstract fun usedRegisters(): RegistersUsed
}
class IRCodeLabel(val name: String): IRCodeLine() { class IRCodeLabel(val name: String): IRCodeLine()
override fun usedRegisters() = RegistersUsed.EMPTY
}
class IRCodeComment(val comment: String): IRCodeLine() { class IRCodeComment(val comment: String): IRCodeLine()
override fun usedRegisters() = RegistersUsed.EMPTY
}
class IRCodeInlineBinary(val data: Collection<UByte>): IRCodeLine() { class IRCodeInlineBinary(val data: Collection<UByte>): IRCodeLine()
override fun usedRegisters() = RegistersUsed.EMPTY
}
abstract class IRCodeChunkBase(val position: Position) { abstract class IRCodeChunkBase(val position: Position) {
val lines = mutableListOf<IRCodeLine>() val lines = mutableListOf<IRCodeLine>()
@ -173,16 +165,13 @@ class IRCodeChunk(position: Position): IRCodeChunkBase(position) {
override fun isEmpty() = lines.isEmpty() override fun isEmpty() = lines.isEmpty()
override fun isNotEmpty() = lines.isNotEmpty() override fun isNotEmpty() = lines.isNotEmpty()
override fun usedRegisters(): RegistersUsed { override fun usedRegisters(): RegistersUsed {
val inputRegs = mutableSetOf<Int>() val inputRegs = mutableMapOf<Int, Int>().withDefault { 0 }
val outputRegs = mutableSetOf<Int>() val inputFpRegs = mutableMapOf<Int, Int>().withDefault { 0 }
val inputFpRegs = mutableSetOf<Int>() val outputRegs = mutableMapOf<Int, Int>().withDefault { 0 }
val outputFpRegs = mutableSetOf<Int>() val outputFpRegs = mutableMapOf<Int, Int>().withDefault { 0 }
lines.forEach { lines.forEach {
val used = it.usedRegisters() if(it is IRInstruction)
inputRegs += used.inputRegs it.addUsedRegistersCounts(inputRegs, outputRegs, inputFpRegs, outputFpRegs)
outputRegs += used.outputRegs
inputFpRegs += used.inputFpRegs
outputFpRegs += used.outputFpRegs
} }
return RegistersUsed(inputRegs, outputRegs, inputFpRegs, outputFpRegs) return RegistersUsed(inputRegs, outputRegs, inputFpRegs, outputFpRegs)
} }
@ -197,10 +186,11 @@ class IRCodeChunk(position: Position): IRCodeChunkBase(position) {
} }
class RegistersUsed( class RegistersUsed(
val inputRegs: Set<Int>, // register num -> number of uses
val outputRegs: Set<Int>, val inputRegs: Map<Int, Int>,
val inputFpRegs: Set<Int>, val outputRegs: Map<Int, Int>,
val outputFpRegs: Set<Int> val inputFpRegs: Map<Int, Int>,
val outputFpRegs: Map<Int, Int>,
) { ) {
override fun toString(): String { override fun toString(): String {
return "input=$inputRegs, output=$outputRegs, inputFp=$inputFpRegs, outputFp=$outputFpRegs" return "input=$inputRegs, output=$outputRegs, inputFp=$inputFpRegs, outputFp=$outputFpRegs"
@ -208,10 +198,6 @@ class RegistersUsed(
fun isEmpty() = inputRegs.isEmpty() && outputRegs.isEmpty() && inputFpRegs.isEmpty() && outputFpRegs.isEmpty() fun isEmpty() = inputRegs.isEmpty() && outputRegs.isEmpty() && inputFpRegs.isEmpty() && outputFpRegs.isEmpty()
fun isNotEmpty() = !isEmpty() fun isNotEmpty() = !isEmpty()
companion object {
val EMPTY = RegistersUsed(emptySet(), emptySet(), emptySet(), emptySet())
}
} }
class IRInlineAsmChunk(val assembly: String, val isIR: Boolean, position: Position): IRCodeChunkBase(position) { class IRInlineAsmChunk(val assembly: String, val isIR: Boolean, position: Position): IRCodeChunkBase(position) {
@ -229,19 +215,16 @@ class IRInlineAsmChunk(val assembly: String, val isIR: Boolean, position: Positi
} }
private fun registersUsedInAssembly(isIR: Boolean, assembly: String): RegistersUsed { private fun registersUsedInAssembly(isIR: Boolean, assembly: String): RegistersUsed {
val inputRegs = mutableSetOf<Int>() val inputRegs = mutableMapOf<Int, Int>().withDefault { 0 }
val inputFpRegs = mutableSetOf<Int>() val inputFpRegs = mutableMapOf<Int, Int>().withDefault { 0 }
val outputRegs = mutableSetOf<Int>() val outputRegs = mutableMapOf<Int, Int>().withDefault { 0 }
val outputFpRegs = mutableSetOf<Int>() val outputFpRegs = mutableMapOf<Int, Int>().withDefault { 0 }
if(isIR) { if(isIR) {
assembly.lineSequence().forEach { line -> assembly.lineSequence().forEach { line ->
val code = parseIRCodeLine(line.trim(), 0, mutableMapOf()) val code = parseIRCodeLine(line.trim(), 0, mutableMapOf())
val used = code.usedRegisters() if(code is IRInstruction)
inputRegs += used.inputRegs code.addUsedRegistersCounts(inputRegs, outputRegs, inputFpRegs, outputFpRegs)
outputRegs += used.outputRegs
inputFpRegs += used.inputFpRegs
outputFpRegs += used.outputFpRegs
} }
} }