mirror of
https://github.com/irmen/prog8.git
synced 2024-12-24 16:29:21 +00:00
ir: count register uses
This commit is contained in:
parent
af6be44676
commit
e7682119e0
@ -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?
|
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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())
|
||||||
|
@ -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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user