mirror of
https://github.com/irmen/prog8.git
synced 2024-09-10 09:54:32 +00:00
failed attempt at McCarthy shortcut evaluation
This commit is contained in:
parent
bb1cda0916
commit
af98d01053
@ -27,16 +27,11 @@ internal class CodeDesugarer(val program: Program,
|
|||||||
// - repeat-forever loops replaced by label+jump.
|
// - repeat-forever loops replaced by label+jump.
|
||||||
|
|
||||||
|
|
||||||
private fun jumpLabel(label: Label): Jump {
|
|
||||||
val ident = IdentifierReference(listOf(label.name), label.position)
|
|
||||||
return Jump(null, ident, null, label.position)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun before(breakStmt: Break, parent: Node): Iterable<IAstModification> {
|
override fun before(breakStmt: Break, parent: Node): Iterable<IAstModification> {
|
||||||
fun jumpAfter(stmt: Statement): Iterable<IAstModification> {
|
fun jumpAfter(stmt: Statement): Iterable<IAstModification> {
|
||||||
val label = program.makeLabel("after", breakStmt.position)
|
val label = program.makeLabel("after", breakStmt.position)
|
||||||
return listOf(
|
return listOf(
|
||||||
IAstModification.ReplaceNode(breakStmt, jumpLabel(label), parent),
|
IAstModification.ReplaceNode(breakStmt, program.jumpLabel(label), parent),
|
||||||
IAstModification.InsertAfter(stmt, label, stmt.parent as IStatementContainer)
|
IAstModification.InsertAfter(stmt, label, stmt.parent as IStatementContainer)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -73,7 +68,7 @@ if not CONDITION
|
|||||||
loopLabel,
|
loopLabel,
|
||||||
untilLoop.body,
|
untilLoop.body,
|
||||||
IfElse(notCondition,
|
IfElse(notCondition,
|
||||||
AnonymousScope(mutableListOf(jumpLabel(loopLabel)), pos),
|
AnonymousScope(mutableListOf(program.jumpLabel(loopLabel)), pos),
|
||||||
AnonymousScope(mutableListOf(), pos),
|
AnonymousScope(mutableListOf(), pos),
|
||||||
pos)
|
pos)
|
||||||
), pos)
|
), pos)
|
||||||
@ -97,11 +92,11 @@ _after:
|
|||||||
val replacement = AnonymousScope(mutableListOf(
|
val replacement = AnonymousScope(mutableListOf(
|
||||||
loopLabel,
|
loopLabel,
|
||||||
IfElse(notCondition,
|
IfElse(notCondition,
|
||||||
AnonymousScope(mutableListOf(jumpLabel(afterLabel)), pos),
|
AnonymousScope(mutableListOf(program.jumpLabel(afterLabel)), pos),
|
||||||
AnonymousScope(mutableListOf(), pos),
|
AnonymousScope(mutableListOf(), pos),
|
||||||
pos),
|
pos),
|
||||||
whileLoop.body,
|
whileLoop.body,
|
||||||
jumpLabel(loopLabel),
|
program.jumpLabel(loopLabel),
|
||||||
afterLabel
|
afterLabel
|
||||||
), pos)
|
), pos)
|
||||||
return listOf(IAstModification.ReplaceNode(whileLoop, replacement, parent))
|
return listOf(IAstModification.ReplaceNode(whileLoop, replacement, parent))
|
||||||
@ -131,7 +126,7 @@ _after:
|
|||||||
override fun after(repeatLoop: RepeatLoop, parent: Node): Iterable<IAstModification> {
|
override fun after(repeatLoop: RepeatLoop, parent: Node): Iterable<IAstModification> {
|
||||||
if(repeatLoop.iterations==null) {
|
if(repeatLoop.iterations==null) {
|
||||||
val label = program.makeLabel("repeat", repeatLoop.position)
|
val label = program.makeLabel("repeat", repeatLoop.position)
|
||||||
val jump = jumpLabel(label)
|
val jump = program.jumpLabel(label)
|
||||||
return listOf(
|
return listOf(
|
||||||
IAstModification.InsertFirst(label, repeatLoop.body),
|
IAstModification.InsertFirst(label, repeatLoop.body),
|
||||||
IAstModification.InsertLast(jump, repeatLoop.body),
|
IAstModification.InsertLast(jump, repeatLoop.body),
|
||||||
|
@ -200,6 +200,17 @@ internal class StatementReorderer(val program: Program,
|
|||||||
&& maySwapOperandOrder(expr))
|
&& maySwapOperandOrder(expr))
|
||||||
return listOf(IAstModification.SwapOperands(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,
|
// 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.
|
// 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).
|
// with this, for instance, uword x = 1 << 10 will result in 1024 rather than 0 (the ubyte result).
|
||||||
@ -279,6 +290,7 @@ internal class StatementReorderer(val program: Program,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return noModifications
|
return noModifications
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,16 +332,16 @@ internal class StatementReorderer(val program: Program,
|
|||||||
// rewrite in-place assignment expressions a bit so that the assignment target usually is the leftmost operand
|
// rewrite in-place assignment expressions a bit so that the assignment target usually is the leftmost operand
|
||||||
val binExpr = assignment.value as? BinaryExpression
|
val binExpr = assignment.value as? BinaryExpression
|
||||||
if(binExpr!=null) {
|
if(binExpr!=null) {
|
||||||
// if (binExpr.operator == "and") {
|
if (binExpr.operator == "and") {
|
||||||
// val leftBinExpr = binExpr.left as? BinaryExpression
|
val leftBinExpr = binExpr.left as? BinaryExpression
|
||||||
// if (leftBinExpr?.operator == "and")
|
if (leftBinExpr?.operator == "and")
|
||||||
// return mcCarthyAndAssignment(binExpr, assignment, parent)
|
return mcCarthyAndAssignment(binExpr, assignment, parent)
|
||||||
// }
|
}
|
||||||
// if (binExpr.operator == "or") {
|
if (binExpr.operator == "or") {
|
||||||
// val leftBinExpr = binExpr.left as? BinaryExpression
|
val leftBinExpr = binExpr.left as? BinaryExpression
|
||||||
// if (leftBinExpr?.operator == "or")
|
if (leftBinExpr?.operator == "or")
|
||||||
// return mcCarthyOrAssignment(binExpr, assignment, parent)
|
return mcCarthyOrAssignment(binExpr, assignment, parent)
|
||||||
// }
|
}
|
||||||
|
|
||||||
if(binExpr.left isSameAs assignment.target) {
|
if(binExpr.left isSameAs assignment.target) {
|
||||||
// A = A <operator> 5, unchanged
|
// A = A <operator> 5, unchanged
|
||||||
@ -438,35 +450,73 @@ internal class StatementReorderer(val program: Program,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun mcCarthyAndAssignment(andExpr: BinaryExpression, assignment: Assignment, assignmentParent: Node): Iterable<IAstModification> {
|
private fun mcCarthyAndAssignment(andExpr: BinaryExpression, assignment: Assignment, assignmentParent: Node): Iterable<IAstModification> {
|
||||||
val andTerms = findTerms(andExpr, "and")
|
val terms = findTerms(andExpr, "and")
|
||||||
if(andTerms.any { it.constValue(program)?.asBooleanValue == false }) {
|
if(terms.any { it.constValue(program)?.asBooleanValue == false }) {
|
||||||
errors.warn("expression is always false", andExpr.position)
|
errors.warn("expression is always false", andExpr.position)
|
||||||
return listOf(IAstModification.ReplaceNode(andExpr, NumericLiteral.fromBoolean(false, andExpr.position), assignment))
|
return listOf(IAstModification.ReplaceNode(andExpr, NumericLiteral.fromBoolean(false, andExpr.position), assignment))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO:
|
val replacement = doShortcutEvaluation(
|
||||||
// repeat for all terms:
|
assignment.target,
|
||||||
// assign term to target
|
assignment.target.inferType(program).getOr(DataType.UNDEFINED),
|
||||||
// add if: if target==0: goto done
|
terms,
|
||||||
// done:.
|
"==",
|
||||||
|
false,
|
||||||
return noModifications
|
assignment.position
|
||||||
|
)
|
||||||
|
return listOf(IAstModification.ReplaceNode(assignment, replacement, assignmentParent))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun mcCarthyOrAssignment(orExpr: BinaryExpression, assignment: Assignment, assignmentParent: Node): Iterable<IAstModification> {
|
private fun mcCarthyOrAssignment(orExpr: BinaryExpression, assignment: Assignment, assignmentParent: Node): Iterable<IAstModification> {
|
||||||
val andTerms = findTerms(orExpr, "or")
|
val terms = findTerms(orExpr, "or")
|
||||||
if(andTerms.any { it.constValue(program)?.asBooleanValue == true }) {
|
if(terms.any { it.constValue(program)?.asBooleanValue == true }) {
|
||||||
errors.warn("expression is always true", orExpr.position)
|
errors.warn("expression is always true", orExpr.position)
|
||||||
return listOf(IAstModification.ReplaceNode(orExpr, NumericLiteral.fromBoolean(true, orExpr.position), assignment))
|
return listOf(IAstModification.ReplaceNode(orExpr, NumericLiteral.fromBoolean(true, orExpr.position), assignment))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO:
|
val replacement = doShortcutEvaluation(
|
||||||
// repeat for all terms:
|
assignment.target,
|
||||||
// assign term to target
|
assignment.target.inferType(program).getOr(DataType.UNDEFINED),
|
||||||
// add if: if target!=0: goto done
|
terms,
|
||||||
// done:.
|
"!=",
|
||||||
|
false,
|
||||||
|
assignment.position
|
||||||
|
)
|
||||||
|
return listOf(IAstModification.ReplaceNode(assignment, replacement, assignmentParent))
|
||||||
|
}
|
||||||
|
|
||||||
return noModifications
|
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> {
|
private fun findTerms(expr: BinaryExpression, operator: String, terms: List<Expression> = emptyList()): List<Expression> {
|
||||||
@ -476,15 +526,45 @@ internal class StatementReorderer(val program: Program,
|
|||||||
return findTerms(leftBinExpr, operator, listOf(expr.right)+terms)
|
return findTerms(leftBinExpr, operator, listOf(expr.right)+terms)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun mcCarthyAndExpression(e1: Expression, e2: Expression, e3: Expression, origAndExpression: BinaryExpression, parent: Node): Iterable<IAstModification> {
|
private fun doShortcutEvaluation(
|
||||||
// TODO
|
target: AssignTarget,
|
||||||
println("AND EXPRESSION:")
|
targetDt: DataType,
|
||||||
println(" $e1")
|
terms: List<Expression>,
|
||||||
println(" $e2")
|
checkZeroOperator: String,
|
||||||
println(" $e3")
|
convertToBool: Boolean,
|
||||||
println(" (orig) $origAndExpression")
|
position: Position
|
||||||
val replacement = NumericLiteral.fromBoolean(false, origAndExpression.position)
|
): AnonymousScope {
|
||||||
return listOf(IAstModification.ReplaceNode(origAndExpression, replacement, parent))
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,6 +155,10 @@ class Program(val name: String,
|
|||||||
return Label(strLabel, position)
|
return Label(strLabel, position)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun jumpLabel(label: Label): Jump {
|
||||||
|
val ident = IdentifierReference(listOf(label.name), label.position)
|
||||||
|
return Jump(null, ident, null, label.position)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,6 +5,9 @@ For next release
|
|||||||
^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^
|
||||||
- add McCarthy evaluation to shortcircuit and/or expressions. Both conditional expressions and assignments!
|
- add McCarthy evaluation to shortcircuit and/or expressions. Both conditional expressions and assignments!
|
||||||
StatementReorder.after(assignment).
|
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
|
- add some more optimizations in vmPeepholeOptimizer
|
||||||
- vm Instruction needs to know what the read-registers/memory are, and what the write-register/memory is.
|
- vm Instruction needs to know what the read-registers/memory are, and what the write-register/memory is.
|
||||||
this info is needed for more advanced optimizations and later code generation steps.
|
this info is needed for more advanced optimizations and later code generation steps.
|
||||||
|
@ -11,7 +11,7 @@ main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub funcFalseWord() -> uword {
|
sub funcFalseWord() -> uword {
|
||||||
txt.print("falseWord() ")
|
txt.print("falseword() ")
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,15 +55,15 @@ main {
|
|||||||
ubyte ub4 = 44
|
ubyte ub4 = 44
|
||||||
ubyte ub5 = 55
|
ubyte ub5 = 55
|
||||||
|
|
||||||
ub4 = 42
|
ub4 = 0
|
||||||
txt.print("and with bytes: ")
|
txt.print("and with bytes: ")
|
||||||
ub5 = ub1 and ub2 and ub3 and ub4 and ub5 ; TODO FIX !! should be True (!=0)
|
ub5 = ub1 and ub2 and ub3 and ub4 and ub5
|
||||||
txt.print_ub(ub5)
|
txt.print_ub(ub5)
|
||||||
txt.nl()
|
txt.nl()
|
||||||
|
|
||||||
ub4 = 42
|
ub4 = 0
|
||||||
txt.print("or with bytes: ")
|
txt.print("or with bytes: ")
|
||||||
ub5 = ub1 or ub2 or ub3 or ub4 or ub5 ; TODO FIX!! should be False (0)
|
ub5 = ub1 or ub2 or ub3 or ub4 or ub5
|
||||||
txt.print_ub(ub5)
|
txt.print_ub(ub5)
|
||||||
txt.nl()
|
txt.nl()
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ main {
|
|||||||
txt.nl()
|
txt.nl()
|
||||||
|
|
||||||
txt.print("and with false: ")
|
txt.print("and with false: ")
|
||||||
value = func1(25) and func2(25) and funcFalse() and false and func3(25) and func4(25)
|
value = func1(25) and func2(25) and funcFalse() and func3(25) and func4(25)
|
||||||
txt.print_ub(value)
|
txt.print_ub(value)
|
||||||
txt.nl()
|
txt.nl()
|
||||||
txt.print("and with true: ")
|
txt.print("and with true: ")
|
||||||
@ -94,11 +94,11 @@ main {
|
|||||||
txt.print_ub(value)
|
txt.print_ub(value)
|
||||||
txt.nl()
|
txt.nl()
|
||||||
txt.print("or with false: ")
|
txt.print("or with false: ")
|
||||||
value = func1(25) or func2(25) or funcFalse() or true or func3(25) or func4(25)
|
value = func1(0) or func2(0) or funcFalse() or func3(25) or func4(25)
|
||||||
txt.print_ub(value)
|
txt.print_ub(value)
|
||||||
txt.nl()
|
txt.nl()
|
||||||
txt.print("or with true: ")
|
txt.print("or with true: ")
|
||||||
value = func1(25) or func2(25) or funcTrue() or func3(25) or func4(25)
|
value = func1(0) or func2(0) or funcTrue() or func3(25) or func4(25)
|
||||||
txt.print_ub(value)
|
txt.print_ub(value)
|
||||||
txt.nl()
|
txt.nl()
|
||||||
txt.print("xor with false: ")
|
txt.print("xor with false: ")
|
||||||
@ -110,6 +110,25 @@ main {
|
|||||||
txt.print_ub(value)
|
txt.print_ub(value)
|
||||||
txt.nl()
|
txt.nl()
|
||||||
|
|
||||||
|
txt.print("\nif and with false: [nothing]: ")
|
||||||
|
if func1(25) and func2(25) and funcFalse() and func3(25) and func4(25)
|
||||||
|
txt.print("failure!")
|
||||||
|
txt.print("\nif and with true: [ok]: ")
|
||||||
|
if func1(25) and func2(25) and funcTrue() and func3(25) and func4(25)
|
||||||
|
txt.print("ok!")
|
||||||
|
txt.print("\nif or with false: [ok]: ")
|
||||||
|
if func1(0) or func2(0) or funcFalse() or func3(25) or func4(25)
|
||||||
|
txt.print("ok!")
|
||||||
|
txt.print("\nif or with true: [ok]: ")
|
||||||
|
if func1(0) or func2(0) or funcTrue() or func3(25) or func4(25)
|
||||||
|
txt.print("ok!")
|
||||||
|
txt.print("\nif xor with false: [nothing]: ")
|
||||||
|
if func1(25) xor func2(25) xor funcFalse() xor func3(25) xor func4(25)
|
||||||
|
txt.print("failure!")
|
||||||
|
txt.print("\nif xor with true: [ok]: ")
|
||||||
|
if func1(25) xor func2(25) xor funcTrue() xor func3(25) xor func4(25)
|
||||||
|
txt.print("ok!")
|
||||||
|
txt.nl()
|
||||||
|
|
||||||
; a "pixelshader":
|
; a "pixelshader":
|
||||||
; sys.gfx_enable(0) ; enable lo res screen
|
; sys.gfx_enable(0) ; enable lo res screen
|
||||||
|
Loading…
Reference in New Issue
Block a user