1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-07-05 09:28:54 +00:00

Optimization improvements:

– better zeropage register flow tracking
– reverse flow analysis speed improvement
– optimize TXA/TAX after LAX
– don't stash A onto stack over externally linear code blocks
This commit is contained in:
Karol Stasiak 2018-06-19 14:23:24 +02:00
parent 5ee9fd85ce
commit 816bfb5f06
6 changed files with 370 additions and 152 deletions

View File

@ -508,6 +508,13 @@ object AlwaysGoodOptimizations {
(Elidable & HasOpcode(PLY)) ~~> { code =>
code.head :: (code.drop(2).init :+ code.head)
},
(Elidable & HasOpcode(LDA) & MatchAddrMode(0) & MatchParameter(1)) ~
(Elidable & HasOpcode(PHA)) ~
(Not(ConcernsStack) & DoesntChangeIndexingInAddrMode(0) & DoesntChangeMemoryAt(0, 1)).*.capture(2) ~
Where(ctx => ctx.isExternallyLinearBlock(2))~
(Elidable & HasOpcode(PLA)) ~~> { code =>
code.head :: (code.drop(2).init :+ code.head)
},
)
val IncrementingIndexRegistersAfterTransfer = new RuleBasedAssemblyOptimization("Incrementing index registers after transfer",
@ -839,7 +846,7 @@ object AlwaysGoodOptimizations {
HasOpcode(TAX) ~ (Elidable & Set(TXA, TAX)) ~~> (_.init),
HasOpcode(TSX) ~ (Elidable & Set(TXS, TSX)) ~~> (_.init),
HasOpcode(TXS) ~ (Elidable & Set(TXS, TSX)) ~~> (_.init),
HasOpcodeIn(Set(TXA, TAX)) ~
HasOpcodeIn(Set(TXA, TAX, LAX, LXA)) ~
(Linear & Not(ChangesNAndZ) & Not(ChangesA) & Not(ChangesX)).* ~
(Elidable & HasOpcodeIn(Set(TXA, TAX))) ~~> (_.init),
HasOpcodeIn(Set(TYA, TAY)) ~
@ -1079,7 +1086,7 @@ object AlwaysGoodOptimizations {
(HasOpcode(LABEL) & MatchParameter(3) & HasCallerCount(1)) ~
(Elidable & HasOpcode(LDA) & MatchAddrMode(0) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~~> (_.init),
HasOpcodeIn(Set(TXA, TAX)) ~
HasOpcodeIn(Set(TXA, TAX, LAX, LXA)) ~
(Not(Set(TXA, TAX)) & Linear & Not(ChangesA) & Not(ChangesX)).* ~
(Elidable & HasOpcodeIn(Set(TXA, TAX)) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~~> (_.init),

View File

@ -92,9 +92,30 @@ case class CpuImportance(a: Importance = UnknownImportance,
object ReverseFlowAnalyzer {
val aluAdders = Set(Opcode.ADC, Opcode.SBC, Opcode.ISC, Opcode.DCP, Opcode.ADC_W, Opcode.SBC_W)
val actuallyRead = Set(AddrMode.IndexedZ, AddrMode.IndexedSY, AddrMode.IndexedY, AddrMode.LongIndexedY, AddrMode.LongIndexedZ, AddrMode.IndexedX, AddrMode.Indirect, AddrMode.AbsoluteIndexedX)
val absoluteLike = Set(AddrMode.ZeroPage, AddrMode.Absolute, AddrMode.LongAbsolute)
private val aluAdders = Set(Opcode.ADC, Opcode.SBC, Opcode.ISC, Opcode.DCP, Opcode.ADC_W, Opcode.SBC_W)
private val actuallyRead = Set(AddrMode.IndexedZ, AddrMode.IndexedSY, AddrMode.IndexedY, AddrMode.LongIndexedY, AddrMode.LongIndexedZ, AddrMode.IndexedX, AddrMode.Indirect, AddrMode.AbsoluteIndexedX)
private val absoluteLike = Set(AddrMode.ZeroPage, AddrMode.Absolute, AddrMode.LongAbsolute)
private val importanceBeforeJsr: CpuImportance = CpuImportance(
a = Unimportant,
ah = Unimportant,
x = Unimportant,
y = Unimportant,
iz = Unimportant,
z = Unimportant,
n = Unimportant,
c = Unimportant,
v = Unimportant,
d = Important,
m = Important,
w = Important,
r0 = Unimportant,
r1 = Unimportant)
private val finalImportance: CpuImportance = CpuImportance(
a = Important, ah = Important,
x = Important, y = Important, iz = Important,
c = Important, v = Important, d = Important, z = Important, n = Important,
m = Important, w = Important,
r0 = Important, r1 = Important)
//noinspection RedundantNewCaseClass
def analyze(f: NormalFunction, code: List[AssemblyLine]): List[CpuImportance] = {
@ -102,16 +123,10 @@ object ReverseFlowAnalyzer {
val codeArray = code.toArray
var changed = true
val finalImportance = new CpuImportance(
a = Important, ah = Important,
x = Important, y = Important, iz = Important,
c = Important, v = Important, d = Important, z = Important, n = Important,
m = Important, w = Important,
r0 = Important, r1 = Important)
changed = true
while (changed) {
changed = false
var currentImportance: CpuImportance = finalImportance
var currentImportance = finalImportance
for (i <- codeArray.indices.reverse) {
import millfork.assembly.mos.Opcode._
import AddrMode._
@ -134,21 +149,7 @@ object ReverseFlowAnalyzer {
case AssemblyLine(JSR | JMP, Absolute | LongAbsolute, MemoryAddressConstant(fun: FunctionInMemory), _) =>
// this case has to be handled first, because the generic JSR importance handler is too conservative
var result = new CpuImportance(
a = Unimportant,
ah = Unimportant,
x = Unimportant,
y = Unimportant,
iz = Unimportant,
z = Unimportant,
n = Unimportant,
c = Unimportant,
v = Unimportant,
d = Important,
m = Important,
w = Important,
r0 = Unimportant,
r1 = Unimportant)
var result = importanceBeforeJsr
fun.params match {
case AssemblyParamSignature(params) =>
params.foreach(_.variable match {
@ -180,7 +181,10 @@ object ReverseFlowAnalyzer {
case AssemblyLine(AND, _, NumericConstant(0, _), _) =>
currentImportance = currentImportance.copy(n = Unimportant, z = Unimportant, a = Unimportant)
case AssemblyLine(opcode, addrMode, _, _) if ReverseFlowAnalyzerPerOpcode.hasDefinition(opcode) =>
case AssemblyLine(opcode, Implied, _, _) if ReverseFlowAnalyzerPerImpiedOpcode.hasDefinition(opcode) =>
currentImportance = ReverseFlowAnalyzerPerImpiedOpcode.get(opcode)(currentImportance)
case AssemblyLine(opcode, addrMode, _, _) if addrMode != Implied && ReverseFlowAnalyzerPerOpcode.hasDefinition(opcode) =>
currentImportance = ReverseFlowAnalyzerPerOpcode.get(opcode)(currentImportance)
if (addrMode == AbsoluteX || addrMode == LongAbsoluteX || addrMode == IndexedX || addrMode == ZeroPageX || addrMode == AbsoluteIndexedX)
currentImportance = currentImportance.copy(x = Important)
@ -275,7 +279,7 @@ object ReverseFlowAnalyzer {
if th.name == "__reg" => currentImportance = currentImportance.copy(r0 = Important, r1 = Important)
case _ => ()
}
} else if (OpcodeClasses.ReadsM(currentLine.opcode) || OpcodeClasses.ReadsMemoryIfNotImpliedOrImmediate(currentLine.opcode)) {
} else if (OpcodeClasses.ReadsMemoryIfNotImpliedOrImmediate(currentLine.opcode)) {
if (OpcodeClasses.AccessesWordInMemory(currentLine.opcode)) {
currentLine.parameter match {
case MemoryAddressConstant(th: Thing)
@ -294,10 +298,10 @@ object ReverseFlowAnalyzer {
}
}
}
// importanceArray.zip(codeArray).foreach{
// case (i, y) => if (y.isPrintable) println(f"$y%-32s $i%-32s")
// }
// println("---------------------")
// importanceArray.zip(codeArray).foreach{
// case (i, y) => if (y.isPrintable) println(f"$y%-32s $i%-32s")
// }
// println("---------------------")
importanceArray.toList
}

View File

@ -0,0 +1,182 @@
package millfork.assembly.mos.opt
import millfork.assembly.mos.Opcode
import millfork.assembly.mos.Opcode._
/**
* @author Karol Stasiak
*/
object ReverseFlowAnalyzerPerImpiedOpcode {
private val finalImportance = CpuImportance(
a = Important, ah = Important,
x = Important, y = Important, iz = Important,
c = Important, v = Important, d = Important, z = Important, n = Important,
m = Important, w = Important)
private def allAddingOutputsUnimportant(currentImportance: CpuImportance): Boolean =
currentImportance.a == Unimportant &&
currentImportance.c == Unimportant &&
currentImportance.z == Unimportant &&
currentImportance.n == Unimportant &&
currentImportance.v == Unimportant
private def allLoadingAccuOutputsUnimportant(currentImportance: CpuImportance): Boolean =
currentImportance.a == Unimportant &&
currentImportance.z == Unimportant &&
currentImportance.n == Unimportant
private def allCompareOutputsAreUnimportant(currentImportance: CpuImportance): Boolean =
currentImportance.z == Unimportant &&
currentImportance.n == Unimportant&&
currentImportance.c == Unimportant
private val map: Map[Opcode.Value, CpuImportance => CpuImportance] = Map(
NOP -> identity,
SEI -> identity,
CLI -> identity,
WAI -> identity,
STP -> identity,
BRK -> (_ => finalImportance),
COP -> (_ => finalImportance),
RTS -> (_ => finalImportance),
RTL -> (_ => finalImportance),
RTI -> (_ => CpuImportance(
a = Unimportant, ah = Unimportant,
x = Unimportant, y = Unimportant, iz = Unimportant,
z = Unimportant, n = Unimportant, c = Unimportant, v = Unimportant, d = Unimportant,
m = Unimportant, w = Unimportant)),
TAX -> (currentImportance => {
currentImportance.copy(
a = currentImportance.x ~ currentImportance.a ~ currentImportance.n ~ currentImportance.z,
x = Unimportant,
n = Unimportant, z = Unimportant, m = Important, w = Important)
}),
TAY -> (currentImportance => {
currentImportance.copy(
a = currentImportance.y ~ currentImportance.a ~ currentImportance.n ~ currentImportance.z,
y = Unimportant,
n = Unimportant, z = Unimportant, m = Important, w = Important)
}),
TXA -> (currentImportance => {
currentImportance.copy(
x = currentImportance.a ~ currentImportance.x ~ currentImportance.n ~ currentImportance.z,
a = Unimportant,
n = Unimportant, z = Unimportant, m = Important, w = Important)
}),
TYA -> (currentImportance => {
currentImportance.copy(
y = currentImportance.a ~ currentImportance.y ~ currentImportance.n ~ currentImportance.z,
a = Unimportant,
n = Unimportant, z = Unimportant, m = Important, w = Important)
}),
TAZ -> (currentImportance => {
currentImportance.copy(
a = currentImportance.iz ~ currentImportance.a ~ currentImportance.n ~ currentImportance.z,
iz = Unimportant,
n = Unimportant, z = Unimportant, m = Important, w = Important)
}),
TZA -> (currentImportance => {
currentImportance.copy(
iz = currentImportance.a ~ currentImportance.iz ~ currentImportance.n ~ currentImportance.z,
a = Unimportant,
n = Unimportant, z = Unimportant, m = Important, w = Important)
}),
TXY -> (currentImportance => {
currentImportance.copy(
x = currentImportance.y ~ currentImportance.x ~ currentImportance.n ~ currentImportance.z,
y = Unimportant,
n = Unimportant, z = Unimportant, m = Important, w = Important)
}),
TYX -> (currentImportance => {
currentImportance.copy(
y = currentImportance.x ~ currentImportance.y ~ currentImportance.n ~ currentImportance.z,
x = Unimportant,
n = Unimportant, z = Unimportant, m = Important, w = Important)
}),
TSX -> (_.copy(x = Unimportant, n = Unimportant, z = Unimportant, w = Important)),
TXS -> (_.copy(x = Important, w = Important)),
XBA -> (currentImportance => {
currentImportance.copy(
ah = currentImportance.a ~ currentImportance.iz ~ currentImportance.n ~ currentImportance.z,
a = currentImportance.ah,
n = Unimportant, z = Unimportant)
}),
TCD -> (_.copy(a = Important, ah = Important)),
TDC -> (_.copy(a = Unimportant, ah = Unimportant, n = Unimportant, z = Unimportant)),
TCS -> (_.copy(a = Important, ah = Important)),
TSC -> (_.copy(a = Unimportant, ah = Unimportant, n = Unimportant, z = Unimportant)),
TRB -> (_.copy(a = Important, z = Unimportant, m = Important)),
TSB -> (_.copy(a = Important, z = Unimportant, m = Important)),
HuSAX -> (currentImportance => {
currentImportance.copy(a = currentImportance.x, x = currentImportance.a, m = Important, w = Important)
}),
SAY -> (currentImportance => {
currentImportance.copy(y = currentImportance.a, a = currentImportance.y, m = Important, w = Important)
}),
SXY -> (currentImportance => {
currentImportance.copy(y = currentImportance.x, x = currentImportance.y, m = Important, w = Important)
}),
ASL -> (_.copy(a = Important, c = Unimportant, n = Unimportant, z = Unimportant, m = Important)),
LSR -> (_.copy(a = Important, c = Unimportant, n = Unimportant, z = Unimportant, m = Important)),
ROL -> (_.copy(a = Important, c = Important, n = Unimportant, z = Unimportant, m = Important)),
ROR -> (_.copy(a = Important, c = Important, n = Unimportant, z = Unimportant, m = Important)),
ASL_W -> (_.copy(a = Important, ah = Important, c = Unimportant, n = Unimportant, z = Unimportant, m = Important)),
LSR_W -> (_.copy(a = Important, ah = Important, c = Unimportant, n = Unimportant, z = Unimportant, m = Important)),
ROL_W -> (_.copy(a = Important, ah = Important, c = Important, n = Unimportant, z = Unimportant, m = Important)),
ROR_W -> (_.copy(a = Important, ah = Important, c = Important, n = Unimportant, z = Unimportant, m = Important)),
DEC -> (_.copy(a = Important, n = Unimportant, z = Unimportant, m = Important)),
DEX -> (_.copy(x = Important, n = Unimportant, z = Unimportant, w = Important)),
DEY -> (_.copy(y = Important, n = Unimportant, z = Unimportant, w = Important)),
DEZ -> (_.copy(iz = Important, n = Unimportant, z = Unimportant)),
INC -> (_.copy(a = Important, n = Unimportant, z = Unimportant, m = Important)),
INX -> (_.copy(x = Important, n = Unimportant, z = Unimportant, w = Important)),
INY -> (_.copy(y = Important, n = Unimportant, z = Unimportant, w = Important)),
INZ -> (_.copy(iz = Important, n = Unimportant, z = Unimportant)),
DEC_W -> (_.copy(a = Important, ah = Important, n = Unimportant, z = Unimportant, m = Important)),
DEX_W -> (_.copy(x = Important, n = Unimportant, z = Unimportant, w = Important)),
DEY_W -> (_.copy(y = Important, n = Unimportant, z = Unimportant, w = Important)),
INC_W -> (_.copy(x = Important, ah = Important, n = Unimportant, z = Unimportant, m = Important)),
INX_W -> (_.copy(x = Important, n = Unimportant, z = Unimportant, w = Important)),
INY_W -> (_.copy(y = Important, n = Unimportant, z = Unimportant, w = Important)),
PHP -> (_.copy(n = Important, c = Important, d = Important, z = Important, v = Important, m = Important, w = Important)),
PLP -> (_.copy(n = Unimportant, c = Unimportant, d = Unimportant, z = Unimportant, v = Unimportant, m = Unimportant, w = Unimportant)),
PHA -> (_.copy(a = Important, m = Important)),
PLA -> (_.copy(a = Unimportant, m = Important, n = Unimportant, z = Unimportant)),
PHX -> (_.copy(x = Important, w = Important)),
PLX -> (_.copy(x = Unimportant, w = Important, n = Unimportant, z = Unimportant)),
PHY -> (_.copy(y = Important, w = Important)),
PLY -> (_.copy(y = Unimportant, w = Important, n = Unimportant, z = Unimportant)),
PHZ -> (_.copy(iz = Important, w = Important)),
PLZ -> (_.copy(iz = Unimportant, w = Important, n = Unimportant, z = Unimportant)),
PHA_W -> (_.copy(a = Important, ah = Important, m = Important)),
PLA_W -> (_.copy(a = Unimportant, ah = Unimportant, m = Important, n = Unimportant, z = Unimportant)),
PHX_W -> (_.copy(x = Important, w = Important)),
PLX_W -> (_.copy(x = Unimportant, w = Important, n = Unimportant, z = Unimportant)),
PHY_W -> (_.copy(y = Important, w = Important)),
PLY_W -> (_.copy(y = Unimportant, w = Important, n = Unimportant, z = Unimportant)),
CLC -> (_.copy(c = Unimportant)),
SEC -> (_.copy(c = Unimportant)),
CLD -> (_.copy(d = Unimportant)),
SED -> (_.copy(d = Unimportant)),
CLV -> (_.copy(v = Unimportant)),
)
def hasDefinition(opcode: Opcode.Value): Boolean = map.contains(opcode)
def get(opcode: Opcode.Value): CpuImportance => CpuImportance = map(opcode)
}

View File

@ -26,25 +26,20 @@ object ReverseFlowAnalyzerPerOpcode {
currentImportance.z == Unimportant &&
currentImportance.n == Unimportant
private def allCompareOutputsAreUnimportant(currentImportance: CpuImportance): Boolean =
currentImportance.z == Unimportant &&
currentImportance.n == Unimportant&&
currentImportance.c == Unimportant
private val map: Map[Opcode.Value, CpuImportance => CpuImportance] = Map(
NOP -> identity,
SEI -> identity,
CLI -> identity,
LABEL -> identity,
JSR -> (_ => finalImportance),
BSR -> (_ => finalImportance),
BRK -> (_ => finalImportance),
COP -> (_ => finalImportance),
RTS -> (_ => finalImportance),
RTL -> (_ => finalImportance),
BYTE -> (_ => finalImportance),
RTI -> (_ => CpuImportance(
a = Unimportant, ah = Unimportant,
x = Unimportant, y = Unimportant, iz = Unimportant,
z = Unimportant, n = Unimportant, c = Unimportant, v = Unimportant, d = Unimportant,
m = Unimportant, w = Unimportant)),
BNE -> (_.copy(z = Important)),
BEQ -> (_.copy(z = Important)),
BMI -> (_.copy(n = Important)),
@ -54,71 +49,6 @@ object ReverseFlowAnalyzerPerOpcode {
BCC -> (_.copy(c = Important)),
BCS -> (_.copy(c = Important)),
TAX -> (currentImportance => {
currentImportance.copy(
a = currentImportance.x ~ currentImportance.a ~ currentImportance.n ~ currentImportance.z,
x = Unimportant,
n = Unimportant, z = Unimportant, m = Important, w = Important)
}),
TAY -> (currentImportance => {
currentImportance.copy(
a = currentImportance.y ~ currentImportance.a ~ currentImportance.n ~ currentImportance.z,
y = Unimportant,
n = Unimportant, z = Unimportant, m = Important, w = Important)
}),
TXA -> (currentImportance => {
currentImportance.copy(
x = currentImportance.a ~ currentImportance.x ~ currentImportance.n ~ currentImportance.z,
a = Unimportant,
n = Unimportant, z = Unimportant, m = Important, w = Important)
}),
TYA -> (currentImportance => {
currentImportance.copy(
y = currentImportance.a ~ currentImportance.y ~ currentImportance.n ~ currentImportance.z,
a = Unimportant,
n = Unimportant, z = Unimportant, m = Important, w = Important)
}),
TAZ -> (currentImportance => {
currentImportance.copy(
a = currentImportance.iz ~ currentImportance.a ~ currentImportance.n ~ currentImportance.z,
iz = Unimportant,
n = Unimportant, z = Unimportant, m = Important, w = Important)
}),
TZA -> (currentImportance => {
currentImportance.copy(
iz = currentImportance.a ~ currentImportance.iz ~ currentImportance.n ~ currentImportance.z,
a = Unimportant,
n = Unimportant, z = Unimportant, m = Important, w = Important)
}),
TXY -> (currentImportance => {
currentImportance.copy(
x = currentImportance.y ~ currentImportance.x ~ currentImportance.n ~ currentImportance.z,
y = Unimportant,
n = Unimportant, z = Unimportant, m = Important, w = Important)
}),
TYX -> (currentImportance => {
currentImportance.copy(
y = currentImportance.x ~ currentImportance.y ~ currentImportance.n ~ currentImportance.z,
x = Unimportant,
n = Unimportant, z = Unimportant, m = Important, w = Important)
}),
XBA -> (currentImportance => {
currentImportance.copy(
ah = currentImportance.a ~ currentImportance.iz ~ currentImportance.n ~ currentImportance.z,
a = currentImportance.ah,
n = Unimportant, z = Unimportant)
}),
HuSAX -> (currentImportance => {
currentImportance.copy(a = currentImportance.x, x = currentImportance.a, m = Important, w = Important)
}),
SAY -> (currentImportance => {
currentImportance.copy(y = currentImportance.a, a = currentImportance.y, m = Important, w = Important)
}),
SXY -> (currentImportance => {
currentImportance.copy(y = currentImportance.x, x = currentImportance.y, m = Important, w = Important)
}),
DISCARD_XF -> (_.copy(x = Unimportant, n = Unimportant, z = Unimportant, c = Unimportant, v = Unimportant, r0 = Unimportant, r1 = Unimportant)),
DISCARD_YF -> (_.copy(y = Unimportant, iz = Unimportant, n = Unimportant, z = Unimportant, c = Unimportant, v = Unimportant, r0 = Unimportant, r1 = Unimportant)),
DISCARD_AF -> (_.copy(a = Unimportant, n = Unimportant, z = Unimportant, c = Unimportant, v = Unimportant, r0 = Unimportant, r1 = Unimportant)),
@ -128,6 +58,8 @@ object ReverseFlowAnalyzerPerOpcode {
LDY -> (_.copy(y = Unimportant, n = Unimportant, z = Unimportant, w = Important)),
LDZ -> (_.copy(iz = Unimportant, n = Unimportant, z = Unimportant)),
LAX -> (_.copy(a = Unimportant, x = Unimportant, n = Unimportant, z = Unimportant)),
LXA -> (_.copy(a = Important, x = Unimportant, n = Unimportant, z = Unimportant)),
XAA -> (_.copy(a = Important, x = Important, n = Unimportant, z = Unimportant)),
ORA -> (currentImportance => {
val ignoreOutput = allLoadingAccuOutputsUnimportant(currentImportance)
@ -150,6 +82,27 @@ object ReverseFlowAnalyzerPerOpcode {
n = Unimportant, z = Unimportant,
m = Important)
}),
SLO -> (currentImportance => {
val ignoreOutput = allLoadingAccuOutputsUnimportant(currentImportance)
currentImportance.copy(
a = if (ignoreOutput) Unimportant else Important,
n = Unimportant, z = Unimportant, c = Unimportant,
m = Important)
}),
SRE -> (currentImportance => {
val ignoreOutput = allLoadingAccuOutputsUnimportant(currentImportance)
currentImportance.copy(
a = if (ignoreOutput) Unimportant else Important,
n = Unimportant, z = Unimportant, c = Unimportant,
m = Important)
}),
RLA -> (currentImportance => {
val ignoreOutput = allLoadingAccuOutputsUnimportant(currentImportance)
currentImportance.copy(
a = if (ignoreOutput) Unimportant else Important,
n = Unimportant, z = Unimportant, c = Important,
m = Important)
}),
BIT -> (currentImportance => {
currentImportance.copy(
a = currentImportance.z,
@ -158,6 +111,33 @@ object ReverseFlowAnalyzerPerOpcode {
v = Unimportant,
m = Important)
}),
CMP -> (currentImportance => {
val ignoreOutput = allCompareOutputsAreUnimportant(currentImportance)
currentImportance.copy(
a = if (ignoreOutput) Unimportant else Important,
n = Unimportant, z = Unimportant, c = Unimportant,
m = Important)
}),
DCP -> (currentImportance => {
val ignoreOutput = allCompareOutputsAreUnimportant(currentImportance)
currentImportance.copy(
a = if (ignoreOutput) Unimportant else Important,
n = Unimportant, z = Unimportant, c = Unimportant)
}),
CPX -> (currentImportance => {
val ignoreOutput = allCompareOutputsAreUnimportant(currentImportance)
currentImportance.copy(
x = if (ignoreOutput) Unimportant else Important,
n = Unimportant, z = Unimportant, c = Unimportant,
w = Important)
}),
CPY -> (currentImportance => {
val ignoreOutput = allCompareOutputsAreUnimportant(currentImportance)
currentImportance.copy(
y = if (ignoreOutput) Unimportant else Important,
n = Unimportant, z = Unimportant, c = Unimportant,
w = Important)
}),
ADC -> (currentImportance => {
val ignoreOutput = allAddingOutputsUnimportant(currentImportance)
@ -196,49 +176,35 @@ object ReverseFlowAnalyzerPerOpcode {
STZ -> (importance => importance.copy(iz = Important, m = Important)),
SAX -> (importance => importance.copy(a = Important, x = Important)),
INC -> (importance => importance.copy(n = Unimportant, z = Unimportant, m = Important)),
DEC -> (importance => importance.copy(n = Unimportant, z = Unimportant, m = Important)),
ROL -> (importance => importance.copy(n = Unimportant, z = Unimportant, c = Important, m = Important)),
ROR -> (importance => importance.copy(n = Unimportant, z = Unimportant, c = Important, m = Important)),
ASL -> (importance => importance.copy(n = Unimportant, z = Unimportant, c = Unimportant, m = Important)),
LSR -> (importance => importance.copy(n = Unimportant, z = Unimportant, c = Unimportant, m = Important)),
SBX -> (importance => importance.copy(a = Important, x = Important, n = Unimportant, z = Unimportant, c = Unimportant, m = Important)),
ANC -> (currentImportance => {
val ignoreOutput = allAddingOutputsUnimportant(currentImportance)
currentImportance.copy(
a = if (ignoreOutput) Unimportant else Important,
n = Unimportant, z = Unimportant, c = Unimportant,
m = Important)
}),
ALR -> (currentImportance => {
val ignoreOutput = allAddingOutputsUnimportant(currentImportance)
currentImportance.copy(
a = if (ignoreOutput) Unimportant else Important,
n = Unimportant, z = Unimportant, c = Unimportant,
m = Important)
}),
STA_W -> (importance => importance.copy(a = Important, ah = Important, m = Important)),
STX_W -> (importance => importance.copy(x = Important, w = Important)),
STY_W -> (importance => importance.copy(y = Important, w = Important)),
STZ_W -> (importance => importance.copy(iz = Important, m = Important)),
DEX -> (_.copy(x = Important, n = Unimportant, z = Unimportant, w = Important)),
DEY -> (_.copy(y = Important, n = Unimportant, z = Unimportant, w = Important)),
DEZ -> (_.copy(iz = Important, n = Unimportant, z = Unimportant)),
INX -> (_.copy(x = Important, n = Unimportant, z = Unimportant, w = Important)),
INY -> (_.copy(y = Important, n = Unimportant, z = Unimportant, w = Important)),
INZ -> (_.copy(iz = Important, n = Unimportant, z = Unimportant)),
DEX_W -> (_.copy(x = Important, n = Unimportant, z = Unimportant, w = Important)),
DEY_W -> (_.copy(y = Important, n = Unimportant, z = Unimportant, w = Important)),
INX_W -> (_.copy(x = Important, n = Unimportant, z = Unimportant, w = Important)),
INY_W -> (_.copy(y = Important, n = Unimportant, z = Unimportant, w = Important)),
PHP -> (_.copy(n = Important, c = Important, d = Important, z = Important, v = Important, m = Important, w = Important)),
PLP -> (_.copy(n = Unimportant, c = Unimportant, d = Unimportant, z = Unimportant, v = Unimportant, m = Unimportant, w = Unimportant)),
PHA -> (_.copy(a = Important, m = Important)),
PLA -> (_.copy(a = Unimportant, m = Important, n = Unimportant, z = Unimportant)),
PHX -> (_.copy(x = Important, w = Important)),
PLX -> (_.copy(x = Unimportant, w = Important, n = Unimportant, z = Unimportant)),
PHY -> (_.copy(y = Important, w = Important)),
PLY -> (_.copy(y = Unimportant, w = Important, n = Unimportant, z = Unimportant)),
PHZ -> (_.copy(iz = Important, w = Important)),
PLZ -> (_.copy(iz = Unimportant, w = Important, n = Unimportant, z = Unimportant)),
PHA_W -> (_.copy(a = Important, ah = Important, m = Important)),
PLA_W -> (_.copy(a = Unimportant, ah = Unimportant, m = Important, n = Unimportant, z = Unimportant)),
PHX_W -> (_.copy(x = Important, w = Important)),
PLX_W -> (_.copy(x = Unimportant, w = Important, n = Unimportant, z = Unimportant)),
PHY_W -> (_.copy(y = Important, w = Important)),
PLY_W -> (_.copy(y = Unimportant, w = Important, n = Unimportant, z = Unimportant)),
CLC -> (_.copy(c = Unimportant)),
SEC -> (_.copy(c = Unimportant)),
CLD -> (_.copy(d = Unimportant)),
SED -> (_.copy(d = Unimportant)),
CLV -> (_.copy(v = Unimportant)),
)
def hasDefinition(opcode: Opcode.Value): Boolean = map.contains(opcode)

View File

@ -847,6 +847,56 @@ case class RefersTo(identifier: String, offset: Int = 999) extends TrivialAssemb
override def toString: String = s"<$identifier+$offset>"
}
case class RefersToOrUses(identifier: String, offset: Int = 999) extends TrivialAssemblyLinePattern {
override def apply(line: AssemblyLine): Boolean = {
line.addrMode match {
case AddrMode.ZeroPage | AddrMode.Absolute | AddrMode.LongAbsolute | AddrMode.Indirect => line.parameter match {
case MemoryAddressConstant(th) =>
(offset == 999 || offset == 0) && th.name == identifier
case CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(nn, _)) =>
(offset == 999 || offset == nn) && th.name == identifier
case CompoundConstant(MathOperator.Plus, NumericConstant(nn, _), MemoryAddressConstant(th)) =>
(offset == 999 || offset == nn) && th.name == identifier
case CompoundConstant(MathOperator.Minus, MemoryAddressConstant(th), NumericConstant(nn, _)) =>
(offset == 999 || offset == -nn) && th.name == identifier
case _ => false
}
case AddrMode.IndexedY | AddrMode.LongIndexedY | AddrMode.IndexedZ | AddrMode.LongIndexedZ => line.parameter match {
case MemoryAddressConstant(th) =>
(offset == 999 || offset == 0 || offset == 1) && th.name == identifier
case CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(nn, _)) =>
(offset == 999 || offset == nn || offset == nn + 1) && th.name == identifier
case CompoundConstant(MathOperator.Plus, NumericConstant(nn, _), MemoryAddressConstant(th)) =>
(offset == 999 || offset == nn || offset == nn + 1) && th.name == identifier
case CompoundConstant(MathOperator.Minus, MemoryAddressConstant(th), NumericConstant(nn, _)) =>
(offset == 999 || offset == -nn || offset == -nn + 1) && th.name == identifier
case _ => false
}
case AddrMode.AbsoluteX | AddrMode.AbsoluteY | AddrMode.AbsoluteIndexedX => line.parameter match {
case MemoryAddressConstant(th) =>
(offset == 999 || offset >= 0 && offset <= 255) && th.name == identifier
case CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(nn, _)) =>
(offset == 999 || offset >= nn && offset <= nn + 255) && th.name == identifier
case CompoundConstant(MathOperator.Plus, NumericConstant(nn, _), MemoryAddressConstant(th)) =>
(offset == 999 || offset >= nn && offset <= nn + 255) && th.name == identifier
case CompoundConstant(MathOperator.Minus, MemoryAddressConstant(th), NumericConstant(nn, _)) =>
(offset == 999 || offset >= -nn && offset <= -nn + 255) && th.name == identifier
case _ => false
}
case AddrMode.IndexedX => line.parameter match {
case MemoryAddressConstant(th) => th.name == identifier
case CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(nn, _)) => th.name == identifier
case CompoundConstant(MathOperator.Plus, NumericConstant(nn, _), MemoryAddressConstant(th)) => th.name == identifier
case CompoundConstant(MathOperator.Minus, MemoryAddressConstant(th), NumericConstant(nn, _)) => th.name == identifier
case _ => false
}
case _ => false
}
}
override def toString: String = s"<$identifier+$offset>"
}
case class CallsAnyOf(identifiers: Set[String]) extends TrivialAssemblyLinePattern {
override def apply(line: AssemblyLine): Boolean = {
(line.addrMode == AddrMode.Absolute ||

View File

@ -3,7 +3,7 @@ package millfork.assembly.mos.opt
import millfork.assembly.mos.Opcode._
import millfork.assembly.mos.AddrMode._
import millfork.assembly.AssemblyOptimization
import millfork.assembly.mos.AssemblyLine
import millfork.assembly.mos.{AssemblyLine, State}
import millfork.env.{CompoundConstant, Constant, MathOperator}
/**
@ -16,7 +16,7 @@ object ZeropageRegisterOptimizations {
val ConstantMultiplication = new RuleBasedAssemblyOptimization("Constant multiplication",
needsFlowInfo = FlowInfoRequirement.ForwardFlow,
(HasOpcode(STA) & RefersTo("__reg", 0) & MatchAddrMode(0) & MatchParameter(1) & MatchA(4)) ~
(Linear & Not(RefersTo("__reg", 1)) & DoesntChangeMemoryAt(0, 1)).* ~
(Linear & Not(RefersToOrUses("__reg", 1)) & DoesntChangeMemoryAt(0, 1)).* ~
(HasOpcode(STA) & RefersTo("__reg", 1) & MatchA(5)) ~
(Elidable & HasOpcode(JSR) & RefersTo("__mul_u8u8u8", 0)) ~~> { (code, ctx) =>
val product = ctx.get[Int](4) * ctx.get[Int](5)
@ -26,7 +26,7 @@ object ZeropageRegisterOptimizations {
// TODO: constants other than power of 2:
(Elidable & HasOpcode(STA) & RefersTo("__reg", 0) & MatchAddrMode(0) & MatchParameter(1)) ~
(Linear & Not(RefersTo("__reg", 1)) & DoesntChangeMemoryAt(0, 1)).* ~
(Linear & Not(RefersToOrUses("__reg", 1)) & DoesntChangeMemoryAt(0, 1)).* ~
(HasOpcode(STA) & RefersTo("__reg", 1) & MatchA(4)) ~
Where(ctx => {
val constant = ctx.get[Int](4)
@ -46,7 +46,7 @@ object ZeropageRegisterOptimizations {
val constant = ctx.get[Int](4)
(constant & (constant - 1)) == 0
}) ~
(Linear & Not(RefersTo("__reg", 1)) & DoesntChangeMemoryAt(0, 1)).* ~
(Linear & Not(RefersToOrUses("__reg", 1)) & DoesntChangeMemoryAt(0, 1)).* ~
(HasOpcode(STA) & RefersTo("__reg", 1)) ~
(Elidable & HasOpcode(JSR) & RefersTo("__mul_u8u8u8", 0)) ~~> { (code, ctx) =>
val constant = ctx.get[Int](4)
@ -70,9 +70,18 @@ object ZeropageRegisterOptimizations {
)
val DeadRegStoreFromFlow = new RuleBasedAssemblyOptimization("Dead zeropage register store from flow",
needsFlowInfo = FlowInfoRequirement.BackwardFlow,
needsFlowInfo = FlowInfoRequirement.BothFlows,
(Elidable & HasOpcode(STA) & RefersTo("__reg", 0) & DoesntMatterWhatItDoesWithReg(0)) ~~> (_.tail),
(Elidable & HasOpcode(STA) & RefersTo("__reg", 1) & DoesntMatterWhatItDoesWithReg(1)) ~~> (_.tail),
(Elidable & HasOpcode(LDY) & RefersTo("__reg", 0)) ~
(Linear & Not(ConcernsY) & Not(RefersToOrUses("__reg", 0))).*.capture(2) ~
(Elidable & (HasA(0) & HasOpcode(STA) | HasOpcode(STZ)) & RefersTo("__reg", 0) & DoesntMatterWhatItDoesWith(State.A)) ~
((Linear & Not(ConcernsY) & Not(RefersToOrUses("__reg", 0))).* ~
(Elidable & RefersToOrUses("__reg", 0) & HasAddrMode(IndexedY) & DoesntMatterWhatItDoesWithReg(0) & DoesntMatterWhatItDoesWith(State.Y))).capture(3) ~~> ((code, ctx) =>
ctx.get[List[AssemblyLine]](2) ++ List(AssemblyLine.immediate(LDY, 0)) ++ ctx.get[List[AssemblyLine]](3)
)
)
val All: List[AssemblyOptimization[AssemblyLine]] = List(