IR: fix m68k indexing datatype size

This commit is contained in:
Irmen de Jong committed 2026-08-08 18:14:30 +02:00
1 parent e2e72a1791
commit 9c8e81b566
14 files changed
+164 -93

No files matched your search

@@ -743,7 +743,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val exprGen
}
result += chunk
} else {
val (code, indexReg) = codeGen.loadIndexReg(targetArray.index, eltSize, false, targetArray.splitWords)
val (code, indexReg) = codeGen.loadIndexReg(targetArray.index, eltSize, codeGen.wordArrayIndex, targetArray.splitWords)
result += code
result += IRCodeChunk(null, null).also {
if(targetArray.splitWords) {
@@ -763,7 +763,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val exprGen
}
result += chunk
} else {
val (code, indexReg) = codeGen.loadIndexReg(targetArray.index, eltSize, false, targetArray.splitWords)
val (code, indexReg) = codeGen.loadIndexReg(targetArray.index, eltSize, codeGen.wordArrayIndex, targetArray.splitWords)
result += code
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.STOREX, targetDt, reg1 = indexReg, fpReg1 = RegisterNum(valueFpRegister), labelSymbol = variable)
@@ -784,7 +784,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val exprGen
}
result += chunk
} else {
val (code, indexReg) = codeGen.loadIndexReg(targetArray.index, eltSize, false, targetArray.splitWords)
val (code, indexReg) = codeGen.loadIndexReg(targetArray.index, eltSize, codeGen.wordArrayIndex, targetArray.splitWords)
result += code
result += IRCodeChunk(null, null).also {
if(targetArray.splitWords) {
@@ -5,7 +5,6 @@ import prog8.code.SymbolTable
import prog8.code.ast.*
import prog8.code.core.AssemblyError
import prog8.code.core.BaseDataType
import prog8.code.core.DataType
import prog8.intermediate.*
@@ -926,18 +925,17 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
it += IRInstruction(Opcode.STOREZX, IRDataType.BYTE, reg1=offsetReg, labelSymbol = targetVariable.name)
}
} else {
val indexTr = exprGen.translateExpression(target.index)
addToResult(result, indexTr, indexTr.resultReg, -1)
val (code, indexReg) = codeGen.loadIndexReg(target.index, eltSize, codeGen.wordArrayIndex, false)
result += code
val indexDt = if(codeGen.wordArrayIndex) IRDataType.WORD else IRDataType.BYTE
result += IRCodeChunk(null, null).also {
if(eltSize>1)
it += codeGen.multiplyByConst(DataType.UBYTE, indexTr.resultReg, eltSize)
if(msb) {
it += if(target.type.isLong)
IRInstruction(Opcode.ADD, IRDataType.BYTE, reg1 = indexTr.resultReg, immediate = 3)
IRInstruction(Opcode.ADD, indexDt, reg1 = indexReg, immediate = 3)
else
IRInstruction(Opcode.INC, IRDataType.BYTE, reg1 = indexTr.resultReg)
IRInstruction(Opcode.INC, indexDt, reg1 = indexReg)
}
it += IRInstruction(Opcode.STOREZX, IRDataType.BYTE, reg1=indexTr.resultReg, labelSymbol = targetVariable.name)
it += IRInstruction(Opcode.STOREZX, IRDataType.BYTE, reg1=indexReg, labelSymbol = targetVariable.name)
}
}
} else {
@@ -951,18 +949,17 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1=valueTr.resultReg, reg2=offsetReg, labelSymbol = targetVariable.name)
}
} else {
val indexTr = exprGen.translateExpression(target.index)
addToResult(result, indexTr, indexTr.resultReg, -1)
val (code, indexReg) = codeGen.loadIndexReg(target.index, eltSize, codeGen.wordArrayIndex, false)
result += code
val indexDt = if(codeGen.wordArrayIndex) IRDataType.WORD else IRDataType.BYTE
result += IRCodeChunk(null, null).also {
if(eltSize>1)
it += codeGen.multiplyByConst(DataType.UBYTE, indexTr.resultReg, eltSize)
if(msb) {
it += if(target.type.isLong)
IRInstruction(Opcode.ADD, IRDataType.BYTE, reg1 = indexTr.resultReg, immediate = 3)
IRInstruction(Opcode.ADD, indexDt, reg1 = indexReg, immediate = 3)
else
IRInstruction(Opcode.INC, IRDataType.BYTE, reg1 = indexTr.resultReg)
IRInstruction(Opcode.INC, indexDt, reg1 = indexReg)
}
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1=valueTr.resultReg, reg2=indexTr.resultReg, labelSymbol = targetVariable.name)
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1=valueTr.resultReg, reg2=indexReg, labelSymbol = targetVariable.name)
}
}
}
@@ -643,15 +643,15 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
}
fun indexByExpression() {
val (code, indexByteReg) = codeGen.loadIndexReg(arrayIx.index, eltSize, false, arrayIx.splitWords)
val (code, indexReg) = codeGen.loadIndexReg(arrayIx.index, eltSize, codeGen.wordArrayIndex, arrayIx.splitWords)
result += code
if(vmDt==IRDataType.FLOAT) {
resultFpRegister = codeGen.registers.next(IRDataType.FLOAT)
addInstr(result, IRInstruction(Opcode.LOADX, IRDataType.FLOAT, fpReg1 = RegisterNum(resultFpRegister), reg1=indexByteReg, labelSymbol = arrayVarSymbol), null)
addInstr(result, IRInstruction(Opcode.LOADX, IRDataType.FLOAT, fpReg1 = RegisterNum(resultFpRegister), reg1=indexReg, labelSymbol = arrayVarSymbol), null)
}
else {
resultRegister = codeGen.registers.next(vmDt)
addInstr(result, IRInstruction(Opcode.LOADX, vmDt, reg1=resultRegister, reg2=indexByteReg, labelSymbol = arrayVarSymbol), null)
addInstr(result, IRInstruction(Opcode.LOADX, vmDt, reg1=resultRegister, reg2=indexReg, labelSymbol = arrayVarSymbol), null)
}
}
@@ -30,6 +30,9 @@ class IRCodeGen(
var wasPackingApplied: Boolean = false
private set
// on 32-bit targets, LOADX/STOREX/STOREZX use a word index register (0-32767) instead of a byte (0-255)
internal val wordArrayIndex: Boolean = options.compTarget.POINTER_MEM_SIZE > 2u
fun generate(): IRProgram {
// The pure "virtual" (VM) target doesn't need symbol prefixing because the VM
// doesn't emit assembly and has no risk of symbol clashes. Any other target
@@ -80,6 +80,7 @@ class IRUnusedCodeRemover(
}
// remove stray loads
val indexRegType = if(irprog.options.compTarget.POINTER_MEM_SIZE > 2u) IRDataType.WORD else IRDataType.BYTE
val readRegs = mutableSetOf<Int>()
val readFpRegs = mutableSetOf<Int>()
instructions.forEach { ins ->
@@ -88,7 +89,7 @@ class IRUnusedCodeRemover(
val writeRegsCounts = mutableMapOf<RegisterNum, Int>()
val writeFpRegsCounts = mutableMapOf<RegisterNum, Int>()
val regsTypes = mutableMapOf<RegisterNum, IRDataType>()
ins.addUsedRegistersCounts(readRegsCounts, writeRegsCounts, readFpRegsCounts, writeFpRegsCounts, regsTypes, null)
ins.addUsedRegistersCounts(readRegsCounts, writeRegsCounts, readFpRegsCounts, writeFpRegsCounts, regsTypes, null, indexRegType)
readRegs.addAll(readRegsCounts.keys.map { it.value })
readFpRegs.addAll(readFpRegsCounts.keys.map { it.value })
}
@@ -71,12 +71,13 @@ object RegisterPacker {
data class Interval(val register: Int, val start: Int, val end: Int, val type: IRDataType)
fun pack(irProg: IRProgram) {
val indexRegType = if(irProg.options.compTarget.POINTER_MEM_SIZE > 2u) IRDataType.WORD else IRDataType.BYTE
val allRegTypes = mutableMapOf<Int, IRDataType>()
irProg.foreachCodeChunk { chunk ->
for (instr in chunk.instructions) {
val (written, read) = getRegisterAccess(instr)
for (r in written + read) {
val dt = getRegisterType(instr, r)
val dt = getRegisterType(instr, r, indexRegType)
allRegTypes.putIfAbsent(r, dt)
}
}
@@ -88,7 +89,7 @@ object RegisterPacker {
val maxReg = allRegTypes.keys.maxOrNull() ?: 0
val startSlot = maxReg + 1
val globalSlotTypes = mutableMapOf<Int, IRDataType>()
irProg.foreachSub { sub -> packSubroutine(sub, allRegTypes, globalSlotTypes, startSlot) }
irProg.foreachSub { sub -> packSubroutine(sub, allRegTypes, globalSlotTypes, startSlot, indexRegType) }
val afterTypes = rebuildTypeMap(irProg)
val afterCount = afterTypes.size
@@ -100,12 +101,13 @@ object RegisterPacker {
// This avoids the strict per-instruction validation in usedRegisters() that POINTER↔LONG↔WORD
// cross-type packing can trigger.
fun rebuildTypeMap(irProg: IRProgram): Map<RegisterNum, IRDataType> {
val indexRegType = if(irProg.options.compTarget.POINTER_MEM_SIZE > 2u) IRDataType.WORD else IRDataType.BYTE
val newTypes = mutableMapOf<RegisterNum, IRDataType>()
irProg.foreachCodeChunk { chunk ->
for (instr in chunk.instructions) {
for ((reg, regNum) in listOf(instr.reg1 to 1, instr.reg2 to 2, instr.reg3 to 3)) {
if (reg != null)
newTypes.putIfAbsent(RegisterNum(reg), determineIntRegType(instr, regNum))
newTypes.putIfAbsent(RegisterNum(reg), determineIntRegType(instr, regNum, indexRegType))
}
instr.fpReg1?.let { fpr -> newTypes.putIfAbsent(RegisterNum(fpr.value), IRDataType.FLOAT) }
instr.fpReg2?.let { fpr -> newTypes.putIfAbsent(RegisterNum(fpr.value), IRDataType.FLOAT) }
@@ -120,7 +122,7 @@ object RegisterPacker {
return newTypes
}
private fun packSubroutine(sub: IRSubroutine, allRegTypes: Map<Int, IRDataType>, globalSlotTypes: MutableMap<Int, IRDataType>, startSlot: Int) {
private fun packSubroutine(sub: IRSubroutine, allRegTypes: Map<Int, IRDataType>, globalSlotTypes: MutableMap<Int, IRDataType>, startSlot: Int, indexRegType: IRDataType) {
if (sub.chunks.isEmpty())
return
@@ -160,7 +162,7 @@ object RegisterPacker {
// Process READ first so types are set before WRITE processing
for (r in read) {
val dt = getRegisterType(instr, r)
val dt = getRegisterType(instr, r, indexRegType)
registerTypes.putIfAbsent(r, dt)
if (r !in liveSet) {
lastUse[r] = globalI
@@ -172,7 +174,7 @@ object RegisterPacker {
for (r in written) {
if (r in liveSet) {
val end = lastUse.getOrElse(r) { globalI }
val actualType = getRegisterType(instr, r)
val actualType = getRegisterType(instr, r, indexRegType)
registerIntervals.getOrPut(r) { mutableListOf() }
.add(Interval(r, globalI, end, actualType))
liveSet.remove(r)
@@ -216,21 +218,21 @@ object RegisterPacker {
mergedIntervals.removeAll { it.register in skipRegs }
}
val conflictGraph = buildConflictGraph(sub)
val conflictGraph = buildConflictGraph(sub, indexRegType)
val packing = greedyColor(mergedIntervals, conflictGraph, allRegTypes, globalSlotTypes, startSlot)
if (packing.isNotEmpty())
rewrite(sub, packing)
}
private fun buildConflictGraph(sub: IRSubroutine): Map<Int, Set<Int>> {
private fun buildConflictGraph(sub: IRSubroutine, indexRegType: IRDataType): Map<Int, Set<Int>> {
val conflicts = mutableMapOf<Int, MutableSet<Int>>()
for (chunk in sub.chunks.filterIsInstance<IRCodeChunk>()) {
val typeRegs = mutableMapOf<IRDataType, MutableSet<Int>>()
for (instr in chunk.instructions) {
for ((reg, regNum) in listOf(instr.reg1 to 1, instr.reg2 to 2, instr.reg3 to 3)) {
if (reg != null) {
val dt = determineIntRegType(instr, regNum)
val dt = determineIntRegType(instr, regNum, indexRegType)
typeRegs.getOrPut(dt) { mutableSetOf() }.add(reg)
}
}
@@ -427,14 +429,14 @@ object RegisterPacker {
return written to read
}
private fun getRegisterType(instr: IRInstruction, register: Int): IRDataType {
private fun getRegisterType(instr: IRInstruction, register: Int, indexRegType: IRDataType): IRDataType {
if (instr.fpReg1?.value == register || instr.fpReg2?.value == register)
return IRDataType.FLOAT
return when {
instr.reg1 == register -> determineIntRegType(instr, 1)
instr.reg2 == register -> determineIntRegType(instr, 2)
instr.reg3 == register -> determineIntRegType(instr, 3)
instr.reg1 == register -> determineIntRegType(instr, 1, indexRegType)
instr.reg2 == register -> determineIntRegType(instr, 2, indexRegType)
instr.reg3 == register -> determineIntRegType(instr, 3, indexRegType)
else -> {
// fcallArgs registers use their own type from the RegSpec, not instr.type
val fcallArgs = instr.fcallArgs
@@ -451,7 +453,7 @@ object RegisterPacker {
}
}
private fun determineIntRegType(instr: IRInstruction, regNum: Int): IRDataType {
private fun determineIntRegType(instr: IRInstruction, regNum: Int, indexRegType: IRDataType): IRDataType {
val opcode = instr.opcode
val type = instr.type
@@ -459,7 +461,7 @@ object RegisterPacker {
return when (opcode) {
Opcode.FFROMUB, Opcode.FFROMSB, Opcode.FTOUB, Opcode.FTOSB,
Opcode.FCOMP, Opcode.SGN -> IRDataType.BYTE
Opcode.LOADX, Opcode.STOREX, Opcode.STOREZX -> IRDataType.BYTE
Opcode.LOADX, Opcode.STOREX, Opcode.STOREZX -> indexRegType
Opcode.FFROMSL, Opcode.FTOSL -> IRDataType.LONG
Opcode.LOADI, Opcode.STOREI -> IRDataType.POINTER
else -> IRDataType.WORD
@@ -468,7 +470,8 @@ object RegisterPacker {
if (type == IRDataType.WORD && regNum == 1) {
return when (opcode) {
Opcode.SGN, Opcode.STOREZX, Opcode.SQRT -> IRDataType.BYTE
Opcode.SGN, Opcode.SQRT -> IRDataType.BYTE
Opcode.STOREZX -> indexRegType
Opcode.EXT, Opcode.EXTS, Opcode.CONCAT -> IRDataType.LONG
else -> type
}
@@ -478,13 +481,14 @@ object RegisterPacker {
return when (opcode) {
Opcode.SGN -> IRDataType.BYTE
Opcode.SQRT -> IRDataType.WORD
Opcode.STOREZX -> indexRegType
else -> type
}
}
if (regNum == 2 || regNum == 3) {
return when (opcode) {
Opcode.LOADX, Opcode.STOREX -> IRDataType.BYTE
Opcode.LOADX, Opcode.STOREX -> indexRegType
Opcode.LOADI, Opcode.STOREI -> IRDataType.POINTER
Opcode.ASRN, Opcode.LSRN, Opcode.LSLN -> IRDataType.BYTE
else -> type ?: IRDataType.BYTE