improve detection of register re-use in parameters

This commit is contained in:
Irmen de Jong 2024-11-24 05:27:43 +01:00
parent cc53d698bf
commit 18e37accf9
2 changed files with 48 additions and 62 deletions

View File

@ -451,66 +451,49 @@ internal class AstChecker(private val program: Program,
} }
} }
val regCounts = mutableMapOf<CpuRegister, Int>().withDefault { 0 } val regsUsed = mutableListOf<RegisterOrPair>()
val statusflagCounts = mutableMapOf<Statusflag, Int>().withDefault { 0 } val statusflagUsed = mutableListOf<Statusflag>()
fun countRegisters(from: Iterable<RegisterOrStatusflag>) { fun countRegisters(from: Iterable<RegisterOrStatusflag>) {
regCounts.clear() regsUsed.clear()
statusflagCounts.clear() statusflagUsed.clear()
for(p in from) { for(p in from) {
when(p.registerOrPair) { when(p.registerOrPair) {
RegisterOrPair.A -> regCounts[CpuRegister.A]=regCounts.getValue(CpuRegister.A)+1 null -> {
RegisterOrPair.X -> regCounts[CpuRegister.X]=regCounts.getValue(CpuRegister.X)+1 if (p.statusflag != null)
RegisterOrPair.Y -> regCounts[CpuRegister.Y]=regCounts.getValue(CpuRegister.Y)+1 statusflagUsed += p.statusflag!!
}
RegisterOrPair.AX -> { RegisterOrPair.AX -> {
regCounts[CpuRegister.A]=regCounts.getValue(CpuRegister.A)+1 regsUsed += RegisterOrPair.A
regCounts[CpuRegister.X]=regCounts.getValue(CpuRegister.X)+1 regsUsed += RegisterOrPair.X
} }
RegisterOrPair.AY -> { RegisterOrPair.AY -> {
regCounts[CpuRegister.A]=regCounts.getValue(CpuRegister.A)+1 regsUsed += RegisterOrPair.A
regCounts[CpuRegister.Y]=regCounts.getValue(CpuRegister.Y)+1 regsUsed += RegisterOrPair.Y
} }
RegisterOrPair.XY -> { RegisterOrPair.XY -> {
regCounts[CpuRegister.X]=regCounts.getValue(CpuRegister.X)+1 regsUsed += RegisterOrPair.X
regCounts[CpuRegister.Y]=regCounts.getValue(CpuRegister.Y)+1 regsUsed += RegisterOrPair.Y
}
RegisterOrPair.FAC1, RegisterOrPair.FAC2 -> { /* no sensible way to count this */ }
RegisterOrPair.R0,
RegisterOrPair.R1,
RegisterOrPair.R2,
RegisterOrPair.R3,
RegisterOrPair.R4,
RegisterOrPair.R5,
RegisterOrPair.R6,
RegisterOrPair.R7,
RegisterOrPair.R8,
RegisterOrPair.R9,
RegisterOrPair.R10,
RegisterOrPair.R11,
RegisterOrPair.R12,
RegisterOrPair.R13,
RegisterOrPair.R14,
RegisterOrPair.R15 -> { /* no sensible way to count this */ }
null -> {
val statusf = p.statusflag
if (statusf != null)
statusflagCounts[statusf] = statusflagCounts.getValue(statusf) + 1
} }
else -> regsUsed += p.registerOrPair!!
} }
} }
} }
countRegisters(subroutine.asmParameterRegisters) countRegisters(subroutine.asmParameterRegisters)
if(regCounts.any{it.value>1}) if(regsUsed.size != regsUsed.toSet().size)
err("a register is used multiple times in the parameters") err("a register is used multiple times in the parameters")
if(statusflagCounts.any{it.value>1}) if(statusflagUsed.size != statusflagUsed.toSet().size)
err("a status flag is used multiple times in the parameters") err("a status flag is used multiple times in the parameters")
countRegisters(subroutine.asmReturnvaluesRegisters) countRegisters(subroutine.asmReturnvaluesRegisters)
if(regCounts.any{it.value>1}) if(regsUsed.size != regsUsed.toSet().size)
err("a register is used multiple times in the return values") err("a register is used multiple times in the return values")
if(statusflagCounts.any{it.value>1}) if(statusflagUsed.size != statusflagUsed.toSet().size)
err("a status flag is used multiple times in the return values") err("a status flag is used multiple times in the return values")
if(subroutine.asmClobbers.intersect(regCounts.keys).isNotEmpty()) for(reg in subroutine.asmClobbers) {
if(regsUsed.contains(RegisterOrPair.fromCpuRegister(reg)))
err("a return register is also in the clobber list") err("a return register is also in the clobber list")
}
if(subroutine.statements.any{it !is InlineAssembly}) if(subroutine.statements.any{it !is InlineAssembly})
err("asmsub can only contain inline assembly (%asm)") err("asmsub can only contain inline assembly (%asm)")

View File

@ -3,31 +3,34 @@
main { main {
sub start() { sub start() {
const long foo2 = $123456 foo(42)
cx16.r0 = $ffff bar(9999,55)
cx16.r1 = $ea31
txt.print_uwbin(cx16.r1 << 7, true)
txt.nl()
txt.print_uwhex(cx16.r0 ^ cx16.r1, true)
txt.nl()
txt.print_ubhex(^cx16.r0, true)
txt.spc()
txt.print_uwhex(<<cx16.r0, false)
txt.nl()
txt.print_ubhex(^foo2, true)
txt.spc()
txt.print_uwhex(<<foo2, false)
txt.nl()
txt.print_ubhex(bankof(foo2), true)
txt.spc()
txt.print_uwhex(foo2 &$ffff, false)
txt.nl() txt.nl()
test(1,2,3)
test2(1)
}
txt.print_ubhex(msw(foo2), true) sub foo(ubyte arg) {
txt.spc() txt.print_ub(arg)
txt.print_uwhex(lsw(foo2), false)
txt.nl() txt.nl()
}
sub bar(uword arg, ubyte arg2) {
txt.print_uw(arg)
txt.spc()
txt.print_ub(arg2)
txt.nl()
}
asmsub test(ubyte a1 @R1, ubyte a2 @R1, ubyte a3 @R2) { ; TODO should give register reuse error
%asm {{
rts
}}
}
asmsub test2(uword a1 @AY) clobbers(A, X) -> ubyte @X {
%asm {{
rts
}}
} }
} }