fix referencesIdentifier() and better removal of unnecessary assignments

This commit is contained in:
Irmen de Jong 2021-11-20 17:33:02 +01:00
parent f9399bcce7
commit 74db5c6be7
12 changed files with 243 additions and 120 deletions

View File

@ -111,7 +111,7 @@ internal class ConstantIdentifierReplacer(private val program: Program, private
override fun before(decl: VarDecl, parent: Node): Iterable<IAstModification> { override fun before(decl: VarDecl, parent: Node): Iterable<IAstModification> {
// the initializer value can't refer to the variable itself (recursive definition) // the initializer value can't refer to the variable itself (recursive definition)
// TODO: use call graph for this? // TODO: use call graph for this?
if(decl.value?.referencesIdentifier(decl.name) == true || decl.arraysize?.indexExpr?.referencesIdentifier(decl.name) == true) { if(decl.value?.referencesIdentifier(listOf(decl.name)) == true || decl.arraysize?.indexExpr?.referencesIdentifier(listOf(decl.name)) == true) {
errors.err("recursive var declaration", decl.position) errors.err("recursive var declaration", decl.position)
return noModifications return noModifications
} }

View File

@ -1,11 +1,9 @@
package prog8.optimizer package prog8.optimizer
import prog8.ast.* import prog8.ast.*
import prog8.ast.base.DataType
import prog8.ast.base.VarDeclType import prog8.ast.base.VarDeclType
import prog8.ast.expressions.BinaryExpression import prog8.ast.expressions.*
import prog8.ast.expressions.FunctionCall
import prog8.ast.expressions.PrefixExpression
import prog8.ast.expressions.TypecastExpression
import prog8.ast.statements.* import prog8.ast.statements.*
import prog8.ast.walk.AstWalker import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstModification import prog8.ast.walk.IAstModification
@ -58,8 +56,7 @@ class UnusedCodeRemover(private val program: Program,
} }
override fun after(scope: AnonymousScope, parent: Node): Iterable<IAstModification> { override fun after(scope: AnonymousScope, parent: Node): Iterable<IAstModification> {
val removeDoubleAssignments = deduplicateAssignments(scope.statements) return deduplicateAssignments(scope.statements, scope)
return removeDoubleAssignments.map { IAstModification.Remove(it, scope) }
} }
override fun after(block: Block, parent: Node): Iterable<IAstModification> { override fun after(block: Block, parent: Node): Iterable<IAstModification> {
@ -75,8 +72,7 @@ class UnusedCodeRemover(private val program: Program,
} }
} }
val removeDoubleAssignments = deduplicateAssignments(block.statements) return deduplicateAssignments(block.statements, block)
return removeDoubleAssignments.map { IAstModification.Remove(it, block) }
} }
override fun after(subroutine: Subroutine, parent: Node): Iterable<IAstModification> { override fun after(subroutine: Subroutine, parent: Node): Iterable<IAstModification> {
@ -99,8 +95,7 @@ class UnusedCodeRemover(private val program: Program,
} }
} }
val removeDoubleAssignments = deduplicateAssignments(subroutine.statements) return deduplicateAssignments(subroutine.statements, subroutine)
return removeDoubleAssignments.map { IAstModification.Remove(it, subroutine) }
} }
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> { override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
@ -135,28 +130,117 @@ class UnusedCodeRemover(private val program: Program,
return noModifications return noModifications
} }
private fun deduplicateAssignments(statements: List<Statement>): List<Assignment> { private fun deduplicateAssignments(statements: List<Statement>, scope: IStatementContainer): List<IAstModification> {
// removes 'duplicate' assignments that assign the same target directly after another // removes 'duplicate' assignments that assign the same target directly after another
val linesToRemove = mutableListOf<Assignment>() val linesToRemove = mutableListOf<Assignment>()
val modifications = mutableListOf<IAstModification>()
for (stmtPairs in statements.windowed(2, step = 1)) { fun substituteZeroInBinexpr(expr: BinaryExpression, zero: NumericLiteralValue, assign1: Assignment, assign2: Assignment) {
val assign1 = stmtPairs[0] as? Assignment if(expr.left isSameAs assign2.target) {
val assign2 = stmtPairs[1] as? Assignment // X = X <oper> Right
if (assign1 != null && assign2 != null && !assign2.isAugmentable) { linesToRemove.add(assign1)
if (assign1.target.isSameAs(assign2.target, program) && !assign1.target.isIOAddress(compTarget.machine)) { modifications.add(IAstModification.ReplaceNode(
if(assign2.target.identifier==null || !assign2.value.referencesIdentifier(*(assign2.target.identifier!!.nameInSource.toTypedArray()))) expr.left, zero, expr
// only remove the second assignment if its value is a simple expression! ))
when(assign2.value) { }
is PrefixExpression, if(expr.right isSameAs assign2.target) {
is BinaryExpression, // X = Left <oper> X
is TypecastExpression, linesToRemove.add(assign1)
is FunctionCall -> { /* don't remove */ } modifications.add(IAstModification.ReplaceNode(
else -> linesToRemove.add(assign1) expr.right, zero, expr
} ))
}
val leftBinExpr = expr.left as? BinaryExpression
val rightBinExpr = expr.right as? BinaryExpression
if(leftBinExpr!=null && rightBinExpr==null) {
if(leftBinExpr.left isSameAs assign2.target) {
// X = (X <oper> Right) <oper> Something
linesToRemove.add(assign1)
modifications.add(IAstModification.ReplaceNode(
leftBinExpr.left, zero, leftBinExpr
))
}
if(leftBinExpr.right isSameAs assign2.target) {
// X = (Left <oper> X) <oper> Something
linesToRemove.add(assign1)
modifications.add(IAstModification.ReplaceNode(
leftBinExpr.right, zero, leftBinExpr
))
}
}
if(leftBinExpr==null && rightBinExpr!=null) {
if(rightBinExpr.left isSameAs assign2.target) {
// X = Something <oper> (X <oper> Right)
linesToRemove.add(assign1)
modifications.add(IAstModification.ReplaceNode(
rightBinExpr.left, zero, rightBinExpr
))
}
if(rightBinExpr.right isSameAs assign2.target) {
// X = Something <oper> (Left <oper> X)
linesToRemove.add(assign1)
modifications.add(IAstModification.ReplaceNode(
rightBinExpr.right, zero, rightBinExpr
))
} }
} }
} }
return linesToRemove fun substituteZeroInPrefixexpr(expr: PrefixExpression, zero: NumericLiteralValue, assign1: Assignment, assign2: Assignment) {
if(expr.expression isSameAs assign2.target) {
linesToRemove.add(assign1)
modifications.add(IAstModification.ReplaceNode(
expr.expression, zero, expr
))
}
}
fun substituteZeroInTypecast(expr: TypecastExpression, zero: NumericLiteralValue, assign1: Assignment, assign2: Assignment) {
if(expr.expression isSameAs assign2.target) {
linesToRemove.add(assign1)
modifications.add(IAstModification.ReplaceNode(
expr.expression, zero, expr
))
}
val subCast = expr.expression as? TypecastExpression
if(subCast!=null && subCast.expression isSameAs assign2.target) {
linesToRemove.add(assign1)
modifications.add(IAstModification.ReplaceNode(
subCast.expression, zero, subCast
))
}
}
for (stmtPairs in statements.windowed(2, step = 1)) {
val assign1 = stmtPairs[0] as? Assignment
val assign2 = stmtPairs[1] as? Assignment
if (assign1 != null && assign2 != null) {
val cvalue1 = assign1.value.constValue(program)
if(cvalue1!=null && cvalue1.number==0.0 && assign2.isAugmentable) {
val value2 = assign2.value
val zero = VarDecl.defaultZero(value2.inferType(program).getOr(DataType.UNDEFINED), value2.position)
when(value2) {
is BinaryExpression -> substituteZeroInBinexpr(value2, zero, assign1, assign2)
is PrefixExpression -> substituteZeroInPrefixexpr(value2, zero, assign1, assign2)
is TypecastExpression -> substituteZeroInTypecast(value2, zero, assign1, assign2)
else -> {}
}
} else {
if (assign1.target.isSameAs(assign2.target, program) && !assign1.target.isIOAddress(compTarget.machine)) {
if(assign2.target.identifier==null || !assign2.value.referencesIdentifier(assign2.target.identifier!!.nameInSource))
// only remove the second assignment if its value is a simple expression!
when(assign2.value) {
is PrefixExpression,
is BinaryExpression,
is TypecastExpression,
is FunctionCall -> { /* don't remove */ }
else -> linesToRemove.add(assign1)
}
}
}
}
}
return modifications + linesToRemove.map { IAstModification.Remove(it, scope) }
} }
} }

