IR now contains "bool" as a type instead of already erasing it into "ubyte". (boolean literals still are simply just 1 and 0 values)

This commit is contained in:
Irmen de Jong 2024-10-15 21:12:22 +02:00
parent 65ddcf91d0
commit cbc4b75e50
8 changed files with 166 additions and 91 deletions

View File

@ -250,7 +250,13 @@ class StRomSub(name: String,
class StSubroutineParameter(val name: String, val type: DataType) class StSubroutineParameter(val name: String, val type: DataType)
class StRomSubParameter(val register: RegisterOrStatusflag, val type: DataType) class StRomSubParameter(val register: RegisterOrStatusflag, val type: DataType)
class StArrayElement(val number: Double?, val addressOfSymbol: String?, val boolean: Boolean?) class StArrayElement(val number: Double?, val addressOfSymbol: String?, val boolean: Boolean?) {
init {
if(number!=null) require(addressOfSymbol==null && boolean==null)
if(addressOfSymbol!=null) require(number==null && boolean==null)
if(boolean!=null) require(addressOfSymbol==null && number==null)
}
}
typealias StString = Pair<String, Encoding> typealias StString = Pair<String, Encoding>
typealias StArray = List<StArrayElement> typealias StArray = List<StArrayElement>

View File

@ -9,7 +9,7 @@ Maybe this routine can be made more intelligent. See usesOtherRegistersWhileEva
Future Things and Ideas Future Things and Ideas
^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^
- keep boolean array intact in IR so that it might be represented as a bitmask in the resulting code (8 times storage improvement) - ir: there are vars in INITGLOBALS that are initialized with code where they simpley have a static numerical initializer value, and could just as well be in VARIABLESWITHINIT . Why are their StVar's not initialized!?
- improve detection that a variable is not read before being written so that initializing it to zero can be omitted (only happens now if a vardecl is immediately followed by a for loop for instance) - improve detection that a variable is not read before being written so that initializing it to zero can be omitted (only happens now if a vardecl is immediately followed by a for loop for instance)
- Improve the SublimeText syntax file for prog8, you can also install this for 'bat': https://github.com/sharkdp/bat?tab=readme-ov-file#adding-new-syntaxes--language-definitions - Improve the SublimeText syntax file for prog8, you can also install this for 'bat': https://github.com/sharkdp/bat?tab=readme-ov-file#adding-new-syntaxes--language-definitions
- Can we support signed % (remainder) somehow? - Can we support signed % (remainder) somehow?

View File

@ -1,14 +1,23 @@
%import diskio
%import textio %import textio
%option no_sysinit %option no_sysinit
%zeropage basicsafe %zeropage basicsafe
main { main {
bool[] barray = [true, false, true, false]
bool value1
bool value2 = barray[cx16.r0L]
bool value3 = true
bool value4 = false
sub start() { sub start() {
txt.print_ub(txt.width()) txt.print_bool(value1)
txt.spc()
txt.print_bool(value2)
txt.spc()
txt.print_bool(value3)
txt.nl() txt.nl()
txt.print_ub(txt.height()) txt.print_bool(value4)
txt.nl() txt.nl()
} }
} }

View File

@ -202,15 +202,19 @@ class IRFileReader {
var initNumeric: Double? = null var initNumeric: Double? = null
var initArray: StArray? = null var initArray: StArray? = null
when(dt) { when(dt) {
DataType.BOOL -> initNumeric = if(value.lowercase()=="false") 0.0 else 1.0 in NumericDatatypesWithBoolean -> initNumeric = parseIRValue(value)
in NumericDatatypes -> initNumeric = parseIRValue(value) DataType.ARRAY_BOOL -> {
initArray = value.split(',').map {
val boolean = parseIRValue(it) != 0.0
StArrayElement(null, null, boolean)
}
}
in ArrayDatatypes -> { in ArrayDatatypes -> {
initArray = value.split(',').map { initArray = value.split(',').map {
if (it.startsWith('@')) if (it.startsWith('@'))
StArrayElement(null, it.drop(1), null) StArrayElement(null, it.drop(1), null)
else else
StArrayElement(parseIRValue(it), null, null) StArrayElement(parseIRValue(it), null, null)
// TODO Boolean IR value?
} }
} }
DataType.STR -> throw IRParseException("STR should have been converted to byte array") DataType.STR -> throw IRParseException("STR should have been converted to byte array")
@ -489,7 +493,7 @@ class IRFileReader {
private fun parseDatatype(type: String, isArray: Boolean): DataType { private fun parseDatatype(type: String, isArray: Boolean): DataType {
if(isArray) { if(isArray) {
return when(type) { return when(type) {
// note: there are no BOOLEANS arrays anymore in the IR. Only UBYTE. "bool" -> DataType.ARRAY_BOOL
"byte" -> DataType.ARRAY_B "byte" -> DataType.ARRAY_B
"ubyte", "str" -> DataType.ARRAY_UB "ubyte", "str" -> DataType.ARRAY_UB
"word" -> DataType.ARRAY_W "word" -> DataType.ARRAY_W

View File

@ -264,7 +264,11 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
in ArrayDatatypes -> { in ArrayDatatypes -> {
if(variable.onetimeInitializationArrayValue!==null) { if(variable.onetimeInitializationArrayValue!==null) {
variable.onetimeInitializationArrayValue.joinToString(",") { variable.onetimeInitializationArrayValue.joinToString(",") {
if(it.number!=null) if(it.bool==true)
"1"
else if(it.bool==false)
"0"
else if(it.number!=null)
it.number.toInt().toHex() it.number.toInt().toHex()
else else
"@${it.addressOfSymbol}" "@${it.addressOfSymbol}"

View File

@ -72,7 +72,7 @@ class IRSymbolTable {
array.forEach { array.forEach {
if(it.addressOfSymbol!=null) { if(it.addressOfSymbol!=null) {
val target = variable.lookup(it.addressOfSymbol!!)!! val target = variable.lookup(it.addressOfSymbol!!)!!
newArray.add(IRStArrayElement(null, target.scopedName)) newArray.add(IRStArrayElement(null, null, target.scopedName))
} else { } else {
newArray.add(IRStArrayElement.from(it)) newArray.add(IRStArrayElement.from(it))
} }
@ -80,13 +80,8 @@ class IRSymbolTable {
return newArray return newArray
} }
scopedName = variable.scopedName scopedName = variable.scopedName
val dt = when(variable.dt) {
DataType.BOOL -> DataType.UBYTE
DataType.ARRAY_BOOL -> DataType.ARRAY_UB
else -> variable.dt
}
varToadd = IRStStaticVariable(scopedName, varToadd = IRStStaticVariable(scopedName,
dt, variable.dt,
variable.onetimeInitializationNumericValue, variable.onetimeInitializationNumericValue,
variable.onetimeInitializationStringValue, variable.onetimeInitializationStringValue,
fixupAddressOfInArray(variable.onetimeInitializationArrayValue), fixupAddressOfInArray(variable.onetimeInitializationArrayValue),
@ -215,27 +210,25 @@ class IRStStaticVariable(name: String,
} }
} }
init {
require(dt!=DataType.BOOL && dt!=DataType.ARRAY_BOOL)
}
val uninitialized = onetimeInitializationArrayValue==null && onetimeInitializationStringValue==null && onetimeInitializationNumericValue==null val uninitialized = onetimeInitializationArrayValue==null && onetimeInitializationStringValue==null && onetimeInitializationNumericValue==null
val typeString: String = dt.typeString(length) val typeString: String = dt.typeString(length)
} }
class IRStArrayElement(val number: Double?, val addressOfSymbol: String?) { class IRStArrayElement(val bool: Boolean?, val number: Double?, val addressOfSymbol: String?) {
companion object { companion object {
fun from(elt: StArrayElement): IRStArrayElement { fun from(elt: StArrayElement): IRStArrayElement {
return if(elt.boolean!=null) return if(elt.boolean!=null)
IRStArrayElement(if(elt.boolean==true) 1.0 else 0.0, elt.addressOfSymbol) IRStArrayElement(elt.boolean, null, elt.addressOfSymbol)
else else
IRStArrayElement(elt.number, elt.addressOfSymbol) IRStArrayElement(null, elt.number, elt.addressOfSymbol)
} }
} }
init { init {
require(number!=null || addressOfSymbol!=null) if(bool!=null) require(number==null && addressOfSymbol==null)
if(number!=null) require(bool==null && addressOfSymbol==null)
if(addressOfSymbol!=null) require(number==null || bool==null)
} }
} }

View File

@ -9,7 +9,7 @@ import prog8.code.right
fun DataType.typeString(length: Int?): String { fun DataType.typeString(length: Int?): String {
val lengthStr = if(length==0) "" else length.toString() val lengthStr = if(length==0) "" else length.toString()
return when (this) { return when (this) {
DataType.BOOL -> "ubyte" // in IR , a boolean is represented by an ubyte. DataType.BOOL -> "bool" // in IR , a boolean is represented by an ubyte.
DataType.UBYTE -> "ubyte" DataType.UBYTE -> "ubyte"
DataType.BYTE -> "byte" DataType.BYTE -> "byte"
DataType.UWORD -> "uword" DataType.UWORD -> "uword"
@ -17,7 +17,7 @@ fun DataType.typeString(length: Int?): String {
DataType.LONG -> "long" DataType.LONG -> "long"
DataType.FLOAT -> "float" DataType.FLOAT -> "float"
DataType.STR -> "ubyte[$lengthStr]" // here string doesn't exist as a seperate datatype anymore DataType.STR -> "ubyte[$lengthStr]" // here string doesn't exist as a seperate datatype anymore
DataType.ARRAY_BOOL -> "ubyte[$lengthStr]" // in IR , a boolean is represented by an ubyte. DataType.ARRAY_BOOL -> "bool[$lengthStr]" // in IR , a boolean is represented by an ubyte.
DataType.ARRAY_UB -> "ubyte[$lengthStr]" DataType.ARRAY_UB -> "ubyte[$lengthStr]"
DataType.ARRAY_B -> "byte[$lengthStr]" DataType.ARRAY_B -> "byte[$lengthStr]"
DataType.ARRAY_UW -> "uword[$lengthStr]" DataType.ARRAY_UW -> "uword[$lengthStr]"

View File

@ -1,9 +1,12 @@
package prog8.vm package prog8.vm
import prog8.code.Either
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
import prog8.code.core.SplitWordArrayTypes import prog8.code.core.SplitWordArrayTypes
import prog8.code.left
import prog8.code.right
import prog8.intermediate.* import prog8.intermediate.*
class VmProgramLoader { class VmProgramLoader {
@ -227,7 +230,7 @@ class VmProgramLoader {
variable.onetimeInitializationNumericValue?.let { variable.onetimeInitializationNumericValue?.let {
when(variable.dt) { when(variable.dt) {
DataType.UBYTE -> memory.setUB(addr, it.toInt().toUByte()) DataType.UBYTE, DataType.BOOL -> memory.setUB(addr, it.toInt().toUByte())
DataType.BYTE -> memory.setSB(addr, it.toInt().toByte()) DataType.BYTE -> memory.setSB(addr, it.toInt().toByte())
DataType.UWORD -> memory.setUW(addr, it.toInt().toUShort()) DataType.UWORD -> memory.setUW(addr, it.toInt().toUShort())
DataType.WORD -> memory.setSW(addr, it.toInt().toShort()) DataType.WORD -> memory.setSW(addr, it.toInt().toShort())
@ -236,19 +239,8 @@ class VmProgramLoader {
} }
} }
variable.onetimeInitializationArrayValue?.let { iElts -> variable.onetimeInitializationArrayValue?.let { iElts ->
require(variable.length==iElts.size || iElts.size==1 || iElts.isEmpty()) require(variable.length==iElts.size)
if(iElts.isEmpty() || iElts.size==1) { initializeWithValues(variable, iElts, addr, symbolAddresses, memory, program)
val iElt = if(iElts.isEmpty()) {
require(variable.uninitialized)
IRStArrayElement(0.0, null)
} else {
require(!variable.uninitialized)
iElts[0]
}
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." } require(variable.onetimeInitializationStringValue==null) { "in vm/ir, strings should have been converted into bytearrays." }
} }
@ -264,43 +256,71 @@ class VmProgramLoader {
) { ) {
var address = startAddress var address = startAddress
when (variable.dt) { when (variable.dt) {
DataType.ARRAY_BOOL -> {
for (elt in iElts) {
val value = getInitializerValue(variable.dt, elt, symbolAddresses)
value.fold(
{ throw IRParseException("didn't expect float") },
{ b -> memory.setUB(address, if(b) 1u else 0u) }
)
address++
}
}
DataType.STR, DataType.ARRAY_UB -> { DataType.STR, DataType.ARRAY_UB -> {
for (elt in iElts) { for (elt in iElts) {
val value = getInitializerValue(variable.dt, elt, symbolAddresses).toInt().toUByte() val value = getInitializerValue(variable.dt, elt, symbolAddresses)
memory.setUB(address, value) value.fold(
{ memory.setUB(address, it.toInt().toUByte()) },
{ throw IRParseException("didn't expect bool") }
)
address++ address++
} }
} }
DataType.ARRAY_B -> { DataType.ARRAY_B -> {
for (elt in iElts) { for (elt in iElts) {
val value = getInitializerValue(variable.dt, elt, symbolAddresses).toInt().toByte() val value = getInitializerValue(variable.dt, elt, symbolAddresses)
memory.setSB(address, value) value.fold(
{ memory.setSB(address, it.toInt().toByte()) },
{ throw IRParseException("didn't expect bool") }
)
address++ address++
} }
} }
DataType.ARRAY_UW -> { DataType.ARRAY_UW -> {
for (elt in iElts) { for (elt in iElts) {
val value = getInitializerValue(variable.dt, elt, symbolAddresses).toInt().toUShort() val value = getInitializerValue(variable.dt, elt, symbolAddresses)
memory.setUW(address, value) value.fold(
{ memory.setUW(address, it.toInt().toUShort()) },
{ throw IRParseException("didn't expect bool") }
)
address += 2 address += 2
} }
} }
DataType.ARRAY_W -> { DataType.ARRAY_W -> {
for (elt in iElts) { for (elt in iElts) {
val value = getInitializerValue(variable.dt, elt, symbolAddresses).toInt().toShort() val value = getInitializerValue(variable.dt, elt, symbolAddresses)
memory.setSW(address, value) value.fold(
{ memory.setSW(address, it.toInt().toShort()) },
{ throw IRParseException("didn't expect bool") }
)
address += 2 address += 2
} }
} }
in SplitWordArrayTypes -> { in SplitWordArrayTypes -> {
for (elt in iElts) { for (elt in iElts) {
val value = getInitializerValue(variable.dt, elt, symbolAddresses).toUInt() val value = getInitializerValue(variable.dt, elt, symbolAddresses)
memory.setUB(address, (value and 255u).toUByte()) value.fold(
memory.setUB(address + variable.length!!, (value shr 8).toUByte()) {
val integer = it.toUInt()
memory.setUB(address, (integer and 255u).toUByte())
memory.setUB(address + variable.length!!, (integer shr 8).toUByte())
},
{ throw IRParseException("didn't expect bool") }
)
address++ address++
} }
} }
@ -308,7 +328,10 @@ class VmProgramLoader {
DataType.ARRAY_F -> { DataType.ARRAY_F -> {
for (elt in iElts) { for (elt in iElts) {
val value = getInitializerValue(variable.dt, elt, symbolAddresses) val value = getInitializerValue(variable.dt, elt, symbolAddresses)
memory.setFloat(address, value) value.fold(
{ memory.setFloat(address, it) },
{ throw IRParseException("didn't expect bool") }
)
address += program.options.compTarget.machine.FLOAT_MEM_SIZE address += program.options.compTarget.machine.FLOAT_MEM_SIZE
} }
} }
@ -328,61 +351,96 @@ class VmProgramLoader {
var address = startAddress var address = startAddress
when (variable.dt) { when (variable.dt) {
DataType.STR, DataType.ARRAY_UB -> { DataType.STR, DataType.ARRAY_UB -> {
val value = getInitializerValue(variable.dt, iElt, symbolAddresses).toInt().toUByte() val value = getInitializerValue(variable.dt, iElt, symbolAddresses)
repeat(variable.length!!) { value.fold(
memory.setUB(address, value) {
address++ val integer = it.toInt().toUByte()
} repeat(variable.length!!) {
memory.setUB(address, integer)
address++
}
},
{ throw IRParseException("didn't expect bool") }
)
} }
DataType.ARRAY_B -> { DataType.ARRAY_B -> {
val value = getInitializerValue(variable.dt, iElt, symbolAddresses).toInt().toByte() val value = getInitializerValue(variable.dt, iElt, symbolAddresses)
repeat(variable.length!!) { value.fold(
memory.setSB(address, value) {
address++ val integer = it.toInt().toByte()
} repeat(variable.length!!) {
memory.setSB(address, integer)
address++
}
},
{ throw IRParseException("didn't expect bool") },
)
} }
DataType.ARRAY_UW -> { DataType.ARRAY_UW -> {
val value = getInitializerValue(variable.dt, iElt, symbolAddresses).toInt().toUShort() val value = getInitializerValue(variable.dt, iElt, symbolAddresses)
repeat(variable.length!!) { value.fold(
memory.setUW(address, value) {
address += 2 val integer = it.toInt().toUShort()
} repeat(variable.length!!) {
memory.setUW(address, integer)
address += 2
}
},
{ throw IRParseException("didn't expect bool") }
)
} }
DataType.ARRAY_W -> { DataType.ARRAY_W -> {
val value = getInitializerValue(variable.dt, iElt, symbolAddresses).toInt().toShort() val value = getInitializerValue(variable.dt, iElt, symbolAddresses)
repeat(variable.length!!) { value.fold(
memory.setSW(address, value) {
address += 2 val integer = it.toInt().toShort()
} repeat(variable.length!!) {
memory.setSW(address, integer)
address += 2
}
},
{ throw IRParseException("didn't expect bool") }
)
} }
in SplitWordArrayTypes -> { in SplitWordArrayTypes -> {
val value = getInitializerValue(variable.dt, iElt, symbolAddresses).toUInt() val value = getInitializerValue(variable.dt, iElt, symbolAddresses)
val lsb = (value and 255u).toUByte() value.fold(
val msb = (value shr 8).toUByte() {
repeat(variable.length!!) { val integer = it.toUInt()
memory.setUB(address, lsb) val lsb = (integer and 255u).toUByte()
memory.setUB(address + variable.length!!, msb) val msb = (integer shr 8).toUByte()
address++ repeat(variable.length!!) {
} memory.setUB(address, lsb)
memory.setUB(address + variable.length!!, msb)
address++
}
},
{ throw IRParseException("didn't expect bool") }
)
} }
DataType.ARRAY_F -> { DataType.ARRAY_F -> {
val value = getInitializerValue(variable.dt, iElt, symbolAddresses) val value = getInitializerValue(variable.dt, iElt, symbolAddresses)
repeat(variable.length!!) { value.fold(
memory.setFloat(address, value) { d ->
address += program.options.compTarget.machine.FLOAT_MEM_SIZE repeat(variable.length!!) {
} memory.setFloat(address, d)
address += program.options.compTarget.machine.FLOAT_MEM_SIZE
}
},
{ throw IRParseException("didn't expect bool") }
)
} }
else -> throw IRParseException("invalid dt") else -> throw IRParseException("invalid dt")
} }
} }
private fun getInitializerValue(arrayDt: DataType, elt: IRStArrayElement, symbolAddresses: MutableMap<String, Int>): Double { private fun getInitializerValue(arrayDt: DataType, elt: IRStArrayElement, symbolAddresses: MutableMap<String, Int>): Either<Double, Boolean> {
if(elt.addressOfSymbol!=null) { if(elt.addressOfSymbol!=null) {
when(arrayDt) { when(arrayDt) {
DataType.ARRAY_UB, DataType.STR, DataType.ARRAY_B, DataType.ARRAY_BOOL -> { DataType.ARRAY_UB, DataType.STR, DataType.ARRAY_B, DataType.ARRAY_BOOL -> {
@ -395,17 +453,18 @@ 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)")
return symbolAddress.toDouble() return left(symbolAddress.toDouble())
} }
else -> { else -> {
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")
return symbolAddress.toDouble() return left(symbolAddress.toDouble())
} }
} }
} else { } else if (elt.number!=null) {
return elt.number!! return left(elt.number!!)
} } else
return right(elt.bool!!)
} }
} }