mirror of
https://github.com/irmen/prog8.git
synced 2025-01-10 20:30:23 +00:00
remove redundant IR instructions like SNZ
This commit is contained in:
parent
fe9a9fc5cb
commit
f5e332daf7
@ -57,7 +57,7 @@ internal class IfElseAsmGen(private val program: PtProgram,
|
||||
is PtBinaryExpression -> { /* no cmp necessary the lda has been done just prior */ }
|
||||
is PtTypeCast -> {
|
||||
if(condition.value.type !in ByteDatatypes)
|
||||
asmgen.out(" cmp #0")
|
||||
asmgen.out(" cmp #0") // maybe can be eliminated altogether? depends on how the actual type cast is done...
|
||||
}
|
||||
else -> asmgen.out(" cmp #0")
|
||||
}
|
||||
|
@ -310,18 +310,24 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
var actualResultFpReg2 = -1
|
||||
when(cast.type) {
|
||||
DataType.BOOL -> {
|
||||
if (cast.value.type in IntegerDatatypes) {
|
||||
when (cast.value.type) {
|
||||
in ByteDatatypes -> {
|
||||
actualResultReg2 = codeGen.registers.nextFree()
|
||||
addInstr(result, IRInstruction(Opcode.SNZ, IRDataType.BYTE, reg1=actualResultReg2, reg2=tr.resultReg), null)
|
||||
}
|
||||
else if(cast.value.type==DataType.FLOAT) {
|
||||
in WordDatatypes -> {
|
||||
actualResultReg2 = codeGen.registers.nextFree()
|
||||
addInstr(result, IRInstruction(Opcode.SNZ, IRDataType.WORD, reg1=actualResultReg2, reg2=tr.resultReg), null)
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
actualResultReg2 = codeGen.registers.nextFree()
|
||||
result += IRCodeChunk(null, null).also {
|
||||
it += IRInstruction(Opcode.SGN, IRDataType.FLOAT, reg1=actualResultReg2, fpReg1 = tr.resultFpReg)
|
||||
it += IRInstruction(Opcode.AND, IRDataType.BYTE, reg1=actualResultReg2, immediate = 1)
|
||||
}
|
||||
}
|
||||
else throw AssemblyError("weird cast value type")
|
||||
else -> throw AssemblyError("weird cast value type")
|
||||
}
|
||||
}
|
||||
DataType.UBYTE -> {
|
||||
when(cast.value.type) {
|
||||
|
@ -337,10 +337,33 @@ class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// a SNZ etc. whose target register is not used can be removed altogether
|
||||
if(ins.opcode in OpcodesThatSetRegFromStatusbits) {
|
||||
val usages = regUsages(ins.reg1!!)
|
||||
if(usages.toList().sumOf { it.second } <= 1) {
|
||||
chunk.instructions.removeAt(idx)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return changed
|
||||
}
|
||||
|
||||
private fun regUsages(register: Int): Map<IRCodeChunkBase, Int> {
|
||||
val chunks = mutableMapOf<IRCodeChunkBase, Int>()
|
||||
irprog.foreachSub { sub ->
|
||||
sub.chunks.forEach { chunk ->
|
||||
val used = chunk.usedRegisters()
|
||||
val numUsages = used.readRegs.getOrDefault(register, 0) + used.writeRegs.getOrDefault(register, 0)
|
||||
if(numUsages>0) {
|
||||
chunks[chunk] = numUsages
|
||||
}
|
||||
}
|
||||
}
|
||||
return chunks
|
||||
}
|
||||
|
||||
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,9 +1,7 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
fix casting uword to bool (don't take only the lsb!)
|
||||
fix IR adding snz in bool casts inside if
|
||||
|
||||
fix 6502 casting uword to bool (don't take only the lsb!)
|
||||
|
||||
fix "wordGreaterValue"
|
||||
|
||||
|
@ -7,20 +7,29 @@
|
||||
main {
|
||||
sub start() {
|
||||
|
||||
test_stack.test()
|
||||
broken_word_gt()
|
||||
broken_word_lt()
|
||||
broken_uword_gt()
|
||||
broken_uword_lt()
|
||||
if cx16.r0L as bool
|
||||
cx16.r0L++
|
||||
|
||||
test_bool()
|
||||
test_float()
|
||||
test_byte()
|
||||
test_ubyte()
|
||||
test_word()
|
||||
test_uword()
|
||||
if cx16.r0 as bool
|
||||
cx16.r0L++
|
||||
|
||||
test_stack.test()
|
||||
if @(cx16.r0) as bool
|
||||
cx16.r0L++
|
||||
|
||||
; test_stack.test()
|
||||
; broken_word_gt()
|
||||
; broken_word_lt()
|
||||
; broken_uword_gt()
|
||||
; broken_uword_lt()
|
||||
;
|
||||
; test_bool()
|
||||
; test_float()
|
||||
; test_byte()
|
||||
; test_ubyte()
|
||||
; test_word()
|
||||
; test_uword()
|
||||
;
|
||||
; test_stack.test()
|
||||
|
||||
if sys.target!=255
|
||||
repeat { }
|
||||
|
@ -472,6 +472,23 @@ val OpcodesThatDependOnCarry = arrayOf(
|
||||
Opcode.ROXRM,
|
||||
)
|
||||
|
||||
val OpcodesThatSetRegFromStatusbits = arrayOf(
|
||||
Opcode.SCC,
|
||||
Opcode.SCS,
|
||||
Opcode.SZ,
|
||||
Opcode.SNZ,
|
||||
Opcode.SEQ,
|
||||
Opcode.SNE,
|
||||
Opcode.SLT,
|
||||
Opcode.SLTS,
|
||||
Opcode.SGT,
|
||||
Opcode.SGTS,
|
||||
Opcode.SLE,
|
||||
Opcode.SLES,
|
||||
Opcode.SGE,
|
||||
Opcode.SGES
|
||||
)
|
||||
|
||||
val OpcodesThatSetStatusbits = OpcodesThatSetStatusbitsButNotCarry + OpcodesThatSetStatusbitsIncludingCarry
|
||||
|
||||
|
||||
|
@ -536,6 +536,9 @@ class RegistersUsed(
|
||||
|
||||
fun isEmpty() = readRegs.isEmpty() && writeRegs.isEmpty() && readFpRegs.isEmpty() && writeFpRegs.isEmpty()
|
||||
fun isNotEmpty() = !isEmpty()
|
||||
|
||||
fun used(register: Int) = register in readRegs || register in writeRegs
|
||||
fun usedFp(fpRegister: Int) = fpRegister in readFpRegs || fpRegister in writeFpRegs
|
||||
}
|
||||
|
||||
private fun registersUsedInAssembly(isIR: Boolean, assembly: String): RegistersUsed {
|
||||
|
Loading…
x
Reference in New Issue
Block a user