From 06184bdcb1df1f0da77eb117d8a174eef64aaa04 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Mon, 27 Jun 2022 21:44:52 +0200 Subject: [PATCH] get rid of failed mccarthy shortcut evaluation --- .../astprocessing/StatementReorderer.kt | 140 ------------------ docs/source/syntaxreference.rst | 5 +- docs/source/todo.rst | 4 - examples/test.p8 | 2 +- 4 files changed, 3 insertions(+), 148 deletions(-) diff --git a/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt b/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt index a62341a15..e2a0be287 100644 --- a/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt +++ b/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt @@ -200,17 +200,6 @@ internal class StatementReorderer(val program: Program, && maySwapOperandOrder(expr)) return listOf(IAstModification.SwapOperands(expr)) - if (expr.operator == "and") { - val leftBinExpr = expr.left as? BinaryExpression - if (leftBinExpr?.operator == "and") - return mcCarthyAndExpression(expr, parent) - } - if (expr.operator == "or") { - val leftBinExpr = expr.left as? BinaryExpression - if (leftBinExpr?.operator == "or") - return mcCarthyOrExpression(expr, parent) - } - // when using a simple bit shift and assigning it to a variable of a different type, // try to make the bit shifting 'wide enough' to fall into the variable's type. // with this, for instance, uword x = 1 << 10 will result in 1024 rather than 0 (the ubyte result). @@ -332,17 +321,6 @@ internal class StatementReorderer(val program: Program, // rewrite in-place assignment expressions a bit so that the assignment target usually is the leftmost operand val binExpr = assignment.value as? BinaryExpression if(binExpr!=null) { - if (binExpr.operator == "and") { - val leftBinExpr = binExpr.left as? BinaryExpression - if (leftBinExpr?.operator == "and") - return mcCarthyAndAssignment(binExpr, assignment, parent) - } - if (binExpr.operator == "or") { - val leftBinExpr = binExpr.left as? BinaryExpression - if (leftBinExpr?.operator == "or") - return mcCarthyOrAssignment(binExpr, assignment, parent) - } - if(binExpr.left isSameAs assignment.target) { // A = A 5, unchanged return noModifications @@ -448,124 +426,6 @@ internal class StatementReorderer(val program: Program, checkUnusedReturnValues(functionCallStatement, function, errors) return tryReplaceCallWithGosub(functionCallStatement, parent, program, options) } - - private fun mcCarthyAndAssignment(andExpr: BinaryExpression, assignment: Assignment, assignmentParent: Node): Iterable { - val terms = findTerms(andExpr, "and") - if(terms.any { it.constValue(program)?.asBooleanValue == false }) { - errors.warn("expression is always false", andExpr.position) - return listOf(IAstModification.ReplaceNode(andExpr, NumericLiteral.fromBoolean(false, andExpr.position), assignment)) - } - - val replacement = doShortcutEvaluation( - assignment.target, - assignment.target.inferType(program).getOr(DataType.UNDEFINED), - terms, - "==", - false, - assignment.position - ) - return listOf(IAstModification.ReplaceNode(assignment, replacement, assignmentParent)) - } - - private fun mcCarthyOrAssignment(orExpr: BinaryExpression, assignment: Assignment, assignmentParent: Node): Iterable { - val terms = findTerms(orExpr, "or") - if(terms.any { it.constValue(program)?.asBooleanValue == true }) { - errors.warn("expression is always true", orExpr.position) - return listOf(IAstModification.ReplaceNode(orExpr, NumericLiteral.fromBoolean(true, orExpr.position), assignment)) - } - - val replacement = doShortcutEvaluation( - assignment.target, - assignment.target.inferType(program).getOr(DataType.UNDEFINED), - terms, - "!=", - false, - assignment.position - ) - return listOf(IAstModification.ReplaceNode(assignment, replacement, assignmentParent)) - } - - private fun mcCarthyAndExpression(expr: BinaryExpression, parent: Node): Iterable { - val terms = findTerms(expr, "and") - if(terms.any { it.constValue(program)?.asBooleanValue == false }) { - errors.warn("expression is always false", expr.position) - return listOf(IAstModification.ReplaceNode(expr, NumericLiteral.fromBoolean(false, expr.position), parent)) - } - - val (tempvarName, _) = program.getTempVar(DataType.UBYTE) - val assignTarget = AssignTarget(IdentifierReference(tempvarName, expr.position), null, null, position = expr.position) - val replacement = doShortcutEvaluation(assignTarget, DataType.UBYTE, terms, "==", true, expr.position) - val exprStmt = expr.containingStatement - return listOf( - IAstModification.InsertBefore(exprStmt, replacement, exprStmt.definingScope), - IAstModification.ReplaceNode(expr, assignTarget.identifier!!.copy(), parent) - ) - } - - private fun mcCarthyOrExpression(expr: BinaryExpression, parent: Node): Iterable { - val terms = findTerms(expr, "or") - if(terms.any { it.constValue(program)?.asBooleanValue == true }) { - errors.warn("expression is always true", expr.position) - return listOf(IAstModification.ReplaceNode(expr, NumericLiteral.fromBoolean(false, expr.position), parent)) - } - - val (tempvarName, _) = program.getTempVar(DataType.UBYTE) - val assignTarget = AssignTarget(IdentifierReference(tempvarName, expr.position), null, null, position = expr.position) - val replacement = doShortcutEvaluation(assignTarget, DataType.UBYTE, terms, "!=", true, expr.position) - val exprStmt = expr.containingStatement - return listOf( - IAstModification.InsertBefore(exprStmt, replacement, exprStmt.definingScope), - IAstModification.ReplaceNode(expr, assignTarget.identifier!!.copy(), parent) - ) - } - - private fun findTerms(expr: BinaryExpression, operator: String, terms: List = emptyList()): List { - if(expr.operator!=operator) - return listOf(expr) + terms - val leftBinExpr = expr.left as? BinaryExpression ?: return listOf(expr.left, expr.right) + terms - return findTerms(leftBinExpr, operator, listOf(expr.right)+terms) - } - - private fun doShortcutEvaluation( - target: AssignTarget, - targetDt: DataType, - terms: List, - checkZeroOperator: String, - convertToBool: Boolean, - position: Position - ): AnonymousScope { - val replacement = AnonymousScope(mutableListOf(), position) - val doneLabel = program.makeLabel("and", position) - for ((idx, term) in terms.withIndex()) { - val value: Expression = if (term is IFunctionCall - && term.target.nameInSource == listOf("boolean") - && term.args[0].inferType(program).isAssignableTo(targetDt) - ) - term.args[0].copy() - else - term.copy() - val assignTerm = Assignment(target.copy(), value, AssignmentOrigin.OPTIMIZER, position) - replacement.statements.add(assignTerm) - if (idx < terms.size - 1) { - val targetCheck = BinaryExpression(target.toExpression(), checkZeroOperator, - NumericLiteral(DataType.UBYTE, 0.0, position), position) - val jumpDone = program.jumpLabel(doneLabel) - val ifStmt = IfElse(targetCheck, - AnonymousScope(mutableListOf(jumpDone), position), - AnonymousScope(mutableListOf(), Position.DUMMY), - position) - replacement.statements.add(ifStmt) - } else if(idx==terms.size-1) { - if(convertToBool) { - assignTerm.value = BuiltinFunctionCall(IdentifierReference(listOf("boolean"), assignTerm.position), mutableListOf(value), assignTerm.position) - } - if(targetDt !in ByteDatatypes) - assignTerm.value = TypecastExpression(assignTerm.value, targetDt, true, assignTerm.position) - } - } - replacement.statements.add(doneLabel) - return replacement - } } diff --git a/docs/source/syntaxreference.rst b/docs/source/syntaxreference.rst index 0d7f72ea7..4280bd01a 100644 --- a/docs/source/syntaxreference.rst +++ b/docs/source/syntaxreference.rst @@ -489,9 +489,8 @@ logical: ``not`` ``and`` ``or`` ``xor`` .. note:: Unlike most other programming languages, there is no short-cirquit or McCarthy-evaluation - for the ``and`` and ``or`` operators at this time. This means that prog8 currently always evaluates - all operands from these logical expressions, even when one of them already determines the outcome. - This may be changed in a future language version. + for the logical ``and`` and ``or`` operators. This means that prog8 currently always evaluates + all operands from these logical expressions, even when one of them already determines the outcome! range creation: ``to`` Creates a range of values from the LHS value to the RHS value, inclusive. diff --git a/docs/source/todo.rst b/docs/source/todo.rst index e85f899a7..36bece277 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,10 +3,6 @@ TODO For next release ^^^^^^^^^^^^^^^^ -- add McCarthy evaluation to shortcircuit and/or expressions. Both conditional expressions and assignments! - StatementReorder.after(assignment). - TODO: boolean expressions. -- add unit tests for all 4 mcarthy shortcut cases. - can we optimize redundant calls to boolean() away? imageviewer.prg got larger because of them - add some more optimizations in vmPeepholeOptimizer - vm Instruction needs to know what the read-registers/memory are, and what the write-register/memory is. diff --git a/examples/test.p8 b/examples/test.p8 index 56e0d2b32..b020b4afa 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,7 +1,7 @@ %import textio %zeropage basicsafe -; NOTE: meant to test to virtual machine output target (use -target vitual) +; NOTE: meant to test to virtual machine output target (use -target virtual) main {