mirror of
https://github.com/irmen/prog8.git
synced 2024-12-27 05:29:38 +00:00
even more optimizations
This commit is contained in:
parent
5e42c0d736
commit
d05169853b
@ -109,12 +109,12 @@ class AstChecker(private val namespace: INameScope,
|
||||
} else {
|
||||
// @todo this is a little hack to make the assembler happy;
|
||||
// certain assembler routines are -for now- always included and *require* an irq.irq routine to be present
|
||||
val pos = module.statements.last().position
|
||||
val pos = module.statements.first().position
|
||||
val dummyIrqBlock = Block("irq", address = null, statements = mutableListOf(
|
||||
Subroutine("irq", listOf(), listOf(), listOf(), listOf(), setOf(), null, true,mutableListOf(), pos)
|
||||
), position = pos)
|
||||
dummyIrqBlock.linkParents(module)
|
||||
module.statements.add(dummyIrqBlock)
|
||||
module.statements.add(0, dummyIrqBlock)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -236,12 +236,12 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
private fun block2asm(blk: IntermediateProgram.ProgramBlock) {
|
||||
block = blk
|
||||
out("\n; ---- block: '${block.shortname}' ----")
|
||||
if(!blk.force_output)
|
||||
out("${block.shortname}\t.proc\n")
|
||||
if(block.address!=null) {
|
||||
out(".cerror * > ${block.address?.toHex()}, 'block address overlaps by ', *-${block.address?.toHex()},' bytes'")
|
||||
out("* = ${block.address?.toHex()}")
|
||||
}
|
||||
if(!blk.force_output)
|
||||
out("${block.shortname}\t.proc\n")
|
||||
out("\n; memdefs and kernel subroutines")
|
||||
memdefs2asm(block)
|
||||
out("\n; variables")
|
||||
@ -872,6 +872,14 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
sta ${(ESTACK_LO + 1).toHex()},x
|
||||
"""
|
||||
}
|
||||
Opcode.XOR_BYTE -> {
|
||||
"""
|
||||
lda ${(ESTACK_LO + 2).toHex()},x
|
||||
eor ${(ESTACK_LO + 1).toHex()},x
|
||||
inx
|
||||
sta ${(ESTACK_LO + 1).toHex()},x
|
||||
"""
|
||||
}
|
||||
Opcode.REMAINDER_UB -> " jsr prog8_lib.remainder_ub"
|
||||
Opcode.REMAINDER_UW -> " jsr prog8_lib.remainder_uw"
|
||||
|
||||
|
@ -11,6 +11,8 @@ import kotlin.math.log2
|
||||
X*Y - X -> X*(Y-1) ???
|
||||
Y*X - X -> X*(Y-1) ???
|
||||
|
||||
|
||||
|
||||
value <associative_operator> X --> X <associative_operator> value <<<<< should be done already
|
||||
|
||||
|
||||
@ -32,6 +34,43 @@ class SimplifyExpressions(private val namespace: INameScope, private val heap: H
|
||||
// +X --> X
|
||||
optimizationsDone++
|
||||
return expr.expression.process(this)
|
||||
} else if (expr.operator == "not") {
|
||||
(expr.expression as? BinaryExpression)?.let {
|
||||
// NOT (...) -> invert ...
|
||||
when(it.operator) {
|
||||
"<" -> {
|
||||
it.operator = ">="
|
||||
optimizationsDone++
|
||||
return it
|
||||
}
|
||||
">" -> {
|
||||
it.operator = "<="
|
||||
optimizationsDone++
|
||||
return it
|
||||
}
|
||||
"<=" -> {
|
||||
it.operator = ">"
|
||||
optimizationsDone++
|
||||
return it
|
||||
}
|
||||
">=" -> {
|
||||
it.operator = "<"
|
||||
optimizationsDone++
|
||||
return it
|
||||
}
|
||||
"==" -> {
|
||||
it.operator = "!="
|
||||
optimizationsDone++
|
||||
return it
|
||||
}
|
||||
"!=" -> {
|
||||
it.operator = "=="
|
||||
optimizationsDone++
|
||||
return it
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.process(expr)
|
||||
}
|
||||
|
@ -4,25 +4,23 @@ import prog8.ast.*
|
||||
import prog8.compiler.HeapValues
|
||||
import prog8.compiler.target.c64.Petscii
|
||||
import prog8.functions.BuiltinFunctions
|
||||
import sun.font.TrueTypeFont
|
||||
import kotlin.math.floor
|
||||
|
||||
|
||||
/*
|
||||
todo remove empty blocks? already done?
|
||||
todo remove empty subs? already done?
|
||||
|
||||
todo remove unused blocks
|
||||
todo remove unused variables
|
||||
todo remove unused subroutines
|
||||
todo remove unused strings and arrays from the heap
|
||||
todo remove if/while/repeat/for statements with empty statement blocks
|
||||
todo replace if statements with only else block
|
||||
todo regular subroutines that have 1 or 2 (u)byte or 1 (u)word parameters -> change to asmsub to accept these in A/Y registers instead of on stack
|
||||
todo optimize integer addition with self into shift 1 (A+=A -> A<<=1)
|
||||
todo analyse for unreachable code and remove that (f.i. code after goto or return that has no label so can never be jumped to)
|
||||
|
||||
todo regular subroutines that have 1 or 2 (u)byte or 1 (u)word parameters -> change to asmsub to accept these in A/Y registers instead of on stack
|
||||
|
||||
todo merge sequence of assignments into one to avoid repeated value loads (as long as the value is a constant and the target not a MEMORY type!)
|
||||
todo report more always true/always false conditions
|
||||
todo (optionally?) inline subroutines that are "sufficiently small" (=VERY small, say 0-3 statements, otherwise code size will explode and short branches will suffer)
|
||||
|
||||
todo inline subroutines that are called exactly once (regardless of their size)
|
||||
todo inline subroutines that are only called a few times (3?) and that are "sufficiently small" (0-3 statements)
|
||||
*/
|
||||
|
||||
class StatementOptimizer(private val namespace: INameScope, private val heap: HeapValues) : IAstProcessor {
|
||||
@ -32,6 +30,33 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
|
||||
private set
|
||||
private val pureBuiltinFunctions = BuiltinFunctions.filter { it.value.pure }
|
||||
|
||||
override fun process(block: Block): IStatement {
|
||||
if(block.statements.isEmpty()) {
|
||||
// remove empty block
|
||||
optimizationsDone++
|
||||
statementsToRemove.add(block)
|
||||
}
|
||||
return super.process(block)
|
||||
}
|
||||
|
||||
override fun process(subroutine: Subroutine): IStatement {
|
||||
if(subroutine.asmAddress==null) {
|
||||
if(subroutine.statements.isEmpty()) {
|
||||
// remove empty subroutine
|
||||
optimizationsDone++
|
||||
statementsToRemove.add(subroutine)
|
||||
} else if(subroutine.statements.size==1) {
|
||||
val stmt = subroutine.statements[0]
|
||||
if(stmt is ReturnFromIrq || stmt is Return) {
|
||||
// remove empty subroutine
|
||||
optimizationsDone++
|
||||
statementsToRemove.add(subroutine)
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.process(subroutine)
|
||||
}
|
||||
|
||||
override fun process(functionCall: FunctionCallStatement): IStatement {
|
||||
if(functionCall.target.nameInSource.size==1 && functionCall.target.nameInSource[0] in BuiltinFunctions) {
|
||||
val functionName = functionCall.target.nameInSource[0]
|
||||
@ -101,6 +126,22 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
|
||||
|
||||
override fun process(ifStatement: IfStatement): IStatement {
|
||||
super.process(ifStatement)
|
||||
|
||||
if(ifStatement.truepart.isEmpty() && ifStatement.elsepart.isEmpty()) {
|
||||
statementsToRemove.add(ifStatement)
|
||||
optimizationsDone++
|
||||
return ifStatement
|
||||
}
|
||||
|
||||
if(ifStatement.truepart.isEmpty() && ifStatement.elsepart.isNotEmpty()) {
|
||||
// invert the condition and move else part to true part
|
||||
ifStatement.truepart = ifStatement.elsepart
|
||||
ifStatement.elsepart = AnonymousScope(mutableListOf(), ifStatement.elsepart.position)
|
||||
ifStatement.condition = PrefixExpression("not", ifStatement.condition, ifStatement.condition.position)
|
||||
optimizationsDone++
|
||||
return ifStatement
|
||||
}
|
||||
|
||||
val constvalue = ifStatement.condition.constValue(namespace, heap)
|
||||
if(constvalue!=null) {
|
||||
return if(constvalue.asBooleanValue){
|
||||
@ -120,6 +161,22 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
|
||||
|
||||
override fun process(forLoop: ForLoop): IStatement {
|
||||
super.process(forLoop)
|
||||
if(forLoop.body.isEmpty()) {
|
||||
// remove empty for loop
|
||||
statementsToRemove.add(forLoop)
|
||||
optimizationsDone++
|
||||
return forLoop
|
||||
} else if(forLoop.body.statements.size==1) {
|
||||
val loopvar = forLoop.body.statements[0] as? VarDecl
|
||||
if(loopvar!=null && loopvar.name==forLoop.loopVar?.nameInSource?.singleOrNull()) {
|
||||
// remove empty for loop
|
||||
statementsToRemove.add(forLoop)
|
||||
optimizationsDone++
|
||||
return forLoop
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val range = forLoop.iterable as? RangeExpr
|
||||
if(range!=null) {
|
||||
if(range.size(heap)==1) {
|
||||
@ -136,6 +193,12 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
|
||||
|
||||
override fun process(whileLoop: WhileLoop): IStatement {
|
||||
super.process(whileLoop)
|
||||
if(whileLoop.body.isEmpty()) {
|
||||
statementsToRemove.add(whileLoop)
|
||||
optimizationsDone++
|
||||
return whileLoop
|
||||
}
|
||||
|
||||
val constvalue = whileLoop.condition.constValue(namespace, heap)
|
||||
if(constvalue!=null) {
|
||||
return if(constvalue.asBooleanValue){
|
||||
@ -160,6 +223,11 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
|
||||
|
||||
override fun process(repeatLoop: RepeatLoop): IStatement {
|
||||
super.process(repeatLoop)
|
||||
if(repeatLoop.body.isEmpty()) {
|
||||
statementsToRemove.add(repeatLoop)
|
||||
optimizationsDone++
|
||||
return repeatLoop
|
||||
}
|
||||
val constvalue = repeatLoop.untilCondition.constValue(namespace, heap)
|
||||
if(constvalue!=null) {
|
||||
return if(constvalue.asBooleanValue){
|
||||
@ -209,9 +277,17 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
|
||||
val bexpr=assignment.value as? BinaryExpression
|
||||
if(bexpr!=null) {
|
||||
val cv = bexpr.right.constValue(namespace, heap)?.asNumericValue?.toDouble()
|
||||
if(cv!=null) {
|
||||
if(cv==null) {
|
||||
if(bexpr.operator=="+" && targetDt!=DataType.FLOAT) {
|
||||
if (same(bexpr.left, bexpr.right) && same(target, bexpr.left)) {
|
||||
bexpr.operator = "*"
|
||||
bexpr.right = LiteralValue.optimalInteger(2, assignment.value.position)
|
||||
optimizationsDone++
|
||||
return assignment
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (same(target, bexpr.left)) {
|
||||
|
||||
// remove assignments that have no effect X=X , X+=0, X-=0, X*=1, X/=1, X//=1, A |= 0, A ^= 0, A<<=0, etc etc
|
||||
// A = A <operator> B
|
||||
val vardeclDt = (target.identifier?.targetStatement(namespace) as? VarDecl)?.type
|
||||
@ -320,6 +396,21 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
|
||||
return super.process(assignment)
|
||||
}
|
||||
|
||||
|
||||
private fun same(left: IExpression, right: IExpression): Boolean {
|
||||
if(left===right)
|
||||
return true
|
||||
when(left) {
|
||||
is RegisterExpr ->
|
||||
return (right is RegisterExpr && right.register==left.register)
|
||||
is IdentifierReference ->
|
||||
return (right is IdentifierReference && right.nameInSource==left.nameInSource)
|
||||
is ArrayIndexedExpression ->
|
||||
return (right is ArrayIndexedExpression && right.identifier==left.identifier && right.arrayspec==left.arrayspec)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun same(target: AssignTarget, value: IExpression): Boolean {
|
||||
return when {
|
||||
target.memoryAddress!=null -> false
|
||||
|
@ -1,13 +1,25 @@
|
||||
%import c64utils
|
||||
%import c64flt
|
||||
|
||||
~ main {
|
||||
|
||||
sub start() {
|
||||
|
||||
c64scr.print("hoi")
|
||||
c64scr.print("ho") ; @todo 2x CHROUT
|
||||
c64scr.print("h") ; @todo 1x CHROUT
|
||||
c64scr.print("h") ; @todo 1x CHROUT
|
||||
c64scr.print("\n") ; @todo 1x CHROUT
|
||||
ubyte i=101
|
||||
byte b = 40
|
||||
uword j=100
|
||||
word w = 4000
|
||||
float f = 99.9
|
||||
|
||||
A+=A
|
||||
Y+=Y
|
||||
i+=i
|
||||
j+=j
|
||||
b+=b
|
||||
w+=w
|
||||
f+=f
|
||||
; X+=X
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user