mirror of
https://github.com/irmen/prog8.git
synced 2024-09-30 00:55:52 +00:00
fix rts in empty asmsub
This commit is contained in:
parent
77de99b383
commit
8ae3bad6f7
@ -279,7 +279,7 @@ class AsmGen6502(internal val program: Program,
|
|||||||
|
|
||||||
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 // TODO why is this done?
|
it.value=null // make sure every var has no init value anymore (could be set due to 'noreinit' option) because initialization is done via explicit assignment
|
||||||
}
|
}
|
||||||
|
|
||||||
out("\n; subroutines in this block")
|
out("\n; subroutines in this block")
|
||||||
|
@ -96,8 +96,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
|||||||
// NOTE: *if* there is a return statement, it will be the only one, and the very last statement of the subroutine
|
// NOTE: *if* there is a return statement, it will be the only one, and the very last statement of the subroutine
|
||||||
// (this condition has been enforced by an ast check earlier)
|
// (this condition has been enforced by an ast check earlier)
|
||||||
asmgen.out(" \t; inlined routine follows: ${sub.name}")
|
asmgen.out(" \t; inlined routine follows: ${sub.name}")
|
||||||
val assembly = sub.statements.single() as InlineAssembly
|
sub.statements.forEach { asmgen.translate(it as InlineAssembly) }
|
||||||
asmgen.translate(assembly)
|
|
||||||
asmgen.out(" \t; inlined routine end: ${sub.name}")
|
asmgen.out(" \t; inlined routine end: ${sub.name}")
|
||||||
} else {
|
} else {
|
||||||
asmgen.out(" jsr $subAsmName")
|
asmgen.out(" jsr $subAsmName")
|
||||||
|
@ -20,33 +20,34 @@ class CX16Zeropage(options: CompilationOptions) : Zeropage(options) {
|
|||||||
|
|
||||||
// the addresses 0x02 to 0x21 (inclusive) are taken for sixteen virtual 16-bit api registers.
|
// the addresses 0x02 to 0x21 (inclusive) are taken for sixteen virtual 16-bit api registers.
|
||||||
|
|
||||||
when (options.zeropage) {
|
synchronized(this) {
|
||||||
ZeropageType.FULL -> {
|
when (options.zeropage) {
|
||||||
free.addAll(0x22u..0xffu)
|
ZeropageType.FULL -> {
|
||||||
|
free.addAll(0x22u..0xffu)
|
||||||
|
}
|
||||||
|
ZeropageType.KERNALSAFE -> {
|
||||||
|
free.addAll(0x22u..0x7fu)
|
||||||
|
free.addAll(0xa9u..0xffu)
|
||||||
|
}
|
||||||
|
ZeropageType.BASICSAFE -> {
|
||||||
|
free.addAll(0x22u..0x7fu)
|
||||||
|
}
|
||||||
|
ZeropageType.DONTUSE -> {
|
||||||
|
free.clear() // don't use zeropage at all
|
||||||
|
}
|
||||||
|
else -> throw InternalCompilerException("for this machine target, zero page type 'floatsafe' is not available. ${options.zeropage}")
|
||||||
}
|
}
|
||||||
ZeropageType.KERNALSAFE -> {
|
|
||||||
free.addAll(0x22u..0x7fu)
|
removeReservedFromFreePool()
|
||||||
free.addAll(0xa9u..0xffu)
|
|
||||||
|
for(reg in 0..15) {
|
||||||
|
allocatedVariables[listOf("cx16", "r${reg}")] = (2+reg*2).toUInt() to (DataType.UWORD to 2) // cx16.r0 .. cx16.r15
|
||||||
|
allocatedVariables[listOf("cx16", "r${reg}s")] = (2+reg*2).toUInt() to (DataType.WORD to 2) // cx16.r0s .. cx16.r15s
|
||||||
|
allocatedVariables[listOf("cx16", "r${reg}L")] = (2+reg*2).toUInt() to (DataType.UBYTE to 1) // cx16.r0L .. cx16.r15L
|
||||||
|
allocatedVariables[listOf("cx16", "r${reg}H")] = (3+reg*2).toUInt() to (DataType.UBYTE to 1) // cx16.r0H .. cx16.r15H
|
||||||
|
allocatedVariables[listOf("cx16", "r${reg}sL")] = (2+reg*2).toUInt() to (DataType.BYTE to 1) // cx16.r0sL .. cx16.r15sL
|
||||||
|
allocatedVariables[listOf("cx16", "r${reg}sH")] = (3+reg*2).toUInt() to (DataType.BYTE to 1) // cx16.r0sH .. cx16.r15sH
|
||||||
}
|
}
|
||||||
ZeropageType.BASICSAFE -> {
|
|
||||||
free.addAll(0x22u..0x7fu)
|
|
||||||
}
|
|
||||||
ZeropageType.DONTUSE -> {
|
|
||||||
free.clear() // don't use zeropage at all
|
|
||||||
}
|
|
||||||
else -> throw InternalCompilerException("for this machine target, zero page type 'floatsafe' is not available. ${options.zeropage}")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
removeReservedFromFreePool()
|
|
||||||
|
|
||||||
for(reg in 0..15) {
|
|
||||||
allocatedVariables[listOf("cx16", "r${reg}")] = (2+reg*2).toUInt() to (DataType.UWORD to 2) // cx16.r0 .. cx16.r15
|
|
||||||
allocatedVariables[listOf("cx16", "r${reg}s")] = (2+reg*2).toUInt() to (DataType.WORD to 2) // cx16.r0s .. cx16.r15s
|
|
||||||
allocatedVariables[listOf("cx16", "r${reg}L")] = (2+reg*2).toUInt() to (DataType.UBYTE to 1) // cx16.r0L .. cx16.r15L
|
|
||||||
allocatedVariables[listOf("cx16", "r${reg}H")] = (3+reg*2).toUInt() to (DataType.UBYTE to 1) // cx16.r0H .. cx16.r15H
|
|
||||||
allocatedVariables[listOf("cx16", "r${reg}sL")] = (2+reg*2).toUInt() to (DataType.BYTE to 1) // cx16.r0sL .. cx16.r15sL
|
|
||||||
allocatedVariables[listOf("cx16", "r${reg}sH")] = (3+reg*2).toUInt() to (DataType.BYTE to 1) // cx16.r0sH .. cx16.r15sH
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -146,12 +146,13 @@ 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 returnStmt = Return(null, subroutine.position)
|
|
||||||
if (!subroutine.isAsmSubroutine && !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
|
||||||
&& subroutine.statements.last() !is Subroutine)) {
|
&& subroutine.statements.last() !is Subroutine
|
||||||
|
&& subroutine.statements.last() !is Return)) {
|
||||||
|
val returnStmt = Return(null, subroutine.position)
|
||||||
mods += IAstModification.InsertLast(returnStmt, subroutine)
|
mods += IAstModification.InsertLast(returnStmt, subroutine)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -167,14 +168,17 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co
|
|||||||
&& prevStmt !is Subroutine
|
&& prevStmt !is Subroutine
|
||||||
&& prevStmt !is Return
|
&& prevStmt !is Return
|
||||||
) {
|
) {
|
||||||
|
val returnStmt = Return(null, subroutine.position)
|
||||||
mods += IAstModification.InsertAfter(outerStatements[subroutineStmtIdx - 1], returnStmt, outerScope)
|
mods += IAstModification.InsertAfter(outerStatements[subroutineStmtIdx - 1], returnStmt, outerScope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subroutine.inline && subroutine.isAsmSubroutine && subroutine.amountOfRtsInAsm() == 0) {
|
if (!subroutine.inline) {
|
||||||
// make sure the NOT INLINED asm subroutine actually has a rts at the end
|
if (subroutine.isAsmSubroutine && subroutine.asmAddress==null && subroutine.amountOfRtsInAsm() == 0) {
|
||||||
// (non-asm routines get a Return statement as needed, above)
|
// make sure the NOT INLINED asm subroutine actually has a rts at the end
|
||||||
mods += IAstModification.InsertLast(InlineAssembly(" rts\n", Position.DUMMY), subroutine)
|
// (non-asm routines get a Return statement as needed, above)
|
||||||
|
mods += IAstModification.InsertLast(InlineAssembly(" rts\n", Position.DUMMY), subroutine)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return mods
|
return mods
|
||||||
|
@ -85,6 +85,7 @@ class TestSubroutines: FunSpec({
|
|||||||
func("text")
|
func("text")
|
||||||
func(text)
|
func(text)
|
||||||
func($2000)
|
func($2000)
|
||||||
|
emptysub()
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub asmfunc(str thing @AY) {
|
asmsub asmfunc(str thing @AY) {
|
||||||
@ -94,6 +95,9 @@ class TestSubroutines: FunSpec({
|
|||||||
uword t2 = thing as uword
|
uword t2 = thing as uword
|
||||||
asmfunc(thing)
|
asmfunc(thing)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub emptysub() {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
val result = compileText(C64Target, false, text, writeAssembly = true).assertSuccess()
|
val result = compileText(C64Target, false, text, writeAssembly = true).assertSuccess()
|
||||||
@ -101,14 +105,16 @@ class TestSubroutines: FunSpec({
|
|||||||
val mainBlock = module.statements.single() as Block
|
val mainBlock = module.statements.single() as Block
|
||||||
val asmfunc = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="asmfunc"}
|
val asmfunc = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="asmfunc"}
|
||||||
val func = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="func"}
|
val func = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="func"}
|
||||||
|
val emptysub = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="emptysub"}
|
||||||
asmfunc.isAsmSubroutine shouldBe true
|
asmfunc.isAsmSubroutine shouldBe true
|
||||||
asmfunc.statements.single() shouldBe instanceOf<Return>()
|
asmfunc.statements.single() shouldBe instanceOf<InlineAssembly>()
|
||||||
|
(asmfunc.statements.single() as InlineAssembly).assembly.trim() shouldBe "rts"
|
||||||
|
asmfunc.amountOfRtsInAsm() shouldBe 1
|
||||||
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
|
||||||
func.parameters.single().type shouldBe DataType.UWORD
|
func.parameters.single().type shouldBe DataType.UWORD
|
||||||
}
|
}
|
||||||
asmfunc.statements.last() shouldBe instanceOf<Return>()
|
|
||||||
|
|
||||||
func.statements.size shouldBe 5
|
func.statements.size shouldBe 5
|
||||||
func.statements[4] shouldBe instanceOf<Return>()
|
func.statements[4] shouldBe instanceOf<Return>()
|
||||||
@ -129,6 +135,9 @@ class TestSubroutines: FunSpec({
|
|||||||
call.args.single() shouldBe instanceOf<IdentifierReference>()
|
call.args.single() shouldBe instanceOf<IdentifierReference>()
|
||||||
}
|
}
|
||||||
(call.args.single() as IdentifierReference).nameInSource.single() shouldBe "thing"
|
(call.args.single() as IdentifierReference).nameInSource.single() shouldBe "thing"
|
||||||
|
|
||||||
|
emptysub.statements.size shouldBe 1
|
||||||
|
emptysub.statements.single() shouldBe instanceOf<Return>()
|
||||||
}
|
}
|
||||||
|
|
||||||
test("ubyte[] array parameters") {
|
test("ubyte[] array parameters") {
|
||||||
|
@ -25,10 +25,12 @@ abstract class Zeropage(protected val options: CompilationOptions) {
|
|||||||
val free = mutableListOf<UInt>() // subclasses must set this to the appropriate free locations.
|
val free = mutableListOf<UInt>() // subclasses must set this to the appropriate free locations.
|
||||||
|
|
||||||
fun removeReservedFromFreePool() {
|
fun removeReservedFromFreePool() {
|
||||||
for (reserved in options.zpReserved)
|
synchronized(this) {
|
||||||
reserve(reserved)
|
for (reserved in options.zpReserved)
|
||||||
|
reserve(reserved)
|
||||||
|
|
||||||
free.removeAll(setOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_W1, SCRATCH_W1 + 1u, SCRATCH_W2, SCRATCH_W2 + 1u))
|
free.removeAll(setOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_W1, SCRATCH_W1 + 1u, SCRATCH_W2, SCRATCH_W2 + 1u))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun availableBytes() = if(options.zeropage== ZeropageType.DONTUSE) 0 else free.size
|
fun availableBytes() = if(options.zeropage== ZeropageType.DONTUSE) 0 else free.size
|
||||||
|
@ -23,8 +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):
|
||||||
|
|
||||||
- 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)
|
- block2asm: removes init-assignments to no longer output the initialization assignments as regular statements (is done separately in block initialization routine)
|
||||||
|
- block2asm: after vardecls2asm it clears the vardecl.value of all variables
|
||||||
- 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.
|
||||||
|
@ -17,7 +17,18 @@ main {
|
|||||||
txt.nl()
|
txt.nl()
|
||||||
txt.print_ub(startval1)
|
txt.print_ub(startval1)
|
||||||
txt.nl()
|
txt.nl()
|
||||||
|
derp()
|
||||||
|
derp()
|
||||||
|
foobar()
|
||||||
startval1++
|
startval1++
|
||||||
mainglobal1++
|
mainglobal1++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
asmsub derp() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub foobar() {
|
||||||
|
txt.print("foobar\n")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user