fix error in IR for inline asm and BSS vars.

This commit is contained in:
Irmen de Jong 2022-12-04 16:02:58 +01:00
parent a82b2da16e
commit bf0604133c
10 changed files with 90 additions and 110 deletions

View File

@ -251,7 +251,7 @@ internal class AstChecker(private val program: Program,
} }
override fun visit(inlineAssembly: InlineAssembly) { override fun visit(inlineAssembly: InlineAssembly) {
if(inlineAssembly.hasReturnOrRts(compilerOptions.compTarget)) if(inlineAssembly.hasReturnOrRts())
count++ count++
} }
} }

View File

@ -168,9 +168,9 @@ internal fun IdentifierReference.isSubroutineParameter(program: Program): Boolea
return false return false
} }
internal fun Subroutine.hasRtsInAsm(compTarget: ICompilationTarget): Boolean { internal fun Subroutine.hasRtsInAsm(): Boolean {
return statements return statements
.asSequence() .asSequence()
.filterIsInstance<InlineAssembly>() .filterIsInstance<InlineAssembly>()
.any { it.hasReturnOrRts(compTarget) } .any { it.hasReturnOrRts() }
} }

View File

@ -137,7 +137,7 @@ internal class BeforeAsmAstChanger(val program: Program,
mods += IAstModification.InsertLast(returnStmt, subroutine) mods += IAstModification.InsertLast(returnStmt, subroutine)
} else { } else {
val last = subroutine.statements.last() val last = subroutine.statements.last()
if((last !is InlineAssembly || !last.hasReturnOrRts(options.compTarget)) && last !is Return) { if((last !is InlineAssembly || !last.hasReturnOrRts()) && last !is Return) {
val lastStatement = subroutine.statements.reversed().firstOrNull { it !is Subroutine } val lastStatement = subroutine.statements.reversed().firstOrNull { it !is Subroutine }
if(lastStatement !is Return) { if(lastStatement !is Return) {
val returnStmt = Return(null, subroutine.position) val returnStmt = Return(null, subroutine.position)
@ -164,7 +164,7 @@ internal class BeforeAsmAstChanger(val program: Program,
} }
if (!subroutine.inline || !options.optimize) { if (!subroutine.inline || !options.optimize) {
if (subroutine.isAsmSubroutine && subroutine.asmAddress==null && !subroutine.hasRtsInAsm(options.compTarget)) { if (subroutine.isAsmSubroutine && subroutine.asmAddress==null && !subroutine.hasRtsInAsm()) {
// make sure the NOT INLINED asm subroutine actually has a rts at the end // make sure the NOT INLINED asm subroutine actually has a rts at the end
// (non-asm routines get a Return statement as needed, above) // (non-asm routines get a Return statement as needed, above)
mods += if(options.compTarget.name==VMTarget.NAME) mods += if(options.compTarget.name==VMTarget.NAME)

View File

@ -62,6 +62,8 @@ internal class SymbolTableMaker: IAstVisitor {
when(decl.type) { when(decl.type) {
VarDeclType.VAR -> { VarDeclType.VAR -> {
var initialNumeric = (decl.value as? NumericLiteral)?.number var initialNumeric = (decl.value as? NumericLiteral)?.number
if(initialNumeric==0.0)
initialNumeric=null // variable will go into BSS and this will be set to 0
val initialStringLit = decl.value as? StringLiteral val initialStringLit = decl.value as? StringLiteral
val initialString = if(initialStringLit==null) null else Pair(initialStringLit.value, initialStringLit.encoding) val initialString = if(initialStringLit==null) null else Pair(initialStringLit.value, initialStringLit.encoding)
val initialArrayLit = decl.value as? ArrayLiteral val initialArrayLit = decl.value as? ArrayLiteral
@ -79,10 +81,8 @@ internal class SymbolTableMaker: IAstVisitor {
false false
else if(decl.isArray) else if(decl.isArray)
initialArray.isNullOrEmpty() initialArray.isNullOrEmpty()
else { else
if(dontReinitGlobals) initialNumeric = initialNumeric ?: 0.0
initialNumeric == null initialNumeric == null
}
StStaticVariable(decl.name, decl.datatype, bss, initialNumeric, initialString, initialArray, numElements, decl.zeropage, decl.position) StStaticVariable(decl.name, decl.datatype, bss, initialNumeric, initialString, initialArray, numElements, decl.zeropage, decl.position)
} }
VarDeclType.CONST -> StConstant(decl.name, decl.datatype, (decl.value as NumericLiteral).number, decl.position) VarDeclType.CONST -> StConstant(decl.name, decl.datatype, (decl.value as NumericLiteral).number, decl.position)

View File

@ -124,7 +124,7 @@ class TestSubroutines: FunSpec({
asmfunc.isAsmSubroutine shouldBe true asmfunc.isAsmSubroutine shouldBe true
asmfunc.statements.single() shouldBe instanceOf<InlineAssembly>() asmfunc.statements.single() shouldBe instanceOf<InlineAssembly>()
(asmfunc.statements.single() as InlineAssembly).assembly.trim() shouldBe "rts" (asmfunc.statements.single() as InlineAssembly).assembly.trim() shouldBe "rts"
asmfunc.hasRtsInAsm(C64Target()) shouldBe true asmfunc.hasRtsInAsm() shouldBe true
func.isAsmSubroutine shouldBe false func.isAsmSubroutine shouldBe false
withClue("str param should have been changed to uword") { withClue("str param should have been changed to uword") {
asmfunc.parameters.single().type shouldBe DataType.UWORD asmfunc.parameters.single().type shouldBe DataType.UWORD

View File

@ -7,7 +7,6 @@ import prog8.ast.expressions.*
import prog8.ast.walk.AstWalker import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstVisitor import prog8.ast.walk.IAstVisitor
import prog8.code.core.* import prog8.code.core.*
import prog8.code.target.VMTarget
interface INamedStatement { interface INamedStatement {
@ -637,12 +636,12 @@ class InlineAssembly(val assembly: String, val isIR: Boolean, override val posit
override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
fun hasReturnOrRts(target: ICompilationTarget): Boolean { fun hasReturnOrRts(): Boolean {
return if(target.name!= VMTarget.NAME) { return if(isIR) {
" return" in assembly || "\treturn" in assembly || " jump" in assembly || "\tjump" in assembly || " jumpa" in assembly || "\tjumpa" in assembly
} else {
" rti" in assembly || "\trti" in assembly || " rts" in assembly || "\trts" in assembly || " rti" in assembly || "\trti" in assembly || " rts" in assembly || "\trts" in assembly ||
" jmp" in assembly || "\tjmp" in assembly || " bra" in assembly || "\tbra" in assembly " jmp" in assembly || "\tjmp" in assembly || " bra" in assembly || "\tbra" in assembly
} else {
" return" in assembly || "\treturn" in assembly || " jump" in assembly || "\tjump" in assembly || " jumpa" in assembly || "\tjumpa" in assembly
} }
} }

View File

@ -3,11 +3,6 @@ TODO
For next release For next release
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
- fix compiler crash when compiling %import test_stack on virtual target.
- bss in IR: with -noreinit, variables that have init value 0 should still be bss.
- 6502 codegen: create BSS section in output assembly code and put StStaticVariables in there with bss=true.
Don't forget to add init code to zero out everything that was put in bss. If array in bss->only zero ONCE if possible.
Note that bss can still contain variables that have @zp tag and those are already dealt with differently
- regression test the various projects before release - regression test the various projects before release
... ...
@ -24,6 +19,10 @@ Future Things and Ideas
^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^
Compiler: Compiler:
- 6502 codegen: create BSS section in output assembly code and put StStaticVariables in there with bss=true.
Don't forget to add init code to zero out everything that was put in bss. If array in bss->only zero ONCE if possible.
Note that bss can still contain variables that have @zp tag and those are already dealt with differently
- bss: subroutine parameters don't have to be set to 0.
- ir: mechanism to determine for chunks which registers are getting input values from "outside" - ir: mechanism to determine for chunks which registers are getting input values from "outside"
- ir: mechanism to determine for chunks which registers are passing values out? (i.e. are used again in another chunk) - ir: mechanism to determine for chunks which registers are passing values out? (i.e. are used again in another chunk)
- ir: peephole opt: renumber registers in chunks to start with 1 again every time (but keep entry values in mind!) - ir: peephole opt: renumber registers in chunks to start with 1 again every time (but keep entry values in mind!)

View File

@ -1,79 +1,52 @@
%import textio %import textio
%import floats %zeropage basicsafe
%option no_sysinit
main { main {
sub score() -> ubyte { ubyte @requirezp zpvar = 10
cx16.r15++ ubyte @zp zpvar2 = 20
return 5 uword empty
} ubyte[10] bssarray
uword[10] bsswordarray
ubyte[10] nonbssarray = 99
str name="irmen"
sub start() { sub start() {
float @shared total = 0 txt.print("= 10 ")
ubyte bb = 5 txt.print_ub(zpvar)
txt.nl()
zpvar++
cx16.r0 = 5 txt.print("= 20 ")
total += cx16.r0 as float txt.print_ub(zpvar2)
total += score() as float txt.nl()
uword ww = 5 zpvar2++
total += ww as float
total += bb as float txt.print("= 0 ")
float result = score() as float txt.print_uw(empty)
total += result txt.nl()
empty++
txt.print("+ 0 ")
txt.print_ub(bssarray[1])
txt.nl()
bssarray[1]++
txt.print("+ 0 ")
txt.print_uw(bsswordarray[1])
txt.nl()
bsswordarray[1]++
txt.print("+ 99 ")
txt.print_ub(nonbssarray[1])
txt.nl()
nonbssarray[1]++
txt.print("+ r ")
txt.chrout(name[1])
txt.nl()
name[1] = (name[1] as ubyte +1)
txt.print("try running again.\n")
} }
} }
;%import textio
;%zeropage basicsafe
;%option no_sysinit
;
;main {
;
; sub start() {
; ; TODO ALSO TEST AS GLOBALS
; ubyte @requirezp zpvar = 10
; ubyte @zp zpvar2 = 20
; uword empty
; ubyte[10] bssarray
; uword[10] bsswordarray
; ubyte[10] nonbssarray = 99
; str name="irmen"
;
; txt.print("10 ")
; txt.print_ub(zpvar)
; txt.nl()
; zpvar++
;
; txt.print("20 ")
; txt.print_ub(zpvar2)
; txt.nl()
; zpvar2++
;
; txt.print("0 ")
; txt.print_uw(empty)
; txt.nl()
; empty++
;
; txt.print("0 ")
; txt.print_ub(bssarray[1])
; txt.nl()
; bssarray[1]++
;
; txt.print("0 ")
; txt.print_uw(bsswordarray[1])
; txt.nl()
; bsswordarray[1]++
;
; txt.print("99 ")
; txt.print_ub(nonbssarray[1])
; txt.nl()
; nonbssarray[1]++
;
; txt.print("r ")
; txt.chrout(name[1])
; txt.nl()
; name[1] = (name[1] as ubyte +1)
;
; txt.print("try running again.\n")
; }
;}

View File

@ -435,7 +435,8 @@ class IRFileReader {
val clobbers = attrs.getValue("CLOBBERS") val clobbers = attrs.getValue("CLOBBERS")
val clobberRegs = if(clobbers.isBlank()) emptyList() else clobbers.split(',').map { CpuRegister.valueOf(it) } val clobberRegs = if(clobbers.isBlank()) emptyList() else clobbers.split(',').map { CpuRegister.valueOf(it) }
val returns = attrs.getValue("RETURNS").split(',').map { rs -> val returnsSpec = attrs.getValue("RETURNS")
val returns = if(returnsSpec.isNullOrBlank()) emptyList() else returnsSpec.split(',').map { rs ->
val (regstr, dtstr) = rs.split(':') val (regstr, dtstr) = rs.split(':')
val dt = parseDatatype(dtstr, false) val dt = parseDatatype(dtstr, false)
val regsf = parseRegisterOrStatusflag(regstr) val regsf = parseRegisterOrStatusflag(regstr)

View File

@ -1,8 +1,6 @@
package prog8.vm package prog8.vm
import prog8.code.core.ArrayDatatypes import prog8.code.core.*
import prog8.code.core.AssemblyError
import prog8.code.core.DataType
import prog8.intermediate.* import prog8.intermediate.*
class VmProgramLoader { class VmProgramLoader {
@ -185,24 +183,34 @@ class VmProgramLoader {
program.st.allVariables().forEach { variable -> program.st.allVariables().forEach { variable ->
var addr = allocations.allocations.getValue(variable.name) var addr = allocations.allocations.getValue(variable.name)
if(variable.bss && variable.dt in ArrayDatatypes) { // zero out BSS variables.
// zero out the array bss variable. if(variable.bss) {
// non-array variables are reset using explicit assignment instructions. if(variable.dt in ArrayDatatypes) {
repeat(variable.length!!) { repeat(variable.length!!) {
when(variable.dt) { when(variable.dt) {
DataType.STR, DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_BOOL -> { DataType.STR, DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_BOOL -> {
memory.setUB(addr, 0u) memory.setUB(addr, 0u)
addr++ addr++
}
DataType.ARRAY_UW, DataType.ARRAY_W -> {
memory.setUW(addr, 0u)
addr += 2
}
DataType.ARRAY_F -> {
memory.setFloat(addr, 0.0f)
addr += program.options.compTarget.machine.FLOAT_MEM_SIZE
}
else -> throw IRParseException("invalid dt")
} }
DataType.ARRAY_UW, DataType.ARRAY_W -> { }
memory.setUW(addr, 0u) } else {
addr += 2 if(program.options.dontReinitGlobals) {
when(variable.dt) {
in ByteDatatypes -> memory.setUB(addr, 0u)
in WordDatatypes -> memory.setUW(addr, 0u)
DataType.FLOAT -> memory.setFloat(addr, 0.0f)
else -> throw IRParseException("invalid dt")
} }
DataType.ARRAY_F -> {
memory.setFloat(addr, 0.0f)
addr += program.options.compTarget.machine.FLOAT_MEM_SIZE
}
else -> throw IRParseException("invalid dt")
} }
} }
} }