diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt index 3903a3813..bfc85cfef 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt @@ -551,8 +551,9 @@ class IRCodeGen( result += labelFirstChunk(translateNode(forLoop.statements), loopLabel) result += addConstMem(loopvarDtIr, null, loopvarSymbol, step) addInstr(result, IRInstruction(Opcode.LOADM, loopvarDtIr, reg1 = indexReg, labelSymbol = loopvarSymbol), null) - val branchOpcode = if(loopvarDt in SignedDatatypes) Opcode.BLES else Opcode.BLE - addInstr(result, IRInstruction(branchOpcode, loopvarDtIr, reg1=indexReg, reg2=endvalueReg, labelSymbol=loopLabel), null) + // if endvalue >= index, iterate loop + val branchOpcode = if(loopvarDt in SignedDatatypes) Opcode.BGES else Opcode.BGE + addInstr(result, IRInstruction(branchOpcode, loopvarDtIr, reg1=endvalueReg, reg2=indexReg, labelSymbol=loopLabel), null) result += IRCodeChunk(labelAfterFor, null) return result @@ -907,56 +908,117 @@ class IRCodeGen( if(ifElse.condition.operator !in ComparisonOperators) throw AssemblyError("if condition should only be a binary comparison expression") - val signed = ifElse.condition.left.type in arrayOf(DataType.BYTE, DataType.WORD, DataType.FLOAT) + val signed = ifElse.condition.left.type in SignedDatatypes val irDt = irType(ifElse.condition.left.type) val goto = ifElse.ifScope.children.firstOrNull() as? PtJump if(goto!=null && ifElse.elseScope.children.isEmpty()) { // special case the form: if goto val result = mutableListOf() - val leftReg = registers.nextFree() - val rightReg = registers.nextFree() - result += expressionEval.translateExpression(ifElse.condition.left, leftReg, -1) - result += expressionEval.translateExpression(ifElse.condition.right, rightReg, -1) - val opcode = when(ifElse.condition.operator) { - "==" -> Opcode.BEQ - "!=" -> Opcode.BNE - "<" -> Opcode.BLT - ">" -> Opcode.BGT - "<=" -> Opcode.BLE - ">=" -> Opcode.BGE + val leftRegNum = registers.nextFree() + val rightRegNum = registers.nextFree() + result += expressionEval.translateExpression(ifElse.condition.left, leftRegNum, -1) + result += expressionEval.translateExpression(ifElse.condition.right, rightRegNum, -1) + val opcode: Opcode + val firstReg: Int + val secondReg: Int + when(ifElse.condition.operator) { + "==" -> { + opcode = Opcode.BEQ + firstReg = leftRegNum + secondReg = rightRegNum + } + "!=" -> { + opcode = Opcode.BNE + firstReg = leftRegNum + secondReg = rightRegNum + } + "<" -> { + // swapped '>' + opcode = if(signed) Opcode.BGTS else Opcode.BGT + firstReg = rightRegNum + secondReg = leftRegNum + } + ">" -> { + opcode = if(signed) Opcode.BGTS else Opcode.BGT + firstReg = leftRegNum + secondReg = rightRegNum + } + "<=" -> { + // swapped '>=' + opcode = if(signed) Opcode.BGES else Opcode.BGE + firstReg = rightRegNum + secondReg = leftRegNum + } + ">=" -> { + opcode = if(signed) Opcode.BGES else Opcode.BGE + firstReg = leftRegNum + secondReg = rightRegNum + } else -> throw AssemblyError("invalid comparison operator") } if(goto.address!=null) - addInstr(result, IRInstruction(opcode, irDt, reg1=leftReg, reg2=rightReg, value = goto.address?.toInt()), null) + addInstr(result, IRInstruction(opcode, irDt, reg1=firstReg, reg2=secondReg, value = goto.address?.toInt()), null) else if(goto.generatedLabel!=null) - addInstr(result, IRInstruction(opcode, irDt, reg1=leftReg, reg2=rightReg, labelSymbol = goto.generatedLabel), null) + addInstr(result, IRInstruction(opcode, irDt, reg1=firstReg, reg2=secondReg, labelSymbol = goto.generatedLabel), null) else - addInstr(result, IRInstruction(opcode, irDt, reg1=leftReg, reg2=rightReg, labelSymbol = goto.identifier!!.targetName.joinToString(".")), null) + addInstr(result, IRInstruction(opcode, irDt, reg1=firstReg, reg2=secondReg, labelSymbol = goto.identifier!!.targetName.joinToString(".")), null) return result } fun translateNonZeroComparison(): IRCodeChunks { val result = mutableListOf() - val elseBranch = when(ifElse.condition.operator) { - "==" -> Opcode.BNE - "!=" -> Opcode.BEQ - "<" -> if(signed) Opcode.BGES else Opcode.BGE - ">" -> if(signed) Opcode.BLES else Opcode.BLE - "<=" -> if(signed) Opcode.BGTS else Opcode.BGT - ">=" -> if(signed) Opcode.BLTS else Opcode.BLT + val leftRegNum = registers.nextFree() + val rightRegNum = registers.nextFree() + result += expressionEval.translateExpression(ifElse.condition.left, leftRegNum, -1) + result += expressionEval.translateExpression(ifElse.condition.right, rightRegNum, -1) + + val elseBranchOpcode: Opcode + val elseBranchFirstReg: Int + val elseBranchSecondReg: Int + when(ifElse.condition.operator) { + "==" -> { + elseBranchOpcode = Opcode.BNE + elseBranchFirstReg = leftRegNum + elseBranchSecondReg = rightRegNum + } + "!=" -> { + elseBranchOpcode = Opcode.BEQ + elseBranchFirstReg = leftRegNum + elseBranchSecondReg = rightRegNum + } + "<" -> { + // else part when left >= right + elseBranchOpcode = if(signed) Opcode.BGES else Opcode.BGE + elseBranchFirstReg = leftRegNum + elseBranchSecondReg = rightRegNum + } + ">" -> { + // else part when left <= right --> right >= left + elseBranchOpcode = if(signed) Opcode.BGES else Opcode.BGE + elseBranchFirstReg = rightRegNum + elseBranchSecondReg = leftRegNum + } + "<=" -> { + // else part when left > right + elseBranchOpcode = if(signed) Opcode.BGTS else Opcode.BGT + elseBranchFirstReg = leftRegNum + elseBranchSecondReg = rightRegNum + } + ">=" -> { + // else part when left < right --> right > left + elseBranchOpcode = if(signed) Opcode.BGTS else Opcode.BGT + elseBranchFirstReg = rightRegNum + elseBranchSecondReg = leftRegNum + } else -> throw AssemblyError("invalid comparison operator") } - val leftReg = registers.nextFree() - val rightReg = registers.nextFree() - result += expressionEval.translateExpression(ifElse.condition.left, leftReg, -1) - result += expressionEval.translateExpression(ifElse.condition.right, rightReg, -1) if(ifElse.elseScope.children.isNotEmpty()) { // if and else parts val elseLabel = createLabelName() val afterIfLabel = createLabelName() - addInstr(result, IRInstruction(elseBranch, irDt, reg1=leftReg, reg2=rightReg, labelSymbol = elseLabel), null) + addInstr(result, IRInstruction(elseBranchOpcode, irDt, reg1=elseBranchFirstReg, reg2=elseBranchSecondReg, labelSymbol = elseLabel), null) result += translateNode(ifElse.ifScope) addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = afterIfLabel), null) result += labelFirstChunk(translateNode(ifElse.elseScope), elseLabel) @@ -964,7 +1026,7 @@ class IRCodeGen( } else { // only if part val afterIfLabel = createLabelName() - addInstr(result, IRInstruction(elseBranch, irDt, reg1=leftReg, reg2=rightReg, labelSymbol = afterIfLabel), null) + addInstr(result, IRInstruction(elseBranchOpcode, irDt, reg1=elseBranchFirstReg, reg2=elseBranchSecondReg, labelSymbol = afterIfLabel), null) result += translateNode(ifElse.ifScope) result += IRCodeChunk(afterIfLabel, null) } @@ -1006,6 +1068,7 @@ class IRCodeGen( } else -> { // another comparison against 0, just use regular codegen for this. + // TODO optimize this translateNonZeroComparison() } } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 64f69f0b9..34fcfeed7 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,7 +3,7 @@ TODO For next release ^^^^^^^^^^^^^^^^ -- remove redundant branch opcodes in IR: BLT(S), BLE(S). Replace by swapped BGT(S), BGE(S). +- try to optimize IR for branching on signed <0, >0, <=0, >=0 by using new branch instructions like we have BNZ. To avoid explicit compares. See translateZeroComparison() - make sure bool value is always 0 or 1 (all casts should convert), then: - rewrite bool=bool^1 into bool=not bool - should solve: bool bb = not bb -> larger code than bool bb ^= 1 diff --git a/intermediate/src/prog8/intermediate/IRInstructions.kt b/intermediate/src/prog8/intermediate/IRInstructions.kt index 168234750..eb83d2909 100644 --- a/intermediate/src/prog8/intermediate/IRInstructions.kt +++ b/intermediate/src/prog8/intermediate/IRInstructions.kt @@ -76,20 +76,17 @@ bz reg1, address - branch to location if reg1 is zero bnz reg1, address - branch to location if reg1 is not zero beq reg1, reg2, address - jump to location in program given by location, if reg1 == reg2 bne reg1, reg2, address - jump to location in program given by location, if reg1 != reg2 -blt reg1, reg2, address - jump to location in program given by location, if reg1 < reg2 (unsigned) TODO REMOVE -blts reg1, reg2, address - jump to location in program given by location, if reg1 < reg2 (signed) TODO REMOVE -ble reg1, reg2, address - jump to location in program given by location, if reg1 <= reg2 (unsigned) TODO REMOVE -bles reg1, reg2, address - jump to location in program given by location, if reg1 <= reg2 (signed) TODO REMOVE bgt reg1, reg2, address - jump to location in program given by location, if reg1 > reg2 (unsigned) bgts reg1, reg2, address - jump to location in program given by location, if reg1 > reg2 (signed) bge reg1, reg2, address - jump to location in program given by location, if reg1 >= reg2 (unsigned) bges reg1, reg2, address - jump to location in program given by location, if reg1 >= reg2 (signed) +( NOTE: there are no blt/ble instructions because these are equivalent to bgt/bge with the operands swapped around.) seq reg1, reg2 - set reg=1 if reg1 == reg2, otherwise set reg1=0 sne reg1, reg2 - set reg=1 if reg1 != reg2, otherwise set reg1=0 -slt reg1, reg2 - set reg=1 if reg1 < reg2 (unsigned), otherwise set reg1=0 TODO REMOVE -slts reg1, reg2 - set reg=1 if reg1 < reg2 (signed), otherwise set reg1=0 TODO REMOVE -sle reg1, reg2 - set reg=1 if reg1 <= reg2 (unsigned), otherwise set reg1=0 TODO REMOVE -sles reg1, reg2 - set reg=1 if reg1 <= reg2 (signed), otherwise set reg1=0 TODO REMOVE +slt reg1, reg2 - set reg=1 if reg1 < reg2 (unsigned), otherwise set reg1=0 +slts reg1, reg2 - set reg=1 if reg1 < reg2 (signed), otherwise set reg1=0 +sle reg1, reg2 - set reg=1 if reg1 <= reg2 (unsigned), otherwise set reg1=0 +sles reg1, reg2 - set reg=1 if reg1 <= reg2 (signed), otherwise set reg1=0 sgt reg1, reg2 - set reg=1 if reg1 > reg2 (unsigned), otherwise set reg1=0 sgts reg1, reg2 - set reg=1 if reg1 > reg2 (signed), otherwise set reg1=0 sge reg1, reg2 - set reg=1 if reg1 >= reg2 (unsigned), otherwise set reg1=0 @@ -244,22 +241,18 @@ enum class Opcode { BNZ, BEQ, BNE, - BLT, // TODO REMOVE - BLTS, // TODO REMOVE BGT, BGTS, - BLE, // TODO REMOVE - BLES, // TODO REMOVE BGE, BGES, SEQ, SNE, - SLT, // TODO REMOVE ? - SLTS, // TODO REMOVE ? + SLT, + SLTS, SGT, SGTS, - SLE, // TODO REMOVE ? - SLES, // TODO REMOVE ? + SLE, + SLES, SGE, SGES, @@ -379,12 +372,8 @@ val OpcodesThatBranch = setOf( Opcode.BNZ, Opcode.BEQ, Opcode.BNE, - Opcode.BLT, - Opcode.BLTS, Opcode.BGT, Opcode.BGTS, - Opcode.BLE, - Opcode.BLES, Opcode.BGE, Opcode.BGES ) @@ -419,12 +408,8 @@ val OpcodesWithMemoryAddressAsValue = setOf( Opcode.BNZ, Opcode.BEQ, Opcode.BNE, - Opcode.BLT, - Opcode.BLTS, Opcode.BGT, Opcode.BGTS, - Opcode.BLE, - Opcode.BLES, Opcode.BGE, Opcode.BGES, Opcode.INCM, @@ -560,12 +545,8 @@ val instructionFormats = mutableMapOf( Opcode.BNZ to InstructionFormat.from("BW,r1, InsBNZ(ins) Opcode.BEQ -> InsBEQ(ins) Opcode.BNE -> InsBNE(ins) - Opcode.BLT -> InsBLTU(ins) - Opcode.BLTS -> InsBLTS(ins) Opcode.BGT -> InsBGTU(ins) Opcode.BGTS -> InsBGTS(ins) - Opcode.BLE -> InsBLEU(ins) - Opcode.BLES -> InsBLES(ins) Opcode.BGE -> InsBGEU(ins) Opcode.BGES -> InsBGES(ins) Opcode.SEQ -> InsSEQ(ins) @@ -676,22 +672,6 @@ class VirtualMachine(irProgram: IRProgram) { nextPc() } - private fun InsBLTU(i: IRInstruction) { - val (left: UInt, right: UInt) = getBranchOperandsU(i) - if(leftright) @@ -709,23 +689,6 @@ class VirtualMachine(irProgram: IRProgram) { nextPc() } - private fun InsBLEU(i: IRInstruction) { - val (left: UInt, right: UInt) = getBranchOperandsU(i) - if(left<=right) - branchTo(i) - else - nextPc() - - } - - private fun InsBLES(i: IRInstruction) { - val (left: Int, right: Int) = getBranchOperands(i) - if(left<=right) - branchTo(i) - else - nextPc() - } - private fun InsBGEU(i: IRInstruction) { val (left: UInt, right: UInt) = getBranchOperandsU(i) if(left>=right)