mirror of
https://github.com/irmen/prog8.git
synced 2024-11-26 11:49:22 +00:00
merge sequential assignments, fix irq
This commit is contained in:
parent
d05169853b
commit
ec770b0f5f
@ -102,7 +102,6 @@ private fun compileMain(args: Array<String>) {
|
||||
}
|
||||
//println(" time1: $time1")
|
||||
val time2 = measureTimeMillis {
|
||||
// @todo this call below is relatively slow
|
||||
moduleAst.constantFold(namespace, heap)
|
||||
}
|
||||
//println(" time2: $time2")
|
||||
@ -111,7 +110,6 @@ private fun compileMain(args: Array<String>) {
|
||||
}
|
||||
//println(" time3: $time3")
|
||||
val time4 = measureTimeMillis {
|
||||
// @todo this call below is relatively slow
|
||||
moduleAst.checkValid(namespace, compilerOptions, heap) // check if tree is valid
|
||||
}
|
||||
//println(" time4: $time4")
|
||||
|
@ -1,5 +1,6 @@
|
||||
package prog8.ast
|
||||
|
||||
import org.antlr.v4.runtime.IntStream
|
||||
import org.antlr.v4.runtime.ParserRuleContext
|
||||
import org.antlr.v4.runtime.tree.TerminalNode
|
||||
import prog8.compiler.HeapValues
|
||||
@ -9,7 +10,7 @@ import prog8.functions.BuiltinFunctions
|
||||
import prog8.functions.NotConstArgumentException
|
||||
import prog8.functions.builtinFunctionReturnType
|
||||
import prog8.parser.prog8Parser
|
||||
import java.nio.file.Paths
|
||||
import java.io.File
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.floor
|
||||
|
||||
@ -1759,7 +1760,11 @@ fun prog8Parser.ModuleContext.toAst(name: String) : Module =
|
||||
|
||||
|
||||
private fun ParserRuleContext.toPosition() : Position {
|
||||
val file = Paths.get(this.start.inputStream.sourceName).fileName.toString()
|
||||
val file =
|
||||
if(start.inputStream.sourceName == IntStream.UNKNOWN_SOURCE_NAME)
|
||||
"<internal>"
|
||||
else
|
||||
File(start.inputStream.sourceName).name
|
||||
// note: be ware of TAB characters in the source text, they count as 1 column...
|
||||
return Position(file, start.line, start.charPositionInLine, stop.charPositionInLine+stop.text.length)
|
||||
}
|
||||
|
@ -106,15 +106,6 @@ class AstChecker(private val namespace: INameScope,
|
||||
if(irqSub!=null) {
|
||||
if(irqSub.parameters.isNotEmpty() || irqSub.returntypes.isNotEmpty())
|
||||
checkResult.add(SyntaxError("irq entrypoint subroutine can't have parameters and/or return values", irqSub.position))
|
||||
} 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.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(0, dummyIrqBlock)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,8 +119,10 @@ class StatementReorderer(private val namespace: INameScope, private val heap: He
|
||||
if(decl.type!=VarDeclType.VAR || decl.value==null)
|
||||
return decl
|
||||
|
||||
// regarding variables that are not on the heap (so: byte, word, float),
|
||||
// replace the var decl with an assignment and add a new vardecl with the default constant value.
|
||||
// Replace the var decl with an assignment and add a new vardecl with the default constant value.
|
||||
// This makes sure the variables get reset to the intended value on a next run of the program.
|
||||
// Variable decls without a value don't get this treatment, which means they retain the last
|
||||
// value they had when restarting the program.
|
||||
if(decl.datatype in NumericDatatypes) {
|
||||
val scope = decl.definingScope()
|
||||
if(scope !in vardeclsToAdd)
|
||||
|
@ -1412,7 +1412,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
private fun translate(stmt: VariableInitializationAssignment) {
|
||||
// this is an assignment to initialize a variable's value in the scope.
|
||||
// the compiler can perhaps optimize this phase.
|
||||
// todo: optimize variable init by keeping track of the block of init values so it can be copied as a whole
|
||||
// todo: optimize variable init by keeping track of the block of init values so it can be copied as a whole via memcopy instead of all separate load value instructions
|
||||
translate(stmt as Assignment)
|
||||
}
|
||||
|
||||
@ -1914,7 +1914,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
continueStmtLabelStack.push(continueLabel)
|
||||
breakStmtLabelStack.push(breakLabel)
|
||||
|
||||
prog.instr(opcodePush(varDt), Value(varDt, range.first)) // @todo use VariableInitializationStatement instead?? (like other for loop)
|
||||
prog.instr(opcodePush(varDt), Value(varDt, range.first))
|
||||
prog.instr(opcodePopvar(varDt), callLabel = varname)
|
||||
prog.label(loopLabel)
|
||||
translate(body)
|
||||
|
@ -11,11 +11,6 @@ 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
|
||||
|
||||
|
||||
todo expression optimization: common (sub) expression elimination (turn common expressions into single subroutine call + introduce variable to hold it)
|
||||
|
||||
*/
|
||||
|
@ -4,7 +4,6 @@ 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
|
||||
|
||||
|
||||
@ -17,8 +16,6 @@ import kotlin.math.floor
|
||||
|
||||
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 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)
|
||||
*/
|
||||
@ -40,6 +37,8 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
|
||||
}
|
||||
|
||||
override fun process(subroutine: Subroutine): IStatement {
|
||||
super.process(subroutine)
|
||||
|
||||
if(subroutine.asmAddress==null) {
|
||||
if(subroutine.statements.isEmpty()) {
|
||||
// remove empty subroutine
|
||||
@ -54,9 +53,54 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.process(subroutine)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
if(linesToRemove.isNotEmpty()) {
|
||||
linesToRemove.reversed().forEach{subroutine.statements.removeAt(it)}
|
||||
}
|
||||
|
||||
return subroutine
|
||||
}
|
||||
|
||||
private fun isNotMemory(target: AssignTarget): Boolean {
|
||||
if(target.register!=null)
|
||||
return true
|
||||
if(target.memoryAddress!=null)
|
||||
return false
|
||||
if(target.arrayindexed!=null) {
|
||||
val targetStmt = target.arrayindexed.identifier.targetStatement(namespace) as? VarDecl
|
||||
if(targetStmt!=null)
|
||||
return targetStmt.type!=VarDeclType.MEMORY
|
||||
}
|
||||
if(target.identifier!=null) {
|
||||
val targetStmt = target.identifier.targetStatement(namespace) as? VarDecl
|
||||
if(targetStmt!=null)
|
||||
return targetStmt.type!=VarDeclType.MEMORY
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
override fun process(functionCall: FunctionCallStatement): IStatement {
|
||||
if(functionCall.target.nameInSource.size==1 && functionCall.target.nameInSource[0] in BuiltinFunctions) {
|
||||
val functionName = functionCall.target.nameInSource[0]
|
||||
@ -424,4 +468,26 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
private fun same(target1: AssignTarget, target2: AssignTarget): Boolean {
|
||||
if(target1===target2)
|
||||
return true
|
||||
if(target1.register!=null && target2.register!=null)
|
||||
return target1.register==target2.register
|
||||
if(target1.identifier!=null && target2.identifier!=null)
|
||||
return target1.identifier.nameInSource==target2.identifier.nameInSource
|
||||
if(target1.memoryAddress!=null && target2.memoryAddress!=null) {
|
||||
val addr1 = target1.memoryAddress!!.addressExpression.constValue(namespace, heap)
|
||||
val addr2 = target2.memoryAddress!!.addressExpression.constValue(namespace, heap)
|
||||
return addr1!=null && addr2!=null && addr1==addr2
|
||||
}
|
||||
if(target1.arrayindexed!=null && target2.arrayindexed!=null) {
|
||||
if(target1.arrayindexed.identifier.nameInSource == target2.arrayindexed.identifier.nameInSource) {
|
||||
val x1 = target1.arrayindexed.arrayspec.x.constValue(namespace, heap)
|
||||
val x2 = target2.arrayindexed.arrayspec.x.constValue(namespace, heap)
|
||||
return x1!=null && x2!=null && x1==x2
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -180,7 +180,6 @@ class StackVm(private var traceOutputFile: String?) {
|
||||
for(i:Int in 1..instructionCount) {
|
||||
try {
|
||||
currentIns = dispatch(currentIns)
|
||||
|
||||
if (evalstack.size > 128)
|
||||
throw VmExecutionException("too many values on evaluation stack")
|
||||
if (callstack.size > 128)
|
||||
|
@ -23,8 +23,9 @@ dontstop:
|
||||
|
||||
sub irq() {
|
||||
ubyte rasterpos=c64.RASTER
|
||||
A=c64.SP0X ; delay for align
|
||||
A=c64.SP0X ; delay for align
|
||||
A*=2 ; delay for align
|
||||
A*=2 ; delay for align
|
||||
A*=2 ; delay for align
|
||||
if color!=len(colors) {
|
||||
c64.EXTCOL = colors[color]
|
||||
c64.RASTER = rasterpos+barheight
|
||||
|
@ -6,19 +6,30 @@
|
||||
sub start() {
|
||||
|
||||
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
|
||||
A=4
|
||||
A=5
|
||||
A=6
|
||||
A=i
|
||||
A=99 ; folded ok!
|
||||
|
||||
i=4
|
||||
i=5
|
||||
i=6
|
||||
i=A
|
||||
i=99 ; folded ok
|
||||
|
||||
@($d020) = 4
|
||||
@($d020) = 5
|
||||
@($d020) = 6
|
||||
@($d020) = 7
|
||||
@($d020) = 8 ; @todo should not be folded
|
||||
|
||||
c64.EXTCOL = 4
|
||||
c64.EXTCOL = 5
|
||||
c64.EXTCOL = 6
|
||||
c64.EXTCOL = 7
|
||||
c64.EXTCOL = 8 ; @todo not fold
|
||||
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user