mirror of
https://github.com/irmen/prog8.git
synced 2024-11-26 11:49:22 +00:00
sort assignments to enable same-value optimization
This commit is contained in:
parent
d37c9d1680
commit
39a5e341af
@ -781,17 +781,17 @@ data class AssignTarget(val register: Register?,
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun shortString(): String {
|
fun shortString(withTypePrefix: Boolean=false): String {
|
||||||
if(register!=null)
|
if(register!=null)
|
||||||
return register.toString()
|
return (if(withTypePrefix) "0register::" else "") + register.toString()
|
||||||
if(identifier!=null)
|
if(identifier!=null)
|
||||||
return identifier.nameInSource.last()
|
return (if(withTypePrefix) "3identifier::" else "") + identifier.nameInSource.last()
|
||||||
if(arrayindexed!=null)
|
if(arrayindexed!=null)
|
||||||
return arrayindexed.identifier.nameInSource.last()
|
return (if(withTypePrefix) "2arrayidx::" else "") + arrayindexed.identifier.nameInSource.last()
|
||||||
val address = memoryAddress?.addressExpression
|
val address = memoryAddress?.addressExpression
|
||||||
if(address is LiteralValue)
|
if(address is LiteralValue)
|
||||||
return address.asIntegerValue.toString()
|
return (if(withTypePrefix) "1address::" else "") +address.asIntegerValue.toString()
|
||||||
return "???"
|
return if(withTypePrefix) "???::???" else "???"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,17 +15,14 @@ class StatementReorderer(private val namespace: INameScope, private val heap: He
|
|||||||
// - all other subroutines will be moved to the end of their block.
|
// - all other subroutines will be moved to the end of their block.
|
||||||
|
|
||||||
|
|
||||||
// @todo sort the VariableInitializations and normal assignments: as long as the values are constants and they follow eachother without other stmts inbetween. something like this:
|
|
||||||
// // sort by datatype and value, so multiple initializations with the same value can be optimized (to load the value just once)
|
|
||||||
// val sortedInits = varinits.sortedWith(compareBy({it.value.resultingDatatype(namespace, heap)}, {it.value.constValue(namespace, heap)?.asNumericValue?.toDouble()}))
|
|
||||||
|
|
||||||
|
|
||||||
private val directivesToMove = setOf("%output", "%launcher", "%zeropage", "%zpreserved", "%address", "%option")
|
private val directivesToMove = setOf("%output", "%launcher", "%zeropage", "%zpreserved", "%address", "%option")
|
||||||
private val vardeclsToAdd = mutableMapOf<INameScope, MutableList<VarDecl>>()
|
private val vardeclsToAdd = mutableMapOf<INameScope, MutableList<VarDecl>>()
|
||||||
|
|
||||||
override fun process(module: Module) {
|
override fun process(module: Module) {
|
||||||
super.process(module)
|
super.process(module)
|
||||||
|
|
||||||
|
module.statements = sortConstantAssignments(module.statements)
|
||||||
|
|
||||||
val (blocks, other) = module.statements.partition { it is Block }
|
val (blocks, other) = module.statements.partition { it is Block }
|
||||||
module.statements = other.asSequence().plus(blocks.sortedBy { (it as Block).address ?: Int.MAX_VALUE }).toMutableList()
|
module.statements = other.asSequence().plus(blocks.sortedBy { (it as Block).address ?: Int.MAX_VALUE }).toMutableList()
|
||||||
|
|
||||||
@ -51,6 +48,9 @@ class StatementReorderer(private val namespace: INameScope, private val heap: He
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun process(block: Block): IStatement {
|
override fun process(block: Block): IStatement {
|
||||||
|
|
||||||
|
block.statements = sortConstantAssignments(block.statements)
|
||||||
|
|
||||||
val subroutines = block.statements.filterIsInstance<Subroutine>()
|
val subroutines = block.statements.filterIsInstance<Subroutine>()
|
||||||
var numSubroutinesAtEnd = 0
|
var numSubroutinesAtEnd = 0
|
||||||
// move all subroutines to the end of the block
|
// move all subroutines to the end of the block
|
||||||
@ -98,6 +98,9 @@ class StatementReorderer(private val namespace: INameScope, private val heap: He
|
|||||||
|
|
||||||
override fun process(subroutine: Subroutine): IStatement {
|
override fun process(subroutine: Subroutine): IStatement {
|
||||||
super.process(subroutine)
|
super.process(subroutine)
|
||||||
|
|
||||||
|
subroutine.statements = sortConstantAssignments(subroutine.statements)
|
||||||
|
|
||||||
val varDecls = subroutine.statements.filterIsInstance<VarDecl>()
|
val varDecls = subroutine.statements.filterIsInstance<VarDecl>()
|
||||||
subroutine.statements.removeAll(varDecls)
|
subroutine.statements.removeAll(varDecls)
|
||||||
subroutine.statements.addAll(0, varDecls)
|
subroutine.statements.addAll(0, varDecls)
|
||||||
@ -120,6 +123,55 @@ class StatementReorderer(private val namespace: INameScope, private val heap: He
|
|||||||
return subroutine
|
return subroutine
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun process(scope: AnonymousScope): AnonymousScope {
|
||||||
|
scope.statements = sortConstantAssignments(scope.statements)
|
||||||
|
return super.process(scope)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun sortConstantAssignments(statements: MutableList<IStatement>): MutableList<IStatement> {
|
||||||
|
// sort assignments by datatype and value, so multiple initializations with the same value can be optimized (to load the value just once)
|
||||||
|
val result = mutableListOf<IStatement>()
|
||||||
|
val stmtIter = statements.iterator()
|
||||||
|
for(stmt in stmtIter) {
|
||||||
|
if(stmt is Assignment) {
|
||||||
|
val constval = stmt.value.constValue(namespace, heap)
|
||||||
|
if(constval!=null) {
|
||||||
|
val (sorted, trailing) = sortConstantAssignmentSequence(stmt, stmtIter)
|
||||||
|
result.addAll(sorted)
|
||||||
|
if(trailing!=null)
|
||||||
|
result.add(trailing)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
result.add(stmt)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
result.add(stmt)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun sortConstantAssignmentSequence(first: Assignment, stmtIter: MutableIterator<IStatement>): Pair<List<Assignment>, IStatement?> {
|
||||||
|
val sequence= mutableListOf<Assignment>(first)
|
||||||
|
var trailing: IStatement? = null
|
||||||
|
while(stmtIter.hasNext()) {
|
||||||
|
val next = stmtIter.next()
|
||||||
|
if(next is Assignment) {
|
||||||
|
val constValue = next.value.constValue(namespace, heap)
|
||||||
|
if(constValue==null) {
|
||||||
|
trailing = next
|
||||||
|
break
|
||||||
|
}
|
||||||
|
sequence.add(next)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
trailing=next
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val sorted = sequence.sortedWith(compareBy({it.value.resultingDatatype(namespace, heap)}, {it.singleTarget?.shortString(true)}))
|
||||||
|
return Pair(sorted, trailing)
|
||||||
|
}
|
||||||
|
|
||||||
override fun process(decl: VarDecl): IStatement {
|
override fun process(decl: VarDecl): IStatement {
|
||||||
super.process(decl)
|
super.process(decl)
|
||||||
if(decl.type!=VarDeclType.VAR || decl.value==null)
|
if(decl.type!=VarDeclType.VAR || decl.value==null)
|
||||||
|
@ -54,27 +54,7 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val linesToRemove = mutableListOf<Int>()
|
val linesToRemove = deduplicateAssignments(subroutine.statements)
|
||||||
var previousAssignmentLine: Int? = null
|
|
||||||
for(i in 0 until subroutine.statements.size) {
|
|
||||||
val stmt = subroutine.statements[i] as? Assignment
|
|
||||||
if(stmt!=null) {
|
|
||||||
if(previousAssignmentLine==null) {
|
|
||||||
previousAssignmentLine = i
|
|
||||||
continue
|
|
||||||
} else {
|
|
||||||
val prev = subroutine.statements[previousAssignmentLine] as Assignment
|
|
||||||
if(prev.targets.size==1 && stmt.targets.size==1 && same(prev.targets[0], stmt.targets[0])) {
|
|
||||||
// get rid of the previous assignment, if the target is not MEMORY
|
|
||||||
if(isNotMemory(prev.targets[0]))
|
|
||||||
linesToRemove.add(previousAssignmentLine)
|
|
||||||
}
|
|
||||||
previousAssignmentLine = i
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
previousAssignmentLine=null
|
|
||||||
}
|
|
||||||
|
|
||||||
if(linesToRemove.isNotEmpty()) {
|
if(linesToRemove.isNotEmpty()) {
|
||||||
linesToRemove.reversed().forEach{subroutine.statements.removeAt(it)}
|
linesToRemove.reversed().forEach{subroutine.statements.removeAt(it)}
|
||||||
}
|
}
|
||||||
@ -82,6 +62,31 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
|
|||||||
return subroutine
|
return subroutine
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun deduplicateAssignments(statements: List<IStatement>): MutableList<Int> {
|
||||||
|
// removes 'duplicate' assignments that assign the same target
|
||||||
|
val linesToRemove = mutableListOf<Int>()
|
||||||
|
var previousAssignmentLine: Int? = null
|
||||||
|
for (i in 0 until statements.size) {
|
||||||
|
val stmt = statements[i] as? Assignment
|
||||||
|
if (stmt != null) {
|
||||||
|
if (previousAssignmentLine == null) {
|
||||||
|
previousAssignmentLine = i
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
val prev = statements[previousAssignmentLine] as Assignment
|
||||||
|
if (prev.targets.size == 1 && stmt.targets.size == 1 && same(prev.targets[0], stmt.targets[0])) {
|
||||||
|
// get rid of the previous assignment, if the target is not MEMORY
|
||||||
|
if (isNotMemory(prev.targets[0]))
|
||||||
|
linesToRemove.add(previousAssignmentLine)
|
||||||
|
}
|
||||||
|
previousAssignmentLine = i
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
previousAssignmentLine = null
|
||||||
|
}
|
||||||
|
return linesToRemove
|
||||||
|
}
|
||||||
|
|
||||||
private fun returnregisters(subroutine: Subroutine): List<RegisterOrStatusflag> {
|
private fun returnregisters(subroutine: Subroutine): List<RegisterOrStatusflag> {
|
||||||
return when {
|
return when {
|
||||||
subroutine.returntypes.isEmpty() -> listOf()
|
subroutine.returntypes.isEmpty() -> listOf()
|
||||||
@ -439,6 +444,14 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
|
|||||||
return super.process(assignment)
|
return super.process(assignment)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun process(scope: AnonymousScope): AnonymousScope {
|
||||||
|
val linesToRemove = deduplicateAssignments(scope.statements)
|
||||||
|
if(linesToRemove.isNotEmpty()) {
|
||||||
|
linesToRemove.reversed().forEach{scope.statements.removeAt(it)}
|
||||||
|
}
|
||||||
|
return super.process(scope)
|
||||||
|
}
|
||||||
|
|
||||||
private fun same(target: AssignTarget, value: IExpression): Boolean {
|
private fun same(target: AssignTarget, value: IExpression): Boolean {
|
||||||
return when {
|
return when {
|
||||||
target.memoryAddress!=null -> false
|
target.memoryAddress!=null -> false
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<module type="PYTHON_MODULE" version="4">
|
<module type="WEB_MODULE" version="4">
|
||||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
<exclude-output />
|
<exclude-output />
|
||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="jdk" jdkName="Python 3.7" jdkType="Python SDK" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
121
examples/test.p8
121
examples/test.p8
@ -5,14 +5,6 @@
|
|||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
|
|
||||||
memset($0400+40*3, 40*8, 81)
|
|
||||||
memsetw($0400+40*12, 8*40/2, $80a0)
|
|
||||||
memset($0400, 20, 33)
|
|
||||||
memcopy($0400, $0400+121, 20)
|
|
||||||
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
ubyte ub1
|
ubyte ub1
|
||||||
ubyte ub2
|
ubyte ub2
|
||||||
byte b1
|
byte b1
|
||||||
@ -37,7 +29,118 @@
|
|||||||
word[3] wa2
|
word[3] wa2
|
||||||
|
|
||||||
|
|
||||||
ub1=ub2*ub1
|
A=$34
|
||||||
|
Y=$34
|
||||||
|
ub1=$33
|
||||||
|
ub1=$34
|
||||||
|
ub2=1
|
||||||
|
ub2=2
|
||||||
|
ub2=3
|
||||||
|
ub2=4
|
||||||
|
ub2=$34
|
||||||
|
uw1=0
|
||||||
|
uw1=1
|
||||||
|
uw1=$0034
|
||||||
|
w1=1
|
||||||
|
w1=2
|
||||||
|
w1=3
|
||||||
|
w1=$0034
|
||||||
|
|
||||||
|
|
||||||
|
if A>5 {
|
||||||
|
A=$34
|
||||||
|
Y=$34
|
||||||
|
ub1=$33
|
||||||
|
ub1=$34
|
||||||
|
ub2=1
|
||||||
|
ub2=2
|
||||||
|
ub2=3
|
||||||
|
ub2=4
|
||||||
|
ub2=$34
|
||||||
|
uw1=0
|
||||||
|
uw1=1
|
||||||
|
uw1=$0034
|
||||||
|
w1=1
|
||||||
|
w1=2
|
||||||
|
w1=3
|
||||||
|
w1=$0034
|
||||||
|
|
||||||
|
} else {
|
||||||
|
A=$34
|
||||||
|
Y=$34
|
||||||
|
ub1=$33
|
||||||
|
ub1=$34
|
||||||
|
ub2=1
|
||||||
|
ub2=2
|
||||||
|
ub2=3
|
||||||
|
ub2=4
|
||||||
|
ub2=$34
|
||||||
|
uw1=0
|
||||||
|
uw1=1
|
||||||
|
uw1=$0034
|
||||||
|
w1=1
|
||||||
|
w1=2
|
||||||
|
w1=3
|
||||||
|
w1=$0034
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
A=$34
|
||||||
|
Y=$34
|
||||||
|
ub1=$33
|
||||||
|
ub1=$34
|
||||||
|
ub2=1
|
||||||
|
ub2=2
|
||||||
|
ub2=3
|
||||||
|
ub2=4
|
||||||
|
ub2=$34
|
||||||
|
uw1=0
|
||||||
|
uw1=1
|
||||||
|
uw1=$0034
|
||||||
|
w1=1
|
||||||
|
w1=2
|
||||||
|
w1=3
|
||||||
|
w1=$0034
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
repeat {
|
||||||
|
A=$34
|
||||||
|
Y=$34
|
||||||
|
ub1=$33
|
||||||
|
ub1=$34
|
||||||
|
ub2=1
|
||||||
|
ub2=2
|
||||||
|
ub2=3
|
||||||
|
ub2=4
|
||||||
|
ub2=$34
|
||||||
|
uw1=0
|
||||||
|
uw1=1
|
||||||
|
uw1=$0034
|
||||||
|
w1=1
|
||||||
|
w1=2
|
||||||
|
w1=3
|
||||||
|
w1=$0034
|
||||||
|
|
||||||
|
} until(true)
|
||||||
|
|
||||||
|
A=$34
|
||||||
|
Y=$34
|
||||||
|
ub1=$33
|
||||||
|
ub1=$34
|
||||||
|
ub2=1
|
||||||
|
ub2=2
|
||||||
|
ub2=3
|
||||||
|
ub2=4
|
||||||
|
ub2=$34
|
||||||
|
uw1=0
|
||||||
|
uw1=1
|
||||||
|
uw1=$0034
|
||||||
|
w1=1
|
||||||
|
w1=2
|
||||||
|
w1=3
|
||||||
|
w1=$0034
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user