diff --git a/src/main/scala/millfork/assembly/AssemblyLine.scala b/src/main/scala/millfork/assembly/AssemblyLine.scala index 5c53e08e..f96cf5d2 100644 --- a/src/main/scala/millfork/assembly/AssemblyLine.scala +++ b/src/main/scala/millfork/assembly/AssemblyLine.scala @@ -50,14 +50,14 @@ object OpcodeClasses { PHX, PHY, PLX, PLY, TAS, LAS ) val ChangesMemoryAlways = Set( - STA, STY, STZ, - STX, DEC, INC, + STA, STY, STZ, STX, + TRB, TSB, SAX, DCP, ISC, SLO, RLA, SRE, RRA, AHX, SHY, SHX, TAS, LAS ) val ChangesMemoryIfNotImplied = Set( - ASL, ROL, LSR, ROR + DEC, INC, ASL, ROL, LSR, ROR ) val ReadsMemoryIfNotImpliedOrImmediate = Set( LDY, CPX, CPY, @@ -305,7 +305,7 @@ case class AssemblyLine(opcode: Opcode.Value, addrMode: AddrMode.Value, var para def sizeInBytes: Int = addrMode match { case Implied => 1 - case Relative | ZeroPageX | ZeroPage | ZeroPageY | IndexedX | IndexedY | Immediate => 2 + case Relative | ZeroPageX | ZeroPage | ZeroPageY | ZeroPageIndirect | IndexedX | IndexedY | Immediate => 2 case AbsoluteIndexedX | AbsoluteX | Absolute | AbsoluteY | Indirect => 3 case DoesNotExist => 0 } diff --git a/src/main/scala/millfork/assembly/opt/CoarseFlowAnalyzer.scala b/src/main/scala/millfork/assembly/opt/CoarseFlowAnalyzer.scala index 12c924cf..d283ed66 100644 --- a/src/main/scala/millfork/assembly/opt/CoarseFlowAnalyzer.scala +++ b/src/main/scala/millfork/assembly/opt/CoarseFlowAnalyzer.scala @@ -195,16 +195,16 @@ object CoarseFlowAnalyzer { currentStatus = initialStatus case AssemblyLine(LDX, Immediate, NumericConstant(nn, _), _) => - val n = nn.toInt + val n = nn.toInt & 0xff currentStatus = currentStatus.nz(n).copy(x = SingleStatus(n)) case AssemblyLine(LDY, Immediate, NumericConstant(nn, _), _) => - val n = nn.toInt + val n = nn.toInt & 0xff currentStatus = currentStatus.nz(n).copy(y = SingleStatus(n)) case AssemblyLine(LDA, Immediate, NumericConstant(nn, _), _) => - val n = nn.toInt + val n = nn.toInt & 0xff currentStatus = currentStatus.nz(n).copy(a = SingleStatus(n)) case AssemblyLine(LAX, Immediate, NumericConstant(nn, _), _) => - val n = nn.toInt + val n = nn.toInt & 0xff currentStatus = currentStatus.nz(n).copy(a = SingleStatus(n), x = SingleStatus(n)) case AssemblyLine(ADC, Immediate, NumericConstant(nn, _), _) => @@ -232,17 +232,17 @@ object CoarseFlowAnalyzer { a = currentStatus.a.map(i => (i & n & 0xff) >> 1)) case AssemblyLine(INX, Implied, _, _) => - currentStatus = currentStatus.copy(n = currentStatus.x.n(_ + 1), z = currentStatus.x.z(_ + 1), x = currentStatus.x.map(_ + 1)) + currentStatus = currentStatus.copy(n = currentStatus.x.n(_ + 1), z = currentStatus.x.z(_ + 1), x = currentStatus.x.map(v => (v + 1) & 0xff)) case AssemblyLine(DEX, Implied, _, _) => - currentStatus = currentStatus.copy(n = currentStatus.x.n(_ - 1), z = currentStatus.x.z(_ - 1), x = currentStatus.x.map(_ - 1)) + currentStatus = currentStatus.copy(n = currentStatus.x.n(_ - 1), z = currentStatus.x.z(_ - 1), x = currentStatus.x.map(v => (v - 1) & 0xff)) case AssemblyLine(INY, Implied, _, _) => - currentStatus = currentStatus.copy(n = currentStatus.y.n(_ + 1), z = currentStatus.y.z(_ + 1), y = currentStatus.y.map(_ + 1)) + currentStatus = currentStatus.copy(n = currentStatus.y.n(_ + 1), z = currentStatus.y.z(_ + 1), y = currentStatus.y.map(v => (v + 1) & 0xff)) case AssemblyLine(DEY, Implied, _, _) => - currentStatus = currentStatus.copy(n = currentStatus.y.n(_ - 1), z = currentStatus.y.z(_ - 1), y = currentStatus.y.map(_ - 1)) + currentStatus = currentStatus.copy(n = currentStatus.y.n(_ - 1), z = currentStatus.y.z(_ - 1), y = currentStatus.y.map(v => (v - 1) & 0xff)) case AssemblyLine(INC, Implied, _, _) => - currentStatus = currentStatus.copy(n = currentStatus.a.n(_ + 1), z = currentStatus.a.z(_ + 1), a = currentStatus.a.map(_ + 1)) + currentStatus = currentStatus.copy(n = currentStatus.a.n(_ + 1), z = currentStatus.a.z(_ + 1), a = currentStatus.a.map(v => (v + 1) & 0xff)) case AssemblyLine(DEC, Implied, _, _) => - currentStatus = currentStatus.copy(n = currentStatus.a.n(_ - 1), z = currentStatus.a.z(_ - 1), a = currentStatus.a.map(_ - 1)) + currentStatus = currentStatus.copy(n = currentStatus.a.n(_ - 1), z = currentStatus.a.z(_ - 1), a = currentStatus.a.map(v => (v - 1) & 0xff)) case AssemblyLine(TAX, _, _, _) => currentStatus = currentStatus.copy(x = currentStatus.a, n = currentStatus.a.n(), z = currentStatus.a.z()) case AssemblyLine(TXA, _, _, _) => @@ -253,7 +253,7 @@ object CoarseFlowAnalyzer { currentStatus = currentStatus.copy(a = currentStatus.y, n = currentStatus.y.n(), z = currentStatus.y.z()) case AssemblyLine(ASL, Implied, _, _) => - currentStatus = currentStatus.copy(a = currentStatus.a.map(_ << 1), n = currentStatus.a.n(_ << 1), z = currentStatus.a.z(_ << 1),c = currentStatus.a.map(a => a.&(0xff).!=(0))) + currentStatus = currentStatus.copy(a = currentStatus.a.map(v => (v << 1) & 0xff), n = currentStatus.a.n(_ << 1), z = currentStatus.a.z(_ << 1),c = currentStatus.a.map(a => a.&(0xff).!=(0))) case AssemblyLine(LSR, Implied, _, _) => currentStatus = currentStatus.copy(a = currentStatus.a.map(a => a.>>(1).&(0x7f)), n = currentStatus.a.n(a => a.>>(1).&(0x7f)), z = currentStatus.a.z(a => a.>>(1).&(0x7f)),c = currentStatus.a.map(a => a.&(1).!=(0))) diff --git a/src/main/scala/millfork/assembly/opt/EmptyMemoryStoreRemoval.scala b/src/main/scala/millfork/assembly/opt/EmptyMemoryStoreRemoval.scala index 3b81f944..375bc078 100644 --- a/src/main/scala/millfork/assembly/opt/EmptyMemoryStoreRemoval.scala +++ b/src/main/scala/millfork/assembly/opt/EmptyMemoryStoreRemoval.scala @@ -4,6 +4,7 @@ import millfork.CompilationOptions import millfork.assembly.AssemblyLine import millfork.env._ import millfork.assembly.Opcode._ +import millfork.assembly.AddrMode._ import millfork.error.ErrorReporting import scala.collection.{immutable, mutable} @@ -14,7 +15,7 @@ import scala.collection.{immutable, mutable} object EmptyMemoryStoreRemoval extends AssemblyOptimization { override def name = "Removing pointless stores to automatic variables" - private val storeOpcodes = Set(STA, STX, STY, STZ, SAX) + private val storeAddrModes = Set(Absolute, ZeroPage, AbsoluteX, AbsoluteY, ZeroPageX, ZeroPageY) override def optimize(f: NormalFunction, code: List[AssemblyLine], options: CompilationOptions): List[AssemblyLine] = { val paramVariables = f.params match { @@ -26,11 +27,13 @@ object EmptyMemoryStoreRemoval extends AssemblyOptimization { } val stillUsedVariables = code.flatMap { case AssemblyLine(_, _, MemoryAddressConstant(th), _) => Some(th.name) + case AssemblyLine(_, _, CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(_, _)), _) => Some(th.name) case _ => None }.toSet - val localVariables = f.environment.getAllLocalVariables.filter { - case MemoryVariable(name, typ, VariableAllocationMethod.Auto) => - typ.size == 1 && !paramVariables(name) && stillUsedVariables(name) + val allLocalVariables = f.environment.getAllLocalVariables + val localVariables = allLocalVariables.filter { + case MemoryVariable(name, typ, VariableAllocationMethod.Auto | VariableAllocationMethod.Zeropage) => + typ.size > 0 && !paramVariables(name) && stillUsedVariables(name) case _ => false } @@ -46,17 +49,43 @@ object EmptyMemoryStoreRemoval extends AssemblyOptimization { val lifetime = VariableLifetime.apply(v.name, code) val lastaccess = lifetime.last if (lastaccess >= 0) { - if (code(lastaccess).opcode match { - case STA | STX | STY | SAX => + val lastVariableAccess = code(lastaccess) + if (lastVariableAccess.elidable && storeAddrModes(lastVariableAccess.addrMode) && (lastVariableAccess.opcode match { + case STA | STX | STY | SAX | STZ | SHX | SHY | AHX => true + case TSB | TRB => + if (importances eq null) importances = ReverseFlowAnalyzer.analyze(f, code) + importances(lastaccess).z != Important case INC | DEC => - if (importances eq null) { - importances = ReverseFlowAnalyzer.analyze(f, code) - } - importances(lastaccess).z != Important && importances(lastaccess).n != Important + if (importances eq null) importances = ReverseFlowAnalyzer.analyze(f, code) + importances(lastaccess).z != Important && + importances(lastaccess).n != Important + case ASL | LSR | ROL | ROR | DCP => + if (importances eq null) importances = ReverseFlowAnalyzer.analyze(f, code) + importances(lastaccess).z != Important && + importances(lastaccess).n != Important && + importances(lastaccess).c != Important + case ISC => + if (importances eq null) importances = ReverseFlowAnalyzer.analyze(f, code) + importances(lastaccess).z != Important && + importances(lastaccess).n != Important && + importances(lastaccess).a != Important + case DCP | SLO | SRE | RLA => + if (importances eq null) importances = ReverseFlowAnalyzer.analyze(f, code) + importances(lastaccess).z != Important && + importances(lastaccess).n != Important && + importances(lastaccess).c != Important && + importances(lastaccess).a != Important + case RRA => + if (importances eq null) importances = ReverseFlowAnalyzer.analyze(f, code) + importances(lastaccess).z != Important && + importances(lastaccess).n != Important && + importances(lastaccess).c != Important && + importances(lastaccess).a != Important && + importances(lastaccess).v != Important case _ => // last variable access is important, or we're in a loop, do not remove false - }) { + })) { badVariables += v.name toRemove += lastaccess } diff --git a/src/main/scala/millfork/assembly/opt/VariableLifetime.scala b/src/main/scala/millfork/assembly/opt/VariableLifetime.scala index 809de3fe..d7da9502 100644 --- a/src/main/scala/millfork/assembly/opt/VariableLifetime.scala +++ b/src/main/scala/millfork/assembly/opt/VariableLifetime.scala @@ -9,11 +9,11 @@ import millfork.error.ErrorReporting */ object VariableLifetime { - // TODO: This only works for 1-byte non-stack variables. - // Should be fixed to also work with larger variables. + // This only works for non-stack variables. def apply(variableName: String, code: List[AssemblyLine]): Range = { val flags = code.map(_.parameter match { case MemoryAddressConstant(MemoryVariable(n, _, _)) if n == variableName => true + case CompoundConstant(MathOperator.Plus, MemoryAddressConstant(MemoryVariable(n, _, _)), NumericConstant(_, 1)) if n == variableName => true case _ => false }) if (flags.forall(!_)) return Range(0, 0) diff --git a/src/main/scala/millfork/output/Assembler.scala b/src/main/scala/millfork/output/Assembler.scala index 8b69cd41..a52eca84 100644 --- a/src/main/scala/millfork/output/Assembler.scala +++ b/src/main/scala/millfork/output/Assembler.scala @@ -708,6 +708,7 @@ object Assembler { cm(TRB, ZeroPage, 0x14) cm(TRB, Absolute, 0x1C) + cm(BRA, Relative, 0x80) cm(BIT, ZeroPageX, 0x34) cm(BIT, AbsoluteX, 0x3C) cm(INC, Implied, 0x1A)