mirror of
https://github.com/irmen/prog8.git
synced 2025-01-27 10:31:40 +00:00
tweak "not" removal/rewriting
This commit is contained in:
parent
4ca0805de1
commit
97cb0cbd08
@ -3,7 +3,7 @@ package prog8.code.core
|
||||
val AssociativeOperators = setOf("+", "*", "&", "|", "^", "or", "and", "xor", "==", "!=")
|
||||
val ComparisonOperators = setOf("==", "!=", "<", ">", "<=", ">=")
|
||||
val AugmentAssignmentOperators = setOf("+", "-", "/", "*", "&", "|", "^", "<<", ">>", "%", "and", "or", "xor")
|
||||
val LogicalOperators = setOf("and", "or", "xor") // not x is replaced with x==0
|
||||
val LogicalOperators = setOf("and", "or", "xor", "not")
|
||||
val BitwiseOperators = setOf("&", "|", "^")
|
||||
|
||||
fun invertedComparisonOperator(operator: String) =
|
||||
|
@ -2,7 +2,6 @@ package prog8.optimizer
|
||||
|
||||
import prog8.ast.Node
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.ExpressionError
|
||||
import prog8.ast.base.FatalAstException
|
||||
import prog8.ast.base.UndefinedSymbolError
|
||||
import prog8.ast.expressions.*
|
||||
@ -14,7 +13,6 @@ import prog8.ast.walk.AstWalker
|
||||
import prog8.ast.walk.IAstModification
|
||||
import prog8.code.core.AssociativeOperators
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.core.IntegerDatatypes
|
||||
|
||||
|
||||
class ConstantFoldingOptimizer(private val program: Program) : AstWalker() {
|
||||
@ -36,54 +34,8 @@ class ConstantFoldingOptimizer(private val program: Program) : AstWalker() {
|
||||
}
|
||||
|
||||
override fun after(expr: PrefixExpression, parent: Node): Iterable<IAstModification> {
|
||||
// Try to turn a unary prefix expression into a single constant value.
|
||||
// Compile-time constant sub expressions will be evaluated on the spot.
|
||||
// For instance, the expression for "- 4.5" will be optimized into the float literal -4.5
|
||||
val subexpr = expr.expression
|
||||
if (subexpr is NumericLiteral) {
|
||||
// accept prefixed literal values (such as -3, not true)
|
||||
return when (expr.operator) {
|
||||
"+" -> listOf(IAstModification.ReplaceNode(expr, subexpr, parent))
|
||||
"-" -> when (subexpr.type) {
|
||||
in IntegerDatatypes -> {
|
||||
listOf(IAstModification.ReplaceNode(expr,
|
||||
NumericLiteral.optimalInteger(-subexpr.number.toInt(), subexpr.position),
|
||||
parent))
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
listOf(IAstModification.ReplaceNode(expr,
|
||||
NumericLiteral(DataType.FLOAT, -subexpr.number, subexpr.position),
|
||||
parent))
|
||||
}
|
||||
else -> throw ExpressionError("can only take negative of int or float", subexpr.position)
|
||||
}
|
||||
"~" -> when (subexpr.type) {
|
||||
DataType.BYTE -> {
|
||||
listOf(IAstModification.ReplaceNode(expr,
|
||||
NumericLiteral(DataType.BYTE, subexpr.number.toInt().inv().toDouble(), subexpr.position),
|
||||
parent))
|
||||
}
|
||||
DataType.UBYTE -> {
|
||||
listOf(IAstModification.ReplaceNode(expr,
|
||||
NumericLiteral(DataType.UBYTE, (subexpr.number.toInt().inv() and 255).toDouble(), subexpr.position),
|
||||
parent))
|
||||
}
|
||||
DataType.WORD -> {
|
||||
listOf(IAstModification.ReplaceNode(expr,
|
||||
NumericLiteral(DataType.WORD, subexpr.number.toInt().inv().toDouble(), subexpr.position),
|
||||
parent))
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
listOf(IAstModification.ReplaceNode(expr,
|
||||
NumericLiteral(DataType.UWORD, (subexpr.number.toInt().inv() and 65535).toDouble(), subexpr.position),
|
||||
parent))
|
||||
}
|
||||
else -> throw ExpressionError("can only take bitwise inversion of int", subexpr.position)
|
||||
}
|
||||
else -> throw ExpressionError(expr.operator, subexpr.position)
|
||||
}
|
||||
}
|
||||
return noModifications
|
||||
val constValue = expr.constValue(program) ?: return noModifications
|
||||
return listOf(IAstModification.ReplaceNode(expr, constValue, parent))
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -330,6 +330,8 @@ private fun processAst(program: Program, errors: IErrorReporter, compilerOptions
|
||||
errors.report()
|
||||
program.reorderStatements(errors, compilerOptions)
|
||||
errors.report()
|
||||
program.changeNotExpression(errors)
|
||||
errors.report()
|
||||
program.addTypecasts(errors, compilerOptions)
|
||||
errors.report()
|
||||
program.variousCleanups(errors, compilerOptions)
|
||||
|
@ -44,6 +44,14 @@ internal fun Program.reorderStatements(errors: IErrorReporter, options: Compilat
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Program.changeNotExpression(errors: IErrorReporter) {
|
||||
val changer = NotExpressionChanger(this, errors)
|
||||
changer.visit(this)
|
||||
while(errors.noErrors() && changer.applyModifications()>0) {
|
||||
changer.visit(this)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Program.charLiteralsToUByteLiterals(target: ICompilationTarget, errors: IErrorReporter) {
|
||||
val walker = object : AstWalker() {
|
||||
override fun after(char: CharLiteral, parent: Node): Iterable<IAstModification> {
|
||||
|
@ -3,7 +3,6 @@ package prog8.compiler.astprocessing
|
||||
import prog8.ast.IFunctionCall
|
||||
import prog8.ast.Node
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.FatalAstException
|
||||
import prog8.ast.base.SyntaxError
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.statements.*
|
||||
@ -114,17 +113,6 @@ class AstPreprocessor(val program: Program, val errors: IErrorReporter, val comp
|
||||
return noModifications
|
||||
}
|
||||
|
||||
override fun before(expr: PrefixExpression, parent: Node): Iterable<IAstModification> {
|
||||
if(expr.operator == "not") {
|
||||
// not(x) --> x==0
|
||||
// this means that "not" will never occur anywhere again in the ast
|
||||
val dt = expr.expression.inferType(program).getOr(DataType.UBYTE)
|
||||
val replacement = BinaryExpression(expr.expression, "==", NumericLiteral(dt,0.0, expr.position), expr.position)
|
||||
return listOf(IAstModification.ReplaceNodeSafe(expr, replacement, parent))
|
||||
}
|
||||
return noModifications
|
||||
}
|
||||
|
||||
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
|
||||
val nextAssignment = decl.nextSibling() as? Assignment
|
||||
if(nextAssignment!=null && nextAssignment.origin!=AssignmentOrigin.VARINIT) {
|
||||
@ -164,6 +152,8 @@ class AstPreprocessor(val program: Program, val errors: IErrorReporter, val comp
|
||||
expr
|
||||
else if(expr is BinaryExpression && expr.operator in LogicalOperators+ComparisonOperators)
|
||||
expr
|
||||
else if(expr is PrefixExpression && expr.operator in LogicalOperators)
|
||||
expr
|
||||
else
|
||||
FunctionCallExpression(IdentifierReference(listOf("boolean"), expr.position), mutableListOf(expr), expr.position)
|
||||
}
|
||||
|
@ -231,8 +231,12 @@ internal class BeforeAsmAstChanger(val program: Program,
|
||||
var rightAssignment: Assignment? = null
|
||||
var rightOperandReplacement: Expression? = null
|
||||
|
||||
val separateLeftExpr = !expr.left.isSimple && expr.left !is IFunctionCall && expr.left !is ContainmentCheck
|
||||
val separateRightExpr = !expr.right.isSimple && expr.right !is IFunctionCall && expr.right !is ContainmentCheck
|
||||
val separateLeftExpr = !expr.left.isSimple
|
||||
&& expr.left !is IFunctionCall
|
||||
&& expr.left !is ContainmentCheck
|
||||
val separateRightExpr = !expr.right.isSimple
|
||||
&& expr.right !is IFunctionCall
|
||||
&& expr.right !is ContainmentCheck
|
||||
val leftDt = expr.left.inferType(program)
|
||||
val rightDt = expr.right.inferType(program)
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
package prog8.compiler.astprocessing
|
||||
|
||||
import prog8.ast.*
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.expressions.BinaryExpression
|
||||
import prog8.ast.expressions.DirectMemoryRead
|
||||
import prog8.ast.expressions.FunctionCallExpression
|
||||
import prog8.ast.expressions.NumericLiteral
|
||||
import prog8.ast.statements.*
|
||||
import prog8.ast.walk.AstWalker
|
||||
import prog8.ast.walk.IAstModification
|
||||
|
@ -0,0 +1,113 @@
|
||||
package prog8.compiler.astprocessing
|
||||
|
||||
import prog8.ast.Node
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.expressions.BinaryExpression
|
||||
import prog8.ast.expressions.Expression
|
||||
import prog8.ast.expressions.NumericLiteral
|
||||
import prog8.ast.expressions.PrefixExpression
|
||||
import prog8.ast.statements.Assignment
|
||||
import prog8.ast.walk.AstWalker
|
||||
import prog8.ast.walk.IAstModification
|
||||
import prog8.code.core.IErrorReporter
|
||||
import prog8.code.core.IntegerDatatypes
|
||||
|
||||
internal class NotExpressionChanger(val program: Program, val errors: IErrorReporter) : AstWalker() {
|
||||
|
||||
override fun before(expr: BinaryExpression, parent: Node): Iterable<IAstModification> {
|
||||
if(expr.operator=="==" || expr.operator=="!=") {
|
||||
val left = expr.left as? BinaryExpression
|
||||
if (left != null) {
|
||||
val rightValue = expr.right.constValue(program)
|
||||
if (rightValue?.number == 0.0 && rightValue.type in IntegerDatatypes) {
|
||||
if (left.operator == "==" && expr.operator == "==") {
|
||||
// (x==something)==0 --> x!=something
|
||||
left.operator = "!="
|
||||
return listOf(IAstModification.ReplaceNode(expr, left, parent))
|
||||
} else if (left.operator == "!=" && expr.operator == "==") {
|
||||
// (x!=something)==0 --> x==something
|
||||
left.operator = "=="
|
||||
return listOf(IAstModification.ReplaceNode(expr, left, parent))
|
||||
} else if (left.operator == "==" && expr.operator == "!=") {
|
||||
// (x==something)!=0 --> x==something
|
||||
left.operator = "=="
|
||||
return listOf(IAstModification.ReplaceNode(expr, left, parent))
|
||||
} else if (left.operator == "!=" && expr.operator == "!=") {
|
||||
// (x!=something)!=0 --> x!=something
|
||||
left.operator = "!="
|
||||
return listOf(IAstModification.ReplaceNode(expr, left, parent))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val left = expr.left as? BinaryExpression
|
||||
val right = expr.right as? BinaryExpression
|
||||
val leftValue = left?.right?.constValue(program)?.number
|
||||
val rightValue = right?.right?.constValue(program)?.number
|
||||
|
||||
if(expr.operator == "or") {
|
||||
if(left?.operator=="==" && right?.operator=="==" && leftValue==0.0 && rightValue==0.0) {
|
||||
// (a==0) or (b==0) -> (a and b)==0
|
||||
val orExpr = BinaryExpression(left.left, "and", right.left, expr.position)
|
||||
val equalsZero = BinaryExpression(orExpr, "==", NumericLiteral.fromBoolean(false, expr.position), expr.position)
|
||||
return listOf(IAstModification.ReplaceNode(expr, equalsZero, parent))
|
||||
}
|
||||
}
|
||||
else if(expr.operator == "and") {
|
||||
if(left?.operator=="==" && right?.operator=="==" && leftValue==0.0 && rightValue==0.0) {
|
||||
// (a==0) and (b==0) -> (a or b)==0
|
||||
val orExpr = BinaryExpression(left.left, "or", right.left, expr.position)
|
||||
val equalsZero = BinaryExpression(orExpr, "==", NumericLiteral.fromBoolean(false, expr.position), expr.position)
|
||||
return listOf(IAstModification.ReplaceNode(expr, equalsZero, parent))
|
||||
}
|
||||
}
|
||||
return noModifications
|
||||
}
|
||||
|
||||
override fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> {
|
||||
// not a or not b -> not(a and b)
|
||||
if(expr.operator=="or") {
|
||||
val left = expr.left as? PrefixExpression
|
||||
val right = expr.right as? PrefixExpression
|
||||
if(left?.operator=="not" && right?.operator=="not") {
|
||||
val andExpr = BinaryExpression(left.expression, "and", right.expression, expr.position)
|
||||
val notExpr = PrefixExpression("not", andExpr, expr.position)
|
||||
return listOf(IAstModification.ReplaceNode(expr, notExpr, parent))
|
||||
}
|
||||
}
|
||||
|
||||
// not a and not b -> not(a or b)
|
||||
if(expr.operator=="and") {
|
||||
val left = expr.left as? PrefixExpression
|
||||
val right = expr.right as? PrefixExpression
|
||||
if(left?.operator=="not" && right?.operator=="not") {
|
||||
val andExpr = BinaryExpression(left.expression, "or", right.expression, expr.position)
|
||||
val notExpr = PrefixExpression("not", andExpr, expr.position)
|
||||
return listOf(IAstModification.ReplaceNode(expr, notExpr, parent))
|
||||
}
|
||||
}
|
||||
|
||||
if(expr.operator=="==") {
|
||||
val rightValue = expr.right.constValue(program)
|
||||
if(rightValue?.number==0.0 && rightValue.type in IntegerDatatypes) {
|
||||
// x==0 -> not x (only if occurs as a subexpression)
|
||||
if(expr.parent is Expression || expr.parent is Assignment) {
|
||||
val notExpr = PrefixExpression("not", expr.left.copy(), expr.position)
|
||||
return listOf(IAstModification.ReplaceNodeSafe(expr, notExpr, parent))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return noModifications
|
||||
}
|
||||
|
||||
override fun after(expr: PrefixExpression, parent: Node): Iterable<IAstModification> {
|
||||
if(expr.operator == "not") {
|
||||
// not(not(x)) -> x
|
||||
if((expr.expression as? PrefixExpression)?.operator=="not")
|
||||
return listOf(IAstModification.ReplaceNode(expr, expr.expression, parent))
|
||||
}
|
||||
return noModifications
|
||||
}
|
||||
}
|
@ -306,12 +306,14 @@ internal class StatementReorderer(val program: Program,
|
||||
val newRight = BinaryExpression(leftBinExpr.right, binExpr.operator, binExpr.right, binExpr.position)
|
||||
val newValue = BinaryExpression(leftBinExpr.left, binExpr.operator, newRight, binExpr.position)
|
||||
listOf(IAstModification.ReplaceNode(binExpr, newValue, assignment))
|
||||
} else {
|
||||
}
|
||||
else if(leftBinExpr.left.constValue(program)!=null && binExpr.right.constValue(program)!=null) {
|
||||
// A = (x <associative-operator> A) <same-operator> y ==> A = A <associative-operator> (x <same-operator> y)
|
||||
val newRight = BinaryExpression(leftBinExpr.left, binExpr.operator, binExpr.right, binExpr.position)
|
||||
val newValue = BinaryExpression(leftBinExpr.right, binExpr.operator, newRight, binExpr.position)
|
||||
listOf(IAstModification.ReplaceNode(binExpr, newValue, assignment))
|
||||
}
|
||||
else noModifications
|
||||
}
|
||||
val rightBinExpr = binExpr.right as? BinaryExpression
|
||||
if(rightBinExpr?.operator == binExpr.operator) {
|
||||
|
@ -48,7 +48,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
|
||||
if(parent is Assignment) {
|
||||
val targetDt = (parent).target.inferType(program).getOrElse { throw FatalAstException("invalid dt") }
|
||||
if(sourceDt istype targetDt) {
|
||||
// we can get rid of this typecast because the type is already
|
||||
// we can get rid of this typecast because the type is already the target type
|
||||
return listOf(IAstModification.ReplaceNode(typecast, typecast.expression, parent))
|
||||
}
|
||||
}
|
||||
@ -71,6 +71,13 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
|
||||
// +X --> X
|
||||
return listOf(IAstModification.ReplaceNode(expr, expr.expression, parent))
|
||||
}
|
||||
else if(expr.operator == "not") {
|
||||
// not(x) --> x==0
|
||||
// this means that "not" will never occur anywhere again in the ast after this
|
||||
val dt = expr.expression.inferType(program).getOr(DataType.UBYTE)
|
||||
val replacement = BinaryExpression(expr.expression, "==", NumericLiteral(dt,0.0, expr.position), expr.position)
|
||||
return listOf(IAstModification.ReplaceNodeSafe(expr, replacement, parent))
|
||||
}
|
||||
return noModifications
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,10 @@
|
||||
package prog8tests
|
||||
|
||||
import io.kotest.assertions.fail
|
||||
import io.kotest.assertions.withClue
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
import io.kotest.matchers.shouldBe
|
||||
import io.kotest.matchers.shouldNotBe
|
||||
import io.kotest.matchers.string.shouldContain
|
||||
import io.kotest.matchers.string.shouldNotBeBlank
|
||||
import io.kotest.matchers.string.shouldStartWith
|
||||
import io.kotest.matchers.types.instanceOf
|
||||
import io.kotest.matchers.types.shouldBeSameInstanceAs
|
||||
@ -14,9 +12,9 @@ import prog8.ast.ParentSentinel
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.statements.*
|
||||
import prog8.code.core.*
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.core.Position
|
||||
import prog8.code.target.C64Target
|
||||
import prog8.compiler.astprocessing.processAstBeforeAsmGeneration
|
||||
import prog8.compiler.printProgram
|
||||
import prog8tests.helpers.*
|
||||
|
||||
@ -253,83 +251,41 @@ class TestOptimization: FunSpec({
|
||||
(initY2.value as NumericLiteral).number shouldBe 11.0
|
||||
}
|
||||
|
||||
test("not-typecasted assignment from ubyte logical expression to uword var should be auto upcasted") {
|
||||
test("various 'not' operator rewrites even without optimizations on") {
|
||||
val src = """
|
||||
main {
|
||||
sub start() {
|
||||
ubyte bb
|
||||
uword ww
|
||||
ww = not bb or not ww ; expression combining ubyte and uword
|
||||
ubyte a1
|
||||
ubyte a2
|
||||
a1 = not not a1 ; a1 = a1==0
|
||||
a1 = not a1 or not a2 ; a1 = (a1 and a2)==0
|
||||
a1 = not a1 and not a2 ; a1 = (a1 or a2)==0
|
||||
}
|
||||
}
|
||||
"""
|
||||
val result = compileText(C64Target(), false, src, writeAssembly = false)!!
|
||||
val stmts = result.program.entrypoint.statements
|
||||
stmts.size shouldBe 7
|
||||
|
||||
val wwAssign = result.program.entrypoint.statements.last() as Assignment
|
||||
val expr = wwAssign.value as TypecastExpression
|
||||
expr.type shouldBe DataType.UWORD
|
||||
|
||||
wwAssign.target.identifier?.nameInSource shouldBe listOf("ww")
|
||||
expr.expression.inferType(result.program) istype DataType.UBYTE shouldBe true
|
||||
}
|
||||
|
||||
test("intermediate assignment steps have correct types for codegen phase (BeforeAsmGenerationAstChanger)") {
|
||||
val src = """
|
||||
main {
|
||||
sub start() {
|
||||
ubyte bb
|
||||
uword ww
|
||||
bb = not bb or not ww ; expression combining ubyte and uword
|
||||
}
|
||||
}
|
||||
"""
|
||||
val result = compileText(C64Target(), false, src, writeAssembly = false)!!
|
||||
|
||||
// bb = ((boolean(bb)==0) or (boolean(ww)==0))
|
||||
val bbAssign = result.program.entrypoint.statements.last() as Assignment
|
||||
val expr = bbAssign.value as BinaryExpression
|
||||
expr.operator shouldBe "or"
|
||||
expr.left shouldBe instanceOf<BinaryExpression>()
|
||||
expr.right shouldBe instanceOf<BinaryExpression>()
|
||||
expr.left.inferType(result.program).getOrElse { fail("dt") } shouldBe DataType.UBYTE
|
||||
expr.right.inferType(result.program).getOrElse { fail("dt") } shouldBe DataType.UBYTE
|
||||
expr.inferType(result.program).getOrElse { fail("dt") } shouldBe DataType.UBYTE
|
||||
|
||||
val options = CompilationOptions(OutputType.PRG, CbmPrgLauncherType.BASIC, ZeropageType.DONTUSE, emptyList(),
|
||||
floats = false,
|
||||
noSysInit = true,
|
||||
compTarget = C64Target(),
|
||||
loadAddress = 0u, outputDir= outputDir)
|
||||
result.program.processAstBeforeAsmGeneration(options, ErrorReporterForTests())
|
||||
printProgram(result.program)
|
||||
|
||||
// TODO this is no longer the case:
|
||||
// assignment is now split into:
|
||||
// bb = not bb
|
||||
// bb = (bb or (not ww as ubyte)
|
||||
// val assigns = result.program.entrypoint.statements.filterIsInstance<Assignment>()
|
||||
// val bbAssigns = assigns.filter { it.value !is NumericLiteral }
|
||||
// bbAssigns.size shouldBe 2
|
||||
//
|
||||
// bbAssigns[0].target.identifier!!.nameInSource shouldBe listOf("bb")
|
||||
// bbAssigns[0].value shouldBe instanceOf<PrefixExpression>()
|
||||
// (bbAssigns[0].value as PrefixExpression).operator shouldBe "not"
|
||||
// ((bbAssigns[0].value as PrefixExpression).expression as? IdentifierReference)?.nameInSource shouldBe listOf("bb")
|
||||
// bbAssigns[0].value.inferType(result.program).getOrElse { fail("dt") } shouldBe DataType.UBYTE
|
||||
//
|
||||
// bbAssigns[1].target.identifier!!.nameInSource shouldBe listOf("bb")
|
||||
// val bbAssigns1expr = bbAssigns[1].value as BinaryExpression
|
||||
// bbAssigns1expr.operator shouldBe "or"
|
||||
// (bbAssigns1expr.left as? IdentifierReference)?.nameInSource shouldBe listOf("bb")
|
||||
// bbAssigns1expr.right shouldBe instanceOf<TypecastExpression>()
|
||||
// val castedValue = (bbAssigns1expr.right as TypecastExpression).expression as PrefixExpression
|
||||
// castedValue.operator shouldBe "not"
|
||||
// (castedValue.expression as? IdentifierReference)?.nameInSource shouldBe listOf("ww")
|
||||
// bbAssigns1expr.inferType(result.program).getOrElse { fail("dt") } shouldBe DataType.UBYTE
|
||||
//
|
||||
// val asm = generateAssembly(result.program, options)
|
||||
// asm shouldNotBe null
|
||||
// asm!!.name.shouldNotBeBlank()
|
||||
val value1 = (stmts[4] as Assignment).value as BinaryExpression
|
||||
val value2 = (stmts[5] as Assignment).value as BinaryExpression
|
||||
val value3 = (stmts[6] as Assignment).value as BinaryExpression
|
||||
value1.operator shouldBe "=="
|
||||
value1.right shouldBe NumericLiteral(DataType.UBYTE, 0.0, Position.DUMMY)
|
||||
value2.operator shouldBe "=="
|
||||
value2.right shouldBe NumericLiteral(DataType.UBYTE, 0.0, Position.DUMMY)
|
||||
value3.operator shouldBe "=="
|
||||
value3.right shouldBe NumericLiteral(DataType.UBYTE, 0.0, Position.DUMMY)
|
||||
val left1 = value1.left as IdentifierReference
|
||||
val left2 = value2.left as BinaryExpression
|
||||
val left3 = value3.left as BinaryExpression
|
||||
left1.nameInSource shouldBe listOf("a1")
|
||||
left2.operator shouldBe "and"
|
||||
(left2.left as IdentifierReference).nameInSource shouldBe listOf("a1")
|
||||
(left2.right as IdentifierReference).nameInSource shouldBe listOf("a2")
|
||||
left3.operator shouldBe "or"
|
||||
(left3.left as IdentifierReference).nameInSource shouldBe listOf("a1")
|
||||
(left3.right as IdentifierReference).nameInSource shouldBe listOf("a2")
|
||||
}
|
||||
|
||||
test("intermediate assignment steps generated for typecasted expression") {
|
||||
|
@ -180,7 +180,7 @@ class TestTypecasts: FunSpec({
|
||||
}"""
|
||||
val result = compileText(C64Target(), false, text, writeAssembly = true)!!
|
||||
val statements = result.program.entrypoint.statements
|
||||
statements.size shouldBe 13
|
||||
statements.size shouldBe 14
|
||||
}
|
||||
|
||||
test("no infinite typecast loop in assignment asmgen") {
|
||||
|
@ -109,6 +109,7 @@ class PrefixExpression(val operator: String, var expression: Expression, overrid
|
||||
DataType.UWORD -> NumericLiteral(DataType.UWORD, (constval.number.toInt().inv() and 65535).toDouble(), constval.position)
|
||||
else -> throw ExpressionError("can only take bitwise inversion of int", constval.position)
|
||||
}
|
||||
"not" -> NumericLiteral.fromBoolean(constval.number==0.0, constval.position)
|
||||
else -> throw FatalAstException("invalid operator")
|
||||
}
|
||||
converted.linkParents(this.parent)
|
||||
@ -214,7 +215,7 @@ class BinaryExpression(var left: Expression, var operator: String, var right: Ex
|
||||
"&" -> leftDt
|
||||
"|" -> leftDt
|
||||
"^" -> leftDt
|
||||
"and", "or", "xor" -> InferredTypes.knownFor(DataType.UBYTE)
|
||||
"and", "or", "xor", "not" -> InferredTypes.knownFor(DataType.UBYTE)
|
||||
"<", ">",
|
||||
"<=", ">=",
|
||||
"==", "!=" -> dynamicBooleanType()
|
||||
|
@ -3,33 +3,32 @@ TODO
|
||||
|
||||
For next release
|
||||
^^^^^^^^^^^^^^^^
|
||||
- code gen for if statements has become bad
|
||||
- assembler incorrectly assembles hello.asm now (crash when run)
|
||||
|
||||
- why can't while and until loops use NOT condition instead of Cond==0 ? Fix this!
|
||||
|
||||
- code gen for if statements has become inefficient? vm/6502?
|
||||
if not diskio.iteration_in_progress or not num_bytes
|
||||
return 0
|
||||
- code gen for while loops has become bad (until loops probably as well)
|
||||
- code gen for while loops has become inefficient: (until loops probably as well)
|
||||
(maybe solved when if statements code has been fixed)
|
||||
while c64.CHRIN()!='\"' {
|
||||
if c64.READST()
|
||||
goto close_end
|
||||
}
|
||||
|
||||
- chess.prg became A LOT larger, why!? (perhaps due to new while/until condition handling?)
|
||||
- imageviewer.prg became A LOT larger, why!?
|
||||
- petaxian.prg became A LOT larger, why!?
|
||||
- some programs became a bit larger since "not" was removed (assembler)
|
||||
|
||||
- 6502: fix logical and/or/xor routines to just be bitwise routines.
|
||||
- petaxian.prg became quite a bit (200 bytes) larger, why!? because of the above?
|
||||
|
||||
- get rid of logical and/or/xor in the codegen (6502+vm)
|
||||
because bitwise versions + correct use of boolean() operand wrapping are equivalent?
|
||||
can do this for instance by replacing and/or/xor with their bitwise versions &, |, ^, ~
|
||||
can do this for instance by replacing and/or/xor with their bitwise versions &, |, ^
|
||||
- ...or: 6502: fix logical and/or/xor routines to just be bitwise routines.
|
||||
|
||||
- check all examples if they still work, maybe we find bug for...:
|
||||
|
||||
- compiling logical.p8 to virtual with optimization generates a lot larger code as without optimizations.
|
||||
this is not the case for the 6502 codegen.
|
||||
|
||||
- add optimizations: not a or not b -> not(a and b) , not a and not b -> not(a or b)
|
||||
actually this now means: (a==0) or (b==0) -> (a or b)==0, (a==0) and (b==0) -> (a or b)==0
|
||||
add unit tests for that.
|
||||
- bin expr splitter: split logical expressions on ands/ors/xors ?
|
||||
|
||||
- add some more optimizations in vmPeepholeOptimizer
|
||||
|
@ -6,22 +6,56 @@
|
||||
main {
|
||||
|
||||
sub start() {
|
||||
; a "pixelshader":
|
||||
sys.gfx_enable(0) ; enable lo res screen
|
||||
ubyte shifter
|
||||
ubyte a1 = 0
|
||||
ubyte a2 = 42
|
||||
ubyte a3 = 1
|
||||
|
||||
repeat {
|
||||
uword xx
|
||||
uword yy = 0
|
||||
repeat 240 {
|
||||
xx = 0
|
||||
repeat 320 {
|
||||
sys.gfx_plot(xx, yy, xx*yy + shifter as ubyte)
|
||||
xx++
|
||||
}
|
||||
yy++
|
||||
}
|
||||
shifter+=4
|
||||
}
|
||||
}
|
||||
if (a1==0)==0
|
||||
a3 = (a1==0)==0
|
||||
|
||||
if (a1!=0)==0
|
||||
a3 = (a1!=0)==0
|
||||
|
||||
if (a1==0)!=0
|
||||
a3 = (a1==0)!=0
|
||||
|
||||
if (a1!=0)!=0
|
||||
a3 = (a1!=0)!=0
|
||||
|
||||
if (a1==0) or (a2==0)
|
||||
a3 = (a1==0) or (a2==0)
|
||||
|
||||
if (a1==0) and (a2==0)
|
||||
a3 = (a1==0) and (a2==0)
|
||||
|
||||
if not a1 or not a2 or not(not(a3))
|
||||
a3=not a1 or not a2 or not(not(a3))
|
||||
|
||||
if (a1==0) or (a2==0)
|
||||
a3 = (a1==0) or (a2==0)
|
||||
|
||||
if (a1==0) and (a2==0)
|
||||
a3 = (a1==0) and (a2==0)
|
||||
|
||||
txt.print_ub(a3)
|
||||
|
||||
|
||||
; ; a "pixelshader":
|
||||
; sys.gfx_enable(0) ; enable lo res screen
|
||||
; ubyte shifter
|
||||
;
|
||||
; repeat {
|
||||
; uword xx
|
||||
; uword yy = 0
|
||||
; repeat 240 {
|
||||
; xx = 0
|
||||
; repeat 320 {
|
||||
; sys.gfx_plot(xx, yy, xx*yy + shifter as ubyte)
|
||||
; xx++
|
||||
; }
|
||||
; yy++
|
||||
; }
|
||||
; shifter+=4
|
||||
; }
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user