diff --git a/codeCore/src/prog8/code/SymbolTable.kt b/codeCore/src/prog8/code/SymbolTable.kt index d55776df0..3286d6937 100644 --- a/codeCore/src/prog8/code/SymbolTable.kt +++ b/codeCore/src/prog8/code/SymbolTable.kt @@ -147,7 +147,6 @@ open class StNode(val name: String, class StStaticVariable(name: String, val dt: DataType, - val bss: Boolean, val onetimeInitializationNumericValue: Double?, // regular (every-run-time) initialization is done via regular assignments val onetimeInitializationStringValue: StString?, val onetimeInitializationArrayValue: StArray?, @@ -155,25 +154,22 @@ class StStaticVariable(name: String, val zpwish: ZeropageWish, // used in the variable allocator astNode: PtNode) : StNode(name, StNodeType.STATICVAR, astNode) { + val uninitialized = onetimeInitializationArrayValue==null && onetimeInitializationStringValue==null && onetimeInitializationNumericValue==null + init { - if(bss) { - require(onetimeInitializationNumericValue==null) - require(onetimeInitializationStringValue==null) - require(onetimeInitializationArrayValue.isNullOrEmpty()) - } else { - require(onetimeInitializationNumericValue!=null || - onetimeInitializationStringValue!=null || - onetimeInitializationArrayValue!=null) - } if(length!=null) { require(onetimeInitializationNumericValue == null) if(onetimeInitializationArrayValue!=null) require(onetimeInitializationArrayValue.isEmpty() ||onetimeInitializationArrayValue.size==length) } - if(onetimeInitializationNumericValue!=null) + if(onetimeInitializationNumericValue!=null) { require(dt in NumericDatatypes) - if(onetimeInitializationArrayValue!=null) + require(onetimeInitializationNumericValue!=0.0) { "zero as init value should just remain uninitialized"} + } + if(onetimeInitializationArrayValue!=null) { require(dt in ArrayDatatypes) + require(onetimeInitializationArrayValue.any { it.number!=0.0} ) { "array of all zerors as init value should just remain uninitialized"} + } if(onetimeInitializationStringValue!=null) { require(dt == DataType.STR) require(length == onetimeInitializationStringValue.first.length+1) diff --git a/codeCore/src/prog8/code/SymbolTableMaker.kt b/codeCore/src/prog8/code/SymbolTableMaker.kt index 5f41c23ce..baaa125ff 100644 --- a/codeCore/src/prog8/code/SymbolTableMaker.kt +++ b/codeCore/src/prog8/code/SymbolTableMaker.kt @@ -72,7 +72,8 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp val numElements: Int? val value = node.value if(value!=null) { - initialNumeric = (value as? PtNumber)?.number + val number = (value as? PtNumber)?.number + initialNumeric = if(number==0.0) null else number // 0 as init value -> just uninitialized when (value) { is PtString -> { initialString = StString(value.value, value.encoding) @@ -80,9 +81,10 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp numElements = value.value.length + 1 // include the terminating 0-byte } is PtArray -> { - initialArray = makeInitialArray(value) + val array = makeInitialArray(value) + initialArray = if(array.all { it.number==0.0 }) null else array // all 0 as init value -> just uninitialized initialString = null - numElements = initialArray.size + numElements = array.size require(node.arraySize?.toInt()==numElements) } else -> { @@ -97,7 +99,7 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp initialString = null numElements = node.arraySize?.toInt() } - StStaticVariable(node.name, node.type, node.bss, initialNumeric, initialString, initialArray, numElements, node.zeropage, node) + StStaticVariable(node.name, node.type, initialNumeric, initialString, initialArray, numElements, node.zeropage, node) } is PtBuiltinFunctionCall -> { if(node.name=="memory") { diff --git a/codeCore/src/prog8/code/ast/AstStatements.kt b/codeCore/src/prog8/code/ast/AstStatements.kt index 9706388f4..831364e54 100644 --- a/codeCore/src/prog8/code/ast/AstStatements.kt +++ b/codeCore/src/prog8/code/ast/AstStatements.kt @@ -155,13 +155,6 @@ class PtVariable(name: String, override val type: DataType, val zeropage: Zeropa init { value?.let {it.parent=this} } - - val bss: Boolean = - when (type) { - DataType.STR -> false - in ArrayDatatypes -> value==null || arraySize==0u - else -> value==null - } } diff --git a/compiler/src/prog8/CompilerMain.kt b/compiler/src/prog8/CompilerMain.kt index dd232285a..88c2e116a 100644 --- a/compiler/src/prog8/CompilerMain.kt +++ b/compiler/src/prog8/CompilerMain.kt @@ -43,7 +43,7 @@ private fun compileMain(args: Array): Boolean { val experimentalCodegen by cli.option(ArgType.Boolean, fullName = "expericodegen", description = "use experimental/alternative codegen") val dontWriteAssembly by cli.option(ArgType.Boolean, fullName = "noasm", description="don't create assembly code") val dontOptimize by cli.option(ArgType.Boolean, fullName = "noopt", description = "don't perform any optimizations") - val dontReinitGlobals by cli.option(ArgType.Boolean, fullName = "noreinit", description = "don't create code to reinitialize globals on multiple runs of the program (experimental)") + val dontReinitGlobals by cli.option(ArgType.Boolean, fullName = "noreinit", description = "don't create code to reinitialize globals on multiple runs of the program") val outputDir by cli.option(ArgType.String, fullName = "out", description = "directory for output files instead of current directory").default(".") val optimizeFloatExpressions by cli.option(ArgType.Boolean, fullName = "optfloatx", description = "optimize float expressions (warning: can increase program size)") val quietAssembler by cli.option(ArgType.Boolean, fullName = "quietasm", description = "don't print assembler output results") diff --git a/compiler/test/TestSymbolTable.kt b/compiler/test/TestSymbolTable.kt index fef5f6cee..fb9c4509e 100644 --- a/compiler/test/TestSymbolTable.kt +++ b/compiler/test/TestSymbolTable.kt @@ -124,10 +124,10 @@ private fun makeSt(): SymbolTable { block1.add(sub12) block1.add(StConstant("c1", DataType.UWORD, 12345.0, astConstant1)) block1.add(StConstant("blockc", DataType.UWORD, 999.0, astConstant2)) - sub11.add(StStaticVariable("v1", DataType.BYTE, true, null, null, null, null, ZeropageWish.DONTCARE, astSub1v1)) - sub11.add(StStaticVariable("v2", DataType.BYTE, true, null, null, null, null, ZeropageWish.DONTCARE, astSub1v2)) - sub12.add(StStaticVariable("v1", DataType.BYTE, true, null, null, null, null, ZeropageWish.DONTCARE, astSub2v1)) - sub12.add(StStaticVariable("v2", DataType.BYTE, true, null, null, null, null, ZeropageWish.DONTCARE, astSub2v2)) + sub11.add(StStaticVariable("v1", DataType.BYTE, null, null, null, null, ZeropageWish.DONTCARE, astSub1v1)) + sub11.add(StStaticVariable("v2", DataType.BYTE, null, null, null, null, ZeropageWish.DONTCARE, astSub1v2)) + sub12.add(StStaticVariable("v1", DataType.BYTE, null, null, null, null, ZeropageWish.DONTCARE, astSub2v1)) + sub12.add(StStaticVariable("v2", DataType.BYTE, null, null, null, null, ZeropageWish.DONTCARE, astSub2v2)) val block2 = StNode("block2", StNodeType.BLOCK, astBlock2) val sub21 = StNode("sub1", StNodeType.SUBROUTINE, astSub21) diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 836ac103b..170255b6c 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,15 +3,14 @@ TODO For next minor release ^^^^^^^^^^^^^^^^^^^^^^ -- fix hasInitValue() and isBssVar() - BSS. 64tass can put variables into a section with .section BSS .send BSS and then putting .dsection BSS where it should output the BSS Define vars in BSS with .fill rather than .byte otherwise they STILL take up space! -- BSS in 6502 codegen: create BSS section in output assembly code and put StStaticVariables in there with bss=true. +- BSS in 6502 codegen: create BSS section in output assembly code and put StStaticVariables in there with uninitialized=true. Don't forget to add init code to zero out everything that was put in bss. If array in bss->only zero ONCE if possible. - Note that 'bss' can still be true for variables that were moved into zeropage, so have to check that! + Note that 'uninitialized' can still be true for variables that were moved into zeropage, so have to check that! - BSS subroutine parameters don't have to be set to 0. - when putting BSS in specific memory block ($a000-$bfff, $c000-$cfff) add a .cerror check for overflow! diff --git a/intermediate/src/prog8/intermediate/IRFileReader.kt b/intermediate/src/prog8/intermediate/IRFileReader.kt index b7acf1e2c..6c993740c 100644 --- a/intermediate/src/prog8/intermediate/IRFileReader.kt +++ b/intermediate/src/prog8/intermediate/IRFileReader.kt @@ -172,7 +172,7 @@ class IRFileReader { val dt: DataType = parseDatatype(type, arraysize!=null) val zp = if(zpwish.isBlank()) ZeropageWish.DONTCARE else ZeropageWish.valueOf(zpwish) val dummyNode = PtVariable(name, dt, zp, null, null, Position.DUMMY) - val newVar = StStaticVariable(name, dt, true, null, null, null, arraysize, zp, dummyNode) + val newVar = StStaticVariable(name, dt, null, null, null, arraysize, zp, dummyNode) variables.add(newVar) } return variables @@ -202,40 +202,23 @@ class IRFileReader { val arraysize = if(arrayspec.isNotBlank()) arrayspec.substring(1, arrayspec.length-1).toInt() else null val dt: DataType = parseDatatype(type, arraysize!=null) val zp = if(zpwish.isBlank()) ZeropageWish.DONTCARE else ZeropageWish.valueOf(zpwish) - val bss: Boolean var initNumeric: Double? = null var initArray: StArray? = null when(dt) { - in NumericDatatypes -> { - if(value.isBlank()) { - require(!dontReinitGlobals) - bss = true - } else { - require(dontReinitGlobals) - bss = false - initNumeric = parseIRValue(value).toDouble() - } - } + in NumericDatatypes -> initNumeric = parseIRValue(value).toDouble() in ArrayDatatypes -> { - if(value.isBlank()) { - bss = true - initArray = emptyList() - } else { - bss = false - initArray = value.split(',').map { - if (it.startsWith('@')) - StArrayElement(null, it.drop(1)) - else - StArrayElement(parseIRValue(it).toDouble(), null) - } + initArray = value.split(',').map { + if (it.startsWith('@')) + StArrayElement(null, it.drop(1)) + else + StArrayElement(parseIRValue(it).toDouble(), null) } } DataType.STR -> throw IRParseException("STR should have been converted to byte array") else -> throw IRParseException("weird dt") } - require(!bss) { "bss var should be in BSS section" } val dummyNode = PtVariable(name, dt, zp, null, null, Position.DUMMY) - variables.add(StStaticVariable(name, dt, bss, initNumeric, null, initArray, arraysize, zp, dummyNode)) + variables.add(StStaticVariable(name, dt, initNumeric, null, initArray, arraysize, zp, dummyNode)) } return variables } diff --git a/intermediate/src/prog8/intermediate/IRFileWriter.kt b/intermediate/src/prog8/intermediate/IRFileWriter.kt index a25d2fbc0..6b39e54a5 100644 --- a/intermediate/src/prog8/intermediate/IRFileWriter.kt +++ b/intermediate/src/prog8/intermediate/IRFileWriter.kt @@ -139,14 +139,16 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) { private fun writeVariables() { + val (variablesNoInit, variablesWithInit) = irProgram.st.allVariables().partition { it.uninitialized } + out.write("\n\n") - for (variable in irProgram.st.allVariables().filter { it.bss }) { + for (variable in variablesNoInit) { val typeStr = getTypeString(variable) out.write("$typeStr ${variable.name} zp=${variable.zpwish}\n") } out.write("\n\n") - for (variable in irProgram.st.allVariables().filter { !it.bss }) { + for (variable in variablesWithInit) { val typeStr = getTypeString(variable) val value: String = when(variable.dt) { DataType.FLOAT -> (variable.onetimeInitializationNumericValue ?: "").toString() diff --git a/intermediate/src/prog8/intermediate/IRSymbolTable.kt b/intermediate/src/prog8/intermediate/IRSymbolTable.kt index 891abeb54..cc258db5c 100644 --- a/intermediate/src/prog8/intermediate/IRSymbolTable.kt +++ b/intermediate/src/prog8/intermediate/IRSymbolTable.kt @@ -75,7 +75,7 @@ class IRSymbolTable(sourceSt: SymbolTable?) { } scopedName = variable.scopedName val dummyNode = PtVariable(scopedName, variable.dt, variable.zpwish, null, null, variable.astNode.position) - varToadd = StStaticVariable(scopedName, variable.dt, variable.bss, + varToadd = StStaticVariable(scopedName, variable.dt, variable.onetimeInitializationNumericValue, variable.onetimeInitializationStringValue, fixupAddressOfInArray(variable.onetimeInitializationArrayValue), diff --git a/intermediate/test/TestIRFileInOut.kt b/intermediate/test/TestIRFileInOut.kt index 58021a360..f2ab57b93 100644 --- a/intermediate/test/TestIRFileInOut.kt +++ b/intermediate/test/TestIRFileInOut.kt @@ -110,7 +110,7 @@ return program.st.allVariables().count() shouldBe 2 val var1 = program.st.lookup("sys.wait.jiffies") as StStaticVariable val var2 = program.st.lookup("sys.bssvar") as StStaticVariable - var1.bss shouldBe false - var2.bss shouldBe true + var1.uninitialized shouldBe false + var2.uninitialized shouldBe true } }) \ No newline at end of file diff --git a/virtualmachine/src/prog8/vm/VmProgramLoader.kt b/virtualmachine/src/prog8/vm/VmProgramLoader.kt index 7bb22aeba..34b8d89f4 100644 --- a/virtualmachine/src/prog8/vm/VmProgramLoader.kt +++ b/virtualmachine/src/prog8/vm/VmProgramLoader.kt @@ -177,7 +177,7 @@ class VmProgramLoader { var addr = allocations.allocations.getValue(variable.name) // zero out uninitialized variables. - if(variable.bss) { + if(variable.uninitialized) { if(variable.dt in ArrayDatatypes) { repeat(variable.length!!) { when(variable.dt) { @@ -222,10 +222,10 @@ class VmProgramLoader { require(variable.length==it.size || it.size==1 || it.size==0) if(it.isEmpty() || it.size==1) { val value = if(it.isEmpty()) { - require(variable.bss) + require(variable.uninitialized) 0.0 } else { - require(!variable.bss) + require(!variable.uninitialized) it[0].number!! } when(variable.dt) {