mirror of
https://github.com/irmen/prog8.git
synced 2025-01-12 19:29:50 +00:00
optimization and fixes
This commit is contained in:
parent
f3c9be4e06
commit
23afb1ccc2
@ -13,15 +13,15 @@
|
|||||||
|
|
||||||
const uword ESTACK_LO = $ce00
|
const uword ESTACK_LO = $ce00
|
||||||
const uword ESTACK_HI = $cf00
|
const uword ESTACK_HI = $cf00
|
||||||
|
|
||||||
|
|
||||||
; ----- utility functions ----
|
; ----- utility functions ----
|
||||||
|
|
||||||
asmsub init_system () -> clobbers(A,X,Y) -> () {
|
asmsub init_system () -> clobbers(A,X,Y) -> () {
|
||||||
; ---- initializes the machine to a sane starting state
|
; ---- initializes the machine to a sane starting state
|
||||||
; This means that the BASIC, KERNAL and CHARGEN ROMs are banked in,
|
; This means that the BASIC, KERNAL and CHARGEN ROMs are banked in,
|
||||||
; the VIC, SID and CIA chips are reset, screen is cleared, and the default IRQ is set.
|
; the VIC, SID and CIA chips are reset, screen is cleared, and the default IRQ is set.
|
||||||
; Also a different color scheme is chosen to identify ourselves a little.
|
; Also a different color scheme is chosen to identify ourselves a little.
|
||||||
; Uppercase charset is activated, and all three registers set to 0, status flags cleared.
|
; Uppercase charset is activated, and all three registers set to 0, status flags cleared.
|
||||||
%asm {{
|
%asm {{
|
||||||
sei
|
sei
|
||||||
@ -186,7 +186,7 @@ asmsub uword2decimal (uword value @ AY) -> clobbers(A,X,Y) -> () {
|
|||||||
iny
|
iny
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -268,7 +268,7 @@ asmsub str2word(str string @ AY) -> clobbers() -> (word @ AY) {
|
|||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub str2ubyte(str string @ AY) -> clobbers(Y) -> (ubyte @ A) {
|
asmsub str2ubyte(str string @ AY) -> clobbers(Y) -> (ubyte @ A) {
|
||||||
%asm {{
|
%asm {{
|
||||||
;-- convert string (address in A/Y) to ubyte number in A
|
;-- convert string (address in A/Y) to ubyte number in A
|
||||||
@ -276,13 +276,13 @@ asmsub str2ubyte(str string @ AY) -> clobbers(Y) -> (ubyte @ A) {
|
|||||||
jmp str2uword
|
jmp str2uword
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub str2byte(str string @ AY) -> clobbers(Y) -> (byte @ A) {
|
asmsub str2byte(str string @ AY) -> clobbers(Y) -> (byte @ A) {
|
||||||
%asm {{
|
%asm {{
|
||||||
;-- convert string (address in A/Y) to byte number in A
|
;-- convert string (address in A/Y) to byte number in A
|
||||||
; @todo don't use the (slow) kernel floating point conversion
|
; @todo don't use the (slow) kernel floating point conversion
|
||||||
jmp str2word
|
jmp str2word
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -413,10 +413,10 @@ _mod2b lda #0 ; self-modified
|
|||||||
bne -
|
bne -
|
||||||
_done rts
|
_done rts
|
||||||
.pend
|
.pend
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
|
||||||
asmsub set_irqvec_excl() -> clobbers(A) -> () {
|
asmsub set_irqvec_excl() -> clobbers(A) -> () {
|
||||||
%asm {{
|
%asm {{
|
||||||
sei
|
sei
|
||||||
@ -445,11 +445,11 @@ asmsub set_irqvec() -> clobbers(A) -> () {
|
|||||||
rts
|
rts
|
||||||
_irq_handler jsr irq.irq
|
_irq_handler jsr irq.irq
|
||||||
jmp c64.IRQDFRT ; continue with normal kernel irq routine
|
jmp c64.IRQDFRT ; continue with normal kernel irq routine
|
||||||
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
asmsub restore_irqvec() -> clobbers() -> () {
|
asmsub restore_irqvec() -> clobbers() -> () {
|
||||||
%asm {{
|
%asm {{
|
||||||
sei
|
sei
|
||||||
@ -517,7 +517,7 @@ asmsub set_rasterirq_excl(uword rasterpos @ AY) -> clobbers(A) -> () {
|
|||||||
cli
|
cli
|
||||||
rts
|
rts
|
||||||
|
|
||||||
_raster_irq_handler
|
_raster_irq_handler
|
||||||
jsr irq.irq
|
jsr irq.irq
|
||||||
lda #$ff
|
lda #$ff
|
||||||
sta c64.VICIRQ ; acknowledge raster irq
|
sta c64.VICIRQ ; acknowledge raster irq
|
||||||
@ -812,7 +812,7 @@ asmsub print (str text @ AY) -> clobbers(A,Y) -> () {
|
|||||||
; ---- print null terminated string from A/Y
|
; ---- print null terminated string from A/Y
|
||||||
; note: the compiler contains an optimization that will replace
|
; note: the compiler contains an optimization that will replace
|
||||||
; a call to this subroutine with a string argument of just one char,
|
; a call to this subroutine with a string argument of just one char,
|
||||||
; by just one call to c64.CHROUT of that single char. @todo do this
|
; by just one call to c64.CHROUT of that single char.
|
||||||
%asm {{
|
%asm {{
|
||||||
sta c64.SCRATCH_ZPB1
|
sta c64.SCRATCH_ZPB1
|
||||||
sty c64.SCRATCH_ZPREG
|
sty c64.SCRATCH_ZPREG
|
||||||
@ -881,7 +881,7 @@ _print_tens txa
|
|||||||
jmp c64.CHROUT
|
jmp c64.CHROUT
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub print_b (byte value @ A) -> clobbers(A,X,Y) -> () {
|
asmsub print_b (byte value @ A) -> clobbers(A,X,Y) -> () {
|
||||||
; ---- print the byte in A in decimal form, without left padding 0s
|
; ---- print the byte in A in decimal form, without left padding 0s
|
||||||
%asm {{
|
%asm {{
|
||||||
@ -1066,7 +1066,7 @@ asmsub setchr (ubyte col @Y, ubyte row @A) -> clobbers(A) -> () {
|
|||||||
+ lda c64.SCRATCH_ZPB1
|
+ lda c64.SCRATCH_ZPB1
|
||||||
_mod sta $ffff ; modified
|
_mod sta $ffff ; modified
|
||||||
rts
|
rts
|
||||||
|
|
||||||
_screenrows .word $0400 + range(0, 1000, 40)
|
_screenrows .word $0400 + range(0, 1000, 40)
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
@ -1088,12 +1088,12 @@ asmsub setclr (ubyte col @Y, ubyte row @A) -> clobbers(A) -> () {
|
|||||||
+ lda c64.SCRATCH_ZPB1
|
+ lda c64.SCRATCH_ZPB1
|
||||||
_mod sta $ffff ; modified
|
_mod sta $ffff ; modified
|
||||||
rts
|
rts
|
||||||
|
|
||||||
_colorrows .word $d800 + range(0, 1000, 40)
|
_colorrows .word $d800 + range(0, 1000, 40)
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sub setcc (ubyte column, ubyte row, ubyte char, ubyte color) {
|
sub setcc (ubyte column, ubyte row, ubyte char, ubyte color) {
|
||||||
; ---- set char+color at the given position on the screen
|
; ---- set char+color at the given position on the screen
|
||||||
%asm {{
|
%asm {{
|
||||||
@ -1117,7 +1117,7 @@ _charmod sta $ffff ; modified
|
|||||||
lda setcc_color
|
lda setcc_color
|
||||||
_colormod sta $ffff ; modified
|
_colormod sta $ffff ; modified
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub PLOT (ubyte col @ Y, ubyte row @ A) -> clobbers(A) -> () {
|
asmsub PLOT (ubyte col @ Y, ubyte row @ A) -> clobbers(A) -> () {
|
||||||
|
@ -102,7 +102,7 @@ private fun compileMain(args: Array<String>) {
|
|||||||
}
|
}
|
||||||
//println(" time1: $time1")
|
//println(" time1: $time1")
|
||||||
val time2 = measureTimeMillis {
|
val time2 = measureTimeMillis {
|
||||||
// @todo this is slow!
|
// @todo this call below is relatively slow
|
||||||
moduleAst.constantFold(namespace, heap)
|
moduleAst.constantFold(namespace, heap)
|
||||||
}
|
}
|
||||||
//println(" time2: $time2")
|
//println(" time2: $time2")
|
||||||
@ -111,7 +111,7 @@ private fun compileMain(args: Array<String>) {
|
|||||||
}
|
}
|
||||||
//println(" time3: $time3")
|
//println(" time3: $time3")
|
||||||
val time4 = measureTimeMillis {
|
val time4 = measureTimeMillis {
|
||||||
// @todo this is slow!
|
// @todo this call below is relatively slow
|
||||||
moduleAst.checkValid(namespace, compilerOptions, heap) // check if tree is valid
|
moduleAst.checkValid(namespace, compilerOptions, heap) // check if tree is valid
|
||||||
}
|
}
|
||||||
//println(" time4: $time4")
|
//println(" time4: $time4")
|
||||||
|
@ -1429,6 +1429,11 @@ data class IdentifierReference(val nameInSource: List<String>, override val posi
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun isIterable(namespace: INameScope, heap: HeapValues): Boolean = resultingDatatype(namespace, heap) in IterableDatatypes
|
override fun isIterable(namespace: INameScope, heap: HeapValues): Boolean = resultingDatatype(namespace, heap) in IterableDatatypes
|
||||||
|
|
||||||
|
fun heapId(namespace: INameScope): Int {
|
||||||
|
val node = namespace.lookup(nameInSource, this) ?: throw UndefinedSymbolError(this)
|
||||||
|
return ((node as? VarDecl)?.value as? LiteralValue)?.heapId ?: throw FatalAstException("identifier is not on the heap")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,11 +21,15 @@ fun Module.checkIdentifiers(heap: HeapValues): MutableMap<String, IStatement> {
|
|||||||
val parent = variable.first.parent
|
val parent = variable.first.parent
|
||||||
when {
|
when {
|
||||||
parent is Assignment && parent.value === variable.first -> {
|
parent is Assignment && parent.value === variable.first -> {
|
||||||
parent.value = IdentifierReference(listOf("auto_heap_value_${variable.first.heapId}"), variable.first.position)
|
val idref = IdentifierReference(listOf("auto_heap_value_${variable.first.heapId}"), variable.first.position)
|
||||||
|
idref.linkParents(parent)
|
||||||
|
parent.value = idref
|
||||||
}
|
}
|
||||||
parent is IFunctionCall -> {
|
parent is IFunctionCall -> {
|
||||||
val parameterPos = parent.arglist.indexOf(variable.first)
|
val parameterPos = parent.arglist.indexOf(variable.first)
|
||||||
parent.arglist[parameterPos] = IdentifierReference(listOf("auto_heap_value_${variable.first.heapId}"), variable.first.position)
|
val idref = IdentifierReference(listOf("auto_heap_value_${variable.first.heapId}"), variable.first.position)
|
||||||
|
idref.linkParents(parent)
|
||||||
|
parent.arglist[parameterPos] = idref
|
||||||
}
|
}
|
||||||
else -> TODO("replace literalvalue by identifierref: $variable (in $parent)")
|
else -> TODO("replace literalvalue by identifierref: $variable (in $parent)")
|
||||||
}
|
}
|
||||||
|
@ -99,6 +99,8 @@ class HeapValues {
|
|||||||
|
|
||||||
fun get(heapId: Int): HeapValue = heap[heapId]
|
fun get(heapId: Int): HeapValue = heap[heapId]
|
||||||
|
|
||||||
|
// TODO remove function
|
||||||
|
|
||||||
fun allEntries() = heap.withIndex().toList()
|
fun allEntries() = heap.withIndex().toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2049,37 +2051,34 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
|||||||
}
|
}
|
||||||
// todo deal with target.arrayindexed?
|
// todo deal with target.arrayindexed?
|
||||||
|
|
||||||
|
fun createLoopCode(step: Int) {
|
||||||
|
if(step!=1 && step !=-1)
|
||||||
|
TODO("can't generate code for step other than 1 or -1 right now")
|
||||||
|
|
||||||
|
// LV++ / LV--
|
||||||
|
val postIncr = PostIncrDecr(lvTarget, if(step==1) "++" else "--", range.position)
|
||||||
|
postIncr.linkParents(body)
|
||||||
|
translate(postIncr)
|
||||||
|
if(lvTarget.register!=null)
|
||||||
|
prog.instr(Opcode.PUSH_VAR_BYTE, callLabel =lvTarget.register.toString())
|
||||||
|
else {
|
||||||
|
val opcode = opcodePushvar(targetStatement!!.datatype)
|
||||||
|
prog.instr(opcode, callLabel = targetStatement.scopedname)
|
||||||
|
}
|
||||||
|
val branch = BranchStatement(
|
||||||
|
BranchCondition.NZ,
|
||||||
|
AnonymousScope(mutableListOf(Jump(null, null, loopLabel, range.position)), range.position),
|
||||||
|
AnonymousScope(mutableListOf(), range.position),
|
||||||
|
range.position)
|
||||||
|
branch.linkParents(body)
|
||||||
|
translate(branch)
|
||||||
|
}
|
||||||
|
|
||||||
when (literalStepValue) {
|
when (literalStepValue) {
|
||||||
1 -> {
|
1 -> createLoopCode(1)
|
||||||
// LV++
|
-1 -> createLoopCode(-1)
|
||||||
val postIncr = PostIncrDecr(lvTarget, "++", range.position)
|
null -> TODO("variable range forloop non-literal-const step increment, At: ${range.position}")
|
||||||
postIncr.linkParents(body)
|
else -> TODO("variable range forloop step increment not 1 or -1, At: ${range.position}")
|
||||||
translate(postIncr)
|
|
||||||
if(lvTarget.register!=null)
|
|
||||||
prog.instr(Opcode.PUSH_VAR_BYTE, callLabel =lvTarget.register.toString())
|
|
||||||
else {
|
|
||||||
val opcode = opcodePushvar(targetStatement!!.datatype)
|
|
||||||
prog.instr(opcode, callLabel = targetStatement.scopedname)
|
|
||||||
}
|
|
||||||
val branch = BranchStatement(
|
|
||||||
BranchCondition.NZ,
|
|
||||||
AnonymousScope(mutableListOf(Jump(null, null, loopLabel, range.position)), range.position),
|
|
||||||
AnonymousScope(mutableListOf(), range.position),
|
|
||||||
range.position)
|
|
||||||
branch.linkParents(body)
|
|
||||||
translate(branch)
|
|
||||||
}
|
|
||||||
-1 -> {
|
|
||||||
// LV--
|
|
||||||
val postIncr = PostIncrDecr(makeAssignmentTarget(), "--", range.position)
|
|
||||||
postIncr.linkParents(body)
|
|
||||||
translate(postIncr)
|
|
||||||
TODO("signed numbers and/or special condition are needed for decreasing for loop. Try an increasing loop and/or constant loop values instead? At: ${range.position}") // fix with signed numbers
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
TODO("non-literal-const or other-than-one step increment code At: ${range.position}")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
prog.label(breakLabel)
|
prog.label(breakLabel)
|
||||||
|
@ -2,6 +2,7 @@ package prog8.optimizing
|
|||||||
|
|
||||||
import prog8.ast.*
|
import prog8.ast.*
|
||||||
import prog8.compiler.HeapValues
|
import prog8.compiler.HeapValues
|
||||||
|
import prog8.compiler.target.c64.Petscii
|
||||||
import prog8.functions.BuiltinFunctions
|
import prog8.functions.BuiltinFunctions
|
||||||
import kotlin.math.floor
|
import kotlin.math.floor
|
||||||
|
|
||||||
@ -37,6 +38,37 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
|
|||||||
if (functionName in pureBuiltinFunctions) {
|
if (functionName in pureBuiltinFunctions) {
|
||||||
printWarning("statement has no effect (function return value is discarded)", functionCall.position)
|
printWarning("statement has no effect (function return value is discarded)", functionCall.position)
|
||||||
statementsToRemove.add(functionCall)
|
statementsToRemove.add(functionCall)
|
||||||
|
return functionCall
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(functionCall.target.nameInSource==listOf("c64scr", "print") ||
|
||||||
|
functionCall.target.nameInSource==listOf("c64scr", "print_p")) {
|
||||||
|
// printing a literal string of just 2 or 1 characters is replaced by directly outputting those characters
|
||||||
|
if(functionCall.arglist.single() is LiteralValue)
|
||||||
|
throw AstException("string argument should be on heap already")
|
||||||
|
val stringVar = functionCall.arglist.single() as? IdentifierReference
|
||||||
|
if(stringVar!=null) {
|
||||||
|
val heapId = stringVar.heapId(namespace)
|
||||||
|
val string = heap.get(heapId).str!!
|
||||||
|
// TODO heap.remove(heapId)
|
||||||
|
if(string.length==1) {
|
||||||
|
val petscii = Petscii.encodePetscii(string, true)[0]
|
||||||
|
functionCall.arglist.clear()
|
||||||
|
functionCall.arglist.add(LiteralValue.optimalInteger(petscii, functionCall.position))
|
||||||
|
functionCall.target = IdentifierReference(listOf("c64", "CHROUT"), functionCall.target.position)
|
||||||
|
optimizationsDone++
|
||||||
|
return functionCall
|
||||||
|
} else if(string.length==2) {
|
||||||
|
val petscii = Petscii.encodePetscii(string, true)
|
||||||
|
val scope = AnonymousScope(mutableListOf(), functionCall.position)
|
||||||
|
scope.statements.add(FunctionCallStatement(IdentifierReference(listOf("c64", "CHROUT"), functionCall.target.position),
|
||||||
|
mutableListOf(LiteralValue.optimalInteger(petscii[0], functionCall.position)), functionCall.position))
|
||||||
|
scope.statements.add(FunctionCallStatement(IdentifierReference(listOf("c64", "CHROUT"), functionCall.target.position),
|
||||||
|
mutableListOf(LiteralValue.optimalInteger(petscii[1], functionCall.position)), functionCall.position))
|
||||||
|
optimizationsDone++
|
||||||
|
return scope
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,48 +1,13 @@
|
|||||||
%import c64utils
|
%import c64utils
|
||||||
%import c64flt
|
|
||||||
|
|
||||||
~ main {
|
~ main {
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
|
|
||||||
uword[4] uwa = 5
|
c64scr.print("hoi")
|
||||||
ubyte[4] uba = 5
|
c64scr.print("ho") ; @todo 2x CHROUT
|
||||||
word[4] wa = 5
|
c64scr.print("h") ; @todo 1x CHROUT
|
||||||
byte[4] ba = 5
|
c64scr.print("h") ; @todo 1x CHROUT
|
||||||
float[4] fa = 5.123
|
c64scr.print("\n") ; @todo 1x CHROUT
|
||||||
str naam = "irmen"
|
|
||||||
float ff = 3.4444
|
|
||||||
|
|
||||||
uword addr
|
|
||||||
|
|
||||||
addr = naam
|
|
||||||
addr = uwa
|
|
||||||
addr = fa
|
|
||||||
|
|
||||||
pairAX(naam)
|
|
||||||
pairAX("hello")
|
|
||||||
pairAX("hello2")
|
|
||||||
pairAX("hello2")
|
|
||||||
pairAX("hello2")
|
|
||||||
pairAY("hello2")
|
|
||||||
pairAY("hello2")
|
|
||||||
pairXY("hello2")
|
|
||||||
pairXY("hello2")
|
|
||||||
pairAX(uwa)
|
|
||||||
pairAX(fa)
|
|
||||||
pairAY(naam)
|
|
||||||
pairAY(uwa)
|
|
||||||
pairAY(fa)
|
|
||||||
pairXY(naam)
|
|
||||||
pairXY(uwa)
|
|
||||||
pairXY(fa)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
asmsub pairAX(uword address @ AX) -> clobbers() -> () {
|
|
||||||
}
|
|
||||||
asmsub pairAY(uword address @ AY) -> clobbers() -> () {
|
|
||||||
}
|
|
||||||
asmsub pairXY(uword address @ XY) -> clobbers() -> () {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user