mirror of
https://github.com/irmen/prog8.git
synced 2024-12-24 16:29:21 +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
|
||||
}
|
||||
|
||||
fun shortString(): String {
|
||||
fun shortString(withTypePrefix: Boolean=false): String {
|
||||
if(register!=null)
|
||||
return register.toString()
|
||||
return (if(withTypePrefix) "0register::" else "") + register.toString()
|
||||
if(identifier!=null)
|
||||
return identifier.nameInSource.last()
|
||||
return (if(withTypePrefix) "3identifier::" else "") + identifier.nameInSource.last()
|
||||
if(arrayindexed!=null)
|
||||
return arrayindexed.identifier.nameInSource.last()
|
||||
return (if(withTypePrefix) "2arrayidx::" else "") + arrayindexed.identifier.nameInSource.last()
|
||||
val address = memoryAddress?.addressExpression
|
||||
if(address is LiteralValue)
|
||||
return address.asIntegerValue.toString()
|
||||
return "???"
|
||||
return (if(withTypePrefix) "1address::" else "") +address.asIntegerValue.toString()
|
||||
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.
|
||||
|
||||
|
||||
// @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 vardeclsToAdd = mutableMapOf<INameScope, MutableList<VarDecl>>()
|
||||
|
||||
override fun process(module: Module) {
|
||||
super.process(module)
|
||||
|
||||
module.statements = sortConstantAssignments(module.statements)
|
||||
|
||||
val (blocks, other) = module.statements.partition { it is Block }
|
||||
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 {
|
||||
|
||||
block.statements = sortConstantAssignments(block.statements)
|
||||
|
||||
val subroutines = block.statements.filterIsInstance<Subroutine>()
|
||||
var numSubroutinesAtEnd = 0
|
||||
// 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 {
|
||||
super.process(subroutine)
|
||||
|
||||
subroutine.statements = sortConstantAssignments(subroutine.statements)
|
||||
|
||||
val varDecls = subroutine.statements.filterIsInstance<VarDecl>()
|
||||
subroutine.statements.removeAll(varDecls)
|
||||
subroutine.statements.addAll(0, varDecls)
|
||||
@ -120,6 +123,55 @@ class StatementReorderer(private val namespace: INameScope, private val heap: He
|
||||
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 {
|
||||
super.process(decl)
|
||||
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>()
|
||||
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
|
||||
}
|
||||
|
||||
val linesToRemove = deduplicateAssignments(subroutine.statements)
|
||||
if(linesToRemove.isNotEmpty()) {
|
||||
linesToRemove.reversed().forEach{subroutine.statements.removeAt(it)}
|
||||
}
|
||||
@ -82,6 +62,31 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
|
||||
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> {
|
||||
return when {
|
||||
subroutine.returntypes.isEmpty() -> listOf()
|
||||
@ -439,6 +444,14 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
|
||||
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 {
|
||||
return when {
|
||||
target.memoryAddress!=null -> false
|
||||
|
@ -1,11 +1,10 @@
|
||||
<?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">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Python 3.7" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
121
examples/test.p8
121
examples/test.p8
@ -5,14 +5,6 @@
|
||||
|
||||
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 ub2
|
||||
byte b1
|
||||
@ -37,7 +29,118 @@
|
||||
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