mirror of
https://github.com/KarolS/millfork.git
synced 2024-12-24 15:29:23 +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:
parent
5ee9fd85ce
commit
816bfb5f06
@ -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),
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
@ -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)
|
||||
|
@ -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 ||
|
||||
|
@ -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(
|
||||
|
Loading…
Reference in New Issue
Block a user