retain constants in IR

some IR related cleanups
This commit is contained in:
Irmen de Jong
2024-12-23 23:29:33 +01:00
parent 4c1e2f3110
commit 5071da6784
15 changed files with 158 additions and 141 deletions

View File

@@ -42,6 +42,7 @@ class SymbolTable(astProgram: PtProgram) : StNode(astProgram.name, StNodeType.GL
} }
val allVariables: Collection<StStaticVariable> by lazy { val allVariables: Collection<StStaticVariable> by lazy {
// can't be done with a generic function because those don't support local recursive functions yet
val vars = mutableListOf<StStaticVariable>() val vars = mutableListOf<StStaticVariable>()
fun collect(node: StNode) { fun collect(node: StNode) {
for(child in node.children) { for(child in node.children) {
@@ -56,6 +57,7 @@ class SymbolTable(astProgram: PtProgram) : StNode(astProgram.name, StNodeType.GL
} }
val allMemMappedVariables: Collection<StMemVar> by lazy { val allMemMappedVariables: Collection<StMemVar> by lazy {
// can't be done with a generic function because those don't support local recursive functions yet
val vars = mutableListOf<StMemVar>() val vars = mutableListOf<StMemVar>()
fun collect(node: StNode) { fun collect(node: StNode) {
for(child in node.children) { for(child in node.children) {
@@ -70,6 +72,7 @@ class SymbolTable(astProgram: PtProgram) : StNode(astProgram.name, StNodeType.GL
} }
val allMemorySlabs: Collection<StMemorySlab> by lazy { val allMemorySlabs: Collection<StMemorySlab> by lazy {
// can't be done with a generic function because those don't support local recursive functions yet
val vars = mutableListOf<StMemorySlab>() val vars = mutableListOf<StMemorySlab>()
fun collect(node: StNode) { fun collect(node: StNode) {
for(child in node.children) { for(child in node.children) {
@@ -113,7 +116,7 @@ enum class StNodeType {
open class StNode(val name: String, open class StNode(val name: String,
val type: StNodeType, val type: StNodeType,
val astNode: PtNode, val astNode: PtNode?,
val children: MutableMap<String, StNode> = mutableMapOf() val children: MutableMap<String, StNode> = mutableMapOf()
) { ) {
@@ -187,7 +190,7 @@ class StStaticVariable(name: String,
val length: Int?, // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte val length: Int?, // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte
val zpwish: ZeropageWish, // used in the variable allocator val zpwish: ZeropageWish, // used in the variable allocator
val align: Int, val align: Int,
astNode: PtNode) : StNode(name, StNodeType.STATICVAR, astNode) { astNode: PtNode?) : StNode(name, StNodeType.STATICVAR, astNode) {
var initializationNumericValue: Double? = null var initializationNumericValue: Double? = null
private set private set
@@ -229,7 +232,7 @@ class StStaticVariable(name: String,
} }
class StConstant(name: String, val dt: BaseDataType, val value: Double, astNode: PtNode) : class StConstant(name: String, val dt: BaseDataType, val value: Double, astNode: PtNode?) :
StNode(name, StNodeType.CONSTANT, astNode) StNode(name, StNodeType.CONSTANT, astNode)
@@ -237,7 +240,7 @@ class StMemVar(name: String,
val dt: DataType, val dt: DataType,
val address: UInt, val address: UInt,
val length: Int?, // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte val length: Int?, // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte
astNode: PtNode) : astNode: PtNode?) :
StNode(name, StNodeType.MEMVAR, astNode) { StNode(name, StNodeType.MEMVAR, astNode) {
init{ init{
@@ -251,7 +254,7 @@ class StMemorySlab(
name: String, name: String,
val size: UInt, val size: UInt,
val align: UInt, val align: UInt,
astNode: PtNode astNode: PtNode?
): ):
StNode(name, StNodeType.MEMORYSLAB, astNode) StNode(name, StNodeType.MEMORYSLAB, astNode)

View File

@@ -59,7 +59,7 @@ class AsmGen6502(val prefixSymbols: Boolean, private val lastGeneratedLabelSeque
} }
is PtFunctionCall -> { is PtFunctionCall -> {
val stNode = st.lookup(node.name)!! val stNode = st.lookup(node.name)!!
if(stNode.astNode.definingBlock()?.options?.noSymbolPrefixing!=true) { if(stNode.astNode!!.definingBlock()?.options?.noSymbolPrefixing!=true) {
val index = node.parent.children.indexOf(node) val index = node.parent.children.indexOf(node)
functionCallsToPrefix += node.parent to index functionCallsToPrefix += node.parent to index
} }
@@ -70,7 +70,7 @@ class AsmGen6502(val prefixSymbols: Boolean, private val lastGeneratedLabelSeque
lookupName = lookupName.dropLast(4) lookupName = lookupName.dropLast(4)
} }
val stNode = st.lookup(lookupName) ?: throw AssemblyError("unknown identifier $node") val stNode = st.lookup(lookupName) ?: throw AssemblyError("unknown identifier $node")
if(stNode.astNode.definingBlock()?.options?.noSymbolPrefixing!=true) { if(stNode.astNode!!.definingBlock()?.options?.noSymbolPrefixing!=true) {
val index = node.parent.children.indexOf(node) val index = node.parent.children.indexOf(node)
nodesToPrefix += node.parent to index nodesToPrefix += node.parent to index
} }
@@ -1268,7 +1268,7 @@ $repeatLabel""")
val node = stScope.astNode val node = stScope.astNode
if(node is PtSubroutineParameter) if(node is PtSubroutineParameter)
return node return node
return node.definingSub()?.parameters?.singleOrNull { it.name===name } return node!!.definingSub()?.parameters?.singleOrNull { it.name===name }
} }
internal fun assignByteOperandsToAAndVar(left: PtExpression, right: PtExpression, rightVarName: String) { internal fun assignByteOperandsToAAndVar(left: PtExpression, right: PtExpression, rightVarName: String) {

View File

@@ -60,7 +60,7 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
variable.scopedName, variable.scopedName,
variable.dt, variable.dt,
variable.length, variable.length,
variable.astNode.position, variable.astNode?.position ?: Position.DUMMY,
errors errors
) )
result.fold( result.fold(
@@ -68,7 +68,7 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
numVariablesAllocatedInZP++ numVariablesAllocatedInZP++
}, },
failure = { failure = {
errors.err(it.message!!, variable.astNode.position) errors.err(it.message!!, variable.astNode?.position ?: Position.DUMMY)
} }
) )
} }
@@ -79,7 +79,7 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
variable.scopedName, variable.scopedName,
variable.dt, variable.dt,
variable.length, variable.length,
variable.astNode.position, variable.astNode?.position ?: Position.DUMMY,
errors errors
) )
result.onSuccess { numVariablesAllocatedInZP++ } result.onSuccess { numVariablesAllocatedInZP++ }
@@ -99,7 +99,7 @@ internal class VariableAllocator(private val symboltable: SymbolTable,
variable.scopedName, variable.scopedName,
variable.dt, variable.dt,
variable.length, variable.length,
variable.astNode.position, variable.astNode?.position ?: Position.DUMMY,
errors errors
) )
result.onSuccess { numVariablesAllocatedInZP++ } result.onSuccess { numVariablesAllocatedInZP++ }

View File

@@ -25,7 +25,7 @@ class IRCodeGen(
verifyNameScoping(program, symbolTable) verifyNameScoping(program, symbolTable)
changeGlobalVarInits(symbolTable) changeGlobalVarInits(symbolTable)
val irSymbolTable = IRSymbolTable.fromStDuringCodegen(symbolTable) val irSymbolTable = IRSymbolTable.fromAstSymboltable(symbolTable)
val irProg = IRProgram(program.name, irSymbolTable, options, program.encoding) val irProg = IRProgram(program.name, irSymbolTable, options, program.encoding)
// collect global variables initializers // collect global variables initializers
@@ -486,7 +486,7 @@ class IRCodeGen(
it += IRInstruction(Opcode.STOREM, irType(DataType.forDt(elementDt)), reg1=tmpReg, labelSymbol = loopvarSymbol) it += IRInstruction(Opcode.STOREM, irType(DataType.forDt(elementDt)), reg1=tmpReg, labelSymbol = loopvarSymbol)
} }
result += translateNode(forLoop.statements) result += translateNode(forLoop.statements)
result += addConstReg(IRDataType.BYTE, indexReg, elementSize) result += addConstIntToReg(IRDataType.BYTE, indexReg, elementSize)
result += IRCodeChunk(null, null).also { result += IRCodeChunk(null, null).also {
if(lengthBytes!=256) { if(lengthBytes!=256) {
// for length 256, the compare is actually against 0, which doesn't require a separate CMP instruction // for length 256, the compare is actually against 0, which doesn't require a separate CMP instruction
@@ -639,7 +639,7 @@ class IRCodeGen(
return result return result
} }
private fun addConstReg(dt: IRDataType, reg: Int, value: Int): IRCodeChunk { private fun addConstIntToReg(dt: IRDataType, reg: Int, value: Int): IRCodeChunk {
val code = IRCodeChunk(null, null) val code = IRCodeChunk(null, null)
when(value) { when(value) {
0 -> { /* do nothing */ } 0 -> { /* do nothing */ }

View File

@@ -94,7 +94,7 @@ private fun integrateDefers(subdefers: Map<PtSub, List<PtDefer>>, program: PtPro
val identifier = node.target as? PtIdentifier val identifier = node.target as? PtIdentifier
if (identifier != null) { if (identifier != null) {
val stNode = st.lookup(identifier.name)!! val stNode = st.lookup(identifier.name)!!
val targetSub = stNode.astNode.definingSub() val targetSub = stNode.astNode!!.definingSub()
if (targetSub != node.definingSub()) if (targetSub != node.definingSub())
jumpsAndCallsToAugment.add(node) jumpsAndCallsToAugment.add(node)
} }

View File

@@ -23,6 +23,8 @@ class TestLaunchEmu: FunSpec({
</VARIABLESNOINIT> </VARIABLESNOINIT>
<VARIABLESWITHINIT> <VARIABLESWITHINIT>
</VARIABLESWITHINIT> </VARIABLESWITHINIT>
<CONSTANTS>
</CONSTANTS>
<MEMORYMAPPEDVARIABLES> <MEMORYMAPPEDVARIABLES>
</MEMORYMAPPEDVARIABLES> </MEMORYMAPPEDVARIABLES>

View File

@@ -21,7 +21,7 @@ class TestSymbolTable: FunSpec({
st.type shouldBe StNodeType.GLOBAL st.type shouldBe StNodeType.GLOBAL
st.children shouldBe mutableMapOf() st.children shouldBe mutableMapOf()
st.astNode shouldBeSameInstanceAs astNode st.astNode shouldBeSameInstanceAs astNode
st.astNode.position shouldBe Position.DUMMY st.astNode!!.position shouldBe Position.DUMMY
} }
test("symboltable flatten") { test("symboltable flatten") {

View File

@@ -46,8 +46,9 @@ Future Things and Ideas
IR/VM IR/VM
----- -----
- cx16.r0-r15 should not be translated to their (fake) addresses but remain symbolical, so they can be translated to what the actual target system specifies for them.
- prefix immediate values with '#' for readability reasons (no technical reason)
- ExpressionCodeResult: get rid of the separation between single result register and multiple result registers? - ExpressionCodeResult: get rid of the separation between single result register and multiple result registers?
- constants are not retained in the IR file, they should. (need to be able to make asm labels from them eventually)
- implement missing operators in AssignmentGen (array shifts etc) - implement missing operators in AssignmentGen (array shifts etc)
- support %align on code chunks - support %align on code chunks
- fix call() return value handling - fix call() return value handling

View File

@@ -1,40 +1,14 @@
%import sprites
%import palette
%import math
%zeropage basicsafe %zeropage basicsafe
%option no_sysinit %option no_sysinit
main { main {
sub start() { sub start() {
word[128] xpos const ubyte CVALUE = 123
word[128] ypos const long CLONG = 555555
ubyte @shared vvalue = 99
for cx16.r2L in 0 to 127 { cx16.r0L = CVALUE + 100
sprites.init(cx16.r2L, 0, 0, sprites.SIZE_8, sprites.SIZE_8, sprites.COLORS_16, 0) cx16.r1L = vvalue + 100
xpos[cx16.r2L] = math.rndw() & 511 as word + 64
ypos[cx16.r2L] = math.rnd()
}
repeat {
sys.waitvsync()
palette.set_color(6, $f00)
sprites.pos_batch(0, 128, &xpos, &ypos)
palette.set_color(6, $0f0)
for cx16.r2L in 0 to 127 {
if cx16.r2L & 1 == 0 {
xpos[cx16.r2L] ++
if xpos[cx16.r2L] > 640
xpos[cx16.r2L] = 0
} else {
ypos[cx16.r2L] ++
if ypos[cx16.r2L] > 480
ypos[cx16.r2L] = 0
}
}
palette.set_color(6, $00f)
}
} }
} }

View File

@@ -1,6 +1,7 @@
package prog8.intermediate package prog8.intermediate
import prog8.code.* import prog8.code.*
import prog8.code.ast.PtConstant
import prog8.code.ast.PtVariable import prog8.code.ast.PtVariable
import prog8.code.core.* import prog8.code.core.*
import prog8.code.target.VMTarget import prog8.code.target.VMTarget
@@ -52,6 +53,7 @@ class IRFileReader {
val asmsymbols = parseAsmSymbols(reader) val asmsymbols = parseAsmSymbols(reader)
val varsWithoutInit = parseVarsWithoutInit(reader) val varsWithoutInit = parseVarsWithoutInit(reader)
val variables = parseVariables(reader) val variables = parseVariables(reader)
val constants = parseConstants(reader)
val memorymapped = parseMemMapped(reader) val memorymapped = parseMemMapped(reader)
val slabs = parseSlabs(reader) val slabs = parseSlabs(reader)
val initGlobals = parseInitGlobals(reader) val initGlobals = parseInitGlobals(reader)
@@ -61,6 +63,7 @@ class IRFileReader {
asmsymbols.forEach { (name, value) -> st.addAsmSymbol(name, value)} asmsymbols.forEach { (name, value) -> st.addAsmSymbol(name, value)}
varsWithoutInit.forEach { st.add(it) } varsWithoutInit.forEach { st.add(it) }
variables.forEach { st.add(it) } variables.forEach { st.add(it) }
constants.forEach { st.add(it) }
memorymapped.forEach { st.add(it) } memorymapped.forEach { st.add(it) }
slabs.forEach { st.add(it) } slabs.forEach { st.add(it) }
@@ -165,19 +168,45 @@ class IRFileReader {
val match = varPattern.matchEntire(line) ?: throw IRParseException("invalid VARIABLESNOINIT $line") val match = varPattern.matchEntire(line) ?: throw IRParseException("invalid VARIABLESNOINIT $line")
val (type, arrayspec, name, zpwish, alignment) = match.destructured val (type, arrayspec, name, zpwish, alignment) = match.destructured
if('.' !in name) if('.' !in name)
throw IRParseException("unscoped varname: $name") throw IRParseException("unscoped name: $name")
val arraysize = if(arrayspec.isNotBlank()) arrayspec.substring(1, arrayspec.length-1).toInt() else null val arraysize = if(arrayspec.isNotBlank()) arrayspec.substring(1, arrayspec.length-1).toInt() else null
val dt = parseDatatype(type, arraysize!=null) val dt = parseDatatype(type, arraysize!=null)
val zp = if(zpwish.isBlank()) ZeropageWish.DONTCARE else ZeropageWish.valueOf(zpwish) val zp = if(zpwish.isBlank()) ZeropageWish.DONTCARE else ZeropageWish.valueOf(zpwish)
val align = if(alignment.isBlank()) 0u else alignment.toUInt() val align = if(alignment.isBlank()) 0u else alignment.toUInt()
val dummyNode = PtVariable(name, dt, zp, align, null, null, Position.DUMMY) val newVar = StStaticVariable(name, dt, null, null, arraysize, zp, align.toInt(), null)
val newVar = StStaticVariable(name, dt, null, null, arraysize, zp, align.toInt(), dummyNode)
variables.add(newVar) variables.add(newVar)
} }
return variables return variables
} }
} }
private fun parseConstants(reader: XMLEventReader): List<StConstant> {
skipText(reader)
val start = reader.nextEvent().asStartElement()
require(start.name.localPart=="CONSTANTS") { "missing CONSTANTS" }
val text = readText(reader).trim()
require(reader.nextEvent().isEndElement)
return if(text.isBlank())
emptyList()
else {
val constantPattern = Regex("(.+?) (.+)=(.*?)")
val constants = mutableListOf<StConstant>()
text.lineSequence().forEach { line ->
// examples:
// uword main.start.qq2=0
val match = constantPattern.matchEntire(line) ?: throw IRParseException("invalid CONSTANT $line")
val (type, name, valueStr) = match.destructured
if('.' !in name)
throw IRParseException("unscoped name: $name")
val dt = parseDatatype(type, false)
val value = parseIRValue(valueStr)
constants.add(StConstant(name, dt.base, value, null))
}
return constants
}
}
private fun parseVariables(reader: XMLEventReader): List<StStaticVariable> { private fun parseVariables(reader: XMLEventReader): List<StStaticVariable> {
skipText(reader) skipText(reader)
val start = reader.nextEvent().asStartElement() val start = reader.nextEvent().asStartElement()
@@ -223,11 +252,10 @@ class IRFileReader {
dt.isString -> throw IRParseException("STR should have been converted to byte array") dt.isString -> throw IRParseException("STR should have been converted to byte array")
else -> throw IRParseException("weird dt") else -> throw IRParseException("weird dt")
} }
val dummyNode = PtVariable(name, dt, zp, align, null, null, Position.DUMMY)
if(arraysize!=null && initArray!=null && initArray.all { it.number==0.0 }) { if(arraysize!=null && initArray!=null && initArray.all { it.number==0.0 }) {
initArray=null // arrays with just zeros can be left uninitialized initArray=null // arrays with just zeros can be left uninitialized
} }
val stVar = StStaticVariable(name, dt, null, initArray, arraysize, zp, align.toInt(), dummyNode) val stVar = StStaticVariable(name, dt, null, initArray, arraysize, zp, align.toInt(), null)
if(initNumeric!=null) if(initNumeric!=null)
stVar.setOnetimeInitNumeric(initNumeric) stVar.setOnetimeInitNumeric(initNumeric)
variables.add(stVar) variables.add(stVar)
@@ -256,16 +284,7 @@ class IRFileReader {
val (type, arrayspec, name, address) = match.destructured val (type, arrayspec, name, address) = match.destructured
val arraysize = if(arrayspec.isNotBlank()) arrayspec.substring(1, arrayspec.length-1).toInt() else null val arraysize = if(arrayspec.isNotBlank()) arrayspec.substring(1, arrayspec.length-1).toInt() else null
val dt = parseDatatype(type, arraysize!=null) val dt = parseDatatype(type, arraysize!=null)
val dummyNode = PtVariable( memvars.add(StMemVar(name, dt, parseIRValue(address).toUInt(), arraysize, null))
name,
dt,
ZeropageWish.NOT_IN_ZEROPAGE,
0u,
null,
null,
Position.DUMMY
)
memvars.add(StMemVar(name, dt, parseIRValue(address).toUInt(), arraysize, dummyNode))
} }
memvars memvars
} }
@@ -287,16 +306,7 @@ class IRFileReader {
// example: "slabname 4096 0" // example: "slabname 4096 0"
val match = slabPattern.matchEntire(line) ?: throw IRParseException("invalid slab $line") val match = slabPattern.matchEntire(line) ?: throw IRParseException("invalid slab $line")
val (name, size, align) = match.destructured val (name, size, align) = match.destructured
val dummyNode = PtVariable( slabs.add(StMemorySlab(name, size.toUInt(), align.toUInt(), null))
name,
DataType.arrayFor(BaseDataType.UBYTE, false),
ZeropageWish.NOT_IN_ZEROPAGE,
0u,
null,
null,
Position.DUMMY
)
slabs.add(StMemorySlab(name, size.toUInt(), align.toUInt(), dummyNode))
} }
slabs slabs
} }
@@ -520,6 +530,7 @@ class IRFileReader {
"word" -> DataType.arrayFor(BaseDataType.WORD, false) "word" -> DataType.arrayFor(BaseDataType.WORD, false)
"uword" -> DataType.arrayFor(BaseDataType.UWORD, false) "uword" -> DataType.arrayFor(BaseDataType.UWORD, false)
"float" -> DataType.arrayFor(BaseDataType.FLOAT, false) "float" -> DataType.arrayFor(BaseDataType.FLOAT, false)
"long" -> DataType.arrayFor(BaseDataType.LONG, false)
else -> throw IRParseException("invalid dt $type") else -> throw IRParseException("invalid dt $type")
} }
} else { } else {
@@ -530,6 +541,7 @@ class IRFileReader {
"word" -> DataType.forDt(BaseDataType.WORD) "word" -> DataType.forDt(BaseDataType.WORD)
"uword" -> DataType.forDt(BaseDataType.UWORD) "uword" -> DataType.forDt(BaseDataType.UWORD)
"float" -> DataType.forDt(BaseDataType.FLOAT) "float" -> DataType.forDt(BaseDataType.FLOAT)
"long" -> DataType.forDt(BaseDataType.LONG)
// note: 'str' should not occur anymore in IR. Should be 'uword' // note: 'str' should not occur anymore in IR. Should be 'uword'
else -> throw IRParseException("invalid dt $type") else -> throw IRParseException("invalid dt $type")
} }

View File

@@ -148,10 +148,13 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
if(code.sourceLinesPositions.any {it !== Position.DUMMY}) { if(code.sourceLinesPositions.any {it !== Position.DUMMY}) {
xml.writeStartElement("P8SRC") xml.writeStartElement("P8SRC")
val sourceTxt = StringBuilder("\n") val sourceTxt = StringBuilder("\n")
code.sourceLinesPositions.filter{ pos -> pos.line>0 }.forEach { pos -> code.sourceLinesPositions
val line = ImportFileSystem.retrieveSourceLine(pos) .filter{ pos -> pos.line > 0 }
sourceTxt.append("$pos $line\n") .sortedBy { it.line }
} .forEach { pos ->
val line = ImportFileSystem.retrieveSourceLine(pos)
sourceTxt.append("$pos $line\n")
}
xml.writeCData(sourceTxt.toString()) xml.writeCData(sourceTxt.toString())
xml.writeEndElement() xml.writeEndElement()
} }
@@ -212,6 +215,17 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
} }
} }
fun writeConstant(constant: IRStConstant) {
val dt = constant.dt
val value: String = when {
dt.isBool -> constant.value.toInt().toString()
dt.isFloat -> constant.value.toString()
dt.isInteger -> constant.value.toInt().toHex()
else -> throw InternalCompilerException("weird dt")
}
xml.writeCharacters("${constant.typeString} ${constant.name}=$value\n")
}
fun writeVarWithInit(variable: IRStStaticVariable) { fun writeVarWithInit(variable: IRStStaticVariable) {
if(variable.dt.isSplitWordArray) { if(variable.dt.isSplitWordArray) {
val lsbValue: String val lsbValue: String
@@ -240,7 +254,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
val value: String = when { val value: String = when {
dt.isBool -> variable.onetimeInitializationNumericValue?.toInt()?.toString() ?: "" dt.isBool -> variable.onetimeInitializationNumericValue?.toInt()?.toString() ?: ""
dt.isFloat -> (variable.onetimeInitializationNumericValue ?: "").toString() dt.isFloat -> (variable.onetimeInitializationNumericValue ?: "").toString()
dt.isNumeric -> variable.onetimeInitializationNumericValue?.toInt()?.toHex() ?: "" dt.isInteger -> variable.onetimeInitializationNumericValue?.toInt()?.toHex() ?: ""
dt.isString -> { dt.isString -> {
val encoded = irProgram.encoding.encodeString(variable.onetimeInitializationStringValue!!.first, variable.onetimeInitializationStringValue.second) + listOf(0u) val encoded = irProgram.encoding.encodeString(variable.onetimeInitializationStringValue!!.first, variable.onetimeInitializationStringValue.second) + listOf(0u)
encoded.joinToString(",") { it.toInt().toString() } encoded.joinToString(",") { it.toInt().toString() }
@@ -285,12 +299,11 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
for (variable in noinitAligned.sortedBy { it.align }) { for (variable in noinitAligned.sortedBy { it.align }) {
writeNoInitVar(variable) writeNoInitVar(variable)
} }
xml.writeEndElement() xml.writeEndElement()
xml.writeCharacters("\n") xml.writeCharacters("\n")
xml.writeStartElement("VARIABLESWITHINIT") xml.writeStartElement("VARIABLESWITHINIT")
xml.writeCharacters("\n") xml.writeCharacters("\n")
val (initNotAligned, initAligned) = variablesWithInit.partition { it.align==0 || it.align==1 } val (initNotAligned, initAligned) = variablesWithInit.partition { it.align==0 || it.align==1 }
for (variable in initNotAligned) { for (variable in initNotAligned) {
writeVarWithInit(variable) writeVarWithInit(variable)
@@ -301,6 +314,14 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
xml.writeEndElement() xml.writeEndElement()
xml.writeCharacters("\n") xml.writeCharacters("\n")
xml.writeStartElement("CONSTANTS")
xml.writeCharacters("\n")
for (constant in irProgram.st.allConstants()) {
writeConstant(constant)
}
xml.writeEndElement()
xml.writeCharacters("\n")
xml.writeStartElement("MEMORYMAPPEDVARIABLES") xml.writeStartElement("MEMORYMAPPEDVARIABLES")
xml.writeCharacters("\n") xml.writeCharacters("\n")
for (variable in irProgram.st.allMemMappedVariables()) { for (variable in irProgram.st.allMemMappedVariables()) {

View File

@@ -11,6 +11,7 @@ PROGRAM:
OPTIONS (from CompilationOptions) OPTIONS (from CompilationOptions)
ASMSYMBOLS (from command line defined symbols) ASMSYMBOLS (from command line defined symbols)
VARIABLES (from Symboltable) VARIABLES (from Symboltable)
CONSTANTS (form Symboltable)
MEMORYMAPPEDVARIABLES (from Symboltable) MEMORYMAPPEDVARIABLES (from Symboltable)
MEMORYSLABS (from Symboltable) MEMORYSLABS (from Symboltable)
INITGLOBALS INITGLOBALS

View File

@@ -13,17 +13,17 @@ class IRSymbolTable {
private val asmSymbols = mutableMapOf<String, String>() private val asmSymbols = mutableMapOf<String, String>()
companion object { companion object {
fun fromStDuringCodegen(sourceSt: SymbolTable?): IRSymbolTable { fun fromAstSymboltable(sourceSt: SymbolTable?): IRSymbolTable {
val st = IRSymbolTable() val st = IRSymbolTable()
if (sourceSt != null) { if (sourceSt != null) {
sourceSt.allVariables.forEach { sourceSt.flat.forEach {
st.add(it) when(it.value.type) {
} StNodeType.STATICVAR -> st.add(it.value as StStaticVariable)
sourceSt.allMemMappedVariables.forEach { StNodeType.MEMVAR -> st.add(it.value as StMemVar)
st.add(it) StNodeType.CONSTANT -> st.add(it.value as StConstant)
} StNodeType.MEMORYSLAB -> st.add(it.value as StMemorySlab)
sourceSt.allMemorySlabs.forEach { else -> { }
st.add(it) }
} }
require(st.table.all { it.key == it.value.name }) require(st.table.all { it.key == it.value.name })
@@ -44,6 +44,9 @@ class IRSymbolTable {
} }
} }
fun allConstants(): Sequence<IRStConstant> =
table.asSequence().map { it.value }.filterIsInstance<IRStConstant>()
fun allVariables(): Sequence<IRStStaticVariable> = fun allVariables(): Sequence<IRStStaticVariable> =
table.asSequence().map { it.value }.filterIsInstance<IRStStaticVariable>() table.asSequence().map { it.value }.filterIsInstance<IRStStaticVariable>()
@@ -60,7 +63,14 @@ class IRSymbolTable {
val varToadd: IRStStaticVariable val varToadd: IRStStaticVariable
if('.' in variable.name) { if('.' in variable.name) {
scopedName = variable.name scopedName = variable.name
varToadd = IRStStaticVariable.from(variable) varToadd = IRStStaticVariable(variable.name,
variable.dt,
variable.initializationNumericValue,
variable.initializationStringValue,
variable.initializationArrayValue?.map { convertArrayElt(it) },
variable.length,
variable.zpwish,
variable.align)
} else { } else {
fun fixupAddressOfInArray(array: List<StArrayElement>?): List<IRStArrayElement>? { fun fixupAddressOfInArray(array: List<StArrayElement>?): List<IRStArrayElement>? {
if(array==null) if(array==null)
@@ -71,7 +81,7 @@ class IRSymbolTable {
val target = variable.lookup(it.addressOfSymbol!!) ?: throw NoSuchElementException("can't find variable ${it.addressOfSymbol}") val target = variable.lookup(it.addressOfSymbol!!) ?: throw NoSuchElementException("can't find variable ${it.addressOfSymbol}")
newArray.add(IRStArrayElement(null, null, target.scopedName)) newArray.add(IRStArrayElement(null, null, target.scopedName))
} else { } else {
newArray.add(IRStArrayElement.from(it)) newArray.add(convertArrayElt(it))
} }
} }
return newArray return newArray
@@ -90,13 +100,17 @@ class IRSymbolTable {
table[scopedName] = varToadd table[scopedName] = varToadd
} }
fun add(variable: StMemVar) { fun add(variable: StMemVar) {
val scopedName: String val scopedName: String
val varToadd: IRStMemVar val varToadd: IRStMemVar
if('.' in variable.name) { if('.' in variable.name) {
scopedName = variable.name scopedName = variable.name
varToadd = IRStMemVar.from(variable) varToadd = IRStMemVar(
variable.name,
variable.dt,
variable.address,
variable.length
)
} else { } else {
scopedName = try { scopedName = try {
variable.scopedName variable.scopedName
@@ -110,13 +124,28 @@ class IRSymbolTable {
fun add(variable: StMemorySlab) { fun add(variable: StMemorySlab) {
val varToadd = if('.' in variable.name) val varToadd = if('.' in variable.name)
IRStMemorySlab.from(variable) IRStMemorySlab(variable.name, variable.size, variable.align)
else { else {
IRStMemorySlab("prog8_slabs.${variable.name}", variable.size, variable.align) IRStMemorySlab("prog8_slabs.${variable.name}", variable.size, variable.align)
} }
table[varToadd.name] = varToadd table[varToadd.name] = varToadd
} }
fun add(constant: StConstant) {
val scopedName: String
val dt = DataType.forDt(constant.dt)
if('.' in constant.name) {
scopedName = constant.name
} else {
scopedName = try {
constant.scopedName
} catch (_: UninitializedPropertyAccessException) {
constant.name
}
}
table[scopedName] = IRStConstant(scopedName, dt, constant.value)
}
fun addAsmSymbol(name: String, value: String) { fun addAsmSymbol(name: String, value: String) {
asmSymbols[name] = value asmSymbols[name] = value
} }
@@ -133,15 +162,20 @@ class IRSymbolTable {
} }
} }
} }
private fun convertArrayElt(elt: StArrayElement): IRStArrayElement = if(elt.boolean!=null)
IRStArrayElement(elt.boolean, null, elt.addressOfSymbol)
else
IRStArrayElement(null, elt.number, elt.addressOfSymbol)
} }
enum class IRStNodeType { enum class IRStNodeType {
STATICVAR, STATICVAR,
MEMVAR, MEMVAR,
MEMORYSLAB MEMORYSLAB,
// the other StNodeType types aren't used here anymore. CONST
// this symbol table only contains variables.
} }
open class IRStNode(val name: String, open class IRStNode(val name: String,
@@ -154,17 +188,6 @@ class IRStMemVar(name: String,
val address: UInt, val address: UInt,
val length: Int? // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte val length: Int? // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte
) : IRStNode(name, IRStNodeType.MEMVAR) { ) : IRStNode(name, IRStNodeType.MEMVAR) {
companion object {
fun from(variable: StMemVar): IRStMemVar {
return IRStMemVar(
variable.name,
variable.dt,
variable.address,
variable.length
)
}
}
init { init {
require(!dt.isString) require(!dt.isString)
} }
@@ -176,18 +199,14 @@ class IRStMemorySlab(
name: String, name: String,
val size: UInt, val size: UInt,
val align: UInt val align: UInt
): IRStNode(name, IRStNodeType.MEMORYSLAB) { ): IRStNode(name, IRStNodeType.MEMORYSLAB)
companion object {
fun from(variable: StMemorySlab): IRStMemorySlab {
return IRStMemorySlab( class IRStConstant(name: String, val dt: DataType, val value: Double) : IRStNode(name, IRStNodeType.CONST) {
variable.name, val typeString: String = dt.irTypeString(null)
variable.size,
variable.align
)
}
}
} }
class IRStStaticVariable(name: String, class IRStStaticVariable(name: String,
val dt: DataType, val dt: DataType,
val onetimeInitializationNumericValue: Double?, // regular (every-run-time) initialization is done via regular assignments val onetimeInitializationNumericValue: Double?, // regular (every-run-time) initialization is done via regular assignments
@@ -197,19 +216,6 @@ class IRStStaticVariable(name: String,
val zpwish: ZeropageWish, // used in the variable allocator val zpwish: ZeropageWish, // used in the variable allocator
val align: Int val align: Int
) : IRStNode(name, IRStNodeType.STATICVAR) { ) : IRStNode(name, IRStNodeType.STATICVAR) {
companion object {
fun from(variable: StStaticVariable): IRStStaticVariable {
return IRStStaticVariable(variable.name,
variable.dt,
variable.initializationNumericValue,
variable.initializationStringValue,
variable.initializationArrayValue?.map { IRStArrayElement.from(it) },
variable.length,
variable.zpwish,
variable.align)
}
}
init { init {
if(align > 0) { if(align > 0) {
require(dt.isString || dt.isArray) require(dt.isString || dt.isArray)
@@ -223,15 +229,6 @@ class IRStStaticVariable(name: String,
} }
class IRStArrayElement(val bool: Boolean?, val number: Double?, val addressOfSymbol: String?) { class IRStArrayElement(val bool: Boolean?, val number: Double?, val addressOfSymbol: String?) {
companion object {
fun from(elt: StArrayElement): IRStArrayElement {
return if(elt.boolean!=null)
IRStArrayElement(elt.boolean, null, elt.addressOfSymbol)
else
IRStArrayElement(null, elt.number, elt.addressOfSymbol)
}
}
init { init {
if(bool!=null) require(number==null && addressOfSymbol==null) if(bool!=null) require(number==null && addressOfSymbol==null)
if(number!=null) require(bool==null && addressOfSymbol==null) if(number!=null) require(bool==null && addressOfSymbol==null)

View File

@@ -58,6 +58,9 @@ uword sys.bssvar zp=DONTCARE align=0
uword sys.wait.jiffies=10 zp=DONTCARE align=0 uword sys.wait.jiffies=10 zp=DONTCARE align=0
ubyte[3] sys.emptystring=0,0,0 zp=DONTCARE align=0 ubyte[3] sys.emptystring=0,0,0 zp=DONTCARE align=0
</VARIABLESWITHINIT> </VARIABLESWITHINIT>
<CONSTANTS>
ubyte main.thing=42
</CONSTANTS>
<MEMORYMAPPEDVARIABLES> <MEMORYMAPPEDVARIABLES>
@uword cx16.r0=65282 @uword cx16.r0=65282
@@ -104,6 +107,7 @@ return
program.name shouldBe "test-ir-reader" program.name shouldBe "test-ir-reader"
program.blocks.size shouldBe 2 program.blocks.size shouldBe 2
program.st.allVariables().count() shouldBe 3 program.st.allVariables().count() shouldBe 3
program.st.allConstants().count() shouldBe 1
val var1 = program.st.lookup("sys.wait.jiffies") as IRStStaticVariable val var1 = program.st.lookup("sys.wait.jiffies") as IRStStaticVariable
val var2 = program.st.lookup("sys.bssvar") as IRStStaticVariable val var2 = program.st.lookup("sys.bssvar") as IRStStaticVariable
val var3 = program.st.lookup("sys.emptystring") as IRStStaticVariable val var3 = program.st.lookup("sys.emptystring") as IRStStaticVariable

View File

@@ -105,6 +105,8 @@ class TestVm: FunSpec( {
</VARIABLESNOINIT> </VARIABLESNOINIT>
<VARIABLESWITHINIT> <VARIABLESWITHINIT>
</VARIABLESWITHINIT> </VARIABLESWITHINIT>
<CONSTANTS>
</CONSTANTS>
<MEMORYMAPPEDVARIABLES> <MEMORYMAPPEDVARIABLES>
</MEMORYMAPPEDVARIABLES> </MEMORYMAPPEDVARIABLES>