diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt index 1f0728680..da227bb99 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt @@ -4,10 +4,7 @@ import com.github.michaelbull.result.Ok import com.github.michaelbull.result.Result import com.github.michaelbull.result.getOrElse import prog8.code.ast.* -import prog8.code.core.AssemblyError -import prog8.code.core.DataType -import prog8.code.core.PrefixOperators -import prog8.code.core.SignedDatatypes +import prog8.code.core.* import prog8.intermediate.* @@ -30,6 +27,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express val memory = augAssign.target.memory val array = augAssign.target.array + // TODO don't fragment the implementation over multiple subroutines val chunks = if(ident!=null) { assignVarAugmented(ident.name, augAssign) } else if(memory != null) { @@ -38,7 +36,8 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express else fallbackAssign(augAssign) } else if(array!=null) { - assignArrayAugmented(array, augAssign) + // TODO assignArrayAugmented(array, augAssign) + fallbackAssign(augAssign) } else { fallbackAssign(augAssign) } @@ -118,12 +117,12 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express // "<<=" -> expressionEval.operatorShiftLeftInplace(array, eltSize, value) // ">>=" -> expressionEval.operatorShiftRightInplace(array, eltSize, signed, value) // "%=" -> expressionEval.operatorModuloInplace(array, eltSize, value) - "==" -> expressionEval.operatorEqualsNotEqualsInplace(array, eltSize, value, true) - "!=" -> expressionEval.operatorEqualsNotEqualsInplace(array, eltSize, value, false) -// "<" -> expressionEval.operatorLessInplace(array, eltSize, signed, value) // TODO reuse code from == -// ">" -> expressionEval.operatorGreaterInplace(array, eltSize, signed, value) // TODO reuse code from == -// "<=" -> expressionEval.operatorLessEqualInplace(array, eltSize, signed, value) // TODO reuse code from == -// ">=" -> expressionEval.operatorGreaterEqualInplace(array, eltSize, signed, value) // TODO reuse code from == + "==" -> expressionEval.operatorEqualsInplace(array, eltSize, value) + "!=" -> expressionEval.operatorNotEqualsInplace(array, eltSize, value) + "<" -> expressionEval.operatorLessInplace(array, eltSize, signed, value) + ">" -> expressionEval.operatorGreaterInplace(array, eltSize, signed, value) + "<=" -> expressionEval.operatorLessEqualInplace(array, eltSize, signed, value) + ">=" -> expressionEval.operatorGreaterEqualInplace(array, eltSize, signed, value) in PrefixOperators -> inplacePrefix(assignment.operator, array, eltSize) // else -> Err(NotImplementedError("invalid augmented assign operator ${assignment.operator}")) @@ -136,12 +135,17 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express private fun fallbackAssign(origAssign: PtAugmentedAssign): IRCodeChunks { val value: PtExpression if(origAssign.operator in PrefixOperators) { - value = PtPrefix(origAssign.operator, origAssign.target.type, origAssign.value.position) + value = PtPrefix(origAssign.operator, origAssign.value.type, origAssign.value.position) value.add(origAssign.value) } else { - require(origAssign.operator.endsWith('=')) - val operator = if(origAssign.operator=="==") "==" else origAssign.operator.dropLast(1) - value = PtBinaryExpression(operator, origAssign.target.type, origAssign.value.position) + val operator = when(origAssign.operator) { + in ComparisonOperators -> origAssign.operator + else -> { + require(origAssign.operator.endsWith('=')) + origAssign.operator.dropLast(1) + } + } + value = PtBinaryExpression(operator, origAssign.value.type, origAssign.value.position) val left: PtExpression = origAssign.target.children.single() as PtExpression value.add(left) value.add(origAssign.value) diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt index 0e97b6ccb..8f539378f 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt @@ -1394,7 +1394,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { } } - private fun createInplaceComparison( + private fun createInplaceComparison( knownAddress: Int?, symbol: String?, vmDt: IRDataType, @@ -1405,7 +1405,29 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { val valueReg = codeGen.registers.nextFree() val cmpResultReg = codeGen.registers.nextFree() if(operand is PtNumber) { - // TODO optimize if operand is 0 + + if(operand.number==0.0 && compareAndSetOpcode in arrayOf(Opcode.SEQ, Opcode.SNE)) { + // ==0 or !=0 optimized case + val compareAndSetOpcodeZero = if(compareAndSetOpcode==Opcode.SEQ) Opcode.SZ else Opcode.SNZ + if (knownAddress != null) { + // in-place modify a memory location + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOADM, vmDt, reg1 = valueReg, address = knownAddress) + it += IRInstruction(compareAndSetOpcodeZero, vmDt, reg1 = cmpResultReg, reg2 = valueReg) + it += IRInstruction(Opcode.STOREM, vmDt, reg1 = cmpResultReg, address = knownAddress) + } + } else { + // in-place modify a symbol (variable) + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOADM, vmDt, reg1 = valueReg, labelSymbol = symbol) + it += IRInstruction(compareAndSetOpcodeZero, vmDt, reg1=cmpResultReg, reg2 = valueReg) + it += IRInstruction(Opcode.STOREM, vmDt, reg1 = cmpResultReg, labelSymbol = symbol) + } + } + return result + } + + // compare against number that is not 0 val numberReg = codeGen.registers.nextFree() if (knownAddress != null) { // in-place modify a memory location @@ -1457,7 +1479,6 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { val cmpReg = codeGen.registers.nextFree() val zeroReg = codeGen.registers.nextFree() if(operand is PtNumber) { - // TODO optimize if operand is 0 ? val numberReg = codeGen.registers.nextFreeFloat() val cmpResultReg = codeGen.registers.nextFree() if (knownAddress != null) { @@ -1512,7 +1533,54 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { return result } - fun operatorEqualsNotEqualsInplace(array: PtArrayIndexer, eltSize: Int, value: PtExpression, equals: Boolean): Result { + fun operatorEqualsInplace(array: PtArrayIndexer, eltSize: Int, value: PtExpression): Result { + if(array.type==DataType.FLOAT) + return Err(NotImplementedError("optimized in-place compare on float arrays")) // TODO + else + return createCompareArrayInplace(array, eltSize, value, Opcode.SZ) + } + + fun operatorNotEqualsInplace(array: PtArrayIndexer, eltSize: Int, value: PtExpression): Result { + if(array.type==DataType.FLOAT) + return Err(NotImplementedError("optimized in-place compare on float arrays")) // TODO + else + return createCompareArrayInplace(array, eltSize, value, Opcode.SNZ) + } + + fun operatorLessInplace(array: PtArrayIndexer, eltSize: Int, signed: Boolean, value: PtExpression): Result { + if(array.type==DataType.FLOAT) + return Err(NotImplementedError("optimized in-place compare on float arrays")) // TODO + else + TODO("<") + //return createOperatorEqualsNotEqualsInplaceComparison(array, eltSize, value, Opcode.SZ) + } + + fun operatorLessEqualInplace(array: PtArrayIndexer, eltSize: Int, signed: Boolean, value: PtExpression): Result { + if(array.type==DataType.FLOAT) + return Err(NotImplementedError("optimized in-place compare on float arrays")) // TODO + else + TODO("<=") + //return createOperatorEqualsNotEqualsInplaceComparison(array, eltSize, value, Opcode.SZ) + } + + fun operatorGreaterInplace(array: PtArrayIndexer, eltSize: Int, signed: Boolean, value: PtExpression): Result { + if(array.type==DataType.FLOAT) + return Err(NotImplementedError("optimized in-place compare on float arrays")) // TODO + else + TODO(">") + //return createOperatorEqualsNotEqualsInplaceComparison(array, eltSize, value, Opcode.SZ) + } + + fun operatorGreaterEqualInplace(array: PtArrayIndexer, eltSize: Int, signed: Boolean, value: PtExpression): Result { + if(array.type==DataType.FLOAT) + return Err(NotImplementedError("optimized in-place compare on float arrays")) // TODO + else + TODO(">=") + //return createOperatorEqualsNotEqualsInplaceComparison(array, eltSize, value, Opcode.SZ) + } + + private fun createCompareArrayInplace(array: PtArrayIndexer, eltSize: Int, value: PtExpression, compareAndSetOpcode: Opcode): Result { + require(array.type!=DataType.FLOAT) val result = mutableListOf() if(array.splitWords) TODO("inplace == for split word array") @@ -1526,7 +1594,6 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { if(constValue!=null) { val valueReg = codeGen.registers.nextFree() if(constValue==0) { - val compareAndSetOpcode = if(equals) Opcode.SZ else Opcode.SNZ result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.LOADM, vmDt, reg1=valueReg, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize) it += IRInstruction(compareAndSetOpcode, vmDt, reg1=cmpResultReg, reg2=valueReg) diff --git a/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt b/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt index b544e875c..051476e9b 100644 --- a/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt +++ b/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt @@ -196,7 +196,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val if(valuetype in IterableDatatypes && targettype==DataType.UWORD) // special case, don't typecast STR/arrays to UWORD, we support those assignments "directly" return noModifications - if((assignment.value as? BinaryExpression)?.operator in ComparisonOperators) { + if((assignment.value as? BinaryExpression)?.operator in ComparisonOperators && targettype in IntegerDatatypes) { // special case, treat a boolean comparison result as the same type as the target value to avoid needless casts later return noModifications } diff --git a/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt b/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt index 7bae16b53..21d7be9c9 100644 --- a/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt +++ b/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt @@ -66,9 +66,9 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter, } // if the expression is a comparison expression, or a logical expression, it produces the - // correct 'boolean' byte result so the cast can be removed. + // correct 'boolean' byte result so the cast can be removed. Only if target is Integer. val binExpr = typecast.expression as? BinaryExpression - if(binExpr!=null && binExpr.operator in ComparisonOperators + LogicalOperators) { + if(binExpr!=null && binExpr.operator in ComparisonOperators + LogicalOperators && typecast.type in IntegerDatatypesNoBool) { return listOf(IAstModification.ReplaceNode(typecast, binExpr, parent)) } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index a821e1569..681d4fdb8 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,8 +1,7 @@ TODO ==== -IR assignVarAugmented(): implement all operators. -IR expressionGen.kt: optimize various stuff if the operand is const value 0 +IR assignArrayAugmented(): implement all operators. (BUT: actually, don't split this up anymore per assign target type ...) maze: if cell & UP!=0 and @(celladdr(cx,cy-1)) & (WALKED|BACKTRACKED) ==0 diff --git a/examples/test.p8 b/examples/test.p8 index aa89810c0..e70b2accd 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,24 +1,29 @@ %import textio +%import floats %zeropage basicsafe %option no_sysinit main { sub start() { + ubyte @shared xx uword[3] ubarr bool[3] barr + float[3] flarr bool @shared bb -; ubarr[1] = ubarr[1] + 2 -; ubarr[1] = ubarr[1] * 3 + ubarr[1] = ubarr[1] < 2 + ubarr[1] = ubarr[1] <= 2 + ubarr[1] = ubarr[1] > 3 + ubarr[1] = ubarr[1] >= 3 ; barr[1] = barr[0] and barr[2] ; barr[1] = barr[0] or barr[2] ; barr[1] = barr[0] xor barr[2] ; barr[1] = not barr[0] - ubarr[1] = 999 - ubarr[1] = ubarr[1]==999 - txt.print_uw(ubarr[1]) +; ubarr[1] = 999 +; ubarr[1] = ubarr[1]==999 +; txt.print_uw(ubarr[1]) ; barr[1] = barr[1] and bb ; barr[1] = barr[1] or bb