streamlining non-zpvars asmgen using new mechanism

This commit is contained in:
Irmen de Jong 2022-02-09 22:32:18 +01:00
parent b043c3a6da
commit e5d7316e5d
8 changed files with 116 additions and 197 deletions

View File

@ -27,7 +27,7 @@ class AsmGen(internal val program: Program,
internal val optimizedWordMultiplications = setOf(3,5,6,7,9,10,12,15,20,25,40,50,80,100,320,640)
internal val loopEndLabels = ArrayDeque<String>()
private val zeropage = options.compTarget.machine.zeropage
private val allocator = VariableAllocator(variables, errors)
private val allocator = VariableAllocator(variables, options, errors)
private val assemblyLines = mutableListOf<String>()
private val breakpointLabels = mutableListOf<String>()
private val forloopsAsmGen = ForLoopsAsmGen(program, this, zeropage)
@ -130,7 +130,7 @@ class AsmGen(internal val program: Program,
is VarDecl -> {
val sourceName = asmVariableName(pointervar)
if (isTargetCpu(CpuType.CPU65c02)) {
return if (isZpVar(target.scopedName)) {
return if (allocator.isZpVar(target.scopedName)) {
// pointervar is already in the zero page, no need to copy
out(" lda ($sourceName)")
sourceName
@ -144,7 +144,7 @@ class AsmGen(internal val program: Program,
"P8ZP_SCRATCH_W1"
}
} else {
return if (isZpVar(target.scopedName)) {
return if (allocator.isZpVar(target.scopedName)) {
// pointervar is already in the zero page, no need to copy
out(" ldy #0 | lda ($sourceName),y")
sourceName
@ -168,7 +168,7 @@ class AsmGen(internal val program: Program,
val sourceName = asmVariableName(pointervar)
val vardecl = pointervar.targetVarDecl(program)!!
if (isTargetCpu(CpuType.CPU65c02)) {
if (isZpVar(vardecl.scopedName)) {
if (allocator.isZpVar(vardecl.scopedName)) {
// pointervar is already in the zero page, no need to copy
out(" sta ($sourceName)")
} else {
@ -180,7 +180,7 @@ class AsmGen(internal val program: Program,
sta (P8ZP_SCRATCH_W2)""")
}
} else {
if (isZpVar(vardecl.scopedName)) {
if (allocator.isZpVar(vardecl.scopedName)) {
// pointervar is already in the zero page, no need to copy
out(" ldy #0 | sta ($sourceName),y")
} else {
@ -1037,12 +1037,8 @@ $repeatLabel lda $counterVar
}
}
internal fun isZpVar(scopedName: List<String>) = scopedName in zeropage.variables
internal fun isZpVar(variable: IdentifierReference): Boolean {
val vardecl = variable.targetVarDecl(program)!!
return vardecl.scopedName in zeropage.variables
}
internal fun isZpVar(variable: IdentifierReference): Boolean =
allocator.isZpVar(variable.targetVarDecl(program)!!.scopedName)
internal fun jmp(asmLabel: String, indirect: Boolean=false) {
if(indirect) {

View File

@ -31,7 +31,7 @@ internal class ProgramGen(
val allInitializers = blockVariableInitializers.asSequence().flatMap { it.value }
require(allInitializers.all { it.origin==AssignmentOrigin.VARINIT }) {"all block-level assignments must be a variable initializer"}
allocator.allocateZeropageVariables(options)
allocator.allocateZeropageVariables()
header()
val allBlocks = program.allBlocks
if(allBlocks.first().name != "main")
@ -347,28 +347,31 @@ internal class ProgramGen(
}
}
private fun nonZpVariables2asm(scope: INameScope) {
private fun nonZpVariables2asm(block: Block) {
val variables = variables.blockVars[block]?.filter { !allocator.isZpVar(it.scopedname) } ?: emptyList()
nonZpVariables2asm(variables)
}
private fun nonZpVariables2asm(sub: Subroutine) {
val variables = variables.subroutineVars[sub]?.filter { !allocator.isZpVar(it.scopedname) } ?: emptyList()
nonZpVariables2asm(variables)
}
private fun nonZpVariables2asm(variables: List<IVariablesAndConsts.StaticVariable>) {
asmgen.out("\n; non-zeropage variables")
val vars = scope.statements
.filterIsInstance<VarDecl>()
.filter {
it.type==VarDeclType.VAR && it.scopedName !in zeropage.variables
}
vars.filter { it.datatype == DataType.STR && shouldActuallyOutputStringVar(it) }
.forEach { outputStringvar(it) }
vars.filter{ it.datatype != DataType.STR }.sortedBy { it.datatype }.forEach {
require(it.zeropage!= ZeropageWish.REQUIRE_ZEROPAGE)
if(!asmgen.isZpVar(it.scopedName))
vardecl2asm(it)
val (stringvars, othervars) = variables.partition { it.type==DataType.STR }
stringvars.forEach {
val stringvalue = it.initialValue as StringLiteralValue
outputStringvar(it.scopedname.last(), it.type, stringvalue.encoding, stringvalue.value)
}
othervars.sortedBy { it.type }.forEach {
vardecl2asm(it)
}
}
private fun vardecl2asm(decl: VarDecl, nameOverride: String?=null) {
val name = nameOverride ?: decl.name
val value = decl.value
private fun vardecl2asm(variable: IVariablesAndConsts.StaticVariable) {
val name = variable.scopedname.last()
val value = variable.initialValue
val staticValue: Number =
if(value!=null) {
if(value is NumericLiteralValue) {
@ -377,13 +380,13 @@ internal class ProgramGen(
else
value.number.toInt()
} else {
if(decl.datatype in NumericDatatypes)
throw AssemblyError("can only deal with constant numeric values for global vars $value at ${decl.position}")
if(variable.type in NumericDatatypes)
throw AssemblyError("can only deal with constant numeric values for global vars")
else 0
}
} else 0
when (decl.datatype) {
when (variable.type) {
DataType.UBYTE -> asmgen.out("$name\t.byte ${staticValue.toHex()}")
DataType.BYTE -> asmgen.out("$name\t.char $staticValue")
DataType.UWORD -> asmgen.out("$name\t.word ${staticValue.toHex()}")
@ -399,7 +402,7 @@ internal class ProgramGen(
DataType.STR -> {
throw AssemblyError("all string vars should have been interned into prog")
}
in ArrayDatatypes -> arrayVardecl2asm(name, decl.datatype, decl.value as? ArrayLiteralValue, decl.arraysize?.constIndex())
in ArrayDatatypes -> arrayVardecl2asm(name, variable.type, value as? ArrayLiteralValue, variable.arraysize)
else -> {
throw AssemblyError("weird dt")
}
@ -480,13 +483,13 @@ internal class ProgramGen(
consts: Set<IVariablesAndConsts.ConstantNumberSymbol>
) {
memvars.forEach {
asmgen.out(" ${it.name} = ${it.address.toHex()}")
asmgen.out(" ${it.scopedname.last()} = ${it.address.toHex()}")
}
consts.forEach {
if(it.type==DataType.FLOAT)
asmgen.out(" ${it.name} = ${it.value}")
asmgen.out(" ${it.scopedname.last()} = ${it.value}")
else
asmgen.out(" ${it.name} = ${it.value.toHex()}")
asmgen.out(" ${it.scopedname.last()} = ${it.value.toHex()}")
}
}
@ -499,23 +502,6 @@ internal class ProgramGen(
}
}
private fun shouldActuallyOutputStringVar(strvar: VarDecl): Boolean {
if(strvar.sharedWithAsm)
return true
val uses = callGraph.usages(strvar)
val onlyInMemoryFuncs = uses.all {
val builtinfunc = (it.parent as? IFunctionCall)?.target?.targetStatement(program) as? BuiltinFunctionPlaceholder
builtinfunc?.name=="memory"
}
return !onlyInMemoryFuncs
}
private fun outputStringvar(strdecl: VarDecl, nameOverride: String?=null) {
val varname = nameOverride ?: strdecl.name
val sv = strdecl.value as StringLiteralValue
outputStringvar(varname, strdecl.datatype, sv.encoding, sv.value)
}
private fun outputStringvar(varname: String, dt: DataType, encoding: Encoding, value: String) {
asmgen.out("$varname\t; $dt $encoding:\"${escape(value).replace("\u0000", "<NULL>")}\"")
val bytes = compTarget.encodeString(value, encoding).plus(0.toUByte())
@ -589,10 +575,3 @@ internal class ProgramGen(
}
}
private fun sameScope(varname: List<String>, scopename: List<String>): Boolean {
if(varname.size!=scopename.size+1)
return false
val pairs = scopename.zip(varname)
return pairs.all { it.first==it.second }
}

View File

@ -6,7 +6,6 @@ import prog8.ast.base.DataType
import prog8.ast.base.IntegerDatatypes
import prog8.ast.expressions.StringLiteralValue
import prog8.ast.statements.Subroutine
import prog8.ast.statements.VarDecl
import prog8.ast.statements.ZeropageWish
import prog8.compilerinterface.CompilationOptions
import prog8.compilerinterface.IErrorReporter
@ -14,8 +13,11 @@ import prog8.compilerinterface.IVariablesAndConsts
import prog8.compilerinterface.ZeropageType
internal class VariableAllocator(private val vars: IVariablesAndConsts, private val errors: IErrorReporter) {
internal class VariableAllocator(private val vars: IVariablesAndConsts,
private val options: CompilationOptions,
private val errors: IErrorReporter) {
private val zeropage = options.compTarget.machine.zeropage
private val subroutineExtras = mutableMapOf<Subroutine, SubroutineExtraAsmInfo>()
private val memorySlabsInternal = mutableMapOf<String, Pair<UInt, UInt>>()
internal val memorySlabs: Map<String, Pair<UInt, UInt>> = memorySlabsInternal
@ -30,40 +32,39 @@ internal class VariableAllocator(private val vars: IVariablesAndConsts, private
* Allocate variables into the Zeropage.
* The result should be retrieved from the current machine's zeropage object!
*/
fun allocateZeropageVariables(options: CompilationOptions) {
internal fun allocateZeropageVariables() {
if(options.zeropage== ZeropageType.DONTUSE)
return
val zeropage = options.compTarget.machine.zeropage
val allVariables = (
vars.blockVars.asSequence().flatMap { it.value }.map {it.origVar to it.origVar.scopedName} +
vars.subroutineVars.asSequence().flatMap { it.value }.map {it.origVar to it.origVar.scopedName})
.toList()
vars.blockVars.asSequence().flatMap { it.value } +
vars.subroutineVars.asSequence().flatMap { it.value }
).toList()
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 }
val varsRequiringZp = allVariables.filter { it.zp == ZeropageWish.REQUIRE_ZEROPAGE }
val varsPreferringZp = allVariables.filter { it.zp == ZeropageWish.PREFER_ZEROPAGE }
val varsDontCare = allVariables.filter { it.zp == ZeropageWish.DONTCARE }
varsRequiringZp.forEach { (vardecl, scopedname) ->
val numElements = numArrayElements(vardecl)
val result = zeropage.allocate(scopedname, vardecl.datatype, vardecl.definingScope, numElements, vardecl.value, vardecl.position, errors)
result.onFailure { errors.err(it.message!!, vardecl.position) }
varsRequiringZp.forEach { variable ->
val numElements = numArrayElements(variable)
val result = zeropage.allocate(variable.scopedname, variable.type, variable.scope, numElements, variable.initialValue, variable.position, errors)
result.onFailure { errors.err(it.message!!, variable.position) }
}
if(errors.noErrors()) {
varsPreferringZp.forEach { (vardecl, scopedname) ->
val numElements = numArrayElements(vardecl)
zeropage.allocate(scopedname, vardecl.datatype, vardecl.definingScope, numElements, vardecl.value, vardecl.position, errors)
varsPreferringZp.forEach { variable ->
val numElements = numArrayElements(variable)
zeropage.allocate(variable.scopedname, variable.type, variable.scope, numElements, variable.initialValue, variable.position, errors)
// no need to check for allocation error, if there is one, just allocate in normal system ram.
}
// try to allocate any other interger variables into the zeropage until it is full.
// TODO some form of intelligent priorization? most often used variables first? loopcounter vars first? ...?
if(errors.noErrors()) {
for ((vardecl, scopedname) in varsDontCare) {
if(vardecl.datatype in IntegerDatatypes) {
val numElements = numArrayElements(vardecl)
zeropage.allocate(scopedname, vardecl.datatype, vardecl.definingScope, numElements, vardecl.value, vardecl.position, errors)
for (variable in varsDontCare) {
if(variable.type in IntegerDatatypes) {
val numElements = numArrayElements(variable)
zeropage.allocate(variable.scopedname, variable.type, variable.scope, numElements, variable.initialValue, variable.position, errors)
if(zeropage.free.isEmpty())
break
}
@ -72,15 +73,14 @@ internal class VariableAllocator(private val vars: IVariablesAndConsts, private
}
}
private fun numArrayElements(vardecl: VarDecl): Int? = when(vardecl.datatype) {
DataType.STR -> {
(vardecl.value as StringLiteralValue).value.length
internal fun isZpVar(scopedName: List<String>) = scopedName in zeropage.variables
private fun numArrayElements(variable: IVariablesAndConsts.StaticVariable) =
when(variable.type) {
DataType.STR -> (variable.initialValue as StringLiteralValue).value.length
in ArrayDatatypes -> variable.arraysize!!
else -> null
}
in ArrayDatatypes -> {
vardecl.arraysize!!.constIndex()
}
else -> null
}
fun subroutineExtra(sub: Subroutine): SubroutineExtraAsmInfo {
var extra = subroutineExtras[sub]

View File

@ -7,10 +7,7 @@ import prog8.ast.expressions.NumericLiteralValue
import prog8.ast.statements.Block
import prog8.ast.statements.Subroutine
import prog8.ast.statements.VarDecl
import prog8.ast.statements.VarDeclOrigin
import prog8.ast.toHex
import prog8.ast.walk.IAstVisitor
import prog8.compilerinterface.IMemSizer
import prog8.compilerinterface.IVariablesAndConsts
@ -33,21 +30,19 @@ internal class VariableExtractor: IAstVisitor {
val scope=decl.definingScope
when (decl.type) {
VarDeclType.VAR -> {
if(decl.origin!= VarDeclOrigin.SUBROUTINEPARAM) {
when (scope) {
is Block -> {
val decls = allBlockVars[scope] ?: mutableSetOf()
decls.add(decl)
allBlockVars[scope] = decls
}
is Subroutine -> {
val decls = allSubroutineVars[scope] ?: mutableSetOf()
decls.add(decl)
allSubroutineVars[scope] = decls
}
else -> {
throw FatalAstException("var can only occur in subroutine or block scope")
}
when (scope) {
is Block -> {
val decls = allBlockVars[scope] ?: mutableSetOf()
decls.add(decl)
allBlockVars[scope] = decls
}
is Subroutine -> {
val decls = allSubroutineVars[scope] ?: mutableSetOf()
decls.add(decl)
allSubroutineVars[scope] = decls
}
else -> {
throw FatalAstException("var can only occur in subroutine or block scope")
}
}
}
@ -102,24 +97,24 @@ internal class VariablesAndConsts (
astSubroutineMemvars: Map<Subroutine, Set<VarDecl>>
) : IVariablesAndConsts
{
override val blockVars: Map<Block, Set<IVariablesAndConsts.StaticBlockVariable>>
override val blockVars: Map<Block, Set<IVariablesAndConsts.StaticVariable>>
override val blockConsts: Map<Block, Set<IVariablesAndConsts.ConstantNumberSymbol>>
override val blockMemvars: Map<Block, Set<IVariablesAndConsts.MemoryMappedVariable>>
override val subroutineVars: Map<Subroutine, Set<IVariablesAndConsts.StaticSubroutineVariable>>
override val subroutineVars: Map<Subroutine, Set<IVariablesAndConsts.StaticVariable>>
override val subroutineConsts: Map<Subroutine, Set<IVariablesAndConsts.ConstantNumberSymbol>>
override val subroutineMemvars: Map<Subroutine, Set<IVariablesAndConsts.MemoryMappedVariable>>
init {
val bv = astBlockVars.keys.associateWith { mutableSetOf<IVariablesAndConsts.StaticBlockVariable>() }
val bv = astBlockVars.keys.associateWith { mutableSetOf<IVariablesAndConsts.StaticVariable>() }
val bc = astBlockConsts.keys.associateWith { mutableSetOf<IVariablesAndConsts.ConstantNumberSymbol>() }
val bmv = astBlockMemvars.keys.associateWith { mutableSetOf<IVariablesAndConsts.MemoryMappedVariable>() }
val sv = astSubroutineVars.keys.associateWith { mutableSetOf<IVariablesAndConsts.StaticSubroutineVariable>() }
val sv = astSubroutineVars.keys.associateWith { mutableSetOf<IVariablesAndConsts.StaticVariable>() }
val sc = astSubroutineConsts.keys.associateWith { mutableSetOf<IVariablesAndConsts.ConstantNumberSymbol>() }
val smv = astSubroutineMemvars.keys.associateWith { mutableSetOf<IVariablesAndConsts.MemoryMappedVariable>() }
astBlockVars.forEach { (block, decls) ->
val vars = bv.getValue(block)
vars.addAll(decls.map {
IVariablesAndConsts.StaticBlockVariable(it.datatype, it.name, it.value, it.zeropage, it.position, it)
IVariablesAndConsts.StaticVariable(it.datatype, it.scopedName, it.definingScope, it.value, it.arraysize?.constIndex(), it.zeropage, it.position)
})
}
astBlockConsts.forEach { (block, decls) ->
@ -127,7 +122,7 @@ internal class VariablesAndConsts (
decls.map {
IVariablesAndConsts.ConstantNumberSymbol(
it.datatype,
it.name,
it.scopedName,
(it.value as NumericLiteralValue).number,
it.position
)
@ -141,7 +136,7 @@ internal class VariablesAndConsts (
vars.add(
IVariablesAndConsts.MemoryMappedVariable(
decl.datatype,
decl.name,
decl.scopedName,
(decl.value as NumericLiteralValue).number.toUInt(),
decl.position
)
@ -152,7 +147,7 @@ internal class VariablesAndConsts (
astSubroutineVars.forEach { (sub, decls) ->
val vars = sv.getValue(sub)
vars.addAll(decls.map {
IVariablesAndConsts.StaticSubroutineVariable(it.datatype, it.name, it.zeropage, it.position, it)
IVariablesAndConsts.StaticVariable(it.datatype, it.scopedName, it.definingScope, it.value, it.arraysize?.constIndex(), it.zeropage, it.position)
})
}
astSubroutineConsts.forEach { (sub, decls) ->
@ -160,7 +155,7 @@ internal class VariablesAndConsts (
decls.map {
IVariablesAndConsts.ConstantNumberSymbol(
it.datatype,
it.name,
it.scopedName,
(it.value as NumericLiteralValue).number,
it.position
)
@ -171,7 +166,7 @@ internal class VariablesAndConsts (
decls.map {
IVariablesAndConsts.MemoryMappedVariable(
it.datatype,
it.name,
it.scopedName,
(it.value as NumericLiteralValue).number.toUInt(),
it.position
)
@ -184,52 +179,4 @@ internal class VariablesAndConsts (
subroutineConsts = sc
subroutineMemvars = smv
}
override fun dump(memsizer: IMemSizer) {
println("\nALL BLOCK VARS:")
blockVars.forEach { (block, vars) ->
val totalsize = vars.sumOf { memsizer.memorySize(it.origVar) }
println("BLOCK: ${block.name} total size: $totalsize")
vars.forEach {
println(" ${it.type} ${it.name} = ${it.initialValue} ${it.position}")
}
}
println("\nALL BLOCK CONSTS:")
blockConsts.forEach { (block, vars) ->
println("BLOCK: ${block.name}")
vars.forEach {
println(" ${it.type} ${it.name} = ${it.value} ${it.position}")
}
}
println("\nALL BLOCK MEMORYVARS:")
blockMemvars.forEach { (block, vars) ->
println("BLOCK: ${block.name}")
vars.forEach {
println(" ${it.type} ${it.name} = ${it.address.toHex()} ${it.position}")
}
}
println("\nALL SUBROUTINE VARS:")
subroutineVars.forEach { (sub, vars) ->
val totalsize = vars.sumOf { memsizer.memorySize(it.origVar) }
println("SUBROUTINE: ${sub.name} total size: $totalsize")
vars.forEach {
println(" ${it.type} ${it.name} ${it.position}")
}
}
println("\nALL SUBROUTINE CONSTS:")
subroutineConsts.forEach { (sub, vars) ->
println("SUBROUTINE: ${sub.name}")
vars.forEach {
println(" ${it.type} ${it.name} = ${it.value} ${it.position}")
}
}
println("\nALL SUBROUTINE MEMORYVARS:")
subroutineMemvars.forEach { (sub, vars) ->
println("SUBROUTINE: ${sub.name}")
vars.forEach {
println(" ${it.type} ${it.name} = ${it.address.toHex()} ${it.position}")
}
}
}
}

View File

@ -70,22 +70,21 @@ class TestAsmGenSymbols: StringSpec({
val module = Module(mutableListOf(block), Position.DUMMY, SourceCode.Generated("test"))
val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder).addModule(module)
val variables = object : IVariablesAndConsts {
override fun dump(memsizer: IMemSizer) { }
override val blockVars: Map<Block, Set<IVariablesAndConsts.StaticBlockVariable>>
override val blockVars: Map<Block, Set<IVariablesAndConsts.StaticVariable>>
override val blockConsts: Map<Block, Set<IVariablesAndConsts.ConstantNumberSymbol>>
override val blockMemvars: Map<Block, Set<IVariablesAndConsts.MemoryMappedVariable>>
override val subroutineVars: Map<Subroutine, Set<IVariablesAndConsts.StaticSubroutineVariable>>
override val subroutineVars: Map<Subroutine, Set<IVariablesAndConsts.StaticVariable>>
override val subroutineConsts: Map<Subroutine, Set<IVariablesAndConsts.ConstantNumberSymbol>>
override val subroutineMemvars: Map<Subroutine, Set<IVariablesAndConsts.MemoryMappedVariable>>
init {
blockVars = mutableMapOf()
blockVars[block] = mutableSetOf(IVariablesAndConsts.StaticBlockVariable(varInBlock.datatype, varInBlock.name, varInBlock.value, varInBlock.zeropage, varInBlock.position, varInBlock))
blockVars[block] = mutableSetOf(IVariablesAndConsts.StaticVariable(varInBlock.datatype, varInBlock.scopedName, varInBlock.definingScope, varInBlock.value, varInBlock.arraysize?.constIndex(), varInBlock.zeropage, varInBlock.position))
blockConsts = mutableMapOf()
blockMemvars = mutableMapOf()
subroutineVars = mutableMapOf()
subroutineVars[subroutine] = mutableSetOf(
IVariablesAndConsts.StaticSubroutineVariable(varInSub.datatype, varInSub.name, var2InSub.zeropage, varInSub.position, varInSub),
IVariablesAndConsts.StaticSubroutineVariable(var2InSub.datatype, var2InSub.name, var2InSub.zeropage, var2InSub.position, var2InSub)
IVariablesAndConsts.StaticVariable(varInSub.datatype, varInSub.scopedName, varInSub.definingScope, varInSub.value, varInSub.arraysize?.constIndex(), varInSub.zeropage, varInSub.position),
IVariablesAndConsts.StaticVariable(var2InSub.datatype, var2InSub.scopedName, var2InSub.definingScope, var2InSub.value, var2InSub.arraysize?.constIndex(), var2InSub.zeropage, var2InSub.position)
)
subroutineConsts = mutableMapOf()
subroutineMemvars = mutableMapOf()

View File

@ -1,31 +1,30 @@
package prog8.compilerinterface
import prog8.ast.INameScope
import prog8.ast.base.DataType
import prog8.ast.base.Position
import prog8.ast.expressions.Expression
import prog8.ast.statements.Block
import prog8.ast.statements.Subroutine
import prog8.ast.statements.VarDecl
import prog8.ast.statements.ZeropageWish
import prog8.ast.statements.*
/**
* Experimental attempt for:
* A more convenient way to pass variable (and constant values) definitions to the code generator,
* so that it doesn't have to scavenge all VerDecl nodes in the AST for this information.
* so that it doesn't have to scavenge and manipulate the VerDecl nodes in the AST for this information.
*/
interface IVariablesAndConsts {
data class ConstantNumberSymbol(val type: DataType, val name: String, val value: Double, val position: Position)
data class MemoryMappedVariable(val type: DataType, val name: String, val address: UInt, val position: Position)
// TODO should get rid of origVar altogether in the following two:
data class StaticBlockVariable(val type: DataType, val name: String, val initialValue: Expression?, val zp: ZeropageWish, val position: Position, val origVar: VarDecl)
data class StaticSubroutineVariable(val type: DataType, val name: String, val zp: ZeropageWish, val position: Position, val origVar: VarDecl)
data class ConstantNumberSymbol(val type: DataType, val scopedname: List<String>, val value: Double, val position: Position)
data class MemoryMappedVariable(val type: DataType, val scopedname: List<String>, val address: UInt, val position: Position)
data class StaticVariable(val type: DataType,
val scopedname: List<String>,
val scope: INameScope,
val initialValue: Expression?,
val arraysize: Int?,
val zp: ZeropageWish,
val position: Position)
fun dump(memsizer: IMemSizer)
val blockVars: Map<Block, Set<StaticBlockVariable>>
val blockVars: Map<Block, Set<StaticVariable>>
val blockConsts: Map<Block, Set<ConstantNumberSymbol>>
val blockMemvars: Map<Block, Set<MemoryMappedVariable>>
val subroutineVars: Map<Subroutine, Set<StaticSubroutineVariable>>
val subroutineVars: Map<Subroutine, Set<StaticVariable>>
val subroutineConsts: Map<Subroutine, Set<ConstantNumberSymbol>>
val subroutineMemvars: Map<Subroutine, Set<MemoryMappedVariable>>
}

View File

@ -3,14 +3,10 @@ TODO
For next release
^^^^^^^^^^^^^^^^
- programGen: don't generate variables from the VarDecl nodes, use allocator/zeropage tables
after that is done:
- get rid of the interned string literals from memory() calls.
- (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 ?)
- check that retval_interm_* are not in the varallocation if they're not used
- 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)
Need help with
@ -28,11 +24,6 @@ Blocked by an official Commander-x16 r39 release
Future Things and Ideas
^^^^^^^^^^^^^^^^^^^^^^^
Ast modifications done in AsmGen that perhaps should not be necessary:
- block2asm: after vardecls2asm it clears the vardecl.value of all variables
--> Don't rely on vardecls at all any longer but use the new IVariablesAndConsts object passed to the AsmGen, this will solve this item.
- block2asm: removes init-assignments to no longer output the initialization assignments as regular statements (is done separately in block initialization routine)
- remove support for old @"screencodes" string encoding syntax (parser+code+docs)
- allow "xxx" * constexpr (where constexpr is not a number literal), now gives expression error not same type
- unify FunctioncallExpression + FunctioncallStatement and PipeExpression + Pipe statement classes, may require moving Expression/Statement into interfaces instead of abstract base classes
@ -66,6 +57,7 @@ Ast modifications done in AsmGen that perhaps should not be necessary:
More optimization ideas
^^^^^^^^^^^^^^^^^^^^^^^
- VariableAllocator: can we think of a smarter strategy for allocating variables into zeropage, rather than first-come-first-served
- translateFunctioncall() in BuiltinFunctionsAsmGen: should be able to assign parameters to a builtin function directly from register(s), this will make the use of a builtin function in a pipe expression more efficient without using a temporary variable
- translateNormalAssignment() -> better code gen for assigning boolean comparison expressions
- when a for loop's loopvariable isn't referenced in the body, and the iterations are known, replace the loop by a repeatloop

View File

@ -6,6 +6,8 @@ main {
ubyte @zp mainglobal1=10
float @shared fl1 = floats.TWOPI
uword @shared m1 = memory("eee", 200, 0)
uword [2] nullwords
ubyte [2] nullbytes
uword [2] valuewords = [1111,22222]
@ -21,7 +23,12 @@ main {
sub start() {
prog8_lib.P8ZP_SCRATCH_B1 = 1
prog8_lib.P8ZP_SCRATCH_W1 = 1111
str alsoname = "also name"
txt.print(alsoname)
txt.print(zpname)
txt.print("internedstring")
txt.spc()
txt.print_uwhex(&prog8_lib.P8ZP_SCRATCH_B1, true)
txt.spc()
txt.print_uwhex(&prog8_lib.P8ZP_SCRATCH_W1, true)