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 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 StArray = List<StArrayElement>

View File

@ -9,7 +9,7 @@ Maybe this routine can be made more intelligent. See usesOtherRegistersWhileEva
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 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?

View File

@ -1,14 +1,23 @@
%import diskio
%import textio
%option no_sysinit
%zeropage basicsafe
main {
bool[] barray = [true, false, true, false]
bool value1
bool value2 = barray[cx16.r0L]
bool value3 = true
bool value4 = false
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.print_ub(txt.height())
txt.print_bool(value4)
txt.nl()
}
}

View File

@ -202,15 +202,19 @@ class IRFileReader {
var initNumeric: Double? = null
var initArray: StArray? = null
when(dt) {
DataType.BOOL -> initNumeric = if(value.lowercase()=="false") 0.0 else 1.0
in NumericDatatypes -> initNumeric = parseIRValue(value)
in NumericDatatypesWithBoolean -> initNumeric = parseIRValue(value)
DataType.ARRAY_BOOL -> {
initArray = value.split(',').map {
val boolean = parseIRValue(it) != 0.0
StArrayElement(null, null, boolean)
}
}
in ArrayDatatypes -> {
initArray = value.split(',').map {
if (it.startsWith('@'))
StArrayElement(null, it.drop(1), null)
else
StArrayElement(parseIRValue(it), null, null)
// TODO Boolean IR value?
}
}
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 {
if(isArray) {
return when(type) {
// note: there are no BOOLEANS arrays anymore in the IR. Only UBYTE.
"bool" -> DataType.ARRAY_BOOL
"byte" -> DataType.ARRAY_B
"ubyte", "str" -> DataType.ARRAY_UB
"word" -> DataType.ARRAY_W

View File

@ -264,7 +264,11 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
in ArrayDatatypes -> {
if(variable.onetimeInitializationArrayValue!==null) {
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()
else
"@${it.addressOfSymbol}"

View File

@ -72,7 +72,7 @@ class IRSymbolTable {
array.forEach {
if(it.addressOfSymbol!=null) {
val target = variable.lookup(it.addressOfSymbol!!)!!
newArray.add(IRStArrayElement(null, target.scopedName))
newArray.add(IRStArrayElement(null, null, target.scopedName))
} else {
newArray.add(IRStArrayElement.from(it))
}
@ -80,13 +80,8 @@ class IRSymbolTable {
return newArray
}
scopedName = variable.scopedName
val dt = when(variable.dt) {
DataType.BOOL -> DataType.UBYTE
DataType.ARRAY_BOOL -> DataType.ARRAY_UB
else -> variable.dt
}
varToadd = IRStStaticVariable(scopedName,
dt,
variable.dt,
variable.onetimeInitializationNumericValue,
variable.onetimeInitializationStringValue,
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 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 {
fun from(elt: StArrayElement): IRStArrayElement {
return if(elt.boolean!=null)
IRStArrayElement(if(elt.boolean==true) 1.0 else 0.0, elt.addressOfSymbol)
IRStArrayElement(elt.boolean, null, elt.addressOfSymbol)
else
IRStArrayElement(elt.number, elt.addressOfSymbol)
IRStArrayElement(null, elt.number, elt.addressOfSymbol)
}
}
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 {
val lengthStr = if(length==0) "" else length.toString()
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.BYTE -> "byte"
DataType.UWORD -> "uword"
@ -17,7 +17,7 @@ fun DataType.typeString(length: Int?): String {
DataType.LONG -> "long"
DataType.FLOAT -> "float"
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_B -> "byte[$lengthStr]"
DataType.ARRAY_UW -> "uword[$lengthStr]"

View File

@ -1,9 +1,12 @@
package prog8.vm
import prog8.code.Either
import prog8.code.core.ArrayDatatypes
import prog8.code.core.AssemblyError
import prog8.code.core.DataType
import prog8.code.core.SplitWordArrayTypes
import prog8.code.left
import prog8.code.right
import prog8.intermediate.*
class VmProgramLoader {
@ -227,7 +230,7 @@ class VmProgramLoader {
variable.onetimeInitializationNumericValue?.let {
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.UWORD -> memory.setUW(addr, it.toInt().toUShort())
DataType.WORD -> memory.setSW(addr, it.toInt().toShort())
@ -236,19 +239,8 @@ class VmProgramLoader {
}
}
variable.onetimeInitializationArrayValue?.let { iElts ->
require(variable.length==iElts.size || iElts.size==1 || iElts.isEmpty())
if(iElts.isEmpty() || iElts.size==1) {
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.length==iElts.size)
initializeWithValues(variable, iElts, addr, symbolAddresses, memory, program)
}
require(variable.onetimeInitializationStringValue==null) { "in vm/ir, strings should have been converted into bytearrays." }
}
@ -264,43 +256,71 @@ class VmProgramLoader {
) {
var address = startAddress
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 -> {
for (elt in iElts) {
val value = getInitializerValue(variable.dt, elt, symbolAddresses).toInt().toUByte()
memory.setUB(address, value)
val value = getInitializerValue(variable.dt, elt, symbolAddresses)
value.fold(
{ memory.setUB(address, it.toInt().toUByte()) },
{ throw IRParseException("didn't expect bool") }
)
address++
}
}
DataType.ARRAY_B -> {
for (elt in iElts) {
val value = getInitializerValue(variable.dt, elt, symbolAddresses).toInt().toByte()
memory.setSB(address, value)
val value = getInitializerValue(variable.dt, elt, symbolAddresses)
value.fold(
{ memory.setSB(address, it.toInt().toByte()) },
{ throw IRParseException("didn't expect bool") }
)
address++
}
}
DataType.ARRAY_UW -> {
for (elt in iElts) {
val value = getInitializerValue(variable.dt, elt, symbolAddresses).toInt().toUShort()
memory.setUW(address, value)
val value = getInitializerValue(variable.dt, elt, symbolAddresses)
value.fold(
{ memory.setUW(address, it.toInt().toUShort()) },
{ throw IRParseException("didn't expect bool") }
)
address += 2
}
}
DataType.ARRAY_W -> {
for (elt in iElts) {
val value = getInitializerValue(variable.dt, elt, symbolAddresses).toInt().toShort()
memory.setSW(address, value)
val value = getInitializerValue(variable.dt, elt, symbolAddresses)
value.fold(
{ memory.setSW(address, it.toInt().toShort()) },
{ throw IRParseException("didn't expect bool") }
)
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())
val value = getInitializerValue(variable.dt, elt, symbolAddresses)
value.fold(
{
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++
}
}
@ -308,7 +328,10 @@ class VmProgramLoader {
DataType.ARRAY_F -> {
for (elt in iElts) {
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
}
}
@ -328,61 +351,96 @@ class VmProgramLoader {
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++
}
val value = getInitializerValue(variable.dt, iElt, symbolAddresses)
value.fold(
{
val integer = it.toInt().toUByte()
repeat(variable.length!!) {
memory.setUB(address, integer)
address++
}
},
{ throw IRParseException("didn't expect bool") }
)
}
DataType.ARRAY_B -> {
val value = getInitializerValue(variable.dt, iElt, symbolAddresses).toInt().toByte()
repeat(variable.length!!) {
memory.setSB(address, value)
address++
}
val value = getInitializerValue(variable.dt, iElt, symbolAddresses)
value.fold(
{
val integer = it.toInt().toByte()
repeat(variable.length!!) {
memory.setSB(address, integer)
address++
}
},
{ throw IRParseException("didn't expect bool") },
)
}
DataType.ARRAY_UW -> {
val value = getInitializerValue(variable.dt, iElt, symbolAddresses).toInt().toUShort()
repeat(variable.length!!) {
memory.setUW(address, value)
address += 2
}
val value = getInitializerValue(variable.dt, iElt, symbolAddresses)
value.fold(
{
val integer = it.toInt().toUShort()
repeat(variable.length!!) {
memory.setUW(address, integer)
address += 2
}
},
{ throw IRParseException("didn't expect bool") }
)
}
DataType.ARRAY_W -> {
val value = getInitializerValue(variable.dt, iElt, symbolAddresses).toInt().toShort()
repeat(variable.length!!) {
memory.setSW(address, value)
address += 2
}
val value = getInitializerValue(variable.dt, iElt, symbolAddresses)
value.fold(
{
val integer = it.toInt().toShort()
repeat(variable.length!!) {
memory.setSW(address, integer)
address += 2
}
},
{ throw IRParseException("didn't expect bool") }
)
}
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++
}
val value = getInitializerValue(variable.dt, iElt, symbolAddresses)
value.fold(
{
val integer = it.toUInt()
val lsb = (integer and 255u).toUByte()
val msb = (integer shr 8).toUByte()
repeat(variable.length!!) {
memory.setUB(address, lsb)
memory.setUB(address + variable.length!!, msb)
address++
}
},
{ throw IRParseException("didn't expect bool") }
)
}
DataType.ARRAY_F -> {
val value = getInitializerValue(variable.dt, iElt, symbolAddresses)
repeat(variable.length!!) {
memory.setFloat(address, value)
address += program.options.compTarget.machine.FLOAT_MEM_SIZE
}
value.fold(
{ d ->
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")
}
}
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) {
when(arrayDt) {
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")
} else
throw IRParseException("for byte-array address-of, expected < or > (lsb/msb)")
return symbolAddress.toDouble()
return left(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()
return left(symbolAddress.toDouble())
}
}
} else {
return elt.number!!
}
} else if (elt.number!=null) {
return left(elt.number!!)
} else
return right(elt.bool!!)
}
}