Merge branch 'optimize-st'

# Conflicts:
#	examples/test.p8
This commit is contained in:
Irmen de Jong 2023-12-17 02:11:01 +01:00
commit eba0bde6f3
14 changed files with 330 additions and 250 deletions

View File

@ -1,6 +1,7 @@
package prog8.codegen.cpu6502
import com.github.michaelbull.result.fold
import prog8.code.StNode
import prog8.code.StNodeType
import prog8.code.SymbolTable
import prog8.code.SymbolTableMaker
@ -282,6 +283,18 @@ class AsmGen6502Internal (
name
}
fun asmVariableName(st: StNode, scope: PtSub?): String {
val name = asmVariableName(st.scopedName)
if(scope==null)
return name
// remove the whole prefix and just make the variable name locally scoped (64tass scopes it to the proper .proc block)
val subName = scope.scopedName
return if (name.length>subName.length && name.startsWith(subName) && name[subName.length] == '.')
name.drop(subName.length+1)
else
name
}
internal fun getTempVarName(dt: DataType): String {
return when(dt) {
DataType.UBYTE -> "cx16.r9L"

View File

@ -1,5 +1,6 @@
package prog8.codegen.cpu6502
import prog8.code.StMemVar
import prog8.code.StStaticVariable
import prog8.code.ast.*
import prog8.code.core.*
@ -311,106 +312,97 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
}
private fun funcReverse(fcall: PtBuiltinFunctionCall) {
val variable = fcall.args.single()
if (variable is PtIdentifier) {
val symbol = asmgen.symbolTable.lookup(variable.name)
val decl = symbol!!.astNode as IPtVariable
val numElements = when(decl) {
is PtConstant -> throw AssemblyError("cannot reverse a constant")
is PtMemMapped -> decl.arraySize
is PtVariable -> decl.arraySize
val variable = fcall.args.single() as PtIdentifier
val symbol = asmgen.symbolTable.lookup(variable.name)
val (dt, numElements) = when(symbol) {
is StStaticVariable -> symbol.dt to symbol.length!!
is StMemVar -> symbol.dt to symbol.length!!
else -> DataType.UNDEFINED to 0
}
val varName = asmgen.asmVariableName(variable)
when (dt) {
DataType.ARRAY_UB, DataType.ARRAY_B -> {
asmgen.out("""
lda #<$varName
ldy #>$varName
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda #$numElements
jsr prog8_lib.func_reverse_b""")
}
val varName = asmgen.asmVariableName(variable)
when (decl.type) {
DataType.ARRAY_UB, DataType.ARRAY_B -> {
asmgen.out("""
lda #<$varName
ldy #>$varName
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda #$numElements
jsr prog8_lib.func_reverse_b""")
}
DataType.ARRAY_UW, DataType.ARRAY_W -> {
asmgen.out("""
lda #<$varName
ldy #>$varName
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda #$numElements
jsr prog8_lib.func_reverse_w""")
}
DataType.STR -> {
val stringLength = (symbol as StStaticVariable).length!!-1
asmgen.out("""
lda #<$varName
ldy #>$varName
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda #$stringLength
jsr prog8_lib.func_reverse_b""")
}
DataType.ARRAY_F -> {
asmgen.out("""
lda #<$varName
ldy #>$varName
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda #$numElements
jsr floats.func_reverse_f""")
}
in SplitWordArrayTypes -> TODO("split word reverse")
else -> throw AssemblyError("weird type")
DataType.ARRAY_UW, DataType.ARRAY_W -> {
asmgen.out("""
lda #<$varName
ldy #>$varName
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda #$numElements
jsr prog8_lib.func_reverse_w""")
}
DataType.STR -> {
asmgen.out("""
lda #<$varName
ldy #>$varName
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda #${numElements-1}
jsr prog8_lib.func_reverse_b""")
}
DataType.ARRAY_F -> {
asmgen.out("""
lda #<$varName
ldy #>$varName
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda #$numElements
jsr floats.func_reverse_f""")
}
in SplitWordArrayTypes -> TODO("split word reverse")
else -> throw AssemblyError("weird type")
}
}
private fun funcSort(fcall: PtBuiltinFunctionCall) {
val variable = fcall.args.single()
if (variable is PtIdentifier) {
val symbol = asmgen.symbolTable.lookup(variable.name)
val decl = symbol!!.astNode as IPtVariable
val varName = asmgen.asmVariableName(variable)
val numElements = when(decl) {
is PtConstant -> throw AssemblyError("cannot sort a constant")
is PtMemMapped -> decl.arraySize
is PtVariable -> decl.arraySize
val variable = fcall.args.single() as PtIdentifier
val symbol = asmgen.symbolTable.lookup(variable.name)
val varName = asmgen.asmVariableName(variable)
val (dt, numElements) = when(symbol) {
is StStaticVariable -> symbol.dt to symbol.length!!
is StMemVar -> symbol.dt to symbol.length!!
else -> DataType.UNDEFINED to 0
}
when (dt) {
DataType.ARRAY_UB, DataType.ARRAY_B -> {
asmgen.out("""
lda #<$varName
ldy #>$varName
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda #$numElements""")
asmgen.out(if (dt == DataType.ARRAY_UB) " jsr prog8_lib.func_sort_ub" else " jsr prog8_lib.func_sort_b")
}
when (decl.type) {
DataType.ARRAY_UB, DataType.ARRAY_B -> {
asmgen.out("""
lda #<$varName
ldy #>$varName
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda #$numElements""")
asmgen.out(if (decl.type == DataType.ARRAY_UB) " jsr prog8_lib.func_sort_ub" else " jsr prog8_lib.func_sort_b")
}
DataType.ARRAY_UW, DataType.ARRAY_W -> {
asmgen.out("""
lda #<$varName
ldy #>$varName
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda #$numElements""")
asmgen.out(if (decl.type == DataType.ARRAY_UW) " jsr prog8_lib.func_sort_uw" else " jsr prog8_lib.func_sort_w")
}
DataType.STR -> {
val stringLength = (symbol as StStaticVariable).length!!-1
asmgen.out("""
lda #<$varName
ldy #>$varName
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda #$stringLength
jsr prog8_lib.func_sort_ub""")
}
DataType.ARRAY_F -> throw AssemblyError("sorting of floating point array is not supported")
in SplitWordArrayTypes -> TODO("split word sort")
else -> throw AssemblyError("weird type")
DataType.ARRAY_UW, DataType.ARRAY_W -> {
asmgen.out("""
lda #<$varName
ldy #>$varName
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda #$numElements""")
asmgen.out(if (dt == DataType.ARRAY_UW) " jsr prog8_lib.func_sort_uw" else " jsr prog8_lib.func_sort_w")
}
} else
throw AssemblyError("weird type")
DataType.STR -> {
asmgen.out("""
lda #<$varName
ldy #>$varName
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda #${numElements-1}
jsr prog8_lib.func_sort_ub""")
}
DataType.ARRAY_F -> throw AssemblyError("sorting of floating point array is not supported")
in SplitWordArrayTypes -> TODO("split word sort")
else -> throw AssemblyError("weird type")
}
}
private fun funcRor2(fcall: PtBuiltinFunctionCall) {
@ -1245,12 +1237,11 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
// address in P8ZP_SCRATCH_W1, number of elements in A
arg as PtIdentifier
val symbol = asmgen.symbolTable.lookup(arg.name)
val arrayVar = symbol!!.astNode as IPtVariable
val numElements = when(arrayVar) {
is PtConstant -> null
is PtMemMapped -> arrayVar.arraySize
is PtVariable -> arrayVar.arraySize
} ?: throw AssemblyError("length of non-array requested")
val numElements = when(symbol) {
is StStaticVariable -> symbol.length!!
is StMemVar -> symbol.length!!
else -> 0
}
val identifierName = asmgen.asmVariableName(arg)
asmgen.out("""
lda #<$identifierName

View File

@ -1,7 +1,11 @@
package prog8.codegen.cpu6502
import com.github.michaelbull.result.fold
import prog8.code.ast.*
import prog8.code.StMemVar
import prog8.code.StStaticVariable
import prog8.code.ast.PtForLoop
import prog8.code.ast.PtIdentifier
import prog8.code.ast.PtRange
import prog8.code.core.*
import kotlin.math.absoluteValue
@ -332,11 +336,10 @@ $endLabel""")
asmgen.loopEndLabels.push(endLabel)
val iterableName = asmgen.asmVariableName(ident)
val symbol = asmgen.symbolTable.lookup(ident.name)
val decl = symbol!!.astNode as IPtVariable
val numElements = when(decl) {
is PtConstant -> throw AssemblyError("length of non-array requested")
is PtMemMapped -> decl.arraySize
is PtVariable -> decl.arraySize
val numElements = when(symbol) {
is StStaticVariable -> symbol.length!!
is StMemVar -> symbol.length!!
else -> 0
}
when(iterableDt) {
DataType.STR -> {
@ -364,7 +367,7 @@ $loopLabel sty $indexVar
lda $iterableName,y
sta ${asmgen.asmVariableName(stmt.variable)}""")
asmgen.translate(stmt.statements)
if(numElements!!<=255u) {
if(numElements<=255) {
asmgen.out("""
ldy $indexVar
iny
@ -379,7 +382,7 @@ $loopLabel sty $indexVar
bne $loopLabel
beq $endLabel""")
}
if(numElements>=16u) {
if(numElements>=16) {
// allocate index var on ZP if possible
val result = zeropage.allocate(indexVar, DataType.UBYTE, null, stmt.position, asmgen.errors)
result.fold(
@ -392,7 +395,7 @@ $loopLabel sty $indexVar
asmgen.out(endLabel)
}
DataType.ARRAY_W, DataType.ARRAY_UW -> {
val length = numElements!! * 2u
val length = numElements * 2
val indexVar = asmgen.makeLabel("for_index")
val loopvarName = asmgen.asmVariableName(stmt.variable)
asmgen.out("""
@ -403,7 +406,7 @@ $loopLabel sty $indexVar
lda $iterableName+1,y
sta $loopvarName+1""")
asmgen.translate(stmt.statements)
if(length<=127u) {
if(length<=127) {
asmgen.out("""
ldy $indexVar
iny
@ -420,7 +423,7 @@ $loopLabel sty $indexVar
bne $loopLabel
beq $endLabel""")
}
if(length>=16u) {
if(length>=16) {
// allocate index var on ZP if possible
val result = zeropage.allocate(indexVar, DataType.UBYTE, null, stmt.position, asmgen.errors)
result.fold(
@ -444,7 +447,7 @@ $loopLabel sty $indexVar
lda ${iterableName}_msb,y
sta $loopvarName+1""")
asmgen.translate(stmt.statements)
if(numElements<=255u) {
if(numElements<=255) {
asmgen.out("""
ldy $indexVar
iny
@ -459,7 +462,7 @@ $loopLabel sty $indexVar
bne $loopLabel
beq $endLabel""")
}
if(numElements>=16u) {
if(numElements>=16) {
// allocate index var on ZP if possible
val result = zeropage.allocate(indexVar, DataType.UBYTE, null, stmt.position, asmgen.errors)
result.fold(

View File

@ -1,5 +1,7 @@
package prog8.codegen.cpu6502.assignment
import prog8.code.StMemVar
import prog8.code.StStaticVariable
import prog8.code.ast.*
import prog8.code.core.*
import prog8.codegen.cpu6502.AsmGen6502Internal
@ -1814,23 +1816,21 @@ internal class AssignmentAsmGen(private val program: PtProgram,
private fun containmentCheckIntoA(containment: PtContainmentCheck) {
val elementDt = containment.element.type
val symbol = asmgen.symbolTable.lookup(containment.iterable.name)
val variable = symbol!!.astNode as IPtVariable
val varname = asmgen.asmVariableName(containment.iterable)
val numElements = when(variable) {
is PtConstant -> null
is PtMemMapped -> variable.arraySize
is PtVariable -> variable.arraySize
val symbol = asmgen.symbolTable.lookup(containment.iterable.name)!!
val symbolName = asmgen.asmVariableName(symbol, containment.definingSub())
val (dt, numElements) = when(symbol) {
is StStaticVariable -> symbol.dt to symbol.length!!
is StMemVar -> symbol.dt to symbol.length!!
else -> DataType.UNDEFINED to 0
}
when(variable.type) {
when(dt) {
DataType.STR -> {
// use subroutine
assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt == DataType.BYTE)
asmgen.saveRegisterStack(CpuRegister.A, true)
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), symbol.astNode.position,"P8ZP_SCRATCH_W1"), varname, null, null)
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), containment.position,"P8ZP_SCRATCH_W1"), symbolName, null, null)
asmgen.restoreRegisterStack(CpuRegister.A, false)
val stringVal = (variable as PtVariable).value as PtString
asmgen.out(" ldy #${stringVal.value.length}")
asmgen.out(" ldy #${numElements-1}")
asmgen.out(" jsr prog8_lib.containment_bytearray")
return
}
@ -1840,7 +1840,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
DataType.ARRAY_B, DataType.ARRAY_UB -> {
assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt == DataType.BYTE)
asmgen.saveRegisterStack(CpuRegister.A, true)
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), symbol.astNode.position, "P8ZP_SCRATCH_W1"), varname, null, null)
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), containment.position, "P8ZP_SCRATCH_W1"), symbolName, null, null)
asmgen.restoreRegisterStack(CpuRegister.A, false)
asmgen.out(" ldy #$numElements")
asmgen.out(" jsr prog8_lib.containment_bytearray")
@ -1848,7 +1848,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
}
DataType.ARRAY_W, DataType.ARRAY_UW -> {
assignExpressionToVariable(containment.element, "P8ZP_SCRATCH_W1", elementDt)
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), symbol.astNode.position, "P8ZP_SCRATCH_W2"), varname, null, null)
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), containment.position, "P8ZP_SCRATCH_W2"), symbolName, null, null)
asmgen.out(" ldy #$numElements")
asmgen.out(" jsr prog8_lib.containment_wordarray")
return

