mirror of
https://github.com/irmen/prog8.git
synced 2024-12-27 20:33:39 +00:00
fix error in IR for inline asm and BSS vars.
This commit is contained in:
parent
a82b2da16e
commit
bf0604133c
@ -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++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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() }
|
||||||
}
|
}
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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!)
|
||||||
|
115
examples/test.p8
115
examples/test.p8
@ -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")
|
|
||||||
; }
|
|
||||||
;}
|
|
||||||
|
@ -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)
|
||||||
|
@ -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")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user