added Absorption laws optimization

This commit is contained in:
Irmen de Jong 2024-01-05 00:26:56 +01:00
parent 8a0e650511
commit 37638e7ed0
3 changed files with 165 additions and 18 deletions

View File

@ -97,6 +97,10 @@ class ExpressionSimplifier(private val program: Program,
} }
override fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> { override fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> {
val newExpr = applyAbsorptionLaws(expr)
if(newExpr!=null)
return listOf(IAstModification.ReplaceNode(expr, newExpr, parent))
val leftVal = expr.left.constValue(program) val leftVal = expr.left.constValue(program)
val rightVal = expr.right.constValue(program) val rightVal = expr.right.constValue(program)
@ -158,8 +162,8 @@ class ExpressionSimplifier(private val program: Program,
val y = determineY(x, leftBinExpr) val y = determineY(x, leftBinExpr)
if (y != null) { if (y != null) {
val yPlus1 = BinaryExpression(y, "+", NumericLiteral(leftDt, 1.0, y.position), y.position) val yPlus1 = BinaryExpression(y, "+", NumericLiteral(leftDt, 1.0, y.position), y.position)
val newExpr = BinaryExpression(x, "*", yPlus1, x.position) val replacement = BinaryExpression(x, "*", yPlus1, x.position)
return listOf(IAstModification.ReplaceNode(expr, newExpr, parent)) return listOf(IAstModification.ReplaceNode(expr, replacement, parent))
} }
} else { } else {
// Y*X - X -> X*(Y - 1) // Y*X - X -> X*(Y - 1)
@ -168,8 +172,8 @@ class ExpressionSimplifier(private val program: Program,
val y = determineY(x, leftBinExpr) val y = determineY(x, leftBinExpr)
if (y != null) { if (y != null) {
val yMinus1 = BinaryExpression(y, "-", NumericLiteral(leftDt, 1.0, y.position), y.position) val yMinus1 = BinaryExpression(y, "-", NumericLiteral(leftDt, 1.0, y.position), y.position)
val newExpr = BinaryExpression(x, "*", yMinus1, x.position) val replacement = BinaryExpression(x, "*", yMinus1, x.position)
return listOf(IAstModification.ReplaceNode(expr, newExpr, parent)) return listOf(IAstModification.ReplaceNode(expr, replacement, parent))
} }
} }
} else if (rightBinExpr?.operator == "*") { } else if (rightBinExpr?.operator == "*") {
@ -180,8 +184,8 @@ class ExpressionSimplifier(private val program: Program,
val y = determineY(x, rightBinExpr) val y = determineY(x, rightBinExpr)
if (y != null) { if (y != null) {
val yPlus1 = BinaryExpression(y, "+", NumericLiteral.optimalInteger(1, y.position), y.position) val yPlus1 = BinaryExpression(y, "+", NumericLiteral.optimalInteger(1, y.position), y.position)
val newExpr = BinaryExpression(x, "*", yPlus1, x.position) val replacement = BinaryExpression(x, "*", yPlus1, x.position)
return listOf(IAstModification.ReplaceNode(expr, newExpr, parent)) return listOf(IAstModification.ReplaceNode(expr, replacement, parent))
} }
} }
} }
@ -270,7 +274,7 @@ class ExpressionSimplifier(private val program: Program,
// simplify when a term is constant and directly determines the outcome // simplify when a term is constant and directly determines the outcome
val constFalse = NumericLiteral.fromBoolean(false, expr.position) val constFalse = NumericLiteral.fromBoolean(false, expr.position)
val newExpr: Expression? = when (expr.operator) { val newExpr2 = when (expr.operator) {
"|" -> { "|" -> {
when { when {
leftVal?.number==0.0 -> expr.right leftVal?.number==0.0 -> expr.right
@ -336,12 +340,44 @@ class ExpressionSimplifier(private val program: Program,
} }
} }
if(newExpr != null) if(newExpr2 != null)
return listOf(IAstModification.ReplaceNode(expr, newExpr, parent)) return listOf(IAstModification.ReplaceNode(expr, newExpr2, parent))
return noModifications return noModifications
} }
private fun applyAbsorptionLaws(expr: BinaryExpression): Expression? {
val rightB = expr.right as? BinaryExpression
if(rightB!=null) {
// absorption laws: a or (a and b) --> a, a and (a or b) --> a
if(expr.operator=="or" && rightB.operator=="and") {
if(expr.left isSameAs rightB.left || expr.left isSameAs rightB.right) {
return expr.left
}
}
else if(expr.operator=="and" && rightB.operator=="or") {
if(expr.left isSameAs rightB.left || expr.left isSameAs rightB.right) {
return expr.left
}
}
}
val leftB = expr.left as? BinaryExpression
if(leftB!=null) {
// absorption laws: (a and b) or a --> a, (a or b) and a --> a
if(expr.operator=="or" && leftB.operator=="and") {
if(expr.right isSameAs leftB.left || expr.left isSameAs leftB.right) {
return expr.right
}
}
else if(expr.operator=="and" && leftB.operator=="or") {
if(expr.right isSameAs leftB.left || expr.right isSameAs leftB.right) {
return expr.right
}
}
}
return null
}
override fun after(functionCallExpr: FunctionCallExpression, parent: Node): Iterable<IAstModification> { override fun after(functionCallExpr: FunctionCallExpression, parent: Node): Iterable<IAstModification> {
if(functionCallExpr.target.nameInSource == listOf("lsb")) { if(functionCallExpr.target.nameInSource == listOf("lsb")) {
if(functionCallExpr.args.isEmpty()) if(functionCallExpr.args.isEmpty())

View File

@ -965,4 +965,83 @@ main {
(assignv1 as NumericLiteral).number shouldBe 1.0 (assignv1 as NumericLiteral).number shouldBe 1.0
(assignv2 as NumericLiteral).number shouldBe 0.0 (assignv2 as NumericLiteral).number shouldBe 0.0
} }
test("De Morgan's laws") {
val src="""
main {
sub start() {
bool @shared a1
bool @shared a2
if a1==0 and a2==0
cx16.r0++
if a1==0 or a2==0
cx16.r0++
if not a1 or not a2
cx16.r0++
if not a1 and not a2
cx16.r0++
}
}"""
val result = compileText(Cx16Target(), true, src, writeAssembly = false)!!
val st = result.compilerAst.entrypoint.statements
st.size shouldBe 8
val if1c = (st[4] as IfElse).condition as BinaryExpression
val if2c = (st[5] as IfElse).condition as BinaryExpression
val if3c = (st[6] as IfElse).condition as BinaryExpression
val if4c = (st[7] as IfElse).condition as BinaryExpression
if1c.operator shouldBe "=="
(if1c.right as NumericLiteral).number shouldBe 0.0
(if1c.left as BinaryExpression).operator shouldBe "or"
if2c.operator shouldBe "=="
(if2c.right as NumericLiteral).number shouldBe 0.0
(if2c.left as BinaryExpression).operator shouldBe "and"
if3c.operator shouldBe "=="
(if3c.right as NumericLiteral).number shouldBe 0.0
(if3c.left as BinaryExpression).operator shouldBe "and"
if4c.operator shouldBe "=="
(if4c.right as NumericLiteral).number shouldBe 0.0
(if4c.left as BinaryExpression).operator shouldBe "or"
}
test("absorption laws") {
val src="""
main {
sub start() {
bool @shared a
bool @shared b
if a or (a and b)
cx16.r0 ++
if a or (b and a)
cx16.r0 ++
if a and (a or b)
cx16.r0 ++
if a and (b or a)
cx16.r0 ++
; no opt:
if a and (b and a)
cx16.r0 ++
if a or (b or a)
cx16.r0 ++
}
}"""
val result = compileText(Cx16Target(), true, src, writeAssembly = false)!!
val st = result.compilerAst.entrypoint.statements
st.size shouldBe 10
val if1 = st[4] as IfElse
val if2 = st[5] as IfElse
val if3 = st[6] as IfElse
val if4 = st[7] as IfElse
(if1.condition as IdentifierReference).nameInSource shouldBe listOf("a")
(if2.condition as IdentifierReference).nameInSource shouldBe listOf("a")
(if3.condition as IdentifierReference).nameInSource shouldBe listOf("a")
(if4.condition as IdentifierReference).nameInSource shouldBe listOf("a")
val if5 = st[8] as IfElse
val if6 = st[9] as IfElse
if5.condition shouldBe instanceOf<BinaryExpression>()
if6.condition shouldBe instanceOf<BinaryExpression>()
}
}) })

View File

@ -7,19 +7,51 @@ main {
; is optimizing this useful? : not a1 or not a2 -> not(a1 and a2) likewise for and. ; is optimizing this useful? : not a1 or not a2 -> not(a1 and a2) likewise for and.
bool @shared a1 = true bool @shared a1 = true
bool @shared a2 bool @shared a2
bool @shared a4 bool @shared a
bool @shared b
if a1==0 and a2==0 ; absorbption opt:
cx16.r0++ ; if a or (a and b)
; cx16.r0 ++
; if a or (b and a)
; cx16.r0 ++
; if a and (a or b)
; cx16.r0 ++
; if a and (b or a)
; cx16.r0 ++
;
; ; no opt:
; if a and (b and a)
; cx16.r0 ++
; if a or (b or a)
; cx16.r0 ++
if (a1!=0 or a2!=0)==0 bool @shared iteration_in_progress = false
cx16.r0++ ubyte @shared num_bytes = 99
if a1==0 or a2==0 if not iteration_in_progress or not num_bytes
cx16.r0++ txt.print("yep1")
else
txt.print("nope1")
if (a1!=0 and a2!=0)==0 iteration_in_progress = true
cx16.r0++ if not iteration_in_progress or not num_bytes
txt.print("yep2")
else
txt.print("nope2")
;
; if a1==0 and a2==0
; cx16.r0++
;
; if (a1!=0 or a2!=0)==0
; cx16.r0++
;
; if a1==0 or a2==0
; cx16.r0++
;
; if (a1!=0 and a2!=0)==0
; cx16.r0++
; if not a1 or not a2 ; if not a1 or not a2