mirror of
https://github.com/irmen/prog8.git
synced 2024-11-22 15:33:02 +00:00
ir: several fixes
This commit is contained in:
parent
02e51d8282
commit
3126959576
@ -80,6 +80,16 @@ class SymbolTable(astProgram: PtProgram) : StNode(astProgram.name, StNodeType.GL
|
||||
}
|
||||
|
||||
override fun lookup(scopedName: String) = flat[scopedName]
|
||||
|
||||
fun getLength(name: String): Int? {
|
||||
val node = flat[name]
|
||||
return when(node) {
|
||||
is StMemVar -> node.length
|
||||
is StMemorySlab -> node.size.toInt()
|
||||
is StStaticVariable -> node.length
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -484,8 +484,8 @@ internal class ProgramAndVarsGen(
|
||||
val vars = allocator.zeropageVars.filter { it.value.dt==DataType.STR }
|
||||
for (variable in vars) {
|
||||
val scopedName = variable.key
|
||||
val svar = symboltable.flat.getValue(scopedName) as StStaticVariable
|
||||
if(svar.onetimeInitializationStringValue!=null)
|
||||
val svar = symboltable.lookup(scopedName) as? StStaticVariable
|
||||
if(svar?.onetimeInitializationStringValue!=null)
|
||||
result.add(ZpStringWithInitial(scopedName, variable.value, svar.onetimeInitializationStringValue!!))
|
||||
}
|
||||
return result
|
||||
@ -496,8 +496,8 @@ internal class ProgramAndVarsGen(
|
||||
val vars = allocator.zeropageVars.filter { it.value.dt in ArrayDatatypes }
|
||||
for (variable in vars) {
|
||||
val scopedName = variable.key
|
||||
val svar = symboltable.flat.getValue(scopedName) as StStaticVariable
|
||||
if(svar.onetimeInitializationArrayValue!=null)
|
||||
val svar = symboltable.lookup(scopedName) as? StStaticVariable
|
||||
if(svar?.onetimeInitializationArrayValue!=null)
|
||||
result.add(ZpArrayWithInitial(scopedName, variable.value, svar.onetimeInitializationArrayValue!!))
|
||||
}
|
||||
return result
|
||||
|
@ -1,6 +1,5 @@
|
||||
package prog8.codegen.intermediate
|
||||
|
||||
import prog8.code.StStaticVariable
|
||||
import prog8.code.ast.*
|
||||
import prog8.code.core.AssemblyError
|
||||
import prog8.code.core.DataType
|
||||
@ -219,8 +218,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
}
|
||||
|
||||
val fixedIndex = constIntValue(targetArray.index)
|
||||
val iterable = codeGen.symbolTable.flat.getValue(targetArray.variable.name) as StStaticVariable
|
||||
val arrayLength = iterable.length!!
|
||||
val arrayLength = codeGen.symbolTable.getLength(targetArray.variable.name)
|
||||
if(zero) {
|
||||
if(fixedIndex!=null) {
|
||||
val chunk = IRCodeChunk(null, null).also {
|
||||
|
@ -119,7 +119,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
|
||||
private fun funcAny(call: PtBuiltinFunctionCall): ExpressionCodeResult {
|
||||
val arrayName = call.args[0] as PtIdentifier
|
||||
val array = codeGen.symbolTable.flat.getValue(arrayName.name) as StStaticVariable
|
||||
val array = codeGen.symbolTable.lookup(arrayName.name) as StStaticVariable // TODO FIX/TEST for memory mapped array
|
||||
val syscall =
|
||||
when (array.dt) {
|
||||
DataType.ARRAY_UB,
|
||||
@ -140,7 +140,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
|
||||
private fun funcAll(call: PtBuiltinFunctionCall): ExpressionCodeResult {
|
||||
val arrayName = call.args[0] as PtIdentifier
|
||||
val array = codeGen.symbolTable.flat.getValue(arrayName.name) as StStaticVariable
|
||||
val array = codeGen.symbolTable.lookup(arrayName.name) as StStaticVariable // TODO FIX/TEST for memory mapped array
|
||||
val syscall =
|
||||
when(array.dt) {
|
||||
DataType.ARRAY_UB,
|
||||
@ -287,7 +287,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
|
||||
private fun funcReverse(call: PtBuiltinFunctionCall): ExpressionCodeResult {
|
||||
val arrayName = call.args[0] as PtIdentifier
|
||||
val array = codeGen.symbolTable.flat.getValue(arrayName.name) as StStaticVariable
|
||||
val array = codeGen.symbolTable.lookup(arrayName.name) as StStaticVariable // TODO FIX/TEST for memory mapped array
|
||||
val syscall =
|
||||
when(array.dt) {
|
||||
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.STR -> IMSyscall.REVERSE_BYTES
|
||||
@ -307,7 +307,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
|
||||
private fun funcSort(call: PtBuiltinFunctionCall): ExpressionCodeResult {
|
||||
val arrayName = call.args[0] as PtIdentifier
|
||||
val array = codeGen.symbolTable.flat.getValue(arrayName.name) as StStaticVariable
|
||||
val array = codeGen.symbolTable.lookup(arrayName.name) as StStaticVariable // TODO FIX/TEST for memory mapped array
|
||||
val syscall =
|
||||
when(array.dt) {
|
||||
DataType.ARRAY_UB -> IMSyscall.SORT_UBYTE
|
||||
|
@ -106,7 +106,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
|
||||
private fun translate(check: PtContainmentCheck): ExpressionCodeResult {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val iterable = codeGen.symbolTable.flat.getValue(check.iterable.name) as StStaticVariable
|
||||
val iterable = codeGen.symbolTable.lookup(check.iterable.name) as StStaticVariable // TODO FIX/TEST for memory mapped array , replace with check.iterable.type???
|
||||
when(iterable.dt) {
|
||||
DataType.STR -> {
|
||||
val elementTr = translateExpression(check.element)
|
||||
@ -164,8 +164,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
|
||||
if(arrayIx.splitWords) {
|
||||
require(vmDt==IRDataType.WORD)
|
||||
val iterable = codeGen.symbolTable.flat.getValue(arrayIx.variable.name) as StStaticVariable
|
||||
val arrayLength = iterable.length!!
|
||||
val arrayLength = codeGen.symbolTable.getLength(arrayIx.variable.name)
|
||||
resultRegister = codeGen.registers.nextFree()
|
||||
if(arrayIx.index is PtNumber) {
|
||||
val memOffset = (arrayIx.index as PtNumber).number.toInt()
|
||||
|
@ -168,6 +168,11 @@ class IRCodeGen(
|
||||
|
||||
replacements.forEach {
|
||||
val old = it.first.instructions[it.second]
|
||||
val formats = instructionFormats.getValue(old.opcode)
|
||||
val format = formats.getOrElse(old.type) { throw IllegalArgumentException("type ${old.type} invalid for ${old.opcode}") }
|
||||
val immediateValue = if(format.immediate) it.third.toInt() else null
|
||||
val addressValue = if(format.immediate) null else it.third.toInt()
|
||||
|
||||
it.first.instructions[it.second] = IRInstruction(
|
||||
old.opcode,
|
||||
old.type,
|
||||
@ -175,9 +180,9 @@ class IRCodeGen(
|
||||
old.reg2,
|
||||
old.fpReg1,
|
||||
old.fpReg2,
|
||||
immediate = immediateValue,
|
||||
null,
|
||||
null,
|
||||
address = it.third.toInt(),
|
||||
address = addressValue,
|
||||
null,
|
||||
null
|
||||
)
|
||||
@ -447,60 +452,63 @@ class IRCodeGen(
|
||||
result += translateForInNonConstantRange(forLoop, loopvar)
|
||||
}
|
||||
is PtIdentifier -> {
|
||||
val iterableVar = symbolTable.lookup(iterable.name) as StStaticVariable
|
||||
require(forLoop.variable.name == loopvar.scopedName)
|
||||
val iterableLength = symbolTable.getLength(iterable.name)
|
||||
val loopvarSymbol = forLoop.variable.name
|
||||
val indexReg = registers.nextFree()
|
||||
val tmpReg = registers.nextFree()
|
||||
val loopLabel = createLabelName()
|
||||
val endLabel = createLabelName()
|
||||
if(iterableVar.dt==DataType.STR) {
|
||||
// iterate over a zero-terminated string
|
||||
addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = indexReg, immediate = 0), null)
|
||||
result += IRCodeChunk(loopLabel, null).also {
|
||||
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1 = tmpReg, reg2 = indexReg, labelSymbol = iterable.name)
|
||||
it += IRInstruction(Opcode.BEQ, IRDataType.BYTE, reg1 = tmpReg, immediate = 0, labelSymbol = endLabel)
|
||||
it += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1 = tmpReg, labelSymbol = loopvarSymbol)
|
||||
when (iterable.type) {
|
||||
DataType.STR -> {
|
||||
// iterate over a zero-terminated string
|
||||
addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1 = indexReg, immediate = 0), null)
|
||||
result += IRCodeChunk(loopLabel, null).also {
|
||||
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1 = tmpReg, reg2 = indexReg, labelSymbol = iterable.name)
|
||||
it += IRInstruction(Opcode.BEQ, IRDataType.BYTE, reg1 = tmpReg, immediate = 0, labelSymbol = endLabel)
|
||||
it += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1 = tmpReg, labelSymbol = loopvarSymbol)
|
||||
}
|
||||
result += translateNode(forLoop.statements)
|
||||
val jumpChunk = IRCodeChunk(null, null)
|
||||
jumpChunk += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1 = indexReg)
|
||||
jumpChunk += IRInstruction(Opcode.JUMP, labelSymbol = loopLabel)
|
||||
result += jumpChunk
|
||||
result += IRCodeChunk(endLabel, null)
|
||||
}
|
||||
result += translateNode(forLoop.statements)
|
||||
val jumpChunk = IRCodeChunk(null, null)
|
||||
jumpChunk += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1 = indexReg)
|
||||
jumpChunk += IRInstruction(Opcode.JUMP, labelSymbol = loopLabel)
|
||||
result += jumpChunk
|
||||
result += IRCodeChunk(endLabel, null)
|
||||
} else if(iterable.type in SplitWordArrayTypes) {
|
||||
// iterate over lsb/msb split word array
|
||||
val elementDt = ArrayToElementTypes.getValue(iterable.type)
|
||||
if(elementDt !in WordDatatypes)
|
||||
throw AssemblyError("weird dt")
|
||||
val length = iterableVar.length!!
|
||||
addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, immediate = 0), null)
|
||||
result += IRCodeChunk(loopLabel, null).also {
|
||||
val tmpRegLsb = registers.nextFree()
|
||||
val tmpRegMsb = registers.nextFree()
|
||||
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpRegLsb, reg2=indexReg, immediate = length, labelSymbol=iterable.name+"_lsb")
|
||||
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpRegMsb, reg2=indexReg, immediate = length, labelSymbol=iterable.name+"_msb")
|
||||
it += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=tmpRegLsb, reg2=tmpRegMsb)
|
||||
it += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpRegLsb, labelSymbol = loopvarSymbol)
|
||||
in SplitWordArrayTypes -> {
|
||||
// iterate over lsb/msb split word array
|
||||
val elementDt = ArrayToElementTypes.getValue(iterable.type)
|
||||
if(elementDt !in WordDatatypes)
|
||||
throw AssemblyError("weird dt")
|
||||
addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, immediate = 0), null)
|
||||
result += IRCodeChunk(loopLabel, null).also {
|
||||
val tmpRegLsb = registers.nextFree()
|
||||
val tmpRegMsb = registers.nextFree()
|
||||
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpRegLsb, reg2=indexReg, immediate = iterableLength, labelSymbol=iterable.name+"_lsb")
|
||||
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1=tmpRegMsb, reg2=indexReg, immediate = iterableLength, labelSymbol=iterable.name+"_msb")
|
||||
it += IRInstruction(Opcode.CONCAT, IRDataType.BYTE, reg1=tmpRegLsb, reg2=tmpRegMsb)
|
||||
it += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpRegLsb, labelSymbol = loopvarSymbol)
|
||||
}
|
||||
result += translateNode(forLoop.statements)
|
||||
result += IRCodeChunk(null, null).also {
|
||||
it += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=indexReg)
|
||||
it += IRInstruction(Opcode.BNE, IRDataType.BYTE, reg1=indexReg, immediate = if(iterableLength==256) 0 else iterableLength, labelSymbol = loopLabel)
|
||||
}
|
||||
}
|
||||
result += translateNode(forLoop.statements)
|
||||
result += IRCodeChunk(null, null).also {
|
||||
it += IRInstruction(Opcode.INC, IRDataType.BYTE, reg1=indexReg)
|
||||
it += IRInstruction(Opcode.BNE, IRDataType.BYTE, reg1=indexReg, immediate = if(length==256) 0 else length, labelSymbol = loopLabel)
|
||||
else -> {
|
||||
// iterate over regular array
|
||||
val elementDt = ArrayToElementTypes.getValue(iterable.type)
|
||||
val elementSize = program.memsizer.memorySize(elementDt)
|
||||
val lengthBytes = iterableLength!! * elementSize
|
||||
addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, immediate = 0), null)
|
||||
result += IRCodeChunk(loopLabel, null).also {
|
||||
it += IRInstruction(Opcode.LOADX, irType(elementDt), reg1=tmpReg, reg2=indexReg, labelSymbol=iterable.name)
|
||||
it += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpReg, labelSymbol = loopvarSymbol)
|
||||
}
|
||||
result += translateNode(forLoop.statements)
|
||||
result += addConstReg(IRDataType.BYTE, indexReg, elementSize)
|
||||
addInstr(result, IRInstruction(Opcode.BNE, IRDataType.BYTE, reg1=indexReg, immediate = if(lengthBytes==256) 0 else lengthBytes, labelSymbol = loopLabel), null)
|
||||
}
|
||||
} else {
|
||||
// iterate over regular array
|
||||
val elementDt = ArrayToElementTypes.getValue(iterable.type)
|
||||
val elementSize = program.memsizer.memorySize(elementDt)
|
||||
val lengthBytes = iterableVar.length!! * elementSize
|
||||
addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, immediate = 0), null)
|
||||
result += IRCodeChunk(loopLabel, null).also {
|
||||
it += IRInstruction(Opcode.LOADX, irType(elementDt), reg1=tmpReg, reg2=indexReg, labelSymbol=iterable.name)
|
||||
it += IRInstruction(Opcode.STOREM, irType(elementDt), reg1=tmpReg, labelSymbol = loopvarSymbol)
|
||||
}
|
||||
result += translateNode(forLoop.statements)
|
||||
result += addConstReg(IRDataType.BYTE, indexReg, elementSize)
|
||||
addInstr(result, IRInstruction(Opcode.BNE, IRDataType.BYTE, reg1=indexReg, immediate = if(lengthBytes==256) 0 else lengthBytes, labelSymbol = loopLabel), null)
|
||||
}
|
||||
}
|
||||
else -> throw AssemblyError("weird for iterable")
|
||||
@ -1362,7 +1370,6 @@ class IRCodeGen(
|
||||
if(array?.splitWords==true) {
|
||||
val variable = array.variable.name
|
||||
val fixedIndex = constIntValue(array.index)
|
||||
val iterable = symbolTable.flat.getValue(array.variable.name) as StStaticVariable
|
||||
if(fixedIndex!=null) {
|
||||
val skipLabel = createLabelName()
|
||||
when(postIncrDecr.operator) {
|
||||
@ -1388,7 +1395,7 @@ class IRCodeGen(
|
||||
else -> throw AssemblyError("weird operator")
|
||||
}
|
||||
} else {
|
||||
val arrayLength = iterable.length!!
|
||||
val arrayLength = symbolTable.getLength(array.variable.name)
|
||||
val indexTr = expressionEval.translateExpression(array.index)
|
||||
addToResult(result, indexTr, indexTr.resultReg, -1)
|
||||
val incReg = registers.nextFree()
|
||||
@ -1611,7 +1618,7 @@ class IRCodeGen(
|
||||
private fun translate(parameters: List<PtSubroutineParameter>) =
|
||||
parameters.map {
|
||||
val flattenedName = it.definingSub()!!.name + "." + it.name
|
||||
val orig = symbolTable.flat.getValue(flattenedName) as StStaticVariable
|
||||
val orig = symbolTable.lookup(flattenedName) as StStaticVariable // TODO FIX/TEST for memory mapped array or other
|
||||
IRSubroutine.IRParam(flattenedName, orig.dt)
|
||||
}
|
||||
|
||||
|
@ -139,6 +139,18 @@ class IRUnusedCodeRemover(
|
||||
.children.single { it is IRSubroutine && it.label=="main.start" }
|
||||
val reachable = mutableSetOf((entrypointSub as IRSubroutine).chunks.first())
|
||||
|
||||
// all chunks referenced in array initializer values are also 'reachable':
|
||||
irprog.st.allVariables()
|
||||
.filter { !it.uninitialized }
|
||||
.forEach {
|
||||
it.onetimeInitializationArrayValue?.let { array ->
|
||||
array.forEach {elt ->
|
||||
if(elt.addressOfSymbol!=null && irprog.st.lookup(elt.addressOfSymbol!!)==null)
|
||||
reachable.add(irprog.getChunkWithLabel(elt.addressOfSymbol!!))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun grow() {
|
||||
val new = mutableSetOf<IRCodeChunkBase>()
|
||||
reachable.forEach {
|
||||
@ -167,6 +179,18 @@ class IRUnusedCodeRemover(
|
||||
private fun removeSimpleUnlinked(allLabeledChunks: Map<String, IRCodeChunkBase>): Int {
|
||||
val linkedChunks = mutableSetOf<IRCodeChunkBase>()
|
||||
|
||||
// all chunks referenced in array initializer values are linked as well!:
|
||||
irprog.st.allVariables()
|
||||
.filter { !it.uninitialized }
|
||||
.forEach {
|
||||
it.onetimeInitializationArrayValue?.let { array ->
|
||||
array.forEach {elt ->
|
||||
if(elt.addressOfSymbol!=null && irprog.st.lookup(elt.addressOfSymbol!!)==null)
|
||||
linkedChunks += irprog.getChunkWithLabel(elt.addressOfSymbol!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
irprog.foreachCodeChunk { chunk ->
|
||||
chunk.next?.let { next -> linkedChunks += next }
|
||||
chunk.instructions.forEach {
|
||||
|
@ -1,8 +1,8 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
- Fix wrong unused subroutines in expericodegen with cx16 shell
|
||||
- Fix expericodegen errors (chess, assem, musicdemo, rockrunners etc)
|
||||
- Fix possible ST type error: // TODO FIX/TEST for memory mapped array
|
||||
- Fix expericodegen errors (chess, assem, musicdemo, rockrunners)
|
||||
|
||||
...
|
||||
|
||||
|
@ -1,10 +1,21 @@
|
||||
%import textio
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
||||
romsub $FFD2 = chrout(ubyte ch @ A)
|
||||
|
||||
sub start() {
|
||||
ubyte ch = '2'
|
||||
chrout(ch)
|
||||
; uword[] routines = [ 0, &command, $4444 ]
|
||||
; cx16.r0 = routines[1]
|
||||
|
||||
&ubyte[5] cells = $4000
|
||||
cells = [1,2,3,4,5]
|
||||
ubyte ub
|
||||
for ub in cells {
|
||||
txt.print_ub(ub)
|
||||
txt.spc()
|
||||
}
|
||||
}
|
||||
|
||||
sub command() {
|
||||
cx16.r0++
|
||||
}
|
||||
}
|
||||
|
@ -58,6 +58,15 @@ class IRProgram(val name: String,
|
||||
fun allSubs(): Sequence<IRSubroutine> = blocks.asSequence().flatMap { it.children.filterIsInstance<IRSubroutine>() }
|
||||
fun foreachSub(operation: (sub: IRSubroutine) -> Unit) = allSubs().forEach { operation(it) }
|
||||
fun foreachCodeChunk(operation: (chunk: IRCodeChunkBase) -> Unit) = allSubs().flatMap { it.chunks }.forEach { operation(it) }
|
||||
fun getChunkWithLabel(label: String): IRCodeChunkBase {
|
||||
for(sub in allSubs()) {
|
||||
for(chunk in sub.chunks) {
|
||||
if(chunk.label==label)
|
||||
return chunk
|
||||
}
|
||||
}
|
||||
throw NoSuchElementException("no chunk with label '$label'")
|
||||
}
|
||||
|
||||
fun addGlobalInits(chunk: IRCodeChunk) {
|
||||
globalInits += chunk
|
||||
|
Loading…
Reference in New Issue
Block a user