diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt index 674803d6e..f5549b464 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt @@ -72,25 +72,25 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express private fun assignVarAugmented(symbol: String, assignment: PtAugmentedAssign): IRCodeChunks { val value = assignment.value - val valueVmDt = codeGen.irType(value.type) + val targetDt = codeGen.irType(assignment.target.type) return when (assignment.operator) { - "+=" -> expressionEval.operatorPlusInplace(null, symbol, valueVmDt, value) - "-=" -> expressionEval.operatorMinusInplace(null, symbol, valueVmDt, value) - "*=" -> expressionEval.operatorMultiplyInplace(null, symbol, valueVmDt, value) - "/=" -> expressionEval.operatorDivideInplace(null, symbol, valueVmDt, value.type in SignedDatatypes, value) - "|=" -> expressionEval.operatorOrInplace(null, symbol, valueVmDt, value) - "&=" -> expressionEval.operatorAndInplace(null, symbol, valueVmDt, value) - "^=" -> expressionEval.operatorXorInplace(null, symbol, valueVmDt, value) - "<<=" -> expressionEval.operatorShiftLeftInplace(null, symbol, valueVmDt, value) - ">>=" -> expressionEval.operatorShiftRightInplace(null, symbol, valueVmDt, value.type in SignedDatatypes, value) - "%=" -> expressionEval.operatorModuloInplace(null, symbol, valueVmDt, value) - "==" -> expressionEval.operatorEqualsInplace(null, symbol, valueVmDt, value) - "!=" -> expressionEval.operatorNotEqualsInplace(null, symbol, valueVmDt, value) - "<" -> expressionEval.operatorLessInplace(null, symbol, valueVmDt, value.type in SignedDatatypes, value) - ">" -> expressionEval.operatorGreaterInplace(null, symbol, valueVmDt, value.type in SignedDatatypes, value) - "<=" -> expressionEval.operatorLessEqualInplace(null, symbol, valueVmDt, value.type in SignedDatatypes, value) - ">=" -> expressionEval.operatorGreaterEqualInplace(null, symbol, valueVmDt, value.type in SignedDatatypes, value) - in PrefixOperators -> inplacePrefix(assignment.operator, valueVmDt, null, symbol) + "+=" -> expressionEval.operatorPlusInplace(null, symbol, targetDt, value) + "-=" -> expressionEval.operatorMinusInplace(null, symbol, targetDt, value) + "*=" -> expressionEval.operatorMultiplyInplace(null, symbol, targetDt, value) + "/=" -> expressionEval.operatorDivideInplace(null, symbol, targetDt, value.type in SignedDatatypes, value) + "|=" -> expressionEval.operatorOrInplace(null, symbol, targetDt, value) + "&=" -> expressionEval.operatorAndInplace(null, symbol, targetDt, value) + "^=" -> expressionEval.operatorXorInplace(null, symbol, targetDt, value) + "<<=" -> expressionEval.operatorShiftLeftInplace(null, symbol, targetDt, value) + ">>=" -> expressionEval.operatorShiftRightInplace(null, symbol, targetDt, value.type in SignedDatatypes, value) + "%=" -> expressionEval.operatorModuloInplace(null, symbol, targetDt, value) + "==" -> expressionEval.operatorEqualsInplace(null, symbol, targetDt, value) + "!=" -> expressionEval.operatorNotEqualsInplace(null, symbol, targetDt, value) + "<" -> expressionEval.operatorLessInplace(null, symbol, targetDt, value.type in SignedDatatypes, value) + ">" -> expressionEval.operatorGreaterInplace(null, symbol, targetDt, value.type in SignedDatatypes, value) + "<=" -> expressionEval.operatorLessEqualInplace(null, symbol, targetDt, value.type in SignedDatatypes, value) + ">=" -> expressionEval.operatorGreaterEqualInplace(null, symbol, targetDt, value.type in SignedDatatypes, value) + in PrefixOperators -> inplacePrefix(assignment.operator, targetDt, null, symbol) else -> throw AssemblyError("invalid augmented assign operator ${assignment.operator}") } } diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt index 4cde54ce1..660fabd0c 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt @@ -268,7 +268,9 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { actualResultReg2 = tr.resultReg addInstr(result, IRInstruction(Opcode.EXT, type = IRDataType.BYTE, reg1 = actualResultReg2), null) } - DataType.WORD -> { } + DataType.WORD -> { + actualResultReg2 = tr.resultReg + } DataType.FLOAT -> { actualResultReg2 = codeGen.registers.nextFree() addInstr(result, IRInstruction(Opcode.FTOUW, IRDataType.FLOAT, reg1=actualResultReg2, fpReg1 = tr.resultFpReg), null) @@ -288,7 +290,9 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { actualResultReg2 = tr.resultReg addInstr(result, IRInstruction(Opcode.EXT, type = IRDataType.BYTE, reg1 = actualResultReg2), null) } - DataType.UWORD -> { } + DataType.UWORD -> { + actualResultReg2 = tr.resultReg + } DataType.FLOAT -> { actualResultReg2 = codeGen.registers.nextFree() addInstr(result, IRInstruction(Opcode.FTOSW, IRDataType.FLOAT, reg1=actualResultReg2, fpReg1 = tr.resultFpReg), null) @@ -316,6 +320,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { } else -> throw AssemblyError("weird cast type") } + return ExpressionCodeResult(result, codeGen.irType(cast.type), actualResultReg2, actualResultFpReg2) } @@ -556,17 +561,17 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { val rightTr = translateExpression(binExpr.right) addToResult(result, rightTr, -1, rightTr.resultFpReg) val resultRegister = codeGen.registers.nextFree() + val valueReg = codeGen.registers.nextFree() + val label = codeGen.createLabelName() + addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=resultRegister, value=1), null) + addInstr(result, IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=valueReg, fpReg1 = leftTr.resultFpReg, fpReg2 = rightTr.resultFpReg), null) if (notEquals) { - addInstr(result, IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=resultRegister, fpReg1 = leftTr.resultFpReg, fpReg2 = rightTr.resultFpReg), null) + addInstr(result, IRInstruction(Opcode.BNZ, IRDataType.BYTE, reg1=valueReg, labelSymbol = label), null) } else { - val label = codeGen.createLabelName() - val valueReg = codeGen.registers.nextFree() - addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=resultRegister, value=1), null) - addInstr(result, IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=valueReg, fpReg1 = leftTr.resultFpReg, fpReg2 = rightTr.resultFpReg), null) addInstr(result, IRInstruction(Opcode.BZ, IRDataType.BYTE, reg1=valueReg, labelSymbol = label), null) - addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=resultRegister, value=0), null) - result += IRCodeChunk(label, null) } + addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=resultRegister, value=0), null) + result += IRCodeChunk(label, null) return ExpressionCodeResult(result, IRDataType.BYTE, resultRegister, -1) } else { if(binExpr.left.type==DataType.STR && binExpr.right.type==DataType.STR) { @@ -1208,152 +1213,124 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { } fun operatorEqualsInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks { - val result = mutableListOf() - val tr = translateExpression(operand) - addToResult(result, tr, tr.resultReg, -1) - if(knownAddress!=null) { - // @(address) = @(address) == operand - val valueReg = codeGen.registers.nextFree() - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOADM, vmDt, reg1=valueReg, value=knownAddress) - it += IRInstruction(Opcode.SEQ, vmDt, reg1=valueReg, reg2=tr.resultReg) - it += IRInstruction(Opcode.STOREM, vmDt, reg1=valueReg, value=knownAddress) - } + return if(vmDt==IRDataType.FLOAT) { + createInplaceFloatComparison(knownAddress, symbol, operand, Opcode.SEQ) } else { - // symbol = symbol == operand - val valueReg = codeGen.registers.nextFree() - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOADM, vmDt, reg1=valueReg, labelSymbol = symbol) - it += IRInstruction(Opcode.SEQ, vmDt, reg1=valueReg, reg2=tr.resultReg) - it += IRInstruction(Opcode.STOREM, vmDt, reg1=valueReg, labelSymbol = symbol) - } + createInplaceComparison(knownAddress, symbol, vmDt, operand, Opcode.SEQ) } - return result } fun operatorNotEqualsInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks { - val result = mutableListOf() - val tr = translateExpression(operand) - addToResult(result, tr, tr.resultReg, -1) - if(knownAddress!=null) { - // @(address) = @(address) != operand - val valueReg = codeGen.registers.nextFree() - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOADM, vmDt, reg1=valueReg, value=knownAddress) - it += IRInstruction(Opcode.SNE, vmDt, reg1=valueReg, reg2=tr.resultReg) - it += IRInstruction(Opcode.STOREM, vmDt, reg1=valueReg, value=knownAddress) - } + return if(vmDt==IRDataType.FLOAT) { + createInplaceFloatComparison(knownAddress, symbol, operand, Opcode.SNE) } else { - // symbol = symbol != operand - val valueReg = codeGen.registers.nextFree() - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOADM, vmDt, reg1=valueReg, labelSymbol = symbol) - it += IRInstruction(Opcode.SNE, vmDt, reg1=valueReg, reg2=tr.resultReg) - it += IRInstruction(Opcode.STOREM, vmDt, reg1=valueReg, labelSymbol = symbol) - } + createInplaceComparison(knownAddress, symbol, vmDt, operand, Opcode.SNE) } - return result + } fun operatorGreaterInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, signed: Boolean, operand: PtExpression): IRCodeChunks { - val result = mutableListOf() - val tr = translateExpression(operand) - addToResult(result, tr, tr.resultReg, -1) val opcode = if(signed) Opcode.SGTS else Opcode.SGT - if(knownAddress!=null) { - // @(address) = @(address) > operand - val valueReg = codeGen.registers.nextFree() - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOADM, vmDt, reg1=valueReg, value=knownAddress) - it += IRInstruction(opcode, vmDt, reg1=valueReg, reg2=tr.resultReg) - it += IRInstruction(Opcode.STOREM, vmDt, reg1=valueReg, value=knownAddress) - } + return if(vmDt==IRDataType.FLOAT) { + createInplaceFloatComparison(knownAddress, symbol, operand, opcode) } else { - // symbol = symbol > operand - val valueReg = codeGen.registers.nextFree() - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOADM, vmDt, reg1=valueReg, labelSymbol = symbol) - it += IRInstruction(opcode, vmDt, reg1=valueReg, reg2=tr.resultReg) - it += IRInstruction(Opcode.STOREM, vmDt, reg1=valueReg, labelSymbol = symbol) - } + createInplaceComparison(knownAddress, symbol, vmDt, operand, opcode) } - return result } fun operatorLessInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, signed: Boolean, operand: PtExpression): IRCodeChunks { - val result = mutableListOf() - val tr = translateExpression(operand) - addToResult(result, tr, tr.resultReg, -1) val opcode = if(signed) Opcode.SLTS else Opcode.SLT - if(knownAddress!=null) { - // @(address) = @(address) < operand - val valueReg = codeGen.registers.nextFree() - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOADM, vmDt, reg1=valueReg, value=knownAddress) - it += IRInstruction(opcode, vmDt, reg1=valueReg, reg2=tr.resultReg) - it += IRInstruction(Opcode.STOREM, vmDt, reg1=valueReg, value=knownAddress) - } + return if(vmDt==IRDataType.FLOAT) { + createInplaceFloatComparison(knownAddress, symbol, operand, opcode) } else { - // symbol = symbol < operand - val valueReg = codeGen.registers.nextFree() - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOADM, vmDt, reg1=valueReg, labelSymbol = symbol) - it += IRInstruction(opcode, vmDt, reg1=valueReg, reg2=tr.resultReg) - it += IRInstruction(Opcode.STOREM, vmDt, reg1=valueReg, labelSymbol = symbol) - } + createInplaceComparison(knownAddress, symbol, vmDt, operand, opcode) } - return result } fun operatorGreaterEqualInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, signed: Boolean, operand: PtExpression): IRCodeChunks { + val opcode = if(signed) Opcode.SGES else Opcode.SGE + return if(vmDt==IRDataType.FLOAT) { + createInplaceFloatComparison(knownAddress, symbol, operand, opcode) + } else { + createInplaceComparison(knownAddress, symbol, vmDt, operand, opcode) + } + } + + fun operatorLessEqualInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, signed: Boolean, operand: PtExpression): IRCodeChunks { + val opcode = if(signed) Opcode.SLES else Opcode.SLE + return if(vmDt==IRDataType.FLOAT) { + createInplaceFloatComparison(knownAddress, symbol, operand, opcode) + } else { + createInplaceComparison(knownAddress, symbol, vmDt, operand, opcode) + } + } + + private fun createInplaceComparison( + knownAddress: Int?, + symbol: String?, + vmDt: IRDataType, + operand: PtExpression, + compareAndSetOpcode: Opcode + ): MutableList { val result = mutableListOf() - val tr = translateExpression(operand) + val tr = translateExpression(operand) // TODO optimize if operand is PtNumber? addToResult(result, tr, tr.resultReg, -1) - val opcode = if(signed) Opcode.SGES else Opcode.SGE - if(knownAddress!=null) { - // @(address) = @(address) > operand + if (knownAddress != null) { + // in-place modify a memory location val valueReg = codeGen.registers.nextFree() result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOADM, vmDt, reg1=valueReg, value=knownAddress) - it += IRInstruction(opcode, vmDt, reg1=valueReg, reg2=tr.resultReg) - it += IRInstruction(Opcode.STOREM, vmDt, reg1=valueReg, value=knownAddress) + it += IRInstruction(Opcode.LOADM, vmDt, reg1 = valueReg, value = knownAddress) + it += IRInstruction(compareAndSetOpcode, vmDt, reg1 = valueReg, reg2 = tr.resultReg) + it += IRInstruction(Opcode.STOREM, vmDt, reg1 = valueReg, value = knownAddress) } } else { - // symbol = symbol > operand + // in-place modify a symbol (variable) val valueReg = codeGen.registers.nextFree() result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOADM, vmDt, reg1=valueReg, labelSymbol = symbol) - it += IRInstruction(opcode, vmDt, reg1=valueReg, reg2=tr.resultReg) - it += IRInstruction(Opcode.STOREM, vmDt, reg1=valueReg, labelSymbol = symbol) + it += IRInstruction(Opcode.LOADM, vmDt, reg1 = valueReg, labelSymbol = symbol) + it += IRInstruction(compareAndSetOpcode, vmDt, reg1 = valueReg, reg2 = tr.resultReg) + it += IRInstruction(Opcode.STOREM, vmDt, reg1 = valueReg, labelSymbol = symbol) } } return result } - fun operatorLessEqualInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, signed: Boolean, operand: PtExpression): IRCodeChunks { + private fun createInplaceFloatComparison( + knownAddress: Int?, + symbol: String?, + operand: PtExpression, + compareAndSetOpcode: Opcode + ): MutableList { val result = mutableListOf() - val tr = translateExpression(operand) - addToResult(result, tr, tr.resultReg, -1) - val opcode = if(signed) Opcode.SLES else Opcode.SLE - if(knownAddress!=null) { - // @(address) = @(address) > operand - val valueReg = codeGen.registers.nextFree() + val tr = translateExpression(operand) // TODO optimize if operand is PtNumber? + addToResult(result, tr, -1, tr.resultFpReg) + val valueReg = codeGen.registers.nextFreeFloat() + val cmpReg = codeGen.registers.nextFree() + val zeroReg = codeGen.registers.nextFree() + if (knownAddress != null) { + // in-place modify a memory location result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOADM, vmDt, reg1=valueReg, value=knownAddress) - it += IRInstruction(opcode, vmDt, reg1=valueReg, reg2=tr.resultReg) - it += IRInstruction(Opcode.STOREM, vmDt, reg1=valueReg, value=knownAddress) + it += IRInstruction(Opcode.LOADM, IRDataType.FLOAT, fpReg1 = valueReg, value = knownAddress) + it += IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=cmpReg, fpReg1 = valueReg, fpReg2 = tr.resultFpReg) + it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=zeroReg, value=0) + it += IRInstruction(compareAndSetOpcode, IRDataType.BYTE, reg1=cmpReg, reg2=zeroReg) + it += IRInstruction(Opcode.FFROMUB, IRDataType.FLOAT, reg1=cmpReg, fpReg1 = valueReg) + it += IRInstruction(Opcode.STOREM, IRDataType.FLOAT, fpReg1 = valueReg, value=knownAddress) } } else { - // symbol = symbol > operand - val valueReg = codeGen.registers.nextFree() + // in-place modify a symbol (variable) result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.LOADM, vmDt, reg1=valueReg, labelSymbol = symbol) - it += IRInstruction(opcode, vmDt, reg1=valueReg, reg2=tr.resultReg) - it += IRInstruction(Opcode.STOREM, vmDt, reg1=valueReg, labelSymbol = symbol) + it += IRInstruction(Opcode.LOADM, IRDataType.FLOAT, fpReg1 = valueReg, labelSymbol = symbol) + it += IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=cmpReg, fpReg1 = valueReg, fpReg2 = tr.resultFpReg) + it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=zeroReg, value=0) + it += IRInstruction(compareAndSetOpcode, IRDataType.BYTE, reg1=cmpReg, reg2=zeroReg) + it += IRInstruction(Opcode.FFROMUB, IRDataType.FLOAT, reg1=cmpReg, fpReg1 = valueReg) + it += IRInstruction(Opcode.STOREM, IRDataType.FLOAT, fpReg1 = valueReg, labelSymbol = symbol) } } return result } + } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 34dd742b8..6803dbdd2 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -4,11 +4,9 @@ TODO For next minor release ^^^^^^^^^^^^^^^^^^^^^^ -newxpr vm: vm/bsieve.p8 has wrong result -once everything works, disable -newexpr option for IR/virtual target because that already works without eval stack +disable -newexpr option for IR/virtual target because that already works without eval stack and creates far superior code without the newexpr flattening. - -IR (normal): fix reg1 out of bounds crash in compiler/test/comparisons/test_compares.p8 +-> move the transform to the 6502 codegen again ? instead of doing it in compiler itself? ...