diff --git a/src/main/scala/millfork/assembly/mos/opt/AlwaysGoodOptimizations.scala b/src/main/scala/millfork/assembly/mos/opt/AlwaysGoodOptimizations.scala index b0020f53..5b67b951 100644 --- a/src/main/scala/millfork/assembly/mos/opt/AlwaysGoodOptimizations.scala +++ b/src/main/scala/millfork/assembly/mos/opt/AlwaysGoodOptimizations.scala @@ -217,6 +217,20 @@ object AlwaysGoodOptimizations { pointlessImmediateStoreToTheSameVariable(MatchX(0), STX, MatchY(0), STY), pointlessImmediateStoreToTheSameVariable(MatchY(0), STY, MatchY(0), STY), + (HasOpcode(PHA)) ~ + (Linear & Not(ChangesA) & Not(ChangesStack) & Not(ChangesMemory)).* ~ + (Elidable & XContainsStackPointer & HasOpcode(STA) & HasAddrMode(AbsoluteX) & HasParameterWhere(p => p.quickSimplify match { + case NumericConstant(n, _) => n == 0x101 + case _ => false + })) ~~> (_.init), + + (HasOpcode(PHA)) ~ + (Linear & Not(ChangesA) & Not(ChangesStack) & Not(ChangesMemory)).* ~ + (Elidable & HasOpcode(STA) & HasAddrMode(Stack) & HasParameterWhere(p => p.quickSimplify match { + case NumericConstant(n, _) => n == 1 + case _ => false + })) ~~> (_.init) + ) val PointlessStashingForLaterStore = new RuleBasedAssemblyOptimization("Pointless stashing for later store", @@ -1093,6 +1107,18 @@ object AlwaysGoodOptimizations { HasOpcodeIn(Set(TYA, TAY)) ~ (Not(Set(TYA, TAY)) & Linear & Not(ChangesA) & Not(ChangesY)).* ~ (Elidable & HasOpcodeIn(Set(TYA, TAY)) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~~> (_.init), + + (HasOpcodeIn(Set(STA, LDA)) & HasAddrModeIn(Set(ZeroPage, Absolute)) & MatchAddrMode(0) & MatchParameter(1)) ~ + (Linear & Not(HasOpcode(TAX)) & Not(ChangesA) & DoesntChangeMemoryAt(0, 1)).* ~ + HasOpcode(TAX) ~ + (LinearOrBranch & Not(ChangesX) & DoesntChangeMemoryAt(0, 1)).* ~ + (Elidable & HasOpcode(LDX) & HasAddrModeIn(Set(ZeroPage, Absolute)) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~~> (_.init), + + (HasOpcodeIn(Set(STA, LDA)) & HasAddrModeIn(Set(ZeroPage, Absolute)) & MatchAddrMode(0) & MatchParameter(1)) ~ + (Linear & Not(HasOpcode(TAY)) & Not(ChangesA) & DoesntChangeMemoryAt(0, 1)).* ~ + HasOpcode(TAY) ~ + (LinearOrBranch & Not(ChangesY) & DoesntChangeMemoryAt(0, 1)).* ~ + (Elidable & HasOpcode(LDY) & HasAddrModeIn(Set(ZeroPage, Absolute)) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~~> (_.init), ) val RearrangableLoadFromTheSameLocation = new RuleBasedAssemblyOptimization("Rearrangable load from the same location", diff --git a/src/main/scala/millfork/assembly/mos/opt/CoarseFlowAnalyzer.scala b/src/main/scala/millfork/assembly/mos/opt/CoarseFlowAnalyzer.scala index cafe44ea..d4829c80 100644 --- a/src/main/scala/millfork/assembly/mos/opt/CoarseFlowAnalyzer.scala +++ b/src/main/scala/millfork/assembly/mos/opt/CoarseFlowAnalyzer.scala @@ -62,7 +62,7 @@ object CoarseFlowAnalyzer { case AssemblyLine(opcode, addrMode, _, _) => currentStatus = currentStatus.copy(src = AnyStatus) - if (OpcodeClasses.ChangesX(opcode)) currentStatus = currentStatus.copy(x = AnyStatus) + if (OpcodeClasses.ChangesX(opcode)) currentStatus = currentStatus.copy(x = AnyStatus, eqSX = false) if (OpcodeClasses.ChangesY(opcode)) currentStatus = currentStatus.copy(y = AnyStatus) if (OpcodeClasses.ChangesAAlways(opcode)) currentStatus = currentStatus.copy(a = AnyStatus, a0 = AnyStatus, a7 = AnyStatus) if (addrMode == Implied && OpcodeClasses.ChangesAIfImplied(opcode)) currentStatus = currentStatus.copy(a = AnyStatus, a0 = AnyStatus, a7 = AnyStatus) @@ -71,6 +71,7 @@ object CoarseFlowAnalyzer { if (OpcodeClasses.ChangesNAndZ(opcode)) currentStatus = currentStatus.nz if (OpcodeClasses.ChangesC(opcode)) currentStatus = currentStatus.copy(c = AnyStatus) if (OpcodeClasses.ChangesV(opcode)) currentStatus = currentStatus.copy(v = AnyStatus) + if (OpcodeClasses.ChangesStack(opcode) || OpcodeClasses.ChangesS(opcode)) currentStatus = currentStatus.copy(eqSX = false) } } // flagArray.zip(codeArray).foreach{ diff --git a/src/main/scala/millfork/assembly/mos/opt/CpuStatus.scala b/src/main/scala/millfork/assembly/mos/opt/CpuStatus.scala index 8afb8922..ae5bf5f0 100644 --- a/src/main/scala/millfork/assembly/mos/opt/CpuStatus.scala +++ b/src/main/scala/millfork/assembly/mos/opt/CpuStatus.scala @@ -48,6 +48,7 @@ case class CpuStatus(a: Status[Int] = UnknownStatus, y: Status[Int] = UnknownStatus, iz: Status[Int] = UnknownStatus, src: Status[SourceOfNZ] = UnknownStatus, + eqSX: Boolean = false, z: Status[Boolean] = UnknownStatus, n: Status[Boolean] = UnknownStatus, c: Status[Boolean] = UnknownStatus, @@ -115,6 +116,7 @@ case class CpuStatus(a: Status[Int] = UnknownStatus, y = this.y ~ that.y, iz = this.iz ~ that.iz, src = this.src ~ that.src, + eqSX = this.eqSX && that.eqSX, z = this.z ~ that.z, n = this.n ~ that.n, c = this.c ~ that.c, diff --git a/src/main/scala/millfork/assembly/mos/opt/FlowAnalyzerForImmediate.scala b/src/main/scala/millfork/assembly/mos/opt/FlowAnalyzerForImmediate.scala index b32755d0..c6cdc814 100644 --- a/src/main/scala/millfork/assembly/mos/opt/FlowAnalyzerForImmediate.scala +++ b/src/main/scala/millfork/assembly/mos/opt/FlowAnalyzerForImmediate.scala @@ -15,7 +15,7 @@ object FlowAnalyzerForImmediate { if ((nn & 1) != 0) currentStatus = currentStatus.copy(c = Status.SingleFalse) if ((nn & 2) != 0) currentStatus = currentStatus.copy(z = Status.SingleFalse) if ((nn & 8) != 0) currentStatus = currentStatus.copy(d = Status.SingleFalse) - if ((nn & 0x10) != 0) currentStatus = currentStatus.copy(w = Status.SingleFalse) + if ((nn & 0x10) != 0) currentStatus = currentStatus.copy(w = Status.SingleFalse, eqSX = false) if ((nn & 0x20) != 0) currentStatus = currentStatus.copy(m = Status.SingleFalse) if ((nn & 0x40) != 0) currentStatus = currentStatus.copy(v = Status.SingleFalse) if ((nn & 0x80) != 0) currentStatus = currentStatus.copy(n = Status.SingleFalse) @@ -26,7 +26,7 @@ object FlowAnalyzerForImmediate { if ((nn & 1) != 0) currentStatus = currentStatus.copy(c = Status.SingleTrue) if ((nn & 2) != 0) currentStatus = currentStatus.copy(z = Status.SingleTrue) if ((nn & 8) != 0) currentStatus = currentStatus.copy(d = Status.SingleTrue) - if ((nn & 0x10) != 0) currentStatus = currentStatus.copy(w = Status.SingleTrue) + if ((nn & 0x10) != 0) currentStatus = currentStatus.copy(w = Status.SingleTrue, eqSX = false) if ((nn & 0x20) != 0) currentStatus = currentStatus.copy(m = Status.SingleTrue) if ((nn & 0x40) != 0) currentStatus = currentStatus.copy(v = Status.SingleTrue) if ((nn & 0x80) != 0) currentStatus = currentStatus.copy(n = Status.SingleTrue) @@ -34,7 +34,7 @@ object FlowAnalyzerForImmediate { }, LDX -> {(nn, currentStatus) => val n = nn & 0xff - currentStatus.nz(n).copy(x = SingleStatus(n), src = SourceOfNZ.X) + currentStatus.nz(n).copy(x = SingleStatus(n), src = SourceOfNZ.X, eqSX = false) }, LDY -> {(nn, currentStatus) => val n = nn & 0xff @@ -54,7 +54,7 @@ object FlowAnalyzerForImmediate { }, LDX_W -> {(nn, currentStatus) => val n = nn & 0xff - currentStatus.nzw(nn).copy(x = SingleStatus(n), src = AnyStatus) + currentStatus.nzw(nn).copy(x = SingleStatus(n), src = AnyStatus, eqSX = false) }, LDY_W -> {(nn, currentStatus) => val n = nn & 0xff @@ -251,6 +251,17 @@ object FlowAnalyzerForImmediate { z = currentStatus.iz.map(v => (v & 0xff) == (nn & 0xff)), src = if (nn == 0) SourceOfNZ.Z else AnyStatus) }, + + SBX -> { (nn, currentStatus) => + val newX = (currentStatus.x <*> currentStatus.a) { (x, a) => (x - (x & a)) & 0xff } + currentStatus.copy( + x = newX, + n = newX.n(), + z = newX.z(), + c = AnyStatus, + eqSX = false, + src = SourceOfNZ.X) + } ) def hasDefinition(opcode: Opcode.Value): Boolean = map.contains(opcode) diff --git a/src/main/scala/millfork/assembly/mos/opt/FlowAnalyzerForImplied.scala b/src/main/scala/millfork/assembly/mos/opt/FlowAnalyzerForImplied.scala index 2010592f..fd6683ed 100644 --- a/src/main/scala/millfork/assembly/mos/opt/FlowAnalyzerForImplied.scala +++ b/src/main/scala/millfork/assembly/mos/opt/FlowAnalyzerForImplied.scala @@ -15,28 +15,30 @@ object FlowAnalyzerForImplied { RTI -> identity, SEI -> identity, CLI -> identity, - TXS -> identity, - PHP -> identity, - PHA -> identity, - PHA_W -> identity, - PHX -> identity, - PHX_W -> identity, - PHY -> identity, - PHY_W -> identity, - PHZ -> identity, - PHD -> identity, - PHK -> identity, - PHB -> identity, + TXS -> (_.copy(eqSX = true)), + PHP -> (_.copy(eqSX = false)), + PHA -> (_.copy(eqSX = false)), + PHA_W -> (_.copy(eqSX = false)), + PHX -> (_.copy(eqSX = false)), + PHX_W -> (_.copy(eqSX = false)), + PHY -> (_.copy(eqSX = false)), + PHY_W -> (_.copy(eqSX = false)), + PHZ -> (_.copy(eqSX = false)), + PHD -> (_.copy(eqSX = false)), + PHK -> (_.copy(eqSX = false)), + PHB -> (_.copy(eqSX = false)), SED -> (_.copy(d = Status.SingleTrue)), CLD -> (_.copy(d = Status.SingleFalse)), CLC -> (_.copy(c = Status.SingleFalse)), SEC -> (_.copy(c = Status.SingleTrue)), CLV -> (_.copy(v = Status.SingleFalse)), - XCE -> (_.copy(c = AnyStatus, m = AnyStatus, x = AnyStatus)), - PLA -> (_.copy(src = SourceOfNZ.A, a = AnyStatus, n = AnyStatus, z = AnyStatus)), - PLX -> (_.copy(src = SourceOfNZ.X, x = AnyStatus, n = AnyStatus, z = AnyStatus)), - PLY -> (_.copy(src = SourceOfNZ.Y, y = AnyStatus, n = AnyStatus, z = AnyStatus)), - PLZ -> (_.copy(src = SourceOfNZ.Z, iz = AnyStatus, n = AnyStatus, z = AnyStatus)), + XCE -> (_.copy(c = AnyStatus, m = AnyStatus, w = AnyStatus, x = AnyStatus, y = AnyStatus, eqSX = false)), + PLA -> (_.copy(src = SourceOfNZ.A, a = AnyStatus, n = AnyStatus, z = AnyStatus, eqSX = false)), + PLX -> (_.copy(src = SourceOfNZ.X, x = AnyStatus, n = AnyStatus, z = AnyStatus, eqSX = false)), + PLX_W -> (_.copy(src = SourceOfNZ.X, x = AnyStatus, n = AnyStatus, z = AnyStatus, eqSX = false)), + PLY -> (_.copy(src = SourceOfNZ.Y, y = AnyStatus, n = AnyStatus, z = AnyStatus, eqSX = false)), + PLY_W -> (_.copy(src = SourceOfNZ.Y, y = AnyStatus, n = AnyStatus, z = AnyStatus, eqSX = false)), + PLZ -> (_.copy(src = SourceOfNZ.Z, iz = AnyStatus, n = AnyStatus, z = AnyStatus, eqSX = false)), XBA -> (currentStatus => currentStatus.copy( a = currentStatus.ah, a0 = currentStatus.ah.bit0, @@ -51,6 +53,7 @@ object FlowAnalyzerForImplied { n = newX.n(), z = newX.z(), x = newX, + eqSX = false, src = SourceOfNZ.X) }), DEX -> (currentStatus => { @@ -59,6 +62,7 @@ object FlowAnalyzerForImplied { n = newX.n(), z = newX.z(), x = newX, + eqSX = false, src = SourceOfNZ.X) }), INY -> (currentStatus => { @@ -129,6 +133,7 @@ object FlowAnalyzerForImplied { n = AnyStatus, z = newX.z().withHiddenHi, x = newX, + eqSX = false, src = AnyStatus) }), DEX_W -> (currentStatus => { @@ -137,6 +142,7 @@ object FlowAnalyzerForImplied { n = AnyStatus, z = newX.z().withHiddenHi, x = newX, + eqSX = false, src = AnyStatus) }), INY_W -> (currentStatus => { @@ -182,6 +188,7 @@ object FlowAnalyzerForImplied { TAX -> (currentStatus => { currentStatus.copy( x = currentStatus.a, + eqSX = false, n = currentStatus.a.n(), z = currentStatus.a.z(), src = SourceOfNZ.AX) @@ -221,6 +228,7 @@ object FlowAnalyzerForImplied { TYX -> (currentStatus => { currentStatus.copy( x = currentStatus.y, + eqSX = false, n = currentStatus.y.n(), z = currentStatus.y.z(), src = SourceOfNZ.XY) @@ -246,6 +254,7 @@ object FlowAnalyzerForImplied { a = currentStatus.x, a0 = currentStatus.x.bit0, a7 = currentStatus.x.bit7, + eqSX = false, x = currentStatus.a) }), SAY -> (currentStatus => { @@ -258,6 +267,7 @@ object FlowAnalyzerForImplied { SXY -> (currentStatus => { currentStatus.copy( y = currentStatus.x, + eqSX = false, x = currentStatus.y) }), ASL -> (currentStatus => { @@ -362,6 +372,7 @@ object FlowAnalyzerForImplied { TSX -> (currentStatus => { currentStatus.copy( x = AnyStatus, + eqSX = true, src = SourceOfNZ.X) }), ) diff --git a/src/main/scala/millfork/assembly/mos/opt/RuleBasedAssemblyOptimization.scala b/src/main/scala/millfork/assembly/mos/opt/RuleBasedAssemblyOptimization.scala index f7beb8b2..e75955a8 100644 --- a/src/main/scala/millfork/assembly/mos/opt/RuleBasedAssemblyOptimization.scala +++ b/src/main/scala/millfork/assembly/mos/opt/RuleBasedAssemblyOptimization.scala @@ -558,6 +558,14 @@ case class HasSet(state: State.Value) extends AssemblyLinePattern { flowInfo.hasSet(state) } +case object XContainsStackPointer extends AssemblyLinePattern { + override def validate(needsFlowInfo: FlowInfoRequirement.Value): Unit = + FlowInfoRequirement.assertForward(needsFlowInfo) + + override def matchLineTo(ctx: AssemblyMatchingContext, flowInfo: FlowInfo, line: AssemblyLine): Boolean = + flowInfo.statusBefore.eqSX +} + case class HasSourceOfNZ(state: State.Value) extends AssemblyLinePattern { override def validate(needsFlowInfo: FlowInfoRequirement.Value): Unit = FlowInfoRequirement.assertForward(needsFlowInfo)