IR: added CMPI instruction

This commit is contained in:
Irmen de Jong 2023-07-14 23:17:29 +02:00
parent b8284a147d
commit 6938c79f88
4 changed files with 76 additions and 0 deletions

View File

@ -47,6 +47,7 @@ class IRPeepholeOptimizer(private val irprog: IRProgram) {
val changed = removeNops(chunk1, indexedInstructions)
|| removeDoubleLoadsAndStores(chunk1, indexedInstructions) // TODO not yet implemented
|| removeUselessArithmetic(chunk1, indexedInstructions)
|| removeNeedlessCompares(chunk1, indexedInstructions)
|| removeWeirdBranches(chunk1, chunk2, indexedInstructions)
|| removeDoubleSecClc(chunk1, indexedInstructions)
|| cleanupPushPop(chunk1, indexedInstructions)
@ -266,6 +267,28 @@ class IRPeepholeOptimizer(private val irprog: IRProgram) {
return changed
}
private fun removeNeedlessCompares(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<IRInstruction>>): Boolean {
// a CMPI with 0, after an instruction like LOAD that already sets the status bits, can be removed.
// but only if the instruction after it is not using the Carry bit because that won't be set by a LOAD instruction etc.
var changed = false
indexedInstructions.reversed().forEach { (idx, ins) ->
if(idx>0 && idx<(indexedInstructions.size-1) && ins.opcode==Opcode.CMPI && ins.immediate==0) {
val previous = indexedInstructions[idx-1].value
if(previous.opcode in OpcodesThatSetStatusbitsIncludingCarry) {
chunk.instructions.removeAt(idx)
changed = true
} else if(previous.opcode in OpcodesThatSetStatusbitsButNotCarry) {
val next = indexedInstructions[idx+1].value
if(next.opcode !in arrayOf(Opcode.BSTCC, Opcode.BSTCS, Opcode.BSTPOS, Opcode.BSTNEG)) {
chunk.instructions.removeAt(idx)
changed = true
}
}
}
}
return changed
}
private fun removeUselessArithmetic(chunk: IRCodeChunk, indexedInstructions: List<IndexedValue<IRInstruction>>): Boolean {
// note: this is hard to solve for the non-immediate instructions atm because the values are loaded into registers first
var changed = false

View File

@ -1,7 +1,9 @@
TODO
====
- IR: optimize WHEN codegen? translate(whenStmt: PtWhen)
- IR: instructions that do type conversion (SZ etc, CONCAT, SGN) should put the result in a DIFFERENT register.
- IR: reduce the number of branch instructions (gradually), replace with CMP(I) + status branch instruction
...

View File

@ -146,6 +146,7 @@ divmod reg1, value - unsigned division reg1/value, stor
sqrt reg1, reg2 - reg1 is the square root of reg2 (reg2 can be .w or .b, result type in reg1 is always .b) you can also use it with floating point types, fpreg1 and fpreg2 (result is also .f)
sgn reg1, reg2 - reg1 is the sign of reg2 (0.b, 1.b or -1.b)
cmp reg1, reg2 - set processor status bits C, N, Z according to comparison of reg1 with reg2. (semantics taken from 6502/68000 CMP instruction)
cmpi reg1, value - set processor status bits C, N, Z according to comparison of reg1 with immediate value. (semantics taken from 6502/68000 CMP instruction)
NOTE: because mul/div are constrained (truncated) to remain in 8 or 16 bits, there is NO NEED for separate signed/unsigned mul and div instructions. The result is identical.
@ -312,6 +313,7 @@ enum class Opcode {
SQRT,
SGN,
CMP,
CMPI,
EXT,
EXTS,
@ -417,6 +419,24 @@ val OpcodesThatBranch = setOf(
Opcode.BLES
)
val OpcodesThatSetStatusbitsIncludingCarry = setOf(
Opcode.CMP,
Opcode.CMPI
)
val OpcodesThatSetStatusbitsButNotCarry = setOf(
Opcode.LOAD,
Opcode.LOADM,
Opcode.LOADI,
Opcode.LOADX,
Opcode.LOADIX,
Opcode.LOADR,
Opcode.INC,
Opcode.INCM,
Opcode.DEC,
Opcode.DECM
)
enum class IRDataType {
BYTE,
WORD,
@ -584,6 +604,7 @@ val instructionFormats = mutableMapOf(
Opcode.DIVMODR to InstructionFormat.from("BW,<>r1,<r2"),
Opcode.DIVMOD to InstructionFormat.from("BW,<>r1,<i"),
Opcode.CMP to InstructionFormat.from("BW,<r1,<r2"),
Opcode.CMPI to InstructionFormat.from("BW,<r1,<i"),
Opcode.EXT to InstructionFormat.from("BW,>r1,<r2"),
Opcode.EXTS to InstructionFormat.from("BW,>r1,<r2"),
Opcode.ANDR to InstructionFormat.from("BW,<>r1,<r2"),

View File

@ -245,6 +245,7 @@ class VirtualMachine(irProgram: IRProgram) {
Opcode.DIVMOD -> InsDIVMOD(ins)
Opcode.SGN -> InsSGN(ins)
Opcode.CMP -> InsCMP(ins)
Opcode.CMPI -> InsCMPI(ins)
Opcode.SQRT -> InsSQRT(ins)
Opcode.EXT -> InsEXT(ins)
Opcode.EXTS -> InsEXTS(ins)
@ -1267,6 +1268,35 @@ class VirtualMachine(irProgram: IRProgram) {
nextPc()
}
private fun InsCMPI(i: IRInstruction) {
val comparison: Int
when(i.type!!) {
IRDataType.BYTE -> {
val reg1 = registers.getUB(i.reg1!!)
comparison = reg1.toInt() - (i.immediate!! and 255)
statusNegative = (comparison and 0x80)==0x80
}
IRDataType.WORD -> {
val reg1 = registers.getUW(i.reg1!!)
comparison = reg1.toInt() - (i.immediate!! and 65535)
statusNegative = (comparison and 0x8000)==0x8000
}
IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
}
if(comparison==0){
statusZero = true
statusCarry = true
} else if(comparison>0) {
statusZero = false
statusCarry = true
} else {
statusZero = false
statusCarry = false
}
nextPc()
}
private fun plusMinusMultAnyByte(operator: String, reg1: Int, reg2: Int) {
val left = registers.getUB(reg1)
val right = registers.getUB(reg2)