mirror of
https://github.com/irmen/prog8.git
synced 2024-11-25 19:31:36 +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) {
|
||||
// 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}' ----")
|
||||
if(block.address!=null)
|
||||
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"))
|
||||
|
||||
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)
|
||||
zeropagevars2asm(block.statements, block)
|
||||
memdefs2asm(block.statements, block)
|
||||
vardecls2asm(block.statements, block)
|
||||
zeropagevars2asm(statements, block)
|
||||
memdefs2asm(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)
|
||||
it.value=null
|
||||
it.value=null // TODO why is this done?
|
||||
}
|
||||
|
||||
out("\n; subroutines in this block")
|
||||
|
||||
// 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) }
|
||||
subroutine.forEach { translateSubroutine(it as Subroutine) }
|
||||
|
||||
if(!options.dontReinitGlobals) {
|
||||
// generate subroutine to initialize block-level (global) variables
|
||||
val initializers = blockVariableInitializers.getValue(block)
|
||||
if (initializers.isNotEmpty()) {
|
||||
out("prog8_init_vars\t.proc\n")
|
||||
initializers.forEach { assign -> translate(assign) }
|
||||
@ -1059,10 +1053,6 @@ class AsmGen6502(internal val program: Program,
|
||||
// (they've been inlined at the call site, remember?)
|
||||
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("")
|
||||
|
@ -49,12 +49,27 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co
|
||||
val subs = block.statements.filterIsInstance<Subroutine>()
|
||||
block.statements.removeAll(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
|
||||
}
|
||||
|
||||
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
|
||||
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")
|
||||
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")
|
||||
}
|
||||
rememberSubroutineVar(decl)
|
||||
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> {
|
||||
val mods = mutableListOf<IAstModification>()
|
||||
val firstDeclarations = mutableMapOf<String, VarDecl>()
|
||||
val rememberedSubroutineVars = subroutineVariables.getOrDefault(subroutine, mutableListOf())
|
||||
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.
|
||||
// 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)
|
||||
if (subroutine.asmAddress == null && !subroutine.inline) {
|
||||
if (!subroutine.isAsmSubroutine && !subroutine.inline) {
|
||||
if(subroutine.statements.isEmpty() ||
|
||||
(subroutine.amountOfRtsInAsm() == 0
|
||||
&& 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)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -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):
|
||||
|
||||
- translateSubroutine:
|
||||
if subroutine marked as inline but optimizations are disabled, make sure the NOT INLINED subroutine actually has a Return statement at the end
|
||||
|
||||
- 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?)
|
||||
|
||||
- block2asm: after vardecls2asm it clears the vardecl.value of all variables (why?)
|
||||
- block2asm: removes init-assignments to no longer output the initialization assignments as regular statements (is done separately in block initialization routine)
|
||||
- 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.
|
||||
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
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
||||
ubyte mainglobal1 = 10
|
||||
ubyte mainglobal2 = 20
|
||||
ubyte mainglobal3 = 30
|
||||
ubyte mainglobal4 = 40
|
||||
|
||||
sub start() {
|
||||
txt.print("ok")
|
||||
ubyte startval1 = 100
|
||||
ubyte startval2 = 110
|
||||
ubyte startval3 = 120
|
||||
ubyte startval4 = 130
|
||||
|
||||
txt.print_ub(mainglobal1)
|
||||
txt.nl()
|
||||
sys.wait(999)
|
||||
txt.print_ub(startval1)
|
||||
txt.nl()
|
||||
startval1++
|
||||
mainglobal1++
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user