View File

@ -18,7 +18,6 @@ class IRCodeGen(
private val expressionEval = ExpressionGen(this)
private val builtinFuncGen = BuiltinFuncGen(this, expressionEval)
private val assignmentGen = AssignmentGen(this, expressionEval)
private var irSymbolTable: IRSymbolTable = IRSymbolTable(null)
internal val registers = RegisterPool()
fun generate(): IRProgram {
@ -26,7 +25,7 @@ class IRCodeGen(
moveAllNestedSubroutinesToBlockScope()
verifyNameScoping(program, symbolTable)
irSymbolTable = IRSymbolTable(symbolTable)
val irSymbolTable = IRSymbolTable.fromStDuringCodegen(symbolTable)
val irProg = IRProgram(program.name, irSymbolTable, options, program.encoding)
// collect global variables initializers

View File

@ -24,7 +24,7 @@ class TestIRPeepholeOpt: FunSpec({
compTarget = target,
loadAddress = target.machine.PROGRAM_LOAD_ADDRESS
)
val prog = IRProgram("test", IRSymbolTable(null), options, target)
val prog = IRProgram("test", IRSymbolTable(), options, target)
prog.addBlock(block)
prog.linkChunks()
prog.validate()

View File

@ -5,11 +5,11 @@ package prog8.buildversion
*/
const val MAVEN_GROUP = "prog8"
const val MAVEN_NAME = "compiler"
const val VERSION = "9.7"
const val GIT_REVISION = 4286
const val GIT_SHA = "cfc9c15f1e9fe96940e170fb14ad3a957109977c"
const val GIT_DATE = "2023-12-10T15:22:00Z"
const val GIT_BRANCH = "master"
const val BUILD_DATE = "2023-12-10T15:44:19Z"
const val BUILD_UNIX_TIME = 1702223059842L
const val VERSION = "9.8-SNAPSHOT"
const val GIT_REVISION = 4287
const val GIT_SHA = "08a079a96e67c26298b81de2d35919be51a3dfd0"
const val GIT_DATE = "2023-12-11T20:15:48Z"
const val GIT_BRANCH = "no-vardecls"
const val BUILD_DATE = "2023-12-11T21:48:14Z"
const val BUILD_UNIX_TIME = 1702331294381L
const val DIRTY = 1

View File

@ -56,7 +56,7 @@ class IRFileReader {
val initGlobals = parseInitGlobals(reader)
val blocks = parseBlocksUntilProgramEnd(reader)
val st = IRSymbolTable(null)
val st = IRSymbolTable()
asmsymbols.forEach { (name, value) -> st.addAsmSymbol(name, value)}
varsWithoutInit.forEach { st.add(it) }
variables.forEach { st.add(it) }

View File

@ -142,7 +142,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
if(irProgram.options.includeSourcelines) {
if(code.sourceLinesPositions.any {it !== Position.DUMMY}) {
xml.writeStartElement("P8SRC")
var sourceTxt = StringBuilder("\n")
val sourceTxt = StringBuilder("\n")
code.sourceLinesPositions.forEach { pos ->
val line = SourceLineCache.retrieveLine(pos)
if(line!=null) {
@ -210,8 +210,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
xml.writeCharacters("ubyte[${variable.length}] ${variable.name}_lsb zp=${variable.zpwish}\n")
xml.writeCharacters("ubyte[${variable.length}] ${variable.name}_msb zp=${variable.zpwish}\n")
} else {
val typeStr = getTypeString(variable)
xml.writeCharacters("$typeStr ${variable.name} zp=${variable.zpwish}\n")
xml.writeCharacters("${variable.typeString} ${variable.name} zp=${variable.zpwish}\n")
}
}
@ -228,15 +227,15 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
lsbValue = ""
msbValue = ""
} else {
lsbValue = variable.onetimeInitializationArrayValue!!.joinToString(",") {
lsbValue = variable.onetimeInitializationArrayValue.joinToString(",") {
if(it.number!=null)
(it.number!!.toInt() and 255).toHex()
(it.number.toInt() and 255).toHex()
else
"@<${it.addressOfSymbol}"
}
msbValue = variable.onetimeInitializationArrayValue!!.joinToString(",") {
msbValue = variable.onetimeInitializationArrayValue.joinToString(",") {
if(it.number!=null)
(it.number!!.toInt() shr 8).toHex()
(it.number.toInt() shr 8).toHex()
else
"@>${it.addressOfSymbol}"
}
@ -244,26 +243,25 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
xml.writeCharacters("ubyte[${variable.length}] ${variable.name}_lsb=$lsbValue zp=${variable.zpwish}\n")
xml.writeCharacters("ubyte[${variable.length}] ${variable.name}_msb=$msbValue zp=${variable.zpwish}\n")
} else {
val typeStr = getTypeString(variable)
val value: String = when(variable.dt) {
DataType.FLOAT -> (variable.onetimeInitializationNumericValue ?: "").toString()
in NumericDatatypes -> (variable.onetimeInitializationNumericValue?.toInt()?.toHex() ?: "").toString()
DataType.STR -> {
val encoded = irProgram.encoding.encodeString(variable.onetimeInitializationStringValue!!.first, variable.onetimeInitializationStringValue!!.second) + listOf(0u)
val encoded = irProgram.encoding.encodeString(variable.onetimeInitializationStringValue!!.first, variable.onetimeInitializationStringValue.second) + listOf(0u)
encoded.joinToString(",") { it.toInt().toString() }
}
DataType.ARRAY_F -> {
if(variable.onetimeInitializationArrayValue!=null) {
variable.onetimeInitializationArrayValue!!.joinToString(",") { it.number!!.toString() }
variable.onetimeInitializationArrayValue.joinToString(",") { it.number!!.toString() }
} else {
"" // array will be zero'd out at program start
}
}
in ArrayDatatypes -> {
if(variable.onetimeInitializationArrayValue!==null) {
variable.onetimeInitializationArrayValue!!.joinToString(",") {
variable.onetimeInitializationArrayValue.joinToString(",") {
if(it.number!=null)
it.number!!.toInt().toHex()
it.number.toInt().toHex()
else
"@${it.addressOfSymbol}"
}
@ -273,7 +271,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
}
else -> throw InternalCompilerException("weird dt")
}
xml.writeCharacters("$typeStr ${variable.name}=$value zp=${variable.zpwish}\n")
xml.writeCharacters("${variable.typeString} ${variable.name}=$value zp=${variable.zpwish}\n")
}
}
xml.writeEndElement()
@ -282,8 +280,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
xml.writeStartElement("MEMORYMAPPEDVARIABLES")
xml.writeCharacters("\n")
for (variable in irProgram.st.allMemMappedVariables()) {
val typeStr = getTypeString(variable)
xml.writeCharacters("@$typeStr ${variable.name}=${variable.address.toHex()}\n")
xml.writeCharacters("@${variable.typeString} ${variable.name}=${variable.address.toHex()}\n")
}
xml.writeEndElement()
xml.writeCharacters("\n")

View File

@ -1,88 +1,88 @@
package prog8.intermediate
import prog8.code.*
import prog8.code.ast.PtVariable
import prog8.code.core.DataType
import prog8.code.core.ZeropageWish
import prog8.code.core.internedStringsModuleName
import prog8.code.core.*
// In the Intermediate Representation, all nesting has been removed.
// So the symbol table is just a big flat mapping of (scoped)name to node.
// We define a stripped down symbol table for use in the IR phase only, rather than reuse the codegen symboltable
class IRSymbolTable(sourceSt: SymbolTable?) {
private val table = mutableMapOf<String, StNode>()
class IRSymbolTable {
private val table = mutableMapOf<String, IRStNode>()
private val asmSymbols = mutableMapOf<String, String>()
init {
if(sourceSt!=null) {
sourceSt.allVariables.forEach {
add(it)
}
sourceSt.allMemMappedVariables.forEach {
add(it)
}
sourceSt.allMemorySlabs.forEach {
add(it)
}
companion object {
fun fromStDuringCodegen(sourceSt: SymbolTable?): IRSymbolTable {
val st = IRSymbolTable()
if (sourceSt != null) {
sourceSt.allVariables.forEach {
st.add(it)
}
sourceSt.allMemMappedVariables.forEach {
st.add(it)
}
sourceSt.allMemorySlabs.forEach {
st.add(it)
}
require(table.all { it.key==it.value.name })
require(st.table.all { it.key == it.value.name })
allVariables().forEach {variable ->
variable.onetimeInitializationArrayValue?.let {
it.forEach { arrayElt ->
if(arrayElt.addressOfSymbol!=null) {
require(arrayElt.addressOfSymbol!!.contains('.')) {
"pointer var in array should be properly scoped: ${arrayElt.addressOfSymbol} in ${variable.name}"
st.allVariables().forEach { variable ->
variable.onetimeInitializationArrayValue?.let {
it.forEach { arrayElt ->
if (arrayElt.addressOfSymbol != null) {
require(arrayElt.addressOfSymbol.contains('.')) {
"pointer var in array should be properly scoped: ${arrayElt.addressOfSymbol} in ${variable.name}"
}
}
}
}
}
}
return st
}
}
fun allVariables(): Sequence<StStaticVariable> =
table.asSequence().map { it.value }.filterIsInstance<StStaticVariable>()
fun allVariables(): Sequence<IRStStaticVariable> =
table.asSequence().map { it.value }.filterIsInstance<IRStStaticVariable>()
fun allMemMappedVariables(): Sequence<StMemVar> =
table.asSequence().map { it.value }.filterIsInstance<StMemVar>()
fun allMemMappedVariables(): Sequence<IRStMemVar> =
table.asSequence().map { it.value }.filterIsInstance<IRStMemVar>()
fun allMemorySlabs(): Sequence<StMemorySlab> =
table.asSequence().map { it.value }.filterIsInstance<StMemorySlab>()
fun allMemorySlabs(): Sequence<IRStMemorySlab> =
table.asSequence().map { it.value }.filterIsInstance<IRStMemorySlab>()
fun lookup(name: String) = table[name]
fun add(variable: StStaticVariable) {
val scopedName: String
val varToadd: StStaticVariable
val varToadd: IRStStaticVariable
if('.' in variable.name) {
scopedName = variable.name
varToadd = variable
varToadd = IRStStaticVariable.from(variable)
} else {
fun fixupAddressOfInArray(array: List<StArrayElement>?): List<StArrayElement>? {
fun fixupAddressOfInArray(array: List<StArrayElement>?): List<IRStArrayElement>? {
if(array==null)
return null
val newArray = mutableListOf<StArrayElement>()
val newArray = mutableListOf<IRStArrayElement>()
array.forEach {
if(it.addressOfSymbol!=null) {
val target = variable.lookup(it.addressOfSymbol!!)!!
newArray.add(StArrayElement(null, target.scopedName))
newArray.add(IRStArrayElement(null, target.scopedName))
} else {
newArray.add(it)
newArray.add(IRStArrayElement.from(it))
}
}
return newArray
}
scopedName = variable.scopedName
val dummyNode = PtVariable(scopedName, variable.dt, variable.zpwish, null, null, variable.astNode.position)
varToadd = StStaticVariable(scopedName, variable.dt,
varToadd = IRStStaticVariable(scopedName, variable.dt,
variable.onetimeInitializationNumericValue,
variable.onetimeInitializationStringValue,
fixupAddressOfInArray(variable.onetimeInitializationArrayValue),
variable.length,
variable.zpwish,
dummyNode
variable.zpwish
)
}
table[scopedName] = varToadd
@ -91,27 +91,26 @@ class IRSymbolTable(sourceSt: SymbolTable?) {
fun add(variable: StMemVar) {
val scopedName: String
val varToadd: StMemVar
val varToadd: IRStMemVar
if('.' in variable.name) {
scopedName = variable.name
varToadd = variable
varToadd = IRStMemVar.from(variable)
} else {
scopedName = try {
variable.scopedName
} catch (ux: UninitializedPropertyAccessException) {
variable.name
}
varToadd = StMemVar(scopedName, variable.dt, variable.address, variable.length, variable.astNode)
varToadd = IRStMemVar(scopedName, variable.dt, variable.address, variable.length)
}
table[scopedName] = varToadd
}
fun add(variable: StMemorySlab) {
val varToadd = if('.' in variable.name)
variable
IRStMemorySlab.from(variable)
else {
val dummyNode = PtVariable(variable.name, DataType.ARRAY_UB, ZeropageWish.NOT_IN_ZEROPAGE, null, null, variable.astNode.position)
StMemorySlab("prog8_slabs.${variable.name}", variable.size, variable.align, dummyNode)
IRStMemorySlab("prog8_slabs.${variable.name}", variable.size, variable.align)
}
table[varToadd.name] = varToadd
}
@ -133,3 +132,118 @@ class IRSymbolTable(sourceSt: SymbolTable?) {
}
}
}
enum class IRStNodeType {
STATICVAR,
MEMVAR,
MEMORYSLAB
// the other StNodeType types aren't used here anymore.
// this symbol table only contains variables.
}
open class IRStNode(val name: String,
val type: IRStNodeType,
val children: MutableMap<String, StNode> = mutableMapOf()
)
class IRStMemVar(name: String,
val dt: DataType,
val address: UInt,
val length: Int? // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte
) : IRStNode(name, IRStNodeType.MEMVAR) {
companion object {
fun from(variable: StMemVar): IRStMemVar {
return IRStMemVar(
variable.name,
variable.dt,
variable.address,
variable.length
)
}
}
val typeString: String
get() = when (dt) {
DataType.UBYTE -> "ubyte"
DataType.BYTE -> "byte"
DataType.UWORD -> "uword"
DataType.WORD -> "word"
DataType.FLOAT -> "float"
DataType.BOOL, DataType.ARRAY_BOOL -> throw InternalCompilerException("bool should have been converted to ubyte")
DataType.ARRAY_UB, DataType.STR -> "ubyte[${length}]"
DataType.ARRAY_B -> "byte[${length}]"
DataType.ARRAY_UW -> "uword[${length}]"
DataType.ARRAY_W -> "word[${length}]"
DataType.ARRAY_F -> "float[${length}]"
in SplitWordArrayTypes -> throw InternalCompilerException("@split can't be used on memory mapped arrays")
else -> throw InternalCompilerException("weird dt")
}
}
class IRStMemorySlab(
name: String,
val size: UInt,
val align: UInt
): IRStNode(name, IRStNodeType.MEMORYSLAB) {
companion object {
fun from(variable: StMemorySlab): IRStMemorySlab {
return IRStMemorySlab(
variable.name,
variable.size,
variable.align
)
}
}
}
class IRStStaticVariable(name: String,
val dt: DataType,
val onetimeInitializationNumericValue: Double?, // regular (every-run-time) initialization is done via regular assignments
val onetimeInitializationStringValue: IRStString?,
val onetimeInitializationArrayValue: IRStArray?,
val length: Int?, // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte
val zpwish: ZeropageWish // used in the variable allocator
) : IRStNode(name, IRStNodeType.STATICVAR) {
companion object {
fun from(variable: StStaticVariable): IRStStaticVariable {
return IRStStaticVariable(variable.name,
variable.dt,
variable.onetimeInitializationNumericValue,
variable.onetimeInitializationStringValue,
variable.onetimeInitializationArrayValue?.map { IRStArrayElement.from(it) },
variable.length,
variable.zpwish)
}
}
val uninitialized = onetimeInitializationArrayValue==null && onetimeInitializationStringValue==null && onetimeInitializationNumericValue==null
val typeString: String
get() = when (dt) {
DataType.UBYTE -> "ubyte"
DataType.BYTE -> "byte"
DataType.UWORD -> "uword"
DataType.WORD -> "word"
DataType.FLOAT -> "float"
DataType.BOOL, DataType.ARRAY_BOOL -> throw InternalCompilerException("bool should have been converted to ubyte")
DataType.ARRAY_UB, DataType.STR -> "ubyte[${length}]"
DataType.ARRAY_B -> "byte[${length}]"
DataType.ARRAY_UW -> "uword[${length}]"
DataType.ARRAY_W -> "word[${length}]"
DataType.ARRAY_F -> "float[${length}]"
in SplitWordArrayTypes -> throw InternalCompilerException("split array should have been converted to 2 ubyte arrays")
else -> throw InternalCompilerException("weird dt")
}
}
class IRStArrayElement(val number: Double?, val addressOfSymbol: String?) {
companion object {
fun from(elt: StArrayElement): IRStArrayElement {
return IRStArrayElement(elt.number, elt.addressOfSymbol)
}
}
}
typealias IRStArray = List<IRStArrayElement>
typealias IRStString = Pair<String, Encoding>

View File

@ -1,7 +1,9 @@
package prog8.intermediate
import prog8.code.*
import prog8.code.Either
import prog8.code.core.*
import prog8.code.left
import prog8.code.right
fun getTypeString(dt : DataType): String = when(dt) {
@ -20,38 +22,6 @@ fun getTypeString(dt : DataType): String = when(dt) {
else -> throw InternalCompilerException("weird dt")
}
fun getTypeString(memvar: StMemVar): String = when(memvar.dt) {
DataType.UBYTE -> "ubyte"
DataType.BYTE -> "byte"
DataType.UWORD -> "uword"
DataType.WORD -> "word"
DataType.FLOAT -> "float"
DataType.BOOL, DataType.ARRAY_BOOL -> throw InternalCompilerException("bool should have been converted to ubyte")
DataType.ARRAY_UB, DataType.STR -> "ubyte[${memvar.length}]"
DataType.ARRAY_B -> "byte[${memvar.length}]"
DataType.ARRAY_UW -> "uword[${memvar.length}]"
DataType.ARRAY_W -> "word[${memvar.length}]"
DataType.ARRAY_F -> "float[${memvar.length}]"
in SplitWordArrayTypes -> throw InternalCompilerException("@split can't be used on memory mapped arrays")
else -> throw InternalCompilerException("weird dt")
}
fun getTypeString(variable : StStaticVariable): String = when(variable.dt) {
DataType.UBYTE -> "ubyte"
DataType.BYTE -> "byte"
DataType.UWORD -> "uword"
DataType.WORD -> "word"
DataType.FLOAT -> "float"
DataType.BOOL, DataType.ARRAY_BOOL -> throw InternalCompilerException("bool should have been converted to ubyte")
DataType.ARRAY_UB, DataType.STR -> "ubyte[${variable.length}]"
DataType.ARRAY_B -> "byte[${variable.length}]"
DataType.ARRAY_UW -> "uword[${variable.length}]"
DataType.ARRAY_W -> "word[${variable.length}]"
DataType.ARRAY_F -> "float[${variable.length}]"
in SplitWordArrayTypes -> throw InternalCompilerException("split array should have been converted to 2 ubyte arrays")
else -> throw InternalCompilerException("weird dt")
}
fun convertIRType(typestr: String): IRDataType? {
return when(typestr.lowercase()) {
"" -> null

View File

@ -1,16 +1,12 @@
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.ints.shouldBeGreaterThan
import io.kotest.matchers.shouldBe
import prog8.code.StStaticVariable
import prog8.code.core.CbmPrgLauncherType
import prog8.code.core.CompilationOptions
import prog8.code.core.OutputType
import prog8.code.core.ZeropageType
import prog8.code.target.Cx16Target
import prog8.intermediate.IRFileReader
import prog8.intermediate.IRFileWriter
import prog8.intermediate.IRProgram
import prog8.intermediate.IRSymbolTable
import prog8.intermediate.*
import kotlin.io.path.*
class TestIRFileInOut: FunSpec({
@ -29,7 +25,7 @@ class TestIRFileInOut: FunSpec({
loadAddress = target.machine.PROGRAM_LOAD_ADDRESS,
outputDir = tempdir
)
val program = IRProgram("unittest-irwriter", IRSymbolTable(null), options, target)
val program = IRProgram("unittest-irwriter", IRSymbolTable(), options, target)
val writer = IRFileWriter(program, null)
val generatedFile = writer.write()
val lines = generatedFile.readLines()
@ -107,9 +103,9 @@ return
program.name shouldBe "test-ir-reader"
program.blocks.size shouldBe 2
program.st.allVariables().count() shouldBe 3
val var1 = program.st.lookup("sys.wait.jiffies") as StStaticVariable
val var2 = program.st.lookup("sys.bssvar") as StStaticVariable
val var3 = program.st.lookup("sys.emptystring") as StStaticVariable
val var1 = program.st.lookup("sys.wait.jiffies") as IRStStaticVariable
val var2 = program.st.lookup("sys.bssvar") as IRStStaticVariable
val var3 = program.st.lookup("sys.emptystring") as IRStStaticVariable
var1.uninitialized shouldBe false
var2.uninitialized shouldBe true
var3.uninitialized shouldBe true

View File

@ -1,8 +1,5 @@
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
@ -247,7 +244,7 @@ class VmProgramLoader {
if(iElts.isEmpty() || iElts.size==1) {
val iElt = if(iElts.isEmpty()) {
require(variable.uninitialized)
StArrayElement(0.0, null)
IRStArrayElement(0.0, null)
} else {
require(!variable.uninitialized)
iElts[0]
@ -262,8 +259,8 @@ class VmProgramLoader {
}
private fun initializeWithValues(
variable: StStaticVariable,
iElts: StArray,
variable: IRStStaticVariable,
iElts: IRStArray,
startAddress: Int,
symbolAddresses: MutableMap<String, Int>,
memory: Memory,
@ -325,8 +322,8 @@ class VmProgramLoader {
}
private fun initializeWithOneValue(
variable: StStaticVariable,
iElt: StArrayElement,
variable: IRStStaticVariable,
iElt: IRStArrayElement,
startAddress: Int,
symbolAddresses: MutableMap<String, Int>,
memory: Memory,
@ -389,7 +386,7 @@ class VmProgramLoader {
}
}
private fun getInitializerValue(arrayDt: DataType, elt: StArrayElement, symbolAddresses: MutableMap<String, Int>): Double {
private fun getInitializerValue(arrayDt: DataType, elt: IRStArrayElement, symbolAddresses: MutableMap<String, Int>): Double {
if(elt.addressOfSymbol!=null) {
when(arrayDt) {
DataType.ARRAY_UB, DataType.STR, DataType.ARRAY_B, DataType.ARRAY_BOOL -> {

View File

@ -29,7 +29,7 @@ class TestVm: FunSpec( {
}
test("vm execution: empty program") {
val program = IRProgram("test", IRSymbolTable(null), getTestOptions(), VMTarget())
val program = IRProgram("test", IRSymbolTable(), getTestOptions(), VMTarget())
val vm = VirtualMachine(program)
vm.callStack.shouldBeEmpty()
vm.valueStack.shouldBeEmpty()
@ -43,7 +43,7 @@ class TestVm: FunSpec( {
}
test("vm execution: modify memory") {
val program = IRProgram("test", IRSymbolTable(null), getTestOptions(), VMTarget())
val program = IRProgram("test", IRSymbolTable(), getTestOptions(), VMTarget())
val block = IRBlock("testmain", null, false, false, IRBlock.BlockAlignment.NONE, Position.DUMMY)
val startSub = IRSubroutine("testmain.testsub", emptyList(), null, Position.DUMMY)
val code = IRCodeChunk(startSub.label, null)
@ -72,7 +72,7 @@ class TestVm: FunSpec( {
}
test("asmsub not supported in vm even with IR") {
val program = IRProgram("test", IRSymbolTable(null), getTestOptions(), VMTarget())
val program = IRProgram("test", IRSymbolTable(), getTestOptions(), VMTarget())
val block = IRBlock("main", null, false, false, IRBlock.BlockAlignment.NONE, Position.DUMMY)
val startSub = IRAsmSubroutine(
"main.asmstart",