mirror of
https://github.com/irmen/prog8.git
synced 2024-12-01 15:52:54 +00:00
rts-check for non-inlined subroutines + var init adjustment when noreinit, moved out of codegen
This commit is contained in:
parent
312949f336
commit
77de99b383
@ -255,6 +255,11 @@ class AsmGen6502(internal val program: Program,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun block2asm(block: Block) {
|
private fun block2asm(block: Block) {
|
||||||
|
// no longer output the initialization assignments as regular statements in the block,
|
||||||
|
// they will be part of the prog8_init_vars init routine generated below.
|
||||||
|
val initializers = blockVariableInitializers.getValue(block)
|
||||||
|
val statements = block.statements.filterNot { it in initializers }
|
||||||
|
|
||||||
out("\n\n; ---- block: '${block.name}' ----")
|
out("\n\n; ---- block: '${block.name}' ----")
|
||||||
if(block.address!=null)
|
if(block.address!=null)
|
||||||
out("* = ${block.address!!.toHex()}")
|
out("* = ${block.address!!.toHex()}")
|
||||||
@ -267,36 +272,25 @@ class AsmGen6502(internal val program: Program,
|
|||||||
|
|
||||||
out("${block.name}\t" + (if("force_output" in block.options()) ".block\n" else ".proc\n"))
|
out("${block.name}\t" + (if("force_output" in block.options()) ".block\n" else ".proc\n"))
|
||||||
|
|
||||||
if(options.dontReinitGlobals) {
|
|
||||||
block.statements.asSequence().filterIsInstance<VarDecl>().forEach {
|
|
||||||
it.zeropage = ZeropageWish.NOT_IN_ZEROPAGE
|
|
||||||
it.findInitializer(program)?.let { initializer -> it.value = initializer.value } // put the init value back into the vardecl
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// no longer output the initialization assignments as regular statements in the block!
|
|
||||||
block.statements.removeAll(blockVariableInitializers.getValue(block))
|
|
||||||
|
|
||||||
outputSourceLine(block)
|
outputSourceLine(block)
|
||||||
zeropagevars2asm(block.statements, block)
|
zeropagevars2asm(statements, block)
|
||||||
memdefs2asm(block.statements, block)
|
memdefs2asm(statements, block)
|
||||||
vardecls2asm(block.statements, block)
|
vardecls2asm(statements, block)
|
||||||
|
|
||||||
block.statements.asSequence().filterIsInstance<VarDecl>().forEach {
|
statements.asSequence().filterIsInstance<VarDecl>().forEach {
|
||||||
if(it.type==VarDeclType.VAR && it.datatype in NumericDatatypes)
|
if(it.type==VarDeclType.VAR && it.datatype in NumericDatatypes)
|
||||||
it.value=null
|
it.value=null // TODO why is this done?
|
||||||
}
|
}
|
||||||
|
|
||||||
out("\n; subroutines in this block")
|
out("\n; subroutines in this block")
|
||||||
|
|
||||||
// first translate regular statements, and then put the subroutines at the end.
|
// first translate regular statements, and then put the subroutines at the end.
|
||||||
val (subroutine, stmts) = block.statements.partition { it is Subroutine }
|
val (subroutine, stmts) = statements.partition { it is Subroutine }
|
||||||
stmts.forEach { translate(it) }
|
stmts.forEach { translate(it) }
|
||||||
subroutine.forEach { translateSubroutine(it as Subroutine) }
|
subroutine.forEach { translateSubroutine(it as Subroutine) }
|
||||||
|
|
||||||
if(!options.dontReinitGlobals) {
|
if(!options.dontReinitGlobals) {
|
||||||
// generate subroutine to initialize block-level (global) variables
|
// generate subroutine to initialize block-level (global) variables
|
||||||
val initializers = blockVariableInitializers.getValue(block)
|
|
||||||
if (initializers.isNotEmpty()) {
|
if (initializers.isNotEmpty()) {
|
||||||
out("prog8_init_vars\t.proc\n")
|
out("prog8_init_vars\t.proc\n")
|
||||||
initializers.forEach { assign -> translate(assign) }
|
initializers.forEach { assign -> translate(assign) }
|
||||||
@ -1059,10 +1053,6 @@ class AsmGen6502(internal val program: Program,
|
|||||||
// (they've been inlined at the call site, remember?)
|
// (they've been inlined at the call site, remember?)
|
||||||
onlyVariables = true
|
onlyVariables = true
|
||||||
}
|
}
|
||||||
else if(sub.amountOfRtsInAsm()==0) {
|
|
||||||
// make sure the NOT INLINED subroutine actually does a rts at the end
|
|
||||||
sub.statements.add(Return(null, Position.DUMMY))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out("")
|
out("")
|
||||||
|
@ -49,12 +49,27 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co
|
|||||||
val subs = block.statements.filterIsInstance<Subroutine>()
|
val subs = block.statements.filterIsInstance<Subroutine>()
|
||||||
block.statements.removeAll(subs)
|
block.statements.removeAll(subs)
|
||||||
block.statements.addAll(subs)
|
block.statements.addAll(subs)
|
||||||
|
|
||||||
|
// adjust global variables initialization
|
||||||
|
if(options.dontReinitGlobals) {
|
||||||
|
block.statements.asSequence().filterIsInstance<VarDecl>().forEach {
|
||||||
|
if(it.type==VarDeclType.VAR) {
|
||||||
|
it.zeropage = ZeropageWish.NOT_IN_ZEROPAGE
|
||||||
|
it.findInitializer(program)?.let { initializer ->
|
||||||
|
it.value = initializer.value // put the init value back into the vardecl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return noModifications
|
return noModifications
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
|
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
|
||||||
if(decl.type== VarDeclType.VAR && decl.value != null && decl.datatype in NumericDatatypes)
|
if(!options.dontReinitGlobals) {
|
||||||
|
if (decl.type == VarDeclType.VAR && decl.value != null && decl.datatype in NumericDatatypes)
|
||||||
throw FatalAstException("vardecls for variables, with initial numerical value, should have been rewritten as plain vardecl + assignment $decl")
|
throw FatalAstException("vardecls for variables, with initial numerical value, should have been rewritten as plain vardecl + assignment $decl")
|
||||||
|
}
|
||||||
rememberSubroutineVar(decl)
|
rememberSubroutineVar(decl)
|
||||||
return noModifications
|
return noModifications
|
||||||
}
|
}
|
||||||
@ -116,6 +131,7 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun after(subroutine: Subroutine, parent: Node): Iterable<IAstModification> {
|
override fun after(subroutine: Subroutine, parent: Node): Iterable<IAstModification> {
|
||||||
|
val mods = mutableListOf<IAstModification>()
|
||||||
val firstDeclarations = mutableMapOf<String, VarDecl>()
|
val firstDeclarations = mutableMapOf<String, VarDecl>()
|
||||||
val rememberedSubroutineVars = subroutineVariables.getOrDefault(subroutine, mutableListOf())
|
val rememberedSubroutineVars = subroutineVariables.getOrDefault(subroutine, mutableListOf())
|
||||||
for(decl in rememberedSubroutineVars) {
|
for(decl in rememberedSubroutineVars) {
|
||||||
@ -130,9 +146,8 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co
|
|||||||
|
|
||||||
// add the implicit return statement at the end (if it's not there yet), but only if it's not a kernal routine.
|
// add the implicit return statement at the end (if it's not there yet), but only if it's not a kernal routine.
|
||||||
// and if an assembly block doesn't contain a rts/rti, and some other situations.
|
// and if an assembly block doesn't contain a rts/rti, and some other situations.
|
||||||
val mods = mutableListOf<IAstModification>()
|
|
||||||
val returnStmt = Return(null, subroutine.position)
|
val returnStmt = Return(null, subroutine.position)
|
||||||
if (subroutine.asmAddress == null && !subroutine.inline) {
|
if (!subroutine.isAsmSubroutine && !subroutine.inline) {
|
||||||
if(subroutine.statements.isEmpty() ||
|
if(subroutine.statements.isEmpty() ||
|
||||||
(subroutine.amountOfRtsInAsm() == 0
|
(subroutine.amountOfRtsInAsm() == 0
|
||||||
&& subroutine.statements.lastOrNull { it !is VarDecl } !is Return
|
&& subroutine.statements.lastOrNull { it !is VarDecl } !is Return
|
||||||
@ -155,6 +170,13 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co
|
|||||||
mods += IAstModification.InsertAfter(outerStatements[subroutineStmtIdx - 1], returnStmt, outerScope)
|
mods += IAstModification.InsertAfter(outerStatements[subroutineStmtIdx - 1], returnStmt, outerScope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (subroutine.inline && subroutine.isAsmSubroutine && subroutine.amountOfRtsInAsm() == 0) {
|
||||||
|
// make sure the NOT INLINED asm subroutine actually has a rts at the end
|
||||||
|
// (non-asm routines get a Return statement as needed, above)
|
||||||
|
mods += IAstModification.InsertLast(InlineAssembly(" rts\n", Position.DUMMY), subroutine)
|
||||||
|
}
|
||||||
|
|
||||||
return mods
|
return mods
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,14 +23,8 @@ Future Things and Ideas
|
|||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
Ast modifications done in AsmGen, that should be done BEFORE calling asmgen (so that it doesn't have to modify the Ast any longer):
|
Ast modifications done in AsmGen, that should be done BEFORE calling asmgen (so that it doesn't have to modify the Ast any longer):
|
||||||
|
|
||||||
- translateSubroutine:
|
- block2asm: after vardecls2asm it clears the vardecl.value of all variables (why?)
|
||||||
if subroutine marked as inline but optimizations are disabled, make sure the NOT INLINED subroutine actually has a Return statement at the end
|
- block2asm: removes init-assignments to no longer output the initialization assignments as regular statements (is done separately in block initialization routine)
|
||||||
|
|
||||||
- block2asm:
|
|
||||||
if(options.dontReinitGlobals) -> currently modifies the zeropage and init value of vardecl's.
|
|
||||||
it removes init-assignments to no longer output the initialization assignments as regular statements (is done separately in block initialization routine)
|
|
||||||
after vardecls2asm it clears the vardecl.value of all variables (why?)
|
|
||||||
|
|
||||||
- Maybe don't rely on vardecls at all any longer but figure out the variable allocations (including ZP allocations) beforehand
|
- Maybe don't rely on vardecls at all any longer but figure out the variable allocations (including ZP allocations) beforehand
|
||||||
and pass that via a new datastructure to asmgen? So that asmgen is no longer tasked with doing the allocations.
|
and pass that via a new datastructure to asmgen? So that asmgen is no longer tasked with doing the allocations.
|
||||||
This could perhaps make it easer for the codegen as well to deal with sections, if any, in the future.
|
This could perhaps make it easer for the codegen as well to deal with sections, if any, in the future.
|
||||||
|
@ -1,9 +1,23 @@
|
|||||||
%import textio
|
%import textio
|
||||||
|
%zeropage basicsafe
|
||||||
|
|
||||||
main {
|
main {
|
||||||
|
ubyte mainglobal1 = 10
|
||||||
|
ubyte mainglobal2 = 20
|
||||||
|
ubyte mainglobal3 = 30
|
||||||
|
ubyte mainglobal4 = 40
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
txt.print("ok")
|
ubyte startval1 = 100
|
||||||
|
ubyte startval2 = 110
|
||||||
|
ubyte startval3 = 120
|
||||||
|
ubyte startval4 = 130
|
||||||
|
|
||||||
|
txt.print_ub(mainglobal1)
|
||||||
txt.nl()
|
txt.nl()
|
||||||
sys.wait(999)
|
txt.print_ub(startval1)
|
||||||
|
txt.nl()
|
||||||
|
startval1++
|
||||||
|
mainglobal1++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user