1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-06-12 06:29:34 +00:00

Removal of detailed flow analysis; it was slow and not worth it

This commit is contained in:
Karol Stasiak 2018-03-05 12:41:43 +01:00
parent 15dbaad6d1
commit 05e147b880
24 changed files with 27 additions and 521 deletions

View File

@ -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.

View File

@ -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

View File

@ -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]

View File

@ -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

View File

@ -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).")

View File

@ -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)
}

View File

@ -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
}
}

View File

@ -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 () {

View File

@ -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(){

View File

@ -11,5 +11,4 @@ object EmuNodeOptimizedRun extends EmuRun(
List(
UnreachableCode,
UnusedLocalVariables),
Nil,
false)
Nil)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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
}

View File

@ -14,8 +14,7 @@ object EmuOptimizedRun extends EmuRun(
OptimizationPresets.Good ++ LaterOptimizations.Nmos ++
OptimizationPresets.Good ++ LaterOptimizations.Nmos ++
ZeropageRegisterOptimizations.All ++
OptimizationPresets.Good,
false)
OptimizationPresets.Good)

View File

@ -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)

View File

@ -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,

View File

@ -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
}

View File

@ -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)

View File

@ -9,8 +9,7 @@ import millfork.{Cpu, OptimizationPresets}
object EmuSuperOptimizedRun extends EmuRun(
Cpu.StrictMos,
OptimizationPresets.NodeOpt,
List(SuperOptimizer),
false)
List(SuperOptimizer))

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -6,4 +6,4 @@ import millfork.Cpu
/**
* @author Karol Stasiak
*/
object EmuUnoptimizedRun extends EmuRun(Cpu.StrictMos, Nil, Nil, false)
object EmuUnoptimizedRun extends EmuRun(Cpu.StrictMos, Nil, Nil)