fix code generation for "return <void function call>"

This commit is contained in:
Irmen de Jong committed 2026-09-17 22:39:53 +02:00
1 parent 7f3b2e8aa6
commit ba76fbfe85
4 files changed
+81 -1

No files matched your search

@@ -1982,6 +1982,16 @@ $repeatLabel""")
return
}
if(sub.signature.returns.isEmpty()) {
// a void subroutine may return the result of a void function call (e.g. "return voidfunc(args)"):
// perform the call for its side effects, then return
val fcall = ret.children.single() as? PtFunctionCall
?: throw AssemblyError("void subroutine can only return the result of a void function call ${ret.position}")
functioncallAsmGen.translateFunctionCall(fcall)
out(" rts")
return
}
val returnDt = sub.signature.returns.single()
if (returnDt.isNumericOrBool || returnDt.isPointer) {
assignExpressionToRegister(returnvalue, returnRegs.single().first.registerOrPair!!, returnDt.isSigned)
@@ -1895,7 +1895,14 @@ class IRCodeGen(
}
val value = ret.children.singleOrNull()
if(value==null) {
if(ret.numReturnValues()==0) {
// a void subroutine may return the result of a void function call (e.g. "return voidfunc(args)"):
// translate the call for its side effects, then return void
val callValue = value as? PtExpression
if(callValue!=null)
result += expressionEval.translateExpression(callValue).chunks
addInstr(result, IRInstructions.returnVoid(), null)
} else if(value==null) {
addInstr(result, IRInstructions.returnVoid(), null)
} else {
value as PtExpression
+33
View File
@@ -13,6 +13,39 @@ class TestM68k : FunSpec({
val outputDir = tempdir().toPath()
test("void subroutine returning the result of a void function call compiles") {
// Regression test: "return voidfunc(args)" inside a void subroutine is valid Prog8.
// The optimizer only rewrites this to "voidfunc(args); return" when it can inline the
// caller, so in general it reaches the IR codegen as a Return whose value expression is a
// void function call. The m68k/IR backend must translate the call for its side effects and
// then return void instead of dying with 'no IR datatype for undefined'.
val src = """
main {
ubyte flag
sub start() {
flag = 1
benchmark(flag)
}
sub benchmark(ubyte f) {
when f {
1 -> return helper(f)
else -> {
}
}
}
sub helper(ubyte x) {
}
}
"""
compileText(Amiga500Target(), optimize = false, src, outputDir, writeAssembly = true, assemble = false) shouldNotBe null
compileText(Amiga500Target(), optimize = true, src, outputDir, writeAssembly = true, assemble = false) shouldNotBe null
compileText(Qemu68kTarget(), optimize = false, src, outputDir, writeAssembly = true, assemble = false) shouldNotBe null
compileText(Qemu68kTarget(), optimize = true, src, outputDir, writeAssembly = true, assemble = false) shouldNotBe null
}
test("module sub returning uword computed from a long expression assembles on qemu68k") {
// Regression test for a m68k backend bug: a module-level sub whose return
// type is uword, but whose return expression is a 'long' value cast to uword,
@@ -24,6 +24,36 @@ class TestVariousCodeGen: FunSpec({
val outputDir = tempdir().toPath()
test("void subroutine returning the result of a void function call compiles on 6502") {
// Regression test: "return voidfunc(args)" inside a void subroutine is valid Prog8.
// The optimizer only rewrites this to "voidfunc(args); return" when it can inline the
// caller, so in general it reaches the 6502 codegen as a Return whose value expression is a
// void function call. The 6502 backend must call it for its side effects and then return.
val text = """
main {
ubyte flag
sub start() {
flag = 1
benchmark(flag)
}
sub benchmark(ubyte f) {
when f {
1 -> return helper(f)
else -> {
}
}
}
sub helper(ubyte x) {
}
}
"""
compileText(Cx16Target(), false, text, outputDir, writeAssembly = true) shouldNotBe null
compileText(Cx16Target(), true, text, outputDir, writeAssembly = true) shouldNotBe null
}
test("nested scoping") {
val text="""
main {