mirror of
https://github.com/irmen/prog8.git
synced 2025-02-16 22:30:46 +00:00
get rid of failed mccarthy shortcut evaluation
This commit is contained in:
parent
af98d01053
commit
06184bdcb1
@ -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 <operator> 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<IAstModification> {
|
||||
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<IAstModification> {
|
||||
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<IAstModification> {
|
||||
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<IAstModification> {
|
||||
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<Expression> = emptyList()): List<Expression> {
|
||||
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<Expression>,
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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 {
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user