gosub only uses an identifier

This commit is contained in:
Irmen de Jong
2022-03-22 20:53:06 +01:00
parent 97b3a0b093
commit 7b27d270a2
15 changed files with 47 additions and 89 deletions
+2 -7
View File
@@ -86,14 +86,9 @@ class PtForLoop(position: Position) : PtNode(position) {
}
class PtGosub(val identifier: PtIdentifier?,
val address: UInt?,
val generatedLabel: String?,
position: Position) : PtNode(position) {
class PtGosub(val identifier: PtIdentifier, position: Position) : PtNode(position) {
override fun printProperties() {
identifier?.printProperties()
if(address!=null) print(address.toHex())
if(generatedLabel!=null) print(generatedLabel)
identifier.printProperties()
}
}
@@ -887,7 +887,7 @@ $repeatLabel lda $counterVar
}
private fun translate(gosub: GoSub) {
val tgt = gosub.identifier!!.targetSubroutine(program)
val tgt = gosub.identifier.targetSubroutine(program)
if(tgt!=null && tgt.isAsmSubroutine) {
// no need to rescue X , this has been taken care of already
out(" jsr ${getJumpTarget(gosub)}")
@@ -917,17 +917,7 @@ $repeatLabel lda $counterVar
}
}
private fun getJumpTarget(gosub: GoSub): String {
val ident = gosub.identifier
val label = gosub.generatedLabel
val addr = gosub.address
return when {
ident!=null -> asmSymbolName(ident)
label!=null -> label
addr!=null -> addr.toHex()
else -> "????"
}
}
private fun getJumpTarget(gosub: GoSub): String = asmSymbolName(gosub.identifier)
private fun translate(ret: Return, withRts: Boolean=true) {
ret.value?.let { returnvalue ->
@@ -36,7 +36,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
}
internal fun saveXbeforeCall(gosub: GoSub) {
val sub = gosub.identifier?.targetSubroutine(program)
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)
@@ -58,7 +58,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
}
internal fun restoreXafterCall(gosub: GoSub) {
val sub = gosub.identifier?.targetSubroutine(program)
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)
@@ -556,11 +556,7 @@ class AstToXmlConverter(internal val program: PtProgram,
private fun write(gosub: PtGosub) {
xml.elt("gosub")
if(gosub.identifier!=null) xml.attr("symbol", strTargetName(gosub.identifier!!))
else if(gosub.address!=null) xml.attr("address", gosub.address!!.toString())
else if(gosub.generatedLabel!=null) xml.attr("label", gosub.generatedLabel!!)
else
throw InternalCompilerException("weird jump target")
xml.attr("symbol", strTargetName(gosub.identifier))
xml.endElt()
}
@@ -135,13 +135,7 @@ class CodeGen(internal val program: PtProgram,
private fun translate(gosub: PtGosub): VmCodeChunk {
val chunk = VmCodeChunk()
if(gosub.address!=null)
throw AssemblyError("cannot gosub to a memory address in the vm target")
else if(gosub.identifier!=null) {
chunk += VmCodeOpcodeWithStringArg(Opcode.GOSUB, gosubArg(gosub.identifier!!.targetName))
} else if(gosub.generatedLabel!=null) {
chunk += VmCodeOpcodeWithStringArg(Opcode.GOSUB, gosubArg(listOf(gosub.generatedLabel!!)))
}
chunk += VmCodeOpcodeWithStringArg(Opcode.GOSUB, gosubArg(gosub.identifier.targetName))
return chunk
}
@@ -291,13 +291,13 @@ class StatementOptimizer(private val program: Program,
override fun after(gosub: GoSub, parent: Node): Iterable<IAstModification> {
// if the next statement is return with no returnvalue, change into a regular jump if there are no parameters as well.
val subroutineParams = gosub.identifier?.targetSubroutine(program)?.parameters
val subroutineParams = gosub.identifier.targetSubroutine(program)?.parameters
if(subroutineParams!=null && subroutineParams.isEmpty()) {
val returnstmt = gosub.nextSibling() as? Return
if(returnstmt!=null && returnstmt.value==null) {
return listOf(
IAstModification.Remove(returnstmt, parent as IStatementContainer),
IAstModification.ReplaceNode(gosub, Jump(gosub.address, gosub.identifier, gosub.generatedLabel, gosub.position), parent)
IAstModification.ReplaceNode(gosub, Jump(null, gosub.identifier, null, gosub.position), parent)
)
}
}
@@ -222,13 +222,7 @@ class IntermediateAstMaker(val program: Program) {
return call
}
private fun transform(gosub: GoSub): PtGosub {
val identifier = if(gosub.identifier!=null) transform(gosub.identifier!!) else null
return PtGosub(identifier,
gosub.address,
gosub.generatedLabel,
gosub.position)
}
private fun transform(gosub: GoSub): PtGosub = PtGosub(transform(gosub.identifier), gosub.position)
private fun transform(srcIf: IfElse): PtIfElse {
val ifelse = PtIfElse(srcIf.position)
@@ -183,18 +183,12 @@ internal class AstChecker(private val program: Program,
}
override fun visit(gosub: GoSub) {
val ident = gosub.identifier
if(ident!=null) {
val targetStatement = checkFunctionOrLabelExists(ident, gosub)
if(targetStatement!=null) {
if(targetStatement is BuiltinFunctionPlaceholder)
errors.err("can't gosub to a builtin function", gosub.position)
}
val targetStatement = checkFunctionOrLabelExists(gosub.identifier, gosub)
if(targetStatement!=null) {
if(targetStatement is BuiltinFunctionPlaceholder)
errors.err("can't gosub to a builtin function", gosub.position)
}
val addr = gosub.address
if(addr!=null && addr > 65535u)
errors.err("gosub address must be valid integer 0..\$ffff", gosub.position)
super.visit(gosub)
}
@@ -411,21 +411,22 @@ internal class StatementReorderer(val program: Program,
override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
val function = functionCallStatement.target.targetStatement(program)!!
checkUnusedReturnValues(functionCallStatement, function, program, errors)
return tryReplaceCallWithGosub(functionCallStatement, parent, program, options)
return tryReplaceCallWithGosub(functionCallStatement, parent, program)
}
}
internal fun tryReplaceCallWithGosub(functionCallStatement: FunctionCallStatement,
parent: Node,
program: Program,
options: CompilationOptions): Iterable<IAstModification> {
internal fun tryReplaceCallWithGosub(
functionCallStatement: FunctionCallStatement,
parent: Node,
program: Program
): Iterable<IAstModification> {
val callee = functionCallStatement.target.targetStatement(program)!!
if(callee is Subroutine) {
if(callee.inline)
return emptyList()
return if(callee.isAsmSubroutine)
tryReplaceCallAsmSubWithGosub(functionCallStatement, parent, callee, options.compTarget)
tryReplaceCallAsmSubWithGosub(functionCallStatement, parent, callee)
else
tryReplaceCallNormalSubWithGosub(functionCallStatement, parent, callee, program)
}
@@ -437,7 +438,7 @@ private fun tryReplaceCallNormalSubWithGosub(call: FunctionCallStatement, parent
if(callee.parameters.isEmpty()) {
// 0 params -> just GoSub
return listOf(IAstModification.ReplaceNode(call, GoSub(null, call.target, null, call.position), parent))
return listOf(IAstModification.ReplaceNode(call, GoSub(call.target, call.position), parent))
}
if(callee.parameters.size==1) {
@@ -466,14 +467,14 @@ private fun tryReplaceCallNormalSubWithGosub(call: FunctionCallStatement, parent
Assignment(AssignTarget(paramIdentifier, null, null, argumentValue.position), argumentValue, AssignmentOrigin.PARAMETERASSIGN, argumentValue.position)
}
val scope = AnonymousScope(assignParams.toMutableList(), call.position)
scope.statements += GoSub(null, call.target, null, call.position)
scope.statements += GoSub(call.target, call.position)
return listOf(IAstModification.ReplaceNode(call, scope, parent))
}
private fun tryReplaceCallAsmSubWithGosub(call: FunctionCallStatement,
parent: Node,
callee: Subroutine,
compTarget: ICompilationTarget
private fun tryReplaceCallAsmSubWithGosub(
call: FunctionCallStatement,
parent: Node,
callee: Subroutine
): Iterable<IAstModification> {
val noModifications = emptyList<IAstModification>()
@@ -483,7 +484,7 @@ private fun tryReplaceCallAsmSubWithGosub(call: FunctionCallStatement,
if(callee.shouldSaveX()) {
scope.statements += FunctionCallStatement(IdentifierReference(listOf("rsavex"), call.position), mutableListOf(), true, call.position)
}
scope.statements += GoSub(null, call.target, null, call.position)
scope.statements += GoSub(call.target, call.position)
if(callee.shouldSaveX()) {
scope.statements += FunctionCallStatement(IdentifierReference(listOf("rrestorex"), call.position), mutableListOf(), true, call.position)
}
@@ -495,15 +496,16 @@ private fun tryReplaceCallAsmSubWithGosub(call: FunctionCallStatement,
return noModifications
} else {
// clobber risk; evaluate the arguments on the CPU stack first (in reverse order)...
return makeGosubWithArgsViaCpuStack(call, call.position, parent, callee, compTarget)
return makeGosubWithArgsViaCpuStack(call, call.position, parent, callee)
}
}
private fun makeGosubWithArgsViaCpuStack(call: IFunctionCall,
position: Position,
parent: Node,
callee: Subroutine,
compTarget: ICompilationTarget): Iterable<IAstModification> {
private fun makeGosubWithArgsViaCpuStack(
call: IFunctionCall,
position: Position,
parent: Node,
callee: Subroutine
): Iterable<IAstModification> {
fun popCall(targetName: List<String>, dt: DataType, position: Position): FunctionCallStatement {
return FunctionCallStatement(
@@ -545,7 +547,7 @@ private fun makeGosubWithArgsViaCpuStack(call: IFunctionCall,
val targetName = callee.scopedName + param.name
scope.statements += popCall(targetName, param.type, position)
}
scope.statements += GoSub(null, call.target, null, position)
scope.statements += GoSub(call.target, position)
if(callee.shouldSaveX()) {
scope.statements += FunctionCallStatement(IdentifierReference(listOf("rrestorex"), position), mutableListOf(), true, position)
}
@@ -200,7 +200,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
}
override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
return tryReplaceCallWithGosub(functionCallStatement, parent, program, options)
return tryReplaceCallWithGosub(functionCallStatement, parent, program)
}
}
@@ -242,11 +242,7 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program:
override fun visit(gosub: GoSub) {
output("gosub ")
when {
gosub.address!=null -> output(gosub.address.toHex())
gosub.generatedLabel!=null -> output(gosub.generatedLabel)
gosub.identifier!=null -> gosub.identifier.accept(this)
}
gosub.identifier.accept(this)
}
override fun visit(ifElse: IfElse) {
@@ -583,25 +583,22 @@ class Jump(var address: UInt?,
"Jump(addr: $address, identifier: $identifier, label: $generatedLabel; pos=$position)"
}
// a GoSub is ONLY created internally for calling subroutines
class GoSub(val address: UInt?,
val identifier: IdentifierReference?,
val generatedLabel: String?, // can be used in code generation scenarios
override val position: Position) : Statement() {
// a GoSub is ONLY created internally for calling subroutines, there's no syntax for it in the language
class GoSub(val identifier: IdentifierReference, override val position: Position) : Statement() {
override lateinit var parent: Node
override fun linkParents(parent: Node) {
this.parent = parent
identifier?.linkParents(this)
identifier.linkParents(this)
}
override fun replaceChildNode(node: Node, replacement: Node) = throw FatalAstException("can't replace here")
override fun copy() = GoSub(address, identifier?.copy(), generatedLabel, position)
override fun copy() = GoSub(identifier.copy(), position)
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
override fun toString() =
"GoSub(addr: $address, identifier: $identifier, label: $generatedLabel; pos=$position)"
"GoSub($identifier; pos=$position)"
}
class FunctionCallStatement(override var target: IdentifierReference,
+1 -1
View File
@@ -300,7 +300,7 @@ abstract class AstWalker {
fun visit(gosub: GoSub, parent: Node) {
track(before(gosub, parent), gosub, parent)
gosub.identifier?.accept(this, gosub)
gosub.identifier.accept(this, gosub)
track(after(gosub, parent), gosub, parent)
}
@@ -71,7 +71,7 @@ interface IAstVisitor {
}
fun visit(gosub: GoSub) {
gosub.identifier?.accept(this)
gosub.identifier.accept(this)
}
fun visit(ifElse: IfElse) {
+1 -1
View File
@@ -101,7 +101,7 @@ class CallGraph(private val program: Program, private val allowMissingIdentifier
}
override fun visit(gosub: GoSub) {
val otherSub = gosub.identifier?.targetSubroutine(program)
val otherSub = gosub.identifier.targetSubroutine(program)
if (otherSub != null) {
gosub.definingSubroutine?.let { thisSub ->
calls[thisSub] = calls.getValue(thisSub) + otherSub