mirror of
https://github.com/irmen/prog8.git
synced 2025-01-12 19:29:50 +00:00
asmgen: only generate storage byte for register saves in subroutine when it's actually needed
This commit is contained in:
parent
e5ee5be9c5
commit
6e53eb9d5c
@ -6,6 +6,7 @@ import prog8.ast.expressions.IdentifierReference
|
||||
import prog8.ast.processing.AstWalker
|
||||
import prog8.ast.processing.IAstVisitor
|
||||
import prog8.ast.statements.*
|
||||
import prog8.compiler.target.c64.codegen.AsmGen
|
||||
import prog8.functions.BuiltinFunctions
|
||||
import java.nio.file.Path
|
||||
|
||||
@ -44,11 +45,19 @@ interface IFunctionCall {
|
||||
var args: MutableList<Expression>
|
||||
}
|
||||
|
||||
|
||||
class AsmGenInfo {
|
||||
var usedRegsaveA = false
|
||||
var usedRegsaveX = false
|
||||
var usedRegsaveY = false
|
||||
}
|
||||
|
||||
interface INameScope {
|
||||
val name: String
|
||||
val position: Position
|
||||
val statements: MutableList<Statement>
|
||||
val parent: Node
|
||||
val asmGenInfo: AsmGenInfo
|
||||
|
||||
fun linkParents(parent: Node)
|
||||
|
||||
@ -260,6 +269,7 @@ class Module(override val name: String,
|
||||
|
||||
override lateinit var parent: Node
|
||||
lateinit var program: Program
|
||||
override val asmGenInfo = AsmGenInfo()
|
||||
val importedBy = mutableListOf<Module>()
|
||||
val imports = mutableSetOf<Module>()
|
||||
|
||||
@ -293,6 +303,7 @@ class GlobalNamespace(val modules: List<Module>): Node, INameScope {
|
||||
override val position = Position("<<<global>>>", 0, 0, 0)
|
||||
override val statements = mutableListOf<Statement>()
|
||||
override var parent: Node = ParentSentinel
|
||||
override val asmGenInfo = AsmGenInfo()
|
||||
|
||||
override fun linkParents(parent: Node) {
|
||||
modules.forEach { it.linkParents(this) }
|
||||
@ -345,6 +356,7 @@ object BuiltinFunctionScopePlaceholder : INameScope {
|
||||
override val position = Position("<<placeholder>>", 0, 0, 0)
|
||||
override var statements = mutableListOf<Statement>()
|
||||
override var parent: Node = ParentSentinel
|
||||
override val asmGenInfo = AsmGenInfo()
|
||||
override fun linkParents(parent: Node) {}
|
||||
}
|
||||
|
||||
|
@ -57,6 +57,7 @@ class Block(override val name: String,
|
||||
val isInLibrary: Boolean,
|
||||
override val position: Position) : Statement(), INameScope {
|
||||
override lateinit var parent: Node
|
||||
override val asmGenInfo = AsmGenInfo()
|
||||
|
||||
override fun linkParents(parent: Node) {
|
||||
this.parent = parent
|
||||
@ -609,6 +610,7 @@ class AnonymousScope(override var statements: MutableList<Statement>,
|
||||
override val position: Position) : INameScope, Statement() {
|
||||
override val name: String
|
||||
override lateinit var parent: Node
|
||||
override val asmGenInfo = AsmGenInfo()
|
||||
|
||||
companion object {
|
||||
private var sequenceNumber = 1
|
||||
@ -662,6 +664,7 @@ class Subroutine(override val name: String,
|
||||
override val position: Position) : Statement(), INameScope {
|
||||
|
||||
override lateinit var parent: Node
|
||||
override val asmGenInfo = AsmGenInfo()
|
||||
val scopedname: String by lazy { makeScopedName(name) }
|
||||
|
||||
override fun linkParents(parent: Node) {
|
||||
@ -939,6 +942,7 @@ class StructDecl(override val name: String,
|
||||
override val position: Position): Statement(), INameScope {
|
||||
|
||||
override lateinit var parent: Node
|
||||
override val asmGenInfo = AsmGenInfo()
|
||||
|
||||
override fun linkParents(parent: Node) {
|
||||
this.parent = parent
|
||||
|
@ -198,7 +198,7 @@ internal class AsmGen(private val program: Program,
|
||||
variable.linkParents(decl.parent)
|
||||
val asgn = AsmAssignment(
|
||||
AsmAssignSource.fromAstSource(decl.value!!, program),
|
||||
AsmAssignTarget(TargetStorageKind.VARIABLE, program, this, decl.datatype, variable = variable),
|
||||
AsmAssignTarget(TargetStorageKind.VARIABLE, program, this, decl.datatype, decl.definingSubroutine(), variable = variable),
|
||||
false, decl.position)
|
||||
assignmentAsmGen.translateNormalAssignment(asgn)
|
||||
}
|
||||
@ -543,12 +543,24 @@ internal class AsmGen(private val program: Program,
|
||||
|
||||
private val saveRegisterLabels = Stack<String>()
|
||||
|
||||
internal fun saveRegister(register: CpuRegister, dontUseStack: Boolean) {
|
||||
internal fun saveRegister(register: CpuRegister, dontUseStack: Boolean, scope: Subroutine?) {
|
||||
if(dontUseStack) {
|
||||
when (register) {
|
||||
CpuRegister.A -> out(" sta _prog8_regsaveA")
|
||||
CpuRegister.X -> out(" stx _prog8_regsaveX")
|
||||
CpuRegister.Y -> out(" sty _prog8_regsaveY")
|
||||
CpuRegister.A -> {
|
||||
out(" sta _prog8_regsaveA")
|
||||
if (scope != null)
|
||||
scope.asmGenInfo.usedRegsaveA = true
|
||||
}
|
||||
CpuRegister.X -> {
|
||||
out(" stx _prog8_regsaveX")
|
||||
if (scope != null)
|
||||
scope.asmGenInfo.usedRegsaveX = true
|
||||
}
|
||||
CpuRegister.Y -> {
|
||||
out(" sty _prog8_regsaveY")
|
||||
if (scope != null)
|
||||
scope.asmGenInfo.usedRegsaveY = true
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
@ -556,11 +568,19 @@ internal class AsmGen(private val program: Program,
|
||||
CpuRegister.A -> out(" pha")
|
||||
CpuRegister.X -> {
|
||||
if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) out(" phx")
|
||||
else out(" stx _prog8_regsaveX")
|
||||
else {
|
||||
out(" stx _prog8_regsaveX")
|
||||
if (scope != null)
|
||||
scope.asmGenInfo.usedRegsaveX = true
|
||||
}
|
||||
}
|
||||
CpuRegister.Y -> {
|
||||
if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) out(" phy")
|
||||
else out(" sty _prog8_regsaveY")
|
||||
else {
|
||||
out(" sty _prog8_regsaveY")
|
||||
if (scope != null)
|
||||
scope.asmGenInfo.usedRegsaveY = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -828,11 +848,13 @@ internal class AsmGen(private val program: Program,
|
||||
out("; statements")
|
||||
sub.statements.forEach{ translate(it) }
|
||||
out("; variables")
|
||||
out("""
|
||||
; register saves
|
||||
_prog8_regsaveA .byte 0
|
||||
_prog8_regsaveX .byte 0
|
||||
_prog8_regsaveY .byte 0""") // TODO only generate these bytes if they're actually used by saveRegister()
|
||||
out("; register saves")
|
||||
if(sub.asmGenInfo.usedRegsaveA)
|
||||
out("_prog8_regsaveA .byte 0")
|
||||
if(sub.asmGenInfo.usedRegsaveX)
|
||||
out("_prog8_regsaveX .byte 0")
|
||||
if(sub.asmGenInfo.usedRegsaveY)
|
||||
out("_prog8_regsaveY .byte 0")
|
||||
vardecls2asm(sub.statements)
|
||||
out(" .pend\n")
|
||||
}
|
||||
|
@ -488,9 +488,9 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
||||
// all other types of swap() calls are done via the evaluation stack
|
||||
fun targetFromExpr(expr: Expression, datatype: DataType): AsmAssignTarget {
|
||||
return when (expr) {
|
||||
is IdentifierReference -> AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, datatype, variable=expr)
|
||||
is ArrayIndexedExpression -> AsmAssignTarget(TargetStorageKind.ARRAY, program, asmgen, datatype, array = expr)
|
||||
is DirectMemoryRead -> AsmAssignTarget(TargetStorageKind.MEMORY, program, asmgen, datatype, memory = DirectMemoryWrite(expr.addressExpression, expr.position))
|
||||
is IdentifierReference -> AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, datatype, expr.definingSubroutine(), variable=expr)
|
||||
is ArrayIndexedExpression -> AsmAssignTarget(TargetStorageKind.ARRAY, program, asmgen, datatype, expr.definingSubroutine(), array = expr)
|
||||
is DirectMemoryRead -> AsmAssignTarget(TargetStorageKind.MEMORY, program, asmgen, datatype, expr.definingSubroutine(), memory = DirectMemoryWrite(expr.addressExpression, expr.position))
|
||||
else -> throw AssemblyError("invalid expression object $expr")
|
||||
}
|
||||
}
|
||||
|
@ -610,7 +610,7 @@ $endLabel""")
|
||||
}
|
||||
|
||||
private fun assignLoopvar(stmt: ForLoop, range: RangeExpr) {
|
||||
val target = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, stmt.loopVarDt(program).typeOrElse(DataType.STRUCT), variable=stmt.loopVar)
|
||||
val target = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, stmt.loopVarDt(program).typeOrElse(DataType.STRUCT), stmt.definingSubroutine(), variable=stmt.loopVar)
|
||||
val src = AsmAssignSource.fromAstSource(range.from, program).adjustDataTypeToTarget(target)
|
||||
val assign = AsmAssignment(src, target, false, range.position)
|
||||
asmgen.translateNormalAssignment(assign)
|
||||
|
@ -1,6 +1,7 @@
|
||||
package prog8.compiler.target.c64.codegen
|
||||
|
||||
import prog8.ast.IFunctionCall
|
||||
import prog8.ast.Node
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.*
|
||||
import prog8.ast.expressions.*
|
||||
@ -19,7 +20,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
||||
val sub = stmt.target.targetSubroutine(program.namespace) ?: throw AssemblyError("undefined subroutine ${stmt.target}")
|
||||
val saveX = CpuRegister.X in sub.asmClobbers || sub.regXasResult() || sub.regXasParam()
|
||||
if(saveX)
|
||||
asmgen.saveRegister(CpuRegister.X, preserveStatusRegisterAfterCall)
|
||||
asmgen.saveRegister(CpuRegister.X, preserveStatusRegisterAfterCall, (stmt as Node).definingSubroutine())
|
||||
|
||||
val subName = asmgen.asmSymbolName(stmt.target)
|
||||
if(stmt.args.isNotEmpty()) {
|
||||
@ -157,7 +158,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
||||
val scopedParamVar = (sub.scopedname+"."+parameter.value.name).split(".")
|
||||
val identifier = IdentifierReference(scopedParamVar, sub.position)
|
||||
identifier.linkParents(value.parent)
|
||||
val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, parameter.value.type, variable = identifier)
|
||||
val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, parameter.value.type, sub, variable = identifier)
|
||||
val source = AsmAssignSource.fromAstSource(value, program).adjustDataTypeToTarget(tgt)
|
||||
val asgn = AsmAssignment(source, tgt, false, Position.DUMMY)
|
||||
asmgen.translateNormalAssignment(asgn)
|
||||
@ -222,7 +223,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
||||
}
|
||||
else -> {
|
||||
// via register or register pair
|
||||
val target = AsmAssignTarget.fromRegisters(register!!, program, asmgen)
|
||||
val target = AsmAssignTarget.fromRegisters(register!!, sub, program, asmgen)
|
||||
val src = if(valueDt in PassByReferenceDatatypes) {
|
||||
if(value is IdentifierReference) {
|
||||
val addr = AddressOf(value, Position.DUMMY)
|
||||
|
@ -15,6 +15,7 @@ internal class PostIncrDecrAsmGen(private val program: Program, private val asmg
|
||||
val targetIdent = stmt.target.identifier
|
||||
val targetMemory = stmt.target.memoryAddress
|
||||
val targetArrayIdx = stmt.target.arrayindexed
|
||||
val scope = stmt.definingSubroutine()
|
||||
when {
|
||||
targetIdent!=null -> {
|
||||
val what = asmgen.asmVariableName(targetIdent)
|
||||
@ -97,7 +98,7 @@ internal class PostIncrDecrAsmGen(private val program: Program, private val asmg
|
||||
}
|
||||
else -> {
|
||||
asmgen.loadScaledArrayIndexIntoRegister(targetArrayIdx, elementDt, CpuRegister.A)
|
||||
asmgen.saveRegister(CpuRegister.X, false)
|
||||
asmgen.saveRegister(CpuRegister.X, false, scope)
|
||||
asmgen.out(" tax")
|
||||
when(elementDt) {
|
||||
in ByteDatatypes -> {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package prog8.compiler.target.c64.codegen.assignment
|
||||
|
||||
import prog8.ast.INameScope
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.*
|
||||
import prog8.ast.expressions.*
|
||||
@ -33,6 +34,7 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
|
||||
program: Program,
|
||||
asmgen: AsmGen,
|
||||
val datatype: DataType,
|
||||
val scope: Subroutine?,
|
||||
val variable: IdentifierReference? = null,
|
||||
val array: ArrayIndexedExpression? = null,
|
||||
val memory: DirectMemoryWrite? = null,
|
||||
@ -63,21 +65,21 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
|
||||
fun fromAstAssignment(assign: Assignment, program: Program, asmgen: AsmGen): AsmAssignTarget = with(assign.target) {
|
||||
val dt = inferType(program, assign).typeOrElse(DataType.STRUCT)
|
||||
when {
|
||||
identifier != null -> AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, dt, variable=identifier, origAstTarget = this)
|
||||
arrayindexed != null -> AsmAssignTarget(TargetStorageKind.ARRAY, program, asmgen, dt, array = arrayindexed, origAstTarget = this)
|
||||
memoryAddress != null -> AsmAssignTarget(TargetStorageKind.MEMORY, program, asmgen, dt, memory = memoryAddress, origAstTarget = this)
|
||||
identifier != null -> AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, dt, assign.definingSubroutine(), variable=identifier, origAstTarget = this)
|
||||
arrayindexed != null -> AsmAssignTarget(TargetStorageKind.ARRAY, program, asmgen, dt, assign.definingSubroutine(), array = arrayindexed, origAstTarget = this)
|
||||
memoryAddress != null -> AsmAssignTarget(TargetStorageKind.MEMORY, program, asmgen, dt, assign.definingSubroutine(), memory = memoryAddress, origAstTarget = this)
|
||||
else -> throw AssemblyError("weird target")
|
||||
}
|
||||
}
|
||||
|
||||
fun fromRegisters(registers: RegisterOrPair, program: Program, asmgen: AsmGen): AsmAssignTarget =
|
||||
fun fromRegisters(registers: RegisterOrPair, scope: Subroutine?, program: Program, asmgen: AsmGen): AsmAssignTarget =
|
||||
when(registers) {
|
||||
RegisterOrPair.A,
|
||||
RegisterOrPair.X,
|
||||
RegisterOrPair.Y -> AsmAssignTarget(TargetStorageKind.REGISTER, program, asmgen, DataType.UBYTE, register = registers)
|
||||
RegisterOrPair.Y -> AsmAssignTarget(TargetStorageKind.REGISTER, program, asmgen, DataType.UBYTE, scope, register = registers)
|
||||
RegisterOrPair.AX,
|
||||
RegisterOrPair.AY,
|
||||
RegisterOrPair.XY -> AsmAssignTarget(TargetStorageKind.REGISTER, program, asmgen, DataType.UWORD, register = registers)
|
||||
RegisterOrPair.XY -> AsmAssignTarget(TargetStorageKind.REGISTER, program, asmgen, DataType.UWORD, scope, register = registers)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -688,7 +688,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
|
||||
asmgen.out(" ldy ${asmgen.asmVariableName(index)} | sta ${target.asmVarname},y")
|
||||
}
|
||||
else -> {
|
||||
asmgen.saveRegister(register, false)
|
||||
asmgen.saveRegister(register, false, target.scope)
|
||||
asmgen.translateExpression(index)
|
||||
asmgen.restoreRegister(register, false)
|
||||
when (register) {
|
||||
@ -1187,7 +1187,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
|
||||
asmgen.storeByteIntoPointer(addressExpr, null)
|
||||
}
|
||||
else -> {
|
||||
asmgen.saveRegister(register, false)
|
||||
asmgen.saveRegister(register, false, memoryAddress.definingSubroutine())
|
||||
asmgen.translateExpression(addressExpr)
|
||||
asmgen.restoreRegister(CpuRegister.A, false)
|
||||
asmgen.out("""
|
||||
|
@ -1,8 +1,10 @@
|
||||
package prog8.compiler.target.c64.codegen.assignment
|
||||
|
||||
import prog8.ast.INameScope
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.*
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.statements.Subroutine
|
||||
import prog8.compiler.AssemblyError
|
||||
import prog8.compiler.target.CompilationTarget
|
||||
import prog8.compiler.target.CpuType
|
||||
@ -137,13 +139,13 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
when {
|
||||
valueLv != null -> inplaceModification_float_litval_to_variable(target.asmVarname, operator, valueLv.toDouble())
|
||||
ident != null -> inplaceModification_float_variable_to_variable(target.asmVarname, operator, ident)
|
||||
valueLv != null -> inplaceModification_float_litval_to_variable(target.asmVarname, operator, valueLv.toDouble(), target.scope)
|
||||
ident != null -> inplaceModification_float_variable_to_variable(target.asmVarname, operator, ident, target.scope)
|
||||
value is TypecastExpression -> {
|
||||
if (tryRemoveRedundantCast(value, target, operator)) return
|
||||
inplaceModification_float_value_to_variable(target.asmVarname, operator, value)
|
||||
inplaceModification_float_value_to_variable(target.asmVarname, operator, value, target.scope)
|
||||
}
|
||||
else -> inplaceModification_float_value_to_variable(target.asmVarname, operator, value)
|
||||
else -> inplaceModification_float_value_to_variable(target.asmVarname, operator, value, target.scope)
|
||||
}
|
||||
}
|
||||
else -> throw AssemblyError("weird type to do in-place modification on ${target.datatype}")
|
||||
@ -1229,13 +1231,13 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
asmgen.out(" inx")
|
||||
}
|
||||
|
||||
private fun inplaceModification_float_value_to_variable(name: String, operator: String, value: Expression) {
|
||||
private fun inplaceModification_float_value_to_variable(name: String, operator: String, value: Expression, scope: Subroutine?) {
|
||||
// this should be the last resort for code generation for this,
|
||||
// because the value is evaluated onto the eval stack (=slow).
|
||||
println("warning: slow stack evaluation used (2): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO
|
||||
asmgen.translateExpression(value)
|
||||
asmgen.out(" jsr floats.pop_float_fac1")
|
||||
asmgen.saveRegister(CpuRegister.X, false)
|
||||
asmgen.saveRegister(CpuRegister.X, false, scope)
|
||||
when (operator) {
|
||||
"**" -> {
|
||||
asmgen.out("""
|
||||
@ -1283,13 +1285,13 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
asmgen.restoreRegister(CpuRegister.X, false)
|
||||
}
|
||||
|
||||
private fun inplaceModification_float_variable_to_variable(name: String, operator: String, ident: IdentifierReference) {
|
||||
private fun inplaceModification_float_variable_to_variable(name: String, operator: String, ident: IdentifierReference, scope: Subroutine?) {
|
||||
val valueDt = ident.targetVarDecl(program.namespace)!!.datatype
|
||||
if(valueDt != DataType.FLOAT)
|
||||
throw AssemblyError("float variable expected")
|
||||
|
||||
val otherName = asmgen.asmVariableName(ident)
|
||||
asmgen.saveRegister(CpuRegister.X, false)
|
||||
asmgen.saveRegister(CpuRegister.X, false, scope)
|
||||
when (operator) {
|
||||
"**" -> {
|
||||
asmgen.out("""
|
||||
@ -1352,9 +1354,9 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
asmgen.restoreRegister(CpuRegister.X, false)
|
||||
}
|
||||
|
||||
private fun inplaceModification_float_litval_to_variable(name: String, operator: String, value: Double) {
|
||||
private fun inplaceModification_float_litval_to_variable(name: String, operator: String, value: Double, scope: Subroutine?) {
|
||||
val constValueName = asmgen.getFloatAsmConst(value)
|
||||
asmgen.saveRegister(CpuRegister.X, false)
|
||||
asmgen.saveRegister(CpuRegister.X, false, scope)
|
||||
when (operator) {
|
||||
"**" -> {
|
||||
asmgen.out("""
|
||||
|
Loading…
x
Reference in New Issue
Block a user