ir: uninitialized vars remain empty, bss section classifier (unused for now as there are no segements yet)

This commit is contained in:
Irmen de Jong 2022-09-28 15:58:58 +02:00
parent 9f09784b55
commit 7c1bdfe713
13 changed files with 86 additions and 34 deletions

View File

@ -169,6 +169,7 @@ 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?,
@ -177,10 +178,19 @@ class StStaticVariable(name: String,
position: Position) : StNode(name, StNodeType.STATICVAR, position) {
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(length == onetimeInitializationArrayValue.size)
require(onetimeInitializationArrayValue.isEmpty() ||onetimeInitializationArrayValue.size==length)
}
if(onetimeInitializationNumericValue!=null)
require(dt in NumericDatatypes)
@ -193,7 +203,7 @@ class StStaticVariable(name: String,
}
override fun printProperties() {
print("$name dt=$dt zpw=$zpwish")
print("$name dt=$dt zpw=$zpwish bss=$bss")
}
}

View File

@ -1 +1 @@
8.6.2
8.7-dev

View File

@ -394,7 +394,7 @@ private fun createAssemblyAndAssemble(program: Program,
compilerOptions.compTarget.machine.initializeZeropage(compilerOptions)
program.processAstBeforeAsmGeneration(compilerOptions, errors)
errors.report()
val symbolTable = SymbolTableMaker().makeFrom(program)
val symbolTable = SymbolTableMaker().makeFrom(program, compilerOptions)
// TODO make removing all VarDecls work, but this needs inferType to be able to get its information from somewhere else as the VarDecl nodes in the Ast,
// or don't use inferType at all anymore and "bake the type information" into the Ast somehow.

View File

@ -7,6 +7,8 @@ import prog8.ast.statements.*
import prog8.ast.walk.IAstVisitor
import prog8.code.*
import prog8.code.core.ArrayDatatypes
import prog8.code.core.CompilationOptions
import prog8.code.core.DataType
import prog8.code.core.Position
import java.util.*
@ -14,10 +16,12 @@ internal class SymbolTableMaker: IAstVisitor {
private val st = SymbolTable()
private val scopestack = Stack<StNode>()
private var dontReinitGlobals = false
fun makeFrom(program: Program): SymbolTable {
fun makeFrom(program: Program, options: CompilationOptions): SymbolTable {
scopestack.clear()
st.children.clear()
dontReinitGlobals = options.dontReinitGlobals
this.visit(program)
program.builtinFunctions.names.forEach {
val node = StNode(it, StNodeType.BUILTINFUNC, Position.DUMMY)
@ -57,7 +61,7 @@ internal class SymbolTableMaker: IAstVisitor {
val node =
when(decl.type) {
VarDeclType.VAR -> {
val initialNumeric = (decl.value as? NumericLiteral)?.number
var initialNumeric = (decl.value as? NumericLiteral)?.number
val initialStringLit = decl.value as? StringLiteral
val initialString = if(initialStringLit==null) null else Pair(initialStringLit.value, initialStringLit.encoding)
val initialArrayLit = decl.value as? ArrayLiteral
@ -71,7 +75,15 @@ internal class SymbolTableMaker: IAstVisitor {
initialStringLit.value.length+1 // include the terminating 0-byte
else
null
StStaticVariable(decl.name, decl.datatype, initialNumeric, initialString, initialArray, numElements, decl.zeropage, decl.position)
val bss = if(decl.datatype==DataType.STR)
false
else if(decl.isArray)
initialArray.isNullOrEmpty()
else {
if(dontReinitGlobals) initialNumeric = initialNumeric ?: 0.0
initialNumeric == null
}
StStaticVariable(decl.name, decl.datatype, bss, initialNumeric, initialString, initialArray, numElements, decl.zeropage, decl.position)
}
VarDeclType.CONST -> StConstant(decl.name, decl.datatype, (decl.value as NumericLiteral).number, decl.position)
VarDeclType.MEMORY -> {

View File

@ -78,10 +78,10 @@ private fun makeSt(): SymbolTable {
block1.add(sub12)
block1.add(StConstant("c1", DataType.UWORD, 12345.0, Position.DUMMY))
block1.add(StConstant("blockc", DataType.UWORD, 999.0, Position.DUMMY))
sub11.add(StStaticVariable("v1", DataType.BYTE, null, null, null, null, ZeropageWish.DONTCARE, Position.DUMMY))
sub11.add(StStaticVariable("v2", DataType.BYTE, null, null, null, null, ZeropageWish.DONTCARE, Position.DUMMY))
sub12.add(StStaticVariable("v1", DataType.BYTE, null, null, null, null, ZeropageWish.DONTCARE, Position.DUMMY))
sub12.add(StStaticVariable("v2", DataType.BYTE, null, null, null, null, ZeropageWish.DONTCARE, Position.DUMMY))
sub11.add(StStaticVariable("v1", DataType.BYTE, true, null, null, null, null, ZeropageWish.DONTCARE, Position.DUMMY))
sub11.add(StStaticVariable("v2", DataType.BYTE, true, null, null, null, null, ZeropageWish.DONTCARE, Position.DUMMY))
sub12.add(StStaticVariable("v1", DataType.BYTE, true, null, null, null, null, ZeropageWish.DONTCARE, Position.DUMMY))
sub12.add(StStaticVariable("v2", DataType.BYTE, true, null, null, null, null, ZeropageWish.DONTCARE, Position.DUMMY))
val block2 = StNode("block2", StNodeType.BLOCK, Position.DUMMY)
val sub21 = StNode("sub1", StNodeType.SUBROUTINE, Position.DUMMY)

View File

@ -71,7 +71,7 @@ class TestAsmGenSymbols: StringSpec({
val errors = ErrorReporterForTests()
val options = CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, true, C64Target(), 999u)
options.compTarget.machine.zeropage = C64Zeropage(options)
val st = SymbolTableMaker().makeFrom(program)
val st = SymbolTableMaker().makeFrom(program, options)
return AsmGen(program, st, options, errors)
}

View File

@ -17,9 +17,9 @@ Future Things and Ideas
^^^^^^^^^^^^^^^^^^^^^^^
Compiler:
- vm/ir: put variables and arrays in BSS section (unless -noreinit is specified)
- create BSS section in output program and put StStaticVariables in there with bss=true. Don't forget to add init code to zero out everything that was put in bss. If array in bss->only zero ONCE! So requires self-modifying code
- vm: Jumps go to a code block rather than a specific address(label) -> also helps future dead code elimination?
- vm: the above means that every label introduces a new code block. This eliminates the use of actual labels altogether.
- vm: the above means that every label introduces a new code block. This eliminates the use of actual labels altogether during execution/translation.
- vm: add more optimizations in IRPeepholeOptimizer
- vm: how to remove all unused subroutines? (the 6502 assembly codegen relies on 64tass solve this for us)
- see if we can let for loops skip the loop if end<start, like other programming languages. Without adding a lot of code size/duplicating the loop condition.

View File

@ -1,5 +1,17 @@
%option enable_floats
main {
sub start() {
%asmbinary "bsieve.prg", 10, 200
ubyte @shared @zp var1 = 42
uword @shared @zp var2 = 4242
str @shared name = "irmen"
ubyte[] @shared array1 = [11,22,33,44]
uword[5] @shared array2 = 9999
uword[5] @shared array3
float @shared fvar = 1.234
float @shared fvar2
float[] @shared farray1 = [1.11,2.22,3.33]
float[5] @shared farray2 = 999.9
float[5] @shared farray3
}
}

View File

@ -112,7 +112,7 @@ class IRFileReader {
if(line!="<VARIABLES>")
throw IRParseException("invalid VARIABLES")
val variables = mutableListOf<StStaticVariable>()
val varPattern = Regex("(.+?)(\\[.+?\\])? (.+)=(.+?) (zp=(.+))?")
val varPattern = Regex("(.+?)(\\[.+?\\])? (.+)=(.*?) (zp=(.+))?")
while(true) {
line = lines.next()
if(line=="</VARIABLES>")
@ -125,27 +125,39 @@ 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(dontReinitGlobals) {
// we need to specify a one time initialization value
if(value.isBlank()) {
require(!dontReinitGlobals)
bss = true
} else {
require(dontReinitGlobals)
bss = false
initNumeric = value.toDouble()
}
}
in ArrayDatatypes -> {
if(value.isBlank()) {
bss = true
initArray = emptyList()
} else {
bss = false
initArray = value.split(',').map {
if(it.startsWith('&'))
if (it.startsWith('&'))
StArrayElement(null, it.drop(1).split('.'))
else
StArrayElement(it.toDouble(), null)
}
}
}
DataType.STR -> throw IRParseException("STR should have been converted to byte array")
else -> throw IRParseException("weird dt")
}
variables.add(StStaticVariable(name, dt, initNumeric, null, initArray, arraysize, zp, Position.DUMMY))
variables.add(StStaticVariable(name, dt, bss, initNumeric, null, initArray, arraysize, zp, Position.DUMMY))
}
return variables
}

View File

@ -101,12 +101,13 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
}
private fun writeVariableAllocations() {
out.write("\n<VARIABLES>\n")
for (variable in irProgram.st.allVariables()) {
val typeStr = getTypeString(variable)
val value: String = when(variable.dt) {
DataType.FLOAT -> (variable.onetimeInitializationNumericValue ?: 0.0).toString()
in NumericDatatypes -> (variable.onetimeInitializationNumericValue?.toInt()?.toString() ?: "0")
DataType.FLOAT -> (variable.onetimeInitializationNumericValue ?: "").toString()
in NumericDatatypes -> (variable.onetimeInitializationNumericValue?.toInt() ?: "").toString()
DataType.STR -> {
val encoded = irProgram.encoding.encodeString(variable.onetimeInitializationStringValue!!.first, variable.onetimeInitializationStringValue!!.second) + listOf(0u)
encoded.joinToString(",") { it.toInt().toString() }
@ -115,7 +116,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
if(variable.onetimeInitializationArrayValue!=null) {
variable.onetimeInitializationArrayValue!!.joinToString(",") { it.number!!.toString() }
} else {
(1..variable.length!!).joinToString(",") { "0" }
"" // array will be zero'd out at program start
}
}
in ArrayDatatypes -> {
@ -127,12 +128,11 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
"&${it.addressOf!!.joinToString(".")}"
}
} else {
(1..variable.length!!).joinToString(",") { "0" }
"" // array will be zero'd out at program start
}
}
else -> throw InternalCompilerException("weird dt")
}
// TODO have uninitialized variables and arrays? (BSS SECTION)
out.write("$typeStr ${variable.name}=$value zp=${variable.zpwish}\n")
}
out.write("</VARIABLES>\n")

View File

@ -70,7 +70,7 @@ class IRSymbolTable(sourceSt: SymbolTable?) {
return newArray
}
scopedName = variable.scopedName.joinToString(".")
varToadd = StStaticVariable(scopedName, variable.dt,
varToadd = StStaticVariable(scopedName, variable.dt, variable.bss,
variable.onetimeInitializationNumericValue,
variable.onetimeInitializationStringValue,
fixupAddressOfInArray(variable.onetimeInitializationArrayValue),

View File

@ -52,7 +52,7 @@ evalStackBaseAddress=null
</OPTIONS>
<VARIABLES>
uword sys.wait.jiffies=0 zp=DONTCARE
uword sys.wait.jiffies= zp=DONTCARE
</VARIABLES>
<MEMORYMAPPEDVARIABLES>

View File

@ -76,9 +76,15 @@ class VmProgramLoader {
}
}
variable.onetimeInitializationArrayValue?.let {
require(variable.length==it.size || it.size==1)
if(it.size==1) {
val value = it[0].number!!
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)
0.0
} else {
require(!variable.bss)
it[0].number!!
}
when(variable.dt) {
DataType.STR, DataType.ARRAY_UB -> {
repeat(variable.length!!) {