mirror of
https://github.com/irmen/prog8.git
synced 2025-03-13 05:31:01 +00:00
IR: added CMPI instruction
This commit is contained in:
parent
b8284a147d
commit
6938c79f88
@ -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
|
||||
|
@ -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
|
||||
|
||||
...
|
||||
|
||||
|
@ -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"),
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user