mirror of
https://github.com/irmen/prog8.git
synced 2026-10-22 05:02:58 +00:00
ir: canonicalize LOADX/STOREX/STOREZX index width and remove guessed-type workaround
This commit is contained in:
1 parent
da0df8f133
commit
cf50372515
12 files changed
+172
-62
No files matched your search
@@ -12,11 +12,35 @@ import prog8.intermediate.*
|
||||
internal class AssignmentGen(private val codeGen: IRCodeGen, private val exprGen: ExpressionGen) {
|
||||
|
||||
private fun normalizeArrayIndex(result: MutableList<IRCodeChunkBase>, indexTr: ExpressionCodeResult): Pair<Int, DataType> {
|
||||
if(codeGen.options.compTarget.POINTER_MEM_SIZE <= 2u || indexTr.dt != IRDataType.BYTE)
|
||||
return indexTr.resultReg to DataType.UBYTE
|
||||
val indexReg = codeGen.registers.next(IRDataType.WORD)
|
||||
addInstr(result, IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1=indexReg, reg2=indexTr.resultReg), null)
|
||||
return indexReg to DataType.UWORD
|
||||
val indexRegType = codeGen.options.compTarget.indexRegType
|
||||
if(indexTr.dt == indexRegType)
|
||||
return indexTr.resultReg to if(indexRegType==IRDataType.WORD) DataType.UWORD else DataType.UBYTE
|
||||
// handle POINTER as its underlying size for the purpose of index canonicalization
|
||||
val effectiveDt = if(indexTr.dt==IRDataType.POINTER) codeGen.options.compTarget.pointerIRType else indexTr.dt
|
||||
if(effectiveDt == indexRegType)
|
||||
return indexTr.resultReg to if(indexRegType==IRDataType.WORD) DataType.UWORD else DataType.UBYTE
|
||||
val newReg = codeGen.registers.next(indexRegType)
|
||||
when {
|
||||
indexRegType==IRDataType.WORD && indexTr.dt==IRDataType.BYTE ->
|
||||
addInstr(result, IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1=newReg, reg2=indexTr.resultReg), null)
|
||||
indexRegType==IRDataType.WORD && indexTr.dt==IRDataType.LONG ->
|
||||
addInstr(result, IRInstruction(Opcode.LSIGW, IRDataType.LONG, reg1=newReg, reg2=indexTr.resultReg), null)
|
||||
indexRegType==IRDataType.WORD && indexTr.dt==IRDataType.POINTER ->
|
||||
addInstr(result, IRInstruction(Opcode.LSIGW, IRDataType.LONG, reg1=newReg, reg2=indexTr.resultReg), null)
|
||||
indexRegType==IRDataType.BYTE && indexTr.dt==IRDataType.WORD ->
|
||||
addInstr(result, IRInstruction(Opcode.LSIGB, IRDataType.WORD, reg1=newReg, reg2=indexTr.resultReg), null)
|
||||
indexRegType==IRDataType.BYTE && indexTr.dt==IRDataType.LONG ->
|
||||
addInstr(result, IRInstruction(Opcode.LSIGB, IRDataType.LONG, reg1=newReg, reg2=indexTr.resultReg), null)
|
||||
indexRegType==IRDataType.BYTE && indexTr.dt==IRDataType.POINTER -> {
|
||||
val ptrType = codeGen.options.compTarget.pointerIRType
|
||||
if(ptrType==IRDataType.WORD)
|
||||
addInstr(result, IRInstruction(Opcode.LSIGB, IRDataType.WORD, reg1=newReg, reg2=indexTr.resultReg), null)
|
||||
else
|
||||
addInstr(result, IRInstruction(Opcode.LSIGB, IRDataType.LONG, reg1=newReg, reg2=indexTr.resultReg), null)
|
||||
}
|
||||
else -> throw IllegalArgumentException("unexpected index conversion ${indexTr.dt} -> $indexRegType")
|
||||
}
|
||||
return newReg to if(indexRegType==IRDataType.WORD) DataType.UWORD else DataType.UBYTE
|
||||
}
|
||||
|
||||
internal fun translate(assignment: PtAssignment): IRCodeChunks {
|
||||
|
||||
@@ -890,32 +890,36 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
val varName = target.variable!!.name + if(msb) "_msb" else "_lsb"
|
||||
if(isConstZeroValue) {
|
||||
if(constIndex!=null) {
|
||||
val offsetReg = codeGen.registers.next(IRDataType.BYTE)
|
||||
val idxType = codeGen.options.compTarget.indexRegType
|
||||
val offsetReg = codeGen.registers.next(idxType)
|
||||
result += IRCodeChunk(null, null).also {
|
||||
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=offsetReg, immediate = constIndex)
|
||||
it += IRInstruction(Opcode.LOAD, idxType, reg1=offsetReg, immediate = constIndex)
|
||||
it += IRInstruction(Opcode.STOREZX, IRDataType.BYTE, reg1=offsetReg, labelSymbol = varName)
|
||||
}
|
||||
} else {
|
||||
val indexTr = exprGen.translateExpression(target.index)
|
||||
addToResult(result, indexTr, indexTr.resultReg, -1)
|
||||
val indexReg = codeGen.canonicalizeIndexReg(result, indexTr)
|
||||
result += IRCodeChunk(null, null).also {
|
||||
it += IRInstruction(Opcode.STOREZX, IRDataType.BYTE, reg1=indexTr.resultReg, labelSymbol = varName)
|
||||
it += IRInstruction(Opcode.STOREZX, IRDataType.BYTE, reg1=indexReg, labelSymbol = varName)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val valueTr = exprGen.translateExpression(call.args[1])
|
||||
addToResult(result, valueTr, valueTr.resultReg, -1)
|
||||
if(constIndex!=null) {
|
||||
val offsetReg = codeGen.registers.next(IRDataType.BYTE)
|
||||
val idxType = codeGen.options.compTarget.indexRegType
|
||||
val offsetReg = codeGen.registers.next(idxType)
|
||||
result += IRCodeChunk(null, null).also {
|
||||
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=offsetReg, immediate = constIndex)
|
||||
it += IRInstruction(Opcode.LOAD, idxType, reg1=offsetReg, immediate = constIndex)
|
||||
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1=valueTr.resultReg, reg2=offsetReg, labelSymbol = varName)
|
||||
}
|
||||
} else {
|
||||
val indexTr = exprGen.translateExpression(target.index)
|
||||
addToResult(result, indexTr, indexTr.resultReg, -1)
|
||||
val indexReg = codeGen.canonicalizeIndexReg(result, indexTr)
|
||||
result += IRCodeChunk(null, null).also {
|
||||
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1=valueTr.resultReg, reg2=indexTr.resultReg, labelSymbol = varName)
|
||||
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1=valueTr.resultReg, reg2=indexReg, labelSymbol = varName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -621,10 +621,11 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
} else {
|
||||
val tr = translateExpression(arrayIx.index)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
val indexReg = codeGen.canonicalizeIndexReg(result, tr)
|
||||
result += IRCodeChunk(null, null).also {
|
||||
val tmpRegMsb = codeGen.registers.next(IRDataType.BYTE)
|
||||
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpRegMsb, reg2 = tr.resultReg, labelSymbol= "${arrayVarSymbol}_msb")
|
||||
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=resultRegister, reg2 = tr.resultReg, labelSymbol= "${arrayVarSymbol}_lsb")
|
||||
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpRegMsb, reg2 = indexReg, labelSymbol= "${arrayVarSymbol}_msb")
|
||||
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=resultRegister, reg2 = indexReg, labelSymbol= "${arrayVarSymbol}_lsb")
|
||||
it += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=finalResultReg, reg2=tmpRegMsb, reg3=resultRegister)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ class IRCodeGen(
|
||||
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
|
||||
internal val wordArrayIndex: Boolean = options.compTarget.indexRegType == IRDataType.WORD
|
||||
|
||||
/**
|
||||
* The IR data type to use for a memory address on the current target.
|
||||
@@ -2259,7 +2259,7 @@ class IRCodeGen(
|
||||
addToResult(result, byteIndexTr, byteIndexTr.resultReg, -1)
|
||||
|
||||
// LOADX/STOREX use word-sized indices on targets with 32-bit pointers.
|
||||
val indexRegType = if(options.compTarget.POINTER_MEM_SIZE > 2u) IRDataType.WORD else IRDataType.BYTE
|
||||
val indexRegType = options.compTarget.indexRegType
|
||||
var indexReg = byteIndexTr.resultReg
|
||||
var indexDt = byteIndexTr.dt
|
||||
if(indexDt != indexRegType) {
|
||||
@@ -2285,6 +2285,37 @@ class IRCodeGen(
|
||||
return Pair(result, indexReg)
|
||||
}
|
||||
|
||||
internal fun canonicalizeIndexReg(result: MutableList<IRCodeChunkBase>, indexTr: ExpressionCodeResult): Int {
|
||||
val indexRegType = options.compTarget.indexRegType
|
||||
if(indexTr.dt == indexRegType)
|
||||
return indexTr.resultReg
|
||||
val effectiveDt = if(indexTr.dt==IRDataType.POINTER) options.compTarget.pointerIRType else indexTr.dt
|
||||
if(effectiveDt == indexRegType)
|
||||
return indexTr.resultReg
|
||||
val newReg = registers.next(indexRegType)
|
||||
when {
|
||||
indexRegType==IRDataType.WORD && indexTr.dt==IRDataType.BYTE ->
|
||||
addInstr(result, IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1=newReg, reg2=indexTr.resultReg), null)
|
||||
indexRegType==IRDataType.WORD && indexTr.dt==IRDataType.LONG ->
|
||||
addInstr(result, IRInstruction(Opcode.LSIGW, IRDataType.LONG, reg1=newReg, reg2=indexTr.resultReg), null)
|
||||
indexRegType==IRDataType.WORD && indexTr.dt==IRDataType.POINTER ->
|
||||
addInstr(result, IRInstruction(Opcode.LSIGW, IRDataType.LONG, reg1=newReg, reg2=indexTr.resultReg), null)
|
||||
indexRegType==IRDataType.BYTE && indexTr.dt==IRDataType.WORD ->
|
||||
addInstr(result, IRInstruction(Opcode.LSIGB, IRDataType.WORD, reg1=newReg, reg2=indexTr.resultReg), null)
|
||||
indexRegType==IRDataType.BYTE && indexTr.dt==IRDataType.LONG ->
|
||||
addInstr(result, IRInstruction(Opcode.LSIGB, IRDataType.LONG, reg1=newReg, reg2=indexTr.resultReg), null)
|
||||
indexRegType==IRDataType.BYTE && indexTr.dt==IRDataType.POINTER -> {
|
||||
val ptrType = options.compTarget.pointerIRType
|
||||
if(ptrType==IRDataType.WORD)
|
||||
addInstr(result, IRInstruction(Opcode.LSIGB, IRDataType.WORD, reg1=newReg, reg2=indexTr.resultReg), null)
|
||||
else
|
||||
addInstr(result, IRInstruction(Opcode.LSIGB, IRDataType.LONG, reg1=newReg, reg2=indexTr.resultReg), null)
|
||||
}
|
||||
else -> throw IllegalArgumentException("unexpected index conversion ${indexTr.dt} -> $indexRegType")
|
||||
}
|
||||
return newReg
|
||||
}
|
||||
|
||||
internal fun irType(type: DataType): IRDataType {
|
||||
if(type.base.isPassByRef)
|
||||
return IRDataType.POINTER
|
||||
|
||||
@@ -1005,7 +1005,7 @@ jump p8_label_gen_2
|
||||
// lsigb.? rX,rA + ext.b rY,rX -> loadr.? rY,rA ; and.? rY,#$ff
|
||||
// Only applied when the intermediate register is not read anywhere else in this chunk.
|
||||
if(chunk.instructions.size<2) return false
|
||||
val readCounts = chunk.usedRegisters().readRegs.withDefault { 0 }
|
||||
val readCounts = chunk.usedRegisters(irprog.options.compTarget.indexRegType).readRegs.withDefault { 0 }
|
||||
|
||||
class Mod(val idx: Int, val replacement: IRInstruction?) // null replacement = delete
|
||||
val mods = mutableListOf<Mod>()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package prog8.codegen.intermediate
|
||||
|
||||
import prog8.code.core.IErrorReporter
|
||||
import prog8.intermediate.indexRegType
|
||||
import prog8.intermediate.*
|
||||
|
||||
|
||||
@@ -80,7 +81,7 @@ class IRUnusedCodeRemover(
|
||||
}
|
||||
|
||||
// remove stray loads
|
||||
val indexRegType = if(irprog.options.compTarget.POINTER_MEM_SIZE > 2u) IRDataType.WORD else IRDataType.BYTE
|
||||
val indexRegType = irprog.options.compTarget.indexRegType
|
||||
val readRegs = mutableSetOf<Int>()
|
||||
val readFpRegs = mutableSetOf<Int>()
|
||||
instructions.forEach { ins ->
|
||||
@@ -89,8 +90,7 @@ class IRUnusedCodeRemover(
|
||||
val writeRegsCounts = mutableMapOf<RegisterNum, Int>()
|
||||
val writeFpRegsCounts = mutableMapOf<RegisterNum, Int>()
|
||||
val regsTypes = mutableMapOf<RegisterNum, IRDataType>()
|
||||
val indexGuessRegs = mutableSetOf<RegisterNum>()
|
||||
ins.addUsedRegistersCounts(readRegsCounts, writeRegsCounts, readFpRegsCounts, writeFpRegsCounts, regsTypes, indexGuessRegs, null, indexRegType)
|
||||
ins.addUsedRegistersCounts(readRegsCounts, writeRegsCounts, readFpRegsCounts, writeFpRegsCounts, regsTypes, null, indexRegType)
|
||||
readRegs.addAll(readRegsCounts.keys.map { it.value })
|
||||
readFpRegs.addAll(readFpRegsCounts.keys.map { it.value })
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package prog8.codegen.intermediate
|
||||
|
||||
import prog8.intermediate.indexRegType
|
||||
import prog8.intermediate.*
|
||||
|
||||
/*
|
||||
@@ -71,7 +72,7 @@ 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 indexRegType = irProg.options.compTarget.indexRegType
|
||||
val allRegTypes = mutableMapOf<Int, IRDataType>()
|
||||
irProg.foreachCodeChunk { chunk ->
|
||||
for (instr in chunk.instructions) {
|
||||
@@ -101,7 +102,7 @@ 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 indexRegType = irProg.options.compTarget.indexRegType
|
||||
val newTypes = mutableMapOf<RegisterNum, IRDataType>()
|
||||
irProg.foreachCodeChunk { chunk ->
|
||||
for (instr in chunk.instructions) {
|
||||
|
||||
Reference in new issue
Block a user