View File

@ -40,7 +40,7 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, private val o
if (binExpr != null && binExpr.operator !in comparisonOperators) { if (binExpr != null && binExpr.operator !in comparisonOperators) {
if (binExpr.left !is BinaryExpression) { if (binExpr.left !is BinaryExpression) {
if (binExpr.right.referencesIdentifier(*assignment.target.identifier!!.nameInSource.toTypedArray())) { if (binExpr.right.referencesIdentifier(assignment.target.identifier!!.nameInSource)) {
// the right part of the expression contains the target variable itself. // the right part of the expression contains the target variable itself.
// we can't 'split' it trivially because the variable will be changed halfway through. // we can't 'split' it trivially because the variable will be changed halfway through.
if(binExpr.operator in associativeOperators) { if(binExpr.operator in associativeOperators) {

View File

@ -351,7 +351,7 @@ private fun writeAssembly(program: Program,
} }
} }
fun printAst(program: Program) { fun printProgram(program: Program) {
println() println()
val printer = AstToSourceTextConverter(::print, program) val printer = AstToSourceTextConverter(::print, program)
printer.visit(program) printer.visit(program)

View File

@ -508,7 +508,7 @@ internal class AstChecker(private val program: Program,
fun err(msg: String) = errors.err(msg, decl.position) fun err(msg: String) = errors.err(msg, decl.position)
// the initializer value can't refer to the variable itself (recursive definition) // the initializer value can't refer to the variable itself (recursive definition)
if(decl.value?.referencesIdentifier(decl.name) == true || decl.arraysize?.indexExpr?.referencesIdentifier(decl.name) == true) if(decl.value?.referencesIdentifier(listOf(decl.name)) == true || decl.arraysize?.indexExpr?.referencesIdentifier(listOf(decl.name)) == true)
err("recursive var declaration") err("recursive var declaration")
// CONST can only occur on simple types (byte, word, float) // CONST can only occur on simple types (byte, word, float)

View File

@ -97,21 +97,8 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter)
val nextAssign = assignment.nextSibling() as? Assignment val nextAssign = assignment.nextSibling() as? Assignment
if(nextAssign!=null && nextAssign.target.isSameAs(assignment.target, program)) { if(nextAssign!=null && nextAssign.target.isSameAs(assignment.target, program)) {
// TODO hmm, if both assignments assign to the same thing, can't we just remove the first altogether??? as long as there isn't a function call in the value!
if(nextAssign.value isSameAs assignment.value) if(nextAssign.value isSameAs assignment.value)
return listOf(IAstModification.Remove(assignment, parent as IStatementContainer)) return listOf(IAstModification.Remove(assignment, parent as IStatementContainer))
if((assignment.value as? NumericLiteralValue)?.number==0.0 && nextAssign.isAugmentable) {
val value = nextAssign.value as BinaryExpression
if(value.left isSameAs assignment.target) {
val assign = Assignment(assignment.target, value.right, nextAssign.position)
return listOf(
IAstModification.Remove(assignment, parent as IStatementContainer),
IAstModification.ReplaceNode(nextAssign, assign, parent)
)
}
}
} }
return noModifications return noModifications

View File

@ -12,7 +12,7 @@ import prog8.ast.expressions.IdentifierReference
import prog8.ast.expressions.NumericLiteralValue import prog8.ast.expressions.NumericLiteralValue
import prog8.ast.expressions.PrefixExpression import prog8.ast.expressions.PrefixExpression
import prog8.ast.statements.* import prog8.ast.statements.*
import prog8.compiler.printAst import prog8.compiler.printProgram
import prog8.compiler.target.C64Target import prog8.compiler.target.C64Target
import prog8.compilerinterface.isIOAddress import prog8.compilerinterface.isIOAddress
import prog8.parser.SourceCode import prog8.parser.SourceCode
@ -144,7 +144,7 @@ class TestMemory: FunSpec({
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY) target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
assign = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY) assign = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
wrapWithProgram(listOf(assign)) wrapWithProgram(listOf(assign))
printAst(target.definingModule.program) printProgram(target.definingModule.program)
target.isIOAddress(C64Target.machine) shouldBe true target.isIOAddress(C64Target.machine) shouldBe true
} }

View File

@ -15,6 +15,7 @@ import prog8.ast.base.Position
import prog8.ast.expressions.* import prog8.ast.expressions.*
import prog8.ast.statements.* import prog8.ast.statements.*
import prog8.compiler.BeforeAsmGenerationAstChanger import prog8.compiler.BeforeAsmGenerationAstChanger
import prog8.compiler.printProgram
import prog8.compiler.target.C64Target import prog8.compiler.target.C64Target
import prog8.compilerinterface.* import prog8.compilerinterface.*
import prog8tests.helpers.* import prog8tests.helpers.*
@ -344,9 +345,15 @@ class TestOptimization: FunSpec({
ubyte @shared z1 ubyte @shared z1
z1 = 10 z1 = 10
ubyte @shared z2 ubyte @shared z2
z2 = z1+z2+5 z2 = ~z2
ubyte @shared z3 ubyte @shared z3
z3 = z1+z3-5 z3 = not z3
uword @shared z4
z4 = (z4 as ubyte)
ubyte @shared z5
z5 = z1+z5+5
ubyte @shared z6
z6 = z1+z6-5
} }
}""" }"""
val result = compileText(C64Target, optimize=true, src, writeAssembly=false).assertSuccess() val result = compileText(C64Target, optimize=true, src, writeAssembly=false).assertSuccess()
@ -354,35 +361,53 @@ class TestOptimization: FunSpec({
ubyte z1 ubyte z1
z1 = 10 z1 = 10
ubyte z2 ubyte z2
z2 = z1 z2 = 255
z2 += 5
ubyte z3 ubyte z3
z3 = z1 z3 = 1
z3 -= 5 uword z4
*/ z4 = 0
ubyte z5
z5 = z1
z5 += 5
ubyte z6
z6 = z1
z6 -= 5
*/
val statements = result.program.entrypoint.statements val statements = result.program.entrypoint.statements
statements.size shouldBe 8 statements.size shouldBe 14
val z1decl = statements[0] as VarDecl val z1decl = statements[0] as VarDecl
val z1init = statements[1] as Assignment val z1init = statements[1] as Assignment
val z2decl = statements[2] as VarDecl val z2decl = statements[2] as VarDecl
val z2init = statements[3] as Assignment val z2init = statements[3] as Assignment
val z2plus = statements[4] as Assignment val z3decl = statements[4] as VarDecl
val z3decl = statements[5] as VarDecl val z3init = statements[5] as Assignment
val z3init = statements[6] as Assignment val z4decl = statements[6] as VarDecl
val z3plus = statements[7] as Assignment val z4init = statements[7] as Assignment
val z5decl = statements[8] as VarDecl
val z5init = statements[9] as Assignment
val z5plus = statements[10] as Assignment
val z6decl = statements[11] as VarDecl
val z6init = statements[12] as Assignment
val z6plus = statements[13] as Assignment
z1decl.name shouldBe "z1" z1decl.name shouldBe "z1"
z1init.value shouldBe NumericLiteralValue(DataType.UBYTE, 10.0, Position.DUMMY) z1init.value shouldBe NumericLiteralValue(DataType.UBYTE, 10.0, Position.DUMMY)
z2decl.name shouldBe "z2" z2decl.name shouldBe "z2"
z2init.value shouldBe IdentifierReference(listOf("z1"), Position.DUMMY) z2init.value shouldBe NumericLiteralValue(DataType.UBYTE, 255.0, Position.DUMMY)
z2plus.isAugmentable shouldBe true
(z2plus.value as BinaryExpression).operator shouldBe "+"
(z2plus.value as BinaryExpression).right shouldBe NumericLiteralValue(DataType.UBYTE, 5.0, Position.DUMMY)
z3decl.name shouldBe "z3" z3decl.name shouldBe "z3"
z3init.value shouldBe IdentifierReference(listOf("z1"), Position.DUMMY) z3init.value shouldBe NumericLiteralValue(DataType.UBYTE, 1.0, Position.DUMMY)
z3plus.isAugmentable shouldBe true z4decl.name shouldBe "z4"
(z3plus.value as BinaryExpression).operator shouldBe "-" z4init.value shouldBe NumericLiteralValue(DataType.UBYTE, 0.0, Position.DUMMY)
(z3plus.value as BinaryExpression).right shouldBe NumericLiteralValue(DataType.UBYTE, 5.0, Position.DUMMY) z5decl.name shouldBe "z5"
z5init.value shouldBe IdentifierReference(listOf("z1"), Position.DUMMY)
z5plus.isAugmentable shouldBe true
(z5plus.value as BinaryExpression).operator shouldBe "+"
(z5plus.value as BinaryExpression).right shouldBe NumericLiteralValue(DataType.UBYTE, 5.0, Position.DUMMY)
z6decl.name shouldBe "z6"
z6init.value shouldBe IdentifierReference(listOf("z1"), Position.DUMMY)
z6plus.isAugmentable shouldBe true
(z6plus.value as BinaryExpression).operator shouldBe "-"
(z6plus.value as BinaryExpression).right shouldBe NumericLiteralValue(DataType.UBYTE, 5.0, Position.DUMMY)
} }
test("force_output option should work with optimizing memwrite assignment") { test("force_output option should work with optimizing memwrite assignment") {
@ -472,4 +497,35 @@ class TestOptimization: FunSpec({
val result = compileText(C64Target, optimize=false, src, writeAssembly=true).assertSuccess() val result = compileText(C64Target, optimize=false, src, writeAssembly=true).assertSuccess()
result.program.entrypoint.statements.size shouldBe 10 result.program.entrypoint.statements.size shouldBe 10
} }
test("keep the value initializer assignment if the next one depends on it") {
val src="""
main {
sub start() {
uword @shared yy
yy = 20 ; ok to remove =0 initializer before this
uword @shared zz
zz += 60 ; NOT ok to remove initializer, should evaluate to 60
ubyte @shared xx
xx = 6+sin8u(xx) ; NOT ok to remove initializer
}
}
"""
val result = compileText(C64Target, optimize=true, src, writeAssembly=false).assertSuccess()
printProgram(result.program)
/* expected result:
uword yy
yy = 20
uword zz
zz = 60
ubyte xx
xx = 0
xx = sin8u(xx)
xx += 6
*/
val stmts = result.program.entrypoint.statements
stmts.size shouldBe 8
stmts.filterIsInstance<VarDecl>().size shouldBe 3
stmts.filterIsInstance<Assignment>().size shouldBe 5
}
}) })

View File

@ -9,7 +9,6 @@ import io.kotest.matchers.types.instanceOf
import prog8.ast.base.DataType import prog8.ast.base.DataType
import prog8.ast.expressions.* import prog8.ast.expressions.*
import prog8.ast.statements.* import prog8.ast.statements.*
import prog8.compiler.printAst
import prog8.compiler.target.C64Target import prog8.compiler.target.C64Target
import prog8tests.helpers.ErrorReporterForTests import prog8tests.helpers.ErrorReporterForTests
import prog8tests.helpers.assertFailure import prog8tests.helpers.assertFailure

View File

@ -22,7 +22,7 @@ sealed class Expression: Node {
abstract fun constValue(program: Program): NumericLiteralValue? abstract fun constValue(program: Program): NumericLiteralValue?
abstract fun accept(visitor: IAstVisitor) abstract fun accept(visitor: IAstVisitor)
abstract fun accept(visitor: AstWalker, parent: Node) abstract fun accept(visitor: AstWalker, parent: Node)
abstract fun referencesIdentifier(vararg scopedName: String): Boolean abstract fun referencesIdentifier(nameInSource: List<String>): Boolean
abstract fun inferType(program: Program): InferredTypes.InferredType abstract fun inferType(program: Program): InferredTypes.InferredType
abstract val isSimple: Boolean abstract val isSimple: Boolean
@ -123,7 +123,7 @@ class PrefixExpression(val operator: String, var expression: Expression, overrid
override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent)
override fun referencesIdentifier(vararg scopedName: String) = expression.referencesIdentifier(*scopedName) override fun referencesIdentifier(nameInSource: List<String>) = expression.referencesIdentifier(nameInSource)
override fun inferType(program: Program): InferredTypes.InferredType { override fun inferType(program: Program): InferredTypes.InferredType {
val inferred = expression.inferType(program) val inferred = expression.inferType(program)
return when(operator) { return when(operator) {
@ -183,7 +183,7 @@ class BinaryExpression(var left: Expression, var operator: String, var right: Ex
override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent)
override fun referencesIdentifier(vararg scopedName: String) = left.referencesIdentifier(*scopedName) || right.referencesIdentifier(*scopedName) override fun referencesIdentifier(nameInSource: List<String>) = left.referencesIdentifier(nameInSource) || right.referencesIdentifier(nameInSource)
override fun inferType(program: Program): InferredTypes.InferredType { override fun inferType(program: Program): InferredTypes.InferredType {
val leftDt = left.inferType(program) val leftDt = left.inferType(program)
val rightDt = right.inferType(program) val rightDt = right.inferType(program)
@ -300,7 +300,7 @@ class ArrayIndexedExpression(var arrayvar: IdentifierReference,
override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent)
override fun referencesIdentifier(vararg scopedName: String) = arrayvar.referencesIdentifier(*scopedName) override fun referencesIdentifier(nameInSource: List<String>) = arrayvar.referencesIdentifier(nameInSource)
override fun inferType(program: Program): InferredTypes.InferredType { override fun inferType(program: Program): InferredTypes.InferredType {
val target = arrayvar.targetStatement(program) val target = arrayvar.targetStatement(program)
@ -341,7 +341,7 @@ class TypecastExpression(var expression: Expression, var type: DataType, val imp
override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent)
override fun referencesIdentifier(vararg scopedName: String) = expression.referencesIdentifier(*scopedName) override fun referencesIdentifier(nameInSource: List<String>) = expression.referencesIdentifier(nameInSource)
override fun inferType(program: Program) = InferredTypes.knownFor(type) override fun inferType(program: Program) = InferredTypes.knownFor(type)
override fun constValue(program: Program): NumericLiteralValue? { override fun constValue(program: Program): NumericLiteralValue? {
val cv = expression.constValue(program) ?: return null val cv = expression.constValue(program) ?: return null
@ -378,7 +378,7 @@ data class AddressOf(var identifier: IdentifierReference, override val position:
override fun copy() = AddressOf(identifier.copy(), position) override fun copy() = AddressOf(identifier.copy(), position)
override fun constValue(program: Program): NumericLiteralValue? = null override fun constValue(program: Program): NumericLiteralValue? = null
override fun referencesIdentifier(vararg scopedName: String) = false override fun referencesIdentifier(nameInSource: List<String>) = identifier.nameInSource==nameInSource
override fun inferType(program: Program) = InferredTypes.knownFor(DataType.UWORD) override fun inferType(program: Program) = InferredTypes.knownFor(DataType.UWORD)
override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent)
@ -404,7 +404,7 @@ class DirectMemoryRead(var addressExpression: Expression, override val position:
override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent)
override fun referencesIdentifier(vararg scopedName: String) = false override fun referencesIdentifier(nameInSource: List<String>) = addressExpression.referencesIdentifier(nameInSource)
override fun inferType(program: Program) = InferredTypes.knownFor(DataType.UBYTE) override fun inferType(program: Program) = InferredTypes.knownFor(DataType.UBYTE)
override fun constValue(program: Program): NumericLiteralValue? = null override fun constValue(program: Program): NumericLiteralValue? = null
@ -472,7 +472,7 @@ class NumericLiteralValue(val type: DataType, // only numerical types allowed
throw FatalAstException("can't replace here") throw FatalAstException("can't replace here")
} }
override fun referencesIdentifier(vararg scopedName: String) = false override fun referencesIdentifier(nameInSource: List<String>) = false
override fun constValue(program: Program) = this override fun constValue(program: Program) = this
override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this)
@ -579,7 +579,7 @@ class CharLiteral(val value: Char,
} }
override fun copy() = CharLiteral(value, altEncoding, position) override fun copy() = CharLiteral(value, altEncoding, position)
override fun referencesIdentifier(vararg scopedName: String) = false override fun referencesIdentifier(nameInSource: List<String>) = false
override fun constValue(program: Program): NumericLiteralValue { override fun constValue(program: Program): NumericLiteralValue {
val bytevalue = program.encoding.encodeString(value.toString(), altEncoding).single() val bytevalue = program.encoding.encodeString(value.toString(), altEncoding).single()
return NumericLiteralValue(DataType.UBYTE, bytevalue.toDouble(), position) return NumericLiteralValue(DataType.UBYTE, bytevalue.toDouble(), position)
@ -614,7 +614,7 @@ class StringLiteralValue(val value: String,
throw FatalAstException("can't replace here") throw FatalAstException("can't replace here")
} }
override fun referencesIdentifier(vararg scopedName: String) = false override fun referencesIdentifier(nameInSource: List<String>) = false
override fun constValue(program: Program): NumericLiteralValue? = null override fun constValue(program: Program): NumericLiteralValue? = null
override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent)
@ -650,7 +650,7 @@ class ArrayLiteralValue(val type: InferredTypes.InferredType, // inferred be
replacement.parent = this replacement.parent = this
} }
override fun referencesIdentifier(vararg scopedName: String) = value.any { it.referencesIdentifier(*scopedName) } override fun referencesIdentifier(nameInSource: List<String>) = value.any { it.referencesIdentifier(nameInSource) }
override fun constValue(program: Program): NumericLiteralValue? = null override fun constValue(program: Program): NumericLiteralValue? = null
override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent)
@ -757,7 +757,7 @@ class RangeExpr(var from: Expression,
override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent)
override fun referencesIdentifier(vararg scopedName: String): Boolean = from.referencesIdentifier(*scopedName) || to.referencesIdentifier(*scopedName) override fun referencesIdentifier(nameInSource: List<String>): Boolean = from.referencesIdentifier(nameInSource) || to.referencesIdentifier(nameInSource)
override fun inferType(program: Program): InferredTypes.InferredType { override fun inferType(program: Program): InferredTypes.InferredType {
val fromDt=from.inferType(program) val fromDt=from.inferType(program)
val toDt=to.inferType(program) val toDt=to.inferType(program)
@ -829,8 +829,7 @@ data class IdentifierReference(val nameInSource: List<String>, override val posi
override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent)
override fun referencesIdentifier(vararg scopedName: String): Boolean = override fun referencesIdentifier(nameInSource: List<String>): Boolean = this.nameInSource==nameInSource
nameInSource.size==scopedName.size && nameInSource.toTypedArray().contentEquals(scopedName)
override fun inferType(program: Program): InferredTypes.InferredType { override fun inferType(program: Program): InferredTypes.InferredType {
return when (val targetStmt = targetStatement(program)) { return when (val targetStmt = targetStatement(program)) {
@ -899,7 +898,7 @@ class FunctionCall(override var target: IdentifierReference,
override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent)
override fun referencesIdentifier(vararg scopedName: String): Boolean = target.referencesIdentifier(*scopedName) || args.any{it.referencesIdentifier(*scopedName)} override fun referencesIdentifier(nameInSource: List<String>): Boolean = target.referencesIdentifier(nameInSource) || args.any{it.referencesIdentifier(nameInSource)}
override fun inferType(program: Program): InferredTypes.InferredType { override fun inferType(program: Program): InferredTypes.InferredType {
val constVal = constValue(program ,false) val constVal = constValue(program ,false)

View File

@ -5,8 +5,6 @@ For next compiler release (7.4)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
fix "test augmented expression asmgen" unittest (and textelite compilation) fix "test augmented expression asmgen" unittest (and textelite compilation)
TODO certain typecast expressions are also augmentable?? what does this even mean, and does the generated code make a difference???
optimize TODO in "Add assignment to initialize with zero" in StatementReorderer optimize TODO in "Add assignment to initialize with zero" in StatementReorderer
optimize TODO in after(assignment) in VariousCleanups optimize TODO in after(assignment) in VariousCleanups
optimize: add some more constant folders mentioned in test.p8 optimize: add some more constant folders mentioned in test.p8

View File

@ -11,42 +11,42 @@ main {
byte bb byte bb
float fl float fl
; TODO add these constant folders: ;; TODO add these constant folders:
;
; (X + C1) + (Y + C2) => (X + Y) + (C1 + C2) ;; (X + C1) + (Y + C2) => (X + Y) + (C1 + C2)
; (X + C1) - (Y + C2) => (X - Y) + (C1 - C2) ;; (X + C1) - (Y + C2) => (X - Y) + (C1 - C2)
; ---> together: (X + C1) <plusmin> (Y + C2) => (X <plusmin> Y) + (C1 <plusmin> C2) ;; ---> together: (X + C1) <plusmin> (Y + C2) => (X <plusmin> Y) + (C1 <plusmin> C2)
;
;
; (X - C1) + (Y - C2) => (X + Y) - (C1 + C2) ;; (X - C1) + (Y - C2) => (X + Y) - (C1 + C2)
; (X - C1) - (Y - C2) => (X - Y) - (C1 - C2) ;; (X - C1) - (Y - C2) => (X - Y) - (C1 - C2)
;
xx=6 ; xx=6
yy=8 ; yy=8
;
yy = (xx+5)+(yy+10) ; yy = (xx+5)+(yy+10)
txt.print_ub(yy) ; 29 ; txt.print_ub(yy) ; 29
txt.nl() ; txt.nl()
;
xx=100 ; xx=100
yy=8 ; yy=8
yy = (xx+5)-(yy+10) ; yy = (xx+5)-(yy+10)
txt.print_ub(yy) ; 87 ; txt.print_ub(yy) ; 87
txt.nl() ; txt.nl()
;
xx=50 ; xx=50
yy=40 ; yy=40
yy = (xx-5)+(yy-10) ; yy = (xx-5)+(yy-10)
txt.print_ub(yy) ; 75 ; txt.print_ub(yy) ; 75
txt.nl() ; txt.nl()
;
xx=50 ; xx=50
yy=20 ; yy=20
yy = (xx-5)-(yy-10) ; yy = (xx-5)-(yy-10)
txt.print_ub(yy) ; 35 ; txt.print_ub(yy) ; 35
txt.nl() ; txt.nl()
;
repeat { ; repeat {
} ; }
} }
} }