ir: several fixes

This commit is contained in:
Irmen de Jong 2023-07-07 15:43:09 +02:00
parent 02e51d8282
commit 3126959576
10 changed files with 128 additions and 70 deletions

View File

@ -80,6 +80,16 @@ class SymbolTable(astProgram: PtProgram) : StNode(astProgram.name, StNodeType.GL
} }
override fun lookup(scopedName: String) = flat[scopedName] override fun lookup(scopedName: String) = flat[scopedName]
fun getLength(name: String): Int? {
val node = flat[name]
return when(node) {
is StMemVar -> node.length
is StMemorySlab -> node.size.toInt()
is StStaticVariable -> node.length
else -> null
}
}
} }

View File

@ -484,8 +484,8 @@ internal class ProgramAndVarsGen(
val vars = allocator.zeropageVars.filter { it.value.dt==DataType.STR } val vars = allocator.zeropageVars.filter { it.value.dt==DataType.STR }
for (variable in vars) { for (variable in vars) {
val scopedName = variable.key val scopedName = variable.key
val svar = symboltable.flat.getValue(scopedName) as StStaticVariable val svar = symboltable.lookup(scopedName) as? StStaticVariable
if(svar.onetimeInitializationStringValue!=null) if(svar?.onetimeInitializationStringValue!=null)
result.add(ZpStringWithInitial(scopedName, variable.value, svar.onetimeInitializationStringValue!!)) result.add(ZpStringWithInitial(scopedName, variable.value, svar.onetimeInitializationStringValue!!))
} }
return result return result
@ -496,8 +496,8 @@ internal class ProgramAndVarsGen(
val vars = allocator.zeropageVars.filter { it.value.dt in ArrayDatatypes } val vars = allocator.zeropageVars.filter { it.value.dt in ArrayDatatypes }
for (variable in vars) { for (variable in vars) {
val scopedName = variable.key val scopedName = variable.key
val svar = symboltable.flat.getValue(scopedName) as StStaticVariable val svar = symboltable.lookup(scopedName) as? StStaticVariable
if(svar.onetimeInitializationArrayValue!=null) if(svar?.onetimeInitializationArrayValue!=null)
result.add(ZpArrayWithInitial(scopedName, variable.value, svar.onetimeInitializationArrayValue!!)) result.add(ZpArrayWithInitial(scopedName, variable.value, svar.onetimeInitializationArrayValue!!))
} }
return result return result

View File

@ -1,6 +1,5 @@
package prog8.codegen.intermediate package prog8.codegen.intermediate
import prog8.code.StStaticVariable
import prog8.code.ast.* import prog8.code.ast.*
import prog8.code.core.AssemblyError import prog8.code.core.AssemblyError
import prog8.code.core.DataType import prog8.code.core.DataType
@ -219,8 +218,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
} }
val fixedIndex = constIntValue(targetArray.index) val fixedIndex = constIntValue(targetArray.index)
val iterable = codeGen.symbolTable.flat.getValue(targetArray.variable.name) as StStaticVariable val arrayLength = codeGen.symbolTable.getLength(targetArray.variable.name)
val arrayLength = iterable.length!!
if(zero) { if(zero) {
if(fixedIndex!=null) { if(fixedIndex!=null) {
val chunk = IRCodeChunk(null, null).also { val chunk = IRCodeChunk(null, null).also {

View File

@ -119,7 +119,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
private fun funcAny(call: PtBuiltinFunctionCall): ExpressionCodeResult { private fun funcAny(call: PtBuiltinFunctionCall): ExpressionCodeResult {
val arrayName = call.args[0] as PtIdentifier val arrayName = call.args[0] as PtIdentifier
val array = codeGen.symbolTable.flat.getValue(arrayName.name) as StStaticVariable val array = codeGen.symbolTable.lookup(arrayName.name) as StStaticVariable // TODO FIX/TEST for memory mapped array
val syscall = val syscall =
when (array.dt) { when (array.dt) {
DataType.ARRAY_UB, DataType.ARRAY_UB,
@ -140,7 +140,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
private fun funcAll(call: PtBuiltinFunctionCall): ExpressionCodeResult { private fun funcAll(call: PtBuiltinFunctionCall): ExpressionCodeResult {
val arrayName = call.args[0] as PtIdentifier val arrayName = call.args[0] as PtIdentifier
val array = codeGen.symbolTable.flat.getValue(arrayName.name) as StStaticVariable val array = codeGen.symbolTable.lookup(arrayName.name) as StStaticVariable // TODO FIX/TEST for memory mapped array
val syscall = val syscall =
when(array.dt) { when(array.dt) {
DataType.ARRAY_UB, DataType.ARRAY_UB,
@ -287,7 +287,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
private fun funcReverse(call: PtBuiltinFunctionCall): ExpressionCodeResult { private fun funcReverse(call: PtBuiltinFunctionCall): ExpressionCodeResult {
val arrayName = call.args[0] as PtIdentifier val arrayName = call.args[0] as PtIdentifier
val array = codeGen.symbolTable.flat.getValue(arrayName.name) as StStaticVariable val array = codeGen.symbolTable.lookup(arrayName.name) as StStaticVariable // TODO FIX/TEST for memory mapped array
val syscall = val syscall =
when(array.dt) { when(array.dt) {
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.STR -> IMSyscall.REVERSE_BYTES DataType.ARRAY_UB, DataType.ARRAY_B, DataType.STR -> IMSyscall.REVERSE_BYTES
@ -307,7 +307,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
private fun funcSort(call: PtBuiltinFunctionCall): ExpressionCodeResult { private fun funcSort(call: PtBuiltinFunctionCall): ExpressionCodeResult {
val arrayName = call.args[0] as PtIdentifier val arrayName = call.args[0] as PtIdentifier
val array = codeGen.symbolTable.flat.getValue(arrayName.name) as StStaticVariable val array = codeGen.symbolTable.lookup(arrayName.name) as StStaticVariable // TODO FIX/TEST for memory mapped array
val syscall = val syscall =
when(array.dt) { when(array.dt) {
DataType.ARRAY_UB -> IMSyscall.SORT_UBYTE DataType.ARRAY_UB -> IMSyscall.SORT_UBYTE

View File

@ -106,7 +106,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
private fun translate(check: PtContainmentCheck): ExpressionCodeResult { private fun translate(check: PtContainmentCheck): ExpressionCodeResult {
val result = mutableListOf<IRCodeChunkBase>() val result = mutableListOf<IRCodeChunkBase>()
val iterable = codeGen.symbolTable.flat.getValue(check.iterable.name) as StStaticVariable val iterable = codeGen.symbolTable.lookup(check.iterable.name) as StStaticVariable // TODO FIX/TEST for memory mapped array , replace with check.iterable.type???
when(iterable.dt) { when(iterable.dt) {
DataType.STR -> { DataType.STR -> {
val elementTr = translateExpression(check.element) val elementTr = translateExpression(check.element)
@ -164,8 +164,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
if(arrayIx.splitWords) { if(arrayIx.splitWords) {
require(vmDt==IRDataType.WORD) require(vmDt==IRDataType.WORD)
val iterable = codeGen.symbolTable.flat.getValue(arrayIx.variable.name) as StStaticVariable val arrayLength = codeGen.symbolTable.getLength(arrayIx.variable.name)
val arrayLength = iterable.length!!
resultRegister = codeGen.registers.nextFree() resultRegister = codeGen.registers.nextFree()
if(arrayIx.index is PtNumber) { if(arrayIx.index is PtNumber) {
val memOffset = (arrayIx.index as PtNumber).number.toInt() val memOffset = (arrayIx.index as PtNumber).number.toInt()

View File

@ -168,6 +168,11 @@ class IRCodeGen(
replacements.forEach { replacements.forEach {
val old = it.first.instructions[it.second] val old = it.first.instructions[it.second]
val formats = instructionFormats.getValue(old.opcode)
val format = formats.getOrElse(old.type) { throw IllegalArgumentException("type ${old.type} invalid for ${old.opcode}") }
val immediateValue = if(format.immediate) it.third.toInt() else null
val addressValue = if(format.immediate) null else it.third.toInt()
it.first.instructions[it.second] = IRInstruction( it.first.instructions[it.second] = IRInstruction(
old.opcode, old.opcode,
old.type, old.type,
@ -175,9 +180,9 @@ class IRCodeGen(
old.reg2, old.reg2,
old.fpReg1, old.fpReg1,
old.fpReg2, old.fpReg2,
immediate = immediateValue,
null, null,
null, address = addressValue,
address = it.third.toInt(),
null, null,
null null
) )
@ -447,60 +452,63 @@ class IRCodeGen(
result += translateForInNonConstantRange(forLoop, loopvar) result += translateForInNonConstantRange(forLoop, loopvar)
} }
is PtIdentifier -> { is PtIdentifier -> {
val iterableVar = symbolTable.lookup(iterable.name) as StStaticVariable
require(forLoop.variable.name == loopvar.scopedName) require(forLoop.variable.name == loopvar.scopedName)
val iterableLength = symbolTable.getLength(iterable.name)
val loopvarSymbol = forLoop.variable.name val loopvarSymbol = forLoop.variable.name
val indexReg = registers.nextFree() val indexReg = registers.nextFree()
val tmpReg = registers.nextFree() val tmpReg = registers.nextFree()
val loopLabel = createLabelName() val loopLabel = createLabelName()
val endLabel = createLabelName() val endLabel = createLabelName()
if(iterableVar.dt==DataType.STR) { when (iterable.type) {
// iterate over a zero-terminated string DataType.STR -> {
addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = indexReg, immediate = 0), null) // iterate over a zero-terminated string
result += IRCodeChunk(loopLabel, null).also { addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = indexReg, immediate = 0), null)
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1 = tmpReg, reg2 = indexReg, labelSymbol = iterable.name) result += IRCodeChunk(loopLabel, null).also {
it += IRInstruction(Opcode.BEQ, IRDataType.BYTE, reg1 = tmpReg, immediate = 0, labelSymbol = endLabel) it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1 = tmpReg, reg2 = indexReg, labelSymbol = iterable.name)
it += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1 = tmpReg, labelSymbol = loopvarSymbol) it += IRInstruction(Opcode.BEQ, IRDataType.BYTE, reg1 = tmpReg, immediate = 0, labelSymbol = endLabel)
it += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1 = tmpReg, labelSymbol = loopvarSymbol)
}
result += translateNode(forLoop.statements)
val jumpChunk = IRCodeChunk(null, null)
jumpChunk += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1 = indexReg)
jumpChunk += IRInstruction(Opcode.JUMP, labelSymbol = loopLabel)
result += jumpChunk
result += IRCodeChunk(endLabel, null)
} }
result += translateNode(forLoop.statements) in SplitWordArrayTypes -> {
val jumpChunk = IRCodeChunk(null, null) // iterate over lsb/msb split word array
jumpChunk += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1 = indexReg) val elementDt = ArrayToElementTypes.getValue(iterable.type)
jumpChunk += IRInstruction(Opcode.JUMP, labelSymbol = loopLabel) if(elementDt !in WordDatatypes)
result += jumpChunk throw AssemblyError("weird dt")
result += IRCodeChunk(endLabel, null) addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, immediate = 0), null)
} else if(iterable.type in SplitWordArrayTypes) { result += IRCodeChunk(loopLabel, null).also {
// iterate over lsb/msb split word array val tmpRegLsb = registers.nextFree()
val elementDt = ArrayToElementTypes.getValue(iterable.type) val tmpRegMsb = registers.nextFree()
if(elementDt !in WordDatatypes) it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpRegLsb, reg2=indexReg, immediate = iterableLength, labelSymbol=iterable.name+"_lsb")
throw AssemblyError("weird dt") it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpRegMsb, reg2=indexReg, immediate = iterableLength, labelSymbol=iterable.name+"_msb")
val length = iterableVar.length!! it += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=tmpRegLsb, reg2=tmpRegMsb)
addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, immediate = 0), null) it += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpRegLsb, labelSymbol = loopvarSymbol)
result += IRCodeChunk(loopLabel, null).also { }
val tmpRegLsb = registers.nextFree() result += translateNode(forLoop.statements)
val tmpRegMsb = registers.nextFree() result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpRegLsb, reg2=indexReg, immediate = length, labelSymbol=iterable.name+"_lsb") it += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=indexReg)
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpRegMsb, reg2=indexReg, immediate = length, labelSymbol=iterable.name+"_msb") it += IRInstruction(Opcode.BNE, IRDataType.BYTE, reg1=indexReg, immediate = if(iterableLength==256) 0 else iterableLength, labelSymbol = loopLabel)
it += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=tmpRegLsb, reg2=tmpRegMsb) }
it += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpRegLsb, labelSymbol = loopvarSymbol)
} }
result += translateNode(forLoop.statements) else -> {
result += IRCodeChunk(null, null).also { // iterate over regular array
it += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=indexReg) val elementDt = ArrayToElementTypes.getValue(iterable.type)
it += IRInstruction(Opcode.BNE, IRDataType.BYTE, reg1=indexReg, immediate = if(length==256) 0 else length, labelSymbol = loopLabel) val elementSize = program.memsizer.memorySize(elementDt)
val lengthBytes = iterableLength!! * elementSize
addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, immediate = 0), null)
result += IRCodeChunk(loopLabel, null).also {
it += IRInstruction(Opcode.LOADX, irType(elementDt), reg1=tmpReg, reg2=indexReg, labelSymbol=iterable.name)
it += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpReg, labelSymbol = loopvarSymbol)
}
result += translateNode(forLoop.statements)
result += addConstReg(IRDataType.BYTE, indexReg, elementSize)
addInstr(result, IRInstruction(Opcode.BNE, IRDataType.BYTE, reg1=indexReg, immediate = if(lengthBytes==256) 0 else lengthBytes, labelSymbol = loopLabel), null)
} }
} else {
// iterate over regular array
val elementDt = ArrayToElementTypes.getValue(iterable.type)
val elementSize = program.memsizer.memorySize(elementDt)
val lengthBytes = iterableVar.length!! * elementSize
addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, immediate = 0), null)
result += IRCodeChunk(loopLabel, null).also {
it += IRInstruction(Opcode.LOADX, irType(elementDt), reg1=tmpReg, reg2=indexReg, labelSymbol=iterable.name)
it += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpReg, labelSymbol = loopvarSymbol)
}
result += translateNode(forLoop.statements)
result += addConstReg(IRDataType.BYTE, indexReg, elementSize)
addInstr(result, IRInstruction(Opcode.BNE, IRDataType.BYTE, reg1=indexReg, immediate = if(lengthBytes==256) 0 else lengthBytes, labelSymbol = loopLabel), null)
} }
} }
else -> throw AssemblyError("weird for iterable") else -> throw AssemblyError("weird for iterable")
@ -1362,7 +1370,6 @@ class IRCodeGen(
if(array?.splitWords==true) { if(array?.splitWords==true) {
val variable = array.variable.name val variable = array.variable.name
val fixedIndex = constIntValue(array.index) val fixedIndex = constIntValue(array.index)
val iterable = symbolTable.flat.getValue(array.variable.name) as StStaticVariable
if(fixedIndex!=null) { if(fixedIndex!=null) {
val skipLabel = createLabelName() val skipLabel = createLabelName()
when(postIncrDecr.operator) { when(postIncrDecr.operator) {
@ -1388,7 +1395,7 @@ class IRCodeGen(
else -> throw AssemblyError("weird operator") else -> throw AssemblyError("weird operator")
} }
} else { } else {
val arrayLength = iterable.length!! val arrayLength = symbolTable.getLength(array.variable.name)
val indexTr = expressionEval.translateExpression(array.index) val indexTr = expressionEval.translateExpression(array.index)
addToResult(result, indexTr, indexTr.resultReg, -1) addToResult(result, indexTr, indexTr.resultReg, -1)
val incReg = registers.nextFree() val incReg = registers.nextFree()
@ -1611,7 +1618,7 @@ class IRCodeGen(
private fun translate(parameters: List<PtSubroutineParameter>) = private fun translate(parameters: List<PtSubroutineParameter>) =
parameters.map { parameters.map {
val flattenedName = it.definingSub()!!.name + "." + it.name val flattenedName = it.definingSub()!!.name + "." + it.name
val orig = symbolTable.flat.getValue(flattenedName) as StStaticVariable val orig = symbolTable.lookup(flattenedName) as StStaticVariable // TODO FIX/TEST for memory mapped array or other
IRSubroutine.IRParam(flattenedName, orig.dt) IRSubroutine.IRParam(flattenedName, orig.dt)
} }

View File

@ -139,6 +139,18 @@ class IRUnusedCodeRemover(
.children.single { it is IRSubroutine && it.label=="main.start" } .children.single { it is IRSubroutine && it.label=="main.start" }
val reachable = mutableSetOf((entrypointSub as IRSubroutine).chunks.first()) val reachable = mutableSetOf((entrypointSub as IRSubroutine).chunks.first())
// all chunks referenced in array initializer values are also 'reachable':
irprog.st.allVariables()
.filter { !it.uninitialized }
.forEach {
it.onetimeInitializationArrayValue?.let { array ->
array.forEach {elt ->
if(elt.addressOfSymbol!=null && irprog.st.lookup(elt.addressOfSymbol!!)==null)
reachable.add(irprog.getChunkWithLabel(elt.addressOfSymbol!!))
}
}
}
fun grow() { fun grow() {
val new = mutableSetOf<IRCodeChunkBase>() val new = mutableSetOf<IRCodeChunkBase>()
reachable.forEach { reachable.forEach {
@ -167,6 +179,18 @@ class IRUnusedCodeRemover(
private fun removeSimpleUnlinked(allLabeledChunks: Map<String, IRCodeChunkBase>): Int { private fun removeSimpleUnlinked(allLabeledChunks: Map<String, IRCodeChunkBase>): Int {
val linkedChunks = mutableSetOf<IRCodeChunkBase>() val linkedChunks = mutableSetOf<IRCodeChunkBase>()
// all chunks referenced in array initializer values are linked as well!:
irprog.st.allVariables()
.filter { !it.uninitialized }
.forEach {
it.onetimeInitializationArrayValue?.let { array ->
array.forEach {elt ->
if(elt.addressOfSymbol!=null && irprog.st.lookup(elt.addressOfSymbol!!)==null)
linkedChunks += irprog.getChunkWithLabel(elt.addressOfSymbol!!)
}
}
}
irprog.foreachCodeChunk { chunk -> irprog.foreachCodeChunk { chunk ->
chunk.next?.let { next -> linkedChunks += next } chunk.next?.let { next -> linkedChunks += next }
chunk.instructions.forEach { chunk.instructions.forEach {

View File

@ -1,8 +1,8 @@
TODO TODO
==== ====
- Fix wrong unused subroutines in expericodegen with cx16 shell - Fix possible ST type error: // TODO FIX/TEST for memory mapped array
- Fix expericodegen errors (chess, assem, musicdemo, rockrunners etc) - Fix expericodegen errors (chess, assem, musicdemo, rockrunners)
... ...

View File

@ -1,10 +1,21 @@
%import textio %import textio
%zeropage basicsafe
main { main {
romsub $FFD2 = chrout(ubyte ch @ A)
sub start() { sub start() {
ubyte ch = '2' ; uword[] routines = [ 0, &command, $4444 ]
chrout(ch) ; cx16.r0 = routines[1]
&ubyte[5] cells = $4000
cells = [1,2,3,4,5]
ubyte ub
for ub in cells {
txt.print_ub(ub)
txt.spc()
}
}
sub command() {
cx16.r0++
} }
} }

View File

@ -58,6 +58,15 @@ class IRProgram(val name: String,
fun allSubs(): Sequence<IRSubroutine> = blocks.asSequence().flatMap { it.children.filterIsInstance<IRSubroutine>() } fun allSubs(): Sequence<IRSubroutine> = blocks.asSequence().flatMap { it.children.filterIsInstance<IRSubroutine>() }
fun foreachSub(operation: (sub: IRSubroutine) -> Unit) = allSubs().forEach { operation(it) } fun foreachSub(operation: (sub: IRSubroutine) -> Unit) = allSubs().forEach { operation(it) }
fun foreachCodeChunk(operation: (chunk: IRCodeChunkBase) -> Unit) = allSubs().flatMap { it.chunks }.forEach { operation(it) } fun foreachCodeChunk(operation: (chunk: IRCodeChunkBase) -> Unit) = allSubs().flatMap { it.chunks }.forEach { operation(it) }
fun getChunkWithLabel(label: String): IRCodeChunkBase {
for(sub in allSubs()) {
for(chunk in sub.chunks) {
if(chunk.label==label)
return chunk
}
}
throw NoSuchElementException("no chunk with label '$label'")
}
fun addGlobalInits(chunk: IRCodeChunk) { fun addGlobalInits(chunk: IRCodeChunk) {
globalInits += chunk globalInits += chunk