mirror of
https://github.com/irmen/prog8.git
synced 2024-07-05 22:29:04 +00:00
make sure X register is also saved if needed when GoSub is used
This commit is contained in:
parent
66d5490702
commit
f5ebf79e71
@ -854,9 +854,15 @@ class AsmGen(private val program: Program,
|
|||||||
internal fun saveXbeforeCall(functionCall: IFunctionCall) =
|
internal fun saveXbeforeCall(functionCall: IFunctionCall) =
|
||||||
functioncallAsmGen.saveXbeforeCall(functionCall)
|
functioncallAsmGen.saveXbeforeCall(functionCall)
|
||||||
|
|
||||||
|
internal fun saveXbeforeCall(gosub: GoSub) =
|
||||||
|
functioncallAsmGen.saveXbeforeCall(gosub)
|
||||||
|
|
||||||
internal fun restoreXafterCall(functionCall: IFunctionCall) =
|
internal fun restoreXafterCall(functionCall: IFunctionCall) =
|
||||||
functioncallAsmGen.restoreXafterCall(functionCall)
|
functioncallAsmGen.restoreXafterCall(functionCall)
|
||||||
|
|
||||||
|
internal fun restoreXafterCall(gosub: GoSub) =
|
||||||
|
functioncallAsmGen.restoreXafterCall(gosub)
|
||||||
|
|
||||||
internal fun translateNormalAssignment(assign: AsmAssignment) =
|
internal fun translateNormalAssignment(assign: AsmAssignment) =
|
||||||
assignmentAsmGen.translateNormalAssignment(assign)
|
assignmentAsmGen.translateNormalAssignment(assign)
|
||||||
|
|
||||||
@ -1380,8 +1386,11 @@ $label nop""")
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun translate(jump: Jump) {
|
private fun translate(jump: Jump) {
|
||||||
if(jump.isGosub)
|
if(jump.isGosub) {
|
||||||
|
saveXbeforeCall(jump as GoSub)
|
||||||
out(" jsr ${getJumpTarget(jump)}")
|
out(" jsr ${getJumpTarget(jump)}")
|
||||||
|
restoreXafterCall(jump as GoSub)
|
||||||
|
}
|
||||||
else
|
else
|
||||||
jmp(getJumpTarget(jump))
|
jmp(getJumpTarget(jump))
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,17 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun saveXbeforeCall(gosub: GoSub) {
|
||||||
|
val sub = gosub.identifier?.targetSubroutine(program)
|
||||||
|
if(sub?.shouldSaveX()==true) {
|
||||||
|
val regSaveOnStack = sub.asmAddress==null // rom-routines don't require registers to be saved on stack, normal subroutines do because they can contain nested calls
|
||||||
|
if(regSaveOnStack)
|
||||||
|
asmgen.saveRegisterStack(CpuRegister.X, sub.shouldKeepA().saveOnEntry)
|
||||||
|
else
|
||||||
|
asmgen.saveRegisterLocal(CpuRegister.X, gosub.definingSubroutine!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal fun restoreXafterCall(stmt: IFunctionCall) {
|
internal fun restoreXafterCall(stmt: IFunctionCall) {
|
||||||
val sub = stmt.target.targetSubroutine(program) ?: throw AssemblyError("undefined subroutine ${stmt.target}")
|
val sub = stmt.target.targetSubroutine(program) ?: throw AssemblyError("undefined subroutine ${stmt.target}")
|
||||||
if(sub.shouldSaveX()) {
|
if(sub.shouldSaveX()) {
|
||||||
@ -45,6 +56,17 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun restoreXafterCall(gosub: GoSub) {
|
||||||
|
val sub = gosub.identifier?.targetSubroutine(program)
|
||||||
|
if(sub?.shouldSaveX()==true) {
|
||||||
|
val regSaveOnStack = sub.asmAddress==null // rom-routines don't require registers to be saved on stack, normal subroutines do because they can contain nested calls
|
||||||
|
if(regSaveOnStack)
|
||||||
|
asmgen.restoreRegisterStack(CpuRegister.X, sub.shouldKeepA().saveOnReturn)
|
||||||
|
else
|
||||||
|
asmgen.restoreRegisterLocal(CpuRegister.X)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal fun translateFunctionCall(call: IFunctionCall, isExpression: Boolean) {
|
internal fun translateFunctionCall(call: IFunctionCall, isExpression: Boolean) {
|
||||||
// Output only the code to set up the parameters and perform the actual call
|
// Output only the code to set up the parameters and perform the actual call
|
||||||
// NOTE: does NOT output the code to deal with the result values!
|
// NOTE: does NOT output the code to deal with the result values!
|
||||||
|
@ -362,30 +362,43 @@ internal class StatementReorderer(val program: Program, val errors: IErrorReport
|
|||||||
override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
|
override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
|
||||||
val function = functionCallStatement.target.targetStatement(program)!!
|
val function = functionCallStatement.target.targetStatement(program)!!
|
||||||
checkUnusedReturnValues(functionCallStatement, function, program, errors)
|
checkUnusedReturnValues(functionCallStatement, function, program, errors)
|
||||||
|
|
||||||
if(function is Subroutine) {
|
if(function is Subroutine) {
|
||||||
if(function.isAsmSubroutine)
|
if(function.inline)
|
||||||
return noModifications // TODO new logic for passing arguments to asmsub
|
return noModifications
|
||||||
|
return if(function.isAsmSubroutine)
|
||||||
// regular subroutine call: replace the call with assigning the params directly + actual call with a GoSub
|
replaceCallAsmSubStatementWithGosub(function, functionCallStatement, parent)
|
||||||
require(function.asmParameterRegisters.isEmpty())
|
else
|
||||||
val assignParams =
|
replaceCallSubStatementWithGosub(function, functionCallStatement, parent)
|
||||||
function.parameters.zip(functionCallStatement.args).map {
|
|
||||||
var argumentValue = it.second
|
|
||||||
val paramIdentifier = IdentifierReference(function.scopedName + it.first.name, argumentValue.position)
|
|
||||||
val argDt = argumentValue.inferType(program).getOrElse { throw FatalAstException("invalid dt") }
|
|
||||||
if(argDt in ArrayDatatypes) {
|
|
||||||
// pass the address of the array instead
|
|
||||||
argumentValue = AddressOf(argumentValue as IdentifierReference, argumentValue.position)
|
|
||||||
}
|
|
||||||
Assignment(AssignTarget(paramIdentifier, null, null, argumentValue.position), argumentValue, argumentValue.position)
|
|
||||||
}
|
|
||||||
return assignParams.map { IAstModification.InsertBefore(functionCallStatement, it, parent as IStatementContainer) } +
|
|
||||||
IAstModification.ReplaceNode(
|
|
||||||
functionCallStatement as Node,
|
|
||||||
GoSub(null, functionCallStatement.target, null, (functionCallStatement as Node).position),
|
|
||||||
parent)
|
|
||||||
}
|
}
|
||||||
return noModifications
|
return noModifications
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun replaceCallSubStatementWithGosub(function: Subroutine, call: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
|
||||||
|
val assignParams =
|
||||||
|
function.parameters.zip(call.args).map {
|
||||||
|
var argumentValue = it.second
|
||||||
|
val paramIdentifier = IdentifierReference(function.scopedName + it.first.name, argumentValue.position)
|
||||||
|
val argDt = argumentValue.inferType(program).getOrElse { throw FatalAstException("invalid dt") }
|
||||||
|
if(argDt in ArrayDatatypes) {
|
||||||
|
// pass the address of the array instead
|
||||||
|
argumentValue = AddressOf(argumentValue as IdentifierReference, argumentValue.position)
|
||||||
|
}
|
||||||
|
Assignment(AssignTarget(paramIdentifier, null, null, argumentValue.position), argumentValue, argumentValue.position)
|
||||||
|
}
|
||||||
|
return assignParams.map { IAstModification.InsertBefore(call, it, parent as IStatementContainer) } +
|
||||||
|
IAstModification.ReplaceNode(
|
||||||
|
call,
|
||||||
|
GoSub(null, call.target, null, call.position),
|
||||||
|
parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun replaceCallAsmSubStatementWithGosub(function: Subroutine, call: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
|
||||||
|
if(function.parameters.isEmpty()) {
|
||||||
|
// 0 params -> just GoSub
|
||||||
|
return listOf(IAstModification.ReplaceNode(call, GoSub(null, call.target, null, call.position), parent))
|
||||||
|
} else {
|
||||||
|
// TODO new logic for passing arguments to asmsub: >0 params -> not sure yet how to do this....
|
||||||
|
return noModifications
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,48 +5,21 @@ main {
|
|||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
|
|
||||||
uword xx
|
ubyte @shared xx=20
|
||||||
ubyte yy = 33
|
ubyte @shared yy=10
|
||||||
xx=xx-routine(2)
|
|
||||||
; concat_string(random_name())
|
|
||||||
|
|
||||||
; ubyte xx=20
|
routine2()
|
||||||
; ubyte yy=10
|
routine2()
|
||||||
;
|
routine2()
|
||||||
; routine(33)
|
|
||||||
; txt.setcc(xx+1, yy+3, 81, 7)
|
|
||||||
; txt.setcc(xx+2, yy+2, 81, 7)
|
|
||||||
; txt.setcc(xx+3, yy+1, 81, 7)
|
|
||||||
;
|
|
||||||
; ; TODO test new param load with subroutine call in expression:
|
|
||||||
; ; yy=routine(33)
|
|
||||||
;
|
|
||||||
; main.routine.r1arg = 20
|
|
||||||
; ; main.routine2.r2arg = 20 ; TODO asmgen
|
|
||||||
;
|
|
||||||
; xx = main.routine.r1arg
|
|
||||||
; xx++
|
|
||||||
; ;xx = main.routine2.r2arg ; TODO asmgen
|
|
||||||
; ;xx++
|
|
||||||
|
|
||||||
repeat {
|
repeat {
|
||||||
|
xx++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub random_name() -> str {
|
asmsub routine2() -> ubyte @A {
|
||||||
ubyte ii
|
|
||||||
str name = " " ; 8 chars max
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
|
|
||||||
ubyte qqq
|
|
||||||
sub routine(ubyte r1arg) -> ubyte {
|
|
||||||
return qqq
|
|
||||||
return main.start.yy
|
|
||||||
}
|
|
||||||
|
|
||||||
asmsub routine2(ubyte r2arg @ A) {
|
|
||||||
%asm {{
|
%asm {{
|
||||||
|
adc #20
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user