mirror of
https://github.com/irmen/prog8.git
synced 2024-11-22 15:33:02 +00:00
ir: uninitialized vars remain empty, bss section classifier (unused for now as there are no segements yet)
This commit is contained in:
parent
9f09784b55
commit
7c1bdfe713
@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1 +1 @@
|
||||
8.6.2
|
||||
8.7-dev
|
||||
|
@ -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.
|
||||
|
@ -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 -> {
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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 -> {
|
||||
initArray = value.split(',').map {
|
||||
if(it.startsWith('&'))
|
||||
StArrayElement(null, it.drop(1).split('.'))
|
||||
else
|
||||
StArrayElement(it.toDouble(), null)
|
||||
if(value.isBlank()) {
|
||||
bss = true
|
||||
initArray = emptyList()
|
||||
} else {
|
||||
bss = false
|
||||
initArray = value.split(',').map {
|
||||
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
|
||||
}
|
||||
|
@ -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")
|
||||
|
@ -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),
|
||||
|
@ -52,7 +52,7 @@ evalStackBaseAddress=null
|
||||
</OPTIONS>
|
||||
|
||||
<VARIABLES>
|
||||
uword sys.wait.jiffies=0 zp=DONTCARE
|
||||
uword sys.wait.jiffies= zp=DONTCARE
|
||||
</VARIABLES>
|
||||
|
||||
<MEMORYMAPPEDVARIABLES>
|
||||
|
@ -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!!) {
|
||||
|
Loading…
Reference in New Issue
Block a user