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

Important bugfixes; removing empty stores to larger variables

This commit is contained in:
Karol Stasiak 2018-03-01 15:57:18 +01:00
parent 3dc526bcb7
commit f8bd496b6b
5 changed files with 58 additions and 28 deletions

View File

@ -50,14 +50,14 @@ object OpcodeClasses {
PHX, PHY, PLX, PLY, TAS, LAS
)
val ChangesMemoryAlways = Set(
STA, STY, STZ,
STX, DEC, INC,
STA, STY, STZ, STX,
TRB, TSB,
SAX, DCP, ISC,
SLO, RLA, SRE, RRA,
AHX, SHY, SHX, TAS, LAS
)
val ChangesMemoryIfNotImplied = Set(
ASL, ROL, LSR, ROR
DEC, INC, ASL, ROL, LSR, ROR
)
val ReadsMemoryIfNotImpliedOrImmediate = Set(
LDY, CPX, CPY,
@ -305,7 +305,7 @@ case class AssemblyLine(opcode: Opcode.Value, addrMode: AddrMode.Value, var para
def sizeInBytes: Int = addrMode match {
case Implied => 1
case Relative | ZeroPageX | ZeroPage | ZeroPageY | IndexedX | IndexedY | Immediate => 2
case Relative | ZeroPageX | ZeroPage | ZeroPageY | ZeroPageIndirect | IndexedX | IndexedY | Immediate => 2
case AbsoluteIndexedX | AbsoluteX | Absolute | AbsoluteY | Indirect => 3
case DoesNotExist => 0
}

View File

@ -195,16 +195,16 @@ object CoarseFlowAnalyzer {
currentStatus = initialStatus
case AssemblyLine(LDX, Immediate, NumericConstant(nn, _), _) =>
val n = nn.toInt
val n = nn.toInt & 0xff
currentStatus = currentStatus.nz(n).copy(x = SingleStatus(n))
case AssemblyLine(LDY, Immediate, NumericConstant(nn, _), _) =>
val n = nn.toInt
val n = nn.toInt & 0xff
currentStatus = currentStatus.nz(n).copy(y = SingleStatus(n))
case AssemblyLine(LDA, Immediate, NumericConstant(nn, _), _) =>
val n = nn.toInt
val n = nn.toInt & 0xff
currentStatus = currentStatus.nz(n).copy(a = SingleStatus(n))
case AssemblyLine(LAX, Immediate, NumericConstant(nn, _), _) =>
val n = nn.toInt
val n = nn.toInt & 0xff
currentStatus = currentStatus.nz(n).copy(a = SingleStatus(n), x = SingleStatus(n))
case AssemblyLine(ADC, Immediate, NumericConstant(nn, _), _) =>
@ -232,17 +232,17 @@ object CoarseFlowAnalyzer {
a = currentStatus.a.map(i => (i & n & 0xff) >> 1))
case AssemblyLine(INX, Implied, _, _) =>
currentStatus = currentStatus.copy(n = currentStatus.x.n(_ + 1), z = currentStatus.x.z(_ + 1), x = currentStatus.x.map(_ + 1))
currentStatus = currentStatus.copy(n = currentStatus.x.n(_ + 1), z = currentStatus.x.z(_ + 1), x = currentStatus.x.map(v => (v + 1) & 0xff))
case AssemblyLine(DEX, Implied, _, _) =>
currentStatus = currentStatus.copy(n = currentStatus.x.n(_ - 1), z = currentStatus.x.z(_ - 1), x = currentStatus.x.map(_ - 1))
currentStatus = currentStatus.copy(n = currentStatus.x.n(_ - 1), z = currentStatus.x.z(_ - 1), x = currentStatus.x.map(v => (v - 1) & 0xff))
case AssemblyLine(INY, Implied, _, _) =>
currentStatus = currentStatus.copy(n = currentStatus.y.n(_ + 1), z = currentStatus.y.z(_ + 1), y = currentStatus.y.map(_ + 1))
currentStatus = currentStatus.copy(n = currentStatus.y.n(_ + 1), z = currentStatus.y.z(_ + 1), y = currentStatus.y.map(v => (v + 1) & 0xff))
case AssemblyLine(DEY, Implied, _, _) =>
currentStatus = currentStatus.copy(n = currentStatus.y.n(_ - 1), z = currentStatus.y.z(_ - 1), y = currentStatus.y.map(_ - 1))
currentStatus = currentStatus.copy(n = currentStatus.y.n(_ - 1), z = currentStatus.y.z(_ - 1), y = currentStatus.y.map(v => (v - 1) & 0xff))
case AssemblyLine(INC, Implied, _, _) =>
currentStatus = currentStatus.copy(n = currentStatus.a.n(_ + 1), z = currentStatus.a.z(_ + 1), a = currentStatus.a.map(_ + 1))
currentStatus = currentStatus.copy(n = currentStatus.a.n(_ + 1), z = currentStatus.a.z(_ + 1), a = currentStatus.a.map(v => (v + 1) & 0xff))
case AssemblyLine(DEC, Implied, _, _) =>
currentStatus = currentStatus.copy(n = currentStatus.a.n(_ - 1), z = currentStatus.a.z(_ - 1), a = currentStatus.a.map(_ - 1))
currentStatus = currentStatus.copy(n = currentStatus.a.n(_ - 1), z = currentStatus.a.z(_ - 1), a = currentStatus.a.map(v => (v - 1) & 0xff))
case AssemblyLine(TAX, _, _, _) =>
currentStatus = currentStatus.copy(x = currentStatus.a, n = currentStatus.a.n(), z = currentStatus.a.z())
case AssemblyLine(TXA, _, _, _) =>
@ -253,7 +253,7 @@ object CoarseFlowAnalyzer {
currentStatus = currentStatus.copy(a = currentStatus.y, n = currentStatus.y.n(), z = currentStatus.y.z())
case AssemblyLine(ASL, Implied, _, _) =>
currentStatus = currentStatus.copy(a = currentStatus.a.map(_ << 1), n = currentStatus.a.n(_ << 1), z = currentStatus.a.z(_ << 1),c = currentStatus.a.map(a => a.&(0xff).!=(0)))
currentStatus = currentStatus.copy(a = currentStatus.a.map(v => (v << 1) & 0xff), n = currentStatus.a.n(_ << 1), z = currentStatus.a.z(_ << 1),c = currentStatus.a.map(a => a.&(0xff).!=(0)))
case AssemblyLine(LSR, Implied, _, _) =>
currentStatus = currentStatus.copy(a = currentStatus.a.map(a => a.>>(1).&(0x7f)), n = currentStatus.a.n(a => a.>>(1).&(0x7f)), z = currentStatus.a.z(a => a.>>(1).&(0x7f)),c = currentStatus.a.map(a => a.&(1).!=(0)))

View File

@ -4,6 +4,7 @@ import millfork.CompilationOptions
import millfork.assembly.AssemblyLine
import millfork.env._
import millfork.assembly.Opcode._
import millfork.assembly.AddrMode._
import millfork.error.ErrorReporting
import scala.collection.{immutable, mutable}
@ -14,7 +15,7 @@ import scala.collection.{immutable, mutable}
object EmptyMemoryStoreRemoval extends AssemblyOptimization {
override def name = "Removing pointless stores to automatic variables"
private val storeOpcodes = Set(STA, STX, STY, STZ, SAX)
private val storeAddrModes = Set(Absolute, ZeroPage, AbsoluteX, AbsoluteY, ZeroPageX, ZeroPageY)
override def optimize(f: NormalFunction, code: List[AssemblyLine], options: CompilationOptions): List[AssemblyLine] = {
val paramVariables = f.params match {
@ -26,11 +27,13 @@ object EmptyMemoryStoreRemoval extends AssemblyOptimization {
}
val stillUsedVariables = code.flatMap {
case AssemblyLine(_, _, MemoryAddressConstant(th), _) => Some(th.name)
case AssemblyLine(_, _, CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(_, _)), _) => Some(th.name)
case _ => None
}.toSet
val localVariables = f.environment.getAllLocalVariables.filter {
case MemoryVariable(name, typ, VariableAllocationMethod.Auto) =>
typ.size == 1 && !paramVariables(name) && stillUsedVariables(name)
val allLocalVariables = f.environment.getAllLocalVariables
val localVariables = allLocalVariables.filter {
case MemoryVariable(name, typ, VariableAllocationMethod.Auto | VariableAllocationMethod.Zeropage) =>
typ.size > 0 && !paramVariables(name) && stillUsedVariables(name)
case _ => false
}
@ -46,17 +49,43 @@ object EmptyMemoryStoreRemoval extends AssemblyOptimization {
val lifetime = VariableLifetime.apply(v.name, code)
val lastaccess = lifetime.last
if (lastaccess >= 0) {
if (code(lastaccess).opcode match {
case STA | STX | STY | SAX =>
val lastVariableAccess = code(lastaccess)
if (lastVariableAccess.elidable && storeAddrModes(lastVariableAccess.addrMode) && (lastVariableAccess.opcode match {
case STA | STX | STY | SAX | STZ | SHX | SHY | AHX =>
true
case TSB | TRB =>
if (importances eq null) importances = ReverseFlowAnalyzer.analyze(f, code)
importances(lastaccess).z != Important
case INC | DEC =>
if (importances eq null) {
importances = ReverseFlowAnalyzer.analyze(f, code)
}
importances(lastaccess).z != Important && importances(lastaccess).n != Important
if (importances eq null) importances = ReverseFlowAnalyzer.analyze(f, code)
importances(lastaccess).z != Important &&
importances(lastaccess).n != Important
case ASL | LSR | ROL | ROR | DCP =>
if (importances eq null) importances = ReverseFlowAnalyzer.analyze(f, code)
importances(lastaccess).z != Important &&
importances(lastaccess).n != Important &&
importances(lastaccess).c != Important
case ISC =>
if (importances eq null) importances = ReverseFlowAnalyzer.analyze(f, code)
importances(lastaccess).z != Important &&
importances(lastaccess).n != Important &&
importances(lastaccess).a != Important
case DCP | SLO | SRE | RLA =>
if (importances eq null) importances = ReverseFlowAnalyzer.analyze(f, code)
importances(lastaccess).z != Important &&
importances(lastaccess).n != Important &&
importances(lastaccess).c != Important &&
importances(lastaccess).a != Important
case RRA =>
if (importances eq null) importances = ReverseFlowAnalyzer.analyze(f, code)
importances(lastaccess).z != Important &&
importances(lastaccess).n != Important &&
importances(lastaccess).c != Important &&
importances(lastaccess).a != Important &&
importances(lastaccess).v != Important
case _ => // last variable access is important, or we're in a loop, do not remove
false
}) {
})) {
badVariables += v.name
toRemove += lastaccess
}

View File

@ -9,11 +9,11 @@ import millfork.error.ErrorReporting
*/
object VariableLifetime {
// TODO: This only works for 1-byte non-stack variables.
// Should be fixed to also work with larger variables.
// This only works for non-stack variables.
def apply(variableName: String, code: List[AssemblyLine]): Range = {
val flags = code.map(_.parameter match {
case MemoryAddressConstant(MemoryVariable(n, _, _)) if n == variableName => true
case CompoundConstant(MathOperator.Plus, MemoryAddressConstant(MemoryVariable(n, _, _)), NumericConstant(_, 1)) if n == variableName => true
case _ => false
})
if (flags.forall(!_)) return Range(0, 0)

View File

@ -708,6 +708,7 @@ object Assembler {
cm(TRB, ZeroPage, 0x14)
cm(TRB, Absolute, 0x1C)
cm(BRA, Relative, 0x80)
cm(BIT, ZeroPageX, 0x34)
cm(BIT, AbsoluteX, 0x3C)
cm(INC, Implied, 0x1A)