mirror of
https://github.com/irmen/prog8.git
synced 2024-10-25 00:24:16 +00:00
variable zp allocation now only done in the allocator
This commit is contained in:
parent
1307bdc612
commit
f3c52c409f
@ -1,6 +1,5 @@
|
|||||||
package prog8.codegen.cpu6502
|
package prog8.codegen.cpu6502
|
||||||
|
|
||||||
import com.github.michaelbull.result.fold
|
|
||||||
import prog8.ast.IFunctionCall
|
import prog8.ast.IFunctionCall
|
||||||
import prog8.ast.Program
|
import prog8.ast.Program
|
||||||
import prog8.ast.antlr.escape
|
import prog8.ast.antlr.escape
|
||||||
@ -164,9 +163,9 @@ internal class ProgramGen(
|
|||||||
asmgen.outputSourceLine(block)
|
asmgen.outputSourceLine(block)
|
||||||
|
|
||||||
val vardecls = block.statements.filterIsInstance<VarDecl>()
|
val vardecls = block.statements.filterIsInstance<VarDecl>()
|
||||||
zeropagevars2asm(vardecls, block)
|
zeropagevars2asm(vardecls)
|
||||||
memdefs2asmVars(vardecls, block)
|
memdefs2asmVars(vardecls, block)
|
||||||
memdefs2asmAsmsubs(block.statements.filterIsInstance<Subroutine>(), block)
|
memdefs2asmAsmsubs(block.statements.filterIsInstance<Subroutine>())
|
||||||
vardecls2asm(vardecls, block)
|
vardecls2asm(vardecls, block)
|
||||||
|
|
||||||
vardecls.forEach {
|
vardecls.forEach {
|
||||||
@ -226,9 +225,9 @@ internal class ProgramGen(
|
|||||||
// regular subroutine
|
// regular subroutine
|
||||||
asmgen.out("${sub.name}\t.proc")
|
asmgen.out("${sub.name}\t.proc")
|
||||||
val vardecls = sub.statements.filterIsInstance<VarDecl>()
|
val vardecls = sub.statements.filterIsInstance<VarDecl>()
|
||||||
zeropagevars2asm(vardecls, null)
|
zeropagevars2asm(vardecls)
|
||||||
memdefs2asmVars(vardecls, null)
|
memdefs2asmVars(vardecls, null)
|
||||||
memdefs2asmAsmsubs(sub.statements.filterIsInstance<Subroutine>(), null)
|
memdefs2asmAsmsubs(sub.statements.filterIsInstance<Subroutine>())
|
||||||
|
|
||||||
// the main.start subroutine is the program's entrypoint and should perform some initialization logic
|
// the main.start subroutine is the program's entrypoint and should perform some initialization logic
|
||||||
if(sub.name=="start" && sub.definingBlock.name=="main")
|
if(sub.name=="start" && sub.definingBlock.name=="main")
|
||||||
@ -349,40 +348,25 @@ internal class ProgramGen(
|
|||||||
clc""")
|
clc""")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun zeropagevars2asm(vardecls: List<VarDecl>, inBlock: Block?) {
|
private fun zeropagevars2asm(vardecls: List<VarDecl>) {
|
||||||
|
// TODO get list of variables directly from allocator or zeropage
|
||||||
val zp = zeropage
|
val zp = zeropage
|
||||||
asmgen.out("; vars allocated on zeropage")
|
asmgen.out("; vars allocated on zeropage")
|
||||||
val variables = vardecls.filter { it.type==VarDeclType.VAR }
|
vardecls
|
||||||
val blockname = inBlock?.name
|
.filter { it.type==VarDeclType.VAR }
|
||||||
for(variable in variables) {
|
.forEach { variable ->
|
||||||
if(blockname=="prog8_lib" && variable.name.startsWith("P8ZP_SCRATCH_"))
|
val scopedName = variable.scopedName
|
||||||
continue // the "hooks" to the temp vars are not generated as new variables
|
val zpAlloc = zp.variables[scopedName]
|
||||||
val scopedName = variable.scopedName
|
if (zpAlloc != null) {
|
||||||
val zpAlloc = zp.variables[scopedName]
|
val lenspec = when(zpAlloc.dt) {
|
||||||
if (zpAlloc == null) {
|
DataType.FLOAT,
|
||||||
// TODO NO LONGER ALLOCATE HERE, IT'S ALL BEEN DONE IN THE VARIABLEALLOCATOR ALREADY
|
DataType.STR,
|
||||||
// This var is not on the ZP yet. Attempt to move it there if it's an integer type
|
in ArrayDatatypes -> " ${zpAlloc.size} bytes"
|
||||||
if(variable.zeropage != ZeropageWish.NOT_IN_ZEROPAGE &&
|
else -> ""
|
||||||
variable.datatype in IntegerDatatypes
|
}
|
||||||
&& options.zeropage != ZeropageType.DONTUSE) {
|
asmgen.out("${variable.name} = ${zpAlloc.address}\t; zp ${variable.datatype} $lenspec")
|
||||||
val result = zp.allocate(scopedName, variable.datatype, null, null, null, errors)
|
|
||||||
errors.report()
|
|
||||||
result.fold(
|
|
||||||
success = { (address, _) -> asmgen.out("${variable.name} = $address\t; zp ${variable.datatype}") },
|
|
||||||
failure = { /* leave it as it is, not on zeropage. */ }
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Var has been placed in ZP, just output the address
|
|
||||||
val lenspec = when(zpAlloc.dt) {
|
|
||||||
DataType.FLOAT,
|
|
||||||
DataType.STR,
|
|
||||||
in ArrayDatatypes -> " ${zpAlloc.size} bytes"
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
asmgen.out("${variable.name} = ${zpAlloc.address}\t; zp ${variable.datatype} $lenspec")
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun vardecl2asm(decl: VarDecl, nameOverride: String?=null) {
|
private fun vardecl2asm(decl: VarDecl, nameOverride: String?=null) {
|
||||||
@ -496,7 +480,7 @@ internal class ProgramGen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun memdefs2asmAsmsubs(subroutines: List<Subroutine>, inBlock: Block?) {
|
private fun memdefs2asmAsmsubs(subroutines: List<Subroutine>) {
|
||||||
subroutines
|
subroutines
|
||||||
.filter { it.isAsmSubroutine }
|
.filter { it.isAsmSubroutine }
|
||||||
.forEach { sub->
|
.forEach { sub->
|
||||||
|
@ -3,6 +3,7 @@ package prog8.codegen.cpu6502
|
|||||||
import com.github.michaelbull.result.onFailure
|
import com.github.michaelbull.result.onFailure
|
||||||
import prog8.ast.base.ArrayDatatypes
|
import prog8.ast.base.ArrayDatatypes
|
||||||
import prog8.ast.base.DataType
|
import prog8.ast.base.DataType
|
||||||
|
import prog8.ast.base.IntegerDatatypes
|
||||||
import prog8.ast.expressions.StringLiteralValue
|
import prog8.ast.expressions.StringLiteralValue
|
||||||
import prog8.ast.statements.Subroutine
|
import prog8.ast.statements.Subroutine
|
||||||
import prog8.ast.statements.VarDecl
|
import prog8.ast.statements.VarDecl
|
||||||
@ -37,44 +38,6 @@ internal class VariableAllocator(val vars: IVariablesAndConsts, val errors: IErr
|
|||||||
.filterNot { it.second.last() == "tbl" } // TODO HACK -- NOT REALLY NECESSARY, BUT OLD CallGraph DIDN'T CONTAIN IT EITHER
|
.filterNot { it.second.last() == "tbl" } // TODO HACK -- NOT REALLY NECESSARY, BUT OLD CallGraph DIDN'T CONTAIN IT EITHER
|
||||||
.filterNot { it.second.last() in setOf("retval_interm_w", "retval_interm_b", "retval_interm_w2", "retval_interm_b2") } // TODO HACK TO REMOVE THESE UNUSED VARS
|
.filterNot { it.second.last() in setOf("retval_interm_w", "retval_interm_b", "retval_interm_w2", "retval_interm_b2") } // TODO HACK TO REMOVE THESE UNUSED VARS
|
||||||
|
|
||||||
val varsRequiringZp = allVariables
|
|
||||||
.filter { it.first.zeropage == ZeropageWish.REQUIRE_ZEROPAGE }
|
|
||||||
val varsPreferringZp = allVariables
|
|
||||||
.filter { it.first.zeropage == ZeropageWish.PREFER_ZEROPAGE }
|
|
||||||
.sortedBy { options.compTarget.memorySize(it.first.datatype) } // allocate the smallest DT first
|
|
||||||
val varsDontCare = allVariables
|
|
||||||
.filter { it.first.zeropage == ZeropageWish.DONTCARE }
|
|
||||||
.sortedBy { options.compTarget.memorySize(it.first.datatype) } // allocate the smallest DT first
|
|
||||||
|
|
||||||
/*
|
|
||||||
// OLD CODE CHECKING:
|
|
||||||
if(true) {
|
|
||||||
val allVariablesFoundInCallgraph = callGraphForCheck.allIdentifiers.asSequence()
|
|
||||||
.map { it.value }
|
|
||||||
.filterIsInstance<VarDecl>()
|
|
||||||
.filter { it.type == VarDeclType.VAR && it.origin != VarDeclOrigin.SUBROUTINEPARAM }
|
|
||||||
.map { it.name to it.position }
|
|
||||||
.toSet()
|
|
||||||
val newAllVars = (vars.blockVars.flatMap { it.value }
|
|
||||||
.map { it.name to it.position } + vars.subroutineVars.flatMap { it.value }
|
|
||||||
.map { it.name to it.position }).toSet()
|
|
||||||
val extraVarsInCallgraph = allVariablesFoundInCallgraph - newAllVars
|
|
||||||
val extraVarsInNew = newAllVars - allVariablesFoundInCallgraph
|
|
||||||
|
|
||||||
if (extraVarsInCallgraph.any() || extraVarsInNew.any()) {
|
|
||||||
println("EXTRA VARS IN CALLGRAPH: ${extraVarsInCallgraph.size}")
|
|
||||||
extraVarsInCallgraph.forEach {
|
|
||||||
println(" $it")
|
|
||||||
}
|
|
||||||
println("EXTRA VARS IN VARIABLESOBJ: ${extraVarsInNew.size}")
|
|
||||||
extraVarsInNew.forEach {
|
|
||||||
println(" $it")
|
|
||||||
}
|
|
||||||
//TODO("fix differences")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
val zeropage = options.compTarget.machine.zeropage
|
val zeropage = options.compTarget.machine.zeropage
|
||||||
|
|
||||||
fun numArrayElements(vardecl: VarDecl): Int? = when(vardecl.datatype) {
|
fun numArrayElements(vardecl: VarDecl): Int? = when(vardecl.datatype) {
|
||||||
@ -87,6 +50,10 @@ internal class VariableAllocator(val vars: IVariablesAndConsts, val errors: IErr
|
|||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val varsRequiringZp = allVariables.filter { it.first.zeropage == ZeropageWish.REQUIRE_ZEROPAGE }
|
||||||
|
val varsPreferringZp = allVariables.filter { it.first.zeropage == ZeropageWish.PREFER_ZEROPAGE }
|
||||||
|
val varsDontCare = allVariables.filter { it.first.zeropage == ZeropageWish.DONTCARE }
|
||||||
|
|
||||||
varsRequiringZp.forEach { (vardecl, scopedname) ->
|
varsRequiringZp.forEach { (vardecl, scopedname) ->
|
||||||
val numElements = numArrayElements(vardecl)
|
val numElements = numArrayElements(vardecl)
|
||||||
val result = zeropage.allocate(scopedname, vardecl.datatype, numElements, vardecl.value, vardecl.position, errors)
|
val result = zeropage.allocate(scopedname, vardecl.datatype, numElements, vardecl.value, vardecl.position, errors)
|
||||||
@ -100,14 +67,18 @@ internal class VariableAllocator(val vars: IVariablesAndConsts, val errors: IErr
|
|||||||
// no need to check for allocation error, if there is one, just allocate in normal system ram.
|
// no need to check for allocation error, if there is one, just allocate in normal system ram.
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO enable zp allocation here and remove it from other places
|
// try to allocate any other interger variables into the zeropage until it is full.
|
||||||
// if(errors.noErrors()) {
|
// TODO some form of intelligent priorization? most often used variables first? loopcounter vars first? ...?
|
||||||
// varsDontCare.forEach { (vardecl, scopedname) ->
|
if(errors.noErrors()) {
|
||||||
// val numElements = numArrayElements(vardecl)
|
for ((vardecl, scopedname) in varsDontCare) {
|
||||||
// zeropage.allocate(scopedname, vardecl.datatype, numElements, vardecl.value, vardecl.position, errors)
|
if(vardecl.datatype in IntegerDatatypes) {
|
||||||
// // no need to check for allocation error, if there is one, just allocate in normal system ram.
|
val numElements = numArrayElements(vardecl)
|
||||||
// }
|
zeropage.allocate(scopedname, vardecl.datatype, numElements, vardecl.value, vardecl.position, errors)
|
||||||
// }
|
if(zeropage.free.isEmpty())
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,9 @@ For next release
|
|||||||
- programGen: don't generate variables from the VarDecl nodes, use allocator/zeropage tables
|
- programGen: don't generate variables from the VarDecl nodes, use allocator/zeropage tables
|
||||||
- (newvaralloc) UnusedCodeRemover after(decl: VarDecl): fix that vars defined in a library can also safely be removed if unused. Currently this breaks programs such as textelite (due to diskio.save().end_address ?)
|
- (newvaralloc) UnusedCodeRemover after(decl: VarDecl): fix that vars defined in a library can also safely be removed if unused. Currently this breaks programs such as textelite (due to diskio.save().end_address ?)
|
||||||
- remove hacks in VariableAllocator
|
- remove hacks in VariableAllocator
|
||||||
|
- make it so that subroutine parameters as variables can again be allocated in ZP, if there's still space
|
||||||
|
- wormfood became a lot larger??? why??? (and chess a little bit larger, but usually program size is down)
|
||||||
|
- check: are prog8_lib.P8ZP_SCRATCH emitted again from prog8_lib.p8 source, or do we only have the correct hardcoded redefines.
|
||||||
|
|
||||||
|
|
||||||
Need help with
|
Need help with
|
||||||
|
@ -17,6 +17,8 @@ main {
|
|||||||
str @requirezp zpname = "irmenzp"
|
str @requirezp zpname = "irmenzp"
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
|
prog8_lib.P8ZP_SCRATCH_B1 = 1
|
||||||
|
|
||||||
txt.print_uw(nullwords[1])
|
txt.print_uw(nullwords[1])
|
||||||
txt.nl()
|
txt.nl()
|
||||||
txt.print_ub(nullbytes[1])
|
txt.print_ub(nullbytes[1])
|
||||||
|
Loading…
Reference in New Issue
Block a user