IR: improve use of loadfield for msb/lsb of struct fields

This commit is contained in:
Irmen de Jong
2026-01-02 21:58:01 +01:00
parent 3f6177cbb8
commit 51503e054a
4 changed files with 37 additions and 6 deletions
@@ -140,7 +140,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
it += IRInstruction(Opcode.ADD, IRDataType.WORD, reg1 = pointerReg, immediate = firstField.second.toInt())
if (firstField.first.isPointer) {
// get the address stored in the pointer and use that for the rest of the chain
// LOADI has an exception to allo reg1 and reg2 to be the same, so we can avoid using extra temporary registers and LOADS
// LOADI has an exception to allo reg1 and reg2 to be the same, so we can avoid using extra temporary registers and LOADs
it += IRInstruction(Opcode.LOADI, IRDataType.WORD, reg1 = pointerReg, reg2 = pointerReg)
} else {
require(chain.isEmpty())
@@ -1841,7 +1841,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
// get new pointer from field
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.ADD, IRDataType.WORD, reg1 = pointerReg, immediate = fieldinfo.second.toInt())
// LOADI has an exception to allow reg1 and reg2 to be the same, so we can avoid using extra temporary registers and LOADS
// LOADI has an exception to allow reg1 and reg2 to be the same, so we can avoid using extra temporary registers and LOADs
it += IRInstruction(Opcode.LOADI, IRDataType.WORD, reg1 = pointerReg, reg2 = pointerReg)
}
}
@@ -1854,7 +1854,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
require(fieldinfo.first.isPointer)
// add the field offset
addInstr(result, IRInstruction(Opcode.ADD, IRDataType.WORD, reg1 = pointerReg, immediate = fieldinfo.second.toInt()), null)
// LOADI has an exception to allow reg1 and reg2 to be the same, so we can avoid using extra temporary registers and LOADS
// LOADI has an exception to allow reg1 and reg2 to be the same, so we can avoid using extra temporary registers and LOADs
addInstr(result, IRInstruction(Opcode.LOADI, IRDataType.WORD, reg1 = pointerReg, reg2 = pointerReg), null)
return result to 0u
} else {
@@ -1863,7 +1863,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
}
if(targetPointerDeref.derefLast) {
require(fieldinfo.first.isPointer)
// LOADI has an exception to allow reg1 and reg2 to be the same, so we can avoid using extra temporary registers and LOADS
// LOADI has an exception to allow reg1 and reg2 to be the same, so we can avoid using extra temporary registers and LOADs
addInstr(result, IRInstruction(Opcode.LOADI, IRDataType.WORD, reg1 = pointerReg, reg2 = pointerReg), null)
}
return result to 0u
@@ -56,6 +56,7 @@ class IRPeepholeOptimizer(private val irprog: IRProgram, private val retainSSA:
|| simplifyConstantReturns(chunk1, indexedInstructions)
|| removeNeedlessLoads(chunk1, indexedInstructions)
|| useArrayIndexingInsteadOfAdds(chunk1, indexedInstructions)
|| loadfields(chunk1, indexedInstructions)
|| removeNops(chunk1, indexedInstructions) // last time, in case one of the optimizers replaced something with a nop
} while (changed)
}
@@ -631,4 +632,34 @@ jump p8_label_gen_2
return changed
}
private fun loadfields(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<IRInstruction>>): Boolean {
var changed = false
indexedInstructions.reversed().forEach { (idx, ins) ->
if (ins.opcode == Opcode.LOADFIELD && ins.immediate==0) {
val loadi = IRInstruction(Opcode.LOADI, ins.type, ins.reg1!!, ins.reg2!!)
chunk.instructions[idx] = loadi
changed = true
}
// add.w R2,#offset loadi.b R1,R2 -> loadfield.b R1,R2,#offset
if(ins.opcode==Opcode.LOADI && ins.reg1!=ins.reg2 && idx>1) {
val previous = indexedInstructions[idx-1].value
if(previous.opcode==Opcode.ADD && previous.type == IRDataType.WORD && previous.reg1==ins.reg2) {
val loadfield = IRInstruction(Opcode.LOADFIELD, ins.type, ins.reg1!!, ins.reg2!!, immediate = previous.immediate!!)
chunk.instructions[idx-1] = loadfield
chunk.instructions.removeAt(idx)
changed = true
}
else if(previous.opcode==Opcode.INC && previous.type == IRDataType.WORD && previous.reg1==ins.reg2) {
val loadfield = IRInstruction(Opcode.LOADFIELD, ins.type, ins.reg1!!, ins.reg2!!, immediate = 1)
chunk.instructions[idx-1] = loadfield
chunk.instructions.removeAt(idx)
changed = true
}
}
}
return changed
}
}