ir: enforce single reg type

This commit is contained in:
Irmen de Jong 2024-12-27 22:32:16 +01:00
parent f42e12bc13
commit ee521793f8
4 changed files with 67 additions and 59 deletions

View File

@ -56,6 +56,7 @@ Future Things and Ideas
IR/VM
-----
- fix the syscall interface. It should not use r0 as return reg, but something in the 65000 range. Also, separete input regs for byte or word types.
- getting it in shape for code generation...: the IR file should be able to encode every detail about a prog8 program (the VM doesn't have to actually be able to run all of it though!)
- add BZ and BNZ instructions? To replace CMPI #0 + Branch?
- fix TODO("IR rol/ror on split words array")

View File

@ -139,14 +139,8 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
if (usedRegs.writeRegs.any())
regs.append(" write: ${usedRegs.writeRegs.toSortedMap().map { (reg, amount) -> "r$reg=${amount}" }}\n")
regs.append(" types:\n")
for ((regnum, types) in usedRegs.regsTypes.toSortedMap()) {
regs.append(" r$regnum -> $types")
if (types.size > 1) {
regs.append(" !!!! more than one type !!!!\n")
println("IR: Detected multi-type register usage: $regnum->$types in ${chunk.label} at perhaps ${chunk.sourceLinesPositions.firstOrNull()}")
}
else
regs.append("\n")
for ((regnum, type) in usedRegs.regsTypes.toSortedMap()) {
regs.append(" r$regnum -> $type\n")
}
}
if(usedRegs.readFpRegs.any() || usedRegs.writeFpRegs.any()) {

View File

@ -83,7 +83,8 @@ call label(argument register list) [: resultreg.type]
syscall number (argument register list) [: resultreg.type]
- do a systemcall identified by number, result value(s) are pushed on value stack by the syscall code so
will be POPped off into the given resultregister if any.
Always preceded by parameter setup and preparecall instructions
Always preceded by parameter setup and preparecall instructions.
All register types (arguments + result register) are ALWAYS WORDS.
return - restore last saved instruction location and continue at that instruction. No return value.
returnr reg1 - like return, but also returns the value in reg1 to the caller
returni number - like return, but also returns the immediate value to the caller
@ -862,7 +863,7 @@ data class IRInstruction(
writeRegsCounts: MutableMap<Int, Int>,
readFpRegsCounts: MutableMap<Int, Int>,
writeFpRegsCounts: MutableMap<Int, Int>,
regsTypes: MutableMap<Int, MutableSet<IRDataType>>
regsTypes: MutableMap<Int, IRDataType>
) {
when (this.reg1direction) {
OperandDirection.UNUSED -> {}
@ -870,20 +871,25 @@ data class IRInstruction(
readRegsCounts[this.reg1!!] = readRegsCounts.getValue(this.reg1)+1
val actualtype = determineReg1Type()
if(actualtype!=null) {
var types = regsTypes[this.reg1]
if(types==null) types = mutableSetOf()
types += actualtype
regsTypes[this.reg1] = types
val existingType = regsTypes[reg1]
if (existingType!=null) {
if (existingType != actualtype)
throw IllegalArgumentException("register $reg1 assigned multiple types! $existingType and $actualtype")
} else
regsTypes[reg1] = actualtype
}
}
OperandDirection.WRITE -> {
writeRegsCounts[this.reg1!!] = writeRegsCounts.getValue(this.reg1)+1
val actualtype = determineReg1Type()
if(actualtype!=null) {
var types = regsTypes[this.reg1]
if(types==null) types = mutableSetOf()
types += actualtype
regsTypes[this.reg1] = types
val existingType = regsTypes[reg1]
if (existingType!=null) {
if (existingType != actualtype)
throw IllegalArgumentException("register $reg1 assigned multiple types! $existingType and $actualtype")
} else
regsTypes[reg1] = actualtype
}
}
OperandDirection.READWRITE -> {
@ -891,10 +897,13 @@ data class IRInstruction(
writeRegsCounts[this.reg1] = writeRegsCounts.getValue(this.reg1)+1
val actualtype = determineReg1Type()
if(actualtype!=null) {
var types = regsTypes[this.reg1]
if(types==null) types = mutableSetOf()
types += actualtype
regsTypes[this.reg1] = types
val existingType = regsTypes[reg1]
if (existingType!=null) {
if (existingType != actualtype)
throw IllegalArgumentException("register $reg1 assigned multiple types! $existingType and $actualtype")
} else
regsTypes[reg1] = actualtype
}
}
}
@ -904,10 +913,12 @@ data class IRInstruction(
writeRegsCounts[this.reg2!!] = writeRegsCounts.getValue(this.reg2)+1
val actualtype = determineReg2Type()
if(actualtype!=null) {
var types = regsTypes[this.reg2]
if(types==null) types = mutableSetOf()
types += actualtype
regsTypes[this.reg2] = types
val existingType = regsTypes[reg2]
if (existingType!=null) {
if (existingType != actualtype)
throw IllegalArgumentException("register $reg2 assigned multiple types! $existingType and $actualtype")
} else
regsTypes[reg2] = actualtype
}
}
else -> throw IllegalArgumentException("reg2 can only be read")
@ -918,10 +929,12 @@ data class IRInstruction(
writeRegsCounts[this.reg3!!] = writeRegsCounts.getValue(this.reg3)+1
val actualtype = determineReg3Type()
if(actualtype!=null) {
var types = regsTypes[this.reg3]
if(types==null) types = mutableSetOf()
types += actualtype
regsTypes[this.reg3] = types
val existingType = regsTypes[reg3]
if (existingType!=null) {
if (existingType != actualtype)
throw IllegalArgumentException("register $reg3 assigned multiple types! $existingType and $actualtype")
} else
regsTypes[reg3] = actualtype
}
}
else -> throw IllegalArgumentException("reg3 can only be read")
@ -949,13 +962,12 @@ data class IRInstruction(
writeFpRegsCounts[it.registerNum] = writeFpRegsCounts.getValue(it.registerNum) + 1
else {
writeRegsCounts[it.registerNum] = writeRegsCounts.getValue(it.registerNum) + 1
val types = regsTypes[it.registerNum]
if (types == null) {
regsTypes[it.registerNum] = mutableSetOf(it.dt)
} else {
types += it.dt
regsTypes[it.registerNum] = types
}
val existingType = regsTypes[it.registerNum]
if (existingType!=null) {
if (existingType != it.dt)
throw IllegalArgumentException("register ${it.registerNum} assigned multiple types! $existingType and ${it.dt}")
} else
regsTypes[it.registerNum] = it.dt
}
}
fcallArgs.arguments.forEach {
@ -963,13 +975,12 @@ data class IRInstruction(
readFpRegsCounts[it.reg.registerNum] = readFpRegsCounts.getValue(it.reg.registerNum)+1
else {
readRegsCounts[it.reg.registerNum] = readRegsCounts.getValue(it.reg.registerNum) + 1
val types = regsTypes[it.reg.registerNum]
if(types==null) {
regsTypes[it.reg.registerNum] = mutableSetOf(it.reg.dt)
} else {
types += it.reg.dt
regsTypes[it.reg.registerNum] = types
}
val existingType = regsTypes[it.reg.registerNum]
if (existingType!=null) {
if (existingType != it.reg.dt)
throw IllegalArgumentException("register ${it.reg.registerNum} assigned multiple types! $existingType and ${it.reg.dt}")
} else
regsTypes[it.reg.registerNum] = it.reg.dt
}
}
}

View File

@ -265,21 +265,23 @@ class IRProgram(val name: String,
fun registersUsed(): RegistersUsed {
val readRegsCounts = mutableMapOf<Int, Int>().withDefault { 0 }
val regsTypes = mutableMapOf<Int, MutableSet<IRDataType>>()
val regsTypes = mutableMapOf<Int, IRDataType>()
val readFpRegsCounts = mutableMapOf<Int, Int>().withDefault { 0 }
val writeRegsCounts = mutableMapOf<Int, Int>().withDefault { 0 }
val writeFpRegsCounts = mutableMapOf<Int, Int>().withDefault { 0 }
fun addUsed(usedRegisters: RegistersUsed) {
fun addUsed(usedRegisters: RegistersUsed, child: IIRBlockElement) {
usedRegisters.readRegs.forEach{ (reg, count) -> readRegsCounts[reg] = readRegsCounts.getValue(reg) + count }
usedRegisters.writeRegs.forEach{ (reg, count) -> writeRegsCounts[reg] = writeRegsCounts.getValue(reg) + count }
usedRegisters.readFpRegs.forEach{ (reg, count) -> readFpRegsCounts[reg] = readFpRegsCounts.getValue(reg) + count }
usedRegisters.writeFpRegs.forEach{ (reg, count) -> writeFpRegsCounts[reg] = writeFpRegsCounts.getValue(reg) + count }
usedRegisters.regsTypes.forEach{ (reg, types) ->
var t = regsTypes[reg]
if(t==null) t = mutableSetOf()
t += types
regsTypes[reg] = t
usedRegisters.regsTypes.forEach{ (reg, type) ->
val existingType = regsTypes[reg]
if (existingType!=null) {
if (existingType != type)
throw IllegalArgumentException("register $reg assigned multiple types! $existingType and $type ${this.name}<--${child.label ?: child}")
} else
regsTypes[reg] = type
}
}
@ -290,11 +292,11 @@ class IRProgram(val name: String,
blocks.forEach {block ->
block.children.forEach { child ->
when(child) {
is IRAsmSubroutine -> addUsed(child.usedRegisters())
is IRCodeChunk -> addUsed(child.usedRegisters())
is IRInlineAsmChunk -> addUsed(child.usedRegisters())
is IRInlineBinaryChunk -> addUsed(child.usedRegisters())
is IRSubroutine -> child.chunks.forEach { chunk -> addUsed(chunk.usedRegisters()) }
is IRAsmSubroutine -> addUsed(child.usedRegisters(), child)
is IRCodeChunk -> addUsed(child.usedRegisters(), child)
is IRInlineAsmChunk -> addUsed(child.usedRegisters(), child)
is IRInlineBinaryChunk -> addUsed(child.usedRegisters(), child)
is IRSubroutine -> child.chunks.forEach { chunk -> addUsed(chunk.usedRegisters(), child) }
}
}
}
@ -468,7 +470,7 @@ class IRCodeChunk(label: String?, next: IRCodeChunkBase?): IRCodeChunkBase(label
override fun isNotEmpty() = instructions.isNotEmpty()
override fun usedRegisters(): RegistersUsed {
val readRegsCounts = mutableMapOf<Int, Int>().withDefault { 0 }
val regsTypes = mutableMapOf<Int, MutableSet<IRDataType>>()
val regsTypes = mutableMapOf<Int, IRDataType>()
val readFpRegsCounts = mutableMapOf<Int, Int>().withDefault { 0 }
val writeRegsCounts = mutableMapOf<Int, Int>().withDefault { 0 }
val writeFpRegsCounts = mutableMapOf<Int, Int>().withDefault { 0 }
@ -530,7 +532,7 @@ class RegistersUsed(
val writeRegs: Map<Int, Int>,
val readFpRegs: Map<Int, Int>,
val writeFpRegs: Map<Int, Int>,
val regsTypes: Map<Int, Set<IRDataType>>
val regsTypes: Map<Int, IRDataType>
) {
override fun toString(): String {
@ -546,7 +548,7 @@ class RegistersUsed(
private fun registersUsedInAssembly(isIR: Boolean, assembly: String): RegistersUsed {
val readRegsCounts = mutableMapOf<Int, Int>().withDefault { 0 }
val regsTypes = mutableMapOf<Int, MutableSet<IRDataType>>()
val regsTypes = mutableMapOf<Int, IRDataType>()
val readFpRegsCounts = mutableMapOf<Int, Int>().withDefault { 0 }
val writeRegsCounts = mutableMapOf<Int, Int>().withDefault { 0 }
val writeFpRegsCounts = mutableMapOf<Int, Int>().withDefault { 0 }