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
^^^^^^^^^^^^^^^^
- 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.close()
val usedRegisters = mutableSetOf<Int>()
val usedFpRegisters = mutableSetOf<Int>()
irProgram.blocks.forEach {
it.inlineAssembly.forEach { chunk ->
val used = chunk.usedRegisters()
usedRegisters += used.inputRegs + used.outputRegs
usedFpRegisters += used.inputFpRegs + used.outputFpRegs
}
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
}
var usedRegisters = 0
fun addUsed(used: RegistersUsed) {
used.inputRegs.forEach{ (reg, count) -> usedRegisters+=count }
used.outputRegs.forEach{ (reg, count) -> usedRegisters+=count }
used.inputFpRegs.forEach{ (reg, count) -> usedRegisters+=count }
used.outputFpRegs.forEach{ (reg, count) -> usedRegisters+=count }
}
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
}

View File

@ -676,7 +676,6 @@ data class IRInstruction(
val reg2direction: OperandDirection
val fpReg1direction: OperandDirection
val fpReg2direction: OperandDirection
private val registersUsed: RegistersUsed
init {
require(labelSymbol?.first()!='_') {"label/symbol should not start with underscore $labelSymbol"}
@ -733,45 +732,43 @@ data class IRInstruction(
else
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 {
val result = mutableListOf(opcode.name.lowercase())

View File

@ -144,21 +144,13 @@ class IRAsmSubroutine(
fun usedRegisters() = registersUsed
}
sealed class IRCodeLine {
abstract fun usedRegisters(): RegistersUsed
}
sealed class IRCodeLine
class IRCodeLabel(val name: String): IRCodeLine() {
override fun usedRegisters() = RegistersUsed.EMPTY
}
class IRCodeLabel(val name: String): IRCodeLine()
class IRCodeComment(val comment: String): IRCodeLine() {
override fun usedRegisters() = RegistersUsed.EMPTY
}
class IRCodeComment(val comment: String): IRCodeLine()
class IRCodeInlineBinary(val data: Collection<UByte>): IRCodeLine() {
override fun usedRegisters() = RegistersUsed.EMPTY
}
class IRCodeInlineBinary(val data: Collection<UByte>): IRCodeLine()
abstract class IRCodeChunkBase(val position: Position) {
val lines = mutableListOf<IRCodeLine>()
@ -173,16 +165,13 @@ class IRCodeChunk(position: Position): IRCodeChunkBase(position) {
override fun isEmpty() = lines.isEmpty()
override fun isNotEmpty() = lines.isNotEmpty()
override fun usedRegisters(): RegistersUsed {
val inputRegs = mutableSetOf<Int>()
val outputRegs = mutableSetOf<Int>()
val inputFpRegs = mutableSetOf<Int>()
val outputFpRegs = mutableSetOf<Int>()
val inputRegs = mutableMapOf<Int, Int>().withDefault { 0 }
val inputFpRegs = mutableMapOf<Int, Int>().withDefault { 0 }
val outputRegs = mutableMapOf<Int, Int>().withDefault { 0 }
val outputFpRegs = mutableMapOf<Int, Int>().withDefault { 0 }
lines.forEach {
val used = it.usedRegisters()
inputRegs += used.inputRegs
outputRegs += used.outputRegs
inputFpRegs += used.inputFpRegs
outputFpRegs += used.outputFpRegs
if(it is IRInstruction)
it.addUsedRegistersCounts(inputRegs, outputRegs, inputFpRegs, outputFpRegs)
}
return RegistersUsed(inputRegs, outputRegs, inputFpRegs, outputFpRegs)
}
@ -197,10 +186,11 @@ class IRCodeChunk(position: Position): IRCodeChunkBase(position) {
}
class RegistersUsed(
val inputRegs: Set<Int>,
val outputRegs: Set<Int>,
val inputFpRegs: Set<Int>,
val outputFpRegs: Set<Int>
// register num -> number of uses
val inputRegs: Map<Int, Int>,
val outputRegs: Map<Int, Int>,
val inputFpRegs: Map<Int, Int>,
val outputFpRegs: Map<Int, Int>,
) {
override fun toString(): String {
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 isNotEmpty() = !isEmpty()
companion object {
val EMPTY = RegistersUsed(emptySet(), emptySet(), emptySet(), emptySet())
}
}
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 {
val inputRegs = mutableSetOf<Int>()
val inputFpRegs = mutableSetOf<Int>()
val outputRegs = mutableSetOf<Int>()
val outputFpRegs = mutableSetOf<Int>()
val inputRegs = mutableMapOf<Int, Int>().withDefault { 0 }
val inputFpRegs = mutableMapOf<Int, Int>().withDefault { 0 }
val outputRegs = mutableMapOf<Int, Int>().withDefault { 0 }
val outputFpRegs = mutableMapOf<Int, Int>().withDefault { 0 }
if(isIR) {
assembly.lineSequence().forEach { line ->
val code = parseIRCodeLine(line.trim(), 0, mutableMapOf())
val used = code.usedRegisters()
inputRegs += used.inputRegs
outputRegs += used.outputRegs
inputFpRegs += used.inputFpRegs
outputFpRegs += used.outputFpRegs
if(code is IRInstruction)
code.addUsedRegistersCounts(inputRegs, outputRegs, inputFpRegs, outputFpRegs)
}
}