diff --git a/codeCore/src/prog8/code/SymbolTable.kt b/codeCore/src/prog8/code/SymbolTable.kt index 82635abae..32dd8a6e5 100644 --- a/codeCore/src/prog8/code/SymbolTable.kt +++ b/codeCore/src/prog8/code/SymbolTable.kt @@ -80,6 +80,16 @@ class SymbolTable(astProgram: PtProgram) : StNode(astProgram.name, StNodeType.GL } 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 + } + } } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt index 343bb290c..812aec809 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt @@ -484,8 +484,8 @@ internal class ProgramAndVarsGen( val vars = allocator.zeropageVars.filter { it.value.dt==DataType.STR } for (variable in vars) { val scopedName = variable.key - val svar = symboltable.flat.getValue(scopedName) as StStaticVariable - if(svar.onetimeInitializationStringValue!=null) + val svar = symboltable.lookup(scopedName) as? StStaticVariable + if(svar?.onetimeInitializationStringValue!=null) result.add(ZpStringWithInitial(scopedName, variable.value, svar.onetimeInitializationStringValue!!)) } return result @@ -496,8 +496,8 @@ internal class ProgramAndVarsGen( val vars = allocator.zeropageVars.filter { it.value.dt in ArrayDatatypes } for (variable in vars) { val scopedName = variable.key - val svar = symboltable.flat.getValue(scopedName) as StStaticVariable - if(svar.onetimeInitializationArrayValue!=null) + val svar = symboltable.lookup(scopedName) as? StStaticVariable + if(svar?.onetimeInitializationArrayValue!=null) result.add(ZpArrayWithInitial(scopedName, variable.value, svar.onetimeInitializationArrayValue!!)) } return result diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt index 5dcdb0160..c9b97f5ad 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt @@ -1,6 +1,5 @@ package prog8.codegen.intermediate -import prog8.code.StStaticVariable import prog8.code.ast.* import prog8.code.core.AssemblyError 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 iterable = codeGen.symbolTable.flat.getValue(targetArray.variable.name) as StStaticVariable - val arrayLength = iterable.length!! + val arrayLength = codeGen.symbolTable.getLength(targetArray.variable.name) if(zero) { if(fixedIndex!=null) { val chunk = IRCodeChunk(null, null).also { diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt index b2886b48c..cdba61341 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt @@ -119,7 +119,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe private fun funcAny(call: PtBuiltinFunctionCall): ExpressionCodeResult { 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 = when (array.dt) { DataType.ARRAY_UB, @@ -140,7 +140,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe private fun funcAll(call: PtBuiltinFunctionCall): ExpressionCodeResult { 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 = when(array.dt) { DataType.ARRAY_UB, @@ -287,7 +287,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe private fun funcReverse(call: PtBuiltinFunctionCall): ExpressionCodeResult { 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 = when(array.dt) { 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 { 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 = when(array.dt) { DataType.ARRAY_UB -> IMSyscall.SORT_UBYTE diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt index c4b52e7cd..2bebb7134 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt @@ -106,7 +106,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { private fun translate(check: PtContainmentCheck): ExpressionCodeResult { val result = mutableListOf() - 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) { DataType.STR -> { val elementTr = translateExpression(check.element) @@ -164,8 +164,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { if(arrayIx.splitWords) { require(vmDt==IRDataType.WORD) - val iterable = codeGen.symbolTable.flat.getValue(arrayIx.variable.name) as StStaticVariable - val arrayLength = iterable.length!! + val arrayLength = codeGen.symbolTable.getLength(arrayIx.variable.name) resultRegister = codeGen.registers.nextFree() if(arrayIx.index is PtNumber) { val memOffset = (arrayIx.index as PtNumber).number.toInt() diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt index e8ba450c5..ff9dbf1ef 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt @@ -168,6 +168,11 @@ class IRCodeGen( replacements.forEach { 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( old.opcode, old.type, @@ -175,9 +180,9 @@ class IRCodeGen( old.reg2, old.fpReg1, old.fpReg2, + immediate = immediateValue, null, - null, - address = it.third.toInt(), + address = addressValue, null, null ) @@ -447,60 +452,63 @@ class IRCodeGen( result += translateForInNonConstantRange(forLoop, loopvar) } is PtIdentifier -> { - val iterableVar = symbolTable.lookup(iterable.name) as StStaticVariable require(forLoop.variable.name == loopvar.scopedName) + val iterableLength = symbolTable.getLength(iterable.name) val loopvarSymbol = forLoop.variable.name val indexReg = registers.nextFree() val tmpReg = registers.nextFree() val loopLabel = createLabelName() val endLabel = createLabelName() - if(iterableVar.dt==DataType.STR) { - // iterate over a zero-terminated string - addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = indexReg, immediate = 0), null) - result += IRCodeChunk(loopLabel, null).also { - it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1 = tmpReg, reg2 = indexReg, labelSymbol = iterable.name) - it += IRInstruction(Opcode.BEQ, IRDataType.BYTE, reg1 = tmpReg, immediate = 0, labelSymbol = endLabel) - it += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1 = tmpReg, labelSymbol = loopvarSymbol) + when (iterable.type) { + DataType.STR -> { + // iterate over a zero-terminated string + addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = indexReg, immediate = 0), null) + result += IRCodeChunk(loopLabel, null).also { + it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1 = tmpReg, reg2 = indexReg, labelSymbol = iterable.name) + 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) - 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) - } else if(iterable.type in SplitWordArrayTypes) { - // iterate over lsb/msb split word array - val elementDt = ArrayToElementTypes.getValue(iterable.type) - if(elementDt !in WordDatatypes) - throw AssemblyError("weird dt") - val length = iterableVar.length!! - addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, immediate = 0), null) - result += IRCodeChunk(loopLabel, null).also { - val tmpRegLsb = registers.nextFree() - val tmpRegMsb = registers.nextFree() - it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpRegLsb, reg2=indexReg, immediate = length, labelSymbol=iterable.name+"_lsb") - it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpRegMsb, reg2=indexReg, immediate = length, labelSymbol=iterable.name+"_msb") - it += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=tmpRegLsb, reg2=tmpRegMsb) - it += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpRegLsb, labelSymbol = loopvarSymbol) + in SplitWordArrayTypes -> { + // iterate over lsb/msb split word array + val elementDt = ArrayToElementTypes.getValue(iterable.type) + if(elementDt !in WordDatatypes) + throw AssemblyError("weird dt") + addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, immediate = 0), null) + result += IRCodeChunk(loopLabel, null).also { + val tmpRegLsb = registers.nextFree() + val tmpRegMsb = registers.nextFree() + it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpRegLsb, reg2=indexReg, immediate = iterableLength, labelSymbol=iterable.name+"_lsb") + it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpRegMsb, reg2=indexReg, immediate = iterableLength, labelSymbol=iterable.name+"_msb") + it += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=tmpRegLsb, reg2=tmpRegMsb) + it += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpRegLsb, labelSymbol = loopvarSymbol) + } + result += translateNode(forLoop.statements) + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=indexReg) + it += IRInstruction(Opcode.BNE, IRDataType.BYTE, reg1=indexReg, immediate = if(iterableLength==256) 0 else iterableLength, labelSymbol = loopLabel) + } } - result += translateNode(forLoop.statements) - result += IRCodeChunk(null, null).also { - it += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=indexReg) - it += IRInstruction(Opcode.BNE, IRDataType.BYTE, reg1=indexReg, immediate = if(length==256) 0 else length, labelSymbol = loopLabel) + else -> { + // iterate over regular array + val elementDt = ArrayToElementTypes.getValue(iterable.type) + 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") @@ -1362,7 +1370,6 @@ class IRCodeGen( if(array?.splitWords==true) { val variable = array.variable.name val fixedIndex = constIntValue(array.index) - val iterable = symbolTable.flat.getValue(array.variable.name) as StStaticVariable if(fixedIndex!=null) { val skipLabel = createLabelName() when(postIncrDecr.operator) { @@ -1388,7 +1395,7 @@ class IRCodeGen( else -> throw AssemblyError("weird operator") } } else { - val arrayLength = iterable.length!! + val arrayLength = symbolTable.getLength(array.variable.name) val indexTr = expressionEval.translateExpression(array.index) addToResult(result, indexTr, indexTr.resultReg, -1) val incReg = registers.nextFree() @@ -1611,7 +1618,7 @@ class IRCodeGen( private fun translate(parameters: List) = parameters.map { 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) } diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRUnusedCodeRemover.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRUnusedCodeRemover.kt index 4d69c1688..e11b70bdf 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRUnusedCodeRemover.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRUnusedCodeRemover.kt @@ -139,6 +139,18 @@ class IRUnusedCodeRemover( .children.single { it is IRSubroutine && it.label=="main.start" } 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() { val new = mutableSetOf() reachable.forEach { @@ -167,6 +179,18 @@ class IRUnusedCodeRemover( private fun removeSimpleUnlinked(allLabeledChunks: Map): Int { val linkedChunks = mutableSetOf() + // 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 -> chunk.next?.let { next -> linkedChunks += next } chunk.instructions.forEach { diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 2822f5e09..18a5eb344 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,8 +1,8 @@ TODO ==== -- Fix wrong unused subroutines in expericodegen with cx16 shell -- Fix expericodegen errors (chess, assem, musicdemo, rockrunners etc) +- Fix possible ST type error: // TODO FIX/TEST for memory mapped array +- Fix expericodegen errors (chess, assem, musicdemo, rockrunners) ... diff --git a/examples/test.p8 b/examples/test.p8 index ec333d23d..d32a124be 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,10 +1,21 @@ %import textio -%zeropage basicsafe main { - romsub $FFD2 = chrout(ubyte ch @ A) + sub start() { - ubyte ch = '2' - chrout(ch) +; uword[] routines = [ 0, &command, $4444 ] +; 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++ } } diff --git a/intermediate/src/prog8/intermediate/IRProgram.kt b/intermediate/src/prog8/intermediate/IRProgram.kt index 3f3ed1442..9ab325353 100644 --- a/intermediate/src/prog8/intermediate/IRProgram.kt +++ b/intermediate/src/prog8/intermediate/IRProgram.kt @@ -58,6 +58,15 @@ class IRProgram(val name: String, fun allSubs(): Sequence = blocks.asSequence().flatMap { it.children.filterIsInstance() } fun foreachSub(operation: (sub: IRSubroutine) -> Unit) = allSubs().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) { globalInits += chunk