mirror of
https://github.com/irmen/prog8.git
synced 2024-11-22 15:33:02 +00:00
streamlining non-zpvars asmgen using new mechanism
This commit is contained in:
parent
b043c3a6da
commit
e5d7316e5d
@ -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) {
|
||||
|
@ -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 }
|
||||
}
|
@ -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]
|
||||
|
@ -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}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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>>
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user