1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-07-05 09:28:54 +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 PHX, PHY, PLX, PLY, TAS, LAS
) )
val ChangesMemoryAlways = Set( val ChangesMemoryAlways = Set(
STA, STY, STZ, STA, STY, STZ, STX,
STX, DEC, INC, TRB, TSB,
SAX, DCP, ISC, SAX, DCP, ISC,
SLO, RLA, SRE, RRA, SLO, RLA, SRE, RRA,
AHX, SHY, SHX, TAS, LAS AHX, SHY, SHX, TAS, LAS
) )
val ChangesMemoryIfNotImplied = Set( val ChangesMemoryIfNotImplied = Set(
ASL, ROL, LSR, ROR DEC, INC, ASL, ROL, LSR, ROR
) )
val ReadsMemoryIfNotImpliedOrImmediate = Set( val ReadsMemoryIfNotImpliedOrImmediate = Set(
LDY, CPX, CPY, LDY, CPX, CPY,
@ -305,7 +305,7 @@ case class AssemblyLine(opcode: Opcode.Value, addrMode: AddrMode.Value, var para
def sizeInBytes: Int = addrMode match { def sizeInBytes: Int = addrMode match {
case Implied => 1 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 AbsoluteIndexedX | AbsoluteX | Absolute | AbsoluteY | Indirect => 3
case DoesNotExist => 0 case DoesNotExist => 0
} }

View File

@ -195,16 +195,16 @@ object CoarseFlowAnalyzer {
currentStatus = initialStatus currentStatus = initialStatus
case AssemblyLine(LDX, Immediate, NumericConstant(nn, _), _) => case AssemblyLine(LDX, Immediate, NumericConstant(nn, _), _) =>
val n = nn.toInt val n = nn.toInt & 0xff
currentStatus = currentStatus.nz(n).copy(x = SingleStatus(n)) currentStatus = currentStatus.nz(n).copy(x = SingleStatus(n))
case AssemblyLine(LDY, Immediate, NumericConstant(nn, _), _) => case AssemblyLine(LDY, Immediate, NumericConstant(nn, _), _) =>
val n = nn.toInt val n = nn.toInt & 0xff
currentStatus = currentStatus.nz(n).copy(y = SingleStatus(n)) currentStatus = currentStatus.nz(n).copy(y = SingleStatus(n))
case AssemblyLine(LDA, Immediate, NumericConstant(nn, _), _) => case AssemblyLine(LDA, Immediate, NumericConstant(nn, _), _) =>
val n = nn.toInt val n = nn.toInt & 0xff
currentStatus = currentStatus.nz(n).copy(a = SingleStatus(n)) currentStatus = currentStatus.nz(n).copy(a = SingleStatus(n))
case AssemblyLine(LAX, Immediate, NumericConstant(nn, _), _) => 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)) currentStatus = currentStatus.nz(n).copy(a = SingleStatus(n), x = SingleStatus(n))
case AssemblyLine(ADC, Immediate, NumericConstant(nn, _), _) => case AssemblyLine(ADC, Immediate, NumericConstant(nn, _), _) =>
@ -232,17 +232,17 @@ object CoarseFlowAnalyzer {
a = currentStatus.a.map(i => (i & n & 0xff) >> 1)) a = currentStatus.a.map(i => (i & n & 0xff) >> 1))
case AssemblyLine(INX, Implied, _, _) => 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, _, _) => 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, _, _) => 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, _, _) => 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, _, _) => 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, _, _) => 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, _, _, _) => case AssemblyLine(TAX, _, _, _) =>
currentStatus = currentStatus.copy(x = currentStatus.a, n = currentStatus.a.n(), z = currentStatus.a.z()) currentStatus = currentStatus.copy(x = currentStatus.a, n = currentStatus.a.n(), z = currentStatus.a.z())
case AssemblyLine(TXA, _, _, _) => case AssemblyLine(TXA, _, _, _) =>
@ -253,7 +253,7 @@ object CoarseFlowAnalyzer {
currentStatus = currentStatus.copy(a = currentStatus.y, n = currentStatus.y.n(), z = currentStatus.y.z()) currentStatus = currentStatus.copy(a = currentStatus.y, n = currentStatus.y.n(), z = currentStatus.y.z())
case AssemblyLine(ASL, Implied, _, _) => 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, _, _) => 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))) 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.assembly.AssemblyLine
import millfork.env._ import millfork.env._
import millfork.assembly.Opcode._ import millfork.assembly.Opcode._
import millfork.assembly.AddrMode._
import millfork.error.ErrorReporting import millfork.error.ErrorReporting
import scala.collection.{immutable, mutable} import scala.collection.{immutable, mutable}
@ -14,7 +15,7 @@ import scala.collection.{immutable, mutable}
object EmptyMemoryStoreRemoval extends AssemblyOptimization { object EmptyMemoryStoreRemoval extends AssemblyOptimization {
override def name = "Removing pointless stores to automatic variables" 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] = { override def optimize(f: NormalFunction, code: List[AssemblyLine], options: CompilationOptions): List[AssemblyLine] = {
val paramVariables = f.params match { val paramVariables = f.params match {
@ -26,11 +27,13 @@ object EmptyMemoryStoreRemoval extends AssemblyOptimization {
} }
val stillUsedVariables = code.flatMap { val stillUsedVariables = code.flatMap {
case AssemblyLine(_, _, MemoryAddressConstant(th), _) => Some(th.name) case AssemblyLine(_, _, MemoryAddressConstant(th), _) => Some(th.name)
case AssemblyLine(_, _, CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(_, _)), _) => Some(th.name)
case _ => None case _ => None
}.toSet }.toSet
val localVariables = f.environment.getAllLocalVariables.filter { val allLocalVariables = f.environment.getAllLocalVariables
case MemoryVariable(name, typ, VariableAllocationMethod.Auto) => val localVariables = allLocalVariables.filter {
typ.size == 1 && !paramVariables(name) && stillUsedVariables(name) case MemoryVariable(name, typ, VariableAllocationMethod.Auto | VariableAllocationMethod.Zeropage) =>
typ.size > 0 && !paramVariables(name) && stillUsedVariables(name)
case _ => false case _ => false
} }
@ -46,17 +49,43 @@ object EmptyMemoryStoreRemoval extends AssemblyOptimization {
val lifetime = VariableLifetime.apply(v.name, code) val lifetime = VariableLifetime.apply(v.name, code)
val lastaccess = lifetime.last val lastaccess = lifetime.last
if (lastaccess >= 0) { if (lastaccess >= 0) {
if (code(lastaccess).opcode match { val lastVariableAccess = code(lastaccess)
case STA | STX | STY | SAX => if (lastVariableAccess.elidable && storeAddrModes(lastVariableAccess.addrMode) && (lastVariableAccess.opcode match {
case STA | STX | STY | SAX | STZ | SHX | SHY | AHX =>
true true
case TSB | TRB =>
if (importances eq null) importances = ReverseFlowAnalyzer.analyze(f, code)
importances(lastaccess).z != Important
case INC | DEC => case INC | DEC =>
if (importances eq null) { if (importances eq null) importances = ReverseFlowAnalyzer.analyze(f, code)
importances = ReverseFlowAnalyzer.analyze(f, code) importances(lastaccess).z != Important &&
} importances(lastaccess).n != Important
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 case _ => // last variable access is important, or we're in a loop, do not remove
false false
}) { })) {
badVariables += v.name badVariables += v.name
toRemove += lastaccess toRemove += lastaccess
} }

View File

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

View File

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