diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRUnusedCodeRemover.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRUnusedCodeRemover.kt index c2163bef1..5c5d14f01 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRUnusedCodeRemover.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRUnusedCodeRemover.kt @@ -25,18 +25,29 @@ class IRUnusedCodeRemover( } private fun pruneSymboltable(blockLabel: String) { - // we could clean up the SymbolTable as well, but ONLY if these symbols aren't referenced somewhere still in an instruction + // we could clean up the SymbolTable as well, but ONLY if these symbols aren't referenced somewhere still in an instruction or variable initializer value val prefix = "$blockLabel." val blockVars = irprog.st.allVariables().filter { it.name.startsWith(prefix) } blockVars.forEach { stVar -> - irprog. allSubs().flatMap { it.chunks }.forEach { chunk -> + irprog.allSubs().flatMap { it.chunks }.forEach { chunk -> chunk.instructions.forEach { ins -> if(ins.labelSymbol == stVar.name) { - return + return // symbol occurs in an instruction } } } + + irprog.st.allVariables().forEach { stVar-> + val initValue = stVar.onetimeInitializationArrayValue + if(initValue!=null && !initValue.isEmpty()) { + if(initValue.any { + it.addressOfSymbol?.startsWith(blockLabel)==true + }) + return // symbol occurs in an initializer value (address-of this symbol)_ + } + } } + irprog.st.removeTree(blockLabel) } @@ -207,9 +218,7 @@ class IRUnusedCodeRemover( return removeUnlinkedChunks(linkedChunks) } - private fun removeUnlinkedChunks( - linkedChunks: Set - ): Int { + private fun removeUnlinkedChunks(linkedChunks: Set): Int { var numRemoved = 0 irprog.foreachSub { sub -> sub.chunks.withIndex().reversed().forEach { (index, chunk) -> diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 498213b6b..da18ce56e 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,8 +1,6 @@ TODO ==== -- fix compiler error with vm/expericodegen: petaxian (minimal error cases in test.p8) - - [on branch: shortcircuit] investigate McCarthy evaluation again? this may also reduce code size perhaps for things like if a>4 or a<2 .... - IR: reduce the number of branch instructions such as BEQ, BEQR, etc (gradually), replace with CMP(I) + status branch instruction - IR: reduce amount of CMP/CMPI after instructions that set the status bits correctly (LOADs? INC? etc), but only after setting the status bits is verified! diff --git a/examples/test.p8 b/examples/test.p8 index 1fd71d5ca..ea10de8a6 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,14 +1,16 @@ +%import textio + main { - uword[] pages = [ &page_credits.chars_1] + uword[] pages1 = [ &page_credits.chars_1] + uword foo2 = &page_credits.chars_1 sub start() { - ; cx16.r0 = pages[0] ; TODO fix IR compiler error undefined symbol pages - uword @shared foo = pages[0] ; TODO fix IR compiler error no chunk with label 'page_credits.chars_1' (caused by optimizer) + txt.print_uw(foo2) + uword @shared foo = pages1[0] ; TODO fix IR compiler error no chunk with label 'page_credits.chars_1' (caused by optimizer) } } page_credits { ubyte[] chars_1 = [11] - ; TODO fix IR compiler crash when this array is moved into main block itself } diff --git a/virtualmachine/src/prog8/vm/VmProgramLoader.kt b/virtualmachine/src/prog8/vm/VmProgramLoader.kt index 405457f74..a0235a2e7 100644 --- a/virtualmachine/src/prog8/vm/VmProgramLoader.kt +++ b/virtualmachine/src/prog8/vm/VmProgramLoader.kt @@ -1,5 +1,8 @@ package prog8.vm +import prog8.code.StArray +import prog8.code.StArrayElement +import prog8.code.StStaticVariable import prog8.code.core.ArrayDatatypes import prog8.code.core.AssemblyError import prog8.code.core.DataType @@ -239,129 +242,177 @@ class VmProgramLoader { else -> throw IRParseException("invalid dt") } } - variable.onetimeInitializationArrayValue?.let { - require(variable.length==it.size || it.size==1 || it.size==0) - if(it.isEmpty() || it.size==1) { - val value = if(it.isEmpty()) { + variable.onetimeInitializationArrayValue?.let { iElts -> + require(variable.length==iElts.size || iElts.size==1 || iElts.size==0) + if(iElts.isEmpty() || iElts.size==1) { + val iElt = if(iElts.isEmpty()) { require(variable.uninitialized) - 0.0 + StArrayElement(0.0, null) } else { require(!variable.uninitialized) - it[0].number!! - } - when(variable.dt) { - DataType.STR, DataType.ARRAY_UB -> { - repeat(variable.length!!) { - memory.setUB(addr, value.toInt().toUByte()) - addr++ - } - } - DataType.ARRAY_B -> { - repeat(variable.length!!) { - memory.setSB(addr, value.toInt().toByte()) - addr++ - } - } - DataType.ARRAY_UW -> { - repeat(variable.length!!) { - memory.setUW(addr, value.toInt().toUShort()) - addr+=2 - } - } - DataType.ARRAY_W -> { - repeat(variable.length!!) { - memory.setSW(addr, value.toInt().toShort()) - addr+=2 - } - } - in SplitWordArrayTypes -> { - val number = value.toUInt() - for(elt in it) { - memory.setUB(addr, (number and 255u).toUByte()) - memory.setUB(addr+variable.length!!, (number shr 8).toUByte()) - addr++ - } - } - DataType.ARRAY_F -> { - repeat(variable.length!!) { - memory.setFloat(addr, value.toFloat()) - addr += program.options.compTarget.machine.FLOAT_MEM_SIZE - } - } - else -> throw IRParseException("invalid dt") + iElts[0] } + initializeWithOneValue(variable, iElt, addr, symbolAddresses, memory, program) } else { - when(variable.dt) { - DataType.STR, DataType.ARRAY_UB -> { - for(elt in it) { - if(elt.addressOfSymbol!=null) { - val name = elt.addressOfSymbol!! - val symbolAddress = if(name.startsWith('<')) { - symbolAddresses[name.drop(1)]?.and(255) - ?: throw IRParseException("vm cannot yet load a label address as a value: $name") - } else if(name.startsWith('>')) { - symbolAddresses[name.drop(1)]?.shr(8) - ?: throw IRParseException("vm cannot yet load a label address as a value: $name") - } else - throw IRParseException("for byte-array address-of, expected < or > (lsb/msb)") - memory.setUB(addr, symbolAddress.toUByte()) - } else { - memory.setUB(addr, elt.number!!.toInt().toUByte()) - } - addr++ - } - } - DataType.ARRAY_B -> { - for(elt in it) { - memory.setSB(addr, elt.number!!.toInt().toByte()) - addr++ - } - } - DataType.ARRAY_UW -> { - for(elt in it) { - if(elt.addressOfSymbol!=null) { - val name = elt.addressOfSymbol!! - val symbolAddress = symbolAddresses[name] - ?: throw IRParseException("vm cannot yet load a label address as a value: $name") - memory.setUW(addr, symbolAddress.toUShort()) - } else { - memory.setUW(addr, elt.number!!.toInt().toUShort()) - } - addr+=2 - } - } - DataType.ARRAY_W -> { - for(elt in it) { - memory.setSW(addr, elt.number!!.toInt().toShort()) - addr+=2 - } - } - in SplitWordArrayTypes -> { - for(elt in it) { - val number = if(elt.addressOfSymbol!=null) { - val name = elt.addressOfSymbol!! - val symbolAddress = symbolAddresses[name] - ?: throw IRParseException("vm cannot yet load a label address as a value: $name") - symbolAddress.toUInt() - } else { - elt.number!!.toInt().toUInt() - } - memory.setUB(addr, (number and 255u).toUByte()) - memory.setUB(addr + variable.length!!, (number shr 8).toUByte()) - addr++ - } - } - DataType.ARRAY_F -> { - for(elt in it) { - memory.setFloat(addr, elt.number!!.toFloat()) - addr+=program.options.compTarget.machine.FLOAT_MEM_SIZE - } - } - else -> throw IRParseException("invalid dt") - } + initializeWithValues(variable, iElts, addr, symbolAddresses, memory, program) } } require(variable.onetimeInitializationStringValue==null) { "in vm/ir, strings should have been converted into bytearrays." } } } + + private fun initializeWithValues( + variable: StStaticVariable, + iElts: StArray, + startAddress: Int, + symbolAddresses: MutableMap, + memory: Memory, + program: IRProgram + ) { + var address = startAddress + when (variable.dt) { + DataType.STR, DataType.ARRAY_UB -> { + for (elt in iElts) { + val value = getInitializerValue(variable.dt, elt, symbolAddresses).toInt().toUByte() + memory.setUB(address, value) + address++ + } + } + + DataType.ARRAY_B -> { + for (elt in iElts) { + val value = getInitializerValue(variable.dt, elt, symbolAddresses).toInt().toByte() + memory.setSB(address, value) + address++ + } + } + + DataType.ARRAY_UW -> { + for (elt in iElts) { + val value = getInitializerValue(variable.dt, elt, symbolAddresses).toInt().toUShort() + memory.setUW(address, value) + address += 2 + } + } + + DataType.ARRAY_W -> { + for (elt in iElts) { + val value = getInitializerValue(variable.dt, elt, symbolAddresses).toInt().toShort() + memory.setSW(address, value) + address += 2 + } + } + + in SplitWordArrayTypes -> { + for (elt in iElts) { + val value = getInitializerValue(variable.dt, elt, symbolAddresses).toUInt() + memory.setUB(address, (value and 255u).toUByte()) + memory.setUB(address + variable.length!!, (value shr 8).toUByte()) + address++ + } + } + + DataType.ARRAY_F -> { + for (elt in iElts) { + val value = getInitializerValue(variable.dt, elt, symbolAddresses).toFloat() + memory.setFloat(address, value) + address += program.options.compTarget.machine.FLOAT_MEM_SIZE + } + } + + else -> throw IRParseException("invalid dt") + } + } + + private fun initializeWithOneValue( + variable: StStaticVariable, + iElt: StArrayElement, + startAddress: Int, + symbolAddresses: MutableMap, + memory: Memory, + program: IRProgram + ) { + var address = startAddress + when (variable.dt) { + DataType.STR, DataType.ARRAY_UB -> { + val value = getInitializerValue(variable.dt, iElt, symbolAddresses).toInt().toUByte() + repeat(variable.length!!) { + memory.setUB(address, value) + address++ + } + } + + DataType.ARRAY_B -> { + val value = getInitializerValue(variable.dt, iElt, symbolAddresses).toInt().toByte() + repeat(variable.length!!) { + memory.setSB(address, value) + address++ + } + } + + DataType.ARRAY_UW -> { + val value = getInitializerValue(variable.dt, iElt, symbolAddresses).toInt().toUShort() + repeat(variable.length!!) { + memory.setUW(address, value) + address += 2 + } + } + + DataType.ARRAY_W -> { + val value = getInitializerValue(variable.dt, iElt, symbolAddresses).toInt().toShort() + repeat(variable.length!!) { + memory.setSW(address, value) + address += 2 + } + } + + in SplitWordArrayTypes -> { + val value = getInitializerValue(variable.dt, iElt, symbolAddresses).toUInt() + val lsb = (value and 255u).toUByte() + val msb = (value shr 8).toUByte() + repeat(variable.length!!) { + memory.setUB(address, lsb) + memory.setUB(address + variable.length!!, msb) + address++ + } + } + + DataType.ARRAY_F -> { + val value = getInitializerValue(variable.dt, iElt, symbolAddresses).toFloat() + repeat(variable.length!!) { + memory.setFloat(address, value) + address += program.options.compTarget.machine.FLOAT_MEM_SIZE + } + } + + else -> throw IRParseException("invalid dt") + } + } + + private fun getInitializerValue(arrayDt: DataType, elt: StArrayElement, symbolAddresses: MutableMap): Double { + if(elt.addressOfSymbol!=null) { + when(arrayDt) { + DataType.ARRAY_UB, DataType.STR, DataType.ARRAY_B, DataType.ARRAY_BOOL -> { + val name = elt.addressOfSymbol!! + val symbolAddress = if(name.startsWith('<')) { + symbolAddresses[name.drop(1)]?.and(255) + ?: throw IRParseException("vm cannot yet load a label address as a value: $name") + } else if(name.startsWith('>')) { + symbolAddresses[name.drop(1)]?.shr(8) + ?: throw IRParseException("vm cannot yet load a label address as a value: $name") + } else + throw IRParseException("for byte-array address-of, expected < or > (lsb/msb)") + return symbolAddress.toDouble() + } + else -> { + val name = elt.addressOfSymbol!! + val symbolAddress = symbolAddresses[name] + ?: throw IRParseException("vm cannot yet load a label address as a value: $name") + return symbolAddress.toDouble() + } + } + } else { + return elt.number!! + } + } }