From 47d0f0ea4043c654729bb898fc182027c6077469 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Fri, 31 Mar 2023 23:55:24 +0200 Subject: [PATCH] implement missing operators in IR code gen --- .../codegen/intermediate/AssignmentGen.kt | 86 ++-- .../codegen/intermediate/ExpressionGen.kt | 225 ++++++++- .../prog8/codegen/intermediate/IRCodeGen.kt | 451 ++++++++++-------- docs/source/todo.rst | 3 + examples/test.p8 | 7 + 5 files changed, 540 insertions(+), 232 deletions(-) diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt index 6fc9c81f8..616a9fbd7 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt @@ -48,15 +48,22 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express val value = assignment.value val vmDt = codeGen.irType(value.type) return when(assignment.operator) { - "+" -> expressionEval.operatorPlusInplace(address, null, vmDt, value).chunks - "-" -> expressionEval.operatorMinusInplace(address, null, vmDt, value).chunks - "*" -> expressionEval.operatorMultiplyInplace(address, null, vmDt, value).chunks - "/" -> expressionEval.operatorDivideInplace(address, null, vmDt, value.type in SignedDatatypes, value).chunks - "|" -> expressionEval.operatorOrInplace(address, null, vmDt, value).chunks - "&" -> expressionEval.operatorAndInplace(address, null, vmDt, value).chunks - "^" -> expressionEval.operatorXorInplace(address, null, vmDt, value).chunks - "<<" -> expressionEval.operatorShiftLeftInplace(address, null, vmDt, value).chunks - ">>" -> expressionEval.operatorShiftRightInplace(address, null, vmDt, value.type in SignedDatatypes, value).chunks + "+" -> expressionEval.operatorPlusInplace(address, null, vmDt, value) + "-" -> expressionEval.operatorMinusInplace(address, null, vmDt, value) + "*" -> expressionEval.operatorMultiplyInplace(address, null, vmDt, value) + "/" -> expressionEval.operatorDivideInplace(address, null, vmDt, value.type in SignedDatatypes, value) + "|" -> expressionEval.operatorOrInplace(address, null, vmDt, value) + "&" -> expressionEval.operatorAndInplace(address, null, vmDt, value) + "^" -> expressionEval.operatorXorInplace(address, null, vmDt, value) + "<<" -> expressionEval.operatorShiftLeftInplace(address, null, vmDt, value) + ">>" -> expressionEval.operatorShiftRightInplace(address, null, vmDt, value.type in SignedDatatypes, value) + "%=" -> expressionEval.operatorModuloInplace(address, null, vmDt, value) + "==" -> expressionEval.operatorEqualsInplace(address, null, vmDt, value) + "!=" -> expressionEval.operatorNotEqualsInplace(address, null, vmDt, value) + "<" -> expressionEval.operatorLessInplace(address, null, vmDt, value.type in SignedDatatypes, value) + ">" -> expressionEval.operatorGreaterInplace(address, null, vmDt, value.type in SignedDatatypes, value) + "<=" -> expressionEval.operatorLessEqualInplace(address, null, vmDt, value.type in SignedDatatypes, value) + ">=" -> expressionEval.operatorGreaterEqualInplace(address, null, vmDt, value.type in SignedDatatypes, value) in PrefixOperators -> inplacePrefix(assignment.operator, vmDt, address, null) else -> throw AssemblyError("invalid augmented assign operator ${assignment.operator}") @@ -67,15 +74,22 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express val value = assignment.value val valueVmDt = codeGen.irType(value.type) return when (assignment.operator) { - "+=" -> expressionEval.operatorPlusInplace(null, symbol, valueVmDt, value).chunks - "-=" -> expressionEval.operatorMinusInplace(null, symbol, valueVmDt, value).chunks - "*=" -> expressionEval.operatorMultiplyInplace(null, symbol, valueVmDt, value).chunks - "/=" -> expressionEval.operatorDivideInplace(null, symbol, valueVmDt, value.type in SignedDatatypes, value).chunks - "|=" -> expressionEval.operatorOrInplace(null, symbol, valueVmDt, value).chunks - "&=" -> expressionEval.operatorAndInplace(null, symbol, valueVmDt, value).chunks - "^=" -> expressionEval.operatorXorInplace(null, symbol, valueVmDt, value).chunks - "<<=" -> expressionEval.operatorShiftLeftInplace(null, symbol, valueVmDt, value).chunks - ">>=" -> expressionEval.operatorShiftRightInplace(null, symbol, valueVmDt, value.type in SignedDatatypes, value).chunks + "+=" -> 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) else -> throw AssemblyError("invalid augmented assign operator ${assignment.operator}") } @@ -84,8 +98,6 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express private fun fallbackAssign(origAssign: PtAugmentedAssign): IRCodeChunks { if (codeGen.options.slowCodegenWarnings) codeGen.errors.warn("indirect code for in-place assignment", origAssign.position) - val normalAssign = PtAssignment(origAssign.position) - normalAssign.add(origAssign.target) val value: PtExpression if(origAssign.operator in PrefixOperators) { value = PtPrefix(origAssign.operator, origAssign.value.type, origAssign.value.position) @@ -93,7 +105,21 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express } else { require(origAssign.operator.endsWith('=')) if(codeGen.options.useNewExprCode) { - TODO("use something else than a BinExpr") + // X += Y -> temp = X, temp += Y, X = temp + val tempvarname = "some_random_tempvar" // TODO create proper tempvar + val tempvar = PtIdentifier(tempvarname, origAssign.target.type, origAssign.position) + val assign = PtAssignment(origAssign.position) + val target = PtAssignTarget(origAssign.position) + target.add(tempvar) + assign.add(target) + assign.add(origAssign.target.children.single()) + val augAssign = PtAugmentedAssign(origAssign.operator, origAssign.position) + augAssign.add(target) + augAssign.add(origAssign.value) + val assignBack = PtAssignment(origAssign.position) + assignBack.add(origAssign.target) + assignBack.add(tempvar) + return translateRegularAssign(assign) + translate(augAssign) + translateRegularAssign(assignBack) } else { value = PtBinaryExpression(origAssign.operator.dropLast(1), origAssign.value.type, origAssign.value.position) val left: PtExpression = origAssign.target.children.single() as PtExpression @@ -101,6 +127,8 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express value.add(origAssign.value) } } + val normalAssign = PtAssignment(origAssign.position) + normalAssign.add(origAssign.target) normalAssign.add(value) return translateRegularAssign(normalAssign) } @@ -262,18 +290,20 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express private fun loadIndexReg(array: PtArrayIndexer, itemsize: Int): Pair { // returns the code to load the Index into the register, which is also return\ed. + + if(codeGen.options.useNewExprCode) { + TODO("use aug assigns instead of BinExpr to calc proper array index") + // return blah + } + val result = mutableListOf() val tr = if(itemsize==1) { expressionEval.translateExpression(array.index) } else { val mult : PtExpression - if(codeGen.options.useNewExprCode) { - TODO("use something else than a BinExpr") - } else { - mult = PtBinaryExpression("*", DataType.UBYTE, array.position) - mult.children += array.index - mult.children += PtNumber(DataType.UBYTE, itemsize.toDouble(), array.position) - } + mult = PtBinaryExpression("*", DataType.UBYTE, array.position) + mult.children += array.index + mult.children += PtNumber(DataType.UBYTE, itemsize.toDouble(), array.position) expressionEval.translateExpression(mult) } addToResult(result, tr, tr.resultReg, -1) diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt index 177b79486..2bd55cf7c 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt @@ -925,7 +925,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { } - internal fun operatorAndInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): ExpressionCodeResult { + internal fun operatorAndInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks { val result = mutableListOf() val tr = translateExpression(operand) addToResult(result, tr, tr.resultReg, -1) @@ -934,10 +934,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { else IRInstruction(Opcode.ANDM, vmDt, reg1=tr.resultReg, labelSymbol = symbol) ,null) - return ExpressionCodeResult(result, vmDt, -1, -1) + return result } - internal fun operatorOrInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): ExpressionCodeResult { + internal fun operatorOrInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks { val result = mutableListOf() val tr = translateExpression(operand) addToResult(result, tr, tr.resultReg, -1) @@ -946,10 +946,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { else IRInstruction(Opcode.ORM, vmDt, reg1=tr.resultReg, labelSymbol = symbol) , null) - return ExpressionCodeResult(result, vmDt, -1, -1) + return result } - internal fun operatorDivideInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, signed: Boolean, operand: PtExpression): ExpressionCodeResult { + internal fun operatorDivideInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, signed: Boolean, operand: PtExpression): IRCodeChunks { val result = mutableListOf() val constFactorRight = operand as? PtNumber if(vmDt==IRDataType.FLOAT) { @@ -995,10 +995,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { addInstr(result, ins, null) } } - return ExpressionCodeResult(result, vmDt, -1, -1) + return result } - internal fun operatorMultiplyInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): ExpressionCodeResult { + internal fun operatorMultiplyInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks { val result = mutableListOf() val constFactorRight = operand as? PtNumber if(vmDt==IRDataType.FLOAT) { @@ -1028,10 +1028,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { , null) } } - return ExpressionCodeResult(result, vmDt, -1, -1) + return result } - internal fun operatorMinusInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): ExpressionCodeResult { + internal fun operatorMinusInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks { val result = mutableListOf() if(vmDt==IRDataType.FLOAT) { if((operand as? PtNumber)?.number==1.0) { @@ -1068,10 +1068,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { , null) } } - return ExpressionCodeResult(result, vmDt, -1, -1) + return result } - internal fun operatorPlusInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): ExpressionCodeResult { + internal fun operatorPlusInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks { val result = mutableListOf() if(vmDt==IRDataType.FLOAT) { if((operand as? PtNumber)?.number==1.0) { @@ -1108,10 +1108,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { , null) } } - return ExpressionCodeResult(result, vmDt, -1, -1) + return result } - internal fun operatorShiftRightInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, signed: Boolean, operand: PtExpression): ExpressionCodeResult { + internal fun operatorShiftRightInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, signed: Boolean, operand: PtExpression): IRCodeChunks { val result = mutableListOf() if(codeGen.isOne(operand)) { val opc = if (signed) Opcode.ASRM else Opcode.LSRM @@ -1130,10 +1130,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { IRInstruction(opc, vmDt, reg1 = tr.resultReg, labelSymbol = symbol) addInstr(result, ins, null) } - return ExpressionCodeResult(result, vmDt, -1, -1) + return result } - internal fun operatorShiftLeftInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): ExpressionCodeResult { + internal fun operatorShiftLeftInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks { val result = mutableListOf() if(codeGen.isOne(operand)){ addInstr(result, if(knownAddress!=null) @@ -1150,10 +1150,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { IRInstruction(Opcode.LSLNM, vmDt, reg1=tr.resultReg, labelSymbol = symbol) ,null) } - return ExpressionCodeResult(result, vmDt, -1, -1) + return result } - internal fun operatorXorInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): ExpressionCodeResult { + internal fun operatorXorInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks { val result = mutableListOf() val tr = translateExpression(operand) addToResult(result, tr, tr.resultReg, -1) @@ -1162,9 +1162,198 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { else IRInstruction(Opcode.XORM, vmDt, reg1=tr.resultReg, labelSymbol = symbol) ,null) - return ExpressionCodeResult(result, vmDt, -1, -1) + return result } + fun operatorModuloInplace(knownAddress: Int?, symbol: String?, vmDt: IRDataType, operand: PtExpression): IRCodeChunks { + val result = mutableListOf() + val resultReg = codeGen.registers.nextFree() + if(operand is PtNumber) { + val number = operand.number.toInt() + if (knownAddress != null) { + // @(address) = @(address) %= operand + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOADM, vmDt, reg1 = resultReg, value = knownAddress) + it += IRInstruction(Opcode.MOD, vmDt, reg1 = resultReg, value = number) + it += IRInstruction(Opcode.STOREM, vmDt, reg1 = resultReg, value = knownAddress) + } + } else { + // symbol = symbol %= operand + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOADM, vmDt, reg1 = resultReg, labelSymbol = symbol) + it += IRInstruction(Opcode.MOD, vmDt, reg1 = resultReg, value = number) + it += IRInstruction(Opcode.STOREM, vmDt, reg1 = resultReg, labelSymbol = symbol) + } + } + } else { + val tr = translateExpression(operand) + result += tr.chunks + if (knownAddress != null) { + // @(address) = @(address) %= operand + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOADM, vmDt, reg1 = resultReg, value = knownAddress) + it += IRInstruction(Opcode.MODR, vmDt, reg1 = resultReg, reg2 = tr.resultReg) + it += IRInstruction(Opcode.STOREM, vmDt, reg1 = resultReg, value = knownAddress) + } + } else { + // symbol = symbol %= operand + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOADM, vmDt, reg1 = resultReg, labelSymbol = symbol) + it += IRInstruction(Opcode.MODR, vmDt, reg1 = resultReg, reg2 = tr.resultReg) + it += IRInstruction(Opcode.STOREM, vmDt, reg1 = resultReg, labelSymbol = symbol) + } + } + } + return result + } + + 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=tr.resultReg, reg2=valueReg) + it += IRInstruction(Opcode.STOREM, vmDt, reg1=tr.resultReg, value=knownAddress) + } + } 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=tr.resultReg, reg2=valueReg) + it += IRInstruction(Opcode.STOREM, vmDt, reg1=tr.resultReg, labelSymbol = symbol) + } + } + 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=tr.resultReg, reg2=valueReg) + it += IRInstruction(Opcode.STOREM, vmDt, reg1=tr.resultReg, value=knownAddress) + } + } 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=tr.resultReg, reg2=valueReg) + it += IRInstruction(Opcode.STOREM, vmDt, reg1=tr.resultReg, labelSymbol = symbol) + } + } + 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=tr.resultReg, reg2=valueReg) + it += IRInstruction(Opcode.STOREM, vmDt, reg1=tr.resultReg, value=knownAddress) + } + } 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=tr.resultReg, reg2=valueReg) + it += IRInstruction(Opcode.STOREM, vmDt, reg1=tr.resultReg, labelSymbol = symbol) + } + } + 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=tr.resultReg, reg2=valueReg) + it += IRInstruction(Opcode.STOREM, vmDt, reg1=tr.resultReg, value=knownAddress) + } + } 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=tr.resultReg, reg2=valueReg) + it += IRInstruction(Opcode.STOREM, vmDt, reg1=tr.resultReg, labelSymbol = symbol) + } + } + return result + } + + fun operatorGreaterEqualInplace(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.SGES else Opcode.SGE + 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=tr.resultReg, reg2=valueReg) + it += IRInstruction(Opcode.STOREM, vmDt, reg1=tr.resultReg, value=knownAddress) + } + } 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=tr.resultReg, reg2=valueReg) + it += IRInstruction(Opcode.STOREM, vmDt, reg1=tr.resultReg, labelSymbol = symbol) + } + } + return result + } + + fun operatorLessEqualInplace(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.SLES else Opcode.SLE + 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=tr.resultReg, reg2=valueReg) + it += IRInstruction(Opcode.STOREM, vmDt, reg1=tr.resultReg, value=knownAddress) + } + } 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=tr.resultReg, reg2=valueReg) + it += IRInstruction(Opcode.STOREM, vmDt, reg1=tr.resultReg, labelSymbol = symbol) + } + } + return result + } } diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt index fa1ccf7db..3a43bcee2 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt @@ -912,67 +912,83 @@ class IRCodeGen( } } else -> { - throw AssemblyError("weird condition node: $condition") + // if X --> meaning: if X!=0 + require(options.useNewExprCode) + val irDt = irType(condition.type) + val signed = condition.type in SignedDatatypes + return if(goto!=null && ifElse.elseScope.children.isEmpty()) { + translateIfFollowedByJustGoto(ifElse, goto, irDt, signed) + } else { + translateIfElseNonZeroComparison(ifElse, irDt, signed) + } } } } private fun translateIfFollowedByJustGoto(ifElse: PtIfElse, goto: PtJump, irDtLeft: IRDataType, signed: Boolean): MutableList { - val condition = ifElse.condition as PtBinaryExpression + val conditionBinExpr = ifElse.condition as? PtBinaryExpression val result = mutableListOf() - if (irDtLeft == IRDataType.FLOAT) { - val leftTr = expressionEval.translateExpression(condition.left) - addToResult(result, leftTr, -1, leftTr.resultFpReg) - val rightTr = expressionEval.translateExpression(condition.right) - addToResult(result, rightTr, -1, rightTr.resultFpReg) - result += IRCodeChunk(null, null).also { - val compResultReg = registers.nextFree() - it += IRInstruction( - Opcode.FCOMP, - IRDataType.FLOAT, - reg1 = compResultReg, - fpReg1 = leftTr.resultFpReg, - fpReg2 = rightTr.resultFpReg - ) - val gotoOpcode = when (condition.operator) { - "==" -> Opcode.BZ - "!=" -> Opcode.BNZ - "<" -> Opcode.BLEZS - ">" -> Opcode.BGEZS - "<=" -> Opcode.BLZS - ">=" -> Opcode.BGZS - else -> throw AssemblyError("weird operator") - } - it += if (goto.address != null) - IRInstruction( - gotoOpcode, - IRDataType.BYTE, - reg1 = compResultReg, - value = goto.address?.toInt() - ) - else if (goto.generatedLabel != null) - IRInstruction( - gotoOpcode, - IRDataType.BYTE, - reg1 = compResultReg, - labelSymbol = goto.generatedLabel - ) - else - IRInstruction( - gotoOpcode, - IRDataType.BYTE, - reg1 = compResultReg, - labelSymbol = goto.identifier!!.name - ) - } + if(conditionBinExpr==null) { + if(irDtLeft==IRDataType.FLOAT) + throw AssemblyError("condition value should not be float") + ifNonZeroIntThenJump(result, ifElse, signed, irDtLeft, goto) return result } else { - val rightConst = condition.right.asConstInteger() - return if (rightConst == 0) - ifZeroIntThenJump(result, ifElse, signed, irDtLeft, goto) - else { - ifNonZeroIntThenJump(result, ifElse, signed, irDtLeft, goto) + if (irDtLeft == IRDataType.FLOAT) { + val leftTr = expressionEval.translateExpression(conditionBinExpr.left) + addToResult(result, leftTr, -1, leftTr.resultFpReg) + val rightTr = expressionEval.translateExpression(conditionBinExpr.right) + addToResult(result, rightTr, -1, rightTr.resultFpReg) + result += IRCodeChunk(null, null).also { + val compResultReg = registers.nextFree() + it += IRInstruction( + Opcode.FCOMP, + IRDataType.FLOAT, + reg1 = compResultReg, + fpReg1 = leftTr.resultFpReg, + fpReg2 = rightTr.resultFpReg + ) + val gotoOpcode = when (conditionBinExpr.operator) { + "==" -> Opcode.BZ + "!=" -> Opcode.BNZ + "<" -> Opcode.BLEZS + ">" -> Opcode.BGEZS + "<=" -> Opcode.BLZS + ">=" -> Opcode.BGZS + else -> throw AssemblyError("weird operator") + } + it += if (goto.address != null) + IRInstruction( + gotoOpcode, + IRDataType.BYTE, + reg1 = compResultReg, + value = goto.address?.toInt() + ) + else if (goto.generatedLabel != null) + IRInstruction( + gotoOpcode, + IRDataType.BYTE, + reg1 = compResultReg, + labelSymbol = goto.generatedLabel + ) + else + IRInstruction( + gotoOpcode, + IRDataType.BYTE, + reg1 = compResultReg, + labelSymbol = goto.identifier!!.name + ) + } + return result + } else { + val rightConst = conditionBinExpr.right.asConstInteger() + if (rightConst == 0) + ifZeroIntThenJump(result, ifElse, signed, irDtLeft, goto) + else { + ifNonZeroIntThenJump(result, ifElse, signed, irDtLeft, goto) + } + return result } } } @@ -983,7 +999,7 @@ class IRCodeGen( signed: Boolean, irDtLeft: IRDataType, goto: PtJump - ): MutableList { + ) { val condition = ifElse.condition as PtBinaryExpression val leftTr = expressionEval.translateExpression(condition.left) addToResult(result, leftTr, leftTr.resultReg, -1) @@ -1002,7 +1018,6 @@ class IRCodeGen( addInstr(result, IRInstruction(opcode, irDtLeft, reg1 = leftTr.resultReg, labelSymbol = goto.generatedLabel), null) else addInstr(result, IRInstruction(opcode, irDtLeft, reg1 = leftTr.resultReg, labelSymbol = goto.identifier!!.name), null) - return result } private fun ifNonZeroIntThenJump( @@ -1011,57 +1026,67 @@ class IRCodeGen( signed: Boolean, irDtLeft: IRDataType, goto: PtJump - ): MutableList { - val condition = ifElse.condition as PtBinaryExpression - val leftTr = expressionEval.translateExpression(condition.left) - addToResult(result, leftTr, leftTr.resultReg, -1) - val rightTr = expressionEval.translateExpression(condition.right) - addToResult(result, rightTr, rightTr.resultReg, -1) - val opcode: Opcode - val firstReg: Int - val secondReg: Int - when (condition.operator) { - "==" -> { - opcode = Opcode.BEQ - firstReg = leftTr.resultReg - secondReg = rightTr.resultReg + ) { + val conditionBinExpr = ifElse.condition as? PtBinaryExpression + if(conditionBinExpr==null) { + val tr = expressionEval.translateExpression(ifElse.condition) + result += tr.chunks + if (goto.address != null) + addInstr(result, IRInstruction(Opcode.BNZ, irDtLeft, reg1 = tr.resultReg, value = goto.address?.toInt()), null) + else if (goto.generatedLabel != null) + addInstr(result, IRInstruction(Opcode.BNZ, irDtLeft, reg1 = tr.resultReg, labelSymbol = goto.generatedLabel), null) + else + addInstr(result, IRInstruction(Opcode.BNZ, irDtLeft, reg1 = tr.resultReg, labelSymbol = goto.identifier!!.name), null) + } else { + val leftTr = expressionEval.translateExpression(conditionBinExpr.left) + addToResult(result, leftTr, leftTr.resultReg, -1) + val rightTr = expressionEval.translateExpression(conditionBinExpr.right) + addToResult(result, rightTr, rightTr.resultReg, -1) + val opcode: Opcode + val firstReg: Int + val secondReg: Int + when (conditionBinExpr.operator) { + "==" -> { + opcode = Opcode.BEQ + firstReg = leftTr.resultReg + secondReg = rightTr.resultReg + } + "!=" -> { + opcode = Opcode.BNE + firstReg = leftTr.resultReg + secondReg = rightTr.resultReg + } + "<" -> { + // swapped '>' + opcode = if (signed) Opcode.BGTS else Opcode.BGT + firstReg = rightTr.resultReg + secondReg = leftTr.resultReg + } + ">" -> { + opcode = if (signed) Opcode.BGTS else Opcode.BGT + firstReg = leftTr.resultReg + secondReg = rightTr.resultReg + } + "<=" -> { + // swapped '>=' + opcode = if (signed) Opcode.BGES else Opcode.BGE + firstReg = rightTr.resultReg + secondReg = leftTr.resultReg + } + ">=" -> { + opcode = if (signed) Opcode.BGES else Opcode.BGE + firstReg = leftTr.resultReg + secondReg = rightTr.resultReg + } + else -> throw AssemblyError("invalid comparison operator") } - "!=" -> { - opcode = Opcode.BNE - firstReg = leftTr.resultReg - secondReg = rightTr.resultReg - } - "<" -> { - // swapped '>' - opcode = if (signed) Opcode.BGTS else Opcode.BGT - firstReg = rightTr.resultReg - secondReg = leftTr.resultReg - } - ">" -> { - opcode = if (signed) Opcode.BGTS else Opcode.BGT - firstReg = leftTr.resultReg - secondReg = rightTr.resultReg - } - "<=" -> { - // swapped '>=' - opcode = if (signed) Opcode.BGES else Opcode.BGE - firstReg = rightTr.resultReg - secondReg = leftTr.resultReg - } - ">=" -> { - opcode = if (signed) Opcode.BGES else Opcode.BGE - firstReg = leftTr.resultReg - secondReg = rightTr.resultReg - } - else -> throw AssemblyError("invalid comparison operator") + if (goto.address != null) + addInstr(result, IRInstruction(opcode, irDtLeft, reg1 = firstReg, reg2 = secondReg, value = goto.address?.toInt()), null) + else if (goto.generatedLabel != null) + addInstr(result, IRInstruction(opcode, irDtLeft, reg1 = firstReg, reg2 = secondReg, labelSymbol = goto.generatedLabel), null) + else + addInstr(result, IRInstruction(opcode, irDtLeft, reg1 = firstReg, reg2 = secondReg, labelSymbol = goto.identifier!!.name), null) } - if (goto.address != null) - addInstr(result, IRInstruction(opcode, irDtLeft, reg1 = firstReg, reg2 = secondReg, value = goto.address?.toInt()), null) - else if (goto.generatedLabel != null) - addInstr(result, IRInstruction(opcode, irDtLeft, reg1 = firstReg, reg2 = secondReg, labelSymbol = goto.generatedLabel), null) - else - addInstr(result, IRInstruction(opcode, irDtLeft, reg1 = firstReg, reg2 = secondReg, labelSymbol = goto.identifier!!.name), null) - return result } private fun translateIfElseZeroComparison(ifElse: PtIfElse, irDtLeft: IRDataType, signed: Boolean): IRCodeChunks { @@ -1131,106 +1156,160 @@ class IRCodeGen( val elseBranchFirstReg: Int val elseBranchSecondReg: Int val branchDt: IRDataType - val condition = ifElse.condition as PtBinaryExpression - if(irDtLeft==IRDataType.FLOAT) { - val leftTr = expressionEval.translateExpression(condition.left) - addToResult(result, leftTr, -1, leftTr.resultFpReg) - val rightTr = expressionEval.translateExpression(condition.right) - addToResult(result, rightTr, -1, rightTr.resultFpReg) - val compResultReg = registers.nextFree() - addInstr(result, IRInstruction(Opcode.FCOMP, IRDataType.FLOAT, reg1=compResultReg, fpReg1 = leftTr.resultFpReg, fpReg2 = rightTr.resultFpReg), null) - val elseBranch = when (condition.operator) { - "==" -> Opcode.BNZ - "!=" -> Opcode.BZ - "<" -> Opcode.BGEZS - ">" -> Opcode.BLEZS - "<=" -> Opcode.BGZS - ">=" -> Opcode.BLZS - else -> throw AssemblyError("weird operator") - } + val condition = ifElse.condition as? PtBinaryExpression + if(condition==null) { + 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()) { - // if and else parts val elseLabel = createLabelName() val afterIfLabel = createLabelName() - addInstr(result, IRInstruction(elseBranch, IRDataType.BYTE, reg1=compResultReg, labelSymbol = elseLabel), null) + addInstr(result, IRInstruction(Opcode.BZ, irDtLeft, reg1=tr.resultReg, labelSymbol = elseLabel), null) result += translateNode(ifElse.ifScope) addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = afterIfLabel), null) result += labelFirstChunk(translateNode(ifElse.elseScope), elseLabel) result += IRCodeChunk(afterIfLabel, null) } else { - // only if part val afterIfLabel = createLabelName() - addInstr(result, IRInstruction(elseBranch, IRDataType.BYTE, reg1=compResultReg, labelSymbol = afterIfLabel), null) + addInstr(result, IRInstruction(Opcode.BZ, irDtLeft, reg1=tr.resultReg, labelSymbol = afterIfLabel), null) result += translateNode(ifElse.ifScope) result += IRCodeChunk(afterIfLabel, null) } + return result } else { - // integer comparisons - branchDt = irDtLeft - val leftTr = expressionEval.translateExpression(condition.left) - addToResult(result, leftTr, leftTr.resultReg, -1) - val rightTr = expressionEval.translateExpression(condition.right) - addToResult(result, rightTr, rightTr.resultReg, -1) - when (condition.operator) { - "==" -> { - elseBranchOpcode = Opcode.BNE - elseBranchFirstReg = leftTr.resultReg - elseBranchSecondReg = rightTr.resultReg + if (irDtLeft == IRDataType.FLOAT) { + val leftTr = expressionEval.translateExpression(condition.left) + addToResult(result, leftTr, -1, leftTr.resultFpReg) + val rightTr = expressionEval.translateExpression(condition.right) + addToResult(result, rightTr, -1, rightTr.resultFpReg) + val compResultReg = registers.nextFree() + addInstr( + result, + IRInstruction( + Opcode.FCOMP, + IRDataType.FLOAT, + reg1 = compResultReg, + fpReg1 = leftTr.resultFpReg, + fpReg2 = rightTr.resultFpReg + ), + null + ) + val elseBranch = when (condition.operator) { + "==" -> Opcode.BNZ + "!=" -> Opcode.BZ + "<" -> Opcode.BGEZS + ">" -> Opcode.BLEZS + "<=" -> Opcode.BGZS + ">=" -> Opcode.BLZS + else -> throw AssemblyError("weird operator") } - "!=" -> { - elseBranchOpcode = Opcode.BEQ - elseBranchFirstReg = leftTr.resultReg - elseBranchSecondReg = rightTr.resultReg + if (ifElse.elseScope.children.isNotEmpty()) { + // if and else parts + val elseLabel = createLabelName() + val afterIfLabel = createLabelName() + addInstr( + result, + IRInstruction(elseBranch, IRDataType.BYTE, reg1 = compResultReg, labelSymbol = elseLabel), + null + ) + result += translateNode(ifElse.ifScope) + addInstr(result, IRInstruction(Opcode.JUMP, labelSymbol = afterIfLabel), null) + result += labelFirstChunk(translateNode(ifElse.elseScope), elseLabel) + result += IRCodeChunk(afterIfLabel, null) + } else { + // only if part + val afterIfLabel = createLabelName() + addInstr( + result, + IRInstruction(elseBranch, IRDataType.BYTE, reg1 = compResultReg, labelSymbol = afterIfLabel), + null + ) + result += translateNode(ifElse.ifScope) + result += IRCodeChunk(afterIfLabel, null) } - "<" -> { - // else part when left >= right - elseBranchOpcode = if (signed) Opcode.BGES else Opcode.BGE - elseBranchFirstReg = leftTr.resultReg - elseBranchSecondReg = rightTr.resultReg - } - ">" -> { - // else part when left <= right --> right >= left - elseBranchOpcode = if (signed) Opcode.BGES else Opcode.BGE - elseBranchFirstReg = rightTr.resultReg - elseBranchSecondReg = leftTr.resultReg - } - "<=" -> { - // else part when left > right - elseBranchOpcode = if (signed) Opcode.BGTS else Opcode.BGT - elseBranchFirstReg = leftTr.resultReg - elseBranchSecondReg = rightTr.resultReg - } - ">=" -> { - // else part when left < right --> right > left - elseBranchOpcode = if (signed) Opcode.BGTS else Opcode.BGT - elseBranchFirstReg = rightTr.resultReg - elseBranchSecondReg = leftTr.resultReg - } - else -> throw AssemblyError("invalid comparison operator") - } - if(ifElse.elseScope.children.isNotEmpty()) { - // if and else parts - val elseLabel = createLabelName() - val afterIfLabel = createLabelName() - addInstr(result, IRInstruction(elseBranchOpcode, branchDt, - 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) - result += IRCodeChunk(afterIfLabel, null) } else { - // only if part - val afterIfLabel = createLabelName() - addInstr(result, IRInstruction(elseBranchOpcode, branchDt, - reg1=elseBranchFirstReg, reg2=elseBranchSecondReg, - labelSymbol = afterIfLabel), null) - result += translateNode(ifElse.ifScope) - result += IRCodeChunk(afterIfLabel, null) - } - } + // integer comparisons + branchDt = irDtLeft + val leftTr = expressionEval.translateExpression(condition.left) + addToResult(result, leftTr, leftTr.resultReg, -1) + val rightTr = expressionEval.translateExpression(condition.right) + addToResult(result, rightTr, rightTr.resultReg, -1) + when (condition.operator) { + "==" -> { + elseBranchOpcode = Opcode.BNE + elseBranchFirstReg = leftTr.resultReg + elseBranchSecondReg = rightTr.resultReg + } - return result + "!=" -> { + elseBranchOpcode = Opcode.BEQ + elseBranchFirstReg = leftTr.resultReg + elseBranchSecondReg = rightTr.resultReg + } + + "<" -> { + // else part when left >= right + elseBranchOpcode = if (signed) Opcode.BGES else Opcode.BGE + elseBranchFirstReg = leftTr.resultReg + elseBranchSecondReg = rightTr.resultReg + } + + ">" -> { + // else part when left <= right --> right >= left + elseBranchOpcode = if (signed) Opcode.BGES else Opcode.BGE + elseBranchFirstReg = rightTr.resultReg + elseBranchSecondReg = leftTr.resultReg + } + + "<=" -> { + // else part when left > right + elseBranchOpcode = if (signed) Opcode.BGTS else Opcode.BGT + elseBranchFirstReg = leftTr.resultReg + elseBranchSecondReg = rightTr.resultReg + } + + ">=" -> { + // else part when left < right --> right > left + elseBranchOpcode = if (signed) Opcode.BGTS else Opcode.BGT + elseBranchFirstReg = rightTr.resultReg + elseBranchSecondReg = leftTr.resultReg + } + + else -> throw AssemblyError("invalid comparison operator") + } + if (ifElse.elseScope.children.isNotEmpty()) { + // if and else parts + val elseLabel = createLabelName() + val afterIfLabel = createLabelName() + addInstr( + result, IRInstruction( + elseBranchOpcode, branchDt, + 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) + result += IRCodeChunk(afterIfLabel, null) + } else { + // only if part + val afterIfLabel = createLabelName() + addInstr( + result, IRInstruction( + elseBranchOpcode, branchDt, + reg1 = elseBranchFirstReg, reg2 = elseBranchSecondReg, + labelSymbol = afterIfLabel + ), null + ) + result += translateNode(ifElse.ifScope) + result += IRCodeChunk(afterIfLabel, null) + } + } + + return result + } } private fun translate(postIncrDecr: PtPostIncrDecr): IRCodeChunks { diff --git a/docs/source/todo.rst b/docs/source/todo.rst index fbaa1af74..0fcdb0a9f 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -4,6 +4,9 @@ TODO For next minor release ^^^^^^^^^^^^^^^^^^^^^^ + +newexpr: fix fallbackAssign() and loadIndexReg() + ... diff --git a/examples/test.p8 b/examples/test.p8 index 090f349c1..b45598e56 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,9 +1,16 @@ %import textio +%import floats %zeropage basicsafe main { sub start() { + ubyte xx=100 + ubyte yy=21 + + xx %= yy + txt.print_ub(xx) + txt.nl() ubyte ub1 = 100 ubyte ub2 = 13