From e5d7316e5df6f8a00e183d17adbed8e300cd4e7a Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Wed, 9 Feb 2022 22:32:18 +0100 Subject: [PATCH] streamlining non-zpvars asmgen using new mechanism --- .../src/prog8/codegen/cpu6502/AsmGen.kt | 18 ++-- .../src/prog8/codegen/cpu6502/ProgramGen.kt | 79 ++++++--------- .../codegen/cpu6502/VariableAllocator.kt | 58 +++++------ .../astprocessing/VariablesAndConsts.kt | 99 +++++-------------- .../test/codegeneration/TestAsmGenSymbols.kt | 11 +-- .../compilerinterface/IVariablesAndConsts.kt | 29 +++--- docs/source/todo.rst | 12 +-- examples/test.p8 | 7 ++ 8 files changed, 116 insertions(+), 197 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index 1aff1c7b9..5c23723d2 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -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() private val zeropage = options.compTarget.machine.zeropage - private val allocator = VariableAllocator(variables, errors) + private val allocator = VariableAllocator(variables, options, errors) private val assemblyLines = mutableListOf() private val breakpointLabels = mutableListOf() 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) = 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) { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramGen.kt index 2227e4ddf..e1424a7b5 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramGen.kt @@ -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) { asmgen.out("\n; non-zeropage variables") - - val vars = scope.statements - .filterIsInstance() - .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 ) { 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", "")}\"") val bytes = compTarget.encodeString(value, encoding).plus(0.toUByte()) @@ -589,10 +575,3 @@ internal class ProgramGen( } } - -private fun sameScope(varname: List, scopename: List): Boolean { - if(varname.size!=scopename.size+1) - return false - val pairs = scopename.zip(varname) - return pairs.all { it.first==it.second } -} \ No newline at end of file diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt index aab7eddf0..0bd862d7d 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/VariableAllocator.kt @@ -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() private val memorySlabsInternal = mutableMapOf>() internal val memorySlabs: Map> = 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) = 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] diff --git a/compiler/src/prog8/compiler/astprocessing/VariablesAndConsts.kt b/compiler/src/prog8/compiler/astprocessing/VariablesAndConsts.kt index e1e16b1a3..14fea44f3 100644 --- a/compiler/src/prog8/compiler/astprocessing/VariablesAndConsts.kt +++ b/compiler/src/prog8/compiler/astprocessing/VariablesAndConsts.kt @@ -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> ) : IVariablesAndConsts { - override val blockVars: Map> + override val blockVars: Map> override val blockConsts: Map> override val blockMemvars: Map> - override val subroutineVars: Map> + override val subroutineVars: Map> override val subroutineConsts: Map> override val subroutineMemvars: Map> init { - val bv = astBlockVars.keys.associateWith { mutableSetOf() } + val bv = astBlockVars.keys.associateWith { mutableSetOf() } val bc = astBlockConsts.keys.associateWith { mutableSetOf() } val bmv = astBlockMemvars.keys.associateWith { mutableSetOf() } - val sv = astSubroutineVars.keys.associateWith { mutableSetOf() } + val sv = astSubroutineVars.keys.associateWith { mutableSetOf() } val sc = astSubroutineConsts.keys.associateWith { mutableSetOf() } val smv = astSubroutineMemvars.keys.associateWith { mutableSetOf() } 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}") - } - } - } } diff --git a/compiler/test/codegeneration/TestAsmGenSymbols.kt b/compiler/test/codegeneration/TestAsmGenSymbols.kt index 1fa4c18cc..cf192aa84 100644 --- a/compiler/test/codegeneration/TestAsmGenSymbols.kt +++ b/compiler/test/codegeneration/TestAsmGenSymbols.kt @@ -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> + override val blockVars: Map> override val blockConsts: Map> override val blockMemvars: Map> - override val subroutineVars: Map> + override val subroutineVars: Map> override val subroutineConsts: Map> override val subroutineMemvars: Map> 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() diff --git a/compilerInterfaces/src/prog8/compilerinterface/IVariablesAndConsts.kt b/compilerInterfaces/src/prog8/compilerinterface/IVariablesAndConsts.kt index d81511042..44bd72a03 100644 --- a/compilerInterfaces/src/prog8/compilerinterface/IVariablesAndConsts.kt +++ b/compilerInterfaces/src/prog8/compilerinterface/IVariablesAndConsts.kt @@ -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, val value: Double, val position: Position) + data class MemoryMappedVariable(val type: DataType, val scopedname: List, val address: UInt, val position: Position) + data class StaticVariable(val type: DataType, + val scopedname: List, + val scope: INameScope, + val initialValue: Expression?, + val arraysize: Int?, + val zp: ZeropageWish, + val position: Position) - fun dump(memsizer: IMemSizer) - - val blockVars: Map> + val blockVars: Map> val blockConsts: Map> val blockMemvars: Map> - val subroutineVars: Map> + val subroutineVars: Map> val subroutineConsts: Map> val subroutineMemvars: Map> } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index f220204d4..ca7acf261 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -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 diff --git a/examples/test.p8 b/examples/test.p8 index 99fb5e06f..8e2e80176 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -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)