From 77de99b3837ca0625375234807b63e15c2015933 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 6 Feb 2022 02:40:04 +0100 Subject: [PATCH] rts-check for non-inlined subroutines + var init adjustment when noreinit, moved out of codegen --- .../src/prog8/codegen/cpu6502/AsmGen6502.kt | 32 +++++++------------ .../astprocessing/BeforeAsmAstChanger.kt | 30 ++++++++++++++--- docs/source/todo.rst | 10 ++---- examples/test.p8 | 18 +++++++++-- 4 files changed, 55 insertions(+), 35 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen6502.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen6502.kt index 8403ea3ef..f36200561 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen6502.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen6502.kt @@ -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().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().forEach { + statements.asSequence().filterIsInstance().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("") diff --git a/compiler/src/prog8/compiler/astprocessing/BeforeAsmAstChanger.kt b/compiler/src/prog8/compiler/astprocessing/BeforeAsmAstChanger.kt index 2e4f64360..dc591f57f 100644 --- a/compiler/src/prog8/compiler/astprocessing/BeforeAsmAstChanger.kt +++ b/compiler/src/prog8/compiler/astprocessing/BeforeAsmAstChanger.kt @@ -49,12 +49,27 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co val subs = block.statements.filterIsInstance() block.statements.removeAll(subs) block.statements.addAll(subs) + + // adjust global variables initialization + if(options.dontReinitGlobals) { + block.statements.asSequence().filterIsInstance().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 { - 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 { + val mods = mutableListOf() val firstDeclarations = mutableMapOf() 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() 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 } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 3b5ab9112..020a7a0fb 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -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. diff --git a/examples/test.p8 b/examples/test.p8 index 6dc232a4a..96545c4b6 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -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++ } }