vm: fixed array initialization values with address-ofs

This commit is contained in:
Irmen de Jong 2023-09-19 23:13:44 +02:00
parent 885df9156f
commit 229c1114dd
4 changed files with 187 additions and 127 deletions

View File

@ -25,18 +25,29 @@ class IRUnusedCodeRemover(
} }
private fun pruneSymboltable(blockLabel: String) { 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 prefix = "$blockLabel."
val blockVars = irprog.st.allVariables().filter { it.name.startsWith(prefix) } val blockVars = irprog.st.allVariables().filter { it.name.startsWith(prefix) }
blockVars.forEach { stVar -> blockVars.forEach { stVar ->
irprog. allSubs().flatMap { it.chunks }.forEach { chunk -> irprog.allSubs().flatMap { it.chunks }.forEach { chunk ->
chunk.instructions.forEach { ins -> chunk.instructions.forEach { ins ->
if(ins.labelSymbol == stVar.name) { 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) irprog.st.removeTree(blockLabel)
} }
@ -207,9 +218,7 @@ class IRUnusedCodeRemover(
return removeUnlinkedChunks(linkedChunks) return removeUnlinkedChunks(linkedChunks)
} }
private fun removeUnlinkedChunks( private fun removeUnlinkedChunks(linkedChunks: Set<IRCodeChunkBase>): Int {
linkedChunks: Set<IRCodeChunkBase>
): Int {
var numRemoved = 0 var numRemoved = 0
irprog.foreachSub { sub -> irprog.foreachSub { sub ->
sub.chunks.withIndex().reversed().forEach { (index, chunk) -> sub.chunks.withIndex().reversed().forEach { (index, chunk) ->

View File

@ -1,8 +1,6 @@
TODO 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 .... - [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 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! - 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!

View File

@ -1,14 +1,16 @@
%import textio
main { main {
uword[] pages = [ &page_credits.chars_1] uword[] pages1 = [ &page_credits.chars_1]
uword foo2 = &page_credits.chars_1
sub start() { sub start() {
; cx16.r0 = pages[0] ; TODO fix IR compiler error undefined symbol pages txt.print_uw(foo2)
uword @shared foo = pages[0] ; TODO fix IR compiler error no chunk with label 'page_credits.chars_1' (caused by optimizer) uword @shared foo = pages1[0] ; TODO fix IR compiler error no chunk with label 'page_credits.chars_1' (caused by optimizer)
} }
} }
page_credits { page_credits {
ubyte[] chars_1 = [11] ubyte[] chars_1 = [11]
; TODO fix IR compiler crash when this array is moved into main block itself
} }

View File

@ -1,5 +1,8 @@
package prog8.vm package prog8.vm
import prog8.code.StArray
import prog8.code.StArrayElement
import prog8.code.StStaticVariable
import prog8.code.core.ArrayDatatypes import prog8.code.core.ArrayDatatypes
import prog8.code.core.AssemblyError import prog8.code.core.AssemblyError
import prog8.code.core.DataType import prog8.code.core.DataType
@ -239,62 +242,157 @@ class VmProgramLoader {
else -> throw IRParseException("invalid dt") else -> throw IRParseException("invalid dt")
} }
} }
variable.onetimeInitializationArrayValue?.let { variable.onetimeInitializationArrayValue?.let { iElts ->
require(variable.length==it.size || it.size==1 || it.size==0) require(variable.length==iElts.size || iElts.size==1 || iElts.size==0)
if(it.isEmpty() || it.size==1) { if(iElts.isEmpty() || iElts.size==1) {
val value = if(it.isEmpty()) { val iElt = if(iElts.isEmpty()) {
require(variable.uninitialized) require(variable.uninitialized)
0.0 StArrayElement(0.0, null)
} else { } else {
require(!variable.uninitialized) require(!variable.uninitialized)
it[0].number!! iElts[0]
} }
when(variable.dt) { initializeWithOneValue(variable, iElt, addr, symbolAddresses, memory, program)
} else {
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<String, Int>,
memory: Memory,
program: IRProgram
) {
var address = startAddress
when (variable.dt) {
DataType.STR, DataType.ARRAY_UB -> { DataType.STR, DataType.ARRAY_UB -> {
repeat(variable.length!!) { for (elt in iElts) {
memory.setUB(addr, value.toInt().toUByte()) val value = getInitializerValue(variable.dt, elt, symbolAddresses).toInt().toUByte()
addr++ memory.setUB(address, value)
address++
} }
} }
DataType.ARRAY_B -> { DataType.ARRAY_B -> {
repeat(variable.length!!) { for (elt in iElts) {
memory.setSB(addr, value.toInt().toByte()) val value = getInitializerValue(variable.dt, elt, symbolAddresses).toInt().toByte()
addr++ memory.setSB(address, value)
address++
} }
} }
DataType.ARRAY_UW -> { DataType.ARRAY_UW -> {
repeat(variable.length!!) { for (elt in iElts) {
memory.setUW(addr, value.toInt().toUShort()) val value = getInitializerValue(variable.dt, elt, symbolAddresses).toInt().toUShort()
addr+=2 memory.setUW(address, value)
address += 2
} }
} }
DataType.ARRAY_W -> { DataType.ARRAY_W -> {
repeat(variable.length!!) { for (elt in iElts) {
memory.setSW(addr, value.toInt().toShort()) val value = getInitializerValue(variable.dt, elt, symbolAddresses).toInt().toShort()
addr+=2 memory.setSW(address, value)
address += 2
} }
} }
in SplitWordArrayTypes -> { in SplitWordArrayTypes -> {
val number = value.toUInt() for (elt in iElts) {
for(elt in it) { val value = getInitializerValue(variable.dt, elt, symbolAddresses).toUInt()
memory.setUB(addr, (number and 255u).toUByte()) memory.setUB(address, (value and 255u).toUByte())
memory.setUB(addr+variable.length!!, (number shr 8).toUByte()) memory.setUB(address + variable.length!!, (value shr 8).toUByte())
addr++ address++
} }
} }
DataType.ARRAY_F -> { DataType.ARRAY_F -> {
repeat(variable.length!!) { for (elt in iElts) {
memory.setFloat(addr, value.toFloat()) val value = getInitializerValue(variable.dt, elt, symbolAddresses).toFloat()
addr += program.options.compTarget.machine.FLOAT_MEM_SIZE memory.setFloat(address, value)
address += program.options.compTarget.machine.FLOAT_MEM_SIZE
} }
} }
else -> throw IRParseException("invalid dt") else -> throw IRParseException("invalid dt")
} }
} else { }
when(variable.dt) {
private fun initializeWithOneValue(
variable: StStaticVariable,
iElt: StArrayElement,
startAddress: Int,
symbolAddresses: MutableMap<String, Int>,
memory: Memory,
program: IRProgram
) {
var address = startAddress
when (variable.dt) {
DataType.STR, DataType.ARRAY_UB -> { DataType.STR, DataType.ARRAY_UB -> {
for(elt in it) { 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<String, Int>): Double {
if(elt.addressOfSymbol!=null) { if(elt.addressOfSymbol!=null) {
when(arrayDt) {
DataType.ARRAY_UB, DataType.STR, DataType.ARRAY_B, DataType.ARRAY_BOOL -> {
val name = elt.addressOfSymbol!! val name = elt.addressOfSymbol!!
val symbolAddress = if(name.startsWith('<')) { val symbolAddress = if(name.startsWith('<')) {
symbolAddresses[name.drop(1)]?.and(255) symbolAddresses[name.drop(1)]?.and(255)
@ -304,64 +402,17 @@ class VmProgramLoader {
?: throw IRParseException("vm cannot yet load a label address as a value: $name") ?: throw IRParseException("vm cannot yet load a label address as a value: $name")
} else } else
throw IRParseException("for byte-array address-of, expected < or > (lsb/msb)") throw IRParseException("for byte-array address-of, expected < or > (lsb/msb)")
memory.setUB(addr, symbolAddress.toUByte()) return symbolAddress.toDouble()
} else {
memory.setUB(addr, elt.number!!.toInt().toUByte())
} }
addr++ else -> {
}
}
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 name = elt.addressOfSymbol!!
val symbolAddress = symbolAddresses[name] val symbolAddress = symbolAddresses[name]
?: throw IRParseException("vm cannot yet load a label address as a value: $name") ?: throw IRParseException("vm cannot yet load a label address as a value: $name")
memory.setUW(addr, symbolAddress.toUShort()) return symbolAddress.toDouble()
}
}
} else { } else {
memory.setUW(addr, elt.number!!.toInt().toUShort()) return elt.number!!
}
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")
}
}
}
require(variable.onetimeInitializationStringValue==null) { "in vm/ir, strings should have been converted into bytearrays." }
} }
} }
} }