removing redundant compares

This commit is contained in:
Irmen de Jong 2023-11-16 21:33:43 +01:00
parent 09d506194f
commit ff8de8e42d
5 changed files with 32 additions and 63 deletions

View File

@ -17,6 +17,8 @@ internal class ExpressionCodeResult(val chunks: IRCodeChunks, val dt: IRDataType
if(resultReg!=-1) require(resultFpReg==-1) if(resultReg!=-1) require(resultFpReg==-1)
if(resultFpReg!=-1) require(resultReg==-1) if(resultFpReg!=-1) require(resultReg==-1)
} }
fun lastInstruction() = chunks.last().instructions.last()
} }
internal class ExpressionGen(private val codeGen: IRCodeGen) { internal class ExpressionGen(private val codeGen: IRCodeGen) {

View File

@ -470,7 +470,6 @@ class IRCodeGen(
addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = indexReg, immediate = 0), null) addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = indexReg, immediate = 0), null)
result += IRCodeChunk(loopLabel, null).also { result += IRCodeChunk(loopLabel, null).also {
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1 = tmpReg, reg2 = indexReg, labelSymbol = iterable.name) it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1 = tmpReg, reg2 = indexReg, labelSymbol = iterable.name)
it += IRInstruction(Opcode.CMPI, IRDataType.BYTE, reg1 = tmpReg, immediate = 0)
it += IRInstruction(Opcode.BSTEQ, labelSymbol = endLabel) it += IRInstruction(Opcode.BSTEQ, labelSymbol = endLabel)
it += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1 = tmpReg, labelSymbol = loopvarSymbol) it += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1 = tmpReg, labelSymbol = loopvarSymbol)
} }
@ -499,7 +498,10 @@ class IRCodeGen(
result += translateNode(forLoop.statements) result += translateNode(forLoop.statements)
result += IRCodeChunk(null, null).also { result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=indexReg) it += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=indexReg)
it += IRInstruction(Opcode.CMPI, IRDataType.BYTE, reg1=indexReg, immediate = if(iterableLength==256) 0 else iterableLength) if(iterableLength!=256) {
// for length 256, the compare is actually against 0, which doesn't require a separate CMP instruction
it += IRInstruction(Opcode.CMPI, IRDataType.BYTE, reg1=indexReg, immediate = iterableLength)
}
it += IRInstruction(Opcode.BSTNE, labelSymbol = loopLabel) it += IRInstruction(Opcode.BSTNE, labelSymbol = loopLabel)
} }
} }
@ -516,7 +518,10 @@ class IRCodeGen(
result += translateNode(forLoop.statements) result += translateNode(forLoop.statements)
result += addConstReg(IRDataType.BYTE, indexReg, elementSize) result += addConstReg(IRDataType.BYTE, indexReg, elementSize)
result += IRCodeChunk(null, null).also { result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.CMPI, IRDataType.BYTE, reg1=indexReg, immediate = if(lengthBytes==256) 0 else lengthBytes) if(lengthBytes!=256) {
// for length 256, the compare is actually against 0, which doesn't require a separate CMP instruction
it += IRInstruction(Opcode.CMPI, IRDataType.BYTE, reg1=indexReg, immediate = lengthBytes)
}
it += IRInstruction(Opcode.BSTNE, labelSymbol = loopLabel) it += IRInstruction(Opcode.BSTNE, labelSymbol = loopLabel)
} }
} }
@ -976,7 +981,6 @@ class IRCodeGen(
fpReg2 = rightTr.resultFpReg fpReg2 = rightTr.resultFpReg
) )
when(condition.operator) { when(condition.operator) {
// TODO: the converted list of operators
"==" -> { "==" -> {
it += IRInstruction(Opcode.CMPI, IRDataType.BYTE, reg1 = compResultReg, immediate = 0) it += IRInstruction(Opcode.CMPI, IRDataType.BYTE, reg1 = compResultReg, immediate = 0)
it += branchInstr(goto, Opcode.BSTEQ) it += branchInstr(goto, Opcode.BSTEQ)
@ -986,7 +990,6 @@ class IRCodeGen(
it += branchInstr(goto, Opcode.BSTNE) it += branchInstr(goto, Opcode.BSTNE)
} }
else -> { else -> {
// TODO: the old list of operators, still to be converted
val gotoOpcode = when (condition.operator) { val gotoOpcode = when (condition.operator) {
"<" -> Opcode.BLTS "<" -> Opcode.BLTS
">" -> Opcode.BGTS ">" -> Opcode.BGTS
@ -1016,7 +1019,7 @@ class IRCodeGen(
} }
} }
// TODO use this everywhere // TODO use this everywhere a PtJump is used
private fun branchInstr(goto: PtJump, branchOpcode: Opcode) = if (goto.address != null) private fun branchInstr(goto: PtJump, branchOpcode: Opcode) = if (goto.address != null)
IRInstruction(branchOpcode, address = goto.address?.toInt()) IRInstruction(branchOpcode, address = goto.address?.toInt())
else if (goto.generatedLabel != null) else if (goto.generatedLabel != null)
@ -1034,18 +1037,19 @@ class IRCodeGen(
val condition = ifElse.condition as PtBinaryExpression val condition = ifElse.condition as PtBinaryExpression
val leftTr = expressionEval.translateExpression(condition.left) val leftTr = expressionEval.translateExpression(condition.left)
addToResult(result, leftTr, leftTr.resultReg, -1) addToResult(result, leftTr, leftTr.resultReg, -1)
val requireCompareZero = leftTr.lastInstruction().opcode !in OpcodesThatSetStatusbits
when(condition.operator) { when(condition.operator) {
// TODO: converted list of operators
"==" -> { "==" -> {
if(requireCompareZero)
addInstr(result, IRInstruction(Opcode.CMPI, irDtLeft, reg1 = leftTr.resultReg, immediate = 0), null) addInstr(result, IRInstruction(Opcode.CMPI, irDtLeft, reg1 = leftTr.resultReg, immediate = 0), null)
addInstr(result, branchInstr(goto, Opcode.BSTEQ), null) addInstr(result, branchInstr(goto, Opcode.BSTEQ), null)
} }
"!=" -> { "!=" -> {
if(requireCompareZero)
addInstr(result, IRInstruction(Opcode.CMPI, irDtLeft, reg1 = leftTr.resultReg, immediate = 0), null) addInstr(result, IRInstruction(Opcode.CMPI, irDtLeft, reg1 = leftTr.resultReg, immediate = 0), null)
addInstr(result, branchInstr(goto, Opcode.BSTNE), null) addInstr(result, branchInstr(goto, Opcode.BSTNE), null)
} }
else -> { else -> {
// TODO: to-be converted operators
val opcode = when (condition.operator) { val opcode = when (condition.operator) {
"<" -> if (signed) Opcode.BLTS else Opcode.BLT "<" -> if (signed) Opcode.BLTS else Opcode.BLT
">" -> if (signed) Opcode.BGTS else Opcode.BGT ">" -> if (signed) Opcode.BGTS else Opcode.BGT
@ -1072,12 +1076,13 @@ class IRCodeGen(
) { ) {
val condition = ifElse.condition as? PtBinaryExpression val condition = ifElse.condition as? PtBinaryExpression
if(condition==null) { if(condition==null) {
val tr = expressionEval.translateExpression(ifElse.condition) throw AssemblyError("expected condition")
result += tr.chunks // val tr = expressionEval.translateExpression(ifElse.condition)
result += IRCodeChunk(null, null).also { // result += tr.chunks
it += IRInstruction(Opcode.CMPI, irDtLeft, reg1 = tr.resultReg, immediate = 0) // result += IRCodeChunk(null, null).also {
it += branchInstr(goto, Opcode.BSTNE) // it += IRInstruction(Opcode.CMPI, irDtLeft, reg1 = tr.resultReg, immediate = 0) // was redundant CMP most likely
} // it += branchInstr(goto, Opcode.BSTNE)
// }
} else { } else {
val leftTr = expressionEval.translateExpression(condition.left) val leftTr = expressionEval.translateExpression(condition.left)
addToResult(result, leftTr, leftTr.resultReg, -1) addToResult(result, leftTr, leftTr.resultReg, -1)
@ -1085,7 +1090,6 @@ class IRCodeGen(
if(number!=null) { if(number!=null) {
val firstReg = leftTr.resultReg val firstReg = leftTr.resultReg
when(condition.operator) { when(condition.operator) {
// TODO: the converted operators
"==" -> { "==" -> {
addInstr(result, IRInstruction(Opcode.CMPI, irDtLeft, reg1 = firstReg, immediate = number), null) addInstr(result, IRInstruction(Opcode.CMPI, irDtLeft, reg1 = firstReg, immediate = number), null)
addInstr(result, branchInstr(goto, Opcode.BSTEQ), null) addInstr(result, branchInstr(goto, Opcode.BSTEQ), null)
@ -1095,7 +1099,6 @@ class IRCodeGen(
addInstr(result, branchInstr(goto, Opcode.BSTNE), null) addInstr(result, branchInstr(goto, Opcode.BSTNE), null)
} }
else -> { else -> {
// TODO: to-be converted operators
val opcode = when (condition.operator) { val opcode = when (condition.operator) {
"<" -> if(signed) Opcode.BLTS else Opcode.BLT "<" -> if(signed) Opcode.BLTS else Opcode.BLT
">" -> if(signed) Opcode.BGTS else Opcode.BGT ">" -> if(signed) Opcode.BGTS else Opcode.BGT
@ -1267,33 +1270,6 @@ class IRCodeGen(
val condition = ifElse.condition as? PtBinaryExpression val condition = ifElse.condition as? PtBinaryExpression
if(condition==null) { if(condition==null) {
throw AssemblyError("if-else condition is not a binaryexpression, should have been converted?") throw AssemblyError("if-else condition is not a binaryexpression, should have been converted?")
// if(irDtLeft==IRDataType.FLOAT)
// throw AssemblyError("condition value should not be float")
// val tr = expressionEval.translateExpression(ifElse.condition)
// result += tr.chunks
// if(ifElse.elseScope.children.isNotEmpty()) {
// val elseLabel = createLabelName()
// result += IRCodeChunk(null, null).also {
// it += IRInstruction(Opcode.CMPI, irDtLeft, reg1=tr.resultReg, immediate = 0)
// it += IRInstruction(Opcode.BSTEQ, labelSymbol = elseLabel)
// TODO("test this")
// }
// result += translateNode(ifElse.ifScope)
// val afterIfLabel = createLabelName()
// addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = afterIfLabel), null)
// result += labelFirstChunk(translateNode(ifElse.elseScope), elseLabel)
// result += IRCodeChunk(afterIfLabel, null)
// } else {
// val afterIfLabel = createLabelName()
// result += IRCodeChunk(null, null).also {
// it += IRInstruction(Opcode.CMPI, irDtLeft, reg1=tr.resultReg, immediate = 0)
// it += IRInstruction(Opcode.BSTEQ, labelSymbol = afterIfLabel)
// TODO("test this")
// }
// result += translateNode(ifElse.ifScope)
// result += IRCodeChunk(afterIfLabel, null)
// }
// return result
} else { } else {
if (irDtLeft == IRDataType.FLOAT) { if (irDtLeft == IRDataType.FLOAT) {
val leftTr = expressionEval.translateExpression(condition.left) val leftTr = expressionEval.translateExpression(condition.left)
@ -1641,10 +1617,7 @@ class IRCodeGen(
addToResult(result, countTr, countTr.resultReg, -1) addToResult(result, countTr, countTr.resultReg, -1)
if(constIntValue(repeat.count)==null) { if(constIntValue(repeat.count)==null) {
// check if the counter is already zero // check if the counter is already zero
result += IRCodeChunk(null, null).also { addInstr(result, IRInstruction(Opcode.BSTEQ, labelSymbol = skipRepeatLabel), null)
it += IRInstruction(Opcode.CMPI, irDt, reg1=countTr.resultReg, immediate = 0)
it += IRInstruction(Opcode.BSTEQ, labelSymbol = skipRepeatLabel)
}
} }
result += labelFirstChunk(translateNode(repeat.statements), repeatLabel) result += labelFirstChunk(translateNode(repeat.statements), repeatLabel)
result += IRCodeChunk(null, null).also { result += IRCodeChunk(null, null).also {

View File

@ -2,7 +2,7 @@
TODO TODO
==== ====
- IR: reduce amount of CMP/CMPI after instructions that set the status bits correctly (LOADs? INC? Bitwise operations, etc), but only after setting the status bits is verified! - IR: use branchInstr() everywhere a PtGoto is used in IRCodeGen
- [on branch: shortcircuit] investigate McCarthy evaluation again? this may also reduce code size perhaps for things like if a>4 or a<2 .... - [on branch: shortcircuit] investigate McCarthy evaluation again? this may also reduce code size perhaps for things like if a>4 or a<2 ....
... ...

View File

@ -1,19 +1,12 @@
%zeropage basicsafe %zeropage basicsafe
%import textio %import textio
txt { main {
%option merge sub start() {
sub println(uword string) { ubyte xx=12
txt.print(string)
if xx==12
txt.print("gottem")
txt.nl() txt.nl()
} }
} }
main {
sub start() {
txt.lowercase()
txt.println("Hello, world1")
txt.println("Hello, world2")
txt.println("Hello, world3")
}
}

View File

@ -437,6 +437,7 @@ val OpcodesThatSetStatusbitsButNotCarry = setOf(
Opcode.DEC, Opcode.DEC,
Opcode.DECM Opcode.DECM
) )
val OpcodesThatSetStatusbits = OpcodesThatSetStatusbitsButNotCarry + OpcodesThatSetStatusbitsIncludingCarry
enum class IRDataType { enum class IRDataType {