mirror of
https://github.com/irmen/prog8.git
synced 2024-09-07 03:54:27 +00:00
ir: count register uses
This commit is contained in:
parent
af6be44676
commit
e7682119e0
@ -3,8 +3,6 @@ TODO
|
||||
|
||||
For next release
|
||||
^^^^^^^^^^^^^^^^
|
||||
- ir: RegistersUsed should actually count the number of times a register is used too?
|
||||
|
||||
...
|
||||
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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())
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user