From 05e147b880eefc5f981373ea9c73cff2b5c8a1b1 Mon Sep 17 00:00:00 2001 From: Karol Stasiak Date: Mon, 5 Mar 2018 12:41:43 +0100 Subject: [PATCH] Removal of detailed flow analysis; it was slow and not worth it --- CHANGELOG.md | 3 + doc/api/command-line.md | 2 - include/c64.ini | 2 +- .../scala/millfork/CompilationOptions.scala | 2 +- src/main/scala/millfork/Main.scala | 3 - .../millfork/assembly/opt/FlowAnalyzer.scala | 6 +- .../assembly/opt/QuantumFlowAnalyzer.scala | 429 ------------------ src/test/scala/millfork/test/ArraySuite.scala | 2 +- .../test/AssemblyOptimizationSuite.scala | 6 +- .../test/emu/EmuNodeOptimizedRun.scala | 3 +- .../test/emu/EmuOptimized65816Run.scala | 3 +- .../test/emu/EmuOptimized65CE02Run.scala | 3 +- .../test/emu/EmuOptimizedCmosRun.scala | 3 +- .../test/emu/EmuOptimizedHudsonRun.scala | 3 +- .../test/emu/EmuOptimizedInlinedRun.scala | 3 +- .../millfork/test/emu/EmuOptimizedRun.scala | 3 +- .../test/emu/EmuQuantumOptimizedRun.scala | 21 - src/test/scala/millfork/test/emu/EmuRun.scala | 3 +- .../emu/EmuSuperOptimizedInliningRun.scala | 5 +- .../emu/EmuSuperQuantumOptimizedRun.scala | 17 - .../test/emu/EmuSuperoptimizedRun.scala | 3 +- .../test/emu/EmuUltraBenchmarkRun.scala | 18 +- .../test/emu/EmuUndocumentedRun.scala | 3 +- .../millfork/test/emu/EmuUnoptimizedRun.scala | 2 +- 24 files changed, 27 insertions(+), 521 deletions(-) delete mode 100644 src/main/scala/millfork/assembly/opt/QuantumFlowAnalyzer.scala delete mode 100644 src/test/scala/millfork/test/emu/EmuQuantumOptimizedRun.scala delete mode 100644 src/test/scala/millfork/test/emu/EmuSuperQuantumOptimizedRun.scala diff --git a/CHANGELOG.md b/CHANGELOG.md index b3730db0..dffab86e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,9 @@ * Added optimizer hints: `inline`, `noinline`, `register`. * Added command line flags `--size`, `--fast`, `--blast-processing`. + +* Removed command line flag `--detailed-flow`. +Detailed flow analysis was slow, broken, hard to maintain, and didn't even help that much. * Added `*'=` and `<<<<` operators. diff --git a/doc/api/command-line.md b/doc/api/command-line.md index b83bce21..c2deb0ac 100644 --- a/doc/api/command-line.md +++ b/doc/api/command-line.md @@ -93,8 +93,6 @@ This may cause problems if the parameter table is stored next to a hardware regi * `--blast-processing` – Optimize for speed, even if it increases the size a lot (experimental). -* `--detailed-flow` – Use detailed flow analysis (experimental). Very computationally expensive and not that great. - * `--dangerous-optimizations` – Use dangerous optimizations (experimental). Dangerous optimizations are more likely to result in broken code. ## Warning options diff --git a/include/c64.ini b/include/c64.ini index d0cbfb03..beb062f0 100644 --- a/include/c64.ini +++ b/include/c64.ini @@ -7,7 +7,7 @@ arch=nmos ; modules to load modules=c64_hardware,loader_0801,c64_kernal,c64_panic,stdlib ; optionally: default flags -emit_illegals=true +emit_illegals=false [allocation] diff --git a/src/main/scala/millfork/CompilationOptions.scala b/src/main/scala/millfork/CompilationOptions.scala index 9da344f6..4fcb6a6b 100644 --- a/src/main/scala/millfork/CompilationOptions.scala +++ b/src/main/scala/millfork/CompilationOptions.scala @@ -121,7 +121,7 @@ object CompilationFlag extends Enumeration { EmitIllegals, EmitCmosOpcodes, EmitCmosNopOpcodes, EmitHudsonOpcodes, Emit65CE02Opcodes, EmitEmulation65816Opcodes, EmitNative65816Opcodes, ZeropagePseudoregister, DecimalMode, ReadOnlyArrays, PreventJmpIndirectBug, LargeCode, ReturnWordsViaAccumulator, // optimization options: - DetailedFlowAnalysis, DangerousOptimizations, InlineFunctions, OptimizeForSize, OptimizeForSpeed, OptimizeForSonicSpeed, + DangerousOptimizations, InlineFunctions, OptimizeForSize, OptimizeForSpeed, OptimizeForSonicSpeed, // memory allocation options VariableOverlap, CompactReturnDispatchParams, // runtime check options diff --git a/src/main/scala/millfork/Main.scala b/src/main/scala/millfork/Main.scala index 75a0c0f1..d8bd0aaa 100644 --- a/src/main/scala/millfork/Main.scala +++ b/src/main/scala/millfork/Main.scala @@ -285,9 +285,6 @@ object Main { c.changeFlag(CompilationFlag.OptimizeForSonicSpeed, true) c.changeFlag(CompilationFlag.InlineFunctions, true) }.description("Prefer faster code even if it is much bigger (experimental). Implies --inline.") - flag("--detailed-flow").action { c => - c.changeFlag(CompilationFlag.DetailedFlowAnalysis, true) - }.description("Use detailed flow analysis (experimental).") flag("--dangerous-optimizations").action { c => c.changeFlag(CompilationFlag.DangerousOptimizations, true) }.description("Use dangerous optimizations (experimental).") diff --git a/src/main/scala/millfork/assembly/opt/FlowAnalyzer.scala b/src/main/scala/millfork/assembly/opt/FlowAnalyzer.scala index 09a4b4d9..8e308c0c 100644 --- a/src/main/scala/millfork/assembly/opt/FlowAnalyzer.scala +++ b/src/main/scala/millfork/assembly/opt/FlowAnalyzer.scala @@ -36,11 +36,7 @@ object FlowAnalyzer { def analyze(f: NormalFunction, code: List[AssemblyLine], options: CompilationOptions, req: FlowInfoRequirement.Value): List[(FlowInfo, AssemblyLine)] = { val forwardFlow = req match { case FlowInfoRequirement.BothFlows | FlowInfoRequirement.ForwardFlow => - if (options.flag(CompilationFlag.DetailedFlowAnalysis)) { - () => QuantumFlowAnalyzer.analyze(f, code).map(_.collapse) - } else { - () => CoarseFlowAnalyzer.analyze(f, code, options) - } + () => CoarseFlowAnalyzer.analyze(f, code, options) case FlowInfoRequirement.BackwardFlow | FlowInfoRequirement.JustLabels | FlowInfoRequirement.NoRequirement => () => List.fill(code.size)(EmptyCpuStatus) } diff --git a/src/main/scala/millfork/assembly/opt/QuantumFlowAnalyzer.scala b/src/main/scala/millfork/assembly/opt/QuantumFlowAnalyzer.scala deleted file mode 100644 index 27d872a5..00000000 --- a/src/main/scala/millfork/assembly/opt/QuantumFlowAnalyzer.scala +++ /dev/null @@ -1,429 +0,0 @@ -package millfork.assembly.opt - -import millfork.assembly.{AssemblyLine, OpcodeClasses} -import millfork.env.{Label, MemoryAddressConstant, NormalFunction, NumericConstant} - -import scala.collection.immutable.BitSet - -/** - * @author Karol Stasiak - */ - -object QCpuStatus { - val InitialStatus = QCpuStatus((for { - c <- Seq(true, false) - v <- Seq(true, false) - n <- Seq(true, false) - z <- Seq(true, false) - } yield QFlagStatus(c = c, d = false, v = v, n = n, z = z) -> QRegStatus(a = QRegStatus.AllValues, x = QRegStatus.AllValues, y = QRegStatus.AllValues, equal = RegEquality.NoEquality)).toMap) - - val UnknownStatus = QCpuStatus((for { - c <- Seq(true, false) - v <- Seq(true, false) - n <- Seq(true, false) - z <- Seq(true, false) - } yield QFlagStatus(c = c, d = false, v = v, n = n, z = z) -> QRegStatus(a = QRegStatus.AllValues, x = QRegStatus.AllValues, y = QRegStatus.AllValues, equal = RegEquality.UnknownEquality)).toMap) - - def gather(l: List[(QFlagStatus, QRegStatus)]) = - QCpuStatus(l.groupBy(_._1). - map { case (k, vs) => k -> vs.map(_._2).reduce(_ ++ _) }. - filterNot(_._2.isEmpty)) -} - -case class QCpuStatus(data: Map[QFlagStatus, QRegStatus]) { - def collapse: CpuStatus = { - val registers = data.values.reduce(_ ++ _) - - def bitset(b: BitSet): Status[Int] = if (b.size == 1) SingleStatus(b.head) else AnyStatus() - - def flag(f: QFlagStatus => Boolean): Status[Boolean] = - if (data.keys.forall(k => f(k))) SingleStatus(true) - else if (data.keys.forall(k => !f(k))) SingleStatus(false) - else AnyStatus() - - CpuStatus( - a = bitset(registers.a), - x = bitset(registers.x), - y = bitset(registers.y), - c = flag(_.c), - d = flag(_.d), - v = flag(_.v), - z = flag(_.z), - n = flag(_.n), - ) - } - - def changeFlagUnconditionally(f: QFlagStatus => QFlagStatus): QCpuStatus = { - QCpuStatus.gather(data.toList.map { case (k, v) => f(k) -> v }) - } - - def changeFlagsInAnUnknownWay(f: QFlagStatus => QFlagStatus, g: QFlagStatus => QFlagStatus): QCpuStatus = { - QCpuStatus.gather(data.toList.flatMap { case (k, v) => List(f(k) -> v, g(k) -> v) }) - } - - def changeFlagsInAnUnknownWay(f: QFlagStatus => QFlagStatus, g: QFlagStatus => QFlagStatus, h: QFlagStatus => QFlagStatus): QCpuStatus = { - QCpuStatus.gather(data.toList.flatMap { case (k, v) => List(f(k) -> v, g(k) -> v, h(k) -> v) }) - } - - def mapRegisters(f: QRegStatus => QRegStatus): QCpuStatus = { - QCpuStatus(data.map { case (k, v) => k -> f(v) }) - } - - def mapRegisters(f: (QFlagStatus, QRegStatus) => QRegStatus): QCpuStatus = { - QCpuStatus(data.map { case (k, v) => k -> f(k, v) }) - } - - def flatMap(f: (QFlagStatus, QRegStatus) => List[(QFlagStatus, QRegStatus)]): QCpuStatus = { - QCpuStatus.gather(data.toList.flatMap { case (k, v) => f(k, v) }) - } - - def changeNZFromA: QCpuStatus = { - QCpuStatus.gather(data.toList.flatMap { case (k, v) => - List( - k.copy(n = false, z = false) -> v.whereA(i => i.toByte > 0), - k.copy(n = true, z = false) -> v.whereA(i => i.toByte < 0), - k.copy(n = false, z = true) -> v.whereA(i => i.toByte == 0)) - }) - } - - def changeNZFromX: QCpuStatus = { - QCpuStatus.gather(data.toList.flatMap { case (k, v) => - List( - k.copy(n = false, z = false) -> v.whereX(i => i.toByte > 0), - k.copy(n = true, z = false) -> v.whereX(i => i.toByte < 0), - k.copy(n = false, z = true) -> v.whereX(i => i.toByte == 0)) - }) - } - - def changeNZFromY: QCpuStatus = { - QCpuStatus.gather(data.toList.flatMap { case (k, v) => - List( - k.copy(n = false, z = false) -> v.whereY(i => i.toByte > 0), - k.copy(n = true, z = false) -> v.whereY(i => i.toByte < 0), - k.copy(n = false, z = true) -> v.whereY(i => i.toByte == 0)) - }) - } - - def ~(that: QCpuStatus): QCpuStatus = QCpuStatus.gather(this.data.toList ++ that.data.toList) -} - -object QRegStatus { - val NoValues: BitSet = BitSet.empty - val AllValues: BitSet = BitSet.fromBitMask(Array(-1L, -1L, -1L, -1L)) - -} - -object RegEquality extends Enumeration { - val NoEquality, AX, AY, XY, AXY, UnknownEquality = Value - - def or(a: Value, b: Value) = { - (a, b) match { - case (UnknownEquality, _) => b - case (_, UnknownEquality) => a - case (NoEquality, _) => NoEquality - case (_, NoEquality) => NoEquality - case (_, _) if a == b => a - case (AXY, _) => b - case (_, AXY) => a - case _ => NoEquality - } - } - - def afterTransfer(a: Value, b: Value) = { - (a, b) match { - case (UnknownEquality, _) => b - case (_, UnknownEquality) => a - case (NoEquality, _) => b - case (_, NoEquality) => a - case (_, _) if a == b => a - case _ => AXY - } - } -} - -case class QRegStatus(a: BitSet, x: BitSet, y: BitSet, equal: RegEquality.Value) { - def isEmpty: Boolean = a.isEmpty || x.isEmpty || y.isEmpty - - def ++(that: QRegStatus) = QRegStatus( - a = a ++ that.a, - x = x ++ that.x, - y = y ++ that.y, - equal = RegEquality.or(equal, that.equal)) - - def afterTransfer(transfer: RegEquality.Value): QRegStatus = - copy(equal = RegEquality.afterTransfer(equal, transfer)) - - def changeA(f: Int => Long): QRegStatus = { - val newA = a.map(i => f(i).toInt & 0xff) - val newEqual = equal match { - case RegEquality.XY => RegEquality.XY - case RegEquality.AXY => RegEquality.XY - case _ => RegEquality.NoEquality - } - QRegStatus(newA, x, y, newEqual) - } - - def changeX(f: Int => Long): QRegStatus = { - val newA = a.map(i => f(i).toInt & 0xff) - val newEqual = equal match { - case RegEquality.XY => RegEquality.XY - case RegEquality.AXY => RegEquality.XY - case _ => RegEquality.NoEquality - } - QRegStatus(newA, x, y, newEqual) - } - - def changeY(f: Int => Long): QRegStatus = { - val newA = a.map(i => f(i).toInt & 0xff) - val newEqual = equal match { - case RegEquality.XY => RegEquality.XY - case RegEquality.AXY => RegEquality.XY - case _ => RegEquality.NoEquality - } - QRegStatus(newA, x, y, newEqual) - } - - def whereA(f: Int => Boolean): QRegStatus = - equal match { - case RegEquality.AXY => - copy(a = a.filter(f), x = x.filter(f), y = y.filter(f)) - case RegEquality.AY => - copy(a = a.filter(f), y = y.filter(f)) - case RegEquality.AX => - copy(a = a.filter(f), x = x.filter(f)) - case _ => - copy(a = a.filter(f)) - } - - def whereX(f: Int => Boolean): QRegStatus = - equal match { - case RegEquality.AXY => - copy(a = a.filter(f), x = x.filter(f), y = y.filter(f)) - case RegEquality.XY => - copy(x = x.filter(f), y = y.filter(f)) - case RegEquality.AX => - copy(a = a.filter(f), x = x.filter(f)) - case _ => - copy(x = x.filter(f)) - } - - def whereY(f: Int => Boolean): QRegStatus = - equal match { - case RegEquality.AXY => - copy(a = a.filter(f), x = x.filter(f), y = y.filter(f)) - case RegEquality.AY => - copy(a = a.filter(f), y = y.filter(f)) - case RegEquality.XY => - copy(x = x.filter(f), y = y.filter(f)) - case _ => - copy(y = y.filter(f)) - } -} - -case class QFlagStatus(c: Boolean, d: Boolean, v: Boolean, z: Boolean, n: Boolean) - -object QuantumFlowAnalyzer { - private def loBit(b: Boolean) = if (b) 1 else 0 - - private def hiBit(b: Boolean) = if (b) 0x80 else 0 - - //noinspection RedundantNewCaseClass - def analyze(f: NormalFunction, code: List[AssemblyLine]): List[QCpuStatus] = { - val flagArray = Array.fill[QCpuStatus](code.length)(QCpuStatus.UnknownStatus) - val codeArray = code.toArray - - var changed = true - while (changed) { - changed = false - var currentStatus: QCpuStatus = if (f.interrupt) QCpuStatus.UnknownStatus else QCpuStatus.UnknownStatus - for (i <- codeArray.indices) { - import millfork.assembly.Opcode._ - import millfork.assembly.AddrMode._ - if (flagArray(i) != currentStatus) { - changed = true - flagArray(i) = currentStatus - } - codeArray(i) match { - case AssemblyLine(LABEL, _, MemoryAddressConstant(Label(l)), _) => - val L = l - currentStatus = codeArray.indices.flatMap(j => codeArray(j) match { - case AssemblyLine(_, _, MemoryAddressConstant(Label(L)), _) => Some(flagArray(j)) - case _ => None - }).fold(QCpuStatus.UnknownStatus)(_ ~ _) - - case AssemblyLine(BCC, _, _, _) => - currentStatus = currentStatus.changeFlagUnconditionally(f => f.copy(c = true)) - case AssemblyLine(BCS, _, _, _) => - currentStatus = currentStatus.changeFlagUnconditionally(f => f.copy(c = false)) - case AssemblyLine(BVS, _, _, _) => - currentStatus = currentStatus.changeFlagUnconditionally(f => f.copy(v = false)) - case AssemblyLine(BVC, _, _, _) => - currentStatus = currentStatus.changeFlagUnconditionally(f => f.copy(v = true)) - case AssemblyLine(BMI, _, _, _) => - currentStatus = currentStatus.changeFlagUnconditionally(f => f.copy(n = false)) - case AssemblyLine(BPL, _, _, _) => - currentStatus = currentStatus.changeFlagUnconditionally(f => f.copy(n = true)) - case AssemblyLine(BEQ, _, _, _) => - currentStatus = currentStatus.changeFlagUnconditionally(f => f.copy(z = false)) - case AssemblyLine(BNE, _, _, _) => - currentStatus = currentStatus.changeFlagUnconditionally(f => f.copy(z = true)) - - case AssemblyLine(SED, _, _, _) => - currentStatus = currentStatus.changeFlagUnconditionally(f => f.copy(d = true)) - case AssemblyLine(SEC, _, _, _) => - currentStatus = currentStatus.changeFlagUnconditionally(f => f.copy(c = true)) - case AssemblyLine(CLD, _, _, _) => - currentStatus = currentStatus.changeFlagUnconditionally(f => f.copy(d = false)) - case AssemblyLine(CLC, _, _, _) => - currentStatus = currentStatus.changeFlagUnconditionally(f => f.copy(c = false)) - case AssemblyLine(CLV, _, _, _) => - currentStatus = currentStatus.changeFlagUnconditionally(f => f.copy(v = false)) - - case AssemblyLine(JSR, _, _, _) => - currentStatus = QCpuStatus.InitialStatus - - case AssemblyLine(LDX, Immediate, NumericConstant(n, _), _) => - currentStatus = currentStatus.mapRegisters(r => r.changeX(_ => n)).changeNZFromX - case AssemblyLine(LDY, Immediate, NumericConstant(n, _), _) => - currentStatus = currentStatus.mapRegisters(r => r.changeY(_ => n)).changeNZFromY - case AssemblyLine(LDA, Immediate, NumericConstant(n, _), _) => - currentStatus = currentStatus.mapRegisters(r => r.changeA(_ => n)).changeNZFromA - case AssemblyLine(LAX, Immediate, NumericConstant(n, _), _) => - currentStatus = currentStatus.mapRegisters(r => r.changeA(_ => n).changeX(_ => n).afterTransfer(RegEquality.AX)).changeNZFromA - - case AssemblyLine(EOR, Immediate, NumericConstant(n, _), _) => - currentStatus = currentStatus.mapRegisters(r => r.changeA(_ ^ n)).changeNZFromA - case AssemblyLine(AND, Immediate, NumericConstant(n, _), _) => - currentStatus = currentStatus.mapRegisters(r => r.changeA(_ & n)).changeNZFromA - case AssemblyLine(ANC, Immediate, NumericConstant(n, _), _) => - currentStatus = currentStatus.mapRegisters(r => r.changeA(_ & n)).changeNZFromA.changeFlagUnconditionally(f => f.copy(c = f.z)) - case AssemblyLine(ORA, Immediate, NumericConstant(n, _), _) => - currentStatus = currentStatus.mapRegisters(r => r.changeA(_ | n)).changeNZFromA - - case AssemblyLine(INX, Implied, _, _) => - currentStatus = currentStatus.mapRegisters(r => r.changeX(_ + 1)).changeNZFromX - case AssemblyLine(DEX, Implied, _, _) => - currentStatus = currentStatus.mapRegisters(r => r.changeX(_ - 1)).changeNZFromX - case AssemblyLine(INY, Implied, _, _) => - currentStatus = currentStatus.mapRegisters(r => r.changeY(_ - 1)).changeNZFromY - case AssemblyLine(DEY, Implied, _, _) => - currentStatus = currentStatus.mapRegisters(r => r.changeY(_ - 1)).changeNZFromY - case AssemblyLine(INC, Implied, _, _) => - currentStatus = currentStatus.mapRegisters(r => r.changeA(_ - 1)).changeNZFromA - case AssemblyLine(DEC, Implied, _, _) => - currentStatus = currentStatus.mapRegisters(r => r.changeA(_ - 1)).changeNZFromA - case AssemblyLine(TAX, _, _, _) => - currentStatus = currentStatus.mapRegisters(r => r.copy(x = r.a).afterTransfer(RegEquality.AX)).changeNZFromX - case AssemblyLine(TXA, _, _, _) => - currentStatus = currentStatus.mapRegisters(r => r.copy(a = r.x).afterTransfer(RegEquality.AX)).changeNZFromA - case AssemblyLine(TAY, _, _, _) => - currentStatus = currentStatus.mapRegisters(r => r.copy(y = r.a).afterTransfer(RegEquality.AY)).changeNZFromY - case AssemblyLine(TYA, _, _, _) => - currentStatus = currentStatus.mapRegisters(r => r.copy(a = r.y).afterTransfer(RegEquality.AY)).changeNZFromA - - case AssemblyLine(ROL, Implied, _, _) => - currentStatus = currentStatus.flatMap((f, r) => List( - f.copy(c = true) -> r.whereA(a => (a & 0x80) != 0).changeA(a => a * 2 + loBit(f.c)), - f.copy(c = false) -> r.whereA(a => (a & 0x80) == 0).changeA(a => a * 2 + loBit(f.c)), - )).changeNZFromA - case AssemblyLine(ROR, Implied, _, _) => - currentStatus = currentStatus.flatMap((f, r) => List( - f.copy(c = true) -> r.whereA(a => (a & 1) != 0).changeA(a => (a >>> 2) & 0x7f | hiBit(f.c)), - f.copy(c = false) -> r.whereA(a => (a & 1) == 0).changeA(a => (a >>> 2) & 0x7f | hiBit(f.c)), - )).changeNZFromA - case AssemblyLine(ASL, Implied, _, _) => - currentStatus = currentStatus.flatMap((f, r) => List( - f.copy(c = true) -> r.whereA(a => (a & 0x80) != 0).changeA(a => a * 2), - f.copy(c = false) -> r.whereA(a => (a & 0x80) == 0).changeA(a => a * 2), - )).changeNZFromA - case AssemblyLine(LSR, Implied, _, _) => - currentStatus = currentStatus.flatMap((f, r) => List( - f.copy(c = true) -> r.whereA(a => (a & 1) != 0).changeA(a => (a >>> 1) & 0x7f), - f.copy(c = false) -> r.whereA(a => (a & 1) == 0).changeA(a => (a >>> 1) & 0x7f), - )).changeNZFromA - case AssemblyLine(ALR, Immediate, NumericConstant(n, _), _) => - currentStatus = currentStatus.flatMap((f, r) => List( - f.copy(c = true) -> r.whereA(a => (a & n & 1) != 0).changeA(a => ((a & n) >>> 2) & 0x7f), - f.copy(c = false) -> r.whereA(a => (a & n & 1) == 0).changeA(a => ((a & n) >>> 2) & 0x7f), - )).changeNZFromA - case AssemblyLine(ADC, Immediate, NumericConstant(nn, _), _) => - val n = nn & 0xff - currentStatus = currentStatus.flatMap((f, r) => - if (f.d) { - val regs = r.copy(a = QRegStatus.AllValues).changeA(_.toLong) - List( - f.copy(c = false, v = false) -> regs, - f.copy(c = true, v = false) -> regs, - f.copy(c = false, v = true) -> regs, - f.copy(c = true, v = true) -> regs, - ) - } else { - if (f.c) { - val regs = r.changeA(_ + n + 1) - List( - f.copy(c = false, v = false) -> regs.whereA(_ >= n), - f.copy(c = true, v = false) -> regs.whereA(_ < n), - f.copy(c = false, v = true) -> regs.whereA(_ >= n), - f.copy(c = true, v = true) -> regs.whereA(_ < n), - ) - } else { - val regs = r.changeA(_ + n) - List( - f.copy(c = false, v = false) -> regs.whereA(_ > n), - f.copy(c = true, v = false) -> regs.whereA(_ <= n), - f.copy(c = false, v = true) -> regs.whereA(_ > n), - f.copy(c = true, v = true) -> regs.whereA(_ <= n), - ) - } - } - ).changeNZFromA - case AssemblyLine(SBC, Immediate, NumericConstant(n, _), _) => - currentStatus = currentStatus.flatMap((f, r) => - if (f.d) { - val regs = r.copy(a = QRegStatus.AllValues).changeA(_.toLong) - // TODO: guess the carry flag correctly - List( - f.copy(c = false, v = false) -> regs, - f.copy(c = true, v = false) -> regs, - f.copy(c = false, v = true) -> regs, - f.copy(c = true, v = true) -> regs, - ) - } else { - val regs = if (f.c) r.changeA(_ - n) else r.changeA(_ - n - 1) - List( - f.copy(c = false, v = false) -> regs, - f.copy(c = true, v = false) -> regs, - f.copy(c = false, v = true) -> regs, - f.copy(c = true, v = true) -> regs, - ) - } - ).changeNZFromA - - case AssemblyLine(opcode, addrMode, parameter, _) => - if (OpcodeClasses.ChangesX(opcode)) currentStatus = currentStatus.mapRegisters(r => r.copy(x = QRegStatus.AllValues)) - if (OpcodeClasses.ChangesY(opcode)) currentStatus = currentStatus.mapRegisters(r => r.copy(y = QRegStatus.AllValues)) - if (OpcodeClasses.ChangesAAlways(opcode)) currentStatus = currentStatus.mapRegisters(r => r.copy(a = QRegStatus.AllValues)) - if (addrMode == Implied && OpcodeClasses.ChangesAIfImplied(opcode)) currentStatus = currentStatus.mapRegisters(r => r.copy(a = QRegStatus.AllValues)) - if (OpcodeClasses.ChangesNAndZ(opcode)) currentStatus = currentStatus.changeFlagsInAnUnknownWay( - _.copy(n = false, z = false), - _.copy(n = true, z = false), - _.copy(n = false, z = true)) - if (OpcodeClasses.ChangesC(opcode)) currentStatus = currentStatus.changeFlagsInAnUnknownWay(_.copy(c = false), _.copy(c = true)) - if (OpcodeClasses.ChangesV(opcode)) currentStatus = currentStatus.changeFlagsInAnUnknownWay(_.copy(v = false), _.copy(v = true)) - if (opcode == CMP || opcode == CPX || opcode == CPY) { - if (addrMode == Immediate) parameter match { - case NumericConstant(0, _) => currentStatus = currentStatus.changeFlagUnconditionally(_.copy(c = true)) - case _ => () - } - } - } - } - // flagArray.zip(codeArray).foreach{ - // case (fl, y) => if (y.isPrintable) println(f"$fl%-32s $y%-32s") - // } - // println("---------------------") - } - - flagArray.toList - } -} diff --git a/src/test/scala/millfork/test/ArraySuite.scala b/src/test/scala/millfork/test/ArraySuite.scala index 382ce33c..bb3bb787 100644 --- a/src/test/scala/millfork/test/ArraySuite.scala +++ b/src/test/scala/millfork/test/ArraySuite.scala @@ -49,7 +49,7 @@ class ArraySuite extends FunSuite with Matchers { } test("Array assignment with offset 1") { - val m = new EmuRun(Cpu.StrictMos, Nil, DangerousOptimizations.All ++ OptimizationPresets.Good, true)( + val m = new EmuRun(Cpu.StrictMos, Nil, DangerousOptimizations.All ++ OptimizationPresets.Good)( """ | array output [8] @$c000 | void main () { diff --git a/src/test/scala/millfork/test/AssemblyOptimizationSuite.scala b/src/test/scala/millfork/test/AssemblyOptimizationSuite.scala index 68c19d10..85ffb5e2 100644 --- a/src/test/scala/millfork/test/AssemblyOptimizationSuite.scala +++ b/src/test/scala/millfork/test/AssemblyOptimizationSuite.scala @@ -112,7 +112,7 @@ class AssemblyOptimizationSuite extends FunSuite with Matchers { } test("LDA-TAY elimination") { - new EmuRun(Cpu.StrictMos, OptimizationPresets.NodeOpt, List(VariableToRegisterOptimization, AlwaysGoodOptimizations.YYY), false)( + new EmuRun(Cpu.StrictMos, OptimizationPresets.NodeOpt, List(VariableToRegisterOptimization, AlwaysGoodOptimizations.YYY))( """ | array mouse_pointer[64] | array arrow[64] @@ -204,7 +204,7 @@ class AssemblyOptimizationSuite extends FunSuite with Matchers { AlwaysGoodOptimizations.PointlessRegisterTransfersBeforeReturn, AlwaysGoodOptimizations.IdempotentDuplicateRemoval, AlwaysGoodOptimizations.IdempotentDuplicateRemoval, - AlwaysGoodOptimizations.IdempotentDuplicateRemoval), false)( + AlwaysGoodOptimizations.IdempotentDuplicateRemoval))( """ | byte output @$C000 | void main(){ delta() } @@ -385,7 +385,7 @@ class AssemblyOptimizationSuite extends FunSuite with Matchers { AlwaysGoodOptimizations.IdempotentDuplicateRemoval, AlwaysGoodOptimizations.IdempotentDuplicateRemoval, AlwaysGoodOptimizations.IdempotentDuplicateRemoval, - AlwaysGoodOptimizations.CommonExpressionInConditional), false)( + AlwaysGoodOptimizations.CommonExpressionInConditional))( """ | byte output @$C000 | void main(){ diff --git a/src/test/scala/millfork/test/emu/EmuNodeOptimizedRun.scala b/src/test/scala/millfork/test/emu/EmuNodeOptimizedRun.scala index f3f65144..1253cbbe 100644 --- a/src/test/scala/millfork/test/emu/EmuNodeOptimizedRun.scala +++ b/src/test/scala/millfork/test/emu/EmuNodeOptimizedRun.scala @@ -11,5 +11,4 @@ object EmuNodeOptimizedRun extends EmuRun( List( UnreachableCode, UnusedLocalVariables), - Nil, - false) \ No newline at end of file + Nil) \ No newline at end of file diff --git a/src/test/scala/millfork/test/emu/EmuOptimized65816Run.scala b/src/test/scala/millfork/test/emu/EmuOptimized65816Run.scala index 134eb254..e47e32d6 100644 --- a/src/test/scala/millfork/test/emu/EmuOptimized65816Run.scala +++ b/src/test/scala/millfork/test/emu/EmuOptimized65816Run.scala @@ -14,8 +14,7 @@ object EmuOptimized65816Run extends EmuRun( CmosOptimizations.All ++ SixteenOptimizations.All ++ OptimizationPresets.Good ++ CmosOptimizations.All ++ SixteenOptimizations.All ++ OptimizationPresets.Good ++ CmosOptimizations.All ++ SixteenOptimizations.All ++ OptimizationPresets.Good ++ - CmosOptimizations.All ++ SixteenOptimizations.All ++ OptimizationPresets.Good, - false) + CmosOptimizations.All ++ SixteenOptimizations.All ++ OptimizationPresets.Good) diff --git a/src/test/scala/millfork/test/emu/EmuOptimized65CE02Run.scala b/src/test/scala/millfork/test/emu/EmuOptimized65CE02Run.scala index 442fcb58..891f26b6 100644 --- a/src/test/scala/millfork/test/emu/EmuOptimized65CE02Run.scala +++ b/src/test/scala/millfork/test/emu/EmuOptimized65CE02Run.scala @@ -12,8 +12,7 @@ object EmuOptimized65CE02Run extends EmuRun( OptimizationPresets.AssOpt ++ CmosOptimizations.All ++ CE02Optimizations.All ++ OptimizationPresets.Good ++ CmosOptimizations.All ++ CE02Optimizations.All ++ OptimizationPresets.Good ++ - CmosOptimizations.All ++ CE02Optimizations.All ++ OptimizationPresets.Good, - false) + CmosOptimizations.All ++ CE02Optimizations.All ++ OptimizationPresets.Good) diff --git a/src/test/scala/millfork/test/emu/EmuOptimizedCmosRun.scala b/src/test/scala/millfork/test/emu/EmuOptimizedCmosRun.scala index 17ce76a1..9e841834 100644 --- a/src/test/scala/millfork/test/emu/EmuOptimizedCmosRun.scala +++ b/src/test/scala/millfork/test/emu/EmuOptimizedCmosRun.scala @@ -14,8 +14,7 @@ object EmuOptimizedCmosRun extends EmuRun( CmosOptimizations.All ++ OptimizationPresets.Good ++ CmosOptimizations.All ++ OptimizationPresets.Good ++ ZeropageRegisterOptimizations.All ++ - CmosOptimizations.All ++ OptimizationPresets.Good, - false) + CmosOptimizations.All ++ OptimizationPresets.Good) diff --git a/src/test/scala/millfork/test/emu/EmuOptimizedHudsonRun.scala b/src/test/scala/millfork/test/emu/EmuOptimizedHudsonRun.scala index 76f403a5..f41d465c 100644 --- a/src/test/scala/millfork/test/emu/EmuOptimizedHudsonRun.scala +++ b/src/test/scala/millfork/test/emu/EmuOptimizedHudsonRun.scala @@ -12,8 +12,7 @@ object EmuOptimizedHudsonRun extends EmuRun( OptimizationPresets.AssOpt ++ CmosOptimizations.All ++ HudsonOptimizations.All ++ OptimizationPresets.Good ++ CmosOptimizations.All ++ HudsonOptimizations.All ++ OptimizationPresets.Good ++ - CmosOptimizations.All ++ HudsonOptimizations.All ++ OptimizationPresets.Good, - false) + CmosOptimizations.All ++ HudsonOptimizations.All ++ OptimizationPresets.Good) diff --git a/src/test/scala/millfork/test/emu/EmuOptimizedInlinedRun.scala b/src/test/scala/millfork/test/emu/EmuOptimizedInlinedRun.scala index 31dd40af..cb3c9c50 100644 --- a/src/test/scala/millfork/test/emu/EmuOptimizedInlinedRun.scala +++ b/src/test/scala/millfork/test/emu/EmuOptimizedInlinedRun.scala @@ -14,8 +14,7 @@ object EmuOptimizedInlinedRun extends EmuRun( OptimizationPresets.Good ++ LaterOptimizations.Nmos ++ OptimizationPresets.Good ++ LaterOptimizations.Nmos ++ ZeropageRegisterOptimizations.All ++ - OptimizationPresets.Good, - false) { + OptimizationPresets.Good) { override def inline: Boolean = true override def blastProcessing: Boolean = false } diff --git a/src/test/scala/millfork/test/emu/EmuOptimizedRun.scala b/src/test/scala/millfork/test/emu/EmuOptimizedRun.scala index e4632471..29e5bde9 100644 --- a/src/test/scala/millfork/test/emu/EmuOptimizedRun.scala +++ b/src/test/scala/millfork/test/emu/EmuOptimizedRun.scala @@ -14,8 +14,7 @@ object EmuOptimizedRun extends EmuRun( OptimizationPresets.Good ++ LaterOptimizations.Nmos ++ OptimizationPresets.Good ++ LaterOptimizations.Nmos ++ ZeropageRegisterOptimizations.All ++ - OptimizationPresets.Good, - false) + OptimizationPresets.Good) diff --git a/src/test/scala/millfork/test/emu/EmuQuantumOptimizedRun.scala b/src/test/scala/millfork/test/emu/EmuQuantumOptimizedRun.scala deleted file mode 100644 index 731956bf..00000000 --- a/src/test/scala/millfork/test/emu/EmuQuantumOptimizedRun.scala +++ /dev/null @@ -1,21 +0,0 @@ -package millfork.test.emu - -import millfork.assembly.opt.{LaterOptimizations, ZeropageRegisterOptimizations} -import millfork.{Cpu, OptimizationPresets} - -/** - * @author Karol Stasiak - */ -object EmuQuantumOptimizedRun extends EmuRun( - Cpu.StrictMos, - OptimizationPresets.NodeOpt, - OptimizationPresets.AssOpt ++ - ZeropageRegisterOptimizations.All ++ - OptimizationPresets.Good ++ LaterOptimizations.Nmos ++ - OptimizationPresets.Good ++ LaterOptimizations.Nmos ++ - ZeropageRegisterOptimizations.All ++ - OptimizationPresets.Good, - true) - - - diff --git a/src/test/scala/millfork/test/emu/EmuRun.scala b/src/test/scala/millfork/test/emu/EmuRun.scala index aff9be38..cdb4c0c5 100644 --- a/src/test/scala/millfork/test/emu/EmuRun.scala +++ b/src/test/scala/millfork/test/emu/EmuRun.scala @@ -24,7 +24,7 @@ import scala.collection.JavaConverters._ */ case class Timings(nmos: Long, cmos: Long) -class EmuRun(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimization], assemblyOptimizations: List[AssemblyOptimization], quantum: Boolean) extends Matchers { +class EmuRun(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimization], assemblyOptimizations: List[AssemblyOptimization]) extends Matchers { def apply(source: String): MemoryBank = { apply2(source)._2 @@ -98,7 +98,6 @@ class EmuRun(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimization], val platform = EmuPlatform.get(cpu) val options = CompilationOptions(platform, Map( CompilationFlag.EmitIllegals -> this.emitIllegals, - CompilationFlag.DetailedFlowAnalysis -> quantum, CompilationFlag.InlineFunctions -> this.inline, CompilationFlag.CompactReturnDispatchParams -> true, CompilationFlag.ZeropagePseudoregister -> true, diff --git a/src/test/scala/millfork/test/emu/EmuSuperOptimizedInliningRun.scala b/src/test/scala/millfork/test/emu/EmuSuperOptimizedInliningRun.scala index 98139190..0b582694 100644 --- a/src/test/scala/millfork/test/emu/EmuSuperOptimizedInliningRun.scala +++ b/src/test/scala/millfork/test/emu/EmuSuperOptimizedInliningRun.scala @@ -6,11 +6,10 @@ import millfork.{Cpu, OptimizationPresets} /** * @author Karol Stasiak */ -object EmuSuperQuantumOptimizedInliningRun extends EmuRun( +object EmuSuperOptimizedInliningRun extends EmuRun( Cpu.StrictMos, OptimizationPresets.NodeOpt, - List(SuperOptimizer), - true) { + List(SuperOptimizer)) { override def inline = true } diff --git a/src/test/scala/millfork/test/emu/EmuSuperQuantumOptimizedRun.scala b/src/test/scala/millfork/test/emu/EmuSuperQuantumOptimizedRun.scala deleted file mode 100644 index fdf03635..00000000 --- a/src/test/scala/millfork/test/emu/EmuSuperQuantumOptimizedRun.scala +++ /dev/null @@ -1,17 +0,0 @@ -package millfork.test.emu - -import millfork.assembly.opt.SuperOptimizer -import millfork.{Cpu, OptimizationPresets} - -/** - * @author Karol Stasiak - */ -// TODO : it doesn't work -object EmuSuperQuantumOptimizedRun extends EmuRun( - Cpu.StrictMos, - OptimizationPresets.NodeOpt, - List(SuperOptimizer), - true) - - - diff --git a/src/test/scala/millfork/test/emu/EmuSuperoptimizedRun.scala b/src/test/scala/millfork/test/emu/EmuSuperoptimizedRun.scala index f39d8c24..df8baf65 100644 --- a/src/test/scala/millfork/test/emu/EmuSuperoptimizedRun.scala +++ b/src/test/scala/millfork/test/emu/EmuSuperoptimizedRun.scala @@ -9,8 +9,7 @@ import millfork.{Cpu, OptimizationPresets} object EmuSuperOptimizedRun extends EmuRun( Cpu.StrictMos, OptimizationPresets.NodeOpt, - List(SuperOptimizer), - false) + List(SuperOptimizer)) diff --git a/src/test/scala/millfork/test/emu/EmuUltraBenchmarkRun.scala b/src/test/scala/millfork/test/emu/EmuUltraBenchmarkRun.scala index 3fc03220..36773caa 100644 --- a/src/test/scala/millfork/test/emu/EmuUltraBenchmarkRun.scala +++ b/src/test/scala/millfork/test/emu/EmuUltraBenchmarkRun.scala @@ -11,22 +11,16 @@ object EmuUltraBenchmarkRun { val (Timings(t1, _), m1) = EmuOptimizedRun.apply2(source) val (Timings(ti, _), mi) = EmuOptimizedInlinedRun.apply2(source) val (Timings(t2, _), m2) = EmuSuperOptimizedRun.apply2(source) - val (Timings(t3, _), m3) = EmuQuantumOptimizedRun.apply2(source) - val (Timings(t4, _), m4) = EmuSuperQuantumOptimizedRun.apply2(source) - val (Timings(t5, _), m5) = EmuSuperQuantumOptimizedInliningRun.apply2(source) + val (Timings(t5, _), m5) = EmuSuperOptimizedInliningRun.apply2(source) println(f"Before optimization: $t0%7d") println(f"After optimization: $t1%7d") println(f"After inlining: $ti%7d") println(f"After superopt.: $t2%7d") - println(f"After quantum: $t3%7d") - println(f"After superquantum: $t4%7d") - println(f"After SQ+inlining: $t5%7d") + println(f"After super. + inl.: $t5%7d") println(f"Gain: ${(100L*(t0-t1)/t0.toDouble).round}%7d%%") println(f"Inlining gain: ${(100L*(t0-ti)/t0.toDouble).round}%7d%%") println(f"Superopt. gain: ${(100L*(t0-t2)/t0.toDouble).round}%7d%%") - println(f"Quantum gain: ${(100L*(t0-t3)/t0.toDouble).round}%7d%%") - println(f"Super quantum gain: ${(100L*(t0-t4)/t0.toDouble).round}%7d%%") - println(f"SQ+inlining gain: ${(100L*(t0-t5)/t0.toDouble).round}%7d%%") + println(f"Super. + inl. gain: ${(100L*(t0-t5)/t0.toDouble).round}%7d%%") println(f"Running unoptimized") verifier(m0) println(f"Running optimized") @@ -35,11 +29,7 @@ object EmuUltraBenchmarkRun { verifier(mi) println(f"Running superoptimized") verifier(m2) - println(f"Running quantum optimized") - verifier(m3) - println(f"Running superquantum optimized") - verifier(m4) - println(f"Running superquantum optimized inlined") + println(f"Running superoptimized inlined") verifier(m5) } } diff --git a/src/test/scala/millfork/test/emu/EmuUndocumentedRun.scala b/src/test/scala/millfork/test/emu/EmuUndocumentedRun.scala index c68d37a3..fd222ae4 100644 --- a/src/test/scala/millfork/test/emu/EmuUndocumentedRun.scala +++ b/src/test/scala/millfork/test/emu/EmuUndocumentedRun.scala @@ -13,8 +13,7 @@ object EmuUndocumentedRun extends EmuRun( UndocumentedOptimizations.All ++ OptimizationPresets.Good ++ LaterOptimizations.Nmos ++ UndocumentedOptimizations.All ++ - OptimizationPresets.Good, - false) { + OptimizationPresets.Good) { override def emitIllegals = true } diff --git a/src/test/scala/millfork/test/emu/EmuUnoptimizedRun.scala b/src/test/scala/millfork/test/emu/EmuUnoptimizedRun.scala index 71af4c70..c565226d 100644 --- a/src/test/scala/millfork/test/emu/EmuUnoptimizedRun.scala +++ b/src/test/scala/millfork/test/emu/EmuUnoptimizedRun.scala @@ -6,4 +6,4 @@ import millfork.Cpu /** * @author Karol Stasiak */ -object EmuUnoptimizedRun extends EmuRun(Cpu.StrictMos, Nil, Nil, false) \ No newline at end of file +object EmuUnoptimizedRun extends EmuRun(Cpu.StrictMos, Nil, Nil) \ No newline at end of file