From ff8de8e42d28d07b5e5f88985a275f159949e140 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Thu, 16 Nov 2023 21:33:43 +0100 Subject: [PATCH] removing redundant compares --- .../codegen/intermediate/ExpressionGen.kt | 2 + .../prog8/codegen/intermediate/IRCodeGen.kt | 71 ++++++------------- docs/source/todo.rst | 2 +- examples/test.p8 | 19 ++--- .../src/prog8/intermediate/IRInstructions.kt | 1 + 5 files changed, 32 insertions(+), 63 deletions(-) diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt index b21258db7..cfcd6b118 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt @@ -17,6 +17,8 @@ internal class ExpressionCodeResult(val chunks: IRCodeChunks, val dt: IRDataType if(resultReg!=-1) require(resultFpReg==-1) if(resultFpReg!=-1) require(resultReg==-1) } + + fun lastInstruction() = chunks.last().instructions.last() } internal class ExpressionGen(private val codeGen: IRCodeGen) { diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt index 849bf3da1..873de6fc5 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt @@ -470,7 +470,6 @@ class IRCodeGen( addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = indexReg, immediate = 0), null) result += IRCodeChunk(loopLabel, null).also { 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.STOREM, IRDataType.BYTE, reg1 = tmpReg, labelSymbol = loopvarSymbol) } @@ -499,7 +498,10 @@ class IRCodeGen( result += translateNode(forLoop.statements) result += IRCodeChunk(null, null).also { 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) } } @@ -516,7 +518,10 @@ class IRCodeGen( result += translateNode(forLoop.statements) result += addConstReg(IRDataType.BYTE, indexReg, elementSize) 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) } } @@ -976,7 +981,6 @@ class IRCodeGen( fpReg2 = rightTr.resultFpReg ) when(condition.operator) { - // TODO: the converted list of operators "==" -> { it += IRInstruction(Opcode.CMPI, IRDataType.BYTE, reg1 = compResultReg, immediate = 0) it += branchInstr(goto, Opcode.BSTEQ) @@ -986,7 +990,6 @@ class IRCodeGen( it += branchInstr(goto, Opcode.BSTNE) } else -> { - // TODO: the old list of operators, still to be converted val gotoOpcode = when (condition.operator) { "<" -> Opcode.BLTS ">" -> 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) IRInstruction(branchOpcode, address = goto.address?.toInt()) else if (goto.generatedLabel != null) @@ -1034,18 +1037,19 @@ class IRCodeGen( val condition = ifElse.condition as PtBinaryExpression val leftTr = expressionEval.translateExpression(condition.left) addToResult(result, leftTr, leftTr.resultReg, -1) + val requireCompareZero = leftTr.lastInstruction().opcode !in OpcodesThatSetStatusbits when(condition.operator) { - // TODO: converted list of operators "==" -> { - addInstr(result, IRInstruction(Opcode.CMPI, irDtLeft, reg1 = leftTr.resultReg, immediate = 0), null) + if(requireCompareZero) + addInstr(result, IRInstruction(Opcode.CMPI, irDtLeft, reg1 = leftTr.resultReg, immediate = 0), null) addInstr(result, branchInstr(goto, Opcode.BSTEQ), null) } "!=" -> { - addInstr(result, IRInstruction(Opcode.CMPI, irDtLeft, reg1 = leftTr.resultReg, immediate = 0), null) + if(requireCompareZero) + addInstr(result, IRInstruction(Opcode.CMPI, irDtLeft, reg1 = leftTr.resultReg, immediate = 0), null) addInstr(result, branchInstr(goto, Opcode.BSTNE), null) } else -> { - // TODO: to-be converted operators val opcode = when (condition.operator) { "<" -> if (signed) Opcode.BLTS else Opcode.BLT ">" -> if (signed) Opcode.BGTS else Opcode.BGT @@ -1072,12 +1076,13 @@ class IRCodeGen( ) { val condition = ifElse.condition as? PtBinaryExpression if(condition==null) { - val tr = expressionEval.translateExpression(ifElse.condition) - result += tr.chunks - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.CMPI, irDtLeft, reg1 = tr.resultReg, immediate = 0) - it += branchInstr(goto, Opcode.BSTNE) - } + throw AssemblyError("expected condition") +// val tr = expressionEval.translateExpression(ifElse.condition) +// result += tr.chunks +// result += IRCodeChunk(null, null).also { +// it += IRInstruction(Opcode.CMPI, irDtLeft, reg1 = tr.resultReg, immediate = 0) // was redundant CMP most likely +// it += branchInstr(goto, Opcode.BSTNE) +// } } else { val leftTr = expressionEval.translateExpression(condition.left) addToResult(result, leftTr, leftTr.resultReg, -1) @@ -1085,7 +1090,6 @@ class IRCodeGen( if(number!=null) { val firstReg = leftTr.resultReg when(condition.operator) { - // TODO: the converted operators "==" -> { addInstr(result, IRInstruction(Opcode.CMPI, irDtLeft, reg1 = firstReg, immediate = number), null) addInstr(result, branchInstr(goto, Opcode.BSTEQ), null) @@ -1095,7 +1099,6 @@ class IRCodeGen( addInstr(result, branchInstr(goto, Opcode.BSTNE), null) } else -> { - // TODO: to-be converted operators val opcode = when (condition.operator) { "<" -> if(signed) Opcode.BLTS else Opcode.BLT ">" -> if(signed) Opcode.BGTS else Opcode.BGT @@ -1267,33 +1270,6 @@ class IRCodeGen( val condition = ifElse.condition as? PtBinaryExpression if(condition==null) { 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 { if (irDtLeft == IRDataType.FLOAT) { val leftTr = expressionEval.translateExpression(condition.left) @@ -1641,10 +1617,7 @@ class IRCodeGen( addToResult(result, countTr, countTr.resultReg, -1) if(constIntValue(repeat.count)==null) { // check if the counter is already zero - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.CMPI, irDt, reg1=countTr.resultReg, immediate = 0) - it += IRInstruction(Opcode.BSTEQ, labelSymbol = skipRepeatLabel) - } + addInstr(result, IRInstruction(Opcode.BSTEQ, labelSymbol = skipRepeatLabel), null) } result += labelFirstChunk(translateNode(repeat.statements), repeatLabel) result += IRCodeChunk(null, null).also { diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 419239642..f803c99bb 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -2,7 +2,7 @@ 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 .... ... diff --git a/examples/test.p8 b/examples/test.p8 index adefd15a9..6396209b3 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,19 +1,12 @@ %zeropage basicsafe %import textio -txt { - %option merge - sub println(uword string) { - txt.print(string) +main { + sub start() { + ubyte xx=12 + + if xx==12 + txt.print("gottem") txt.nl() } } - -main { - sub start() { - txt.lowercase() - txt.println("Hello, world1") - txt.println("Hello, world2") - txt.println("Hello, world3") - } -} diff --git a/intermediate/src/prog8/intermediate/IRInstructions.kt b/intermediate/src/prog8/intermediate/IRInstructions.kt index abb6dcc07..cecc88006 100644 --- a/intermediate/src/prog8/intermediate/IRInstructions.kt +++ b/intermediate/src/prog8/intermediate/IRInstructions.kt @@ -437,6 +437,7 @@ val OpcodesThatSetStatusbitsButNotCarry = setOf( Opcode.DEC, Opcode.DECM ) +val OpcodesThatSetStatusbits = OpcodesThatSetStatusbitsButNotCarry + OpcodesThatSetStatusbitsIncludingCarry enum class IRDataType {