mirror of
https://github.com/KarolS/millfork.git
synced 2025-04-10 16:39:59 +00:00
Add original line numbers to generated assembly
This commit is contained in:
parent
a985c4f753
commit
406d69c74a
@ -47,6 +47,8 @@ Choose syntax for assembly output on 8080-like targets.
|
||||
|
||||
* `--syntax=intel`, `--syntax=zilog` – sets both previous options at once
|
||||
|
||||
* `-fline-numbers`, `-fno-line-numbers` – Whether should show source line numbers in assembly output.
|
||||
|
||||
## Verbosity options
|
||||
|
||||
* `-q` – Suppress all messages except for errors.
|
||||
|
@ -303,7 +303,7 @@ object Cpu extends Enumeration {
|
||||
object CompilationFlag extends Enumeration {
|
||||
val
|
||||
// common compilation options:
|
||||
EmitIllegals, DecimalMode, ReadOnlyArrays, LenientTextEncoding,
|
||||
EmitIllegals, DecimalMode, ReadOnlyArrays, LenientTextEncoding, LineNumbersInAssembly,
|
||||
// compilation options for MOS:
|
||||
EmitCmosOpcodes, EmitCmosNopOpcodes, EmitHudsonOpcodes, Emit65CE02Opcodes, EmitEmulation65816Opcodes, EmitNative65816Opcodes,
|
||||
PreventJmpIndirectBug, LargeCode, ReturnWordsViaAccumulator,
|
||||
|
@ -298,6 +298,10 @@ object Main {
|
||||
c.changeFlag(CompilationFlag.UseIntelSyntaxForInput, v).changeFlag(CompilationFlag.UseIntelSyntaxForOutput, v)
|
||||
).description("Select syntax for assembly input and output.")
|
||||
|
||||
boolean("-fline-numbers", "-fno-line-numbers").action((c,v) =>
|
||||
c.changeFlag(CompilationFlag.LineNumbersInAssembly, v)
|
||||
).description("Show source line numbers in assembly.")
|
||||
|
||||
endOfFlags("--").description("Marks the end of options.")
|
||||
|
||||
fluff("", "Verbosity options:", "")
|
||||
|
@ -1,12 +1,46 @@
|
||||
package millfork.assembly
|
||||
|
||||
import millfork.env.Constant
|
||||
import millfork.node.Position
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
*/
|
||||
trait AbstractCode {
|
||||
def sizeInBytes: Int
|
||||
|
||||
def isPrintable: Boolean
|
||||
|
||||
def parameter: Constant
|
||||
|
||||
def source: Option[SourceLine]
|
||||
}
|
||||
|
||||
object SourceLine {
|
||||
val MultipleFiles: SourceLine = SourceLine("", 0)
|
||||
|
||||
def merge(line: Option[SourceLine], lines: Seq[Option[SourceLine]]): Option[SourceLine] = {
|
||||
line match {
|
||||
case Some(l) =>
|
||||
Some(lines.flatten.foldLeft(l)(_ ~ _))
|
||||
case None =>
|
||||
lines.flatten.reduceOption(_ ~ _)
|
||||
}
|
||||
}
|
||||
|
||||
def merge(lines: Seq[Option[SourceLine]]): Option[SourceLine] = {
|
||||
lines.flatten.reduceOption(_ ~ _)
|
||||
}
|
||||
|
||||
def of(pos: Option[Position]): Option[SourceLine] = pos.map(p => SourceLine(p.moduleName, p.line))
|
||||
}
|
||||
|
||||
case class SourceLine(moduleName: String, line: Int) {
|
||||
def ~(that: SourceLine): SourceLine = if (this.moduleName == that.moduleName) SourceLine(moduleName, line min that.line) else SourceLine.MultipleFiles
|
||||
|
||||
def ~(that: Option[SourceLine]): SourceLine = that.fold(this)(this ~ _)
|
||||
}
|
||||
|
||||
object Elidability extends Enumeration {
|
||||
val Elidable, Volatile, Fixed = Value
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
package millfork.assembly.mos
|
||||
|
||||
import millfork.assembly.AbstractCode
|
||||
import millfork.assembly.{AbstractCode, Elidability, SourceLine}
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.compiler.CompilationContext
|
||||
import millfork.compiler.mos.MosCompiler
|
||||
import millfork.env._
|
||||
import millfork.node.Position
|
||||
import millfork.{CompilationFlag, CompilationOptions}
|
||||
|
||||
//noinspection TypeAnnotation
|
||||
@ -475,7 +476,26 @@ object AssemblyLine {
|
||||
AssemblyLine(opcode, AddrMode.Stack, NumericConstant(addr & 0xff, 1))
|
||||
}
|
||||
|
||||
case class AssemblyLine(opcode: Opcode.Value, addrMode: AddrMode.Value, var parameter: Constant, elidable: Boolean = true) extends AbstractCode {
|
||||
object AssemblyLine0 {
|
||||
@inline
|
||||
def unapply(a: AssemblyLine): Some[(Opcode.Value, AddrMode.Value, Constant)] = Some(a.opcode, a.addrMode, a.parameter)
|
||||
}
|
||||
|
||||
case class AssemblyLine(opcode: Opcode.Value, addrMode: AddrMode.Value, var parameter: Constant, elidability: Elidability.Value = Elidability.Elidable, source: Option[SourceLine] = None) extends AbstractCode {
|
||||
|
||||
def pos(s: Option[SourceLine]): AssemblyLine = if (s.isEmpty || s == source) this else this.copy(source = s)
|
||||
|
||||
def pos(s1: Option[SourceLine], s2: Option[SourceLine]): AssemblyLine = pos(Seq(s1, s2))
|
||||
|
||||
def position(s: Option[Position]): AssemblyLine = pos(SourceLine.of(s))
|
||||
|
||||
def positionIfEmpty(s: Option[Position]): AssemblyLine = if (s.isEmpty || source.isDefined) this else pos(SourceLine.of(s))
|
||||
|
||||
def pos(s: Seq[Option[SourceLine]]): AssemblyLine = pos(SourceLine.merge(s))
|
||||
|
||||
def mergePos(s: Seq[Option[SourceLine]]): AssemblyLine = if (s.isEmpty) this else pos(SourceLine.merge(this.source, s))
|
||||
|
||||
def elidable: Boolean = elidability == Elidability.Elidable
|
||||
|
||||
|
||||
import AddrMode._
|
||||
@ -571,8 +591,8 @@ case class AssemblyLine(opcode: Opcode.Value, addrMode: AddrMode.Value, var para
|
||||
|
||||
def isPrintable: Boolean = true //addrMode != AddrMode.DoesNotExist || opcode == LABEL
|
||||
|
||||
override def toString: String =
|
||||
if (opcode == LABEL) {
|
||||
override def toString: String = {
|
||||
val raw = if (opcode == LABEL) {
|
||||
parameter.toString
|
||||
} else if (opcode == BYTE) {
|
||||
" !byte " + parameter.toString
|
||||
@ -585,4 +605,9 @@ case class AssemblyLine(opcode: Opcode.Value, addrMode: AddrMode.Value, var para
|
||||
}
|
||||
s" $op ${AddrMode.addrModeToString(addrMode, parameter.toString)}"
|
||||
}
|
||||
source match {
|
||||
case Some(SourceLine(_, line)) if line > 0 => f"$raw%-30s \t; @ $line%d"
|
||||
case _ => raw
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -943,10 +943,10 @@ object AlwaysGoodOptimizations {
|
||||
val ADDR = ctx.get[Constant](1)
|
||||
val value = code.foldLeft(oldA) { (prev, line) =>
|
||||
line match {
|
||||
case AssemblyLine(INC, AbsoluteX, ADDR, _) => (prev + 1) & 0xff
|
||||
case AssemblyLine(DEC, AbsoluteX, ADDR, _) => (prev - 1) & 0xff
|
||||
case AssemblyLine(ASL, AbsoluteX, ADDR, _) => (prev << 1) & 0xff
|
||||
case AssemblyLine(LSR, AbsoluteX, ADDR, _) => (prev >> 1) & 0xff
|
||||
case AssemblyLine0(INC, AbsoluteX, ADDR) => (prev + 1) & 0xff
|
||||
case AssemblyLine0(DEC, AbsoluteX, ADDR) => (prev - 1) & 0xff
|
||||
case AssemblyLine0(ASL, AbsoluteX, ADDR) => (prev << 1) & 0xff
|
||||
case AssemblyLine0(LSR, AbsoluteX, ADDR) => (prev >> 1) & 0xff
|
||||
case _ => prev
|
||||
}
|
||||
}
|
||||
@ -1795,7 +1795,7 @@ object AlwaysGoodOptimizations {
|
||||
List(code.head, AssemblyLine.implied(ROL))
|
||||
},
|
||||
(Elidable & HasOpcode(ADC) & HasImmediate(0) & HasClear(State.C) & DoesntMatterWhatItDoesWith(State.V, State.C, State.N, State.Z)) ~~> (_ => Nil),
|
||||
(Elidable & HasOpcode(ROL) & HasClear(State.C)) ~ DebugMatching ~~> (code => code.map(_.copy(opcode = ASL))),
|
||||
(Elidable & HasOpcode(ROL) & HasClear(State.C)) ~~> (code => code.map(_.copy(opcode = ASL))),
|
||||
(Elidable & HasOpcode(ROR) & HasClear(State.C)) ~~> (code => code.map(_.copy(opcode = LSR))),
|
||||
(HasOpcode(AND) & HasImmediate(1)) ~
|
||||
(Linear & Not(ChangesNAndZ) & Not(HasOpcode(CLC)) & Not(ChangesA)).* ~
|
||||
|
@ -1,9 +1,9 @@
|
||||
package millfork.assembly.mos.opt
|
||||
|
||||
import millfork.assembly.mos.{AssemblyLine, OpcodeClasses}
|
||||
import millfork.assembly.{AssemblyOptimization, OptimizationContext}
|
||||
import millfork.assembly.mos.{AssemblyLine, AssemblyLine0, OpcodeClasses}
|
||||
import millfork.assembly.{AssemblyOptimization, Elidability, OptimizationContext}
|
||||
import millfork.env.NormalFunction
|
||||
import millfork.error.{ConsoleLogger, Logger}
|
||||
import millfork.error.Logger
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
@ -100,57 +100,57 @@ class ChangeIndexRegisterOptimization(preferX2Y: Boolean) extends AssemblyOptimi
|
||||
|
||||
//noinspection OptionEqualsSome
|
||||
private def canOptimize(code: List[AssemblyLine], dir: IndexDirection, loaded: Option[IndexReg]): Boolean = code match {
|
||||
case AssemblyLine(_, AbsoluteY, _, _) :: xs if loaded != Some(Y) => false
|
||||
case AssemblyLine(_, ZeroPageY, _, _) :: xs if loaded != Some(Y) => false
|
||||
case AssemblyLine(_, IndexedY, _, _) :: xs if dir == Y2X || loaded != Some(Y) => false
|
||||
case AssemblyLine(_, LongIndexedY, _, _) :: xs if dir == Y2X || loaded != Some(Y) => false
|
||||
case AssemblyLine(_, AbsoluteX, _, _) :: xs if loaded != Some(X) => false
|
||||
case AssemblyLine(_, LongAbsoluteX, _, _) :: xs if loaded != Some(X) => false
|
||||
case AssemblyLine(_, ZeroPageX, _, _) :: xs if loaded != Some(X) => false
|
||||
case AssemblyLine(_, IndexedX, _, _) :: xs if dir == X2Y || loaded != Some(X) => false
|
||||
case AssemblyLine(_, AbsoluteIndexedX, _, _) :: xs if dir == X2Y => false
|
||||
case AssemblyLine(SHX | SHY | AHX | TAS | LAS, _, _, _) :: xs => false
|
||||
case AssemblyLine(TXY, _, _, e) :: xs => e && loaded == Some(X) && canOptimize(xs, dir, Some(Y))
|
||||
case AssemblyLine(TYX, _, _, e) :: xs => e && loaded == Some(Y) && canOptimize(xs, dir, Some(X))
|
||||
case AssemblyLine0(_, AbsoluteY, _) :: xs if loaded != Some(Y) => false
|
||||
case AssemblyLine0(_, ZeroPageY, _) :: xs if loaded != Some(Y) => false
|
||||
case AssemblyLine0(_, IndexedY, _) :: xs if dir == Y2X || loaded != Some(Y) => false
|
||||
case AssemblyLine0(_, LongIndexedY, _) :: xs if dir == Y2X || loaded != Some(Y) => false
|
||||
case AssemblyLine0(_, AbsoluteX, _) :: xs if loaded != Some(X) => false
|
||||
case AssemblyLine0(_, LongAbsoluteX, _) :: xs if loaded != Some(X) => false
|
||||
case AssemblyLine0(_, ZeroPageX, _) :: xs if loaded != Some(X) => false
|
||||
case AssemblyLine0(_, IndexedX, _) :: xs if dir == X2Y || loaded != Some(X) => false
|
||||
case AssemblyLine0(_, AbsoluteIndexedX, _) :: xs if dir == X2Y => false
|
||||
case AssemblyLine0(SHX | SHY | AHX | TAS | LAS, _, _) :: xs => false
|
||||
case AssemblyLine(TXY, _, _, e, _) :: xs => (e == Elidability.Elidable || e == Elidability.Volatile) && loaded == Some(X) && canOptimize(xs, dir, Some(Y))
|
||||
case AssemblyLine(TYX, _, _, e, _) :: xs => (e == Elidability.Elidable || e == Elidability.Volatile) && loaded == Some(Y) && canOptimize(xs, dir, Some(X))
|
||||
|
||||
// using a wrong index register for one instruction is fine
|
||||
case AssemblyLine(LDY | TAY, _, _, _) :: AssemblyLine(_, IndexedY, _, _) :: xs if dir == Y2X =>
|
||||
case AssemblyLine0(LDY | TAY, _, _) :: AssemblyLine0(_, IndexedY, _) :: xs if dir == Y2X =>
|
||||
canOptimize(xs, dir, None)
|
||||
case AssemblyLine(LDX | TAX, _, _, _) :: AssemblyLine(_, IndexedX, _, _) :: xs if dir == X2Y =>
|
||||
case AssemblyLine0(LDX | TAX, _, _) :: AssemblyLine0(_, IndexedX, _) :: xs if dir == X2Y =>
|
||||
canOptimize(xs, dir, None)
|
||||
case AssemblyLine(LDX | TAX, _, _, _) :: AssemblyLine(INC | DEC | ASL | ROL | ROR | LSR | LDY | STY | STZ, AbsoluteX | ZeroPageX, _, _) :: xs if dir == X2Y =>
|
||||
case AssemblyLine0(LDX | TAX, _, _) :: AssemblyLine0(INC | DEC | ASL | ROL | ROR | LSR | LDY | STY | STZ, AbsoluteX | ZeroPageX, _) :: xs if dir == X2Y =>
|
||||
canOptimize(xs, dir, None)
|
||||
case AssemblyLine(LDY | TAY, _, _, _) :: AssemblyLine(INY | DEY, _, _, _) :: AssemblyLine(_, IndexedY, _, _) :: xs if dir == Y2X =>
|
||||
case AssemblyLine0(LDY | TAY, _, _) :: AssemblyLine0(INY | DEY, _, _) :: AssemblyLine0(_, IndexedY, _) :: xs if dir == Y2X =>
|
||||
canOptimize(xs, dir, None)
|
||||
case AssemblyLine(LDX | TAX, _, _, _) :: AssemblyLine(INX | DEX, _, _, _) :: AssemblyLine(_, IndexedX, _, _) :: xs if dir == X2Y =>
|
||||
case AssemblyLine0(LDX | TAX, _, _) :: AssemblyLine0(INX | DEX, _, _) :: AssemblyLine0(_, IndexedX, _) :: xs if dir == X2Y =>
|
||||
canOptimize(xs, dir, None)
|
||||
case AssemblyLine(LDX | TAX, _, _, _) :: AssemblyLine(INX | DEX, _, _, _) :: AssemblyLine(INC | DEC | ASL | ROL | ROR | LSR | LDY | STY | STZ, AbsoluteX | ZeroPageX, _, _) :: xs if dir == X2Y =>
|
||||
case AssemblyLine0(LDX | TAX, _, _) :: AssemblyLine0(INX | DEX, _, _) :: AssemblyLine0(INC | DEC | ASL | ROL | ROR | LSR | LDY | STY | STZ, AbsoluteX | ZeroPageX, _) :: xs if dir == X2Y =>
|
||||
canOptimize(xs, dir, None)
|
||||
|
||||
case AssemblyLine(INC | DEC | ASL | ROL | ROR | LSR | STZ | LDZ | LDY | STY | BIT, AbsoluteX | ZeroPageX, _, _) :: xs if dir == X2Y => false
|
||||
case AssemblyLine(LDX | STX, AbsoluteY | ZeroPageY, _, _) :: xs if dir == Y2X => false
|
||||
case AssemblyLine0(INC | DEC | ASL | ROL | ROR | LSR | STZ | LDZ | LDY | STY | BIT, AbsoluteX | ZeroPageX, _) :: xs if dir == X2Y => false
|
||||
case AssemblyLine0(LDX | STX, AbsoluteY | ZeroPageY, _) :: xs if dir == Y2X => false
|
||||
|
||||
case AssemblyLine(LAX, _, _, _) :: xs => false
|
||||
case AssemblyLine(JSR | BSR, _, _, _) :: xs => false // TODO
|
||||
case AssemblyLine(JMP, Absolute, _, _) :: xs => canOptimize(xs, dir, None) // TODO
|
||||
case AssemblyLine(op, _, _, _) :: xs if OpcodeClasses.ShortBranching(op) => canOptimize(xs, dir, None)
|
||||
case AssemblyLine(RTS | RTL | BRA | BRL, _, _, _) :: xs => canOptimize(xs, dir, None)
|
||||
case AssemblyLine(LABEL, _, _, _) :: xs => canOptimize(xs, dir, None)
|
||||
case AssemblyLine(DISCARD_XF, _, _, _) :: xs => canOptimize(xs, dir, loaded.filter(_ != X))
|
||||
case AssemblyLine(DISCARD_YF, _, _, _) :: xs => canOptimize(xs, dir, loaded.filter(_ != Y))
|
||||
case AssemblyLine(_, DoesNotExist, _, _) :: xs => canOptimize(xs, dir, loaded)
|
||||
case AssemblyLine0(LAX, _, _) :: xs => false
|
||||
case AssemblyLine0(JSR | BSR, _, _) :: xs => false // TODO
|
||||
case AssemblyLine0(JMP, Absolute, _) :: xs => canOptimize(xs, dir, None) // TODO
|
||||
case AssemblyLine0(op, _, _) :: xs if OpcodeClasses.ShortBranching(op) => canOptimize(xs, dir, None)
|
||||
case AssemblyLine0(RTS | RTL | BRA | BRL, _, _) :: xs => canOptimize(xs, dir, None)
|
||||
case AssemblyLine0(LABEL, _, _) :: xs => canOptimize(xs, dir, None)
|
||||
case AssemblyLine0(DISCARD_XF, _, _) :: xs => canOptimize(xs, dir, loaded.filter(_ != X))
|
||||
case AssemblyLine0(DISCARD_YF, _, _) :: xs => canOptimize(xs, dir, loaded.filter(_ != Y))
|
||||
case AssemblyLine0(_, DoesNotExist, _) :: xs => canOptimize(xs, dir, loaded)
|
||||
|
||||
case AssemblyLine(TAX | LDX | PLX, _, _, e) :: xs =>
|
||||
(e || dir == Y2X) && canOptimize(xs, dir, Some(X))
|
||||
case AssemblyLine(TAY | LDY | PLY, _, _, e) :: xs =>
|
||||
(e || dir == X2Y) && canOptimize(xs, dir, Some(Y))
|
||||
case AssemblyLine(TXA | STX | PHX | CPX | INX | DEX | HuSAX, _, _, e) :: xs =>
|
||||
(e || dir == Y2X) && loaded == Some(X) && canOptimize(xs, dir, Some(X))
|
||||
case AssemblyLine(TYA | STY | PHY | CPY | INY | DEY | SAY, _, _, e) :: xs =>
|
||||
(e || dir == X2Y) && loaded == Some(Y) && canOptimize(xs, dir, Some(Y))
|
||||
case AssemblyLine(TAX | LDX | PLX, _, _, e, _) :: xs =>
|
||||
(e == Elidability.Elidable || e == Elidability.Volatile || dir == Y2X) && canOptimize(xs, dir, Some(X))
|
||||
case AssemblyLine(TAY | LDY | PLY, _, _, e, _) :: xs =>
|
||||
(e == Elidability.Elidable || e == Elidability.Volatile || dir == X2Y) && canOptimize(xs, dir, Some(Y))
|
||||
case AssemblyLine(TXA | STX | PHX | CPX | INX | DEX | HuSAX, _, _, e, _) :: xs =>
|
||||
(e == Elidability.Elidable || e == Elidability.Volatile || dir == Y2X) && loaded == Some(X) && canOptimize(xs, dir, Some(X))
|
||||
case AssemblyLine(TYA | STY | PHY | CPY | INY | DEY | SAY, _, _, e, _) :: xs =>
|
||||
(e == Elidability.Elidable || e == Elidability.Volatile || dir == X2Y) && loaded == Some(Y) && canOptimize(xs, dir, Some(Y))
|
||||
|
||||
case AssemblyLine(SAX | TXS | SBX, _, _, _) :: xs => dir == Y2X && loaded == Some(X) && canOptimize(xs, dir, Some(X))
|
||||
case AssemblyLine(TSX, _, _, _) :: xs => dir == Y2X && loaded != Some(Y) && canOptimize(xs, dir, Some(X))
|
||||
case AssemblyLine0(SAX | TXS | SBX, _, _) :: xs => dir == Y2X && loaded == Some(X) && canOptimize(xs, dir, Some(X))
|
||||
case AssemblyLine0(TSX, _, _) :: xs => dir == Y2X && loaded != Some(Y) && canOptimize(xs, dir, Some(X))
|
||||
|
||||
case _ :: xs => canOptimize(xs, dir, loaded)
|
||||
|
||||
@ -158,71 +158,71 @@ class ChangeIndexRegisterOptimization(preferX2Y: Boolean) extends AssemblyOptimi
|
||||
}
|
||||
|
||||
private def switchX2Y(code: List[AssemblyLine])(implicit log: Logger): List[AssemblyLine] = code match {
|
||||
case (a@AssemblyLine(LDX | TAX, _, _, _))
|
||||
:: (b@AssemblyLine(INC | DEC | ASL | ROL | ROR | LSR | LDY | STY | STZ, AbsoluteX | ZeroPageX, _, _))
|
||||
case (a@AssemblyLine0(LDX | TAX, _, _))
|
||||
:: (b@AssemblyLine0(INC | DEC | ASL | ROL | ROR | LSR | LDY | STY | STZ, AbsoluteX | ZeroPageX, _))
|
||||
:: xs => a :: b :: switchX2Y(xs)
|
||||
case (a@AssemblyLine(LDX | TAX, _, _, _))
|
||||
:: (b@AssemblyLine(_, IndexedX, _, _))
|
||||
case (a@AssemblyLine0(LDX | TAX, _, _))
|
||||
:: (b@AssemblyLine0(_, IndexedX, _))
|
||||
:: xs => a :: b :: switchX2Y(xs)
|
||||
case (a@AssemblyLine(LDX | TAX, _, _, _))
|
||||
:: (i@AssemblyLine(INX | DEX, _, _, _))
|
||||
:: (b@AssemblyLine(INC | DEC | ASL | ROL | ROR | LSR | LDY | STY | STZ, AbsoluteX | ZeroPageX, _, _))
|
||||
case (a@AssemblyLine0(LDX | TAX, _, _))
|
||||
:: (i@AssemblyLine0(INX | DEX, _, _))
|
||||
:: (b@AssemblyLine0(INC | DEC | ASL | ROL | ROR | LSR | LDY | STY | STZ, AbsoluteX | ZeroPageX, _))
|
||||
:: xs => a :: i :: b :: switchX2Y(xs)
|
||||
case (a@AssemblyLine(LDX | TAX, _, _, _))
|
||||
:: (i@AssemblyLine(INX | DEX, _, _, _))
|
||||
:: (b@AssemblyLine(_, IndexedX, _, _))
|
||||
case (a@AssemblyLine0(LDX | TAX, _, _))
|
||||
:: (i@AssemblyLine0(INX | DEX, _, _))
|
||||
:: (b@AssemblyLine0(_, IndexedX, _))
|
||||
:: xs => a :: i :: b :: switchX2Y(xs)
|
||||
case (x@AssemblyLine(TAX, _, _, _)) :: xs => x.copy(opcode = TAY) :: switchX2Y(xs)
|
||||
case (x@AssemblyLine(TXA, _, _, _)) :: xs => x.copy(opcode = TYA) :: switchX2Y(xs)
|
||||
case (x@AssemblyLine(TXY | TYX, _, _, _)) :: xs => x.copy(opcode = TYX) :: switchX2Y(xs) // keep the transfer for the flags
|
||||
case (x@AssemblyLine(STX, _, _, _)) :: xs => x.copy(opcode = STY) :: switchX2Y(xs)
|
||||
case (x@AssemblyLine(LDX, _, _, _)) :: xs => x.copy(opcode = LDY) :: switchX2Y(xs)
|
||||
case (x@AssemblyLine(INX, _, _, _)) :: xs => x.copy(opcode = INY) :: switchX2Y(xs)
|
||||
case (x@AssemblyLine(DEX, _, _, _)) :: xs => x.copy(opcode = DEY) :: switchX2Y(xs)
|
||||
case (x@AssemblyLine(CPX, _, _, _)) :: xs => x.copy(opcode = CPY) :: switchX2Y(xs)
|
||||
case (x@AssemblyLine(PHX, _, _, _)) :: xs => x.copy(opcode = PHY) :: switchX2Y(xs)
|
||||
case (x@AssemblyLine(PLX, _, _, _)) :: xs => x.copy(opcode = PLY) :: switchX2Y(xs)
|
||||
case (x@AssemblyLine(HuSAX, _, _, _)) :: xs => x.copy(opcode = SAY) :: switchX2Y(xs)
|
||||
case (x@AssemblyLine0(TAX, _, _)) :: xs => x.copy(opcode = TAY) :: switchX2Y(xs)
|
||||
case (x@AssemblyLine0(TXA, _, _)) :: xs => x.copy(opcode = TYA) :: switchX2Y(xs)
|
||||
case (x@AssemblyLine0(TXY | TYX, _, _)) :: xs => x.copy(opcode = TYX) :: switchX2Y(xs) // keep the transfer for the flags
|
||||
case (x@AssemblyLine0(STX, _, _)) :: xs => x.copy(opcode = STY) :: switchX2Y(xs)
|
||||
case (x@AssemblyLine0(LDX, _, _)) :: xs => x.copy(opcode = LDY) :: switchX2Y(xs)
|
||||
case (x@AssemblyLine0(INX, _, _)) :: xs => x.copy(opcode = INY) :: switchX2Y(xs)
|
||||
case (x@AssemblyLine0(DEX, _, _)) :: xs => x.copy(opcode = DEY) :: switchX2Y(xs)
|
||||
case (x@AssemblyLine0(CPX, _, _)) :: xs => x.copy(opcode = CPY) :: switchX2Y(xs)
|
||||
case (x@AssemblyLine0(PHX, _, _)) :: xs => x.copy(opcode = PHY) :: switchX2Y(xs)
|
||||
case (x@AssemblyLine0(PLX, _, _)) :: xs => x.copy(opcode = PLY) :: switchX2Y(xs)
|
||||
case (x@AssemblyLine0(HuSAX, _, _)) :: xs => x.copy(opcode = SAY) :: switchX2Y(xs)
|
||||
|
||||
case AssemblyLine(LAX, _, _, _) :: xs => log.fatal("Unexpected LAX")
|
||||
case AssemblyLine(TXS, _, _, _) :: xs => log.fatal("Unexpected TXS")
|
||||
case AssemblyLine(TSX, _, _, _) :: xs => log.fatal("Unexpected TSX")
|
||||
case AssemblyLine(SBX, _, _, _) :: xs => log.fatal("Unexpected SBX")
|
||||
case AssemblyLine(SAX, _, _, _) :: xs => log.fatal("Unexpected SAX")
|
||||
case AssemblyLine(SXY, _, _, _) :: xs => log.fatal("Unexpected SXY")
|
||||
case AssemblyLine0(LAX, _, _) :: xs => log.fatal("Unexpected LAX")
|
||||
case AssemblyLine0(TXS, _, _) :: xs => log.fatal("Unexpected TXS")
|
||||
case AssemblyLine0(TSX, _, _) :: xs => log.fatal("Unexpected TSX")
|
||||
case AssemblyLine0(SBX, _, _) :: xs => log.fatal("Unexpected SBX")
|
||||
case AssemblyLine0(SAX, _, _) :: xs => log.fatal("Unexpected SAX")
|
||||
case AssemblyLine0(SXY, _, _) :: xs => log.fatal("Unexpected SXY")
|
||||
|
||||
case (x@AssemblyLine(_, AbsoluteX, _, _)) :: xs => x.copy(addrMode = AbsoluteY) :: switchX2Y(xs)
|
||||
case (x@AssemblyLine(_, ZeroPageX, _, _)) :: xs => x.copy(addrMode = ZeroPageY) :: switchX2Y(xs)
|
||||
case (x@AssemblyLine(_, IndexedX, _, _)) :: xs => log.fatal("Unexpected IndexedX")
|
||||
case (x@AssemblyLine0(_, AbsoluteX, _)) :: xs => x.copy(addrMode = AbsoluteY) :: switchX2Y(xs)
|
||||
case (x@AssemblyLine0(_, ZeroPageX, _)) :: xs => x.copy(addrMode = ZeroPageY) :: switchX2Y(xs)
|
||||
case (x@AssemblyLine0(_, IndexedX, _)) :: xs => log.fatal("Unexpected IndexedX")
|
||||
|
||||
case x::xs => x :: switchX2Y(xs)
|
||||
case Nil => Nil
|
||||
}
|
||||
|
||||
private def switchY2X(code: List[AssemblyLine])(implicit log: Logger): List[AssemblyLine] = code match {
|
||||
case AssemblyLine(LDY | TAY, _, _, _)
|
||||
:: AssemblyLine(_, IndexedY, _, _)
|
||||
case AssemblyLine0(LDY | TAY, _, _)
|
||||
:: AssemblyLine0(_, IndexedY, _)
|
||||
:: xs => code.take(2) ++ switchY2X(xs)
|
||||
case AssemblyLine(LDY | TAY, _, _, _)
|
||||
:: (i@AssemblyLine(INY | DEY, _, _, _))
|
||||
:: AssemblyLine(_, IndexedY, _, _)
|
||||
case AssemblyLine0(LDY | TAY, _, _)
|
||||
:: (i@AssemblyLine0(INY | DEY, _, _))
|
||||
:: AssemblyLine0(_, IndexedY, _)
|
||||
:: xs => code.take(3) ++ switchY2X(xs)
|
||||
case (x@AssemblyLine(TAY, _, _, _)) :: xs => x.copy(opcode = TAX) :: switchY2X(xs)
|
||||
case (x@AssemblyLine(TYA, _, _, _)) :: xs => x.copy(opcode = TXA) :: switchY2X(xs)
|
||||
case (x@AssemblyLine(TYX | TXY, _, _, _)) :: xs => x.copy(opcode = TXY) :: switchY2X(xs) // keep the transfer for the flags
|
||||
case (x@AssemblyLine(STY, _, _, _)) :: xs => x.copy(opcode = STX) :: switchY2X(xs)
|
||||
case (x@AssemblyLine(LDY, _, _, _)) :: xs => x.copy(opcode = LDX) :: switchY2X(xs)
|
||||
case (x@AssemblyLine(INY, _, _, _)) :: xs => x.copy(opcode = INX) :: switchY2X(xs)
|
||||
case (x@AssemblyLine(DEY, _, _, _)) :: xs => x.copy(opcode = DEX) :: switchY2X(xs)
|
||||
case (x@AssemblyLine(CPY, _, _, _)) :: xs => x.copy(opcode = CPX) :: switchY2X(xs)
|
||||
case (x@AssemblyLine(PHY, _, _, _)) :: xs => x.copy(opcode = PHX) :: switchY2X(xs)
|
||||
case (x@AssemblyLine(PLY, _, _, _)) :: xs => x.copy(opcode = PLX) :: switchY2X(xs)
|
||||
case (x@AssemblyLine(SAY, _, _, _)) :: xs => x.copy(opcode = HuSAX) :: switchY2X(xs)
|
||||
case AssemblyLine(SXY, _, _, _) :: xs => log.fatal("Unexpected SXY")
|
||||
case (x@AssemblyLine0(TAY, _, _)) :: xs => x.copy(opcode = TAX) :: switchY2X(xs)
|
||||
case (x@AssemblyLine0(TYA, _, _)) :: xs => x.copy(opcode = TXA) :: switchY2X(xs)
|
||||
case (x@AssemblyLine0(TYX | TXY, _, _)) :: xs => x.copy(opcode = TXY) :: switchY2X(xs) // keep the transfer for the flags
|
||||
case (x@AssemblyLine0(STY, _, _)) :: xs => x.copy(opcode = STX) :: switchY2X(xs)
|
||||
case (x@AssemblyLine0(LDY, _, _)) :: xs => x.copy(opcode = LDX) :: switchY2X(xs)
|
||||
case (x@AssemblyLine0(INY, _, _)) :: xs => x.copy(opcode = INX) :: switchY2X(xs)
|
||||
case (x@AssemblyLine0(DEY, _, _)) :: xs => x.copy(opcode = DEX) :: switchY2X(xs)
|
||||
case (x@AssemblyLine0(CPY, _, _)) :: xs => x.copy(opcode = CPX) :: switchY2X(xs)
|
||||
case (x@AssemblyLine0(PHY, _, _)) :: xs => x.copy(opcode = PHX) :: switchY2X(xs)
|
||||
case (x@AssemblyLine0(PLY, _, _)) :: xs => x.copy(opcode = PLX) :: switchY2X(xs)
|
||||
case (x@AssemblyLine0(SAY, _, _)) :: xs => x.copy(opcode = HuSAX) :: switchY2X(xs)
|
||||
case AssemblyLine0(SXY, _, _) :: xs => log.fatal("Unexpected SXY")
|
||||
|
||||
case (x@AssemblyLine(_, AbsoluteY, _, _)) :: xs => x.copy(addrMode = AbsoluteX) :: switchY2X(xs)
|
||||
case (x@AssemblyLine(_, ZeroPageY, _, _)) :: xs => x.copy(addrMode = ZeroPageX) :: switchY2X(xs)
|
||||
case AssemblyLine(_, IndexedY, _, _) :: xs => log.fatal("Unexpected IndexedY")
|
||||
case (x@AssemblyLine0(_, AbsoluteY, _)) :: xs => x.copy(addrMode = AbsoluteX) :: switchY2X(xs)
|
||||
case (x@AssemblyLine0(_, ZeroPageY, _)) :: xs => x.copy(addrMode = ZeroPageX) :: switchY2X(xs)
|
||||
case AssemblyLine0(_, IndexedY, _) :: xs => log.fatal("Unexpected IndexedY")
|
||||
|
||||
case x::xs => x :: switchY2X(xs)
|
||||
case Nil => Nil
|
||||
|
@ -2,8 +2,7 @@ package millfork.assembly.mos.opt
|
||||
|
||||
import millfork.assembly.OptimizationContext
|
||||
import millfork.{CompilationFlag, CompilationOptions}
|
||||
import millfork.assembly.mos.AssemblyLine
|
||||
import millfork.assembly.mos.OpcodeClasses
|
||||
import millfork.assembly.mos.{AssemblyLine, AssemblyLine0, OpcodeClasses}
|
||||
import millfork.assembly.opt.AnyStatus
|
||||
import millfork.env._
|
||||
|
||||
@ -45,14 +44,14 @@ object CoarseFlowAnalyzer {
|
||||
flagArray(i) = currentStatus
|
||||
}
|
||||
codeArray(i) match {
|
||||
case AssemblyLine(LABEL, _, MemoryAddressConstant(Label(l)), _) =>
|
||||
case AssemblyLine0(LABEL, _, MemoryAddressConstant(Label(l))) =>
|
||||
val L = l
|
||||
currentStatus = codeArray.indices.flatMap(j => codeArray(j) match {
|
||||
case AssemblyLine(_, _, MemoryAddressConstant(Label(L)), _) => Some(flagArray(j))
|
||||
case AssemblyLine0(_, _, MemoryAddressConstant(Label(L))) => Some(flagArray(j))
|
||||
case _ => None
|
||||
}).fold(currentStatus)(_ ~ _)
|
||||
|
||||
case AssemblyLine(JSR, _, MemoryAddressConstant(th), _) =>
|
||||
case AssemblyLine0(JSR, _, MemoryAddressConstant(th)) =>
|
||||
currentStatus = initialStatus.copy(
|
||||
a = if (niceFunctionProperties(DoesntChangeA -> th.name)) currentStatus.a else AnyStatus,
|
||||
ah = if (niceFunctionProperties(DoesntChangeAH -> th.name)) currentStatus.ah else AnyStatus,
|
||||
@ -63,27 +62,27 @@ object CoarseFlowAnalyzer {
|
||||
c = if (niceFunctionProperties(DoesntChangeC -> th.name)) currentStatus.c else AnyStatus
|
||||
)
|
||||
|
||||
case AssemblyLine(JSR | BYTE, _, _, _) =>
|
||||
case AssemblyLine0(JSR | BYTE, _, _) =>
|
||||
currentStatus = initialStatus
|
||||
|
||||
case AssemblyLine(op, Implied, _, _) if FlowAnalyzerForImplied.hasDefinition(op) =>
|
||||
case AssemblyLine0(op, Implied, _) if FlowAnalyzerForImplied.hasDefinition(op) =>
|
||||
currentStatus = FlowAnalyzerForImplied.get(op)(currentStatus)
|
||||
|
||||
case AssemblyLine(op, Immediate | WordImmediate, NumericConstant(nn, _), _) if FlowAnalyzerForImmediate.hasDefinition(op) =>
|
||||
case AssemblyLine0(op, Immediate | WordImmediate, NumericConstant(nn, _)) if FlowAnalyzerForImmediate.hasDefinition(op) =>
|
||||
currentStatus = FlowAnalyzerForImmediate.get(op)(nn.toInt, currentStatus)
|
||||
|
||||
case AssemblyLine(op, _, MemoryAddressConstant(th: Thing), _)
|
||||
case AssemblyLine0(op, _, MemoryAddressConstant(th: Thing))
|
||||
if th.name == "__reg" && FlowAnalyzerForTheRest.hasDefinition(op) =>
|
||||
currentStatus = FlowAnalyzerForTheRest.get(op)(currentStatus, Some(0))
|
||||
|
||||
case AssemblyLine(op, _, CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th: Thing), NumericConstant(n, _)), _)
|
||||
case AssemblyLine0(op, _, CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th: Thing), NumericConstant(n, _)))
|
||||
if th.name == "__reg" && FlowAnalyzerForTheRest.hasDefinition(op) =>
|
||||
currentStatus = FlowAnalyzerForTheRest.get(op)(currentStatus, Some(n.toInt))
|
||||
|
||||
case AssemblyLine(op, _, _, _) if FlowAnalyzerForTheRest.hasDefinition(op) =>
|
||||
case AssemblyLine0(op, _, _) if FlowAnalyzerForTheRest.hasDefinition(op) =>
|
||||
currentStatus = FlowAnalyzerForTheRest.get(op)(currentStatus, None)
|
||||
|
||||
case AssemblyLine(opcode, addrMode, _, _) =>
|
||||
case AssemblyLine0(opcode, addrMode, _) =>
|
||||
currentStatus = currentStatus.copy(src = AnyStatus)
|
||||
if (OpcodeClasses.ChangesX(opcode)) currentStatus = currentStatus.copy(x = AnyStatus, eqSX = false)
|
||||
if (OpcodeClasses.ChangesY(opcode)) currentStatus = currentStatus.copy(y = AnyStatus)
|
||||
|
@ -2,7 +2,7 @@ package millfork.assembly.mos.opt
|
||||
|
||||
import millfork.CompilationOptions
|
||||
import millfork.assembly.{AssemblyOptimization, OptimizationContext}
|
||||
import millfork.assembly.mos.AssemblyLine
|
||||
import millfork.assembly.mos.{AssemblyLine, AssemblyLine0}
|
||||
import millfork.env._
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.mos.AddrMode._
|
||||
@ -29,12 +29,12 @@ object EmptyMemoryStoreRemoval extends AssemblyOptimization[AssemblyLine] {
|
||||
return code
|
||||
}
|
||||
val stillUsedVariables = code.flatMap {
|
||||
case AssemblyLine(_, _, MemoryAddressConstant(th), _) => Some(th.name)
|
||||
case AssemblyLine(_, _, CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(_, _)), _) => Some(th.name)
|
||||
case AssemblyLine0(_, _, MemoryAddressConstant(th)) => Some(th.name)
|
||||
case AssemblyLine0(_, _, CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(_, _))) => Some(th.name)
|
||||
case _ => None
|
||||
}.toSet
|
||||
val variablesWithAddressesTaken = code.flatMap {
|
||||
case AssemblyLine(_, Immediate, SubbyteConstant(MemoryAddressConstant(th), _), _) =>
|
||||
case AssemblyLine0(_, Immediate, SubbyteConstant(MemoryAddressConstant(th), _)) =>
|
||||
Some(th.name)
|
||||
case _ => None
|
||||
}.toSet
|
||||
|
@ -2,9 +2,9 @@ package millfork.assembly.mos.opt
|
||||
|
||||
import millfork.Cpu
|
||||
import millfork.assembly.mos.AddrMode._
|
||||
import millfork.assembly.mos.AssemblyLine
|
||||
import millfork.assembly.mos.{AssemblyLine, AssemblyLine0}
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.{AssemblyOptimization, OptimizationContext}
|
||||
import millfork.assembly.{AssemblyOptimization, Elidability, OptimizationContext}
|
||||
import millfork.env._
|
||||
import millfork.error.ConsoleLogger
|
||||
|
||||
@ -19,8 +19,8 @@ object EmptyParameterStoreRemoval extends AssemblyOptimization[AssemblyLine] {
|
||||
|
||||
override def optimize(f: NormalFunction, code: List[AssemblyLine], optimizationContext: OptimizationContext): List[AssemblyLine] = {
|
||||
val usedFunctions = code.flatMap {
|
||||
case AssemblyLine(JSR | BSR | JMP, _, MemoryAddressConstant(th), _) => Some(th.name)
|
||||
case AssemblyLine(JSR | BSR | JMP, _, NumericConstant(addr, _), _) => Some("$" + addr.toHexString)
|
||||
case AssemblyLine0(JSR | BSR | JMP, _, MemoryAddressConstant(th)) => Some(th.name)
|
||||
case AssemblyLine0(JSR | BSR | JMP, _, NumericConstant(addr, _)) => Some("$" + addr.toHexString)
|
||||
case _ => None
|
||||
}.toSet
|
||||
val foreignVariables = f.environment.root.things.values.flatMap {
|
||||
@ -50,19 +50,19 @@ object EmptyParameterStoreRemoval extends AssemblyOptimization[AssemblyLine] {
|
||||
case _ => Nil
|
||||
}.toSet
|
||||
val stillReadOrStoredVariables = code.flatMap {
|
||||
case AssemblyLine(_, _, MemoryAddressConstant(th), _) => Some(th.name)
|
||||
case AssemblyLine(_, _, CompoundConstant(_, MemoryAddressConstant(th), _), _) => Some(th.name)
|
||||
case AssemblyLine(_, Immediate, SubbyteConstant(MemoryAddressConstant(th), _), _) => Some(th.name)
|
||||
case AssemblyLine0(_, _, MemoryAddressConstant(th)) => Some(th.name)
|
||||
case AssemblyLine0(_, _, CompoundConstant(_, MemoryAddressConstant(th), _)) => Some(th.name)
|
||||
case AssemblyLine0(_, Immediate, SubbyteConstant(MemoryAddressConstant(th), _)) => Some(th.name)
|
||||
case _ => None
|
||||
}.toSet
|
||||
val stillReadVariables = code.flatMap {
|
||||
case AssemblyLine(op, am, MemoryAddressConstant(th), true)
|
||||
case AssemblyLine(op, am, MemoryAddressConstant(th), Elidability.Elidable, _)
|
||||
if storeInstructions(op) && storeAddrModes(am) => Nil
|
||||
case AssemblyLine(op, am, CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(_, _)), true)
|
||||
case AssemblyLine(op, am, CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(_, _)), Elidability.Elidable, _)
|
||||
if storeInstructions(op) && storeAddrModes(am) => Nil
|
||||
case AssemblyLine(_, _, MemoryAddressConstant(th), _) => Some(th.name)
|
||||
case AssemblyLine(_, _, CompoundConstant(_, MemoryAddressConstant(th), _), _) => Some(th.name)
|
||||
case AssemblyLine(_, Immediate, SubbyteConstant(MemoryAddressConstant(th), _), _) => Some(th.name)
|
||||
case AssemblyLine0(_, _, MemoryAddressConstant(th)) => Some(th.name)
|
||||
case AssemblyLine0(_, _, CompoundConstant(_, MemoryAddressConstant(th), _)) => Some(th.name)
|
||||
case AssemblyLine0(_, Immediate, SubbyteConstant(MemoryAddressConstant(th), _)) => Some(th.name)
|
||||
case _ => None
|
||||
}.toSet
|
||||
|
||||
@ -73,10 +73,10 @@ object EmptyParameterStoreRemoval extends AssemblyOptimization[AssemblyLine] {
|
||||
|
||||
optimizationContext.log.debug(s"Removing pointless store(s) to foreign variables ${unusedForeignVariables.mkString(", ")}")
|
||||
code.filterNot {
|
||||
case AssemblyLine(op, am, MemoryAddressConstant(th), _)
|
||||
case AssemblyLine0(op, am, MemoryAddressConstant(th))
|
||||
if storeInstructions(op) && storeAddrModes(am) =>
|
||||
unusedForeignVariables(th.name)
|
||||
case AssemblyLine(op, am, CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(_, _)), true)
|
||||
case AssemblyLine(op, am, CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(_, _)), Elidability.Elidable, _)
|
||||
if storeInstructions(op) && storeAddrModes(am) =>
|
||||
unusedForeignVariables(th.name)
|
||||
case _ => false
|
||||
|
@ -1,7 +1,7 @@
|
||||
package millfork.assembly.mos.opt
|
||||
|
||||
import millfork.assembly.OptimizationContext
|
||||
import millfork.assembly.mos.{AssemblyLine, Opcode, State}
|
||||
import millfork.assembly.mos.{AssemblyLine, AssemblyLine0, Opcode, State}
|
||||
import millfork.env.{Label, MemoryAddressConstant, NormalFunction}
|
||||
|
||||
/**
|
||||
@ -53,7 +53,7 @@ object FlowAnalyzer {
|
||||
val labelMap: () => Option[Map[String, Int]] = () => req match {
|
||||
case FlowInfoRequirement.NoRequirement => None
|
||||
case _ => Some(code.flatMap {
|
||||
case AssemblyLine(op, _, MemoryAddressConstant(Label(l)), _) if op != Opcode.LABEL => Some(l)
|
||||
case AssemblyLine0(op, _, MemoryAddressConstant(Label(l))) if op != Opcode.LABEL => Some(l)
|
||||
case _ => None
|
||||
}.groupBy(identity).mapValues(_.size))
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package millfork.assembly.mos.opt
|
||||
|
||||
import millfork.CompilationOptions
|
||||
import millfork.assembly.{AssemblyOptimization, OptimizationContext}
|
||||
import millfork.assembly.{AssemblyOptimization, Elidability, OptimizationContext}
|
||||
import millfork.assembly.mos.AssemblyLine
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.mos.AddrMode._
|
||||
@ -17,9 +17,9 @@ object HudsonOptimizations {
|
||||
def removeLoadZero(f: NormalFunction, code: List[AssemblyLine], optimizationContext: OptimizationContext): List[AssemblyLine] = {
|
||||
ReverseFlowAnalyzer.analyze(f, code, optimizationContext).zip(code).map {
|
||||
case (i, l) if i.n != Unimportant || i.z != Unimportant => l
|
||||
case (i, AssemblyLine(LDA, Immediate, NumericConstant(0, _), true)) => AssemblyLine.implied(CLA)
|
||||
case (_, AssemblyLine(LDX, Immediate, NumericConstant(0, _), true)) => AssemblyLine.implied(CLX)
|
||||
case (_, AssemblyLine(LDY, Immediate, NumericConstant(0, _), true)) => AssemblyLine.implied(CLY)
|
||||
case (i, AssemblyLine(LDA, Immediate, NumericConstant(0, _), Elidability.Elidable | Elidability.Volatile, s)) => AssemblyLine.implied(CLA).pos(s)
|
||||
case (_, AssemblyLine(LDX, Immediate, NumericConstant(0, _), Elidability.Elidable | Elidability.Volatile, s)) => AssemblyLine.implied(CLX).pos(s)
|
||||
case (_, AssemblyLine(LDY, Immediate, NumericConstant(0, _), Elidability.Elidable | Elidability.Volatile, s)) => AssemblyLine.implied(CLY).pos(s)
|
||||
case (_, l) => l
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,12 @@ package millfork.assembly.mos.opt
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
import millfork.assembly.mos.{AddrMode, AssemblyLine, Opcode}
|
||||
import millfork.assembly.mos.{AddrMode, AssemblyLine, AssemblyLine0, Opcode}
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.env.{Label, MemoryAddressConstant, NormalFunction}
|
||||
import millfork.error.ConsoleLogger
|
||||
import millfork.CompilationOptions
|
||||
import millfork.assembly.Elidability
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
@ -41,12 +42,12 @@ object JumpFixing {
|
||||
o += line.sizeInBytes
|
||||
}
|
||||
val labelOffsets = code.zipWithIndex.flatMap {
|
||||
case (AssemblyLine(LABEL, _, MemoryAddressConstant(Label(label)), _), ix) => Some(label -> offsets(ix))
|
||||
case (AssemblyLine0(LABEL, _, MemoryAddressConstant(Label(label))), ix) => Some(label -> offsets(ix))
|
||||
case _ => None
|
||||
}.toMap
|
||||
var changed = false
|
||||
val result = code.zipWithIndex.flatMap {
|
||||
case (line@AssemblyLine(op, AddrMode.Relative, MemoryAddressConstant(Label(label)), true), ix) =>
|
||||
case (line@AssemblyLine(op, AddrMode.Relative, MemoryAddressConstant(Label(label)), Elidability.Elidable, _), ix) =>
|
||||
labelOffsets.get(label).fold(List(line)) { labelOffset =>
|
||||
val thisOffset = offsets(ix)
|
||||
if (invalidShortJump(thisOffset, labelOffset)) {
|
||||
|
@ -1,7 +1,8 @@
|
||||
package millfork.assembly.mos.opt
|
||||
|
||||
import millfork.CompilationOptions
|
||||
import millfork.assembly.mos.{AssemblyLine, OpcodeClasses}
|
||||
import millfork.assembly.Elidability
|
||||
import millfork.assembly.mos.{AssemblyLine, AssemblyLine0, OpcodeClasses}
|
||||
import millfork.env.{Label, MemoryAddressConstant}
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.mos.AddrMode._
|
||||
@ -21,20 +22,20 @@ object JumpFollowing {
|
||||
val currentLabels = mutable.Set[String]()
|
||||
for (line <- code) {
|
||||
line match {
|
||||
case AssemblyLine(LABEL, _, MemoryAddressConstant(Label(label)), _) =>
|
||||
case AssemblyLine0(LABEL, _, MemoryAddressConstant(Label(label))) =>
|
||||
currentLabels += label
|
||||
case AssemblyLine(op, _, _, _) if OpcodeClasses.NoopDiscardsFlags(op) =>
|
||||
case AssemblyLine(LABEL, _, _, _) =>
|
||||
case AssemblyLine(RTS, _, _, _) =>
|
||||
case AssemblyLine0(op, _, _) if OpcodeClasses.NoopDiscardsFlags(op) =>
|
||||
case AssemblyLine0(LABEL, _, _) =>
|
||||
case AssemblyLine0(RTS, _, _) =>
|
||||
labelsToRts ++= currentLabels
|
||||
currentLabels.clear()
|
||||
case AssemblyLine(RTI, _, _, _) =>
|
||||
case AssemblyLine0(RTI, _, _) =>
|
||||
labelsToRti ++= currentLabels
|
||||
currentLabels.clear()
|
||||
case AssemblyLine(RTL, _, _, _) =>
|
||||
case AssemblyLine0(RTL, _, _) =>
|
||||
labelsToRtl ++= currentLabels
|
||||
currentLabels.clear()
|
||||
case AssemblyLine(JMP | BRA, Absolute | Relative, MemoryAddressConstant(Label(label)), _) =>
|
||||
case AssemblyLine0(JMP | BRA, Absolute | Relative, MemoryAddressConstant(Label(label))) =>
|
||||
labelsToJumps ++= currentLabels.map(_ -> label)
|
||||
currentLabels.clear()
|
||||
case _ =>
|
||||
@ -42,19 +43,19 @@ object JumpFollowing {
|
||||
}
|
||||
}
|
||||
code.map {
|
||||
case jump@AssemblyLine(JMP | BRA, Absolute | Relative | LongRelative | LongAbsolute, MemoryAddressConstant(Label(label)), true) =>
|
||||
case jump@AssemblyLine(JMP | BRA, Absolute | Relative | LongRelative | LongAbsolute, MemoryAddressConstant(Label(label)), Elidability.Elidable, s) =>
|
||||
if (labelsToRts(label)) {
|
||||
options.log.debug(s"Optimizing ${jump.opcode} straight into RTS")
|
||||
AssemblyLine.implied(RTS)
|
||||
AssemblyLine.implied(RTS).pos(s)
|
||||
} else if (labelsToRti(label)) {
|
||||
options.log.debug(s"Optimizing ${jump.opcode} straight into RTI")
|
||||
AssemblyLine.implied(RTI)
|
||||
AssemblyLine.implied(RTI).pos(s)
|
||||
} else if (labelsToRtl(label)) {
|
||||
options.log.debug(s"Optimizing ${jump.opcode} straight into RTL")
|
||||
AssemblyLine.implied(RTL)
|
||||
AssemblyLine.implied(RTL).pos(s)
|
||||
} else if (labelsToJumps.contains(label)) {
|
||||
options.log.debug(s"Optimizing ${jump.opcode} straight into a jump")
|
||||
AssemblyLine.absolute(JMP, Label(labelsToJumps(label)))
|
||||
AssemblyLine.absolute(JMP, Label(labelsToJumps(label))).pos(s)
|
||||
} else jump
|
||||
case x => x
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package millfork.assembly.mos.opt
|
||||
|
||||
import millfork.assembly.OptimizationContext
|
||||
import millfork.assembly.mos.{AddrMode, AssemblyLine}
|
||||
import millfork.assembly.{Elidability, OptimizationContext}
|
||||
import millfork.assembly.mos.{AddrMode, AssemblyLine, AssemblyLine0}
|
||||
import millfork.{CompilationFlag, CompilationOptions}
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.env.{Label, MemoryAddressConstant, NormalFunction}
|
||||
@ -27,13 +27,13 @@ object JumpShortening {
|
||||
o += line.sizeInBytes
|
||||
}
|
||||
val labelOffsets = code.zipWithIndex.flatMap {
|
||||
case (AssemblyLine(LABEL, _, MemoryAddressConstant(Label(label)), _), ix) => Some(label -> offsets(ix))
|
||||
case (AssemblyLine0(LABEL, _, MemoryAddressConstant(Label(label))), ix) => Some(label -> offsets(ix))
|
||||
case _ => None
|
||||
}.toMap
|
||||
val cmos = options.flags(CompilationFlag.EmitCmosOpcodes)
|
||||
if (cmos) {
|
||||
code.zipWithIndex.map {
|
||||
case (line@AssemblyLine(JMP, AddrMode.Absolute, MemoryAddressConstant(Label(label)), true), ix) =>
|
||||
case (line@AssemblyLine(JMP, AddrMode.Absolute, MemoryAddressConstant(Label(label)), Elidability.Elidable, _), ix) =>
|
||||
labelOffsets.get(label).fold(line) { labelOffset =>
|
||||
val thisOffset = offsets(ix)
|
||||
if (validShortJump(thisOffset, labelOffset)) {
|
||||
@ -51,7 +51,7 @@ object JumpShortening {
|
||||
}
|
||||
} else {
|
||||
FlowAnalyzer.analyze(f, code, optimizationContext, FlowInfoRequirement.ForwardFlow).zipWithIndex.map {
|
||||
case ((info, line@AssemblyLine(JMP, AddrMode.Absolute, MemoryAddressConstant(Label(label)), _)), ix) =>
|
||||
case ((info, line@AssemblyLine0(JMP, AddrMode.Absolute, MemoryAddressConstant(Label(label)))), ix) =>
|
||||
labelOffsets.get(label).fold(line) { labelOffset =>
|
||||
val thisOffset = offsets(ix)
|
||||
if (validShortJump(thisOffset, labelOffset)) {
|
||||
|
@ -1,10 +1,10 @@
|
||||
package millfork.assembly.mos.opt
|
||||
|
||||
import millfork.CompilationOptions
|
||||
import millfork.assembly.{AssemblyOptimization, OptimizationContext}
|
||||
import millfork.assembly.{AssemblyOptimization, Elidability, OptimizationContext}
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.mos.AddrMode._
|
||||
import millfork.assembly.mos.{AssemblyLine, OpcodeClasses}
|
||||
import millfork.assembly.mos.{AssemblyLine, AssemblyLine0, OpcodeClasses}
|
||||
import millfork.assembly.opt.SingleStatus
|
||||
import millfork.env._
|
||||
import millfork.error.{ConsoleLogger, Logger}
|
||||
@ -19,7 +19,7 @@ object LocalVariableReadOptimization extends AssemblyOptimization[AssemblyLine]
|
||||
override def optimize(f: NormalFunction, code: List[AssemblyLine], optimizationContext: OptimizationContext): List[AssemblyLine] = {
|
||||
|
||||
val stillUsedVariables = code.flatMap {
|
||||
case AssemblyLine(_, _, MemoryAddressConstant(th: MemoryVariable), _) => th match {
|
||||
case AssemblyLine0(_, _, MemoryAddressConstant(th: MemoryVariable)) => th match {
|
||||
case MemoryVariable(name, typ, VariableAllocationMethod.Auto | VariableAllocationMethod.Register)
|
||||
if typ.size == 1 => Some(name)
|
||||
case _ => None
|
||||
@ -27,7 +27,7 @@ object LocalVariableReadOptimization extends AssemblyOptimization[AssemblyLine]
|
||||
case _ => None
|
||||
}.toSet
|
||||
val variablesWithAddressesTaken = code.flatMap {
|
||||
case AssemblyLine(_, _, SubbyteConstant(MemoryAddressConstant(th), _), _) => Some(th.name)
|
||||
case AssemblyLine0(_, _, SubbyteConstant(MemoryAddressConstant(th), _)) => Some(th.name)
|
||||
case _ => None
|
||||
}.toSet
|
||||
val eligibleVariables = (stillUsedVariables -- variablesWithAddressesTaken).filterNot(_.startsWith("__"))
|
||||
@ -56,11 +56,11 @@ object LocalVariableReadOptimization extends AssemblyOptimization[AssemblyLine]
|
||||
case (AssemblyLine(op@(
|
||||
LDA | LDX | LDY | LDZ |
|
||||
ADC | ORA | EOR | AND | SBC |
|
||||
CMP | CPX | CPY | CPZ), Absolute | ZeroPage, MemoryAddressConstant(th), true), _) :: xs
|
||||
CMP | CPX | CPY | CPZ), Absolute | ZeroPage, MemoryAddressConstant(th), Elidability.Elidable, s), _) :: xs
|
||||
if variables(th.name) && map.contains(th.name) =>
|
||||
true -> (AssemblyLine.immediate(op, map(th.name)) :: optimizeImpl(xs, variables, map)._2)
|
||||
true -> (AssemblyLine.immediate(op, map(th.name)).pos(s) :: optimizeImpl(xs, variables, map)._2)
|
||||
|
||||
case (x@AssemblyLine(STA, Absolute | ZeroPage, MemoryAddressConstant(th), _), status) :: xs
|
||||
case (x@AssemblyLine0(STA, Absolute | ZeroPage, MemoryAddressConstant(th)), status) :: xs
|
||||
if variables(th.name) =>
|
||||
val newMap = status.a match {
|
||||
case SingleStatus(n) => map + (th.name -> n)
|
||||
@ -68,7 +68,7 @@ object LocalVariableReadOptimization extends AssemblyOptimization[AssemblyLine]
|
||||
}
|
||||
x :: optimizeImpl(xs, variables, newMap)
|
||||
|
||||
case (x@AssemblyLine(STX, Absolute | ZeroPage, MemoryAddressConstant(th), _), status) :: xs
|
||||
case (x@AssemblyLine0(STX, Absolute | ZeroPage, MemoryAddressConstant(th)), status) :: xs
|
||||
if variables(th.name) =>
|
||||
val newMap = status.x match {
|
||||
case SingleStatus(n) => map + (th.name -> n)
|
||||
@ -76,7 +76,7 @@ object LocalVariableReadOptimization extends AssemblyOptimization[AssemblyLine]
|
||||
}
|
||||
x :: optimizeImpl(xs, variables, newMap)
|
||||
|
||||
case (x@AssemblyLine(STY, Absolute | ZeroPage, MemoryAddressConstant(th: ThingInMemory), _), status) :: xs
|
||||
case (x@AssemblyLine0(STY, Absolute | ZeroPage, MemoryAddressConstant(th: ThingInMemory)), status) :: xs
|
||||
if variables(th.name) =>
|
||||
val newMap = status.y match {
|
||||
case SingleStatus(n) => map + (th.name -> n)
|
||||
@ -84,7 +84,7 @@ object LocalVariableReadOptimization extends AssemblyOptimization[AssemblyLine]
|
||||
}
|
||||
x :: optimizeImpl(xs, variables, newMap)
|
||||
|
||||
case (x@AssemblyLine(STZ, Absolute | ZeroPage, MemoryAddressConstant(th), _), status) :: xs
|
||||
case (x@AssemblyLine0(STZ, Absolute | ZeroPage, MemoryAddressConstant(th)), status) :: xs
|
||||
if variables(th.name) =>
|
||||
val newMap = status.iz match {
|
||||
case SingleStatus(n) => map + (th.name -> n)
|
||||
@ -92,7 +92,7 @@ object LocalVariableReadOptimization extends AssemblyOptimization[AssemblyLine]
|
||||
}
|
||||
x :: optimizeImpl(xs, variables, newMap)
|
||||
|
||||
case (x@AssemblyLine(SAX, Absolute | ZeroPage, MemoryAddressConstant(th), _), status) :: xs
|
||||
case (x@AssemblyLine0(SAX, Absolute | ZeroPage, MemoryAddressConstant(th)), status) :: xs
|
||||
if variables(th.name) =>
|
||||
val newMap = (status.a, status.x) match {
|
||||
case (SingleStatus(m), SingleStatus(n)) => map + (th.name -> (m & n))
|
||||
@ -102,28 +102,28 @@ object LocalVariableReadOptimization extends AssemblyOptimization[AssemblyLine]
|
||||
}
|
||||
x :: optimizeImpl(xs, variables, newMap)
|
||||
|
||||
case (x@AssemblyLine(INC | ISC, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (x@AssemblyLine0(INC | ISC, Absolute | ZeroPage, MemoryAddressConstant(th)), _) :: xs
|
||||
if map.contains(th.name) =>
|
||||
x :: optimizeImpl(xs, variables, map + (th.name -> map(th.name).+(1).&(0xff)))
|
||||
|
||||
case (x@AssemblyLine(DEC | DCP, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (x@AssemblyLine0(DEC | DCP, Absolute | ZeroPage, MemoryAddressConstant(th)), _) :: xs
|
||||
if map.contains(th.name) =>
|
||||
x :: optimizeImpl(xs, variables, map + (th.name -> map(th.name).-(1).&(0xff)))
|
||||
|
||||
case (x@AssemblyLine(ASL | SLO, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (x@AssemblyLine0(ASL | SLO, Absolute | ZeroPage, MemoryAddressConstant(th)), _) :: xs
|
||||
if map.contains(th.name) =>
|
||||
x :: optimizeImpl(xs, variables, map + (th.name -> map(th.name).<<(1).&(0xff)))
|
||||
|
||||
case (x@AssemblyLine(LSR | SRE, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (x@AssemblyLine0(LSR | SRE, Absolute | ZeroPage, MemoryAddressConstant(th)), _) :: xs
|
||||
if map.contains(th.name) =>
|
||||
x :: optimizeImpl(xs, variables, map + (th.name -> map(th.name).&(0xff).>>(1)))
|
||||
|
||||
// TODO: consider handling some more opcodes
|
||||
case (x@AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (x@AssemblyLine0(op, Absolute | ZeroPage, MemoryAddressConstant(th)), _) :: xs
|
||||
if OpcodeClasses.ChangesMemoryAlways(op) && map.contains(th.name) =>
|
||||
x :: optimizeImpl(xs, variables, map - th.name)
|
||||
|
||||
case (x@AssemblyLine(LABEL, _, _, _), _) :: xs => x :: optimizeImpl(xs, variables, Map())
|
||||
case (x@AssemblyLine0(LABEL, _, _), _) :: xs => x :: optimizeImpl(xs, variables, Map())
|
||||
case (x, _) :: xs => x :: optimizeImpl(xs, variables, map)
|
||||
case Nil => (false, Nil)
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ package millfork.assembly.mos.opt
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
import millfork.{CompilationFlag, CompilationOptions}
|
||||
import millfork.assembly.mos.{AssemblyLine, State}
|
||||
import millfork.assembly.mos.{AssemblyLine, AssemblyLine0, State}
|
||||
import millfork.assembly.mos.OpcodeClasses._
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.mos.AddrMode._
|
||||
@ -71,12 +71,12 @@ object LoopUnrolling {
|
||||
|
||||
private def fixLabels(code: List[AssemblyLine]) = {
|
||||
val localLabels = code.flatMap {
|
||||
case AssemblyLine(LABEL, _, MemoryAddressConstant(Label(l)), _) => Some(l)
|
||||
case AssemblyLine0(LABEL, _, MemoryAddressConstant(Label(l))) => Some(l)
|
||||
case _ => None
|
||||
}.toSet
|
||||
val labelPrefix = getNextLabel("ur")
|
||||
code.map {
|
||||
case s@AssemblyLine(_, _, MemoryAddressConstant(Label(l)), _) if localLabels(l) =>
|
||||
case s@AssemblyLine0(_, _, MemoryAddressConstant(Label(l))) if localLabels(l) =>
|
||||
s.copy(parameter = MemoryAddressConstant(Label(labelPrefix + l)))
|
||||
case s => s
|
||||
}
|
||||
|
@ -147,10 +147,10 @@ object ReverseFlowAnalyzer {
|
||||
}
|
||||
val currentLine = codeArray(i)
|
||||
currentLine match {
|
||||
case AssemblyLine(opcode, Relative | LongRelative, MemoryAddressConstant(Label(l)), _) if OpcodeClasses.ShortConditionalBranching(opcode) =>
|
||||
case AssemblyLine0(opcode, Relative | LongRelative, MemoryAddressConstant(Label(l))) if OpcodeClasses.ShortConditionalBranching(opcode) =>
|
||||
val L = l
|
||||
val labelIndex = codeArray.indexWhere {
|
||||
case AssemblyLine(LABEL, _, MemoryAddressConstant(Label(L)), _) => true
|
||||
case AssemblyLine0(LABEL, _, MemoryAddressConstant(Label(L))) => true
|
||||
case _ => false
|
||||
}
|
||||
currentImportance = if (labelIndex < 0) finalImportance else importanceArray(labelIndex) ~ currentImportance
|
||||
@ -158,7 +158,7 @@ object ReverseFlowAnalyzer {
|
||||
}
|
||||
currentLine match {
|
||||
|
||||
case AssemblyLine(JSR | JMP, Absolute | LongAbsolute, MemoryAddressConstant(fun: FunctionInMemory), _) =>
|
||||
case AssemblyLine0(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 = importanceBeforeJsr
|
||||
fun.params match {
|
||||
@ -218,15 +218,15 @@ object ReverseFlowAnalyzer {
|
||||
else result.r3
|
||||
)
|
||||
|
||||
case AssemblyLine(ANC, _, NumericConstant(0, _), _) =>
|
||||
case AssemblyLine0(ANC, _, NumericConstant(0, _)) =>
|
||||
currentImportance = currentImportance.copy(c = Unimportant, n = Unimportant, z = Unimportant, a = Unimportant)
|
||||
case AssemblyLine(AND, _, NumericConstant(0, _), _) =>
|
||||
case AssemblyLine0(AND, _, NumericConstant(0, _)) =>
|
||||
currentImportance = currentImportance.copy(n = Unimportant, z = Unimportant, a = Unimportant)
|
||||
|
||||
case AssemblyLine(opcode, Implied, _, _) if ReverseFlowAnalyzerPerImpiedOpcode.hasDefinition(opcode) =>
|
||||
case AssemblyLine0(opcode, Implied, _) if ReverseFlowAnalyzerPerImpiedOpcode.hasDefinition(opcode) =>
|
||||
currentImportance = ReverseFlowAnalyzerPerImpiedOpcode.get(opcode)(currentImportance)
|
||||
|
||||
case AssemblyLine(opcode, addrMode, _, _) if addrMode != Implied && ReverseFlowAnalyzerPerOpcode.hasDefinition(opcode) =>
|
||||
case AssemblyLine0(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)
|
||||
@ -235,18 +235,18 @@ object ReverseFlowAnalyzer {
|
||||
else if (addrMode == IndexedZ /*|| addrMode == LongIndexedZ*/ )
|
||||
currentImportance = currentImportance.copy(iz = Important)
|
||||
|
||||
case AssemblyLine(JMP | BRA, Absolute | Relative | LongAbsolute | LongRelative, MemoryAddressConstant(Label(l)), _) =>
|
||||
case AssemblyLine0(JMP | BRA, Absolute | Relative | LongAbsolute | LongRelative, MemoryAddressConstant(Label(l))) =>
|
||||
val L = l
|
||||
val labelIndex = codeArray.indexWhere {
|
||||
case AssemblyLine(LABEL, _, MemoryAddressConstant(Label(L)), _) => true
|
||||
case AssemblyLine0(LABEL, _, MemoryAddressConstant(Label(L))) => true
|
||||
case _ => false
|
||||
}
|
||||
currentImportance = if (labelIndex < 0) finalImportance else importanceArray(labelIndex)
|
||||
|
||||
case AssemblyLine(JMP, Indirect | AbsoluteIndexedX | LongIndirect, _, _) =>
|
||||
case AssemblyLine0(JMP, Indirect | AbsoluteIndexedX | LongIndirect, _) =>
|
||||
currentImportance = finalImportance
|
||||
|
||||
case AssemblyLine(REP | SEP, _, NumericConstant(n, _), _) =>
|
||||
case AssemblyLine0(REP | SEP, _, NumericConstant(n, _)) =>
|
||||
if ((n & 1) != 0) currentImportance = currentImportance.copy(c = Unimportant)
|
||||
if ((n & 2) != 0) currentImportance = currentImportance.copy(z = Unimportant)
|
||||
if ((n & 8) != 0) currentImportance = currentImportance.copy(d = Unimportant)
|
||||
@ -255,7 +255,7 @@ object ReverseFlowAnalyzer {
|
||||
if ((n & 0x40) != 0) currentImportance = currentImportance.copy(v = Unimportant)
|
||||
if ((n & 0x80) != 0) currentImportance = currentImportance.copy(n = Unimportant)
|
||||
|
||||
case AssemblyLine(opcode, addrMode, _, _) =>
|
||||
case AssemblyLine0(opcode, addrMode, _) =>
|
||||
val reallyIgnoreC =
|
||||
currentImportance.c == Unimportant &&
|
||||
currentImportance.v == Unimportant &&
|
||||
|
@ -63,6 +63,12 @@ class RuleBasedAssemblyOptimization(val name: String, val needsFlowInfo: FlowInf
|
||||
case Some(rest: List[(FlowInfo, AssemblyLine)]) =>
|
||||
val matchedChunkToOptimize: List[AssemblyLine] = code.take(code.length - rest.length).map(_._2)
|
||||
val optimizedChunk: List[AssemblyLine] = rule.result(matchedChunkToOptimize, ctx)
|
||||
val optimizedChunkWithSource =
|
||||
if (optimizedChunk.isEmpty) optimizedChunk
|
||||
else if (matchedChunkToOptimize.size == 1) optimizedChunk.map(_.pos(matchedChunkToOptimize.head.source))
|
||||
else if (optimizedChunk.size == 1) optimizedChunk.map(_.pos(SourceLine.merge(matchedChunkToOptimize.map(_.source))))
|
||||
else if (matchedChunkToOptimize.flatMap(_.source).toSet.size == 1) optimizedChunk.map(_.pos(SourceLine.merge(matchedChunkToOptimize.map(_.source))))
|
||||
else optimizedChunk
|
||||
log.debug(s"Applied $name ($index)")
|
||||
if (needsFlowInfo != FlowInfoRequirement.NoRequirement) {
|
||||
val before = code.head._1.statusBefore
|
||||
@ -73,12 +79,12 @@ class RuleBasedAssemblyOptimization(val name: String, val needsFlowInfo: FlowInf
|
||||
if (log.traceEnabled) {
|
||||
matchedChunkToOptimize.filter(_.isPrintable).foreach(l => log.trace(l.toString))
|
||||
log.trace(" ↓")
|
||||
optimizedChunk.filter(_.isPrintable).foreach(l => log.trace(l.toString))
|
||||
optimizedChunkWithSource.filter(_.isPrintable).foreach(l => log.trace(l.toString))
|
||||
}
|
||||
if (needsFlowInfo != FlowInfoRequirement.NoRequirement) {
|
||||
return optimizedChunk ++ optimizeImpl(f, rest, optimizationContext)
|
||||
return optimizedChunkWithSource ++ optimizeImpl(f, rest, optimizationContext)
|
||||
} else {
|
||||
return optimize(f, optimizedChunk ++ rest.map(_._2), optimizationContext)
|
||||
return optimize(f, optimizedChunkWithSource ++ rest.map(_._2), optimizationContext)
|
||||
}
|
||||
case None => ()
|
||||
}
|
||||
@ -191,19 +197,19 @@ class AssemblyMatchingContext(val compilationOptions: CompilationOptions,
|
||||
val jumps = mutable.Set[String]()
|
||||
get[List[AssemblyLine]](i).foreach {
|
||||
// JSR and BSR are allowed
|
||||
case AssemblyLine(Opcode.RTS | Opcode.RTI | Opcode.RTL | Opcode.BRK, _, _, _) =>
|
||||
case AssemblyLine0(Opcode.RTS | Opcode.RTI | Opcode.RTL | Opcode.BRK, _, _) =>
|
||||
return false
|
||||
case AssemblyLine(Opcode.JMP, AddrMode.Indirect | AddrMode.AbsoluteIndexedX | AddrMode.LongIndirect, _, _) =>
|
||||
case AssemblyLine0(Opcode.JMP, AddrMode.Indirect | AddrMode.AbsoluteIndexedX | AddrMode.LongIndirect, _) =>
|
||||
return false
|
||||
case AssemblyLine(Opcode.LABEL, _, MemoryAddressConstant(Label(l)), _) =>
|
||||
case AssemblyLine0(Opcode.LABEL, _, MemoryAddressConstant(Label(l))) =>
|
||||
labels += l
|
||||
case AssemblyLine(Opcode.JMP, AddrMode.Absolute, MemoryAddressConstant(Label(l)), _) =>
|
||||
case AssemblyLine0(Opcode.JMP, AddrMode.Absolute, MemoryAddressConstant(Label(l))) =>
|
||||
jumps += l
|
||||
case AssemblyLine(Opcode.JMP, AddrMode.Absolute | AddrMode.LongAbsolute, _, _) =>
|
||||
case AssemblyLine0(Opcode.JMP, AddrMode.Absolute | AddrMode.LongAbsolute, _) =>
|
||||
return false
|
||||
case AssemblyLine(_, AddrMode.Relative, MemoryAddressConstant(Label(l)), _) =>
|
||||
case AssemblyLine0(_, AddrMode.Relative, MemoryAddressConstant(Label(l))) =>
|
||||
jumps += l
|
||||
case AssemblyLine(br, _, _, _) if OpcodeClasses.ShortBranching(br) =>
|
||||
case AssemblyLine0(br, _, _) if OpcodeClasses.ShortBranching(br) =>
|
||||
return false
|
||||
case _ => ()
|
||||
}
|
||||
@ -721,7 +727,7 @@ case class EitherPattern(l: AssemblyLinePattern, r: AssemblyLinePattern) extends
|
||||
|
||||
case object Elidable extends AssemblyLinePattern {
|
||||
override def matchLineTo(ctx: AssemblyMatchingContext, flowInfo: FlowInfo, line: AssemblyLine): Boolean =
|
||||
line.elidable
|
||||
line.elidability == Elidability.Elidable
|
||||
}
|
||||
|
||||
case object DebugMatching extends AssemblyPattern {
|
||||
@ -849,8 +855,8 @@ case object ChangesA extends AssemblyLinePattern {
|
||||
import Opcode._
|
||||
import AddrMode._
|
||||
line match {
|
||||
case AssemblyLine(JSR, Absolute | LongAbsolute, MemoryAddressConstant(th), _) => ctx.functionChangesA(th.name)
|
||||
case AssemblyLine(_, Implied, _, _) => OpcodeClasses.ChangesAIfImplied(line.opcode) || OpcodeClasses.ChangesAAlways(line.opcode)
|
||||
case AssemblyLine0(JSR, Absolute | LongAbsolute, MemoryAddressConstant(th)) => ctx.functionChangesA(th.name)
|
||||
case AssemblyLine0(_, Implied, _) => OpcodeClasses.ChangesAIfImplied(line.opcode) || OpcodeClasses.ChangesAAlways(line.opcode)
|
||||
case _ => OpcodeClasses.ChangesAAlways(line.opcode)
|
||||
}
|
||||
}
|
||||
@ -861,7 +867,7 @@ case object ChangesX extends AssemblyLinePattern {
|
||||
import Opcode._
|
||||
import AddrMode._
|
||||
line match {
|
||||
case AssemblyLine(JSR, Absolute | LongAbsolute, MemoryAddressConstant(th), _) => ctx.functionChangesX(th.name)
|
||||
case AssemblyLine0(JSR, Absolute | LongAbsolute, MemoryAddressConstant(th)) => ctx.functionChangesX(th.name)
|
||||
case _ => OpcodeClasses.ChangesX(line.opcode)
|
||||
}
|
||||
}
|
||||
@ -872,7 +878,7 @@ case object ChangesY extends AssemblyLinePattern {
|
||||
import Opcode._
|
||||
import AddrMode._
|
||||
line match {
|
||||
case AssemblyLine(JSR, Absolute | LongAbsolute, MemoryAddressConstant(th), _) => ctx.functionChangesY(th.name)
|
||||
case AssemblyLine0(JSR, Absolute | LongAbsolute, MemoryAddressConstant(th)) => ctx.functionChangesY(th.name)
|
||||
case _ => OpcodeClasses.ChangesY(line.opcode)
|
||||
}
|
||||
}
|
||||
@ -885,7 +891,7 @@ case object ReadsC extends AssemblyLinePattern {
|
||||
import Opcode._
|
||||
import AddrMode._
|
||||
line match {
|
||||
case AssemblyLine(JSR | BSR, Absolute | LongAbsolute, MemoryAddressConstant(th), _) => ctx.functionReadsC(th.name)
|
||||
case AssemblyLine0(JSR | BSR, Absolute | LongAbsolute, MemoryAddressConstant(th)) => ctx.functionReadsC(th.name)
|
||||
case _ => OpcodeClasses.ReadsC(line.opcode)
|
||||
}
|
||||
}
|
||||
@ -896,7 +902,7 @@ case object ReadsD extends AssemblyLinePattern {
|
||||
import Opcode._
|
||||
import AddrMode._
|
||||
line match {
|
||||
case AssemblyLine(JSR | BSR, Absolute | LongAbsolute, MemoryAddressConstant(th), _) => ctx.functionReadsD(th.name)
|
||||
case AssemblyLine0(JSR | BSR, Absolute | LongAbsolute, MemoryAddressConstant(th)) => ctx.functionReadsD(th.name)
|
||||
case _ => OpcodeClasses.ReadsD(line.opcode)
|
||||
}
|
||||
}
|
||||
@ -911,7 +917,7 @@ case object ChangesC extends AssemblyLinePattern {
|
||||
import Opcode._
|
||||
import AddrMode._
|
||||
line match {
|
||||
case AssemblyLine(JSR | BSR, Absolute | LongAbsolute, MemoryAddressConstant(th), _) => ctx.functionChangesC(th.name)
|
||||
case AssemblyLine0(JSR | BSR, Absolute | LongAbsolute, MemoryAddressConstant(th)) => ctx.functionChangesC(th.name)
|
||||
case _ => OpcodeClasses.ChangesC(line.opcode)
|
||||
}
|
||||
}
|
||||
@ -950,8 +956,8 @@ case object ChangesAH extends AssemblyLinePattern {
|
||||
import Opcode._
|
||||
import AddrMode._
|
||||
line match {
|
||||
case AssemblyLine(JSR, Absolute | LongAbsolute, MemoryAddressConstant(th), _) => ctx.functionChangesAH(th.name)
|
||||
case AssemblyLine(_, Implied, _, _) => OpcodeClasses.ChangesAHIfImplied(line.opcode) || OpcodeClasses.ChangesAHAlways(line.opcode)
|
||||
case AssemblyLine0(JSR, Absolute | LongAbsolute, MemoryAddressConstant(th)) => ctx.functionChangesAH(th.name)
|
||||
case AssemblyLine0(_, Implied, _) => OpcodeClasses.ChangesAHIfImplied(line.opcode) || OpcodeClasses.ChangesAHAlways(line.opcode)
|
||||
case _ => OpcodeClasses.ChangesAHAlways(line.opcode)
|
||||
}
|
||||
}
|
||||
@ -959,15 +965,15 @@ case object ChangesAH extends AssemblyLinePattern {
|
||||
|
||||
case object ChangesM extends TrivialAssemblyLinePattern {
|
||||
override def apply(line: AssemblyLine): Boolean = line match {
|
||||
case AssemblyLine(Opcode.SEP | Opcode.REP, AddrMode.Immediate, NumericConstant(n, _), _) => (n & 0x20) != 0
|
||||
case AssemblyLine(Opcode.SEP | Opcode.REP | Opcode.PLP | Opcode.XCE, _, _, _) => true
|
||||
case AssemblyLine0(Opcode.SEP | Opcode.REP, AddrMode.Immediate, NumericConstant(n, _)) => (n & 0x20) != 0
|
||||
case AssemblyLine0(Opcode.SEP | Opcode.REP | Opcode.PLP | Opcode.XCE, _, _) => true
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
case object ChangesW extends TrivialAssemblyLinePattern {
|
||||
override def apply(line: AssemblyLine): Boolean = line match {
|
||||
case AssemblyLine(Opcode.SEP | Opcode.REP, AddrMode.Immediate, NumericConstant(n, _), _) => (n & 0x10) != 0
|
||||
case AssemblyLine(Opcode.SEP | Opcode.REP | Opcode.PLP | Opcode.XCE, _, _, _) => true
|
||||
case AssemblyLine0(Opcode.SEP | Opcode.REP, AddrMode.Immediate, NumericConstant(n, _)) => (n & 0x10) != 0
|
||||
case AssemblyLine0(Opcode.SEP | Opcode.REP | Opcode.PLP | Opcode.XCE, _, _) => true
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
@ -977,9 +983,9 @@ case object ChangesMemory extends AssemblyLinePattern {
|
||||
import AddrMode._
|
||||
import Opcode._
|
||||
line match {
|
||||
case AssemblyLine(JSR | BSR, Absolute | LongAbsolute, MemoryAddressConstant(th), _) => ctx.functionChangesMemory(th.name)
|
||||
case AssemblyLine(op, Implied, _, _) => OpcodeClasses.ChangesMemoryAlways(op)
|
||||
case AssemblyLine(op, _, _, _) => OpcodeClasses.ChangesMemoryAlways(op) || OpcodeClasses.ChangesMemoryIfNotImplied(op)
|
||||
case AssemblyLine0(JSR | BSR, Absolute | LongAbsolute, MemoryAddressConstant(th)) => ctx.functionChangesMemory(th.name)
|
||||
case AssemblyLine0(op, Implied, _) => OpcodeClasses.ChangesMemoryAlways(op)
|
||||
case AssemblyLine0(op, _, _) => OpcodeClasses.ChangesMemoryAlways(op) || OpcodeClasses.ChangesMemoryIfNotImplied(op)
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
@ -990,7 +996,7 @@ case class DoesntChangeMemoryAt(addrMode1: Int, param1: Int, opcode: Opcode.Valu
|
||||
import AddrMode._
|
||||
import Opcode._
|
||||
line match {
|
||||
case AssemblyLine(JSR | BSR, Absolute | LongAbsolute, MemoryAddressConstant(th), _) => !ctx.functionChangesMemory(th.name)
|
||||
case AssemblyLine0(JSR | BSR, Absolute | LongAbsolute, MemoryAddressConstant(th)) => !ctx.functionChangesMemory(th.name)
|
||||
case _ =>
|
||||
val p1 = ctx.get[Constant](param1)
|
||||
val a1 = ctx.get[AddrMode.Value](addrMode1)
|
||||
@ -1013,7 +1019,7 @@ case class DoesNotConcernMemoryAt(addrMode1: Int, param1: Int) extends AssemblyL
|
||||
import AddrMode._
|
||||
import Opcode._
|
||||
line match {
|
||||
case AssemblyLine(JSR | BSR, Absolute | LongAbsolute, MemoryAddressConstant(th), _) => !ctx.functionReadsMemory(th.name) && !ctx.functionChangesMemory(th.name)
|
||||
case AssemblyLine0(JSR | BSR, Absolute | LongAbsolute, MemoryAddressConstant(th)) => !ctx.functionReadsMemory(th.name) && !ctx.functionChangesMemory(th.name)
|
||||
case _ =>
|
||||
val p1 = ctx.get[Constant](param1)
|
||||
val a1 = ctx.get[AddrMode.Value](addrMode1)
|
||||
@ -1273,7 +1279,7 @@ case class Before(pattern: AssemblyPattern) extends AssemblyLinePattern {
|
||||
case class HasCallerCount(count: Int) extends AssemblyLinePattern {
|
||||
override def matchLineTo(ctx: AssemblyMatchingContext, flowInfo: FlowInfo, line: AssemblyLine): Boolean =
|
||||
line match {
|
||||
case AssemblyLine(Opcode.LABEL, _, MemoryAddressConstant(Label(l)), _) => flowInfo.labelUseCount(l) == count
|
||||
case AssemblyLine0(Opcode.LABEL, _, MemoryAddressConstant(Label(l))) => flowInfo.labelUseCount(l) == count
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
@ -1300,7 +1306,7 @@ case object IsZeroPage extends AssemblyLinePattern {
|
||||
override def matchLineTo(ctx: AssemblyMatchingContext, flowInfo: FlowInfo, line: AssemblyLine): Boolean = {
|
||||
import Opcode._
|
||||
line match {
|
||||
case AssemblyLine(_, AddrMode.ZeroPage, _, _) => true
|
||||
case AssemblyLine0(_, AddrMode.ZeroPage, _) => true
|
||||
case l@AssemblyLine(LDA | STA | CMP |
|
||||
LDX | STX | CPX |
|
||||
LDY | STY | CPY |
|
||||
@ -1308,7 +1314,7 @@ case object IsZeroPage extends AssemblyLinePattern {
|
||||
BIT |
|
||||
ADC | SBC | AND | ORA | EOR |
|
||||
INC | DEC | ROL | ROR | ASL | LSR |
|
||||
ISC | DCP | LAX | SAX | RLA | RRA | SLO | SRE, AddrMode.Absolute, p, true) =>
|
||||
ISC | DCP | LAX | SAX | RLA | RRA | SLO | SRE, AddrMode.Absolute, p, Elidability.Elidable, _) =>
|
||||
p match {
|
||||
case NumericConstant(n, _) => n <= 255
|
||||
case MemoryAddressConstant(th) => ctx.labelMap.getOrElse(th.name, 0x800) < 0x100
|
||||
|
@ -1,10 +1,9 @@
|
||||
package millfork.assembly.mos.opt
|
||||
|
||||
import millfork.{CompilationFlag, CompilationOptions, NonOverlappingIntervals}
|
||||
import millfork.assembly._
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.mos.AddrMode._
|
||||
import millfork.assembly.mos.{AddrMode, AssemblyLine, Opcode}
|
||||
import millfork.assembly.mos.{AddrMode, AssemblyLine, AssemblyLine0, Opcode}
|
||||
import millfork.env._
|
||||
import millfork.error.{ConsoleLogger, Logger}
|
||||
|
||||
@ -44,11 +43,11 @@ object SingleAssignmentVariableOptimization extends AssemblyOptimization[Assembl
|
||||
return code
|
||||
}
|
||||
val stillUsedVariables = code.flatMap {
|
||||
case AssemblyLine(_, _, MemoryAddressConstant(th), _) => Some(th.name)
|
||||
case AssemblyLine0(_, _, MemoryAddressConstant(th)) => Some(th.name)
|
||||
case _ => None
|
||||
}.toSet
|
||||
val variablesWithAddressesTaken = code.flatMap {
|
||||
case AssemblyLine(_, _, SubbyteConstant(MemoryAddressConstant(th), _), _) => Some(th.name)
|
||||
case AssemblyLine0(_, _, SubbyteConstant(MemoryAddressConstant(th), _)) => Some(th.name)
|
||||
case _ => None
|
||||
}.toSet
|
||||
val localVariables = f.environment.getAllLocalVariables.filter {
|
||||
@ -77,16 +76,16 @@ object SingleAssignmentVariableOptimization extends AssemblyOptimization[Assembl
|
||||
|
||||
private def findSourceForVariable(variable: String, code:List[AssemblyLine]): Either[Boolean, List[AssemblyLine]] = code match {
|
||||
case Nil => Left(true)
|
||||
case (load@AssemblyLine(LDA, _, _, _)) :: AssemblyLine(STA, Absolute | ZeroPage, MemoryAddressConstant(v), true) :: xs
|
||||
case (load@AssemblyLine0(LDA, _, _)) :: AssemblyLine(STA, Absolute | ZeroPage, MemoryAddressConstant(v), Elidability.Elidable, _) :: xs
|
||||
if v.name == variable =>
|
||||
findSourceForVariable(variable, xs) match {
|
||||
case Left(true) => Right(List(load))
|
||||
case _ => Left(false)
|
||||
}
|
||||
case AssemblyLine(LAX | LDX | LDY | ADC | SBC | CMP | CPX | CPY | AND | EOR | ORA, Absolute | ZeroPage, MemoryAddressConstant(v), _) :: xs
|
||||
case AssemblyLine0(LAX | LDX | LDY | ADC | SBC | CMP | CPX | CPY | AND | EOR | ORA, Absolute | ZeroPage, MemoryAddressConstant(v)) :: xs
|
||||
if v.name == variable =>
|
||||
findSourceForVariable(variable, xs)
|
||||
case AssemblyLine(_, _, MemoryAddressConstant(v), _) :: _
|
||||
case AssemblyLine0(_, _, MemoryAddressConstant(v)) :: _
|
||||
if v.name == variable => Left(false)
|
||||
case x :: xs => findSourceForVariable(variable, xs)
|
||||
}
|
||||
@ -106,17 +105,17 @@ object SingleAssignmentVariableOptimization extends AssemblyOptimization[Assembl
|
||||
|
||||
private def replaceVariable(variable: String, replacement: List[AssemblyLine], code: List[(AssemblyLine, CpuImportance)]): Option[List[AssemblyLine]] = code match {
|
||||
case Nil => Some(Nil)
|
||||
case (AssemblyLine(STA, Absolute | ZeroPage, MemoryAddressConstant(v), true), _) :: xs
|
||||
case (AssemblyLine(STA, Absolute | ZeroPage, MemoryAddressConstant(v), Elidability.Elidable, _), _) :: xs
|
||||
if v.name == variable =>
|
||||
replaceVariable(variable, replacement, xs)
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(v), true), imp) :: xs
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(v), Elidability.Elidable, _), imp) :: xs
|
||||
if v.name == variable =>
|
||||
replaceVariable(variable, replacement, xs).map(replacement ++ _)
|
||||
case (AssemblyLine(op@(LAX | LDX | LDY | ADC | SBC | CMP | CPX | CPY | AND | EOR | ORA), Absolute | ZeroPage, MemoryAddressConstant(v), true), imp) :: xs
|
||||
case (AssemblyLine(op@(LAX | LDX | LDY | ADC | SBC | CMP | CPX | CPY | AND | EOR | ORA), Absolute | ZeroPage, MemoryAddressConstant(v), Elidability.Elidable, _), imp) :: xs
|
||||
if v.name == variable =>
|
||||
if (isSingleLda(replacement, getAddrModes(op))) replaceVariable(variable, replacement, xs).map(replacement.map(_.copy(opcode = op)) ++ _)
|
||||
else None
|
||||
case (AssemblyLine(_, _, MemoryAddressConstant(v), _), _) :: xs if v.name == variable => None
|
||||
case (AssemblyLine0(_, _, MemoryAddressConstant(v)), _) :: xs if v.name == variable => None
|
||||
case x :: xs => replaceVariable(variable, replacement, xs).map(x._1 :: _)
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
package millfork.assembly.mos.opt
|
||||
|
||||
import millfork.assembly.mos.AssemblyLine
|
||||
import millfork.assembly.mos.{AssemblyLine, AssemblyLine0}
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.{AssemblyOptimization, OptimizationContext}
|
||||
import millfork.env._
|
||||
@ -13,19 +13,19 @@ object UnusedLabelRemoval extends AssemblyOptimization[AssemblyLine] {
|
||||
|
||||
override def optimize(f: NormalFunction, code: List[AssemblyLine], optimizationContext: OptimizationContext): List[AssemblyLine] = {
|
||||
val usedLabels = code.flatMap {
|
||||
case AssemblyLine(LABEL, _, _, _) => None
|
||||
case AssemblyLine(_, _, MemoryAddressConstant(Label(l)), _) => Some(l)
|
||||
case AssemblyLine0(LABEL, _, _) => None
|
||||
case AssemblyLine0(_, _, MemoryAddressConstant(Label(l))) => Some(l)
|
||||
case _ => None
|
||||
}.toSet
|
||||
val definedLabels = code.flatMap {
|
||||
case AssemblyLine(LABEL, _, MemoryAddressConstant(Label(l)), _) => Some(l).filter(_.startsWith("."))
|
||||
case AssemblyLine0(LABEL, _, MemoryAddressConstant(Label(l))) => Some(l).filter(_.startsWith("."))
|
||||
case _ => None
|
||||
}.toSet
|
||||
val toRemove = definedLabels -- usedLabels
|
||||
if (toRemove.nonEmpty) {
|
||||
optimizationContext.log.debug("Removing labels: " + toRemove.mkString(", "))
|
||||
code.filterNot {
|
||||
case AssemblyLine(LABEL, _, MemoryAddressConstant(Label(l)), _) => toRemove(l)
|
||||
case AssemblyLine0(LABEL, _, MemoryAddressConstant(Label(l))) => toRemove(l)
|
||||
case _ => false
|
||||
}
|
||||
} else {
|
||||
|
@ -1,7 +1,7 @@
|
||||
package millfork.assembly.mos.opt
|
||||
|
||||
import millfork.{CompilationFlag, NonOverlappingIntervals}
|
||||
import millfork.assembly.{AssemblyOptimization, OptimizationContext}
|
||||
import millfork.assembly.{AssemblyOptimization, Elidability, OptimizationContext}
|
||||
import millfork.assembly.mos._
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import AddrMode._
|
||||
@ -10,7 +10,7 @@ import millfork.error.Logger
|
||||
import millfork.node.MosNiceFunctionProperty
|
||||
|
||||
import scala.collection.mutable.ListBuffer
|
||||
import scala.util.control.TailCalls.{ TailRec, done, tailcall }
|
||||
import scala.util.control.TailCalls.{TailRec, done, tailcall}
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
@ -131,11 +131,11 @@ object VariableToRegisterOptimization extends AssemblyOptimization[AssemblyLine]
|
||||
return code
|
||||
}
|
||||
val stillUsedVariables = code.flatMap {
|
||||
case AssemblyLine(_, _, MemoryAddressConstant(th), _) => Some(th.name)
|
||||
case AssemblyLine0(_, _, MemoryAddressConstant(th)) => Some(th.name)
|
||||
case _ => None
|
||||
}.toSet
|
||||
val variablesWithAddressesTaken = code.flatMap {
|
||||
case AssemblyLine(_, _, SubbyteConstant(MemoryAddressConstant(th), _), _) => Some(th.name)
|
||||
case AssemblyLine0(_, _, SubbyteConstant(MemoryAddressConstant(th), _)) => Some(th.name)
|
||||
case _ => None
|
||||
}.toSet
|
||||
val localVariables = f.environment.getAllLocalVariables.filter {
|
||||
@ -354,17 +354,17 @@ object VariableToRegisterOptimization extends AssemblyOptimization[AssemblyLine]
|
||||
val vy = yCandidate.getOrElse("-")
|
||||
val vz = zCandidate.getOrElse("-")
|
||||
lines match {
|
||||
case (AssemblyLine(_, Immediate, SubbyteConstant(MemoryAddressConstant(th), _), _), _) :: xs
|
||||
case (AssemblyLine0(_, Immediate, SubbyteConstant(MemoryAddressConstant(th), _)), _) :: xs
|
||||
if th.name == vx || th.name == vy || th.name == vz =>
|
||||
// if an address of a variable is used, then that variable cannot be assigned to a register
|
||||
None
|
||||
|
||||
case (AssemblyLine(_, AbsoluteX | AbsoluteY | LongAbsoluteX |
|
||||
case (AssemblyLine0(_, AbsoluteX | AbsoluteY | LongAbsoluteX |
|
||||
ZeroPageX | ZeroPageY |
|
||||
IndexedY | IndexedX | IndexedZ |
|
||||
LongIndexedY | LongIndexedZ |
|
||||
Indirect | LongIndirect |
|
||||
AbsoluteIndexedX, MemoryAddressConstant(th), _), _) :: xs =>
|
||||
AbsoluteIndexedX, MemoryAddressConstant(th)), _) :: xs =>
|
||||
// if a variable is used as an array or a pointer, then it cannot be assigned to a register
|
||||
if (th.name == vx || th.name == vy || th.name == vz) {
|
||||
None
|
||||
@ -372,50 +372,50 @@ object VariableToRegisterOptimization extends AssemblyOptimization[AssemblyLine]
|
||||
canBeInlined(xCandidate, yCandidate, zCandidate, features, xs)
|
||||
}
|
||||
|
||||
case (AssemblyLine(SEP | REP, Immediate, NumericConstant(nn, _), _), _) :: xs =>
|
||||
case (AssemblyLine0(SEP | REP, Immediate, NumericConstant(nn, _)), _) :: xs =>
|
||||
if ((nn & 0x10) == 0) canBeInlined(xCandidate, yCandidate, zCandidate, features, xs)
|
||||
else None
|
||||
|
||||
case (AssemblyLine(SEP | REP, _, _, _), _) :: xs => None
|
||||
case (AssemblyLine0(SEP | REP, _, _), _) :: xs => None
|
||||
|
||||
case (AssemblyLine(STY | LDY, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs if th.name == vx =>
|
||||
case (AssemblyLine0(STY | LDY, Absolute | ZeroPage, MemoryAddressConstant(th)), _) :: xs if th.name == vx =>
|
||||
if (features.indexRegisterTransfers) canBeInlined(xCandidate, yCandidate, zCandidate, features, xs).map(_ + CyclesAndBytes(bytes = 2, cycles = 2))
|
||||
else None
|
||||
|
||||
case (AssemblyLine(STX | LDX, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs if th.name == vy =>
|
||||
case (AssemblyLine0(STX | LDX, Absolute | ZeroPage, MemoryAddressConstant(th)), _) :: xs if th.name == vy =>
|
||||
if (features.indexRegisterTransfers) canBeInlined(xCandidate, yCandidate, zCandidate, features, xs).map(_ + CyclesAndBytes(bytes = 2, cycles = 2))
|
||||
else None
|
||||
|
||||
case (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), elidable),_) :: xs
|
||||
case (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), elidability, _), _) :: xs
|
||||
if opcodesIdentityTable(op) && features.blastProcessing =>
|
||||
if (th.name == vx || th.name == vy) {
|
||||
if (elidable) canBeInlined(xCandidate, yCandidate, zCandidate, features, xs).map(_ + CyclesAndBytes(bytes = 0, cycles = -1))
|
||||
if (elidability == Elidability.Elidable) canBeInlined(xCandidate, yCandidate, zCandidate, features, xs).map(_ + CyclesAndBytes(bytes = 0, cycles = -1))
|
||||
else None
|
||||
} else {
|
||||
if (th.name == vz) None
|
||||
else canBeInlined(xCandidate, yCandidate, zCandidate, features, xs)
|
||||
}
|
||||
|
||||
case (AssemblyLine(opcode, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (AssemblyLine0(opcode, Absolute | ZeroPage, MemoryAddressConstant(th)), _) :: xs
|
||||
if th.name == vx && (opcode == LDY || opcode == LDZ || opcodesThatCannotBeUsedWithIndexRegistersAsParameters(opcode)) =>
|
||||
// if a variable is used by some opcodes, then it cannot be assigned to a register
|
||||
None
|
||||
|
||||
case (AssemblyLine(opcode, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (AssemblyLine0(opcode, Absolute | ZeroPage, MemoryAddressConstant(th)), _) :: xs
|
||||
if th.name == vy && (opcode == LDX || opcode == LAX || opcode == LDZ || opcodesThatCannotBeUsedWithIndexRegistersAsParameters(opcode)) =>
|
||||
// if a variable is used by some opcodes, then it cannot be assigned to a register
|
||||
None
|
||||
|
||||
case (AssemblyLine(opcode, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (AssemblyLine0(opcode, Absolute | ZeroPage, MemoryAddressConstant(th)), _) :: xs
|
||||
if th.name == vz && (opcode == LDX || opcode == LDY || opcodesThatCannotBeUsedWithIndexRegistersAsParameters(opcode)) =>
|
||||
// if a variable is used by some opcodes, then it cannot be assigned to a register
|
||||
None
|
||||
|
||||
case (AssemblyLine(LDX, Absolute | ZeroPage, MemoryAddressConstant(th), elidable), imp) :: xs
|
||||
case (AssemblyLine(LDX, Absolute | ZeroPage, MemoryAddressConstant(th), elidability, _), imp) :: xs
|
||||
if xCandidate.isDefined =>
|
||||
// if a register is populated with a different variable, then this variable cannot be assigned to that register
|
||||
// removing LDX saves 3 cycles
|
||||
if (elidable && th.name == vx) {
|
||||
if (elidability == Elidability.Elidable && th.name == vx) {
|
||||
if (imp.z == Unimportant && imp.n == Unimportant) {
|
||||
canBeInlined(xCandidate, yCandidate, zCandidate, features, xs).map(_ + CyclesAndBytes(bytes = 2, cycles = 2))
|
||||
} else {
|
||||
@ -425,21 +425,21 @@ object VariableToRegisterOptimization extends AssemblyOptimization[AssemblyLine]
|
||||
None
|
||||
}
|
||||
|
||||
case (AssemblyLine(LAX, Absolute | ZeroPage, MemoryAddressConstant(th), elidable), _) :: xs
|
||||
case (AssemblyLine(LAX, Absolute | ZeroPage, MemoryAddressConstant(th), elidability, _), _) :: xs
|
||||
if xCandidate.isDefined =>
|
||||
// LAX = LDX-LDA, and since LDX simplifies to nothing and LDA simplifies to TXA,
|
||||
// LAX simplifies to TXA, saving two bytes
|
||||
if (elidable && th.name == vx) {
|
||||
if (elidability == Elidability.Elidable && th.name == vx) {
|
||||
canBeInlined(xCandidate, yCandidate, zCandidate, features, xs).map(_ + CyclesAndBytes(bytes = 2, cycles = 2))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
case (AssemblyLine(LDY, Absolute | ZeroPage, MemoryAddressConstant(th), elidable), imp) :: xs if yCandidate.isDefined =>
|
||||
case (AssemblyLine(LDY, Absolute | ZeroPage, MemoryAddressConstant(th), elidability, _), imp) :: xs if yCandidate.isDefined =>
|
||||
// if a register is populated with a different variable, then this variable cannot be assigned to that register
|
||||
// removing LDX saves 3 bytes
|
||||
// sometimes that LDX has to be converted into CPX#0
|
||||
if (elidable && th.name == vy) {
|
||||
if (elidability == Elidability.Elidable && th.name == vy) {
|
||||
if (imp.z == Unimportant && imp.n == Unimportant) {
|
||||
canBeInlined(xCandidate, yCandidate, zCandidate, features, xs).map(_ + CyclesAndBytes(bytes = 3, cycles = 4))
|
||||
} else {
|
||||
@ -449,8 +449,8 @@ object VariableToRegisterOptimization extends AssemblyOptimization[AssemblyLine]
|
||||
None
|
||||
}
|
||||
|
||||
case (AssemblyLine(LDZ, Absolute | ZeroPage, MemoryAddressConstant(th), elidable), imp) :: xs if zCandidate.isDefined =>
|
||||
if (elidable && th.name == vz) {
|
||||
case (AssemblyLine(LDZ, Absolute | ZeroPage, MemoryAddressConstant(th), elidability, _), imp) :: xs if zCandidate.isDefined =>
|
||||
if (elidability == Elidability.Elidable && th.name == vz) {
|
||||
if (imp.z == Unimportant && imp.n == Unimportant) {
|
||||
canBeInlined(xCandidate, yCandidate, zCandidate, features, xs).map(_ + CyclesAndBytes(bytes = 3, cycles = 4))
|
||||
} else {
|
||||
@ -460,73 +460,73 @@ object VariableToRegisterOptimization extends AssemblyOptimization[AssemblyLine]
|
||||
None
|
||||
}
|
||||
|
||||
case (AssemblyLine(LDX, _, _, _), _) :: xs if xCandidate.isDefined =>
|
||||
case (AssemblyLine0(LDX, _, _), _) :: xs if xCandidate.isDefined =>
|
||||
// if a register is populated with something else than a variable, then no variable cannot be assigned to that register
|
||||
None
|
||||
|
||||
case (AssemblyLine(LDY, _, _, _), _) :: xs if yCandidate.isDefined =>
|
||||
case (AssemblyLine0(LDY, _, _), _) :: xs if yCandidate.isDefined =>
|
||||
// if a register is populated with something else than a variable, then no variable cannot be assigned to that register
|
||||
None
|
||||
|
||||
case (AssemblyLine(LDZ, _, _, _), _) :: xs if zCandidate.isDefined =>
|
||||
case (AssemblyLine0(LDZ, _, _), _) :: xs if zCandidate.isDefined =>
|
||||
// if a register is populated with something else than a variable, then no variable cannot be assigned to that register
|
||||
None
|
||||
|
||||
case (AssemblyLine(LDA, _, _, elidable),_) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), elidable2),_) :: xs
|
||||
case (AssemblyLine(LDA, _, _, elidability, _), _) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), elidability2, _), _) :: xs
|
||||
if opcodesCommutative(op) =>
|
||||
// LDAw/ANDx -> TXA/ANDw
|
||||
if (th.name == vx || th.name == vy) {
|
||||
if (elidable && elidable2) canBeInlined(xCandidate, yCandidate, zCandidate, features, xs).map(_ + CyclesAndBytes(bytes = 2, cycles = 2))
|
||||
if (elidability == Elidability.Elidable && elidability2 == Elidability.Elidable) canBeInlined(xCandidate, yCandidate, zCandidate, features, xs).map(_ + CyclesAndBytes(bytes = 2, cycles = 2))
|
||||
else None
|
||||
} else {
|
||||
if (th.name == vz) None
|
||||
else canBeInlined(xCandidate, yCandidate, zCandidate, features, xs)
|
||||
}
|
||||
|
||||
case (AssemblyLine(LDA, _, _, elidable),_) :: (AssemblyLine(CLC, _, _, _),_) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), elidable2),_) :: xs
|
||||
case (AssemblyLine(LDA, _, _, elidability, _), _) :: (AssemblyLine0(CLC, _, _),_) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), elidability2, _), _) :: xs
|
||||
if opcodesCommutative(op) =>
|
||||
if (th.name == vx || th.name == vy) {
|
||||
if (elidable && elidable2) canBeInlined(xCandidate, yCandidate, zCandidate, features, xs).map(_ + CyclesAndBytes(bytes = 2, cycles = 2))
|
||||
if (elidability == Elidability.Elidable && elidability2 == Elidability.Elidable) canBeInlined(xCandidate, yCandidate, zCandidate, features, xs).map(_ + CyclesAndBytes(bytes = 2, cycles = 2))
|
||||
else None
|
||||
} else {
|
||||
if (th.name == vz) None
|
||||
else canBeInlined(xCandidate, yCandidate, zCandidate, features, xs)
|
||||
}
|
||||
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), elidable), _) :: (AssemblyLine(TAX, _, _, elidable2), _) :: xs
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), elidability, _), _) :: (AssemblyLine(TAX, _, _, elidability2, _), _) :: xs
|
||||
if xCandidate.isDefined =>
|
||||
// a variable cannot be inlined if there is TAX not after LDA of that variable
|
||||
// but LDA-TAX can be simplified to TXA
|
||||
if (elidable && elidable2 && th.name == vx) {
|
||||
if (elidability == Elidability.Elidable && elidability2 == Elidability.Elidable && th.name == vx) {
|
||||
canBeInlined(xCandidate, yCandidate, zCandidate, features, xs).map(_ + CyclesAndBytes(bytes = 3, cycles = 4))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), elidable), _) :: (AssemblyLine(TAY, _, _, elidable2), _) :: xs
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), elidability, _), _) :: (AssemblyLine(TAY, _, _, elidability2, _), _) :: xs
|
||||
if yCandidate.isDefined =>
|
||||
// a variable cannot be inlined if there is TAY not after LDA of that variable
|
||||
// but LDA-TAY can be simplified to TYA
|
||||
if (elidable && elidable2 && th.name == vy) {
|
||||
if (elidability == Elidability.Elidable && elidability2 == Elidability.Elidable && th.name == vy) {
|
||||
canBeInlined(xCandidate, yCandidate, zCandidate, features, xs).map(_ + CyclesAndBytes(bytes = 3, cycles = 4))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), elidable), _) :: (AssemblyLine(TAZ, _, _, elidable2), _) :: xs
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), elidability, _), _) :: (AssemblyLine(TAZ, _, _, elidability2, _), _) :: xs
|
||||
if zCandidate.isDefined =>
|
||||
// a variable cannot be inlined if there is TAZ not after LDA of that variable
|
||||
// but LDA-TAZ can be simplified to TZA
|
||||
if (elidable && elidable2 && th.name == vy) {
|
||||
if (elidability == Elidability.Elidable && elidability2 == Elidability.Elidable && th.name == vy) {
|
||||
canBeInlined(xCandidate, yCandidate, zCandidate, features, xs).map(_ + CyclesAndBytes(bytes = 3, cycles = 4))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
case (AssemblyLine(LDA | STA, Absolute | ZeroPage, MemoryAddressConstant(th), elidable), _) :: xs =>
|
||||
case (AssemblyLine(LDA | STA, Absolute | ZeroPage, MemoryAddressConstant(th), elidability, _), _) :: xs =>
|
||||
// changing LDA->TXA, STA->TAX, INC->INX, DEC->DEX saves 2 bytes
|
||||
if (th.name == vy || th.name == vx || th.name == vz) {
|
||||
if (elidable) {
|
||||
if (elidability == Elidability.Elidable) {
|
||||
canBeInlined(xCandidate, yCandidate, zCandidate, features, xs).map(_ + CyclesAndBytes(bytes = 2, cycles = 2))
|
||||
} else {
|
||||
None
|
||||
@ -535,10 +535,10 @@ object VariableToRegisterOptimization extends AssemblyOptimization[AssemblyLine]
|
||||
canBeInlined(xCandidate, yCandidate, zCandidate, features, xs)
|
||||
}
|
||||
|
||||
case (AssemblyLine(INC | DEC, Absolute | ZeroPage, MemoryAddressConstant(th), elidable), _) :: xs =>
|
||||
case (AssemblyLine(INC | DEC, Absolute | ZeroPage, MemoryAddressConstant(th), elidability, _), _) :: xs =>
|
||||
// changing LDA->TXA, STA->TAX, INC->INX, DEC->DEX saves 2 bytes
|
||||
if (th.name == vy || th.name == vx || th.name == vz) {
|
||||
if (elidable) {
|
||||
if (elidability == Elidability.Elidable) {
|
||||
canBeInlined(xCandidate, yCandidate, zCandidate, features, xs).map(_ + CyclesAndBytes(bytes = 2, cycles = 4))
|
||||
} else {
|
||||
None
|
||||
@ -547,10 +547,10 @@ object VariableToRegisterOptimization extends AssemblyOptimization[AssemblyLine]
|
||||
canBeInlined(xCandidate, yCandidate, zCandidate, features, xs)
|
||||
}
|
||||
|
||||
case (AssemblyLine(STZ, Absolute | ZeroPage, MemoryAddressConstant(th), elidable), _) :: xs =>
|
||||
case (AssemblyLine(STZ, Absolute | ZeroPage, MemoryAddressConstant(th), elidability, _), _) :: xs =>
|
||||
// changing STZ->LDX saves 1 byte
|
||||
if (th.name == vy || th.name == vx) {
|
||||
if (elidable && features.izIsAlwaysZero) {
|
||||
if (elidability == Elidability.Elidable && features.izIsAlwaysZero) {
|
||||
canBeInlined(xCandidate, yCandidate, zCandidate, features, xs).map(_ + CyclesAndBytes(bytes = 1, cycles = 2))
|
||||
} else {
|
||||
None
|
||||
@ -559,23 +559,23 @@ object VariableToRegisterOptimization extends AssemblyOptimization[AssemblyLine]
|
||||
canBeInlined(xCandidate, yCandidate, zCandidate, features, xs)
|
||||
}
|
||||
|
||||
case (AssemblyLine(TAX, _, _, _), _) :: xs if xCandidate.isDefined =>
|
||||
case (AssemblyLine0(TAX, _, _), _) :: xs if xCandidate.isDefined =>
|
||||
// a variable cannot be inlined if there is TAX not after LDA of that variable
|
||||
None
|
||||
|
||||
case (AssemblyLine(TAY, _, _, _), _) :: xs if yCandidate.isDefined =>
|
||||
case (AssemblyLine0(TAY, _, _), _) :: xs if yCandidate.isDefined =>
|
||||
// a variable cannot be inlined if there is TAY not after LDA of that variable
|
||||
None
|
||||
|
||||
case (AssemblyLine(TAZ, _, _, _), _) :: xs if zCandidate.isDefined =>
|
||||
case (AssemblyLine0(TAZ, _, _), _) :: xs if zCandidate.isDefined =>
|
||||
// a variable cannot be inlined if there is TAZ not after LDA of that variable
|
||||
None
|
||||
|
||||
case (AssemblyLine(LABEL, _, _, _), _) :: xs =>
|
||||
case (AssemblyLine0(LABEL, _, _), _) :: xs =>
|
||||
// labels always end the initial section
|
||||
canBeInlined(xCandidate, yCandidate, zCandidate, features, xs)
|
||||
|
||||
case (AssemblyLine(JSR, Absolute | LongAbsolute, MemoryAddressConstant(th), _), _) :: xs =>
|
||||
case (AssemblyLine0(JSR, Absolute | LongAbsolute, MemoryAddressConstant(th)), _) :: xs =>
|
||||
if (
|
||||
xCandidate.isDefined && features.functionsSafeForX(th.name) ||
|
||||
yCandidate.isDefined && features.functionsSafeForY(th.name) ||
|
||||
@ -601,75 +601,75 @@ object VariableToRegisterOptimization extends AssemblyOptimization[AssemblyLine]
|
||||
def canBeInlinedToAccumulator(features: FeaturesForAccumulator, start: Boolean, synced: Boolean, candidate: String, lines: List[(AssemblyLine, CpuImportance)]): Option[CyclesAndBytes] = {
|
||||
lines match {
|
||||
|
||||
case (AssemblyLine(STA, Absolute | ZeroPage, MemoryAddressConstant(th), true),_) :: xs
|
||||
case (AssemblyLine(STA, Absolute | ZeroPage, MemoryAddressConstant(th), Elidability.Elidable, _), _) :: xs
|
||||
if th.name == candidate && start || synced =>
|
||||
canBeInlinedToAccumulator(features, start = false, synced = true, candidate, xs).map(_ + CyclesAndBytes(bytes = 2, cycles = 4))
|
||||
|
||||
case (AssemblyLine(op, _, _, _),_) :: xs if opcodesThatAlwaysPrecludeAAllocation(op) =>
|
||||
case (AssemblyLine0(op, _, _),_) :: xs if opcodesThatAlwaysPrecludeAAllocation(op) =>
|
||||
None
|
||||
|
||||
case (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), _),_) :: xs
|
||||
case (AssemblyLine0(op, Absolute | ZeroPage, MemoryAddressConstant(th)), _) :: xs
|
||||
if th.name == candidate && opcodesThatCannotBeUsedWithAccumulatorAsParameter(op) =>
|
||||
// if a variable is used by some opcodes, then it cannot be assigned to a register
|
||||
None
|
||||
|
||||
case (AssemblyLine(_, Immediate, SubbyteConstant(MemoryAddressConstant(th), _), _),_) :: xs
|
||||
case (AssemblyLine0(_, Immediate, SubbyteConstant(MemoryAddressConstant(th), _)), _) :: xs
|
||||
if th.name == candidate =>
|
||||
// if an address of a variable is used, then that variable cannot be assigned to a register
|
||||
None
|
||||
|
||||
case (AssemblyLine(_, AbsoluteX | AbsoluteY | ZeroPageX | ZeroPageY | IndexedY | IndexedX | IndexedZ | Indirect | AbsoluteIndexedX, MemoryAddressConstant(th), _),_) :: xs
|
||||
case (AssemblyLine0(_, AbsoluteX | AbsoluteY | ZeroPageX | ZeroPageY | IndexedY | IndexedX | IndexedZ | Indirect | AbsoluteIndexedX, MemoryAddressConstant(th)), _) :: xs
|
||||
if th.name == candidate =>
|
||||
// if a variable is used as an array or a pointer, then it cannot be assigned to a register
|
||||
None
|
||||
|
||||
case (AssemblyLine(SEP | REP, Immediate, NumericConstant(nn, _), _), _) :: xs =>
|
||||
case (AssemblyLine0(SEP | REP, Immediate, NumericConstant(nn, _)), _) :: xs =>
|
||||
if ((nn & 0x20) == 0) canBeInlinedToAccumulator(features, start = false, synced = synced, candidate, xs)
|
||||
else None
|
||||
|
||||
case (AssemblyLine(SEP | REP, _, _, _), _) :: xs => None
|
||||
case (AssemblyLine0(SEP | REP, _, _), _) :: xs => None
|
||||
|
||||
case (AssemblyLine(STA, _, MemoryAddressConstant(th), elidable) ,_):: xs if th.name == candidate =>
|
||||
if (synced && elidable) {
|
||||
case (AssemblyLine(STA, _, MemoryAddressConstant(th), elidability, _), _) :: xs if th.name == candidate =>
|
||||
if (synced && elidability == Elidability.Elidable) {
|
||||
canBeInlinedToAccumulator(features, start = false, synced = true, candidate, xs).map(_ + CyclesAndBytes(bytes = 3, cycles = 4))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
case (AssemblyLine(DCP, Absolute | ZeroPage, MemoryAddressConstant(th), _) ,_):: xs if th.name == candidate =>
|
||||
case (AssemblyLine0(DCP, Absolute | ZeroPage, MemoryAddressConstant(th)), _) :: xs if th.name == candidate =>
|
||||
if (synced) {
|
||||
canBeInlinedToAccumulator(features, start = false, synced = true, candidate, xs)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
case (AssemblyLine(STA | SAX, _, MemoryAddressConstant(th), elidable) ,_):: xs if th.name != candidate =>
|
||||
case (AssemblyLine(STA | SAX, _, MemoryAddressConstant(th), elidability, _), _) :: xs if th.name != candidate =>
|
||||
if (synced) {
|
||||
canBeInlinedToAccumulator(features, start = false, synced = true, candidate, xs)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
case (AssemblyLine(STA | SAX, _, NumericConstant(_, _), _) ,_):: xs =>
|
||||
case (AssemblyLine0(STA | SAX, _, NumericConstant(_, _)), _) :: xs =>
|
||||
if (synced) {
|
||||
canBeInlinedToAccumulator(features, start = false, synced = true, candidate, xs)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
case (AssemblyLine(SAX, _, MemoryAddressConstant(th), _) ,_):: xs if th.name == candidate =>
|
||||
case (AssemblyLine0(SAX, _, MemoryAddressConstant(th)), _) :: xs if th.name == candidate =>
|
||||
// if XAA had stable magic $FF, then SAXv/LDAv would correspond to XAA#ff
|
||||
// but there's no point in even thinking about that
|
||||
None
|
||||
|
||||
case (AssemblyLine(TAX | TAY, _, _, _),_) :: xs =>
|
||||
case (AssemblyLine0(TAX | TAY, _, _),_) :: xs =>
|
||||
if (synced) {
|
||||
canBeInlinedToAccumulator(features, start = false, synced = true, candidate, xs)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), true), imp) :: xs
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), Elidability.Elidable, _), imp) :: xs
|
||||
if th.name == candidate =>
|
||||
// removing LDA saves 3 bytes
|
||||
if (imp.z == Unimportant && imp.n == Unimportant) {
|
||||
@ -678,58 +678,58 @@ object VariableToRegisterOptimization extends AssemblyOptimization[AssemblyLine]
|
||||
canBeInlinedToAccumulator(features, start = false, synced = true, candidate, xs).map(_ + CyclesAndBytes(bytes = 1, cycles = 2))
|
||||
}
|
||||
|
||||
case (AssemblyLine(LDA, _, _, elidable),_) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), elidable2),_) :: xs
|
||||
case (AssemblyLine(LDA, _, _, elidability, _), _) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), elidability2, _), _) :: xs
|
||||
if opcodesCommutative(op) =>
|
||||
if (th.name == candidate) {
|
||||
if (elidable && elidable2) canBeInlinedToAccumulator(features, start = false, synced = true, candidate, xs).map(_ + CyclesAndBytes(bytes = 3, cycles = 4))
|
||||
if (elidability == Elidability.Elidable && elidability2 == Elidability.Elidable) canBeInlinedToAccumulator(features, start = false, synced = true, candidate, xs).map(_ + CyclesAndBytes(bytes = 3, cycles = 4))
|
||||
else None
|
||||
} else canBeInlinedToAccumulator(features, start = false, synced = synced, candidate, xs)
|
||||
|
||||
case (AssemblyLine(LDA, _, _, elidable),_) :: (AssemblyLine(CLC, _, _, _),_) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), elidable2),_) :: xs
|
||||
case (AssemblyLine(LDA, _, _, elidability, _), _) :: (AssemblyLine0(CLC, _, _),_) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), elidability2, _), _) :: xs
|
||||
if opcodesCommutative(op) =>
|
||||
if (th.name == candidate) {
|
||||
if (elidable && elidable2) canBeInlinedToAccumulator(features, start = false, synced = true, candidate, xs).map(_ + CyclesAndBytes(bytes = 3, cycles = 4))
|
||||
if (elidability == Elidability.Elidable && elidability2 == Elidability.Elidable) canBeInlinedToAccumulator(features, start = false, synced = true, candidate, xs).map(_ + CyclesAndBytes(bytes = 3, cycles = 4))
|
||||
else None
|
||||
} else canBeInlinedToAccumulator(features, start = false, synced = synced, candidate, xs)
|
||||
|
||||
case (AssemblyLine(LDX | LDY | LAX, Absolute | ZeroPage, MemoryAddressConstant(th), elidable),_) :: xs
|
||||
case (AssemblyLine(LDX | LDY | LAX, Absolute | ZeroPage, MemoryAddressConstant(th), elidability, _), _) :: xs
|
||||
if th.name == candidate =>
|
||||
// converting a load into a transfer saves 2 bytes
|
||||
if (elidable) {
|
||||
if (elidability == Elidability.Elidable) {
|
||||
canBeInlinedToAccumulator(features, start = false, synced = true, candidate, xs).map(_ + CyclesAndBytes(bytes = 2, cycles = 2))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
case (AssemblyLine(LDA | LAX, _, _, _),_) :: xs =>
|
||||
case (AssemblyLine0(LDA | LAX, _, _),_) :: xs =>
|
||||
// if a register is populated with something else than a variable, then no variable cannot be assigned to that register
|
||||
None
|
||||
|
||||
case (AssemblyLine(ASL | LSR | ROR | ROL, Absolute | ZeroPage, MemoryAddressConstant(th), elidable),_) :: xs
|
||||
case (AssemblyLine(ASL | LSR | ROR | ROL, Absolute | ZeroPage, MemoryAddressConstant(th), elidability, _), _) :: xs
|
||||
if th.name == candidate =>
|
||||
if (elidable) {
|
||||
if (elidability == Elidability.Elidable) {
|
||||
canBeInlinedToAccumulator(features, start = false, synced = false, candidate, xs).map(_ + CyclesAndBytes(bytes = 2, cycles = 4))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
case (AssemblyLine(INC | DEC, Absolute | ZeroPage, MemoryAddressConstant(th), elidable),_) :: xs
|
||||
case (AssemblyLine(INC | DEC, Absolute | ZeroPage, MemoryAddressConstant(th), elidability, _), _) :: xs
|
||||
if th.name == candidate =>
|
||||
if (features.cmos && elidable) {
|
||||
if (features.cmos && elidability == Elidability.Elidable) {
|
||||
canBeInlinedToAccumulator(features, start = false, synced = false, candidate, xs).map(_ + CyclesAndBytes(bytes = 2, cycles = 4))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
case (AssemblyLine(TXA | TYA, _, _, elidable), imp) :: xs =>
|
||||
if (imp.a == Unimportant && imp.c == Unimportant && imp.v == Unimportant && elidable) {
|
||||
case (AssemblyLine(TXA | TYA, _, _, elidability, _), imp) :: xs =>
|
||||
if (imp.a == Unimportant && imp.c == Unimportant && imp.v == Unimportant && elidability == Elidability.Elidable) {
|
||||
// TYA/TXA has to be converted to CPY#0/CPX#0
|
||||
canBeInlinedToAccumulator(features, start = false, synced = false, candidate, xs).map(_ + CyclesAndBytes(bytes = -1, cycles = 0))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
case (AssemblyLine(JSR, Absolute | LongAbsolute, MemoryAddressConstant(th), _), _) :: xs =>
|
||||
case (AssemblyLine0(JSR, Absolute | LongAbsolute, MemoryAddressConstant(th)), _) :: xs =>
|
||||
if (features.safeFunctions(th.name)) canBeInlinedToAccumulator(features, start = false, synced = synced, candidate, xs)
|
||||
else None
|
||||
|
||||
@ -756,249 +756,249 @@ object VariableToRegisterOptimization extends AssemblyOptimization[AssemblyLine]
|
||||
val vz = zCandidate.getOrElse("-")
|
||||
val va = aCandidate.getOrElse("-")
|
||||
lines match {
|
||||
case (AssemblyLine(INC, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (AssemblyLine(INC, Absolute | ZeroPage, MemoryAddressConstant(th), _, s), _) :: xs
|
||||
if th.name == vx =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map( AssemblyLine.implied(INX) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map( AssemblyLine.implied(INX).pos(s) :: _)
|
||||
|
||||
case (AssemblyLine(INC, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (AssemblyLine(INC, Absolute | ZeroPage, MemoryAddressConstant(th), _, s), _) :: xs
|
||||
if th.name == vy =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(INY) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(INY).pos(s) :: _)
|
||||
|
||||
case (AssemblyLine(INC, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (AssemblyLine(INC, Absolute | ZeroPage, MemoryAddressConstant(th), _, s), _) :: xs
|
||||
if th.name == vz =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(INZ) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(INZ).pos(s) :: _)
|
||||
|
||||
case (AssemblyLine(DEC, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (AssemblyLine(DEC, Absolute | ZeroPage, MemoryAddressConstant(th), _, s), _) :: xs
|
||||
if th.name == vx =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(DEX) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(DEX).pos(s) :: _)
|
||||
|
||||
case (AssemblyLine(DEC, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (AssemblyLine(DEC, Absolute | ZeroPage, MemoryAddressConstant(th), _, s), _) :: xs
|
||||
if th.name == vy =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(DEY) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(DEY).pos(s) :: _)
|
||||
|
||||
case (AssemblyLine(DEC, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (AssemblyLine(DEC, Absolute | ZeroPage, MemoryAddressConstant(th), _, s), _) :: xs
|
||||
if th.name == vz =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(DEZ) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(DEZ).pos(s) :: _)
|
||||
|
||||
case (AssemblyLine(opcode@(DEC | INC | ROL | ROR | ASL | LSR), Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (AssemblyLine(opcode@(DEC | INC | ROL | ROR | ASL | LSR), Absolute | ZeroPage, MemoryAddressConstant(th), _, s), _) :: xs
|
||||
if th.name == va =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(opcode) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(opcode).pos(s) :: _)
|
||||
|
||||
case (AssemblyLine(LDX, Absolute | ZeroPage, MemoryAddressConstant(th), _), imp) :: xs
|
||||
case (AssemblyLine(LDX, Absolute | ZeroPage, MemoryAddressConstant(th), _, s), imp) :: xs
|
||||
if th.name == vx =>
|
||||
if (imp.z == Unimportant && imp.n == Unimportant) {
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs))
|
||||
} else {
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.immediate(CPX, 0) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.immediate(CPX, 0).pos(s) :: _)
|
||||
}
|
||||
|
||||
case (AssemblyLine(LAX, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (AssemblyLine(LAX, Absolute | ZeroPage, MemoryAddressConstant(th), _, s), _) :: xs
|
||||
if th.name == vx =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TXA) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TXA).pos(s) :: _)
|
||||
|
||||
case (l@AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (l@AssemblyLine0(op, Absolute | ZeroPage, MemoryAddressConstant(th)), _) :: xs
|
||||
if opcodesIdentityTable(op) && th.name == vx =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(l.copy(addrMode = AbsoluteX, parameter = features.identityArray) :: _)
|
||||
|
||||
case (l@AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (l@AssemblyLine0(op, Absolute | ZeroPage, MemoryAddressConstant(th)), _) :: xs
|
||||
if opcodesIdentityTable(op) && th.name == vy =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(l.copy(addrMode = AbsoluteY, parameter = features.identityArray) :: _)
|
||||
|
||||
case (l@AssemblyLine(LDA, _, _, _), _) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (l@AssemblyLine0(LDA, _, _), _) :: (AssemblyLine0(op, Absolute | ZeroPage, MemoryAddressConstant(th)), _) :: xs
|
||||
if opcodesCommutative(op) && th.name == va =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(l.copy(opcode = op) :: _)
|
||||
|
||||
case (l@AssemblyLine(LDA, _, _, _), _) :: (clc@AssemblyLine(CLC, _, _, _), _) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (l@AssemblyLine0(LDA, _, _), _) :: (clc@AssemblyLine0(CLC, _, _), _) :: (AssemblyLine0(op, Absolute | ZeroPage, MemoryAddressConstant(th)), _) :: xs
|
||||
if opcodesCommutative(op) && th.name == va =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(clc :: l.copy(opcode = op) :: _)
|
||||
|
||||
case (l@AssemblyLine(LDA, _, _, _), _) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (l@AssemblyLine(LDA, _, _, _, s), _) :: (AssemblyLine0(op, Absolute | ZeroPage, MemoryAddressConstant(th)), _) :: xs
|
||||
if opcodesCommutative(op) && th.name == vx =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TXA) :: l.copy(opcode = op) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TXA).pos(s) :: l.copy(opcode = op) :: _)
|
||||
|
||||
case (l@AssemblyLine(LDA, _, _, _), _) :: (clc@AssemblyLine(CLC, _, _, _), _) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (l@AssemblyLine(LDA, _, _, _, s), _) :: (clc@AssemblyLine0(CLC, _, _), _) :: (AssemblyLine0(op, Absolute | ZeroPage, MemoryAddressConstant(th)), _) :: xs
|
||||
if opcodesCommutative(op) && th.name == vx =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TXA) :: clc :: l.copy(opcode = op) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TXA).pos(s) :: clc :: l.copy(opcode = op) :: _)
|
||||
|
||||
case (l@AssemblyLine(LDA, _, _, _), _) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (l@AssemblyLine(LDA, _, _, _, s), _) :: (AssemblyLine0(op, Absolute | ZeroPage, MemoryAddressConstant(th)), _) :: xs
|
||||
if opcodesCommutative(op) && th.name == vy =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TYA) :: l.copy(opcode = op) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TYA).pos(s) :: l.copy(opcode = op) :: _)
|
||||
|
||||
case (l@AssemblyLine(LDA, _, _, _), _) :: (clc@AssemblyLine(CLC, _, _, _), _) :: (AssemblyLine(op, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (l@AssemblyLine(LDA, _, _, _, s), _) :: (clc@AssemblyLine0(CLC, _, _), _) :: (AssemblyLine0(op, Absolute | ZeroPage, MemoryAddressConstant(th)), _) :: xs
|
||||
if opcodesCommutative(op) && th.name == vy =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TYA) :: clc :: l.copy(opcode = op) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TYA).pos(s) :: clc :: l.copy(opcode = op) :: _)
|
||||
|
||||
case (AssemblyLine(LDA | STA, Absolute | ZeroPage, MemoryAddressConstant(th), _), imp) :: xs
|
||||
case (AssemblyLine(LDA | STA, Absolute | ZeroPage, MemoryAddressConstant(th), _, s), imp) :: xs
|
||||
if th.name == va =>
|
||||
if (imp.z == Unimportant && imp.n == Unimportant) {
|
||||
inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)
|
||||
} else {
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.immediate(CMP, 0) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.immediate(CMP, 0).pos(s) :: _)
|
||||
}
|
||||
|
||||
case (AssemblyLine(LAX, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (AssemblyLine(LAX, Absolute | ZeroPage, MemoryAddressConstant(th), _, s), _) :: xs
|
||||
if th.name == va =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TAX) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TAX).pos(s) :: _)
|
||||
|
||||
case (AssemblyLine(LDY, Absolute | ZeroPage, MemoryAddressConstant(th), _), imp) :: xs
|
||||
case (AssemblyLine(LDY, Absolute | ZeroPage, MemoryAddressConstant(th), _, s), imp) :: xs
|
||||
if th.name == vy =>
|
||||
if (imp.z == Unimportant && imp.n == Unimportant) {
|
||||
inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)
|
||||
} else {
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.immediate(CPY, 0) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.immediate(CPY, 0).pos(s) :: _)
|
||||
}
|
||||
|
||||
case (AssemblyLine(LDZ, Absolute | ZeroPage, MemoryAddressConstant(th), _), imp) :: xs
|
||||
case (AssemblyLine(LDZ, Absolute | ZeroPage, MemoryAddressConstant(th), _, s), imp) :: xs
|
||||
if th.name == vz =>
|
||||
if (imp.z == Unimportant && imp.n == Unimportant) {
|
||||
inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)
|
||||
} else {
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.immediate(CPZ, 0) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.immediate(CPZ, 0).pos(s) :: _)
|
||||
}
|
||||
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), true), _) :: (AssemblyLine(TAX, _, _, true), _) :: xs
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), Elidability.Elidable, s), _) :: (AssemblyLine(TAX, _, _, Elidability.Elidable, _), _) :: xs
|
||||
if th.name == vx =>
|
||||
// these TXA's may get optimized away by a different optimization
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TXA) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TXA).pos(s) :: _)
|
||||
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), true), _) :: (AssemblyLine(TAY, _, _, true), _) :: xs
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), Elidability.Elidable, s), _) :: (AssemblyLine(TAY, _, _, Elidability.Elidable, _), _) :: xs
|
||||
if th.name == vy =>
|
||||
// these TYA's may get optimized away by a different optimization
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TYA) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TYA).pos(s) :: _)
|
||||
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), true), _) :: (AssemblyLine(TAZ, _, _, true), _) :: xs
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), Elidability.Elidable, s), _) :: (AssemblyLine(TAZ, _, _, Elidability.Elidable, _), _) :: xs
|
||||
if th.name == vz =>
|
||||
// these TZA's may get optimized away by a different optimization
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TZA) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TZA).pos(s) :: _)
|
||||
|
||||
case (AssemblyLine(LDX, Absolute | ZeroPage, MemoryAddressConstant(th), true), _) :: (AssemblyLine(TXA, _, _, true), _) :: xs
|
||||
case (AssemblyLine(LDX, Absolute | ZeroPage, MemoryAddressConstant(th), Elidability.Elidable, s), _) :: (AssemblyLine(TXA, _, _, Elidability.Elidable, _), _) :: xs
|
||||
if th.name == va =>
|
||||
// these TAX's may get optimized away by a different optimization
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TAX) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TAX).pos(s) :: _)
|
||||
|
||||
case (AssemblyLine(LDY, Absolute | ZeroPage, MemoryAddressConstant(th), true), _) :: (AssemblyLine(TYA, _, _, true), _) :: xs
|
||||
case (AssemblyLine(LDY, Absolute | ZeroPage, MemoryAddressConstant(th), Elidability.Elidable, _), _) :: (AssemblyLine(TYA, _, _, Elidability.Elidable, _), _) :: xs
|
||||
if th.name == va =>
|
||||
// these TAY's may get optimized away by a different optimization
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TAY) :: _)
|
||||
|
||||
case (AssemblyLine(LDA, am, param, true), _) :: (AssemblyLine(STA, Absolute | ZeroPage, MemoryAddressConstant(th), true), _) :: xs
|
||||
case (AssemblyLine(LDA, am, param, Elidability.Elidable, s1), _) :: (AssemblyLine(STA, Absolute | ZeroPage, MemoryAddressConstant(th), Elidability.Elidable, s2), _) :: xs
|
||||
if th.name == vx && LdxAddrModes(am) =>
|
||||
// these TXA's may get optimized away by a different optimization
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine(LDX, am, param) :: AssemblyLine.implied(TXA) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine(LDX, am, param).pos(s1, s2) :: AssemblyLine.implied(TXA).pos(s1, s2) :: _)
|
||||
|
||||
case (AssemblyLine(LDA, am, param, true), _) :: (AssemblyLine(STA, Absolute | ZeroPage, MemoryAddressConstant(th), true), _) :: xs
|
||||
case (AssemblyLine(LDA, am, param, Elidability.Elidable, s1), _) :: (AssemblyLine(STA, Absolute | ZeroPage, MemoryAddressConstant(th), Elidability.Elidable, s2), _) :: xs
|
||||
if th.name == vy && LdyAddrModes(am) =>
|
||||
// these TYA's may get optimized away by a different optimization
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine(LDY, am, param) :: AssemblyLine.implied(TYA) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine(LDY, am, param).pos(s1, s2) :: AssemblyLine.implied(TYA).pos(s1, s2) :: _)
|
||||
|
||||
case (AssemblyLine(LDA, am, param, true), _) :: (AssemblyLine(STA, Absolute | ZeroPage, MemoryAddressConstant(th), true), _) :: xs
|
||||
case (AssemblyLine(LDA, am, param, Elidability.Elidable, s1), _) :: (AssemblyLine(STA, Absolute | ZeroPage, MemoryAddressConstant(th), Elidability.Elidable, s2), _) :: xs
|
||||
if th.name == vz && LdzAddrModes(am) =>
|
||||
// these TZA's may get optimized away by a different optimization
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine(LDZ, am, param) :: AssemblyLine.implied(TZA) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine(LDZ, am, param).pos(s1, s2) :: AssemblyLine.implied(TZA).pos(s1, s2) :: _)
|
||||
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: (AssemblyLine(CMP, am, param, true), _) :: xs
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), _, s1), _) :: (AssemblyLine(CMP, am, param, Elidability.Elidable, s2), _) :: xs
|
||||
if th.name == vx && CpxyzAddrModes(am) && isNot(vx, param) =>
|
||||
// ditto
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TXA) :: AssemblyLine(CPX, am, param) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TXA).pos(s1) :: AssemblyLine(CPX, am, param).pos(s2) :: _)
|
||||
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: (AssemblyLine(CMP, am, param, true), _) :: xs
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), _, s1), _) :: (AssemblyLine(CMP, am, param, Elidability.Elidable, s2), _) :: xs
|
||||
if th.name == vy && CpxyzAddrModes(am) && isNot(vx, param) =>
|
||||
// ditto
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TYA) :: AssemblyLine(CPY, am, param) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TYA).pos(s1) :: AssemblyLine(CPY, am, param).pos(s2) :: _)
|
||||
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: (AssemblyLine(CMP, am, param, true), _) :: xs
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), _, s1), _) :: (AssemblyLine(CMP, am, param, Elidability.Elidable, s2), _) :: xs
|
||||
if th.name == vy && CpxyzAddrModes(am) && isNot(vx, param) =>
|
||||
// ditto
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TZA) :: AssemblyLine(CPZ, am, param) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TZA).pos(s1) :: AssemblyLine(CPZ, am, param).pos(s2) :: _)
|
||||
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), _, s), _) :: xs
|
||||
if th.name == vx =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TXA) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TXA).pos(s) :: _)
|
||||
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), _, s), _) :: xs
|
||||
if th.name == vy =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TYA) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TYA).pos(s) :: _)
|
||||
|
||||
case (AssemblyLine(LDY, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (AssemblyLine(LDY, Absolute | ZeroPage, MemoryAddressConstant(th), _, s), _) :: xs
|
||||
if th.name == vx =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TXY) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TXY).pos(s) :: _)
|
||||
|
||||
case (AssemblyLine(LDX, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (AssemblyLine(LDX, Absolute | ZeroPage, MemoryAddressConstant(th), _, s), _) :: xs
|
||||
if th.name == vy =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TYX) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TYX).pos(s) :: _)
|
||||
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (AssemblyLine(LDA, Absolute | ZeroPage, MemoryAddressConstant(th), _, s), _) :: xs
|
||||
if th.name == vz =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TZA) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TZA).pos(s) :: _)
|
||||
|
||||
case (AssemblyLine(LDX, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (AssemblyLine(LDX, Absolute | ZeroPage, MemoryAddressConstant(th), _, s), _) :: xs
|
||||
if th.name == va =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TAX) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TAX).pos(s) :: _)
|
||||
|
||||
case (AssemblyLine(LDY, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (AssemblyLine(LDY, Absolute | ZeroPage, MemoryAddressConstant(th), _, s), _) :: xs
|
||||
if th.name == va =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TAY) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TAY).pos(s) :: _)
|
||||
|
||||
case (AssemblyLine(STA, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (AssemblyLine(STA, Absolute | ZeroPage, MemoryAddressConstant(th), _, s), _) :: xs
|
||||
if th.name == vx =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TAX) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TAX).pos(s) :: _)
|
||||
|
||||
case (AssemblyLine(STA, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (AssemblyLine(STA, Absolute | ZeroPage, MemoryAddressConstant(th), _, s), _) :: xs
|
||||
if th.name == vy =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TAY) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TAY).pos(s) :: _)
|
||||
|
||||
case (AssemblyLine(STA, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (AssemblyLine(STA, Absolute | ZeroPage, MemoryAddressConstant(th), _, s), _) :: xs
|
||||
if th.name == vz =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TAZ) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TAZ).pos(s) :: _)
|
||||
|
||||
case (AssemblyLine(STX, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (AssemblyLine(STX, Absolute | ZeroPage, MemoryAddressConstant(th), _, s), _) :: xs
|
||||
if th.name == va =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TXA) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TXA).pos(s) :: _)
|
||||
|
||||
case (AssemblyLine(STY, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (AssemblyLine(STY, Absolute | ZeroPage, MemoryAddressConstant(th), _, s), _) :: xs
|
||||
if th.name == va =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TYA) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TYA).pos(s) :: _)
|
||||
|
||||
case (AssemblyLine(STX, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (AssemblyLine(STX, Absolute | ZeroPage, MemoryAddressConstant(th), _, s), _) :: xs
|
||||
if th.name == vy =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TXY) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TXY).pos(s) :: _)
|
||||
|
||||
case (AssemblyLine(STY, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (AssemblyLine(STY, Absolute | ZeroPage, MemoryAddressConstant(th), _, s), _) :: xs
|
||||
if th.name == vx =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TYX) :: _)
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TYX).pos(s) :: _)
|
||||
|
||||
case (AssemblyLine(STZ, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (AssemblyLine(STZ, Absolute | ZeroPage, MemoryAddressConstant(th), _, s), _) :: xs
|
||||
if th.name == vx =>
|
||||
if (features.izIsAlwaysZero) tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.immediate(LDX, 0) :: _)
|
||||
if (features.izIsAlwaysZero) tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.immediate(LDX, 0).pos(s) :: _)
|
||||
else features.log.fatal("Unexpected STZ")
|
||||
|
||||
case (AssemblyLine(STZ, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (AssemblyLine(STZ, Absolute | ZeroPage, MemoryAddressConstant(th), _, s), _) :: xs
|
||||
if th.name == vy =>
|
||||
if (features.izIsAlwaysZero) tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.immediate(LDY, 0) :: _)
|
||||
if (features.izIsAlwaysZero) tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.immediate(LDY, 0).pos(s) :: _)
|
||||
else features.log.fatal("Unexpected STZ")
|
||||
|
||||
case (AssemblyLine(STZ, Absolute | ZeroPage, MemoryAddressConstant(th), _), _) :: xs
|
||||
case (AssemblyLine(STZ, Absolute | ZeroPage, MemoryAddressConstant(th), _, s), _) :: xs
|
||||
if th.name == va =>
|
||||
if (features.izIsAlwaysZero) tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.immediate(LDA, 0) :: _)
|
||||
else tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TZA) :: _)
|
||||
if (features.izIsAlwaysZero) tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.immediate(LDA, 0).pos(s) :: _)
|
||||
else tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.implied(TZA).pos(s) :: _)
|
||||
|
||||
case (AssemblyLine(TAX, _, _, _), _) :: xs if xCandidate.isDefined =>
|
||||
case (AssemblyLine0(TAX, _, _), _) :: xs if xCandidate.isDefined =>
|
||||
features.log.fatal("Unexpected TAX")
|
||||
|
||||
case (AssemblyLine(TAY, _, _, _), _) :: xs if yCandidate.isDefined =>
|
||||
case (AssemblyLine0(TAY, _, _), _) :: xs if yCandidate.isDefined =>
|
||||
features.log.fatal("Unexpected TAY")
|
||||
|
||||
case (AssemblyLine(TAZ, _, _, _), _) :: xs if zCandidate.isDefined =>
|
||||
case (AssemblyLine0(TAZ, _, _), _) :: xs if zCandidate.isDefined =>
|
||||
features.log.fatal("Unexpected TAZ")
|
||||
|
||||
case (AssemblyLine(TXA, _, _, _), _) :: xs if aCandidate.isDefined =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.immediate(CPX, 0) :: _)
|
||||
case (AssemblyLine(TXA, _, _, _, s), _) :: xs if aCandidate.isDefined =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.immediate(CPX, 0).pos(s) :: _)
|
||||
|
||||
case (AssemblyLine(TYA, _, _, _), _) :: xs if aCandidate.isDefined =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.immediate(CPY, 0) :: _)
|
||||
case (AssemblyLine(TYA, _, _, _, s), _) :: xs if aCandidate.isDefined =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.immediate(CPY, 0).pos(s) :: _)
|
||||
|
||||
case (AssemblyLine(TZA, _, _, _), _) :: xs if aCandidate.isDefined =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.immediate(CPZ, 0) :: _)
|
||||
case (AssemblyLine(TZA, _, _, _, s), _) :: xs if aCandidate.isDefined =>
|
||||
tailcall(inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs)).map(AssemblyLine.immediate(CPZ, 0).pos(s) :: _)
|
||||
|
||||
case (x, _) :: xs => inlineVars(xCandidate, yCandidate, zCandidate, aCandidate, features, xs).map(x :: _)
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
package millfork.assembly.z80
|
||||
|
||||
import millfork.CompilationFlag
|
||||
import millfork.assembly.AbstractCode
|
||||
import millfork.assembly.{AbstractCode, Elidability, SourceLine}
|
||||
import millfork.compiler.CompilationContext
|
||||
import millfork.env.{Constant, Label, NumericConstant, ThingInMemory}
|
||||
import millfork.node.ZRegister
|
||||
import millfork.node.{Position, ZRegister}
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
@ -177,7 +177,24 @@ object ZLine {
|
||||
def ldViaIxy(x: Boolean, targetOffset: Int, source: ZRegister.Value): ZLine = if (x) ldViaIx(targetOffset, source) else ldViaIy(targetOffset, source)
|
||||
}
|
||||
|
||||
case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Constant, elidable: Boolean = true) extends AbstractCode {
|
||||
object ZLine0 {
|
||||
@inline
|
||||
def unapply(a: ZLine): Some[(ZOpcode.Value, ZRegisters, Constant)] = Some(a.opcode, a.registers, a.parameter)
|
||||
}
|
||||
|
||||
case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Constant, elidability: Elidability.Value = Elidability.Elidable, source: Option[SourceLine] = None) extends AbstractCode {
|
||||
|
||||
def pos(s: Option[SourceLine]): ZLine = if (s.isEmpty || s == source) this else this.copy(source = s)
|
||||
|
||||
def pos(s1: Option[SourceLine], s2: Option[SourceLine]): ZLine = pos(Seq(s1, s2))
|
||||
|
||||
def position(s: Option[Position]): ZLine = pos(SourceLine.of(s))
|
||||
|
||||
def pos(s: Seq[Option[SourceLine]]): ZLine = pos(SourceLine.merge(s))
|
||||
|
||||
def mergePos(s: Seq[Option[SourceLine]]): ZLine = if (s.isEmpty) this else pos(SourceLine.merge(this.source, s))
|
||||
|
||||
def elidable: Boolean = elidability == Elidability.Elidable
|
||||
|
||||
override def sizeInBytes: Int = {
|
||||
import ZOpcode._
|
||||
@ -268,7 +285,7 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
|
||||
|
||||
override def toString: String = {
|
||||
import ZOpcode._
|
||||
opcode match {
|
||||
val raw = opcode match {
|
||||
case DISCARD_A => " ; DISCARD_A"
|
||||
case DISCARD_HL => " ; DISCARD_HL"
|
||||
case DISCARD_F => " ; DISCARD_F"
|
||||
@ -350,6 +367,10 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
|
||||
}
|
||||
s" $os$ps"
|
||||
}
|
||||
source match {
|
||||
case Some(SourceLine(_, line)) if line > 0 => f"$raw%-30s \t; @ $line%d"
|
||||
case _ => raw
|
||||
}
|
||||
}
|
||||
|
||||
def toIntelString: String = {
|
||||
|
@ -16,8 +16,8 @@ object AlwaysGoodI80Optimizations {
|
||||
|
||||
def change8BitLoadTarget(line: ZLine, newTarget: ZRegister.Value): ZLine = {
|
||||
line match {
|
||||
case ZLine(LD, TwoRegistersOffset(_, s, o), p, _) => ZLine(LD, TwoRegistersOffset(newTarget, s, o), p)
|
||||
case ZLine(LD, TwoRegisters(_, s), p, _) => ZLine(LD, TwoRegisters(newTarget, s), p)
|
||||
case ZLine0(LD, TwoRegistersOffset(_, s, o), p) => line.copy(registers = TwoRegistersOffset(newTarget, s, o))
|
||||
case ZLine0(LD, TwoRegisters(_, s), p) => line.copy(registers = TwoRegisters(newTarget, s))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,8 +15,8 @@ object AlwaysGoodZ80Optimizations {
|
||||
|
||||
def change8BitLoadTarget(line: ZLine, newTarget: ZRegister.Value): ZLine = {
|
||||
line match {
|
||||
case ZLine(LD, TwoRegistersOffset(_, s, o), p, _) => ZLine(LD, TwoRegistersOffset(newTarget, s, o), p)
|
||||
case ZLine(LD, TwoRegisters(_, s), p, _) => ZLine(LD, TwoRegisters(newTarget, s), p)
|
||||
case ZLine(LD, TwoRegistersOffset(_, s, o), p, _, sl) => line.copy(registers = TwoRegistersOffset(newTarget, s, o))
|
||||
case ZLine(LD, TwoRegisters(_, s), p, _, sl) => line.copy(registers = TwoRegisters(newTarget, s))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,12 +35,12 @@ object ByteVariableToRegisterOptimization extends AssemblyOptimization[ZLine] {
|
||||
val costFunction: CyclesAndBytes => Int = if (options.flag(CompilationFlag.OptimizeForSpeed)) _.cycles else _.bytes
|
||||
lazy val savingsForRemovingOneStackVariable = {
|
||||
val localVariableAreaSize = code.flatMap {
|
||||
case ZLine(_, OneRegisterOffset(ZRegister.MEM_IX_D, offset), _, _) if useIx => Some(offset)
|
||||
case ZLine(_, TwoRegistersOffset(_, ZRegister.MEM_IX_D, offset), _, _) if useIx => Some(offset)
|
||||
case ZLine(_, TwoRegistersOffset(ZRegister.MEM_IX_D, _, offset), _, _) if useIx => Some(offset)
|
||||
case ZLine(_, OneRegisterOffset(ZRegister.MEM_IY_D, offset), _, _) if useIy => Some(offset)
|
||||
case ZLine(_, TwoRegistersOffset(_, ZRegister.MEM_IY_D, offset), _, _) if useIy => Some(offset)
|
||||
case ZLine(_, TwoRegistersOffset(ZRegister.MEM_IY_D, _, offset), _, _) if useIy => Some(offset)
|
||||
case ZLine0(_, OneRegisterOffset(ZRegister.MEM_IX_D, offset), _) if useIx => Some(offset)
|
||||
case ZLine0(_, TwoRegistersOffset(_, ZRegister.MEM_IX_D, offset), _) if useIx => Some(offset)
|
||||
case ZLine0(_, TwoRegistersOffset(ZRegister.MEM_IX_D, _, offset), _) if useIx => Some(offset)
|
||||
case ZLine0(_, OneRegisterOffset(ZRegister.MEM_IY_D, offset), _) if useIy => Some(offset)
|
||||
case ZLine0(_, TwoRegistersOffset(_, ZRegister.MEM_IY_D, offset), _) if useIy => Some(offset)
|
||||
case ZLine0(_, TwoRegistersOffset(ZRegister.MEM_IY_D, _, offset), _) if useIy => Some(offset)
|
||||
case _ => None
|
||||
}.toSet.size
|
||||
val prologueAndEpilogue = if (f.returnType.size == 2) CyclesAndBytes(107, 20) else CyclesAndBytes(95, 17)
|
||||
@ -239,62 +239,62 @@ object ByteVariableToRegisterOptimization extends AssemblyOptimization[ZLine] {
|
||||
def unapply(c: Int): Option[Int] = if ("IY+" + c == vname) Some(c) else None
|
||||
}
|
||||
code match {
|
||||
case (_, ZLine(LD, TwoRegisters(A, MEM_ABS_8), ThisVar(_), _)) :: xs =>
|
||||
case (_, ZLine0(LD, TwoRegisters(A, MEM_ABS_8), ThisVar(_))) :: xs =>
|
||||
canBeInlined(vname, synced, target, addressInHl, addressInBc, addressInDe, xs).map(add(CyclesAndBytes(9, 2)))
|
||||
case (_, ZLine(LD, TwoRegisters(MEM_ABS_8, A), ThisVar(_), _)) :: xs =>
|
||||
case (_, ZLine0(LD, TwoRegisters(MEM_ABS_8, A), ThisVar(_))) :: xs =>
|
||||
canBeInlined(vname, synced, target, addressInHl, addressInBc, addressInDe, xs).map(add(CyclesAndBytes(9, 2)))
|
||||
|
||||
case (_, ZLine(LD, TwoRegistersOffset(reg, MEM_IX_D, ThisOffsetX(_)), _, _)) :: xs =>
|
||||
case (_, ZLine0(LD, TwoRegistersOffset(reg, MEM_IX_D, ThisOffsetX(_)), _)) :: xs =>
|
||||
canBeInlined(vname, synced, target, addressInHl, addressInBc, addressInDe, xs).map(add(reg == target, CyclesAndBytes(19, 3), CyclesAndBytes(15, 2)))
|
||||
case (_, ZLine(LD, TwoRegistersOffset(MEM_IX_D, reg, ThisOffsetX(_)), _, _)) :: xs =>
|
||||
case (_, ZLine0(LD, TwoRegistersOffset(MEM_IX_D, reg, ThisOffsetX(_)), _)) :: xs =>
|
||||
canBeInlined(vname, synced, target, addressInHl, addressInBc, addressInDe, xs).map(add(reg == target, CyclesAndBytes(19, 3), CyclesAndBytes(15, 2)))
|
||||
case (_, ZLine(_, OneRegisterOffset(MEM_IX_D, ThisOffsetX(_)), _, _)) :: xs =>
|
||||
case (_, ZLine0(_, OneRegisterOffset(MEM_IX_D, ThisOffsetX(_)), _)) :: xs =>
|
||||
canBeInlined(vname, synced, target, addressInHl, addressInBc, addressInDe, xs).map(add(CyclesAndBytes(15, 2)))
|
||||
|
||||
case (_, ZLine(LD, TwoRegistersOffset(reg, MEM_IY_D, ThisOffsetY(_)), _, _)) :: xs =>
|
||||
case (_, ZLine0(LD, TwoRegistersOffset(reg, MEM_IY_D, ThisOffsetY(_)), _)) :: xs =>
|
||||
canBeInlined(vname, synced, target, addressInHl, addressInBc, addressInDe, xs).map(add(reg == target, CyclesAndBytes(19, 3), CyclesAndBytes(15, 2)))
|
||||
case (_, ZLine(LD, TwoRegistersOffset(MEM_IY_D, reg, ThisOffsetY(_)), _, _)) :: xs =>
|
||||
case (_, ZLine0(LD, TwoRegistersOffset(MEM_IY_D, reg, ThisOffsetY(_)), _)) :: xs =>
|
||||
canBeInlined(vname, synced, target, addressInHl, addressInBc, addressInDe, xs).map(add(reg == target, CyclesAndBytes(19, 3), CyclesAndBytes(15, 2)))
|
||||
case (_, ZLine(_, OneRegisterOffset(MEM_IY_D, ThisOffsetY(_)), _, _)) :: xs =>
|
||||
case (_, ZLine0(_, OneRegisterOffset(MEM_IY_D, ThisOffsetY(_)), _)) :: xs =>
|
||||
canBeInlined(vname, synced, target, addressInHl, addressInBc, addressInDe, xs).map(add(CyclesAndBytes(15, 2)))
|
||||
|
||||
case (_, ZLine(LD_16, TwoRegisters(HL, IMM_16), ThisVar(_), _)) :: xs =>
|
||||
case (_, ZLine0(LD_16, TwoRegisters(HL, IMM_16), ThisVar(_))) :: xs =>
|
||||
if (target == H || target == L) fail(61) else
|
||||
canBeInlined(vname, synced, target, addressInHl = Some(true), addressInBc, addressInDe, xs).map(add(CyclesAndBytes(10, 3)))
|
||||
case (_, ZLine(LD_16, TwoRegisters(BC, IMM_16), ThisVar(_), _)) :: xs =>
|
||||
case (_, ZLine0(LD_16, TwoRegisters(BC, IMM_16), ThisVar(_))) :: xs =>
|
||||
if (target == B || target == C) fail(61) else
|
||||
canBeInlined(vname, synced, target, addressInHl, addressInBc = Some(true), addressInDe, xs).map(add(CyclesAndBytes(10, 3)))
|
||||
case (_, ZLine(LD_16, TwoRegisters(DE, IMM_16), ThisVar(_), _)) :: xs =>
|
||||
case (_, ZLine0(LD_16, TwoRegisters(DE, IMM_16), ThisVar(_))) :: xs =>
|
||||
if (target == D || target == E) fail(61) else
|
||||
canBeInlined(vname, synced, target, addressInHl, addressInBc, addressInDe = Some(true), xs).map(add(CyclesAndBytes(10, 3)))
|
||||
|
||||
case (_, ZLine(_, OneRegister(MEM_HL), _, _)) :: xs => addressInHl match {
|
||||
case (_, ZLine0(_, OneRegister(MEM_HL), _)) :: xs => addressInHl match {
|
||||
case Some(true) => canBeInlined(vname, synced, target, addressInHl, addressInBc, addressInDe, xs).map(add(CyclesAndBytes(3, 0)))
|
||||
case Some(false) => canBeInlined(vname, synced, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
case None => fail(70)
|
||||
}
|
||||
|
||||
case (_, ZLine(LD, TwoRegisters(MEM_HL, NotTarget(_)) | TwoRegisters(NotTarget(_), MEM_HL), _, _)) :: xs => addressInHl match {
|
||||
case (_, ZLine0(LD, TwoRegisters(MEM_HL, NotTarget(_)) | TwoRegisters(NotTarget(_), MEM_HL), _)) :: xs => addressInHl match {
|
||||
case Some(true) => canBeInlined(vname, synced, target, addressInHl, addressInBc, addressInDe, xs).map(add(CyclesAndBytes(3, 0)))
|
||||
case Some(false) => canBeInlined(vname, synced, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
case None => fail(71)
|
||||
}
|
||||
case (_, ZLine(LD, TwoRegisters(MEM_BC, NotTarget(_)) | TwoRegisters(NotTarget(_), MEM_BC), _, _)) :: xs => addressInBc match {
|
||||
case (_, ZLine0(LD, TwoRegisters(MEM_BC, NotTarget(_)) | TwoRegisters(NotTarget(_), MEM_BC), _)) :: xs => addressInBc match {
|
||||
case Some(true) => canBeInlined(vname, synced, target, addressInHl, addressInBc, addressInDe, xs).map(add(CyclesAndBytes(3, 0)))
|
||||
case Some(false) => canBeInlined(vname, synced, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
case None => fail(72)
|
||||
}
|
||||
case (_, ZLine(LD, TwoRegisters(MEM_DE, NotTarget(_)) | TwoRegisters(NotTarget(_), MEM_DE), _, _)) :: xs => addressInDe match {
|
||||
case (_, ZLine0(LD, TwoRegisters(MEM_DE, NotTarget(_)) | TwoRegisters(NotTarget(_), MEM_DE), _)) :: xs => addressInDe match {
|
||||
case Some(true) => canBeInlined(vname, synced, target, addressInHl, addressInBc, addressInDe, xs).map(add(CyclesAndBytes(3, 0)))
|
||||
case Some(false) => canBeInlined(vname, synced, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
case None => fail(73)
|
||||
}
|
||||
|
||||
case (_, ZLine(_, _, SubbyteConstant(ThisVar(_), _), _)) :: _ => fail(6)
|
||||
case (_, ZLine(_, _, ThisVar(_), _)) :: _ => fail(4)
|
||||
case (_, ZLine(_, _, CompoundConstant(_, ThisVar(_), _), _)) :: _ => fail(5)
|
||||
case (_, ZLine0(_, _, SubbyteConstant(ThisVar(_), _))) :: _ => fail(6)
|
||||
case (_, ZLine0(_, _, ThisVar(_))) :: _ => fail(4)
|
||||
case (_, ZLine0(_, _, CompoundConstant(_, ThisVar(_), _))) :: _ => fail(5)
|
||||
|
||||
case (_, ZLine(CALL, _, _, _)) :: xs =>
|
||||
case (_, ZLine0(CALL, _, _)) :: xs =>
|
||||
// TODO: check return type and allow HL sometimes
|
||||
target match {
|
||||
case ZRegister.B | ZRegister.C | ZRegister.D | ZRegister.E =>
|
||||
@ -307,7 +307,7 @@ object ByteVariableToRegisterOptimization extends AssemblyOptimization[ZLine] {
|
||||
case (_, x) :: xs if x.readsRegister(target) && !synced => fail(2)
|
||||
|
||||
// TODO: tossing addresses around:
|
||||
// case (_, ZLine(LD, TwoRegisters(H, B), _, _)) :: (_, ZLine(LD, TwoRegisters(L, C), _, _)) :: xs =>
|
||||
// case (_, ZLine0(LD, TwoRegisters(H, B), _)) :: (_, ZLine0(LD, TwoRegisters(L, C), _)) :: xs =>
|
||||
|
||||
|
||||
case (_, x) :: xs if x.changesRegister(HL) => canBeInlined(vname, synced, target, addressInHl = Some(false), addressInBc, addressInDe, xs)
|
||||
@ -318,7 +318,7 @@ object ByteVariableToRegisterOptimization extends AssemblyOptimization[ZLine] {
|
||||
case (_, x) :: xs if x.readsRegister(BC) && addressInBc.contains(true) => fail(82)
|
||||
case (_, x) :: xs if x.readsRegister(DE) && addressInDe.contains(true) => fail(83)
|
||||
|
||||
case (_, ZLine(LABEL, _, _, _)) :: xs => canBeInlined(vname, synced = false, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
case (_, ZLine0(LABEL, _, _)) :: xs => canBeInlined(vname, synced = false, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
case _ :: xs => canBeInlined(vname, synced, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
case _ => Some(CyclesAndBytes.Zero)
|
||||
}
|
||||
@ -327,69 +327,69 @@ object ByteVariableToRegisterOptimization extends AssemblyOptimization[ZLine] {
|
||||
def inlineVars(vname: String, target: ZRegister.Value, addressInHl: Boolean, addressInBc: Boolean, addressInDe: Boolean, code: List[ZLine]): List[ZLine] = {
|
||||
// if (code.nonEmpty) println(code.head)
|
||||
code match {
|
||||
case ZLine(LD, TwoRegisters(A, MEM_ABS_8), MemoryAddressConstant(th), _) :: xs if th.name == vname =>
|
||||
ZLine.ld8(A, target) :: inlineVars(vname, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
case ZLine(LD, TwoRegisters(MEM_ABS_8, A), MemoryAddressConstant(th), _) :: xs if th.name == vname =>
|
||||
ZLine.ld8(target, A) :: inlineVars(vname, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
case ZLine(LD, TwoRegisters(A, MEM_ABS_8), MemoryAddressConstant(th), _, s) :: xs if th.name == vname =>
|
||||
ZLine.ld8(A, target).pos(s) :: inlineVars(vname, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
case ZLine(LD, TwoRegisters(MEM_ABS_8, A), MemoryAddressConstant(th), _, s) :: xs if th.name == vname =>
|
||||
ZLine.ld8(target, A).pos(s) :: inlineVars(vname, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
|
||||
case ZLine(LD, TwoRegistersOffset(reg, MEM_IX_D, off), _, _) :: xs if "IX+" + off == vname =>
|
||||
case ZLine(LD, TwoRegistersOffset(reg, MEM_IX_D, off), _, _, s) :: xs if "IX+" + off == vname =>
|
||||
if (reg == target) inlineVars(vname, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
else ZLine.ld8(reg, target) :: inlineVars(vname, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
case ZLine(LD, TwoRegistersOffset(MEM_IX_D, reg, off), _, _) :: xs if "IX+" + off == vname =>
|
||||
else ZLine.ld8(reg, target).pos(s) :: inlineVars(vname, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
case ZLine(LD, TwoRegistersOffset(MEM_IX_D, reg, off), _, _, s) :: xs if "IX+" + off == vname =>
|
||||
if (reg == target) inlineVars(vname, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
else ZLine.ld8(target, reg) :: inlineVars(vname, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
case (l@ZLine(_, OneRegisterOffset(MEM_IX_D, off), _, _)) :: xs if "IX+" + off == vname =>
|
||||
else ZLine.ld8(target, reg).pos(s) :: inlineVars(vname, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
case (l@ZLine0(_, OneRegisterOffset(MEM_IX_D, off), _)) :: xs if "IX+" + off == vname =>
|
||||
l.copy(registers = OneRegister(target)) :: inlineVars(vname, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
|
||||
case ZLine(LD, TwoRegistersOffset(reg, MEM_IY_D, off), _, _) :: xs if "IY+" + off == vname =>
|
||||
case ZLine(LD, TwoRegistersOffset(reg, MEM_IY_D, off), _, _, s) :: xs if "IY+" + off == vname =>
|
||||
if (reg == target) inlineVars(vname, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
else ZLine.ld8(reg, target) :: inlineVars(vname, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
case ZLine(LD, TwoRegistersOffset(MEM_IY_D, reg, off), _, _) :: xs if "IY+" + off == vname =>
|
||||
else ZLine.ld8(reg, target).pos(s) :: inlineVars(vname, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
case ZLine(LD, TwoRegistersOffset(MEM_IY_D, reg, off), _, _, s) :: xs if "IY+" + off == vname =>
|
||||
if (reg == target) inlineVars(vname, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
else ZLine.ld8(target, reg) :: inlineVars(vname, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
case (l@ZLine(_, OneRegisterOffset(MEM_IY_D, off), _, _)) :: xs if "IY+" + off == vname =>
|
||||
else ZLine.ld8(target, reg).pos(s) :: inlineVars(vname, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
case (l@ZLine0(_, OneRegisterOffset(MEM_IY_D, off), _)) :: xs if "IY+" + off == vname =>
|
||||
l.copy(registers = OneRegister(target)) :: inlineVars(vname, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
|
||||
case ZLine(LD_16, TwoRegisters(HL, IMM_16), MemoryAddressConstant(th), _) :: xs if th.name == vname =>
|
||||
case ZLine0(LD_16, TwoRegisters(HL, IMM_16), MemoryAddressConstant(th)) :: xs if th.name == vname =>
|
||||
inlineVars(vname, target, addressInHl = true, addressInBc, addressInDe, xs)
|
||||
case ZLine(LD_16, TwoRegisters(BC, IMM_16), MemoryAddressConstant(th), _) :: xs if th.name == vname =>
|
||||
case ZLine0(LD_16, TwoRegisters(BC, IMM_16), MemoryAddressConstant(th)) :: xs if th.name == vname =>
|
||||
inlineVars(vname, target, addressInHl, addressInBc = true, addressInDe, xs)
|
||||
case ZLine(LD_16, TwoRegisters(DE, IMM_16), MemoryAddressConstant(th), _) :: xs if th.name == vname =>
|
||||
case ZLine0(LD_16, TwoRegisters(DE, IMM_16), MemoryAddressConstant(th)) :: xs if th.name == vname =>
|
||||
inlineVars(vname, target, addressInHl, addressInBc, addressInDe = true, xs)
|
||||
|
||||
case (x@ZLine(_, OneRegister(MEM_HL), _, _)) :: xs if addressInHl =>
|
||||
case (x@ZLine0(_, OneRegister(MEM_HL), _)) :: xs if addressInHl =>
|
||||
x.copy(registers = OneRegister(target)) ::
|
||||
inlineVars(vname, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
|
||||
case (x@ZLine(LD, TwoRegisters(MEM_HL, reg), p, _)) :: xs if addressInHl =>
|
||||
case (x@ZLine0(LD, TwoRegisters(MEM_HL, reg), p)) :: xs if addressInHl =>
|
||||
x.copy(registers = TwoRegisters(target, reg), parameter = p) ::
|
||||
inlineVars(vname, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
case (x@ZLine(LD, TwoRegisters(reg, MEM_HL), p, _)) :: xs if addressInHl =>
|
||||
case (x@ZLine0(LD, TwoRegisters(reg, MEM_HL), p)) :: xs if addressInHl =>
|
||||
x.copy(registers = TwoRegisters(reg, target), parameter = p) ::
|
||||
inlineVars(vname, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
|
||||
case (x@ZLine(LD, TwoRegisters(MEM_BC, reg), p, _)) :: xs if addressInBc =>
|
||||
case (x@ZLine0(LD, TwoRegisters(MEM_BC, reg), p)) :: xs if addressInBc =>
|
||||
x.copy(registers = TwoRegisters(target, reg), parameter = p) ::
|
||||
inlineVars(vname, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
case (x@ZLine(LD, TwoRegisters(reg, MEM_BC), p, _)) :: xs if addressInBc =>
|
||||
case (x@ZLine0(LD, TwoRegisters(reg, MEM_BC), p)) :: xs if addressInBc =>
|
||||
x.copy(registers = TwoRegisters(reg, target), parameter = p) ::
|
||||
inlineVars(vname, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
|
||||
case (x@ZLine(LD, TwoRegisters(MEM_DE, reg), p, _)) :: xs if addressInDe =>
|
||||
case (x@ZLine0(LD, TwoRegisters(MEM_DE, reg), p)) :: xs if addressInDe =>
|
||||
x.copy(registers = TwoRegisters(target, reg), parameter = p) ::
|
||||
inlineVars(vname, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
case (x@ZLine(LD, TwoRegisters(reg, MEM_DE), p, _)) :: xs if addressInDe =>
|
||||
case (x@ZLine0(LD, TwoRegisters(reg, MEM_DE), p)) :: xs if addressInDe =>
|
||||
x.copy(registers = TwoRegisters(reg, target), parameter = p) ::
|
||||
inlineVars(vname, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
|
||||
case (x@ZLine(CALL,_,_,_))::xs =>
|
||||
case (x@ZLine(CALL,_,_,_,s))::xs =>
|
||||
// TODO: this push/pull pair shouldn't prevent the inlining to the other register in the pair
|
||||
target match {
|
||||
case ZRegister.B | ZRegister.C =>
|
||||
ZLine.register(PUSH, BC) :: x :: ZLine.register(POP, BC) ::
|
||||
ZLine.register(PUSH, BC).pos(s) :: x :: ZLine.register(POP, BC).pos(s) ::
|
||||
inlineVars(vname, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
case ZRegister.D | ZRegister.E =>
|
||||
ZLine.register(PUSH, DE) :: x :: ZLine.register(POP, DE) ::
|
||||
ZLine.register(PUSH, DE).pos(s) :: x :: ZLine.register(POP, DE).pos(s) ::
|
||||
inlineVars(vname, target, addressInHl, addressInBc, addressInDe, xs)
|
||||
}
|
||||
|
||||
|
@ -37,15 +37,15 @@ object CoarseFlowAnalyzer {
|
||||
flagArray(i) = currentStatus
|
||||
}
|
||||
codeArray(i) match {
|
||||
case ZLine(LABEL, _, MemoryAddressConstant(Label(l)), _) =>
|
||||
case ZLine0(LABEL, _, MemoryAddressConstant(Label(l))) =>
|
||||
val L = l
|
||||
currentStatus = codeArray.indices.flatMap(j => codeArray(j) match {
|
||||
case ZLine(DJNZ, _, MemoryAddressConstant(Label(L)), _) => Some(flagArray(j).copy(b = AnyStatus))
|
||||
case ZLine(_, _, MemoryAddressConstant(Label(L)), _) => Some(flagArray(j))
|
||||
case ZLine0(DJNZ, _, MemoryAddressConstant(Label(L))) => Some(flagArray(j).copy(b = AnyStatus))
|
||||
case ZLine0(_, _, MemoryAddressConstant(Label(L))) => Some(flagArray(j))
|
||||
case _ => None
|
||||
}).fold(currentStatus)(_ ~ _)
|
||||
|
||||
case ZLine(CALL, _, MemoryAddressConstant(fun: FunctionInMemory), _) =>
|
||||
case ZLine0(CALL, _, MemoryAddressConstant(fun: FunctionInMemory)) =>
|
||||
val n = fun.name
|
||||
val result = initialStatus.copy(memIx = currentStatus.memIx)
|
||||
currentStatus = result.copy(
|
||||
@ -57,12 +57,12 @@ object CoarseFlowAnalyzer {
|
||||
l = if (preservesL(n)) currentStatus.l else result.l
|
||||
)
|
||||
|
||||
case ZLine(CALL, _, _, _) =>
|
||||
case ZLine0(CALL, _, _) =>
|
||||
currentStatus = initialStatus.copy(memIx = currentStatus.memIx)
|
||||
case ZLine(BYTE, _, _, _) =>
|
||||
case ZLine0(BYTE, _, _) =>
|
||||
currentStatus = initialStatus
|
||||
|
||||
case ZLine(ADD, OneRegister(ZRegister.IMM_8), NumericConstant(0, _), _) =>
|
||||
case ZLine0(ADD, OneRegister(ZRegister.IMM_8), NumericConstant(0, _)) =>
|
||||
currentStatus = currentStatus.copy(
|
||||
nf = Status.SingleFalse,
|
||||
cf = Status.SingleFalse,
|
||||
@ -70,7 +70,7 @@ object CoarseFlowAnalyzer {
|
||||
sf = currentStatus.a.map(_.&(0x80) == 0),
|
||||
pf = if (z80) Status.SingleFalse else AnyStatus,
|
||||
hf = Status.SingleFalse)
|
||||
case ZLine(SUB, OneRegister(ZRegister.IMM_8), NumericConstant(0, _), _) =>
|
||||
case ZLine0(SUB, OneRegister(ZRegister.IMM_8), NumericConstant(0, _)) =>
|
||||
currentStatus = currentStatus.copy(
|
||||
nf = Status.SingleTrue,
|
||||
cf = Status.SingleFalse,
|
||||
@ -78,96 +78,96 @@ object CoarseFlowAnalyzer {
|
||||
sf = currentStatus.a.map(_.&(0x80) == 0),
|
||||
pf = if (z80) Status.SingleFalse else AnyStatus,
|
||||
hf = Status.SingleFalse)
|
||||
case l@ZLine(ADD, OneRegister(s), _, _) =>
|
||||
case l@ZLine0(ADD, OneRegister(s), _) =>
|
||||
currentStatus = currentStatus.copy(a = (currentStatus.a <*> currentStatus.getRegister(s)) ((m, n) => (m + n) & 0xff),
|
||||
nf = Status.SingleFalse, cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
|
||||
case ZLine(SUB, OneRegister(s), _, _) =>
|
||||
case ZLine0(SUB, OneRegister(s), _) =>
|
||||
currentStatus = currentStatus.copy(a = (currentStatus.a <*> currentStatus.getRegister(s)) ((m, n) => (m - n) & 0xff),
|
||||
nf = Status.SingleTrue, cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
|
||||
case ZLine(AND, OneRegister(s), _, _) =>
|
||||
case ZLine0(AND, OneRegister(s), _) =>
|
||||
currentStatus = currentStatus.copy(a = (currentStatus.a <*> currentStatus.getRegister(s)) ((m, n) => (m & n) & 0xff),
|
||||
nf = Status.SingleFalse, cf = Status.SingleFalse, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
|
||||
case ZLine(OR, OneRegister(ZRegister.A), _, _) =>
|
||||
case ZLine0(OR, OneRegister(ZRegister.A), _) =>
|
||||
currentStatus = currentStatus.copy(nf = Status.SingleFalse, cf = Status.SingleFalse, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
|
||||
case ZLine(XOR, OneRegister(ZRegister.A), _, _) =>
|
||||
case ZLine0(XOR, OneRegister(ZRegister.A), _) =>
|
||||
currentStatus = currentStatus.copy(a = Status.SingleZero, nf = Status.SingleFalse, cf = Status.SingleFalse, zf = Status.SingleTrue, sf = Status.SingleFalse, pf = AnyStatus, hf = AnyStatus)
|
||||
case ZLine(OR, OneRegister(s), _, _) =>
|
||||
case ZLine0(OR, OneRegister(s), _) =>
|
||||
currentStatus = currentStatus.copy(a = (currentStatus.a <*> currentStatus.getRegister(s)) ((m, n) => (m | n) & 0xff),
|
||||
nf = Status.SingleFalse, cf = Status.SingleFalse, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
|
||||
case ZLine(XOR, OneRegister(s), _, _) =>
|
||||
case ZLine0(XOR, OneRegister(s), _) =>
|
||||
currentStatus = currentStatus.copy(a = (currentStatus.a <*> currentStatus.getRegister(s)) ((m, n) => (m ^ n) & 0xff),
|
||||
nf = Status.SingleFalse, cf = Status.SingleFalse, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
|
||||
|
||||
case ZLine(INC, OneRegister(r), _, _) =>
|
||||
case ZLine0(INC, OneRegister(r), _) =>
|
||||
currentStatus = currentStatus.
|
||||
copy(cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus).
|
||||
setRegister(r, currentStatus.getRegister(r).map(i => i.+(1).&(0xff)))
|
||||
case ZLine(DEC, OneRegister(r), _, _) =>
|
||||
case ZLine0(DEC, OneRegister(r), _) =>
|
||||
currentStatus = currentStatus.
|
||||
copy(cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus).
|
||||
setRegister(r, currentStatus.getRegister(r).map(i => i.-(1).&(0xff)))
|
||||
case ZLine(op, OneRegister(r), _, _) if ZOpcodeClasses.SET(op) =>
|
||||
case ZLine0(op, OneRegister(r), _) if ZOpcodeClasses.SET(op) =>
|
||||
currentStatus = currentStatus.setRegister(r, currentStatus.getRegister(r).map(i => i | 1.<<(ZOpcodeClasses.SET_seq.indexOf(op))))
|
||||
case ZLine(op, OneRegister(r), _, _) if ZOpcodeClasses.RES(op) =>
|
||||
case ZLine0(op, OneRegister(r), _) if ZOpcodeClasses.RES(op) =>
|
||||
currentStatus = currentStatus.setRegister(r, currentStatus.getRegister(r).map(i => i & ~1.<<(ZOpcodeClasses.RES_seq.indexOf(op))))
|
||||
|
||||
case ZLine(ADD, OneRegisterOffset(s, o), _, _) =>
|
||||
case ZLine0(ADD, OneRegisterOffset(s, o), _) =>
|
||||
currentStatus = currentStatus.copy(a = (currentStatus.a <*> currentStatus.getRegister(s, o)) ((m, n) => (m + n) & 0xff),
|
||||
cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
|
||||
case ZLine(SUB, OneRegisterOffset(s, o), _, _) =>
|
||||
case ZLine0(SUB, OneRegisterOffset(s, o), _) =>
|
||||
currentStatus = currentStatus.copy(a = (currentStatus.a <*> currentStatus.getRegister(s, o)) ((m, n) => (m - n) & 0xff),
|
||||
cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
|
||||
case ZLine(AND, OneRegisterOffset(s, o), _, _) =>
|
||||
case ZLine0(AND, OneRegisterOffset(s, o), _) =>
|
||||
currentStatus = currentStatus.copy(a = (currentStatus.a <*> currentStatus.getRegister(s, o)) ((m, n) => (m & n) & 0xff),
|
||||
cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
|
||||
case ZLine(OR, OneRegisterOffset(s, o), _, _) =>
|
||||
case ZLine0(OR, OneRegisterOffset(s, o), _) =>
|
||||
currentStatus = currentStatus.copy(a = (currentStatus.a <*> currentStatus.getRegister(s, o)) ((m, n) => (m | n) & 0xff),
|
||||
cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
|
||||
case ZLine(XOR, OneRegisterOffset(s, o), _, _) =>
|
||||
case ZLine0(XOR, OneRegisterOffset(s, o), _) =>
|
||||
currentStatus = currentStatus.copy(a = (currentStatus.a <*> currentStatus.getRegister(s, o)) ((m, n) => (m ^ n) & 0xff),
|
||||
cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
|
||||
|
||||
case ZLine(CP, _, _, _) =>
|
||||
case ZLine0(CP, _, _) =>
|
||||
currentStatus = currentStatus.copy(cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
|
||||
|
||||
case ZLine(LD_16, TwoRegisters(t, ZRegister.IMM_16), NumericConstant(value, _), _) =>
|
||||
case ZLine0(LD_16, TwoRegisters(t, ZRegister.IMM_16), NumericConstant(value, _)) =>
|
||||
currentStatus = currentStatus.setRegister(t, SingleStatus(value.toInt))
|
||||
case ZLine(LD_16, TwoRegisters(ZRegister.HL, ZRegister.IMM_16), xx, _) =>
|
||||
case ZLine0(LD_16, TwoRegisters(ZRegister.HL, ZRegister.IMM_16), xx) =>
|
||||
currentStatus = currentStatus.setHL(SingleStatus(xx))
|
||||
case ZLine(LD, TwoRegisters(t, ZRegister.IMM_8), NumericConstant(value, _), _) =>
|
||||
case ZLine0(LD, TwoRegisters(t, ZRegister.IMM_8), NumericConstant(value, _)) =>
|
||||
currentStatus = currentStatus.setRegister(t, SingleStatus(value.toInt))
|
||||
case ZLine(LD, TwoRegistersOffset(t, ZRegister.IMM_8, o), NumericConstant(value, _), _) =>
|
||||
case ZLine0(LD, TwoRegistersOffset(t, ZRegister.IMM_8, o), NumericConstant(value, _)) =>
|
||||
currentStatus = currentStatus.setRegister(t, SingleStatus(value.toInt), o)
|
||||
case ZLine(LD | LD_16, TwoRegisters(t, s), _, _) =>
|
||||
case ZLine0(LD | LD_16, TwoRegisters(t, s), _) =>
|
||||
currentStatus = currentStatus.setRegister(t, currentStatus.getRegister(s))
|
||||
case ZLine(LD | LD_16, TwoRegistersOffset(t, s, o), _, _) =>
|
||||
case ZLine0(LD | LD_16, TwoRegistersOffset(t, s, o), _) =>
|
||||
currentStatus = currentStatus.setRegister(t, currentStatus.getRegister(s, o), o)
|
||||
case ZLine(EX_DE_HL, _, _, _) =>
|
||||
case ZLine0(EX_DE_HL, _, _) =>
|
||||
currentStatus = currentStatus.copy(d = currentStatus.h, e = currentStatus.l, h = currentStatus.d, l = currentStatus.e)
|
||||
case ZLine(ADD_16, TwoRegisters(t, s), _, _) =>
|
||||
case ZLine0(ADD_16, TwoRegisters(t, s), _) =>
|
||||
currentStatus = currentStatus.copy(cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
|
||||
.setRegister(t, (currentStatus.getRegister(t) <*> currentStatus.getRegister(s)) ((m, n) => (m + n) & 0xffff))
|
||||
|
||||
case ZLine(SLA, OneRegister(r), _, _) =>
|
||||
case ZLine0(SLA, OneRegister(r), _) =>
|
||||
currentStatus = currentStatus.copy(cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
|
||||
.setRegister(r, currentStatus.getRegister(r).map(_.<<(1).&(0xff)))
|
||||
case ZLine(SRL, OneRegister(r), _, _) =>
|
||||
case ZLine0(SRL, OneRegister(r), _) =>
|
||||
currentStatus = currentStatus.copy(cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
|
||||
.setRegister(r, currentStatus.getRegister(r).map(_.>>(1).&(0x7f)))
|
||||
|
||||
|
||||
case ZLine(RLA | RRA | RLCA | RRCA, _, _, _) =>
|
||||
case ZLine0(RLA | RRA | RLCA | RRCA, _, _) =>
|
||||
currentStatus = currentStatus.copy(
|
||||
a = AnyStatus, cf = AnyStatus,
|
||||
zf = AnyStatus,
|
||||
pf = AnyStatus, hf = Status.SingleFalse)
|
||||
|
||||
case ZLine(SCF, _, _, _) =>
|
||||
case ZLine0(SCF, _, _) =>
|
||||
currentStatus = currentStatus.copy(cf = Status.SingleTrue, hf = Status.SingleFalse, nf = Status.SingleFalse)
|
||||
case ZLine(CCF, _, _, _) =>
|
||||
case ZLine0(CCF, _, _) =>
|
||||
currentStatus = currentStatus.copy(cf = currentStatus.cf.negate, hf = AnyStatus, nf = AnyStatus)
|
||||
|
||||
case ZLine(opcode, registers, _, _) =>
|
||||
case ZLine0(opcode, registers, _) =>
|
||||
currentStatus = currentStatus.copy(cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
|
||||
if (ZOpcodeClasses.ChangesAAlways(opcode)) currentStatus = currentStatus.copy(a = AnyStatus)
|
||||
if (ZOpcodeClasses.ChangesBCAlways(opcode)) currentStatus = currentStatus.copy(b = AnyStatus, c = AnyStatus)
|
||||
|
@ -1,7 +1,7 @@
|
||||
package millfork.assembly.z80.opt
|
||||
|
||||
import millfork.CompilationFlag
|
||||
import millfork.assembly.{AssemblyOptimization, OptimizationContext}
|
||||
import millfork.assembly.{AssemblyOptimization, Elidability, OptimizationContext}
|
||||
import millfork.assembly.z80._
|
||||
import millfork.env.{MemoryAddressConstant, NormalFunction, NumericConstant}
|
||||
import millfork.node.ZRegister
|
||||
@ -29,11 +29,11 @@ object CompactStackFrame extends AssemblyOptimization[ZLine] {
|
||||
import millfork.assembly.z80.ZOpcode._
|
||||
import millfork.node.ZRegister._
|
||||
code match {
|
||||
case (name@ZLine(LABEL, _, _, _)) ::
|
||||
ZLine(PUSH, OneRegister(Index), _, true) ::
|
||||
ZLine(LD_16, TwoRegisters(Index, IMM_16), NumericConstant(negativeSize, _), true) ::
|
||||
ZLine(ADD_16, TwoRegisters(Index, SP), _, true) ::
|
||||
ZLine(LD_16, TwoRegisters(SP, Index), _, true) :: tail =>
|
||||
case (name@ZLine0(LABEL, _, _)) ::
|
||||
ZLine(PUSH, OneRegister(Index), _, Elidability.Elidable, s1) ::
|
||||
ZLine(LD_16, TwoRegisters(Index, IMM_16), NumericConstant(negativeSize, _), Elidability.Elidable, s2) ::
|
||||
ZLine(ADD_16, TwoRegisters(Index, SP), _, Elidability.Elidable, s3) ::
|
||||
ZLine(LD_16, TwoRegisters(SP, Index), _, Elidability.Elidable, s4) :: tail =>
|
||||
val sourceSize = (-negativeSize).&(0xffff).toInt
|
||||
val usedOffsets: Set[Int] = findUsedOffsets(tail, Index match {
|
||||
case IX => MEM_IX_D
|
||||
@ -42,10 +42,10 @@ object CompactStackFrame extends AssemblyOptimization[ZLine] {
|
||||
val targetSize = usedOffsets.size + usedOffsets.size.&(1)
|
||||
if (targetSize == sourceSize) None else {
|
||||
val prologue = if (targetSize == 0) Nil else List(
|
||||
ZLine.register(PUSH, Index),
|
||||
ZLine.ldImm16(Index, 0x10000 - targetSize),
|
||||
ZLine.registers(ADD_16, Index, SP),
|
||||
ZLine.ld16(SP, Index))
|
||||
ZLine.register(PUSH, Index).pos(s1),
|
||||
ZLine.ldImm16(Index, 0x10000 - targetSize).pos(s2),
|
||||
ZLine.registers(ADD_16, Index, SP).pos(s3),
|
||||
ZLine.ld16(SP, Index).pos(s4))
|
||||
val map = usedOffsets.toSeq.sorted.zipWithIndex.toMap
|
||||
optimizeContinue(tail, Index, sourceSize, targetSize, map).map { optTail =>
|
||||
(name :: prologue ++ optTail, sourceSize, targetSize)
|
||||
@ -59,9 +59,9 @@ object CompactStackFrame extends AssemblyOptimization[ZLine] {
|
||||
|
||||
def findUsedOffsets(code: List[ZLine], Mem: ZRegister.Value): Set[Int] = {
|
||||
code.flatMap {
|
||||
case ZLine(_, OneRegisterOffset(Mem, offset), _, _) => Some(offset)
|
||||
case ZLine(_, TwoRegistersOffset(_, Mem, offset), _, _) => Some(offset)
|
||||
case ZLine(_, TwoRegistersOffset(Mem, _, offset), _, _) => Some(offset)
|
||||
case ZLine0(_, OneRegisterOffset(Mem, offset), _) => Some(offset)
|
||||
case ZLine0(_, TwoRegistersOffset(_, Mem, offset), _) => Some(offset)
|
||||
case ZLine0(_, TwoRegistersOffset(Mem, _, offset), _) => Some(offset)
|
||||
case _ => None
|
||||
}.toSet
|
||||
}
|
||||
@ -74,42 +74,42 @@ object CompactStackFrame extends AssemblyOptimization[ZLine] {
|
||||
case IY => MEM_IY_D
|
||||
}
|
||||
code match {
|
||||
case (head@ZLine(_, TwoRegistersOffset(reg, Mem, offset), _, _)) :: tail =>
|
||||
case (head@ZLine0(_, TwoRegistersOffset(reg, Mem, offset), _)) :: tail =>
|
||||
optimizeContinue(tail, Index, sourceSize, targetSize, mapping).map(
|
||||
head.copy(registers = TwoRegistersOffset(reg, Mem, mapping(offset))) :: _)
|
||||
|
||||
case (head@ZLine(_, TwoRegistersOffset(Mem, reg, offset), _, _)) :: tail =>
|
||||
case (head@ZLine0(_, TwoRegistersOffset(Mem, reg, offset), _)) :: tail =>
|
||||
optimizeContinue(tail, Index, sourceSize, targetSize, mapping).map(
|
||||
head.copy(registers = TwoRegistersOffset(Mem, reg, mapping(offset))) :: _)
|
||||
|
||||
case (head@ZLine(_, OneRegisterOffset(Mem, offset), _, _)) :: tail =>
|
||||
case (head@ZLine0(_, OneRegisterOffset(Mem, offset), _)) :: tail =>
|
||||
optimizeContinue(tail, Index, sourceSize, targetSize, mapping).map(
|
||||
head.copy(registers = OneRegisterOffset(Mem, mapping(offset))) :: _)
|
||||
|
||||
case
|
||||
ZLine(LD_16, TwoRegisters(Index, IMM_16), NumericConstant(size, _), _) ::
|
||||
ZLine(ADD_16, TwoRegisters(Index, SP), _, _) ::
|
||||
ZLine(LD_16, TwoRegisters(SP, Index), _, _) ::
|
||||
ZLine(POP, OneRegister(Index), _, _) :: tail =>
|
||||
ZLine(LD_16, TwoRegisters(Index, IMM_16), NumericConstant(size, _), _, s1) ::
|
||||
ZLine(ADD_16, TwoRegisters(Index, SP), _, _, s2) ::
|
||||
ZLine(LD_16, TwoRegisters(SP, Index), _, _, s3) ::
|
||||
ZLine(POP, OneRegister(Index), _, _, s4) :: tail =>
|
||||
if (size != sourceSize) None
|
||||
else {
|
||||
stripReturn(tail).flatMap {
|
||||
case (ret, rest) =>
|
||||
val epilogue = if (targetSize == 0) Nil else {
|
||||
List(
|
||||
ZLine.ldImm16(Index, targetSize),
|
||||
ZLine.registers(ADD_16, Index, SP),
|
||||
ZLine.ld16(SP, Index),
|
||||
ZLine.register(POP, Index))
|
||||
ZLine.ldImm16(Index, targetSize).pos(s1),
|
||||
ZLine.registers(ADD_16, Index, SP).pos(s2),
|
||||
ZLine.ld16(SP, Index).pos(s3),
|
||||
ZLine.register(POP, Index).pos(s4))
|
||||
}
|
||||
optimizeContinue(rest, Index, sourceSize, targetSize, mapping).map(epilogue ++ ret ++ _)
|
||||
}
|
||||
}
|
||||
case
|
||||
ZLine(LD_16, TwoRegisters(HL, IMM_16), NumericConstant(size, _), _) ::
|
||||
ZLine(ADD_16, TwoRegisters(HL, SP), _, _) ::
|
||||
ZLine(LD_16, TwoRegisters(SP, HL), _, _) ::
|
||||
ZLine(POP, OneRegister(Index), _, _) :: tail =>
|
||||
ZLine(LD_16, TwoRegisters(HL, IMM_16), NumericConstant(size, _), _, s1) ::
|
||||
ZLine(ADD_16, TwoRegisters(HL, SP), _, _, s2) ::
|
||||
ZLine(LD_16, TwoRegisters(SP, HL), _, _, s3) ::
|
||||
ZLine(POP, OneRegister(Index), _, _, s4) :: tail =>
|
||||
if (size != sourceSize) {
|
||||
println("Mismatched stack frame sizes")
|
||||
None
|
||||
@ -118,16 +118,16 @@ object CompactStackFrame extends AssemblyOptimization[ZLine] {
|
||||
case (ret, rest) =>
|
||||
val epilogue = if (targetSize == 0) Nil else {
|
||||
List(
|
||||
ZLine.ldImm16(HL, targetSize),
|
||||
ZLine.registers(ADD_16, HL, SP),
|
||||
ZLine.ld16(SP, HL),
|
||||
ZLine.register(POP, Index))
|
||||
ZLine.ldImm16(HL, targetSize).pos(s1),
|
||||
ZLine.registers(ADD_16, HL, SP).pos(s2),
|
||||
ZLine.ld16(SP, HL).pos(s3),
|
||||
ZLine.register(POP, Index).pos(s4))
|
||||
}
|
||||
optimizeContinue(rest, Index, sourceSize, targetSize, mapping).map(epilogue ++ ret ++ _)
|
||||
}
|
||||
}
|
||||
case ZLine(RET | RETI | RETN | BYTE, _, _, _) :: _ => None
|
||||
case ZLine(JP, _, MemoryAddressConstant(f: NormalFunction), _) :: _ => None
|
||||
case ZLine0(RET | RETI | RETN | BYTE, _, _) :: _ => None
|
||||
case ZLine0(JP, _, MemoryAddressConstant(f: NormalFunction)) :: _ => None
|
||||
case x :: _ if x.changesRegister(Index) => None
|
||||
case x :: xs => optimizeContinue(xs, Index, sourceSize, targetSize, mapping).map(x :: _)
|
||||
case Nil => Some(Nil)
|
||||
@ -140,8 +140,8 @@ object CompactStackFrame extends AssemblyOptimization[ZLine] {
|
||||
import millfork.assembly.z80.ZOpcode._
|
||||
val potentialResult = (discards :+ rest.head) -> rest.tail
|
||||
rest.head match {
|
||||
case ZLine(RET | RETI | RETN, _, _, _) => Some(potentialResult)
|
||||
case ZLine(JP, NoRegisters, MemoryAddressConstant(f: NormalFunction), _) => Some(potentialResult)
|
||||
case ZLine0(RET | RETI | RETN, _, _) => Some(potentialResult)
|
||||
case ZLine0(JP, NoRegisters, MemoryAddressConstant(f: NormalFunction)) => Some(potentialResult)
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
package millfork.assembly.z80.opt
|
||||
|
||||
import millfork.assembly.Elidability
|
||||
import millfork.assembly.z80.ZOpcode._
|
||||
import millfork.assembly.z80._
|
||||
import millfork.env.{Constant, Label, MemoryAddressConstant, NormalFunction}
|
||||
import millfork.parser.Preprocessor.IfContext
|
||||
import millfork.{CompilationFlag, CompilationOptions}
|
||||
import millfork.env.{Constant, Label, MemoryAddressConstant}
|
||||
import millfork.CompilationOptions
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
@ -12,18 +12,18 @@ import millfork.{CompilationFlag, CompilationOptions}
|
||||
object ConditionalInstructions {
|
||||
|
||||
def apply(options: CompilationOptions, code: List[ZLine]): List[ZLine] = code match {
|
||||
case (jump@ZLine(JR | JP, IfFlagSet(_) | IfFlagClear(_), MemoryAddressConstant(Label(label)), true)) ::
|
||||
(call@ZLine(CALL, NoRegisters, _, _)) ::
|
||||
case (jump@ZLine(JR | JP, IfFlagSet(_) | IfFlagClear(_), MemoryAddressConstant(Label(label)), Elidability.Elidable, _)) ::
|
||||
(call@ZLine0(CALL, NoRegisters, _)) ::
|
||||
xs =>
|
||||
if (startsWithLabel(label, xs)) {
|
||||
val condCall = call.copy(registers = jump.registers.negate)
|
||||
options.log.debug(s"Replacing ${jump.toString.trim} ${call.toString.trim} with ${condCall.toString.trim}")
|
||||
condCall :: apply(options, xs)
|
||||
}else jump :: call :: apply(options, xs)
|
||||
case (jump@ZLine(JR | JP, IfFlagSet(_) | IfFlagClear(_), MemoryAddressConstant(Label(label)), true)) :: xs =>
|
||||
case (jump@ZLine(JR | JP, IfFlagSet(_) | IfFlagClear(_), MemoryAddressConstant(Label(label)), Elidability.Elidable, sl)) :: xs =>
|
||||
retPrecededByDiscards(xs) match {
|
||||
case Some(rest) if startsWithLabel(label, rest) =>
|
||||
val condRet = ZLine(RET, jump.registers.negate, Constant.Zero)
|
||||
val condRet = ZLine(RET, jump.registers.negate, Constant.Zero).pos(sl)
|
||||
options.log.debug(s"Replacing ${jump.toString.trim} RET with ${condRet.toString.trim}")
|
||||
condRet :: apply(options, rest)
|
||||
|
||||
@ -35,17 +35,17 @@ object ConditionalInstructions {
|
||||
|
||||
private def retPrecededByDiscards(code: List[ZLine]): Option[List[ZLine]] = {
|
||||
code match {
|
||||
case ZLine(op, _, _, _) :: xs if ZOpcodeClasses.NoopDiscards(op) => retPrecededByDiscards(xs)
|
||||
case ZLine(RET, NoRegisters, _, _) :: xs => Some(xs)
|
||||
case ZLine0(op, _, _) :: xs if ZOpcodeClasses.NoopDiscards(op) => retPrecededByDiscards(xs)
|
||||
case ZLine0(RET, NoRegisters, _) :: xs => Some(xs)
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
|
||||
private def startsWithLabel(LabelName: String, code: List[ZLine]): Boolean = {
|
||||
code match {
|
||||
case ZLine(LABEL, _, MemoryAddressConstant(Label(LabelName)), _) :: xs => true
|
||||
case ZLine(LABEL, _, _, _) :: xs => startsWithLabel(LabelName, xs)
|
||||
case ZLine(op, _, _, _) :: xs if ZOpcodeClasses.NoopDiscards(op) => startsWithLabel(LabelName, xs)
|
||||
case ZLine0(LABEL, _, MemoryAddressConstant(Label(LabelName))) :: xs => true
|
||||
case ZLine0(LABEL, _, _) :: xs => startsWithLabel(LabelName, xs)
|
||||
case ZLine0(op, _, _) :: xs if ZOpcodeClasses.NoopDiscards(op) => startsWithLabel(LabelName, xs)
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package millfork.assembly.z80.opt
|
||||
|
||||
import millfork.assembly.z80.{OneRegister, TwoRegisters, ZLine}
|
||||
import millfork.assembly.{AssemblyOptimization, OptimizationContext}
|
||||
import millfork.assembly.{AssemblyOptimization, Elidability, OptimizationContext}
|
||||
import millfork.env._
|
||||
import millfork.error.ConsoleLogger
|
||||
import millfork.node.ZRegister
|
||||
@ -30,12 +30,12 @@ object EmptyMemoryStoreRemoval extends AssemblyOptimization[ZLine] {
|
||||
val lastVariableAccess = code(lastaccess)
|
||||
import millfork.assembly.z80.ZOpcode._
|
||||
if (lastVariableAccess match {
|
||||
case ZLine(LD, TwoRegisters(MEM_HL, _), _, true) => true
|
||||
case ZLine(LD | LD_16, TwoRegisters(MEM_ABS_8 | MEM_ABS_16, _), _, true) => true
|
||||
case ZLine(INC | DEC, OneRegister(MEM_HL), _, true) =>
|
||||
case ZLine(LD, TwoRegisters(MEM_HL, _), _, Elidability.Elidable, _) => true
|
||||
case ZLine(LD | LD_16, TwoRegisters(MEM_ABS_8 | MEM_ABS_16, _), _, Elidability.Elidable, _) => true
|
||||
case ZLine(INC | DEC, OneRegister(MEM_HL), _, Elidability.Elidable, _) =>
|
||||
val importances = vs.codeWithFlow(lastaccess)._1.importanceAfter
|
||||
Seq(importances.sf, importances.zf).forall(_ == Unimportant)
|
||||
case ZLine(SLA | SLL | SRA | SRL | RL | RR | RLC | RRC, OneRegister(MEM_HL), _, true) =>
|
||||
case ZLine(SLA | SLL | SRA | SRL | RL | RR | RLC | RRC, OneRegister(MEM_HL), _, Elidability.Elidable, _) =>
|
||||
val importances = vs.codeWithFlow(lastaccess)._1.importanceAfter
|
||||
Seq(importances.sf, importances.zf, importances.cf).forall(_ == Unimportant)
|
||||
case _ => false
|
||||
|
@ -2,10 +2,9 @@ package millfork.assembly.z80.opt
|
||||
|
||||
import millfork.Cpu
|
||||
import millfork.assembly.z80.ZOpcode._
|
||||
import millfork.assembly.z80.{TwoRegisters, ZLine}
|
||||
import millfork.assembly.{AssemblyOptimization, OptimizationContext}
|
||||
import millfork.assembly.z80.{TwoRegisters, ZLine, ZLine0}
|
||||
import millfork.assembly.{AssemblyOptimization, Elidability, OptimizationContext}
|
||||
import millfork.env._
|
||||
import millfork.error.ConsoleLogger
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
@ -15,8 +14,8 @@ object EmptyParameterStoreRemoval extends AssemblyOptimization[ZLine] {
|
||||
|
||||
override def optimize(f: NormalFunction, code: List[ZLine], optimizationContext: OptimizationContext): List[ZLine] = {
|
||||
val usedFunctions = code.flatMap {
|
||||
case ZLine(CALL | JP | JR, _, MemoryAddressConstant(th), _) => Some(th.name)
|
||||
case ZLine(CALL | JP | JR, _, NumericConstant(addr, _), _) => Some("$" + addr.toHexString)
|
||||
case ZLine0(CALL | JP | JR, _, MemoryAddressConstant(th)) => Some(th.name)
|
||||
case ZLine0(CALL | JP | JR, _, NumericConstant(addr, _)) => Some("$" + addr.toHexString)
|
||||
case _ => None
|
||||
}.toSet
|
||||
val foreignVariables = f.environment.root.things.values.flatMap {
|
||||
@ -46,17 +45,17 @@ object EmptyParameterStoreRemoval extends AssemblyOptimization[ZLine] {
|
||||
}.toSet
|
||||
import millfork.node.ZRegister._
|
||||
val stillReadOrStoredVariables = code.flatMap {
|
||||
case ZLine(_, _, MemoryAddressConstant(th), _) => Some(th.name)
|
||||
case ZLine(_, _, CompoundConstant(_, MemoryAddressConstant(th), _), _) => Some(th.name)
|
||||
case ZLine(_, _, SubbyteConstant(MemoryAddressConstant(th), _), _) => Some(th.name)
|
||||
case ZLine0(_, _, MemoryAddressConstant(th)) => Some(th.name)
|
||||
case ZLine0(_, _, CompoundConstant(_, MemoryAddressConstant(th), _)) => Some(th.name)
|
||||
case ZLine0(_, _, SubbyteConstant(MemoryAddressConstant(th), _)) => Some(th.name)
|
||||
case _ => None
|
||||
}.toSet
|
||||
val stillReadVariables = code.flatMap {
|
||||
case ZLine(LD | LD_16, TwoRegisters(MEM_ABS_8 | MEM_ABS_16, _), MemoryAddressConstant(th), true) => Nil
|
||||
case ZLine(LD | LD_16, TwoRegisters(MEM_ABS_8 | MEM_ABS_16, _), CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(_, _)), true) => Nil
|
||||
case ZLine(_, _, MemoryAddressConstant(th), _) => Some(th.name)
|
||||
case ZLine(_, _, CompoundConstant(_, MemoryAddressConstant(th), _), _) => Some(th.name)
|
||||
case ZLine(_, _, SubbyteConstant(MemoryAddressConstant(th), _), _) => Some(th.name)
|
||||
case ZLine(LD | LD_16, TwoRegisters(MEM_ABS_8 | MEM_ABS_16, _), MemoryAddressConstant(th), Elidability.Elidable, _) => Nil
|
||||
case ZLine(LD | LD_16, TwoRegisters(MEM_ABS_8 | MEM_ABS_16, _), CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(_, _)), Elidability.Elidable, _) => Nil
|
||||
case ZLine0(_, _, MemoryAddressConstant(th)) => Some(th.name)
|
||||
case ZLine0(_, _, CompoundConstant(_, MemoryAddressConstant(th), _)) => Some(th.name)
|
||||
case ZLine0(_, _, SubbyteConstant(MemoryAddressConstant(th), _)) => Some(th.name)
|
||||
case _ => None
|
||||
}.toSet
|
||||
|
||||
@ -67,9 +66,9 @@ object EmptyParameterStoreRemoval extends AssemblyOptimization[ZLine] {
|
||||
|
||||
optimizationContext.log.debug(s"Removing pointless store(s) to foreign variables ${unusedForeignVariables.mkString(", ")}")
|
||||
code.filterNot {
|
||||
case ZLine(LD | LD_16, TwoRegisters(MEM_ABS_8 | MEM_ABS_16, _), MemoryAddressConstant(th), _) =>
|
||||
case ZLine0(LD | LD_16, TwoRegisters(MEM_ABS_8 | MEM_ABS_16, _), MemoryAddressConstant(th)) =>
|
||||
unusedForeignVariables(th.name)
|
||||
case ZLine(LD | LD_16, TwoRegisters(MEM_ABS_8 | MEM_ABS_16, _), CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(_, _)), true) =>
|
||||
case ZLine(LD | LD_16, TwoRegisters(MEM_ABS_8 | MEM_ABS_16, _), CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(_, _)), Elidability.Elidable, _) =>
|
||||
unusedForeignVariables(th.name)
|
||||
case _ => false
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package millfork.assembly.z80.opt
|
||||
|
||||
import millfork.CompilationOptions
|
||||
import millfork.assembly.z80.{ZLine, ZOpcode}
|
||||
import millfork.assembly.z80.{ZLine, ZLine0, ZOpcode}
|
||||
import millfork.env.{Label, MemoryAddressConstant, NormalFunction}
|
||||
|
||||
/**
|
||||
@ -47,7 +47,7 @@ object FlowAnalyzer {
|
||||
val labelMap: (() => Option[Map[String, Int]]) = () => req match {
|
||||
case FlowInfoRequirement.NoRequirement => None
|
||||
case _ => Some(code.flatMap {
|
||||
case ZLine(op, _, MemoryAddressConstant(Label(l)), _) if op != ZOpcode.LABEL => Some(l)
|
||||
case ZLine0(op, _, MemoryAddressConstant(Label(l))) if op != ZOpcode.LABEL => Some(l)
|
||||
case _ => None
|
||||
}.groupBy(identity).mapValues(_.size))
|
||||
}
|
||||
|
@ -3,7 +3,8 @@ package millfork.assembly.z80.opt
|
||||
import millfork.assembly.z80.ZOpcode._
|
||||
import millfork.assembly.z80._
|
||||
import millfork.env.{Constant, Label, MemoryAddressConstant}
|
||||
import millfork.{CompilationOptions}
|
||||
import millfork.CompilationOptions
|
||||
import millfork.assembly.Elidability
|
||||
|
||||
import scala.collection.mutable
|
||||
|
||||
@ -18,14 +19,14 @@ object JumpFollowing {
|
||||
val currentLabels = mutable.Set[String]()
|
||||
for (line <- code) {
|
||||
line match {
|
||||
case ZLine(LABEL, _, MemoryAddressConstant(Label(label)), _) =>
|
||||
case ZLine0(LABEL, _, MemoryAddressConstant(Label(label))) =>
|
||||
currentLabels += label
|
||||
case ZLine(op, _, _, _) if ZOpcodeClasses.NoopDiscards(op) =>
|
||||
case ZLine(LABEL, _, _, _) =>
|
||||
case ZLine(RET, NoRegisters, _, _) =>
|
||||
case ZLine0(op, _, _) if ZOpcodeClasses.NoopDiscards(op) =>
|
||||
case ZLine0(LABEL, _, _) =>
|
||||
case ZLine0(RET, NoRegisters, _) =>
|
||||
labelsToRet ++= currentLabels
|
||||
currentLabels.clear()
|
||||
case ZLine(JP | JR, NoRegisters, MemoryAddressConstant(Label(label)), _) =>
|
||||
case ZLine0(JP | JR, NoRegisters, MemoryAddressConstant(Label(label))) =>
|
||||
labelsToJumps ++= currentLabels.map(_ -> label)
|
||||
currentLabels.clear()
|
||||
case _ =>
|
||||
@ -33,7 +34,7 @@ object JumpFollowing {
|
||||
}
|
||||
}
|
||||
code.map {
|
||||
case jump@ZLine(JR | JP, cond, MemoryAddressConstant(Label(label)), true) =>
|
||||
case jump@ZLine(JR | JP, cond, MemoryAddressConstant(Label(label)), Elidability.Elidable, _) =>
|
||||
if (labelsToRet(label)) {
|
||||
options.log.debug(s"Optimizing ${jump.opcode} straight into RET")
|
||||
ZLine(RET, cond, Constant.Zero)
|
||||
|
@ -1,7 +1,7 @@
|
||||
package millfork.assembly.z80.opt
|
||||
|
||||
import millfork.{CompilationFlag, CompilationOptions}
|
||||
import millfork.assembly.OptimizationContext
|
||||
import millfork.assembly.{Elidability, OptimizationContext}
|
||||
import millfork.assembly.z80.ZOpcode._
|
||||
import millfork.assembly.z80._
|
||||
import millfork.env.{Label, MemoryAddressConstant, NormalFunction}
|
||||
@ -30,11 +30,11 @@ object JumpShortening {
|
||||
o += line.sizeInBytes
|
||||
}
|
||||
val labelOffsets = code.zipWithIndex.flatMap {
|
||||
case (ZLine(LABEL, _, MemoryAddressConstant(Label(label)), _), ix) => Some(label -> offsets(ix))
|
||||
case (ZLine0(LABEL, _, MemoryAddressConstant(Label(label))), ix) => Some(label -> offsets(ix))
|
||||
case _ => None
|
||||
}.toMap
|
||||
code.zipWithIndex.map {
|
||||
case (line@ZLine(JP, NoRegisters | IfFlagSet(ZFlag.Z | ZFlag.C) | IfFlagClear(ZFlag.Z | ZFlag.C), MemoryAddressConstant(Label(label)), true), ix) =>
|
||||
case (line@ZLine(JP, NoRegisters | IfFlagSet(ZFlag.Z | ZFlag.C) | IfFlagClear(ZFlag.Z | ZFlag.C), MemoryAddressConstant(Label(label)), Elidability.Elidable, _), ix) =>
|
||||
labelOffsets.get(label).fold(line) { labelOffset =>
|
||||
val thisOffset = offsets(ix)
|
||||
val willBeTaken = line.registers == NoRegisters ||
|
||||
|
@ -205,45 +205,45 @@ object ReverseFlowAnalyzer {
|
||||
}
|
||||
val currentLine = codeArray(i)
|
||||
currentLine match {
|
||||
case ZLine(LABEL | EI | DI | NOP, _, _, _) => ()
|
||||
case ZLine(DJNZ, _, MemoryAddressConstant(Label(l)), _) =>
|
||||
case ZLine0(LABEL | EI | DI | NOP, _, _) => ()
|
||||
case ZLine0(DJNZ, _, MemoryAddressConstant(Label(l))) =>
|
||||
val labelIndex = getLabelIndex(codeArray, l)
|
||||
currentImportance = if (labelIndex < 0) finalImportance else (importanceArray(labelIndex) ~ currentImportance).butReadsRegister(ZRegister.B).butReadsFlag(ZFlag.Z)
|
||||
case ZLine(JP | JR, IfFlagSet(flag), MemoryAddressConstant(Label(l)), _) =>
|
||||
case ZLine0(JP | JR, IfFlagSet(flag), MemoryAddressConstant(Label(l))) =>
|
||||
val labelIndex = getLabelIndex(codeArray, l)
|
||||
currentImportance = if (labelIndex < 0) finalImportance else importanceArray(labelIndex) ~ currentImportance.butReadsFlag(flag)
|
||||
case ZLine(JP | JR, IfFlagClear(flag), MemoryAddressConstant(Label(l)), _) =>
|
||||
case ZLine0(JP | JR, IfFlagClear(flag), MemoryAddressConstant(Label(l))) =>
|
||||
val labelIndex = getLabelIndex(codeArray, l)
|
||||
currentImportance = if (labelIndex < 0) finalImportance else importanceArray(labelIndex) ~ currentImportance.butReadsFlag(flag)
|
||||
case ZLine(JP | JR, NoRegisters, MemoryAddressConstant(Label(l)), _) =>
|
||||
case ZLine0(JP | JR, NoRegisters, MemoryAddressConstant(Label(l))) =>
|
||||
val labelIndex = getLabelIndex(codeArray, l)
|
||||
currentImportance = if (labelIndex < 0) finalImportance else importanceArray(labelIndex)
|
||||
case ZLine(DISCARD_HL, _, _, _) =>
|
||||
case ZLine0(DISCARD_HL, _, _) =>
|
||||
currentImportance = currentImportance.copy(h = Unimportant, l = Unimportant)
|
||||
case ZLine(DISCARD_DE, _, _, _) =>
|
||||
case ZLine0(DISCARD_DE, _, _) =>
|
||||
currentImportance = currentImportance.copy(d = Unimportant, e = Unimportant)
|
||||
case ZLine(DISCARD_BC, _, _, _) =>
|
||||
case ZLine0(DISCARD_BC, _, _) =>
|
||||
currentImportance = currentImportance.copy(b = Unimportant, c = Unimportant)
|
||||
case ZLine(DISCARD_IX, _, _, _) =>
|
||||
case ZLine0(DISCARD_IX, _, _) =>
|
||||
currentImportance = currentImportance.copy(ixh = Unimportant, ixl = Unimportant)
|
||||
case ZLine(DISCARD_IY, _, _, _) =>
|
||||
case ZLine0(DISCARD_IY, _, _) =>
|
||||
currentImportance = currentImportance.copy(iyh = Unimportant, iyl = Unimportant)
|
||||
case ZLine(DISCARD_A, _, _, _) =>
|
||||
case ZLine0(DISCARD_A, _, _) =>
|
||||
currentImportance = currentImportance.copy(a = Unimportant)
|
||||
case ZLine(DISCARD_F, _, _, _) =>
|
||||
case ZLine0(DISCARD_F, _, _) =>
|
||||
currentImportance = currentImportance.copy(cf = Unimportant, zf = Unimportant, sf = Unimportant, pf = Unimportant, hf = Unimportant, nf = Unimportant)
|
||||
case ZLine(LD, TwoRegistersOffset(t, s, o), _, _) =>
|
||||
case ZLine0(LD, TwoRegistersOffset(t, s, o), _) =>
|
||||
currentImportance = currentImportance.butWritesRegister(t, o).butReadsRegister(s, o)
|
||||
case ZLine(LD | LD_16, TwoRegisters(t, s), _, _) =>
|
||||
case ZLine0(LD | LD_16, TwoRegisters(t, s), _) =>
|
||||
currentImportance = currentImportance.butWritesRegister(t).butReadsRegister(s)
|
||||
case ZLine(EX_DE_HL, TwoRegisters(t, s), _, _) =>
|
||||
case ZLine0(EX_DE_HL, TwoRegisters(t, s), _) =>
|
||||
currentImportance = currentImportance.copy(d = currentImportance.h, e = currentImportance.l, h = currentImportance.d, l = currentImportance.e)
|
||||
case ZLine(ADD_16, TwoRegisters(t, s), _, _) =>
|
||||
case ZLine0(ADD_16, TwoRegisters(t, s), _) =>
|
||||
currentImportance = currentImportance.butReadsRegister(t).butReadsRegister(s)
|
||||
case ZLine(ADC_16 | SBC_16, TwoRegisters(t, s), _, _) =>
|
||||
case ZLine0(ADC_16 | SBC_16, TwoRegisters(t, s), _) =>
|
||||
currentImportance = currentImportance.butReadsRegister(t).butReadsRegister(s).butReadsFlag(ZFlag.C)
|
||||
|
||||
case ZLine(XOR, OneRegister(ZRegister.A), _, _) =>
|
||||
case ZLine0(XOR, OneRegister(ZRegister.A), _) =>
|
||||
currentImportance = currentImportance.copy(
|
||||
a = Unimportant,
|
||||
cf = Unimportant,
|
||||
@ -252,7 +252,7 @@ object ReverseFlowAnalyzer {
|
||||
hf = Unimportant,
|
||||
pf = Unimportant
|
||||
)
|
||||
case ZLine(OR | AND, OneRegister(ZRegister.A), _, _) =>
|
||||
case ZLine0(OR | AND, OneRegister(ZRegister.A), _) =>
|
||||
currentImportance = currentImportance.copy(
|
||||
a = currentImportance.zf ~ currentImportance.sf ~ currentImportance.pf ~ currentImportance.a,
|
||||
cf = Unimportant,
|
||||
@ -262,7 +262,7 @@ object ReverseFlowAnalyzer {
|
||||
pf = Unimportant
|
||||
)
|
||||
|
||||
case ZLine(ADD | SUB | CP, OneRegister(s), _, _) =>
|
||||
case ZLine0(ADD | SUB | CP, OneRegister(s), _) =>
|
||||
currentImportance = currentImportance.butReadsRegister(s).copy(
|
||||
a = Important,
|
||||
cf = Unimportant,
|
||||
@ -272,7 +272,7 @@ object ReverseFlowAnalyzer {
|
||||
pf = Unimportant,
|
||||
nf = Unimportant
|
||||
)
|
||||
case ZLine(ADD | SUB | CP, OneRegisterOffset(s, o), _, _) =>
|
||||
case ZLine0(ADD | SUB | CP, OneRegisterOffset(s, o), _) =>
|
||||
currentImportance = currentImportance.butReadsRegister(s, o).copy(
|
||||
a = Important,
|
||||
cf = Unimportant,
|
||||
@ -283,7 +283,7 @@ object ReverseFlowAnalyzer {
|
||||
nf = Unimportant
|
||||
)
|
||||
|
||||
case ZLine(AND | OR | XOR, OneRegister(s), _, _) =>
|
||||
case ZLine0(AND | OR | XOR, OneRegister(s), _) =>
|
||||
currentImportance = currentImportance.butReadsRegister(s).copy(
|
||||
a = Important,
|
||||
cf = Unimportant,
|
||||
@ -292,7 +292,7 @@ object ReverseFlowAnalyzer {
|
||||
sf = Unimportant
|
||||
)
|
||||
|
||||
case ZLine(AND | OR | XOR, OneRegisterOffset(s, o), _, _) =>
|
||||
case ZLine0(AND | OR | XOR, OneRegisterOffset(s, o), _) =>
|
||||
currentImportance = currentImportance.butReadsRegister(s, o).copy(
|
||||
a = Important,
|
||||
cf = Unimportant,
|
||||
@ -300,7 +300,7 @@ object ReverseFlowAnalyzer {
|
||||
pf = Unimportant,
|
||||
sf = Unimportant
|
||||
)
|
||||
case ZLine(ADC | SBC, OneRegister(s), _, _) =>
|
||||
case ZLine0(ADC | SBC, OneRegister(s), _) =>
|
||||
currentImportance = currentImportance.butReadsRegister(s).copy(
|
||||
a = Important,
|
||||
cf = Important,
|
||||
@ -310,7 +310,7 @@ object ReverseFlowAnalyzer {
|
||||
pf = Unimportant,
|
||||
nf = Unimportant
|
||||
)
|
||||
case ZLine(ADC | SBC, OneRegisterOffset(s, o), _, _) =>
|
||||
case ZLine0(ADC | SBC, OneRegisterOffset(s, o), _) =>
|
||||
currentImportance = currentImportance.butReadsRegister(s, o).copy(
|
||||
a = Important,
|
||||
cf = Important,
|
||||
@ -322,28 +322,28 @@ object ReverseFlowAnalyzer {
|
||||
)
|
||||
|
||||
|
||||
case ZLine(DAA, _, _, _) =>
|
||||
case ZLine0(DAA, _, _) =>
|
||||
currentImportance = currentImportance.copy(
|
||||
a = Important,
|
||||
hf = Important
|
||||
)
|
||||
case ZLine(NEG, _, _, _) =>
|
||||
case ZLine0(NEG, _, _) =>
|
||||
currentImportance = currentImportance.copy(
|
||||
a = Important
|
||||
)
|
||||
case ZLine(INC | DEC | INC_16 | DEC_16, OneRegister(s), _, _) =>
|
||||
case ZLine0(INC | DEC | INC_16 | DEC_16, OneRegister(s), _) =>
|
||||
currentImportance = currentImportance.butReadsRegister(s)
|
||||
case ZLine(INC | DEC | INC_16 | DEC_16, OneRegisterOffset(s, o), _, _) =>
|
||||
case ZLine0(INC | DEC | INC_16 | DEC_16, OneRegisterOffset(s, o), _) =>
|
||||
currentImportance = currentImportance.butReadsRegister(s, o)
|
||||
case ZLine(op, OneRegister(s), _, _) if ZOpcodeClasses.AllSingleBit(op)=>
|
||||
case ZLine0(op, OneRegister(s), _) if ZOpcodeClasses.AllSingleBit(op)=>
|
||||
currentImportance = currentImportance.butReadsRegister(s)
|
||||
case ZLine(op, OneRegisterOffset(s, o), _, _) if ZOpcodeClasses.AllSingleBit(op)=>
|
||||
case ZLine0(op, OneRegisterOffset(s, o), _) if ZOpcodeClasses.AllSingleBit(op)=>
|
||||
currentImportance = currentImportance.butReadsRegister(s, o)
|
||||
case ZLine(POP, OneRegister(r), _, _) =>
|
||||
case ZLine0(POP, OneRegister(r), _) =>
|
||||
currentImportance = currentImportance.butWritesRegister(r)
|
||||
case ZLine(PUSH, OneRegister(r), _, _) =>
|
||||
case ZLine0(PUSH, OneRegister(r), _) =>
|
||||
currentImportance = currentImportance.butReadsRegister(r)
|
||||
case ZLine(CALL | JP, NoRegisters, MemoryAddressConstant(fun: FunctionInMemory), _) =>
|
||||
case ZLine0(CALL | JP, NoRegisters, MemoryAddressConstant(fun: FunctionInMemory)) =>
|
||||
val n = fun.name
|
||||
fun.params match {
|
||||
case NormalParamSignature(List(v)) if v.typ.size == 1 =>
|
||||
@ -440,15 +440,15 @@ object ReverseFlowAnalyzer {
|
||||
currentImportance = finalImportance.copy(memIx = currentImportance.memIx)
|
||||
}
|
||||
|
||||
case ZLine(SLA | SRL, OneRegister(r), _, _) =>
|
||||
case ZLine0(SLA | SRL, OneRegister(r), _) =>
|
||||
currentImportance = currentImportance.butReadsRegister(r).copy(cf = Unimportant, zf = Unimportant, hf = Unimportant, nf = Unimportant, pf = Unimportant)
|
||||
case ZLine(RL | RR | RLC | RRC, OneRegister(r), _, _) =>
|
||||
case ZLine0(RL | RR | RLC | RRC, OneRegister(r), _) =>
|
||||
currentImportance = currentImportance.butReadsRegister(r).copy(cf = Important, zf = Unimportant, hf = Unimportant, nf = Unimportant, pf = Unimportant)
|
||||
case ZLine(SWAP, OneRegister(r), _, _) =>
|
||||
case ZLine0(SWAP, OneRegister(r), _) =>
|
||||
currentImportance = currentImportance.butReadsRegister(r).copy(cf = Unimportant, zf = Unimportant, hf = Unimportant, nf = Unimportant, pf = Unimportant)
|
||||
case ZLine(RLA | RRA | RLCA | RRCA, _, _, _) =>
|
||||
case ZLine0(RLA | RRA | RLCA | RRCA, _, _) =>
|
||||
currentImportance = currentImportance.butReadsRegister(ZRegister.A).copy(cf = Important, hf = Unimportant, nf = Unimportant)
|
||||
case ZLine(SCF, _, _, _) =>
|
||||
case ZLine0(SCF, _, _) =>
|
||||
currentImportance = currentImportance.copy(cf = Unimportant, hf = Unimportant, nf = Unimportant)
|
||||
case _ =>
|
||||
currentImportance = finalImportance // TODO
|
||||
@ -465,7 +465,7 @@ object ReverseFlowAnalyzer {
|
||||
|
||||
private def getLabelIndex(codeArray: Array[ZLine], L: String) = {
|
||||
codeArray.indexWhere {
|
||||
case ZLine(ZOpcode.LABEL, _, MemoryAddressConstant(Label(L)), _) => true
|
||||
case ZLine0(ZOpcode.LABEL, _, MemoryAddressConstant(Label(L))) => true
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +55,12 @@ class RuleBasedAssemblyOptimization(val name: String, val needsFlowInfo: FlowInf
|
||||
case Some(rest: List[(FlowInfo, ZLine)]) =>
|
||||
val matchedChunkToOptimize: List[ZLine] = code.take(code.length - rest.length).map(_._2)
|
||||
val optimizedChunk: List[ZLine] = rule.result(matchedChunkToOptimize, ctx)
|
||||
val optimizedChunkWithSource =
|
||||
if (optimizedChunk.isEmpty) optimizedChunk
|
||||
else if (matchedChunkToOptimize.size == 1) optimizedChunk.map(_.pos(matchedChunkToOptimize.head.source))
|
||||
else if (optimizedChunk.size == 1) optimizedChunk.map(_.pos(SourceLine.merge(matchedChunkToOptimize.map(_.source))))
|
||||
else if (matchedChunkToOptimize.flatMap(_.source).toSet.size == 1) optimizedChunk.map(_.pos(SourceLine.merge(matchedChunkToOptimize.map(_.source))))
|
||||
else optimizedChunk
|
||||
log.debug(s"Applied $name ($index)")
|
||||
if (needsFlowInfo != FlowInfoRequirement.NoRequirement) {
|
||||
val before = code.head._1.statusBefore
|
||||
@ -67,12 +73,12 @@ class RuleBasedAssemblyOptimization(val name: String, val needsFlowInfo: FlowInf
|
||||
if (log.traceEnabled) {
|
||||
matchedChunkToOptimize.filter(_.isPrintable).foreach(l => log.trace(l.toString))
|
||||
log.trace(" ↓")
|
||||
optimizedChunk.filter(_.isPrintable).foreach(l => log.trace(l.toString))
|
||||
optimizedChunkWithSource.filter(_.isPrintable).foreach(l => log.trace(l.toString))
|
||||
}
|
||||
if (needsFlowInfo != FlowInfoRequirement.NoRequirement) {
|
||||
return optimizedChunk ++ optimizeImpl(f, rest, optimizationContext)
|
||||
return optimizedChunkWithSource ++ optimizeImpl(f, rest, optimizationContext)
|
||||
} else {
|
||||
return optimize(f, optimizedChunk ++ rest.map(_._2), optimizationContext)
|
||||
return optimize(f, optimizedChunkWithSource ++ rest.map(_._2), optimizationContext)
|
||||
}
|
||||
case None => ()
|
||||
}
|
||||
@ -149,15 +155,15 @@ class AssemblyMatchingContext(val compilationOptions: CompilationOptions) {
|
||||
import millfork.assembly.z80.ZOpcode._
|
||||
get[List[ZLine]](i).foreach {
|
||||
// JSR and BSR are allowed
|
||||
case ZLine(RET | RST | RETI | RETN, _, _, _) =>
|
||||
case ZLine0(RET | RST | RETI | RETN, _, _) =>
|
||||
return false
|
||||
case ZLine(JP | JR, OneRegister(_), _, _) =>
|
||||
case ZLine0(JP | JR, OneRegister(_), _) =>
|
||||
return false
|
||||
case ZLine(JP | JR | DJNZ, _, MemoryAddressConstant(Label(l)), _) =>
|
||||
case ZLine0(JP | JR | DJNZ, _, MemoryAddressConstant(Label(l))) =>
|
||||
jumps += l
|
||||
case ZLine(LABEL, _, MemoryAddressConstant(Label(l)), _) =>
|
||||
case ZLine0(LABEL, _, MemoryAddressConstant(Label(l))) =>
|
||||
labels += l
|
||||
case ZLine(JP | JR | DJNZ, _, _, _) =>
|
||||
case ZLine0(JP | JR | DJNZ, _, _) =>
|
||||
return false
|
||||
case _ => ()
|
||||
}
|
||||
@ -998,7 +1004,7 @@ case class Before(pattern: AssemblyPattern) extends AssemblyLinePattern {
|
||||
case class HasCallerCount(count: Int) extends AssemblyLinePattern {
|
||||
override def matchLineTo(ctx: AssemblyMatchingContext, flowInfo: FlowInfo, line: ZLine): Boolean =
|
||||
line match {
|
||||
case ZLine(ZOpcode.LABEL, _, MemoryAddressConstant(Label(l)), _) => flowInfo.labelUseCount(l) == count
|
||||
case ZLine0(ZOpcode.LABEL, _, MemoryAddressConstant(Label(l))) => flowInfo.labelUseCount(l) == count
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
@ -14,9 +14,9 @@ object StackVariableLifetime {
|
||||
// TODO: this is also probably very wrong
|
||||
def apply(variableOffset: Int, codeWithFlow: List[(FlowInfo, ZLine)]): Range = {
|
||||
val flags = codeWithFlow.map {
|
||||
case (_, ZLine(_, OneRegisterOffset(ZRegister.MEM_IX_D, i), _, _)) => i == variableOffset
|
||||
case (_, ZLine(_, TwoRegistersOffset(ZRegister.MEM_IX_D, _, i), _, _)) => i == variableOffset
|
||||
case (_, ZLine(_, TwoRegistersOffset(_, ZRegister.MEM_IX_D, i), _, _)) => i == variableOffset
|
||||
case (_, ZLine0(_, OneRegisterOffset(ZRegister.MEM_IX_D, i), _)) => i == variableOffset
|
||||
case (_, ZLine0(_, TwoRegistersOffset(ZRegister.MEM_IX_D, _, i), _)) => i == variableOffset
|
||||
case (_, ZLine0(_, TwoRegistersOffset(_, ZRegister.MEM_IX_D, i), _)) => i == variableOffset
|
||||
case _ => false
|
||||
}
|
||||
if (flags.forall(!_)) return Range(0, 0)
|
||||
|
@ -1,7 +1,7 @@
|
||||
package millfork.assembly.z80.opt
|
||||
|
||||
import millfork.assembly.opt.SingleStatus
|
||||
import millfork.assembly.z80.{OneRegister, TwoRegisters, ZLine}
|
||||
import millfork.assembly.z80.{OneRegister, TwoRegisters, ZLine, ZLine0}
|
||||
import millfork.env._
|
||||
import millfork.error.ConsoleLogger
|
||||
import millfork.node.ZRegister
|
||||
@ -15,9 +15,9 @@ object VariableLifetime {
|
||||
// TODO: this is also probably very wrong
|
||||
def apply(variableName: String, codeWithFlow: List[(FlowInfo, ZLine)]): Range = {
|
||||
val flags = codeWithFlow.map {
|
||||
case (_, ZLine(_, _, MemoryAddressConstant(MemoryVariable(n, _, _)), _)) => n == variableName
|
||||
case (_, ZLine(_, _, CompoundConstant(MathOperator.Plus, MemoryAddressConstant(MemoryVariable(n, _, _)), NumericConstant(_, 1)), _)) => n == variableName
|
||||
case (i, ZLine(_, TwoRegisters(ZRegister.MEM_HL, _) | TwoRegisters(_, ZRegister.MEM_HL) | OneRegister(ZRegister.MEM_HL), _, _)) =>
|
||||
case (_, ZLine0(_, _, MemoryAddressConstant(MemoryVariable(n, _, _)))) => n == variableName
|
||||
case (_, ZLine0(_, _, CompoundConstant(MathOperator.Plus, MemoryAddressConstant(MemoryVariable(n, _, _)), NumericConstant(_, 1)))) => n == variableName
|
||||
case (i, ZLine0(_, TwoRegisters(ZRegister.MEM_HL, _) | TwoRegisters(_, ZRegister.MEM_HL) | OneRegister(ZRegister.MEM_HL), _)) =>
|
||||
i.statusBefore.hl match {
|
||||
case SingleStatus(MemoryAddressConstant(MemoryVariable(n, _, _))) => n == variableName
|
||||
case SingleStatus(CompoundConstant(MathOperator.Plus, MemoryAddressConstant(MemoryVariable(n, _, _)), NumericConstant(_, 1))) => n == variableName
|
||||
|
@ -3,7 +3,7 @@ package millfork.assembly.z80.opt
|
||||
import millfork.CompilationFlag
|
||||
import millfork.assembly.OptimizationContext
|
||||
import millfork.assembly.opt.SingleStatus
|
||||
import millfork.assembly.z80.{OneRegister, TwoRegisters, ZLine}
|
||||
import millfork.assembly.z80.{OneRegister, TwoRegisters, ZLine, ZLine0}
|
||||
import millfork.env._
|
||||
import millfork.node.ZRegister
|
||||
|
||||
@ -40,22 +40,22 @@ object VariableStatus {
|
||||
return None
|
||||
}
|
||||
val stillUsedVariables = code.flatMap {
|
||||
case ZLine(_, TwoRegisters(MEM_ABS_8 | MEM_ABS_16, _), MemoryAddressConstant(th), _) => Some(th.name)
|
||||
case ZLine(_, TwoRegisters(_, MEM_ABS_8 | MEM_ABS_16), MemoryAddressConstant(th), _) => Some(th.name)
|
||||
case ZLine(_, TwoRegisters(_, IMM_16), MemoryAddressConstant(th), _) => Some(th.name)
|
||||
case ZLine(_, TwoRegisters(MEM_ABS_8 | MEM_ABS_16, _), CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(_, _)), _) => Some(th.name)
|
||||
case ZLine(_, TwoRegisters(_, MEM_ABS_8 | MEM_ABS_16), CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(_, _)), _) => Some(th.name)
|
||||
case ZLine(_, TwoRegisters(_, IMM_16), CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(_, _)), _) => Some(th.name)
|
||||
case ZLine0(_, TwoRegisters(MEM_ABS_8 | MEM_ABS_16, _), MemoryAddressConstant(th)) => Some(th.name)
|
||||
case ZLine0(_, TwoRegisters(_, MEM_ABS_8 | MEM_ABS_16), MemoryAddressConstant(th)) => Some(th.name)
|
||||
case ZLine0(_, TwoRegisters(_, IMM_16), MemoryAddressConstant(th)) => Some(th.name)
|
||||
case ZLine0(_, TwoRegisters(MEM_ABS_8 | MEM_ABS_16, _), CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(_, _))) => Some(th.name)
|
||||
case ZLine0(_, TwoRegisters(_, MEM_ABS_8 | MEM_ABS_16), CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(_, _))) => Some(th.name)
|
||||
case ZLine0(_, TwoRegisters(_, IMM_16), CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(_, _))) => Some(th.name)
|
||||
case _ => None
|
||||
}.toSet
|
||||
val variablesWithAddressesTaken = code.zipWithIndex.flatMap {
|
||||
case (ZLine(_, _, SubbyteConstant(MemoryAddressConstant(th), _), _), _) =>
|
||||
case (ZLine0(_, _, SubbyteConstant(MemoryAddressConstant(th), _)), _) =>
|
||||
Some(th.name)
|
||||
case (ZLine(_, _, SubbyteConstant(CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(_, _)), _), _), _) =>
|
||||
case (ZLine0(_, _, SubbyteConstant(CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(_, _)), _)), _) =>
|
||||
Some(th.name)
|
||||
case (ZLine(_,
|
||||
case (ZLine0(_,
|
||||
TwoRegisters(ZRegister.MEM_HL, _) | TwoRegisters(_, ZRegister.MEM_HL) | OneRegister(ZRegister.MEM_HL),
|
||||
_, _), i) =>
|
||||
_), i) =>
|
||||
flow(i)._1.statusBefore.hl match {
|
||||
case SingleStatus(MemoryAddressConstant(th)) =>
|
||||
if (flow(i)._1.importanceAfter.hlNumeric != Unimportant) Some(th.name)
|
||||
|
@ -1,8 +1,8 @@
|
||||
package millfork.assembly.z80.opt
|
||||
|
||||
import millfork.{CompilationFlag, NonOverlappingIntervals}
|
||||
import millfork.assembly.{AssemblyOptimization, OptimizationContext}
|
||||
import millfork.assembly.z80.{TwoRegisters, ZFlag, ZLine}
|
||||
import millfork.assembly.{AssemblyOptimization, Elidability, OptimizationContext}
|
||||
import millfork.assembly.z80.{TwoRegisters, ZFlag, ZLine, ZLine0}
|
||||
import millfork.env._
|
||||
import millfork.error.ConsoleLogger
|
||||
import millfork.node.ZRegister
|
||||
@ -192,21 +192,21 @@ object WordVariableToRegisterOptimization extends AssemblyOptimization[ZLine] {
|
||||
None
|
||||
}
|
||||
code match {
|
||||
case (_, ZLine(LD_16, TwoRegisters(BC, IMM_16), _, true))::
|
||||
(i, ZLine(ADD_16, TwoRegisters(HL, BC), _, true)) :: xs if target == BC =>
|
||||
case (_, ZLine(LD_16, TwoRegisters(BC, IMM_16), _, Elidability.Elidable, _))::
|
||||
(i, ZLine(ADD_16, TwoRegisters(HL, BC), _, Elidability.Elidable, _)) :: xs if target == BC =>
|
||||
if (i.importanceAfter.getRegister(BC) == Important) fail(22)
|
||||
else if(i.importanceAfter.getRegister(DE) == Important) canBeInlined(vname, synced, target, xs).map(add(CyclesAndBytes(-21, -2)))
|
||||
else canBeInlined(vname, synced = true, target, xs)
|
||||
|
||||
case (_, ZLine(LD_16, TwoRegisters(DE, IMM_16), _, true))::
|
||||
(i, ZLine(ADD_16, TwoRegisters(HL, DE), _, true)) :: xs if target == DE =>
|
||||
case (_, ZLine(LD_16, TwoRegisters(DE, IMM_16), _, Elidability.Elidable, _))::
|
||||
(i, ZLine(ADD_16, TwoRegisters(HL, DE), _, Elidability.Elidable, _)) :: xs if target == DE =>
|
||||
if (i.importanceAfter.getRegister(DE) == Important) fail(23)
|
||||
else if (i.importanceAfter.getRegister(BC) == Important) canBeInlined(vname, synced, target, xs).map(add(CyclesAndBytes(-21, -2)))
|
||||
else canBeInlined(vname, synced = true, target, xs)
|
||||
|
||||
case (_, ZLine(LD_16, TwoRegisters(HL, MEM_ABS_16), MemoryAddressConstant(th1), true)) ::
|
||||
(_, ZLine(ADD_16, TwoRegisters(HL, BC | DE), _, _)) ::
|
||||
(i, ZLine(LD_16, TwoRegisters(MEM_ABS_16, HL), MemoryAddressConstant(th2), true)) ::
|
||||
case (_, ZLine(LD_16, TwoRegisters(HL, MEM_ABS_16), MemoryAddressConstant(th1), Elidability.Elidable, _)) ::
|
||||
(_, ZLine0(ADD_16, TwoRegisters(HL, BC | DE), _)) ::
|
||||
(i, ZLine(LD_16, TwoRegisters(MEM_ABS_16, HL), MemoryAddressConstant(th2), Elidability.Elidable, _)) ::
|
||||
xs if target == HL && th1.name != vname && th2.name != vname &&
|
||||
i.importanceAfter.getFlag(ZFlag.Z) != Important &&
|
||||
i.importanceAfter.getFlag(ZFlag.H) != Important &&
|
||||
@ -220,65 +220,65 @@ object WordVariableToRegisterOptimization extends AssemblyOptimization[ZLine] {
|
||||
// cycles after: 13 + 4 + 13 + 13 + 4 + 13 = 60
|
||||
canBeInlined(vname, synced = true, target, xs).map(add(CyclesAndBytes(-17, -7)))
|
||||
|
||||
case (_, ZLine(LD_16, TwoRegisters(t, _), _, true)) ::
|
||||
(_, ZLine(LD_16, TwoRegisters(HL, MEM_ABS_16), MemoryAddressConstant(th), true)) ::
|
||||
(i, ZLine(ADD_16, TwoRegisters(HL, t2), _, _)) ::
|
||||
case (_, ZLine(LD_16, TwoRegisters(t, _), _, Elidability.Elidable, _)) ::
|
||||
(_, ZLine(LD_16, TwoRegisters(HL, MEM_ABS_16), MemoryAddressConstant(th), Elidability.Elidable, _)) ::
|
||||
(i, ZLine0(ADD_16, TwoRegisters(HL, t2), _)) ::
|
||||
xs if th.name == vname && t != HL && t == t2 && i.importanceAfter.getRegister(t) == Unimportant =>
|
||||
// LD PP ; LD HL,(qq) ; ADD HL,PP → LD H,P ; LD L,P ; ADD HL,QQ
|
||||
canBeInlined(vname, synced = true, target, xs).map(add(target == t, CyclesAndBytes(16, 3), CyclesAndBytes(8, 1)))
|
||||
|
||||
// case (_, ZLine(LD_16, TwoRegisters(t, _), _, true)) ::
|
||||
// (_, ZLine(LD_16, TwoRegisters(HL, MEM_ABS_16), MemoryAddressConstant(th), true)) ::
|
||||
// (i, ZLine(ADD_16, TwoRegisters(HL, t2), _, _)) ::
|
||||
// case (_, ZLine(LD_16, TwoRegisters(t, _), _, true, _)) ::
|
||||
// (_, ZLine(LD_16, TwoRegisters(HL, MEM_ABS_16), MemoryAddressConstant(th), true, _)) ::
|
||||
// (i, ZLine0(ADD_16, TwoRegisters(HL, t2), _)) ::
|
||||
// xs if th.name == vname && t == target && t != HL && t == t2 && i.importanceAfter.getRegister(t) == Unimportant =>
|
||||
// canBeInlined(vname, synced = true, target, xs).map(add(CyclesAndBytes(16, 3)))
|
||||
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, HL), MemoryAddressConstant(th), true)) ::
|
||||
(_, ZLine(LD_16, TwoRegisters(t, _), _, true)) ::
|
||||
(i, ZLine(ADD_16, TwoRegisters(HL, t2), _, _)) ::
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, HL), MemoryAddressConstant(th), Elidability.Elidable, _)) ::
|
||||
(_, ZLine(LD_16, TwoRegisters(t, _), _, Elidability.Elidable, _)) ::
|
||||
(i, ZLine0(ADD_16, TwoRegisters(HL, t2), _)) ::
|
||||
xs if th.name == vname && t != HL && t == t2 && i.importanceAfter.getRegister(t) == Unimportant =>
|
||||
// LD (vv),HL ; LD QQ,__ ; ADD HL,QQ (vv@QQ)→ LD QQ,HL ; LD HL,__, ADD HL,QQ
|
||||
canBeInlined(vname, synced = true, target, xs).map(add(target == t, CyclesAndBytes(16, 3), CyclesAndBytes(8, 1)))
|
||||
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, HL), MemoryAddressConstant(th), true)) ::
|
||||
(_, ZLine(LD_16, TwoRegisters(t, _), _, true)) ::
|
||||
(i, ZLine(ADD_16, TwoRegisters(HL, t2), _, _)) ::
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, HL), MemoryAddressConstant(th), Elidability.Elidable, _)) ::
|
||||
(_, ZLine(LD_16, TwoRegisters(t, _), _, Elidability.Elidable, _)) ::
|
||||
(i, ZLine0(ADD_16, TwoRegisters(HL, t2), _)) ::
|
||||
xs if t == target && th.name == vname && t != HL && t == t2 && i.importanceAfter.getRegister(t) == Unimportant =>
|
||||
// LD (vv),HL ; LD QQ,__ ; ADD HL,QQ (vv@QQ)→ LD QQ,HL ; LD PP,__, ADD HL,PP
|
||||
canBeInlined(vname, synced = true, target, xs).map(add(CyclesAndBytes(16, 3)))
|
||||
|
||||
case (_, ZLine(LD_16, TwoRegisters(HL, MEM_ABS_16), MemoryAddressConstant(th), true)) :: xs if th.name == vname =>
|
||||
case (_, ZLine(LD_16, TwoRegisters(HL, MEM_ABS_16), MemoryAddressConstant(th), Elidability.Elidable, _)) :: xs if th.name == vname =>
|
||||
canBeInlined(vname, synced = true, target, xs).map(add(target == HL, CyclesAndBytes(16, 3), CyclesAndBytes(8, 1)))
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, HL), MemoryAddressConstant(th), true)) :: xs if th.name == vname =>
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, HL), MemoryAddressConstant(th), Elidability.Elidable, _)) :: xs if th.name == vname =>
|
||||
canBeInlined(vname, synced = true, target, xs).map(add(target == HL, CyclesAndBytes(16, 3), CyclesAndBytes(8, 1)))
|
||||
case (_, ZLine(LD_16, TwoRegisters(DE, MEM_ABS_16), MemoryAddressConstant(th), true)) :: xs if th.name == vname =>
|
||||
case (_, ZLine(LD_16, TwoRegisters(DE, MEM_ABS_16), MemoryAddressConstant(th), Elidability.Elidable, _)) :: xs if th.name == vname =>
|
||||
canBeInlined(vname, synced = true, target, xs).map(add(target == DE, CyclesAndBytes(16, 3), CyclesAndBytes(8, 1)))
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, DE), MemoryAddressConstant(th), true)) :: xs if th.name == vname =>
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, DE), MemoryAddressConstant(th), Elidability.Elidable, _)) :: xs if th.name == vname =>
|
||||
canBeInlined(vname, synced = true, target, xs).map(add(target == DE, CyclesAndBytes(16, 3), CyclesAndBytes(8, 1)))
|
||||
case (_, ZLine(LD_16, TwoRegisters(BC, MEM_ABS_16), MemoryAddressConstant(th), true)) :: xs if th.name == vname =>
|
||||
case (_, ZLine(LD_16, TwoRegisters(BC, MEM_ABS_16), MemoryAddressConstant(th), Elidability.Elidable, _)) :: xs if th.name == vname =>
|
||||
canBeInlined(vname, synced = true, target, xs).map(add(target == BC, CyclesAndBytes(16, 3), CyclesAndBytes(8, 1)))
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, BC), MemoryAddressConstant(th), true)) :: xs if th.name == vname =>
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, BC), MemoryAddressConstant(th), Elidability.Elidable, _)) :: xs if th.name == vname =>
|
||||
canBeInlined(vname, synced = true, target, xs).map(add(target == BC, CyclesAndBytes(16, 3), CyclesAndBytes(8, 1)))
|
||||
|
||||
case (_, x) :: (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, t), MemoryAddressConstant(th), true)) :: xs
|
||||
case (_, x) :: (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, t), MemoryAddressConstant(th), Elidability.Elidable, _)) :: xs
|
||||
if th.name == vname && t == target && x.changesRegister(t) =>
|
||||
canBeInlined(vname, synced = true, target, xs).map(add(CyclesAndBytes(16, 3)))
|
||||
|
||||
|
||||
case (_, ZLine(LD, TwoRegisters(A, MEM_ABS_8), MemoryAddressConstant(th), true)) :: xs if th.name == vname =>
|
||||
case (_, ZLine(LD, TwoRegisters(A, MEM_ABS_8), MemoryAddressConstant(th), Elidability.Elidable, _)) :: xs if th.name == vname =>
|
||||
canBeInlined(vname, synced, target, xs).map(add(CyclesAndBytes(9, 2)))
|
||||
case (_, ZLine(LD, TwoRegisters(MEM_ABS_8, A), MemoryAddressConstant(th), true)) :: xs if th.name == vname =>
|
||||
case (_, ZLine(LD, TwoRegisters(MEM_ABS_8, A), MemoryAddressConstant(th), Elidability.Elidable, _)) :: xs if th.name == vname =>
|
||||
canBeInlined(vname, synced, target, xs).map(add(CyclesAndBytes(9, 2)))
|
||||
|
||||
case (_, ZLine(LD, TwoRegisters(A, MEM_ABS_8), CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(1,_)), true)) :: xs if th.name == vname =>
|
||||
case (_, ZLine(LD, TwoRegisters(A, MEM_ABS_8), CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(1, _)), Elidability.Elidable, _)) :: xs if th.name == vname =>
|
||||
canBeInlined(vname, synced, target, xs).map(add(CyclesAndBytes(9, 2)))
|
||||
case (_, ZLine(LD, TwoRegisters(MEM_ABS_8, A), CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(1, _)), true)) :: xs if th.name == vname =>
|
||||
case (_, ZLine(LD, TwoRegisters(MEM_ABS_8, A), CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(1, _)), Elidability.Elidable, _)) :: xs if th.name == vname =>
|
||||
canBeInlined(vname, synced, target, xs).map(add(CyclesAndBytes(9, 2)))
|
||||
|
||||
case (_, ZLine(_, _, MemoryAddressConstant(th), _)) :: _ if th.name == vname => fail(4)
|
||||
case (_, ZLine(_, _, CompoundConstant(_, MemoryAddressConstant(th), _), _)) :: _ if th.name == vname => fail(5)
|
||||
case (_, ZLine(_, _, SubbyteConstant(MemoryAddressConstant(th), _), _)) :: _ if th.name == vname => fail(6)
|
||||
case (_, ZLine(CALL, _, _, _)) :: xs => target match {
|
||||
case (_, ZLine0(_, _, MemoryAddressConstant(th))) :: _ if th.name == vname => fail(4)
|
||||
case (_, ZLine0(_, _, CompoundConstant(_, MemoryAddressConstant(th), _))) :: _ if th.name == vname => fail(5)
|
||||
case (_, ZLine0(_, _, SubbyteConstant(MemoryAddressConstant(th), _))) :: _ if th.name == vname => fail(6)
|
||||
case (_, ZLine0(CALL, _, _)) :: xs => target match {
|
||||
// TODO: check return type and allow HL sometimes
|
||||
case BC | DE =>
|
||||
canBeInlined(vname, synced, target, xs).map(add(CyclesAndBytes(-21, -2)))
|
||||
@ -286,8 +286,8 @@ object WordVariableToRegisterOptimization extends AssemblyOptimization[ZLine] {
|
||||
}
|
||||
case (_, x) :: xs if x.changesRegister(target) => fail(1)
|
||||
case (_, x) :: xs if x.readsRegister(target) && !synced => fail(2)
|
||||
case (_, ZLine(LABEL, _, _, _)) :: xs => canBeInlined(vname, synced = false, target, xs)
|
||||
case (_, ZLine(CALL, _, _, _)) :: xs => fail(3)
|
||||
case (_, ZLine0(LABEL, _, _)) :: xs => canBeInlined(vname, synced = false, target, xs)
|
||||
case (_, ZLine0(CALL, _, _)) :: xs => fail(3)
|
||||
case _ :: xs => canBeInlined(vname, synced, target, xs)
|
||||
case _ => Some(CyclesAndBytes.Zero)
|
||||
}
|
||||
@ -297,31 +297,31 @@ object WordVariableToRegisterOptimization extends AssemblyOptimization[ZLine] {
|
||||
// if (code.nonEmpty) println(code.head)
|
||||
code match {
|
||||
|
||||
case (_, load@ZLine(LD_16, TwoRegisters(BC, IMM_16), _, _)) ::
|
||||
(f, add@ZLine(ADD_16, TwoRegisters(HL, BC), _, _)) ::
|
||||
case (_, load@ZLine(LD_16, TwoRegisters(BC, IMM_16), _, _, s1)) ::
|
||||
(f, add@ZLine(ADD_16, TwoRegisters(HL, BC), _, _, s2)) ::
|
||||
xs if bc != "" =>
|
||||
if (f.importanceAfter.getRegister(DE) == Important) {
|
||||
ZLine.register(PUSH, BC) :: load :: add :: ZLine.register(POP, BC) :: inlineVars(hl, bc, de, xs)
|
||||
ZLine.register(PUSH, BC).pos(s1) :: load :: add :: ZLine.register(POP, BC).pos(s2) :: inlineVars(hl, bc, de, xs)
|
||||
} else {
|
||||
load.copy(registers = TwoRegisters(DE, IMM_16)) ::
|
||||
ZLine.registers(ADD_16, HL, DE) ::
|
||||
ZLine.registers(ADD_16, HL, DE).pos(s2) ::
|
||||
inlineVars(hl, bc, de, xs)
|
||||
}
|
||||
|
||||
case (_, load@ZLine(LD_16, TwoRegisters(DE, IMM_16), _, _)) ::
|
||||
(f, add@ZLine(ADD_16, TwoRegisters(HL, DE), _, _)) ::
|
||||
case (_, load@ZLine(LD_16, TwoRegisters(DE, IMM_16), _, _, s1)) ::
|
||||
(f, add@ZLine(ADD_16, TwoRegisters(HL, DE), _, _, s2)) ::
|
||||
xs if de != "" =>
|
||||
if (f.importanceAfter.getRegister(BC) == Important) {
|
||||
ZLine.register(PUSH, DE) :: load :: add :: ZLine.register(POP, DE) :: inlineVars(hl, bc, de, xs)
|
||||
ZLine.register(PUSH, DE).pos(s1) :: load :: add :: ZLine.register(POP, DE).pos(s2) :: inlineVars(hl, bc, de, xs)
|
||||
} else {
|
||||
load.copy(registers = TwoRegisters(BC, IMM_16)) ::
|
||||
ZLine.registers(ADD_16, HL, BC) ::
|
||||
ZLine.registers(ADD_16, HL, BC).pos(s2) ::
|
||||
inlineVars(hl, bc, de, xs)
|
||||
}
|
||||
|
||||
case (_, ZLine(LD_16, TwoRegisters(HL, MEM_ABS_16), a1@MemoryAddressConstant(th1), _)) ::
|
||||
(_, ZLine(ADD_16, TwoRegisters(HL, reg@(DE | BC)), _, _)) ::
|
||||
(_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, HL), a2@MemoryAddressConstant(th2), _)) ::
|
||||
case (_, ZLine(LD_16, TwoRegisters(HL, MEM_ABS_16), a1@MemoryAddressConstant(th1), _, s1)) ::
|
||||
(_, ZLine(ADD_16, TwoRegisters(HL, reg@(DE | BC)), _, _, s2)) ::
|
||||
(_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, HL), a2@MemoryAddressConstant(th2), _, s3)) ::
|
||||
xs if hl != "" && th1.name != hl && th2.name != hl=>
|
||||
// bytes before: 3 + 1 + 3 = 7
|
||||
// cycles before: 16 + 11 + 16 = 43
|
||||
@ -331,127 +331,127 @@ object WordVariableToRegisterOptimization extends AssemblyOptimization[ZLine] {
|
||||
case BC => (B,C)
|
||||
case DE => (D, E)
|
||||
}
|
||||
ZLine.ldAbs8(A, a1) ::
|
||||
ZLine.register(ADD, l) ::
|
||||
ZLine.ldAbs8(a2, A) ::
|
||||
ZLine.ldAbs8(A, a1 + 1) ::
|
||||
ZLine.register(ADC, h) ::
|
||||
ZLine.ldAbs8(a2 + 1, A) ::
|
||||
ZLine.ldAbs8(A, a1).pos(s1) ::
|
||||
ZLine.register(ADD, l).pos(s2) ::
|
||||
ZLine.ldAbs8(a2, A).pos(s3) ::
|
||||
ZLine.ldAbs8(A, a1 + 1).pos(s1) ::
|
||||
ZLine.register(ADC, h).pos(s2) ::
|
||||
ZLine.ldAbs8(a2 + 1, A).pos(s3) ::
|
||||
inlineVars(hl, bc, de, xs)
|
||||
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, HL), MemoryAddressConstant(th), _)) ::
|
||||
(_, loadConst@ZLine(LD_16, TwoRegisters(BC, constSource), _, _)) ::
|
||||
(_, add@ZLine(ADD_16, TwoRegisters(HL, BC), _, _)) :: xs if th.name == bc =>
|
||||
ZLine.ld8(B, H) :: ZLine.ld8(C, L) ::
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, HL), MemoryAddressConstant(th), _, s1)) ::
|
||||
(_, loadConst@ZLine(LD_16, TwoRegisters(BC, constSource), _, _, s2)) ::
|
||||
(_, add@ZLine(ADD_16, TwoRegisters(HL, BC), _, _, s3)) :: xs if th.name == bc =>
|
||||
ZLine.ld8(B, H).pos(s1) :: ZLine.ld8(C, L).pos(s1) ::
|
||||
loadConst.copy(registers = TwoRegisters(HL, constSource)) ::
|
||||
add.copy(registers = TwoRegisters(HL, BC)) :: inlineVars(hl, bc, de, xs)
|
||||
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, HL), MemoryAddressConstant(th), _)) ::
|
||||
(_, loadConst@ZLine(LD_16, TwoRegisters(DE, constSource), _, _)) ::
|
||||
(_, add@ZLine(ADD_16, TwoRegisters(HL, DE), _, _)) :: xs if th.name == de =>
|
||||
ZLine.ld8(D, H) :: ZLine.ld8(E, L) ::
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, HL), MemoryAddressConstant(th), _, s1)) ::
|
||||
(_, loadConst@ZLine0(LD_16, TwoRegisters(DE, constSource), _)) ::
|
||||
(_, add@ZLine0(ADD_16, TwoRegisters(HL, DE), _)) :: xs if th.name == de =>
|
||||
ZLine.ld8(D, H).pos(s1) :: ZLine.ld8(E, L).pos(s1) ::
|
||||
loadConst.copy(registers = TwoRegisters(HL, constSource)) ::
|
||||
add.copy(registers = TwoRegisters(HL, DE)) :: inlineVars(hl, bc, de, xs)
|
||||
// TODO: above with regs swapped
|
||||
|
||||
case (_, loadConst@ZLine(LD_16, TwoRegisters(t, constSource), _, _)) ::
|
||||
(_, ZLine(LD_16, TwoRegisters(HL, MEM_ABS_16), MemoryAddressConstant(th), _)) ::
|
||||
(_, add@ZLine(ADD_16, TwoRegisters(HL, t2), _, _)) :: xs if th.name == bc && t == t2 && t != HL =>
|
||||
case (_, loadConst@ZLine0(LD_16, TwoRegisters(t, constSource), _)) ::
|
||||
(_, ZLine0(LD_16, TwoRegisters(HL, MEM_ABS_16), MemoryAddressConstant(th))) ::
|
||||
(_, add@ZLine0(ADD_16, TwoRegisters(HL, t2), _)) :: xs if th.name == bc && t == t2 && t != HL =>
|
||||
loadConst.copy(registers = TwoRegisters(HL, constSource)) ::
|
||||
add.copy(registers = TwoRegisters(HL, BC)) :: inlineVars(hl, bc, de, xs)
|
||||
|
||||
case (_, loadConst@ZLine(LD_16, TwoRegisters(t, constSource),_,_)) ::
|
||||
(_, ZLine(LD_16, TwoRegisters(HL, MEM_ABS_16), MemoryAddressConstant(th), _)) ::
|
||||
(_, add@ZLine(ADD_16, TwoRegisters(HL, t2), _, _)) :: xs if th.name == de && t == t2 && t != HL =>
|
||||
case (_, loadConst@ZLine0(LD_16, TwoRegisters(t, constSource),_)) ::
|
||||
(_, ZLine0(LD_16, TwoRegisters(HL, MEM_ABS_16), MemoryAddressConstant(th))) ::
|
||||
(_, add@ZLine0(ADD_16, TwoRegisters(HL, t2), _)) :: xs if th.name == de && t == t2 && t != HL =>
|
||||
loadConst.copy(registers = TwoRegisters(HL, constSource)) ::
|
||||
add.copy(registers = TwoRegisters(HL, DE)) :: inlineVars(hl, bc, de, xs)
|
||||
|
||||
case (_, ZLine(LD_16, TwoRegisters(HL, MEM_ABS_16), MemoryAddressConstant(th), _) ) :: xs if th.name == hl =>
|
||||
case (_, ZLine(LD_16, TwoRegisters(HL, MEM_ABS_16), MemoryAddressConstant(th), _, s)) :: xs if th.name == hl =>
|
||||
inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, HL), MemoryAddressConstant(th), _) ) :: xs if th.name == hl =>
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, HL), MemoryAddressConstant(th), _, s)) :: xs if th.name == hl =>
|
||||
inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD_16, TwoRegisters(HL, MEM_ABS_16), MemoryAddressConstant(th), _) ) :: xs if th.name == bc =>
|
||||
ZLine.ld8(H, B) :: ZLine.ld8(L, C) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, HL), MemoryAddressConstant(th), _) ) :: xs if th.name == bc =>
|
||||
ZLine.ld8(B, H) :: ZLine.ld8(C, L) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD_16, TwoRegisters(HL, MEM_ABS_16), MemoryAddressConstant(th), _) ) :: xs if th.name == de =>
|
||||
ZLine.ld8(H, D) :: ZLine.ld8(L, E) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, HL), MemoryAddressConstant(th), _) ) :: xs if th.name == de =>
|
||||
ZLine.ld8(D, H) :: ZLine.ld8(E, L) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD_16, TwoRegisters(HL, MEM_ABS_16), MemoryAddressConstant(th), _, s)) :: xs if th.name == bc =>
|
||||
ZLine.ld8(H, B).pos(s) :: ZLine.ld8(L, C).pos(s) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, HL), MemoryAddressConstant(th), _, s)) :: xs if th.name == bc =>
|
||||
ZLine.ld8(B, H).pos(s) :: ZLine.ld8(C, L).pos(s) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD_16, TwoRegisters(HL, MEM_ABS_16), MemoryAddressConstant(th), _, s)) :: xs if th.name == de =>
|
||||
ZLine.ld8(H, D).pos(s) :: ZLine.ld8(L, E).pos(s) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, HL), MemoryAddressConstant(th), _, s)) :: xs if th.name == de =>
|
||||
ZLine.ld8(D, H).pos(s) :: ZLine.ld8(E, L).pos(s) :: inlineVars(hl, bc, de, xs)
|
||||
|
||||
case (_, ZLine(LD_16, TwoRegisters(DE, MEM_ABS_16), MemoryAddressConstant(th), _) ) :: xs if th.name == de =>
|
||||
case (_, ZLine(LD_16, TwoRegisters(DE, MEM_ABS_16), MemoryAddressConstant(th), _, s)) :: xs if th.name == de =>
|
||||
inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, DE), MemoryAddressConstant(th), _) ) :: xs if th.name == de =>
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, DE), MemoryAddressConstant(th), _, s)) :: xs if th.name == de =>
|
||||
inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD_16, TwoRegisters(DE, MEM_ABS_16), MemoryAddressConstant(th), _) ) :: xs if th.name == bc =>
|
||||
ZLine.ld8(D, B) :: ZLine.ld8(E, C) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, DE), MemoryAddressConstant(th), _) ) :: xs if th.name == bc =>
|
||||
ZLine.ld8(B, D) :: ZLine.ld8(C, E) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD_16, TwoRegisters(DE, MEM_ABS_16), MemoryAddressConstant(th), _) ) :: xs if th.name == hl =>
|
||||
ZLine.ld8(D, H) :: ZLine.ld8(E, L) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, DE), MemoryAddressConstant(th), _) ) :: xs if th.name == hl =>
|
||||
ZLine.ld8(H, D) :: ZLine.ld8(L, E) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD_16, TwoRegisters(DE, MEM_ABS_16), MemoryAddressConstant(th), _, s)) :: xs if th.name == bc =>
|
||||
ZLine.ld8(D, B).pos(s) :: ZLine.ld8(E, C).pos(s) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, DE), MemoryAddressConstant(th), _, s)) :: xs if th.name == bc =>
|
||||
ZLine.ld8(B, D).pos(s) :: ZLine.ld8(C, E).pos(s) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD_16, TwoRegisters(DE, MEM_ABS_16), MemoryAddressConstant(th), _, s)) :: xs if th.name == hl =>
|
||||
ZLine.ld8(D, H).pos(s) :: ZLine.ld8(E, L).pos(s) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, DE), MemoryAddressConstant(th), _, s)) :: xs if th.name == hl =>
|
||||
ZLine.ld8(H, D).pos(s) :: ZLine.ld8(L, E).pos(s) :: inlineVars(hl, bc, de, xs)
|
||||
|
||||
case (_, ZLine(LD_16, TwoRegisters(BC, MEM_ABS_16), MemoryAddressConstant(th), _) ) :: xs if th.name == bc =>
|
||||
case (_, ZLine(LD_16, TwoRegisters(BC, MEM_ABS_16), MemoryAddressConstant(th), _, s)) :: xs if th.name == bc =>
|
||||
inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, BC), MemoryAddressConstant(th), _) ) :: xs if th.name == bc =>
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, BC), MemoryAddressConstant(th), _, s)) :: xs if th.name == bc =>
|
||||
inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD_16, TwoRegisters(BC, MEM_ABS_16), MemoryAddressConstant(th), _) ) :: xs if th.name == hl =>
|
||||
ZLine.ld8(B, H) :: ZLine.ld8(C, L) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, BC), MemoryAddressConstant(th), _) ) :: xs if th.name == hl =>
|
||||
ZLine.ld8(H, B) :: ZLine.ld8(L, C) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD_16, TwoRegisters(BC, MEM_ABS_16), MemoryAddressConstant(th), _) ) :: xs if th.name == de =>
|
||||
ZLine.ld8(B, D) :: ZLine.ld8(C, E) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, BC), MemoryAddressConstant(th), _) ) :: xs if th.name == de =>
|
||||
ZLine.ld8(D, B) :: ZLine.ld8(E, C) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD_16, TwoRegisters(BC, MEM_ABS_16), MemoryAddressConstant(th), _, s)) :: xs if th.name == hl =>
|
||||
ZLine.ld8(B, H).pos(s) :: ZLine.ld8(C, L).pos(s) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, BC), MemoryAddressConstant(th), _, s)) :: xs if th.name == hl =>
|
||||
ZLine.ld8(H, B).pos(s) :: ZLine.ld8(L, C).pos(s) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD_16, TwoRegisters(BC, MEM_ABS_16), MemoryAddressConstant(th), _, s)) :: xs if th.name == de =>
|
||||
ZLine.ld8(B, D).pos(s) :: ZLine.ld8(C, E).pos(s) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, BC), MemoryAddressConstant(th), _, s)) :: xs if th.name == de =>
|
||||
ZLine.ld8(D, B).pos(s) :: ZLine.ld8(E, C).pos(s) :: inlineVars(hl, bc, de, xs)
|
||||
|
||||
case (_, ZLine(LD, TwoRegisters(A, MEM_ABS_8), MemoryAddressConstant(th), _) ) :: xs if th.name == hl =>
|
||||
ZLine.ld8(A, L) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD, TwoRegisters(MEM_ABS_8, A), MemoryAddressConstant(th), _) ) :: xs if th.name == hl =>
|
||||
ZLine.ld8(L, A) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD, TwoRegisters(A, MEM_ABS_8), MemoryAddressConstant(th), _) ) :: xs if th.name == bc =>
|
||||
ZLine.ld8(A, C) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD, TwoRegisters(MEM_ABS_8, A), MemoryAddressConstant(th), _) ) :: xs if th.name == bc =>
|
||||
ZLine.ld8(C, A) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD, TwoRegisters(A, MEM_ABS_8), MemoryAddressConstant(th), _) ) :: xs if th.name == de =>
|
||||
ZLine.ld8(A, E) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD, TwoRegisters(MEM_ABS_8, A), MemoryAddressConstant(th), _) ) :: xs if th.name == de =>
|
||||
ZLine.ld8(E, A) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD, TwoRegisters(A, MEM_ABS_8), MemoryAddressConstant(th), _, s)) :: xs if th.name == hl =>
|
||||
ZLine.ld8(A, L).pos(s) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD, TwoRegisters(MEM_ABS_8, A), MemoryAddressConstant(th), _, s)) :: xs if th.name == hl =>
|
||||
ZLine.ld8(L, A).pos(s) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD, TwoRegisters(A, MEM_ABS_8), MemoryAddressConstant(th), _, s)) :: xs if th.name == bc =>
|
||||
ZLine.ld8(A, C).pos(s) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD, TwoRegisters(MEM_ABS_8, A), MemoryAddressConstant(th), _, s)) :: xs if th.name == bc =>
|
||||
ZLine.ld8(C, A).pos(s) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD, TwoRegisters(A, MEM_ABS_8), MemoryAddressConstant(th), _, s)) :: xs if th.name == de =>
|
||||
ZLine.ld8(A, E).pos(s) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD, TwoRegisters(MEM_ABS_8, A), MemoryAddressConstant(th), _, s)) :: xs if th.name == de =>
|
||||
ZLine.ld8(E, A).pos(s) :: inlineVars(hl, bc, de, xs)
|
||||
|
||||
case (_, ZLine(LD, TwoRegisters(A, MEM_ABS_8), CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(1, _)), _) ) :: xs if th.name == hl =>
|
||||
ZLine.ld8(A, H) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD, TwoRegisters(MEM_ABS_8, A), CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(1, _)), _) ) :: xs if th.name == hl =>
|
||||
ZLine.ld8(H, A) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD, TwoRegisters(A, MEM_ABS_8), CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(1, _)), _) ) :: xs if th.name == bc =>
|
||||
ZLine.ld8(A, B) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD, TwoRegisters(MEM_ABS_8, A), CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(1, _)), _) ) :: xs if th.name == bc =>
|
||||
ZLine.ld8(B, A) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD, TwoRegisters(A, MEM_ABS_8), CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(1, _)), _) ) :: xs if th.name == de =>
|
||||
ZLine.ld8(A, D) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD, TwoRegisters(MEM_ABS_8, A), CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(1, _)), _) ) :: xs if th.name == de =>
|
||||
ZLine.ld8(D, A) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD, TwoRegisters(A, MEM_ABS_8), CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(1, _)), _, s)) :: xs if th.name == hl =>
|
||||
ZLine.ld8(A, H).pos(s) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD, TwoRegisters(MEM_ABS_8, A), CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(1, _)), _, s)) :: xs if th.name == hl =>
|
||||
ZLine.ld8(H, A).pos(s) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD, TwoRegisters(A, MEM_ABS_8), CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(1, _)), _, s)) :: xs if th.name == bc =>
|
||||
ZLine.ld8(A, B).pos(s) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD, TwoRegisters(MEM_ABS_8, A), CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(1, _)), _, s)) :: xs if th.name == bc =>
|
||||
ZLine.ld8(B, A).pos(s) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD, TwoRegisters(A, MEM_ABS_8), CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(1, _)), _, s)) :: xs if th.name == de =>
|
||||
ZLine.ld8(A, D).pos(s) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, ZLine(LD, TwoRegisters(MEM_ABS_8, A), CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(1, _)), _, s)) :: xs if th.name == de =>
|
||||
ZLine.ld8(D, A).pos(s) :: inlineVars(hl, bc, de, xs)
|
||||
|
||||
case (_, l1@ZLine(LD_16, TwoRegisters(BC, IMM_16), _, _)) :: (_, l2@ZLine(ADD_16, TwoRegisters(HL, BC), _, _)) :: xs if bc != "" =>
|
||||
ZLine.register(PUSH, BC) :: l1 :: l2 :: ZLine.register(POP, BC) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, l1@ZLine(LD_16, TwoRegisters(BC, IMM_16), _, _, s1)) :: (_, l2@ZLine(ADD_16, TwoRegisters(HL, BC), _, _, s2)) :: xs if bc != "" =>
|
||||
ZLine.register(PUSH, BC).pos(s1) :: l1 :: l2 :: ZLine.register(POP, BC).pos(s2) :: inlineVars(hl, bc, de, xs)
|
||||
|
||||
case (_, l1@ZLine(LD_16, TwoRegisters(DE, IMM_16), _, _)) :: (_, l2@ZLine(ADD_16, TwoRegisters(HL, DE), _, _)) :: xs if de != "" =>
|
||||
ZLine.register(PUSH, DE) :: l1 :: l2 :: ZLine.register(POP, DE) :: inlineVars(hl, bc, de, xs)
|
||||
case (_, l1@ZLine(LD_16, TwoRegisters(DE, IMM_16), _, _, s1)) :: (_, l2@ZLine(ADD_16, TwoRegisters(HL, DE), _, _, s2)) :: xs if de != "" =>
|
||||
ZLine.register(PUSH, DE).pos(s1) :: l1 :: l2 :: ZLine.register(POP, DE).pos(s2) :: inlineVars(hl, bc, de, xs)
|
||||
|
||||
case (_, x@ZLine(CALL, _, _, _)) :: xs =>
|
||||
case (_, x@ZLine(CALL, _, _, _, s)) :: xs =>
|
||||
if (bc != "") {
|
||||
ZLine.register(PUSH, BC) :: x :: ZLine.register(POP, BC) :: inlineVars(hl, bc, de, xs)
|
||||
ZLine.register(PUSH, BC).pos(s) :: x :: ZLine.register(POP, BC).pos(s) :: inlineVars(hl, bc, de, xs)
|
||||
} else if (de != "") {
|
||||
ZLine.register(PUSH, DE) :: x :: ZLine.register(POP, DE) :: inlineVars(hl, bc, de, xs)
|
||||
ZLine.register(PUSH, DE).pos(s) :: x :: ZLine.register(POP, DE).pos(s) :: inlineVars(hl, bc, de, xs)
|
||||
} else {
|
||||
throw new IllegalStateException()
|
||||
}
|
||||
|
||||
|
||||
case x :: (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, HL), MemoryAddressConstant(th), _)) :: xs if x._2.changesRegister(HL) && th.name == hl =>
|
||||
case x :: (_, ZLine0(LD_16, TwoRegisters(MEM_ABS_16, HL), MemoryAddressConstant(th))) :: xs if x._2.changesRegister(HL) && th.name == hl =>
|
||||
x._2 :: inlineVars(hl, bc, de, xs)
|
||||
case x :: (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, BC), MemoryAddressConstant(th), _)) :: xs if x._2.changesRegister(BC) && th.name == bc =>
|
||||
case x :: (_, ZLine0(LD_16, TwoRegisters(MEM_ABS_16, BC), MemoryAddressConstant(th))) :: xs if x._2.changesRegister(BC) && th.name == bc =>
|
||||
x._2 :: inlineVars(hl, bc, de, xs)
|
||||
case x :: (_, ZLine(LD_16, TwoRegisters(MEM_ABS_16, DE), MemoryAddressConstant(th), _)) :: xs if x._2.changesRegister(DE) && th.name == de =>
|
||||
case x :: (_, ZLine0(LD_16, TwoRegisters(MEM_ABS_16, DE), MemoryAddressConstant(th))) :: xs if x._2.changesRegister(DE) && th.name == de =>
|
||||
x._2 :: inlineVars(hl, bc, de, xs)
|
||||
|
||||
case x :: _ if bc != "" && x._2.changesRegister(BC) => throw new IllegalStateException()
|
||||
|
@ -1,6 +1,7 @@
|
||||
package millfork.compiler.mos
|
||||
|
||||
import millfork.CompilationFlag
|
||||
import millfork.assembly.Elidability
|
||||
import millfork.assembly.mos.AddrMode._
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.mos._
|
||||
@ -314,7 +315,7 @@ object BuiltIns {
|
||||
case Some(NumericConstant(shift, _)) if shift > 0 =>
|
||||
if (ctx.options.flags(CompilationFlag.EmitNative65816Opcodes)) {
|
||||
targetBytes match {
|
||||
case List(List(AssemblyLine(STA, a1, l, _)), List(AssemblyLine(STA, a2, h, _))) =>
|
||||
case List(List(AssemblyLine0(STA, a1, l)), List(AssemblyLine0(STA, a2, h))) =>
|
||||
if (a1 == a2 && l.+(1).quickSimplify == h) {
|
||||
return List(AssemblyLine.accu16) ++ List.fill(shift.toInt)(AssemblyLine(if (aslRatherThanLsr) ASL_W else LSR_W, a1, l)) ++ List(AssemblyLine.accu8)
|
||||
}
|
||||
@ -345,7 +346,7 @@ object BuiltIns {
|
||||
|
||||
if (ctx.options.flags(CompilationFlag.EmitNative65816Opcodes)) {
|
||||
targetBytes match {
|
||||
case List(List(AssemblyLine(STA, a1, l, _)), List(AssemblyLine(STA, a2, h, _))) =>
|
||||
case List(List(AssemblyLine0(STA, a1, l)), List(AssemblyLine0(STA, a2, h))) =>
|
||||
if (a1 == a2 && l.+(1).quickSimplify == h) {
|
||||
return compileCounter ++ List(
|
||||
AssemblyLine.relative(BEQ, labelSkip),
|
||||
@ -428,7 +429,7 @@ object BuiltIns {
|
||||
case ComparisonType.Equal | ComparisonType.NotEqual | ComparisonType.LessSigned | ComparisonType.GreaterOrEqualSigned =>
|
||||
val secondParamCompiledUnoptimized = simpleOperation(cmpOp, ctx, rhs, IndexChoice.PreferY, preserveA = true, commutative = false)
|
||||
secondParamCompiledUnoptimized match {
|
||||
case List(AssemblyLine(cmpOp, Immediate, NumericConstant(0, _), true)) =>
|
||||
case List(AssemblyLine(cmpOp, Immediate, NumericConstant(0, _), Elidability.Elidable, _)) =>
|
||||
if (OpcodeClasses.ChangesAAlways(firstParamCompiled.last.opcode)) {
|
||||
Nil
|
||||
} else {
|
||||
@ -941,8 +942,8 @@ object BuiltIns {
|
||||
var addendSize = addendType.size
|
||||
|
||||
def isRhsComplex(xs: List[AssemblyLine]): Boolean = xs match {
|
||||
case AssemblyLine(LDA, _, _, _) :: Nil => false
|
||||
case AssemblyLine(LDA, _, _, _) :: AssemblyLine(LDX, _, _, _) :: Nil => false
|
||||
case AssemblyLine0(LDA, _, _) :: Nil => false
|
||||
case AssemblyLine0(LDA, _, _) :: AssemblyLine0(LDX, _, _) :: Nil => false
|
||||
case _ => true
|
||||
}
|
||||
|
||||
@ -974,7 +975,7 @@ object BuiltIns {
|
||||
case Some(NumericConstant(1, _)) if canUseIncDec && !subtract =>
|
||||
if (ctx.options.flags(CompilationFlag.Emit65CE02Opcodes)) {
|
||||
targetBytes match {
|
||||
case List(List(AssemblyLine(STA, ZeroPage, l, _)), List(AssemblyLine(STA, ZeroPage, h, _))) =>
|
||||
case List(List(AssemblyLine0(STA, ZeroPage, l)), List(AssemblyLine0(STA, ZeroPage, h))) =>
|
||||
if (l.+(1).quickSimplify == h) {
|
||||
return List(AssemblyLine.zeropage(INC_W, l))
|
||||
}
|
||||
@ -983,7 +984,7 @@ object BuiltIns {
|
||||
}
|
||||
if (ctx.options.flags(CompilationFlag.EmitNative65816Opcodes)) {
|
||||
targetBytes match {
|
||||
case List(List(AssemblyLine(STA, a1@(ZeroPage | Absolute | ZeroPageX | AbsoluteX), l, _)), List(AssemblyLine(STA, a2, h, _))) =>
|
||||
case List(List(AssemblyLine0(STA, a1@(ZeroPage | Absolute | ZeroPageX | AbsoluteX), l)), List(AssemblyLine0(STA, a2, h))) =>
|
||||
if (a1 == a2 && l.+(1).quickSimplify == h) {
|
||||
return List(AssemblyLine.accu16, AssemblyLine(INC_W, a1, l), AssemblyLine.accu8)
|
||||
}
|
||||
@ -994,7 +995,7 @@ object BuiltIns {
|
||||
case Some(NumericConstant(-1, _)) if canUseIncDec && subtract =>
|
||||
if (ctx.options.flags(CompilationFlag.Emit65CE02Opcodes)) {
|
||||
targetBytes match {
|
||||
case List(List(AssemblyLine(STA, ZeroPage, l, _)), List(AssemblyLine(STA, ZeroPage, h, _))) =>
|
||||
case List(List(AssemblyLine0(STA, ZeroPage, l)), List(AssemblyLine0(STA, ZeroPage, h))) =>
|
||||
if (l.+(1).quickSimplify == h) {
|
||||
return List(AssemblyLine.zeropage(INC_W, l))
|
||||
}
|
||||
@ -1002,7 +1003,7 @@ object BuiltIns {
|
||||
}
|
||||
if (ctx.options.flags(CompilationFlag.EmitNative65816Opcodes)) {
|
||||
targetBytes match {
|
||||
case List(List(AssemblyLine(STA, a1@(ZeroPage | Absolute | ZeroPageX | AbsoluteX), l, _)), List(AssemblyLine(STA, a2, h, _))) =>
|
||||
case List(List(AssemblyLine0(STA, a1@(ZeroPage | Absolute | ZeroPageX | AbsoluteX), l)), List(AssemblyLine0(STA, a2, h))) =>
|
||||
if (a1 == a2 && l.+(1).quickSimplify == h) {
|
||||
return List(AssemblyLine.accu16, AssemblyLine(INC_W, a1, l), AssemblyLine.accu8)
|
||||
}
|
||||
@ -1013,7 +1014,7 @@ object BuiltIns {
|
||||
case Some(NumericConstant(1, _)) if canUseIncDec && subtract =>
|
||||
if (ctx.options.flags(CompilationFlag.Emit65CE02Opcodes)) {
|
||||
targetBytes match {
|
||||
case List(List(AssemblyLine(STA, ZeroPage, l, _)), List(AssemblyLine(STA, ZeroPage, h, _))) =>
|
||||
case List(List(AssemblyLine0(STA, ZeroPage, l)), List(AssemblyLine0(STA, ZeroPage, h))) =>
|
||||
if (l.+(1).quickSimplify == h) {
|
||||
return List(AssemblyLine.zeropage(DEC_W, l))
|
||||
}
|
||||
@ -1021,7 +1022,7 @@ object BuiltIns {
|
||||
}
|
||||
if (ctx.options.flags(CompilationFlag.EmitNative65816Opcodes)) {
|
||||
targetBytes match {
|
||||
case List(List(AssemblyLine(STA, a1@(ZeroPage | Absolute | ZeroPageX | AbsoluteX), l, _)), List(AssemblyLine(STA, a2, h, _))) =>
|
||||
case List(List(AssemblyLine0(STA, a1@(ZeroPage | Absolute | ZeroPageX | AbsoluteX), l)), List(AssemblyLine0(STA, a2, h))) =>
|
||||
if (a1 == a2 && l.+(1).quickSimplify == h) {
|
||||
return List(AssemblyLine.accu16, AssemblyLine(DEC_W, a1, l), AssemblyLine.accu8)
|
||||
}
|
||||
@ -1032,7 +1033,7 @@ object BuiltIns {
|
||||
case Some(NumericConstant(-1, _)) if canUseIncDec && !subtract =>
|
||||
if (ctx.options.flags(CompilationFlag.Emit65CE02Opcodes)) {
|
||||
targetBytes match {
|
||||
case List(List(AssemblyLine(STA, ZeroPage, l, _)), List(AssemblyLine(STA, ZeroPage, h, _))) =>
|
||||
case List(List(AssemblyLine0(STA, ZeroPage, l)), List(AssemblyLine0(STA, ZeroPage, h))) =>
|
||||
if (l.+(1).quickSimplify == h) {
|
||||
return List(AssemblyLine.zeropage(DEC_W, l))
|
||||
}
|
||||
@ -1040,7 +1041,7 @@ object BuiltIns {
|
||||
}
|
||||
if (ctx.options.flags(CompilationFlag.EmitNative65816Opcodes)) {
|
||||
targetBytes match {
|
||||
case List(List(AssemblyLine(STA, a1@(ZeroPage | Absolute | ZeroPageX | AbsoluteX), l, _)), List(AssemblyLine(STA, a2, h, _))) =>
|
||||
case List(List(AssemblyLine0(STA, a1@(ZeroPage | Absolute | ZeroPageX | AbsoluteX), l)), List(AssemblyLine0(STA, a2, h))) =>
|
||||
if (a1 == a2 && l.+(1).quickSimplify == h) {
|
||||
return List(AssemblyLine.accu16, AssemblyLine(DEC_W, a1, l), AssemblyLine.accu8)
|
||||
}
|
||||
@ -1121,9 +1122,9 @@ object BuiltIns {
|
||||
if (ctx.options.flags(CompilationFlag.EmitNative65816Opcodes)) {
|
||||
(removeTsx(targetBytes), calculateRhs, removeTsx(addendByteRead)) match {
|
||||
case (
|
||||
List(List(AssemblyLine(STA, ta1, tl, _)), List(AssemblyLine(STA, ta2, th, _))),
|
||||
List(List(AssemblyLine0(STA, ta1, tl)), List(AssemblyLine0(STA, ta2, th))),
|
||||
Nil,
|
||||
List(List(AssemblyLine(LDA, Immediate, al, _)), List(AssemblyLine(LDA, Immediate, ah, _)))) =>
|
||||
List(List(AssemblyLine0(LDA, Immediate, al)), List(AssemblyLine0(LDA, Immediate, ah)))) =>
|
||||
if (ta1 == ta2 && tl.+(1).quickSimplify == th) {
|
||||
return wrapInSedCldIfNeeded(decimal, List(
|
||||
AssemblyLine.implied(if(subtract) SEC else CLC),
|
||||
@ -1134,9 +1135,9 @@ object BuiltIns {
|
||||
AssemblyLine.accu8))
|
||||
}
|
||||
case (
|
||||
List(List(AssemblyLine(STA, ta1, tl, _)), List(AssemblyLine(STA, ta2, th, _))),
|
||||
List(List(AssemblyLine0(STA, ta1, tl)), List(AssemblyLine0(STA, ta2, th))),
|
||||
Nil,
|
||||
List(List(AssemblyLine(LDA, aa1, al, _)), List(AssemblyLine(LDA, aa2, ah, _)))) =>
|
||||
List(List(AssemblyLine0(LDA, aa1, al)), List(AssemblyLine0(LDA, aa2, ah)))) =>
|
||||
if (ta1 == ta2 && aa1 == aa2 && tl.+(1).quickSimplify == th && al.+(1).quickSimplify == ah) {
|
||||
return wrapInSedCldIfNeeded(decimal, List(
|
||||
AssemblyLine.accu16,
|
||||
@ -1147,9 +1148,9 @@ object BuiltIns {
|
||||
AssemblyLine.accu8))
|
||||
}
|
||||
case (
|
||||
List(List(AssemblyLine(STA, ta1, tl, _)), List(AssemblyLine(STA, ta2, th, _))),
|
||||
List(AssemblyLine(TSX, _, _, _), AssemblyLine(LDA, AbsoluteX, NumericConstant(al, _), _), AssemblyLine(LDY, AbsoluteX, NumericConstant(ah, _), _)),
|
||||
List(Nil, List(AssemblyLine(TYA, _, _, _)))) =>
|
||||
List(List(AssemblyLine0(STA, ta1, tl)), List(AssemblyLine0(STA, ta2, th))),
|
||||
List(AssemblyLine0(TSX, _, _), AssemblyLine0(LDA, AbsoluteX, NumericConstant(al, _)), AssemblyLine0(LDY, AbsoluteX, NumericConstant(ah, _))),
|
||||
List(Nil, List(AssemblyLine0(TYA, _, _)))) =>
|
||||
if (ta1 == ta2 && tl.+(1).quickSimplify == th && al + 1 == ah) {
|
||||
return wrapInSedCldIfNeeded(decimal, List(
|
||||
AssemblyLine.accu16,
|
||||
@ -1291,7 +1292,7 @@ object BuiltIns {
|
||||
}
|
||||
if (ctx.options.flags(CompilationFlag.EmitNative65816Opcodes)) {
|
||||
(removeTsx(targetBytes), removeTsx(addendByteRead)) match {
|
||||
case (List(List(AssemblyLine(STA, ta1, tl, _)), List(AssemblyLine(STA, ta2, th, _))), List(List(AssemblyLine(LDA, Immediate, al, _)), List(AssemblyLine(LDA, Immediate, ah, _)))) =>
|
||||
case (List(List(AssemblyLine0(STA, ta1, tl)), List(AssemblyLine0(STA, ta2, th))), List(List(AssemblyLine0(LDA, Immediate, al)), List(AssemblyLine0(LDA, Immediate, ah)))) =>
|
||||
if (ta1 == ta2 && tl.+(1).quickSimplify == th) {
|
||||
return List(
|
||||
AssemblyLine.accu16,
|
||||
@ -1300,7 +1301,7 @@ object BuiltIns {
|
||||
AssemblyLine(STA_W, ta1, tl),
|
||||
AssemblyLine.accu8)
|
||||
}
|
||||
case (List(List(AssemblyLine(STA, ta1, tl, _)), List(AssemblyLine(STA, ta2, th, _))), List(List(AssemblyLine(LDA, aa1, al, _)), List(AssemblyLine(LDA, aa2, ah, _)))) =>
|
||||
case (List(List(AssemblyLine0(STA, ta1, tl)), List(AssemblyLine0(STA, ta2, th))), List(List(AssemblyLine0(LDA, aa1, al)), List(AssemblyLine0(LDA, aa2, ah)))) =>
|
||||
if (ta1 == ta2 && aa1 == aa2 && tl.+(1).quickSimplify == th && al.+(1).quickSimplify == ah) {
|
||||
return List(
|
||||
AssemblyLine.accu16,
|
||||
@ -1416,7 +1417,7 @@ object BuiltIns {
|
||||
}
|
||||
|
||||
private def removeTsx(codes: List[List[AssemblyLine]]): List[List[AssemblyLine]] = codes.map {
|
||||
case List(AssemblyLine(TSX, _, _, _), AssemblyLine(op, AbsoluteX, NumericConstant(nn, _), _)) if nn >= 0x100 && nn <= 0x1ff =>
|
||||
case List(AssemblyLine0(TSX, _, _), AssemblyLine0(op, AbsoluteX, NumericConstant(nn, _))) if nn >= 0x100 && nn <= 0x1ff =>
|
||||
List(AssemblyLine(op, Stack, NumericConstant(nn & 0xff, 1)))
|
||||
case x => x
|
||||
}
|
||||
|
@ -74,8 +74,8 @@ object DecimalBuiltIns {
|
||||
}
|
||||
List(
|
||||
if (rotate) AssemblyLine.implied(ROR) else AssemblyLine.implied(LSR),
|
||||
AssemblyLine(LABEL, DoesNotExist, Label(constantLabel).toAddress, elidable = cmos),
|
||||
AssemblyLine(PHP, Implied, Constant.Zero, elidable = cmos),
|
||||
AssemblyLine(LABEL, DoesNotExist, Label(constantLabel).toAddress, elidability = if (cmos) Elidability.Elidable else Elidability.Fixed),
|
||||
AssemblyLine(PHP, Implied, Constant.Zero, elidability = if (cmos) Elidability.Elidable else Elidability.Fixed),
|
||||
AssemblyLine.relative(BPL, skipHiDigit),
|
||||
AssemblyLine.implied(SEC),
|
||||
AssemblyLine.immediate(SBC, 0x30),
|
||||
|
@ -1,6 +1,7 @@
|
||||
package millfork.compiler.mos
|
||||
|
||||
import millfork.CompilationFlag
|
||||
import millfork.assembly.Elidability
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.mos._
|
||||
import millfork.compiler.{AbstractCompiler, CompilationContext}
|
||||
@ -18,11 +19,11 @@ object MosCompiler extends AbstractCompiler[AssemblyLine] {
|
||||
val chunk = MosStatementCompiler.compile(ctx, new MosStatementPreprocessor(ctx, ctx.function.code)())
|
||||
val zpRegisterSize = ctx.options.zpRegisterSize
|
||||
|
||||
val storeParamsFromRegisters = ctx.function.params match {
|
||||
val storeParamsFromRegisters = (ctx.function.params match {
|
||||
case NormalParamSignature(List(param@MemoryVariable(_, typ, _))) if typ.size == 1 =>
|
||||
List(AssemblyLine.absolute(STA, param))
|
||||
case _ => Nil
|
||||
}
|
||||
}).map(_.position(ctx.function.position))
|
||||
val phReg =
|
||||
if (zpRegisterSize > 0) {
|
||||
val reg = ctx.env.get[VariableInMemory]("__reg")
|
||||
@ -30,7 +31,7 @@ object MosCompiler extends AbstractCompiler[AssemblyLine] {
|
||||
List(
|
||||
AssemblyLine.zeropage(LDA, reg, i),
|
||||
AssemblyLine.implied(PHA))
|
||||
}.toList
|
||||
}.toList.map(_.position(ctx.function.position))
|
||||
} else Nil
|
||||
|
||||
val prefix = storeParamsFromRegisters ++ (if (ctx.function.interrupt) {
|
||||
@ -116,8 +117,8 @@ object MosCompiler extends AbstractCompiler[AssemblyLine] {
|
||||
}
|
||||
AssemblyLine.accu16 :: (initialBytes ++ lastByte)
|
||||
} else phReg
|
||||
} else Nil) ++ stackPointerFixAtBeginning(ctx)
|
||||
val label = AssemblyLine.label(Label(ctx.function.name)).copy(elidable = false)
|
||||
} else Nil).map(_.position(ctx.function.position)) ++ stackPointerFixAtBeginning(ctx)
|
||||
val label = AssemblyLine.label(Label(ctx.function.name)).copy(elidability = Elidability.Fixed)
|
||||
label :: (prefix ++ chunk)
|
||||
}
|
||||
|
||||
@ -130,9 +131,9 @@ object MosCompiler extends AbstractCompiler[AssemblyLine] {
|
||||
AssemblyLine.implied(TSX),
|
||||
AssemblyLine.immediate(LDA, 0xff),
|
||||
AssemblyLine.immediate(SBX, m.stackVariablesSize),
|
||||
AssemblyLine.implied(TXS)) // this TXS is fine, it won't appear in 65816 code
|
||||
AssemblyLine.implied(TXS)).map(_.position(m.position)) // this TXS is fine, it won't appear in 65816 code
|
||||
}
|
||||
List.fill(m.stackVariablesSize)(AssemblyLine.implied(PHA))
|
||||
List.fill(m.stackVariablesSize)(AssemblyLine.implied(PHA)).map(_.position(m.position))
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -75,8 +75,8 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
||||
}
|
||||
|
||||
def fixTsx(code: List[AssemblyLine]): List[AssemblyLine] = code match {
|
||||
case (tsx@AssemblyLine(TSX, _, _, _)) :: xs => tsx :: AssemblyLine.implied(INX) :: fixTsx(xs)
|
||||
case (txs@AssemblyLine(TXS, _, _, _)) :: xs => ???
|
||||
case (tsx@AssemblyLine0(TSX, _, _)) :: xs => tsx :: AssemblyLine.implied(INX) :: fixTsx(xs)
|
||||
case (txs@AssemblyLine0(TXS, _, _)) :: xs => ???
|
||||
case x :: xs => x :: fixTsx(xs)
|
||||
case Nil => Nil
|
||||
}
|
||||
@ -95,22 +95,20 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
||||
|
||||
def changesZpreg(code: List[AssemblyLine], Offset: Int): Boolean = {
|
||||
code.exists {
|
||||
case AssemblyLine(op,
|
||||
case AssemblyLine0(op,
|
||||
AddrMode.ZeroPage | AddrMode.Absolute | AddrMode.LongAbsolute,
|
||||
CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(Offset, _)),
|
||||
_) if th.name == "__reg" && OpcodeClasses.ChangesMemoryAlways(op) || OpcodeClasses.ChangesMemoryIfNotImplied(op) => true
|
||||
case AssemblyLine(op,
|
||||
CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(Offset, _))) if th.name == "__reg" && OpcodeClasses.ChangesMemoryAlways(op) || OpcodeClasses.ChangesMemoryIfNotImplied(op) => true
|
||||
case AssemblyLine0(op,
|
||||
AddrMode.ZeroPage | AddrMode.Absolute | AddrMode.LongAbsolute,
|
||||
MemoryAddressConstant(th),
|
||||
_) if th.name == "__reg" && Offset == 0 && OpcodeClasses.ChangesMemoryAlways(op) || OpcodeClasses.ChangesMemoryIfNotImplied(op) => true
|
||||
case AssemblyLine(JSR | BYTE | BSR, _, _, _) => true
|
||||
MemoryAddressConstant(th)) if th.name == "__reg" && Offset == 0 && OpcodeClasses.ChangesMemoryAlways(op) || OpcodeClasses.ChangesMemoryIfNotImplied(op) => true
|
||||
case AssemblyLine0(JSR | BYTE | BSR, _, _) => true
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
||||
def preserveCarryIfNeeded(ctx: CompilationContext, code: List[AssemblyLine]): List[AssemblyLine] = {
|
||||
if (code.exists {
|
||||
case AssemblyLine(JSR | BSR, Absolute | LongAbsolute, MemoryAddressConstant(th), _) => true
|
||||
case AssemblyLine0(JSR | BSR, Absolute | LongAbsolute, MemoryAddressConstant(th)) => true
|
||||
case x => OpcodeClasses.ChangesC(x.opcode)
|
||||
}) {
|
||||
AssemblyLine.implied(PHP) +: fixTsx(code) :+ AssemblyLine.implied(PLP)
|
||||
@ -751,26 +749,36 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
||||
ctx.log.error("Invalid number of parameters", f.position)
|
||||
Nil
|
||||
} else {
|
||||
assertAllArithmeticBytes("Nonet argument has to be a byte", ctx, params)
|
||||
params.head match {
|
||||
case SumExpression(addends, _) =>
|
||||
if (addends.exists(a => !a._1)) {
|
||||
ctx.log.warn("Nonet subtraction may not work as expected", expr.position)
|
||||
env.eval(expr) match {
|
||||
case Some(c) =>
|
||||
exprTypeAndVariable match {
|
||||
case Some((t, v)) =>
|
||||
compileConstant(ctx, c, v)
|
||||
case _ =>
|
||||
Nil
|
||||
}
|
||||
if (addends.size > 2) {
|
||||
ctx.log.warn("Nonet addition works correctly only for two operands", expr.position)
|
||||
case None =>
|
||||
assertAllArithmeticBytes("Nonet argument has to be a byte", ctx, params)
|
||||
params.head match {
|
||||
case SumExpression(addends, _) =>
|
||||
if (addends.exists(a => !a._1)) {
|
||||
ctx.log.warn("Nonet subtraction may not work as expected", expr.position)
|
||||
}
|
||||
if (addends.size > 2) {
|
||||
ctx.log.warn("Nonet addition works correctly only for two operands", expr.position)
|
||||
}
|
||||
case FunctionCallExpression("+" | "+'" | "<<" | "<<'" | "nonet", _) => // ok
|
||||
case _ =>
|
||||
ctx.log.warn("Unspecified nonet operation, results might be unpredictable", expr.position)
|
||||
}
|
||||
case FunctionCallExpression("+" | "+'" | "<<" | "<<'" | "nonet", _) => // ok
|
||||
case _ =>
|
||||
ctx.log.warn("Unspecified nonet operation, results might be unpredictable", expr.position)
|
||||
val label = ctx.nextLabel("no")
|
||||
compile(ctx, params.head, Some(b -> RegisterVariable(MosRegister.A, b)), BranchSpec.None) ++ List(
|
||||
AssemblyLine.immediate(LDX, 0),
|
||||
AssemblyLine.relative(BCC, label),
|
||||
AssemblyLine.implied(INX),
|
||||
AssemblyLine.label(label)
|
||||
)
|
||||
}
|
||||
val label = ctx.nextLabel("no")
|
||||
compile(ctx, params.head, Some(b -> RegisterVariable(MosRegister.A, b)), BranchSpec.None) ++ List(
|
||||
AssemblyLine.immediate(LDX, 0),
|
||||
AssemblyLine.relative(BCC, label),
|
||||
AssemblyLine.implied(INX),
|
||||
AssemblyLine.label(label)
|
||||
)
|
||||
}
|
||||
case "&&" =>
|
||||
assertBool(ctx, "&&", params)
|
||||
@ -1076,12 +1084,12 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
||||
case function: MacroFunction =>
|
||||
val (paramPreparation, statements) = MosMacroExpander.inlineFunction(ctx, function, params, expr.position)
|
||||
paramPreparation ++ statements.map {
|
||||
case MosAssemblyStatement(opcode, addrMode, expression, elidable) =>
|
||||
case MosAssemblyStatement(opcode, addrMode, expression, elidability) =>
|
||||
val param = env.evalForAsm(expression).getOrElse {
|
||||
ctx.log.error("Inlining failed due to non-constant things", expression.position)
|
||||
Constant.Zero
|
||||
}
|
||||
AssemblyLine(opcode, addrMode, param, elidable)
|
||||
AssemblyLine(opcode, addrMode, param, elidability)
|
||||
}
|
||||
case function: EmptyFunction =>
|
||||
??? // TODO: type conversion?
|
||||
|
@ -1,7 +1,7 @@
|
||||
package millfork.compiler.mos
|
||||
|
||||
import millfork.CompilationFlag
|
||||
import millfork.assembly.BranchingOpcodeMapping
|
||||
import millfork.assembly.{BranchingOpcodeMapping, Elidability}
|
||||
import millfork.assembly.mos.AddrMode._
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.mos._
|
||||
@ -138,7 +138,7 @@ object MosStatementCompiler extends AbstractStatementCompiler[AssemblyLine] {
|
||||
List(AssemblyLine.implied(RTS))
|
||||
})
|
||||
}
|
||||
statement match {
|
||||
(statement match {
|
||||
case EmptyStatement(stmts) =>
|
||||
stmts.foreach(s => compile(ctx, s))
|
||||
Nil
|
||||
@ -165,10 +165,10 @@ object MosStatementCompiler extends AbstractStatementCompiler[AssemblyLine] {
|
||||
case RawBytesStatement(contents) =>
|
||||
env.extractArrayContents(contents).map { expr =>
|
||||
env.eval(expr) match {
|
||||
case Some(c) => AssemblyLine(BYTE, RawByte, c, elidable = false)
|
||||
case Some(c) => AssemblyLine(BYTE, RawByte, c, elidability = Elidability.Fixed)
|
||||
case None =>
|
||||
ctx.log.error("Non-constant raw byte", position = statement.position)
|
||||
AssemblyLine(BYTE, RawByte, Constant.Zero, elidable = false)
|
||||
AssemblyLine(BYTE, RawByte, Constant.Zero, elidability = Elidability.Fixed)
|
||||
}
|
||||
}
|
||||
case Assignment(dest, source) =>
|
||||
@ -273,7 +273,7 @@ object MosStatementCompiler extends AbstractStatementCompiler[AssemblyLine] {
|
||||
compileBreakStatement(ctx, s)
|
||||
case s:ContinueStatement =>
|
||||
compileContinueStatement(ctx, s)
|
||||
}
|
||||
}).map(_.positionIfEmpty(statement.position))
|
||||
}
|
||||
|
||||
def stackPointerFixBeforeReturn(ctx: CompilationContext): List[AssemblyLine] = {
|
||||
|
@ -76,10 +76,10 @@ object PseudoregisterBuiltIns {
|
||||
val compileRight = MosExpressionCompiler.compile(ctx, r, Some(rightType -> ctx.env.get[VariableInMemory]("__reg.b2b3")), BranchSpec.None)
|
||||
compileRight match {
|
||||
case List(
|
||||
AssemblyLine(LDA, Immediate, NumericConstant(0, _), _),
|
||||
AssemblyLine(STA, ZeroPage, _, _),
|
||||
AssemblyLine(LDX | LDA, Immediate, NumericConstant(0, _), _),
|
||||
AssemblyLine(STA | STX, ZeroPage, _, _)) => Nil
|
||||
AssemblyLine0(LDA, Immediate, NumericConstant(0, _)),
|
||||
AssemblyLine0(STA, ZeroPage, _),
|
||||
AssemblyLine0(LDX | LDA, Immediate, NumericConstant(0, _)),
|
||||
AssemblyLine0(STA | STX, ZeroPage, _)) => Nil
|
||||
case _ =>
|
||||
compileRight ++
|
||||
List(
|
||||
@ -108,16 +108,16 @@ object PseudoregisterBuiltIns {
|
||||
compileRight match {
|
||||
|
||||
case List(
|
||||
AssemblyLine(LDA, Immediate, NumericConstant(0, _), _),
|
||||
AssemblyLine(STA, ZeroPage, _, _),
|
||||
AssemblyLine(LDX | LDA, Immediate, NumericConstant(0, _), _),
|
||||
AssemblyLine(STA | STX, ZeroPage, _, _)) => Nil
|
||||
AssemblyLine0(LDA, Immediate, NumericConstant(0, _)),
|
||||
AssemblyLine0(STA, ZeroPage, _),
|
||||
AssemblyLine0(LDX | LDA, Immediate, NumericConstant(0, _)),
|
||||
AssemblyLine0(STA | STX, ZeroPage, _)) => Nil
|
||||
|
||||
case List(
|
||||
l@AssemblyLine(LDA, _, _, _),
|
||||
AssemblyLine(STA, ZeroPage, _, _),
|
||||
h@AssemblyLine(LDX | LDA, addrMode, _, _),
|
||||
AssemblyLine(STA | STX, ZeroPage, _, _)) if addrMode != ZeroPageY => BuiltIns.wrapInSedCldIfNeeded(decimal,
|
||||
l@AssemblyLine0(LDA, _, _),
|
||||
AssemblyLine0(STA, ZeroPage, _),
|
||||
h@AssemblyLine0(LDX | LDA, addrMode, _),
|
||||
AssemblyLine0(STA | STX, ZeroPage, _)) if addrMode != ZeroPageY => BuiltIns.wrapInSedCldIfNeeded(decimal,
|
||||
List(prepareCarry,
|
||||
AssemblyLine.zeropage(LDA, reg),
|
||||
l.copy(opcode = op),
|
||||
@ -176,24 +176,24 @@ object PseudoregisterBuiltIns {
|
||||
val compileRight = MosExpressionCompiler.compile(ctx, r, Some(MosExpressionCompiler.getExpressionType(ctx, r) -> reg), BranchSpec.None)
|
||||
compileRight match {
|
||||
case List(
|
||||
AssemblyLine(LDA, Immediate, NumericConstant(0, _), _),
|
||||
AssemblyLine(STA, ZeroPage, _, _),
|
||||
AssemblyLine(LDX | LDA, Immediate, NumericConstant(0, _), _),
|
||||
AssemblyLine(STA | STX, ZeroPage, _, _))
|
||||
AssemblyLine0(LDA, Immediate, NumericConstant(0, _)),
|
||||
AssemblyLine0(STA, ZeroPage, _),
|
||||
AssemblyLine0(LDX | LDA, Immediate, NumericConstant(0, _)),
|
||||
AssemblyLine0(STA | STX, ZeroPage, _))
|
||||
if op != AND => Nil
|
||||
|
||||
case List(
|
||||
AssemblyLine(LDA, Immediate, NumericConstant(0xff, _), _),
|
||||
AssemblyLine(STA, ZeroPage, _, _),
|
||||
AssemblyLine(LDX | LDA, Immediate, NumericConstant(0xff, _), _),
|
||||
AssemblyLine(STA | STX, ZeroPage, _, _))
|
||||
AssemblyLine0(LDA, Immediate, NumericConstant(0xff, _)),
|
||||
AssemblyLine0(STA, ZeroPage, _),
|
||||
AssemblyLine0(LDX | LDA, Immediate, NumericConstant(0xff, _)),
|
||||
AssemblyLine0(STA | STX, ZeroPage, _))
|
||||
if op == AND => Nil
|
||||
|
||||
case List(
|
||||
l@AssemblyLine(LDA, _, _, _),
|
||||
AssemblyLine(STA, ZeroPage, _, _),
|
||||
h@AssemblyLine(LDX | LDA, addrMode, _, _),
|
||||
AssemblyLine(STA | STX, ZeroPage, _, _)) if addrMode != ZeroPageY =>
|
||||
l@AssemblyLine0(LDA, _, _),
|
||||
AssemblyLine0(STA, ZeroPage, _),
|
||||
h@AssemblyLine0(LDX | LDA, addrMode, _),
|
||||
AssemblyLine0(STA | STX, ZeroPage, _)) if addrMode != ZeroPageY =>
|
||||
List(
|
||||
AssemblyLine.zeropage(LDA, reg),
|
||||
l.copy(opcode = op),
|
||||
@ -245,8 +245,8 @@ object PseudoregisterBuiltIns {
|
||||
case _ =>
|
||||
val compileCounter = MosExpressionCompiler.compile(ctx, r, Some(b -> RegisterVariable(MosRegister.X, b)), NoBranching)
|
||||
val compileCounterAndPrepareFirstParam = compileCounter match {
|
||||
case List(AssemblyLine(LDX, _, _, _)) => firstParamCompiled ++ compileCounter
|
||||
case List(AssemblyLine(LDY, _, _, _), AssemblyLine(LDX, _, _, _)) => firstParamCompiled ++ compileCounter
|
||||
case List(AssemblyLine0(LDX, _, _)) => firstParamCompiled ++ compileCounter
|
||||
case List(AssemblyLine0(LDY, _, _), AssemblyLine0(LDX, _, _)) => firstParamCompiled ++ compileCounter
|
||||
case _ =>
|
||||
MosExpressionCompiler.compile(ctx, r, Some(b -> RegisterVariable(MosRegister.A, b)), NoBranching) ++
|
||||
List(AssemblyLine.implied(PHA)) ++
|
||||
@ -343,14 +343,14 @@ object PseudoregisterBuiltIns {
|
||||
}
|
||||
|
||||
def usesRegLo(code: List[AssemblyLine]): Boolean = code.forall{
|
||||
case AssemblyLine(JSR | BSR | TCD | TDC, _, _, _) => true
|
||||
case AssemblyLine(_, _, MemoryAddressConstant(th), _) if th.name == "__reg" => true
|
||||
case AssemblyLine0(JSR | BSR | TCD | TDC, _, _) => true
|
||||
case AssemblyLine0(_, _, MemoryAddressConstant(th)) if th.name == "__reg" => true
|
||||
case _ => false
|
||||
}
|
||||
|
||||
def usesRegHi(code: List[AssemblyLine]): Boolean = code.forall{
|
||||
case AssemblyLine(JSR | BSR | TCD | TDC, _, _, _) => true
|
||||
case AssemblyLine(_, _, CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(1, _)), _) if th.name == "__reg" => true
|
||||
case AssemblyLine0(JSR | BSR | TCD | TDC, _, _) => true
|
||||
case AssemblyLine0(_, _, CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(1, _))) if th.name == "__reg" => true
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package millfork.compiler.z80
|
||||
|
||||
import millfork.CompilationFlag
|
||||
import millfork.assembly.Elidability
|
||||
import millfork.assembly.z80._
|
||||
import millfork.compiler.CompilationContext
|
||||
import millfork.env._
|
||||
@ -68,7 +69,7 @@ object Z80BulkMemoryOperations {
|
||||
case _ => Z80ExpressionCompiler.stashBCIfChanged(ctx, loadA)
|
||||
}
|
||||
val loadDE = calculateAddress match {
|
||||
case List(ZLine(ZOpcode.LD_16, TwoRegisters(ZRegister.HL, ZRegister.IMM_16), c, _)) =>
|
||||
case List(ZLine0(ZOpcode.LD_16, TwoRegisters(ZRegister.HL, ZRegister.IMM_16), c)) =>
|
||||
if (incOp == DEC_16) List(ZLine.ldImm16(ZRegister.DE, (c - 1).quickSimplify))
|
||||
else List(ZLine.ldImm16(ZRegister.DE, (c + 1).quickSimplify))
|
||||
case _ => List(
|
||||
@ -465,7 +466,7 @@ object Z80BulkMemoryOperations {
|
||||
}
|
||||
Z80StatementCompiler.compile(ctx, IfStatement(
|
||||
FunctionCallExpression(operator, List(f.start, f.end)),
|
||||
List(Z80AssemblyStatement(ZOpcode.NOP, NoRegisters, None, LiteralExpression(0, 1), elidable = false)),
|
||||
List(Z80AssemblyStatement(ZOpcode.NOP, NoRegisters, None, LiteralExpression(0, 1), elidability = Elidability.Fixed)),
|
||||
Nil))
|
||||
}
|
||||
|
||||
|
@ -233,13 +233,13 @@ object Z80Comparisons {
|
||||
import ZRegister._
|
||||
val sub = if (i == 0) SUB else SBC
|
||||
var compareBytes = (lb, rb) match {
|
||||
case (List(ZLine(LD, TwoRegisters(A, _), _, _)),
|
||||
List(ZLine(LD, TwoRegisters(A, IMM_8), param, _))) =>
|
||||
case (List(ZLine0(LD, TwoRegisters(A, _), _)),
|
||||
List(ZLine0(LD, TwoRegisters(A, IMM_8), param))) =>
|
||||
lb :+ ZLine.imm8(sub, param)
|
||||
case (List(ZLine(LD, TwoRegisters(A, _), _, _)),
|
||||
List(ZLine(LD, TwoRegisters(A, reg), _, _))) if reg != MEM_ABS_8 =>
|
||||
case (List(ZLine0(LD, TwoRegisters(A, _), _)),
|
||||
List(ZLine0(LD, TwoRegisters(A, reg), _))) if reg != MEM_ABS_8 =>
|
||||
lb :+ ZLine.register(sub, reg)
|
||||
case (List(ZLine(LD, TwoRegisters(A, _), _, _)), _) =>
|
||||
case (List(ZLine0(LD, TwoRegisters(A, _), _)), _) =>
|
||||
Z80ExpressionCompiler.stashAFIfChangedF(ctx, rb :+ ZLine.ld8(E, A)) ++ lb :+ ZLine.register(sub, E)
|
||||
case _ =>
|
||||
if (preserveBc || preserveHl) ??? // TODO: preserve HL/BC for the next round of comparisons
|
||||
@ -293,17 +293,17 @@ object Z80Comparisons {
|
||||
import ZOpcode._
|
||||
import ZRegister._
|
||||
(lb, rb) match {
|
||||
case (_, List(ZLine(LD, TwoRegisters(A, IMM_8), param, _))) =>
|
||||
case (_, List(ZLine0(LD, TwoRegisters(A, IMM_8), param))) =>
|
||||
lb :+ ZLine.imm8(CP, param)
|
||||
case (List(ZLine(LD, TwoRegisters(A, IMM_8), param, _)), _) =>
|
||||
case (List(ZLine0(LD, TwoRegisters(A, IMM_8), param)), _) =>
|
||||
rb :+ ZLine.imm8(CP, param)
|
||||
case (List(ZLine(LD, TwoRegisters(A, _), _, _)),
|
||||
List(ZLine(LD, TwoRegisters(A, reg), _, _))) if reg != MEM_ABS_8 =>
|
||||
case (List(ZLine0(LD, TwoRegisters(A, _), _)),
|
||||
List(ZLine0(LD, TwoRegisters(A, reg), _))) if reg != MEM_ABS_8 =>
|
||||
lb :+ ZLine.register(CP, reg)
|
||||
case (List(ZLine(LD, TwoRegisters(A, reg), _, _)),
|
||||
List(ZLine(LD, TwoRegisters(A, _), _, _))) if reg != MEM_ABS_8 =>
|
||||
case (List(ZLine0(LD, TwoRegisters(A, reg), _)),
|
||||
List(ZLine0(LD, TwoRegisters(A, _), _))) if reg != MEM_ABS_8 =>
|
||||
rb :+ ZLine.register(CP, reg)
|
||||
case (List(ZLine(LD, TwoRegisters(A, _), _, _)), _) =>
|
||||
case (List(ZLine0(LD, TwoRegisters(A, _), _)), _) =>
|
||||
(rb :+ ZLine.ld8(E, A)) ++ lb :+ ZLine.register(CP, E)
|
||||
case _ =>
|
||||
var actualLb = lb
|
||||
@ -322,14 +322,14 @@ object Z80Comparisons {
|
||||
|
||||
private def isBytesFromHL(calculateLeft: List[List[ZLine]]) = {
|
||||
calculateLeft(1) match {
|
||||
case List(ZLine(ZOpcode.LD, TwoRegisters(ZRegister.A, ZRegister.H), _, _)) => true
|
||||
case List(ZLine0(ZOpcode.LD, TwoRegisters(ZRegister.A, ZRegister.H), _)) => true
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
||||
private def isBytesFromBC(calculateLeft: List[List[ZLine]]) = {
|
||||
calculateLeft(1) match {
|
||||
case List(ZLine(ZOpcode.LD, TwoRegisters(ZRegister.A, ZRegister.B), _, _)) => true
|
||||
case List(ZLine0(ZOpcode.LD, TwoRegisters(ZRegister.A, ZRegister.B), _)) => true
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package millfork.compiler.z80
|
||||
|
||||
import millfork.CompilationFlag
|
||||
import millfork.assembly.Elidability
|
||||
import millfork.assembly.z80.ZLine
|
||||
import millfork.compiler.{AbstractCompiler, CompilationContext}
|
||||
import millfork.env.{Label, NormalParamSignature}
|
||||
@ -14,7 +15,7 @@ object Z80Compiler extends AbstractCompiler[ZLine] {
|
||||
override def compile(ctx: CompilationContext): List[ZLine] = {
|
||||
ctx.env.nameCheck(ctx.function.code)
|
||||
val chunk = Z80StatementCompiler.compile(ctx, new Z80StatementPreprocessor(ctx, ctx.function.code)())
|
||||
val label = ZLine.label(Label(ctx.function.name)).copy(elidable = false)
|
||||
val label = ZLine.label(Label(ctx.function.name)).copy(elidability = Elidability.Fixed)
|
||||
val storeParamsFromRegisters = ctx.function.params match {
|
||||
case NormalParamSignature(List(param)) if param.typ.size == 1 =>
|
||||
List(ZLine.ldAbs8(param.toAddress, ZRegister.A))
|
||||
@ -61,7 +62,7 @@ object Z80Compiler extends AbstractCompiler[ZLine] {
|
||||
}
|
||||
case _ => Nil
|
||||
}
|
||||
label :: (preserveRegisters(ctx) ++ stackPointerFixAtBeginning(ctx) ++ storeParamsFromRegisters ++ chunk)
|
||||
label :: (preserveRegisters(ctx) ++ stackPointerFixAtBeginning(ctx) ++ storeParamsFromRegisters).map(_.position(ctx.function.position)) ++ chunk
|
||||
}
|
||||
|
||||
def preserveRegisters(ctx: CompilationContext): List[ZLine] = {
|
||||
@ -103,7 +104,7 @@ object Z80Compiler extends AbstractCompiler[ZLine] {
|
||||
def restoreRegistersAndReturn(ctx: CompilationContext): List[ZLine] = {
|
||||
import millfork.assembly.z80.ZOpcode._
|
||||
import ZRegister._
|
||||
if (ctx.function.interrupt) {
|
||||
(if (ctx.function.interrupt) {
|
||||
if (ctx.options.flag(CompilationFlag.EmitZ80Opcodes)) {
|
||||
if (ctx.options.flag(CompilationFlag.UseShadowRegistersForInterrupts)) {
|
||||
List(
|
||||
@ -155,7 +156,7 @@ object Z80Compiler extends AbstractCompiler[ZLine] {
|
||||
ZLine.register(POP, IX),
|
||||
ZLine.implied(RET))
|
||||
} else List(ZLine.implied(RET))
|
||||
} else List(ZLine.implied(RET))
|
||||
} else List(ZLine.implied(RET))).map(_.position(ctx.function.position))
|
||||
}
|
||||
|
||||
def stackPointerFixAtBeginning(ctx: CompilationContext): List[ZLine] = {
|
||||
@ -172,7 +173,7 @@ object Z80Compiler extends AbstractCompiler[ZLine] {
|
||||
import millfork.assembly.z80.ZOpcode._
|
||||
import ZRegister._
|
||||
val localVariableArea = ctx.function.stackVariablesSize.&(1).+(ctx.function.stackVariablesSize)
|
||||
if (ctx.options.flag(CompilationFlag.UseIxForStack)) {
|
||||
(if (ctx.options.flag(CompilationFlag.UseIxForStack)) {
|
||||
List(
|
||||
ZLine.register(PUSH, IX),
|
||||
ZLine.ldImm16(IX, 0x10000 - localVariableArea),
|
||||
@ -228,6 +229,6 @@ object Z80Compiler extends AbstractCompiler[ZLine] {
|
||||
ZLine.registers(ADD_16, HL, SP),
|
||||
ZLine.ld16(SP, HL))
|
||||
}
|
||||
}
|
||||
}).map(_.position(ctx.function.position))
|
||||
}
|
||||
}
|
||||
|
@ -25,13 +25,13 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
||||
val toA = compileToA(ctx, expression)
|
||||
if (toA.isEmpty) Nil else {
|
||||
toA.last match {
|
||||
case ZLine(ZOpcode.LD, TwoRegisters(ZRegister.A, source), _, _) if source == register =>
|
||||
case ZLine0(ZOpcode.LD, TwoRegisters(ZRegister.A, source), _) if source == register =>
|
||||
toA.init
|
||||
case ZLine(ZOpcode.LD, TwoRegisters(ZRegister.A, source@(ZRegister.B | ZRegister.C | ZRegister.D | ZRegister.E | ZRegister.MEM_HL)), _, _) =>
|
||||
case ZLine0(ZOpcode.LD, TwoRegisters(ZRegister.A, source@(ZRegister.B | ZRegister.C | ZRegister.D | ZRegister.E | ZRegister.MEM_HL)), _) =>
|
||||
toA.init :+ ZLine.ld8(register, source)
|
||||
case ZLine(ZOpcode.LD, TwoRegistersOffset(ZRegister.A, ZRegister.MEM_IX_D, offset), _, _) =>
|
||||
case ZLine0(ZOpcode.LD, TwoRegistersOffset(ZRegister.A, ZRegister.MEM_IX_D, offset), _) =>
|
||||
toA.init :+ ZLine.ldViaIx(register, offset)
|
||||
case ZLine(ZOpcode.LD, TwoRegistersOffset(ZRegister.A, ZRegister.MEM_IY_D, offset), _, _) =>
|
||||
case ZLine0(ZOpcode.LD, TwoRegistersOffset(ZRegister.A, ZRegister.MEM_IY_D, offset), _) =>
|
||||
toA.init :+ ZLine.ldViaIy(register, offset)
|
||||
case _ =>
|
||||
toA :+ ZLine.ld8(register, ZRegister.A)
|
||||
@ -126,15 +126,15 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
||||
}
|
||||
|
||||
def fixTsx(ctx: CompilationContext, code: List[ZLine]): List[ZLine] = code match {
|
||||
case (ldhlsp@ZLine(LD_HLSP, _, param, _)) :: xs => ldhlsp.copy(parameter = param + 2) :: fixTsx(ctx, xs)
|
||||
case (ldhl@ZLine(LD_16, TwoRegisters(ZRegister.HL, ZRegister.IMM_16), param, _)) ::
|
||||
(addhlsp@ZLine(ADD_16, TwoRegisters(ZRegister.HL, ZRegister.SP), _, _)) ::
|
||||
(ldsphl@ZLine(LD_16, TwoRegisters(ZRegister.SP, ZRegister.HL), _, _)) ::
|
||||
case (ldhlsp@ZLine0(LD_HLSP, _, param)) :: xs => ldhlsp.copy(parameter = param + 2) :: fixTsx(ctx, xs)
|
||||
case (ldhl@ZLine0(LD_16, TwoRegisters(ZRegister.HL, ZRegister.IMM_16), param)) ::
|
||||
(addhlsp@ZLine0(ADD_16, TwoRegisters(ZRegister.HL, ZRegister.SP), _)) ::
|
||||
(ldsphl@ZLine0(LD_16, TwoRegisters(ZRegister.SP, ZRegister.HL), _)) ::
|
||||
xs => ??? // TODO: ldhl :: addhlsp :: ldsphl :: fixTsx(ctx, xs)
|
||||
case (ldhl@ZLine(LD_16, TwoRegisters(ZRegister.HL, ZRegister.IMM_16), param, _)) ::
|
||||
(addhlsp@ZLine(ADD_16, TwoRegisters(ZRegister.HL, ZRegister.SP), _, _)) ::
|
||||
case (ldhl@ZLine0(LD_16, TwoRegisters(ZRegister.HL, ZRegister.IMM_16), param)) ::
|
||||
(addhlsp@ZLine0(ADD_16, TwoRegisters(ZRegister.HL, ZRegister.SP), _)) ::
|
||||
xs => ldhl.copy(parameter = param + 2) :: addhlsp :: fixTsx(ctx, xs)
|
||||
case (x@ZLine(EX_SP, _, _, _)) :: xs =>
|
||||
case (x@ZLine0(EX_SP, _, _)) :: xs =>
|
||||
// EX_SP should be only generated by the optimizer
|
||||
ctx.log.warn("Stray EX (SP) encountered, generated code might be invalid")
|
||||
x :: fixTsx(ctx, xs)
|
||||
@ -438,7 +438,7 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
||||
}
|
||||
case i: IndexedExpression =>
|
||||
calculateAddressToHL(ctx, i) match {
|
||||
case List(ZLine(LD_16, TwoRegisters(ZRegister.HL, ZRegister.IMM_16), addr, _)) => loadByte(addr, target)
|
||||
case List(ZLine0(LD_16, TwoRegisters(ZRegister.HL, ZRegister.IMM_16), addr)) => loadByte(addr, target)
|
||||
case code => code ++ loadByteViaHL(target)
|
||||
}
|
||||
case SumExpression(params, decimal) =>
|
||||
@ -1188,7 +1188,7 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
|
||||
}
|
||||
case i:IndexedExpression =>
|
||||
calculateAddressToHL(ctx, i) match {
|
||||
case List(ZLine(LD_16, TwoRegisters(ZRegister.HL, ZRegister.IMM_16), addr, _)) => storeA(ctx, addr, 1, signedSource)
|
||||
case List(ZLine0(LD_16, TwoRegisters(ZRegister.HL, ZRegister.IMM_16), addr)) => storeA(ctx, addr, 1, signedSource)
|
||||
case code => if (code.exists(changesA)) {
|
||||
List(ZLine.ld8(ZRegister.E, ZRegister.A)) ++ stashDEIfChanged(ctx, code) :+ ZLine.ld8(ZRegister.MEM_HL, ZRegister.E)
|
||||
} else code :+ ZLine.ld8(ZRegister.MEM_HL, ZRegister.A)
|
||||
|
@ -19,7 +19,7 @@ object Z80StatementCompiler extends AbstractStatementCompiler[ZLine] {
|
||||
val options = ctx.options
|
||||
val env = ctx.env
|
||||
val ret = Z80Compiler.restoreRegistersAndReturn(ctx)
|
||||
statement match {
|
||||
(statement match {
|
||||
case EmptyStatement(stmts) =>
|
||||
stmts.foreach(s => compile(ctx, s))
|
||||
Nil
|
||||
@ -158,7 +158,7 @@ object Z80StatementCompiler extends AbstractStatementCompiler[ZLine] {
|
||||
}
|
||||
case ExpressionStatement(e) =>
|
||||
Z80ExpressionCompiler.compile(ctx, e, ZExpressionTarget.NOTHING)
|
||||
case Z80AssemblyStatement(op, reg, offset, expression, elidable) =>
|
||||
case Z80AssemblyStatement(op, reg, offset, expression, elidability) =>
|
||||
val param: Constant = expression match {
|
||||
// TODO: hmmm
|
||||
case VariableExpression(name) =>
|
||||
@ -191,8 +191,8 @@ object Z80StatementCompiler extends AbstractStatementCompiler[ZLine] {
|
||||
}
|
||||
case _ => reg
|
||||
}
|
||||
List(ZLine(op, registers, param, elidable))
|
||||
}
|
||||
List(ZLine(op, registers, param, elidability))
|
||||
}).map(_.position(statement.position))
|
||||
}
|
||||
|
||||
private def fixStackOnReturn(ctx: CompilationContext): List[ZLine] = {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package millfork.node
|
||||
|
||||
import millfork.assembly.Elidability
|
||||
import millfork.assembly.mos.{AddrMode, Opcode}
|
||||
import millfork.assembly.z80.{ZOpcode, ZRegisters}
|
||||
import millfork.env.{Constant, ParamPassingConvention, Type}
|
||||
@ -345,11 +346,11 @@ case class Assignment(destination: LhsExpression, source: Expression) extends Ex
|
||||
override def getAllExpressions: List[Expression] = List(destination, source)
|
||||
}
|
||||
|
||||
case class MosAssemblyStatement(opcode: Opcode.Value, addrMode: AddrMode.Value, expression: Expression, elidable: Boolean) extends ExecutableStatement {
|
||||
case class MosAssemblyStatement(opcode: Opcode.Value, addrMode: AddrMode.Value, expression: Expression, elidability: Elidability.Value) extends ExecutableStatement {
|
||||
override def getAllExpressions: List[Expression] = List(expression)
|
||||
}
|
||||
|
||||
case class Z80AssemblyStatement(opcode: ZOpcode.Value, registers: ZRegisters, offsetExpression: Option[Expression], expression: Expression, elidable: Boolean) extends ExecutableStatement {
|
||||
case class Z80AssemblyStatement(opcode: ZOpcode.Value, registers: ZRegisters, offsetExpression: Option[Expression], expression: Expression, elidability: Elidability.Value) extends ExecutableStatement {
|
||||
override def getAllExpressions: List[Expression] = List(expression)
|
||||
}
|
||||
|
||||
@ -390,7 +391,7 @@ case class ContinueStatement(label: String) extends ExecutableStatement {
|
||||
}
|
||||
|
||||
object MosAssemblyStatement {
|
||||
def implied(opcode: Opcode.Value, elidable: Boolean) = MosAssemblyStatement(opcode, AddrMode.Implied, LiteralExpression(0, 1), elidable)
|
||||
def implied(opcode: Opcode.Value, elidability: Elidability.Value) = MosAssemblyStatement(opcode, AddrMode.Implied, LiteralExpression(0, 1), elidability)
|
||||
|
||||
def nonexistent(opcode: Opcode.Value) = MosAssemblyStatement(opcode, AddrMode.DoesNotExist, LiteralExpression(0, 1), elidable = true)
|
||||
def nonexistent(opcode: Opcode.Value) = MosAssemblyStatement(opcode, AddrMode.DoesNotExist, LiteralExpression(0, 1), elidability = Elidability.Elidable)
|
||||
}
|
@ -3,7 +3,7 @@ package millfork.output
|
||||
import millfork.assembly._
|
||||
import millfork.compiler.{AbstractCompiler, CompilationContext}
|
||||
import millfork.env._
|
||||
import millfork.error.{ConsoleLogger, Logger}
|
||||
import millfork.error.Logger
|
||||
import millfork.node.{CallGraph, NiceFunctionProperty, Program}
|
||||
import millfork._
|
||||
import millfork.assembly.z80.ZLine
|
||||
@ -323,14 +323,14 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
|
||||
val thing = if (name.endsWith(".addr")) env.get[ThingInMemory](name.stripSuffix(".addr")) else env.get[ThingInMemory](name + ".array")
|
||||
env.things += altName -> ConstantThing(altName, NumericConstant(index, 2), env.get[Type]("pointer"))
|
||||
assembly.append("* = $" + index.toHexString)
|
||||
assembly.append(" !byte $2c")
|
||||
assembly.append(" " + bytePseudoopcode + " $2c")
|
||||
assembly.append(name)
|
||||
val c = thing.toAddress
|
||||
writeByte(bank, index, 0x2c.toByte) // BIT abs
|
||||
index += 1
|
||||
for (i <- 0 until typ.size) {
|
||||
writeByte(bank, index, c.subbyte(i))
|
||||
assembly.append(" !byte " + c.subbyte(i).quickSimplify)
|
||||
assembly.append(" " + bytePseudoopcode + " " + c.subbyte(i).quickSimplify)
|
||||
index += 1
|
||||
}
|
||||
initializedVariablesSize += typ.size
|
||||
@ -341,7 +341,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
|
||||
val index = codeAllocators("default").allocateBytes(mem.banks("default"), options, 1, initialized = true, writeable = false, location = AllocationLocation.High, alignment = NoAlignment)
|
||||
writeByte("default", index, 2.toByte) // BIT abs
|
||||
assembly.append("* = $" + index.toHexString)
|
||||
assembly.append(" !byte 2 ;; end of LUnix relocatable segment")
|
||||
assembly.append(" " + bytePseudoopcode + " 2 ;; end of LUnix relocatable segment")
|
||||
justAfterCode += "default" -> (index + 1)
|
||||
}
|
||||
env.allPreallocatables.foreach {
|
||||
@ -360,7 +360,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
|
||||
index += 1
|
||||
}
|
||||
items.grouped(16).foreach { group =>
|
||||
assembly.append(" !byte " + group.map(expr => env.eval(expr) match {
|
||||
assembly.append(" " + bytePseudoopcode + " " + group.map(expr => env.eval(expr) match {
|
||||
case Some(c) => c.quickSimplify.toString
|
||||
case None => "<? unknown constant ?>"
|
||||
}).mkString(", "))
|
||||
@ -380,7 +380,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
|
||||
case Some(c) =>
|
||||
for (i <- 0 until typ.size) {
|
||||
writeByte(bank, index, c.subbyte(i))
|
||||
assembly.append(" !byte " + c.subbyte(i).quickSimplify)
|
||||
assembly.append(" " + bytePseudoopcode + " " + c.subbyte(i).quickSimplify)
|
||||
index += 1
|
||||
}
|
||||
case None =>
|
||||
@ -475,24 +475,47 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
|
||||
|
||||
def performFinalOptimizationPass(f: NormalFunction, actuallyOptimize: Boolean, options: CompilationOptions, code: List[T]): List[T]
|
||||
|
||||
private val FinalWhitespace = "\\s+$".r
|
||||
|
||||
private def outputFunction(bank: String, code: List[T], startFrom: Int, assOut: mutable.ArrayBuffer[String], options: CompilationOptions): Int = {
|
||||
val printLineNumbers = options.flag(CompilationFlag.LineNumbersInAssembly)
|
||||
var index = startFrom
|
||||
assOut.append("* = $" + startFrom.toHexString)
|
||||
var lastSource = Option.empty[SourceLine]
|
||||
for (instr <- code) {
|
||||
if (instr.isPrintable) {
|
||||
if (options.flag(CompilationFlag.UseIntelSyntaxForOutput)) {
|
||||
if(lastSource != instr.source) {
|
||||
lastSource = instr.source
|
||||
if (printLineNumbers) {
|
||||
lastSource match {
|
||||
case Some(SourceLine(moduleName, line)) if line > 0 =>
|
||||
assOut.append(s";line:$line:$moduleName")
|
||||
case _ =>
|
||||
assOut.append(s";line")
|
||||
}
|
||||
}
|
||||
}
|
||||
val line = if (options.flag(CompilationFlag.UseIntelSyntaxForOutput)) {
|
||||
instr match {
|
||||
case zline: ZLine =>
|
||||
assOut.append(zline.toIntelString)
|
||||
zline.toIntelString
|
||||
case _ =>
|
||||
assOut.append(instr.toString)
|
||||
instr.toString
|
||||
}
|
||||
} else {
|
||||
assOut.append(instr.toString)
|
||||
instr.toString
|
||||
}
|
||||
if (line.contains("; @")) {
|
||||
assOut.append(FinalWhitespace.replaceAllIn(line.substring(0, line.lastIndexOf("; @")), ""))
|
||||
} else {
|
||||
assOut.append(line)
|
||||
}
|
||||
}
|
||||
index = emitInstruction(bank, options, index, instr)
|
||||
}
|
||||
if (printLineNumbers && lastSource.isDefined){
|
||||
assOut.append(s";line")
|
||||
}
|
||||
index
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
package millfork.output
|
||||
|
||||
import millfork.JobContext
|
||||
import millfork.assembly.AbstractCode
|
||||
import millfork.assembly.{AbstractCode, Elidability}
|
||||
import millfork.assembly.mos.Opcode
|
||||
import millfork.assembly.z80.ZOpcode
|
||||
import millfork.compiler.AbstractCompiler
|
||||
@ -72,8 +72,8 @@ abstract class AbstractInliningCalculator[T <: AbstractCode] {
|
||||
case s: ArrayContents => getAllCalledFunctions(s.getAllExpressions)
|
||||
case s: FunctionDeclarationStatement => getAllCalledFunctions(s.address.toList) ++ getAllCalledFunctions(s.statements.getOrElse(Nil))
|
||||
case Assignment(VariableExpression(_), expr) => getAllCalledFunctions(expr :: Nil)
|
||||
case MosAssemblyStatement(Opcode.JSR, _, VariableExpression(name), true) => (name -> false) :: Nil
|
||||
case Z80AssemblyStatement(ZOpcode.CALL, _, _, VariableExpression(name), true) => (name -> false) :: Nil
|
||||
case MosAssemblyStatement(Opcode.JSR, _, VariableExpression(name), Elidability.Elidable) => (name -> false) :: Nil
|
||||
case Z80AssemblyStatement(ZOpcode.CALL, _, _, VariableExpression(name), Elidability.Elidable) => (name -> false) :: Nil
|
||||
case s: Statement => getAllCalledFunctions(s.getAllExpressions)
|
||||
case s: VariableExpression => Set(
|
||||
s.name,
|
||||
|
@ -6,7 +6,7 @@ import millfork.env._
|
||||
import millfork.error.{ConsoleLogger, FatalErrorReporting}
|
||||
import millfork.node.{MosNiceFunctionProperty, NiceFunctionProperty, Program}
|
||||
import millfork._
|
||||
import millfork.assembly.mos.{AddrMode, AssemblyLine, Opcode, OpcodeClasses}
|
||||
import millfork.assembly.mos._
|
||||
import millfork.compiler.mos.MosCompiler
|
||||
|
||||
import scala.annotation.tailrec
|
||||
@ -33,32 +33,32 @@ class MosAssembler(program: Program,
|
||||
import millfork.assembly.mos.AddrMode._
|
||||
import millfork.assembly.mos.Opcode._
|
||||
instr match {
|
||||
case AssemblyLine(BYTE, RawByte, c, _) =>
|
||||
case AssemblyLine0(BYTE, RawByte, c) =>
|
||||
writeByte(bank, index, c)
|
||||
index + 1
|
||||
case AssemblyLine(BYTE, _, _, _) => log.fatal("BYTE opcode failure")
|
||||
case AssemblyLine(_, RawByte, _, _) => log.fatal("BYTE opcode failure")
|
||||
case AssemblyLine(LABEL, _, MemoryAddressConstant(Label(labelName)), _) =>
|
||||
case AssemblyLine0(BYTE, _, _) => log.fatal("BYTE opcode failure")
|
||||
case AssemblyLine0(_, RawByte, _) => log.fatal("BYTE opcode failure")
|
||||
case AssemblyLine0(LABEL, _, MemoryAddressConstant(Label(labelName))) =>
|
||||
labelMap(labelName) = index
|
||||
index
|
||||
case AssemblyLine(_, DoesNotExist, _, _) =>
|
||||
case AssemblyLine0(_, DoesNotExist, _) =>
|
||||
index
|
||||
case AssemblyLine(op, Implied, _, _) =>
|
||||
case AssemblyLine0(op, Implied, _) =>
|
||||
writeByte(bank, index, MosAssembler.opcodeFor(op, Implied, options))
|
||||
index + 1
|
||||
case AssemblyLine(op, Relative, param, _) =>
|
||||
case AssemblyLine0(op, Relative, param) =>
|
||||
writeByte(bank, index, MosAssembler.opcodeFor(op, Relative, options))
|
||||
writeByte(bank, index + 1, AssertByte(param - (index + 2)))
|
||||
index + 2
|
||||
case AssemblyLine(op, am@(Immediate | ZeroPage | ZeroPageX | ZeroPageY | IndexedY | IndexedX | IndexedZ | LongIndexedY | LongIndexedZ | Stack), param, _) =>
|
||||
case AssemblyLine0(op, am@(Immediate | ZeroPage | ZeroPageX | ZeroPageY | IndexedY | IndexedX | IndexedZ | LongIndexedY | LongIndexedZ | Stack), param) =>
|
||||
writeByte(bank, index, MosAssembler.opcodeFor(op, am, options))
|
||||
writeByte(bank, index + 1, param)
|
||||
index + 2
|
||||
case AssemblyLine(op, am@(WordImmediate | Absolute | AbsoluteY | AbsoluteX | Indirect | AbsoluteIndexedX), param, _) =>
|
||||
case AssemblyLine0(op, am@(WordImmediate | Absolute | AbsoluteY | AbsoluteX | Indirect | AbsoluteIndexedX), param) =>
|
||||
writeByte(bank, index, MosAssembler.opcodeFor(op, am, options))
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case AssemblyLine(op, am@(LongAbsolute | LongAbsoluteX | LongIndirect), param, _) =>
|
||||
case AssemblyLine0(op, am@(LongAbsolute | LongAbsoluteX | LongIndirect), param) =>
|
||||
writeByte(bank, index, MosAssembler.opcodeFor(op, am, options))
|
||||
writeWord(bank, index + 1, param)
|
||||
writeByte(bank, index + 3, extractBank(param, options))
|
||||
@ -76,7 +76,7 @@ class MosAssembler(program: Program,
|
||||
BIT |
|
||||
ADC | SBC | AND | ORA | EOR |
|
||||
INC | DEC | ROL | ROR | ASL | LSR |
|
||||
ISC | DCP | LAX | SAX | RLA | RRA | SLO | SRE, AddrMode.Absolute, p, true) =>
|
||||
ISC | DCP | LAX | SAX | RLA | RRA | SLO | SRE, AddrMode.Absolute, p, Elidability.Elidable, _) =>
|
||||
p match {
|
||||
case NumericConstant(n, _) => if (n <= 255) l.copy(addrMode = AddrMode.ZeroPage) else l
|
||||
case MemoryAddressConstant(th) => if (labelMap.getOrElse(th.name, 0x800) < 0x100) l.copy(addrMode = AddrMode.ZeroPage) else l
|
||||
@ -95,8 +95,8 @@ class MosAssembler(program: Program,
|
||||
import Opcode._
|
||||
import AddrMode._
|
||||
code match {
|
||||
case AssemblyLine(JMP | JSR | BSR, Indirect | LongIndirect | AbsoluteIndexedX, _, _) :: _ => true
|
||||
case AssemblyLine(PHA, _, _, _) :: AssemblyLine(RTS | RTL, _, _, _) :: _ => true
|
||||
case AssemblyLine0(JMP | JSR | BSR, Indirect | LongIndirect | AbsoluteIndexedX, _) :: _ => true
|
||||
case AssemblyLine0(PHA, _, _) :: AssemblyLine0(RTS | RTL, _, _) :: _ => true
|
||||
case _ :: xs => isNaughty(xs)
|
||||
case Nil => false
|
||||
}
|
||||
@ -109,15 +109,15 @@ class MosAssembler(program: Program,
|
||||
import NiceFunctionProperty._
|
||||
if (isNaughty(code)) return
|
||||
val localLabels = code.flatMap {
|
||||
case AssemblyLine(LABEL, _, MemoryAddressConstant(Label(l)), _) => Some(l)
|
||||
case AssemblyLine0(LABEL, _, MemoryAddressConstant(Label(l))) => Some(l)
|
||||
case _ => None
|
||||
}.toSet
|
||||
def genericPropertyScan(niceFunctionProperty: NiceFunctionProperty)(predicate: AssemblyLine => Boolean): Unit = {
|
||||
val preserved = code.forall {
|
||||
case AssemblyLine(JSR | BSR | JMP, Absolute | LongAbsolute, MemoryAddressConstant(th), _) => niceFunctionProperties(niceFunctionProperty -> th.name)
|
||||
case AssemblyLine(JSR | BSR, _, _, _) => false
|
||||
case AssemblyLine(op, _, MemoryAddressConstant(Label(label)), _) if OpcodeClasses.AllDirectJumps(op) => localLabels(label)
|
||||
case AssemblyLine(op, _, _, _) if OpcodeClasses.AllDirectJumps(op) => false
|
||||
case AssemblyLine0(JSR | BSR | JMP, Absolute | LongAbsolute, MemoryAddressConstant(th)) => niceFunctionProperties(niceFunctionProperty -> th.name)
|
||||
case AssemblyLine0(JSR | BSR, _, _) => false
|
||||
case AssemblyLine0(op, _, MemoryAddressConstant(Label(label))) if OpcodeClasses.AllDirectJumps(op) => localLabels(label)
|
||||
case AssemblyLine0(op, _, _) if OpcodeClasses.AllDirectJumps(op) => false
|
||||
case l => predicate(l)
|
||||
}
|
||||
if (preserved) {
|
||||
@ -125,47 +125,47 @@ class MosAssembler(program: Program,
|
||||
}
|
||||
}
|
||||
genericPropertyScan(DoesntChangeX) {
|
||||
case AssemblyLine(op, _, _, _) => !OpcodeClasses.ChangesX(op)
|
||||
case AssemblyLine0(op, _, _) => !OpcodeClasses.ChangesX(op)
|
||||
}
|
||||
genericPropertyScan(DoesntChangeY) {
|
||||
case AssemblyLine(op, _, _, _) => !OpcodeClasses.ChangesY(op)
|
||||
case AssemblyLine0(op, _, _) => !OpcodeClasses.ChangesY(op)
|
||||
}
|
||||
genericPropertyScan(DoesntChangeA) {
|
||||
case AssemblyLine(op, _, _, _) if OpcodeClasses.ChangesAAlways(op) => false
|
||||
case AssemblyLine(op, _, Implied, _) if OpcodeClasses.ChangesAIfImplied(op) => false
|
||||
case AssemblyLine0(op, _, _) if OpcodeClasses.ChangesAAlways(op) => false
|
||||
case AssemblyLine0(op, _, Implied) if OpcodeClasses.ChangesAIfImplied(op) => false
|
||||
case _ => true
|
||||
}
|
||||
genericPropertyScan(DoesntChangeIZ) {
|
||||
case AssemblyLine(op, _, _, _) => !OpcodeClasses.ChangesIZ(op)
|
||||
case AssemblyLine0(op, _, _) => !OpcodeClasses.ChangesIZ(op)
|
||||
}
|
||||
genericPropertyScan(DoesntChangeAH) {
|
||||
case AssemblyLine(op, _, _, _) if OpcodeClasses.ChangesAHAlways(op) => false
|
||||
case AssemblyLine(op, _, Implied, _) if OpcodeClasses.ChangesAHIfImplied(op) => false
|
||||
case AssemblyLine0(op, _, _) if OpcodeClasses.ChangesAHAlways(op) => false
|
||||
case AssemblyLine0(op, _, Implied) if OpcodeClasses.ChangesAHIfImplied(op) => false
|
||||
case _ => true
|
||||
}
|
||||
genericPropertyScan(DoesntChangeC) {
|
||||
case AssemblyLine(SEP | REP, Immediate, NumericConstant(imm, _), _) => (imm & 1) == 0
|
||||
case AssemblyLine(SEP | REP, _, _, _) => false
|
||||
case AssemblyLine(op, _, _, _) => !OpcodeClasses.ChangesC(op)
|
||||
case AssemblyLine0(SEP | REP, Immediate, NumericConstant(imm, _)) => (imm & 1) == 0
|
||||
case AssemblyLine0(SEP | REP, _, _) => false
|
||||
case AssemblyLine0(op, _, _) => !OpcodeClasses.ChangesC(op)
|
||||
}
|
||||
genericPropertyScan(DoesntConcernD) {
|
||||
case AssemblyLine(SEP | REP, Immediate, NumericConstant(imm, _), _) => (imm & 8) == 0
|
||||
case AssemblyLine(SEP | REP, _, _, _) => false
|
||||
case AssemblyLine(op, _, _, _) => !OpcodeClasses.ReadsD(op) && !OpcodeClasses.OverwritesD(op)
|
||||
case AssemblyLine0(SEP | REP, Immediate, NumericConstant(imm, _)) => (imm & 8) == 0
|
||||
case AssemblyLine0(SEP | REP, _, _) => false
|
||||
case AssemblyLine0(op, _, _) => !OpcodeClasses.ReadsD(op) && !OpcodeClasses.OverwritesD(op)
|
||||
}
|
||||
genericPropertyScan(DoesntReadMemory) {
|
||||
case AssemblyLine(op, Implied | Immediate | WordImmediate, _, _) => true
|
||||
case AssemblyLine(op, _, _, _) if OpcodeClasses.ReadsMemoryIfNotImpliedOrImmediate(op) => false
|
||||
case AssemblyLine0(op, Implied | Immediate | WordImmediate, _) => true
|
||||
case AssemblyLine0(op, _, _) if OpcodeClasses.ReadsMemoryIfNotImpliedOrImmediate(op) => false
|
||||
case _ => true
|
||||
}
|
||||
genericPropertyScan(DoesntWriteMemory) {
|
||||
case AssemblyLine(op, Implied | Immediate | WordImmediate, _, _) => true
|
||||
case AssemblyLine(op, _, _, _) if OpcodeClasses.ChangesMemoryIfNotImplied(op) || OpcodeClasses.ChangesMemoryAlways(op) => false
|
||||
case AssemblyLine0(op, Implied | Immediate | WordImmediate, _) => true
|
||||
case AssemblyLine0(op, _, _) if OpcodeClasses.ChangesMemoryIfNotImplied(op) || OpcodeClasses.ChangesMemoryAlways(op) => false
|
||||
case _ => true
|
||||
}
|
||||
genericPropertyScan(IsLeaf) {
|
||||
case AssemblyLine(JSR | BSR, Implied | Immediate | WordImmediate, _, _) => false
|
||||
case AssemblyLine(JMP, Absolute, th:Thing, _) => th.name.startsWith(".")
|
||||
case AssemblyLine0(JSR | BSR, Implied | Immediate | WordImmediate, _) => false
|
||||
case AssemblyLine0(JMP, Absolute, th:Thing) => th.name.startsWith(".")
|
||||
case _ => true
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package millfork.output
|
||||
|
||||
import millfork.CompilationOptions
|
||||
import millfork.assembly.mos.{AddrMode, AssemblyLine, Opcode, OpcodeClasses}
|
||||
import millfork.assembly.mos._
|
||||
import millfork.env.{Environment, Label, MemoryAddressConstant}
|
||||
import Opcode._
|
||||
import millfork.assembly.mos.AddrMode._
|
||||
@ -13,7 +13,7 @@ import scala.collection.mutable
|
||||
*/
|
||||
class MosDeduplicate(env: Environment, options: CompilationOptions) extends Deduplicate[AssemblyLine](env, options) {
|
||||
override def getJump(line: AssemblyLine): Option[String] = line match {
|
||||
case AssemblyLine(Opcode.JMP, Absolute, MemoryAddressConstant(thing), _) => Some(thing.name)
|
||||
case AssemblyLine0(Opcode.JMP, Absolute, MemoryAddressConstant(thing)) => Some(thing.name)
|
||||
case _ => None
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ class MosDeduplicate(env: Environment, options: CompilationOptions) extends Dedu
|
||||
|
||||
override def actualCode(FunctionName: String, functionCode: List[AssemblyLine]): List[AssemblyLine] = {
|
||||
functionCode match {
|
||||
case AssemblyLine(Opcode.LABEL, _, MemoryAddressConstant(Label(FunctionName)), _) :: xs => xs
|
||||
case AssemblyLine0(Opcode.LABEL, _, MemoryAddressConstant(Label(FunctionName))) :: xs => xs
|
||||
case xs => xs
|
||||
}
|
||||
}
|
||||
@ -63,14 +63,14 @@ class MosDeduplicate(env: Environment, options: CompilationOptions) extends Dedu
|
||||
|
||||
def rtsPrecededByDiscards(xs: List[AssemblyLine]): Option[List[AssemblyLine]] = {
|
||||
xs match {
|
||||
case AssemblyLine(op, _, _, _) :: xs if OpcodeClasses.NoopDiscardsFlags(op) => rtsPrecededByDiscards(xs)
|
||||
case AssemblyLine(RTS, _, _, _) :: xs => Some(xs)
|
||||
case AssemblyLine0(op, _, _) :: xs if OpcodeClasses.NoopDiscardsFlags(op) => rtsPrecededByDiscards(xs)
|
||||
case AssemblyLine0(RTS, _, _) :: xs => Some(xs)
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
|
||||
override def tco(code: List[AssemblyLine]): List[AssemblyLine] = code match {
|
||||
case (call@AssemblyLine(JSR, Absolute | LongAbsolute, _, _)) :: xs => rtsPrecededByDiscards(xs) match {
|
||||
case (call@AssemblyLine0(JSR, Absolute | LongAbsolute, _)) :: xs => rtsPrecededByDiscards(xs) match {
|
||||
case Some(rest) => call.copy(opcode = JMP) :: tco(rest)
|
||||
case _ => call :: tco(xs)
|
||||
}
|
||||
@ -82,13 +82,13 @@ class MosDeduplicate(env: Environment, options: CompilationOptions) extends Dedu
|
||||
val map = mutable.Map[String, String]()
|
||||
var counter = 0
|
||||
code.foreach{
|
||||
case AssemblyLine(LABEL, _, MemoryAddressConstant(Label(x)), _) if x.startsWith(".") =>
|
||||
case AssemblyLine0(LABEL, _, MemoryAddressConstant(Label(x))) if x.startsWith(".") =>
|
||||
map(x) = if (temporary) ".ddtmp__" + counter else env.nextLabel("dd")
|
||||
counter += 1
|
||||
case _ =>
|
||||
}
|
||||
code.map{
|
||||
case l@AssemblyLine(_, _, MemoryAddressConstant(Label(x)), _) if map.contains(x) =>
|
||||
case l@AssemblyLine0(_, _, MemoryAddressConstant(Label(x))) if map.contains(x) =>
|
||||
l.copy(parameter = MemoryAddressConstant(Label(map(x))))
|
||||
case l => l
|
||||
}
|
||||
@ -98,14 +98,14 @@ class MosDeduplicate(env: Environment, options: CompilationOptions) extends Dedu
|
||||
val myLabels = mutable.Set[String]()
|
||||
val useCount = mutable.Map[String, Int]()
|
||||
snippet.foreach{
|
||||
case AssemblyLine(LABEL, _, MemoryAddressConstant(Label(x)), _) =>
|
||||
case AssemblyLine0(LABEL, _, MemoryAddressConstant(Label(x))) =>
|
||||
myLabels += x
|
||||
case AssemblyLine(_, _, MemoryAddressConstant(Label(x)), _) =>
|
||||
case AssemblyLine0(_, _, MemoryAddressConstant(Label(x))) =>
|
||||
useCount(x) = useCount.getOrElse(x, 0) - 1
|
||||
case _ =>
|
||||
}
|
||||
wholeCode.foreach {
|
||||
case AssemblyLine(op, _, MemoryAddressConstant(Label(x)), _) if op != LABEL && myLabels(x) =>
|
||||
case AssemblyLine0(op, _, MemoryAddressConstant(Label(x))) if op != LABEL && myLabels(x) =>
|
||||
useCount(x) = useCount.getOrElse(x, 0) + 1
|
||||
case _ =>
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package millfork.output
|
||||
|
||||
import millfork.JobContext
|
||||
import millfork.assembly.Elidability
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.mos.{AddrMode, _}
|
||||
import millfork.compiler.AbstractCompiler
|
||||
@ -23,13 +24,13 @@ object MosInliningCalculator extends AbstractInliningCalculator[AssemblyLine] {
|
||||
def codeForInlining(fname: String, functionsThatCanBeCalledFromInlinedFunctions: Set[String], code: List[AssemblyLine]): Option[List[AssemblyLine]] = {
|
||||
if (code.isEmpty) return None
|
||||
val localLabels = code.flatMap{
|
||||
case AssemblyLine(LABEL, _, MemoryAddressConstant(Label(l)), _) => Some(l)
|
||||
case AssemblyLine0(LABEL, _, MemoryAddressConstant(Label(l))) => Some(l)
|
||||
case _ => None
|
||||
}
|
||||
val lastLineOfCode = code.last
|
||||
lastLineOfCode match {
|
||||
case AssemblyLine(RTS | RTL, _, _, _) =>
|
||||
case AssemblyLine(JMP, AddrMode.Absolute, _, _) =>
|
||||
case AssemblyLine0(RTS | RTL, _, _) =>
|
||||
case AssemblyLine0(JMP, AddrMode.Absolute, _) =>
|
||||
case _ => return None
|
||||
}
|
||||
var result = code.init
|
||||
@ -41,20 +42,20 @@ object MosInliningCalculator extends AbstractInliningCalculator[AssemblyLine] {
|
||||
}
|
||||
if (result.head.opcode == LABEL && result.head.parameter == Label(fname).toAddress) result = result.tail
|
||||
if (result.exists{
|
||||
case AssemblyLine(op, AddrMode.Absolute | AddrMode.Relative | AddrMode.DoesNotExist, MemoryAddressConstant(Label(l)), _) if jumpingRelatedOpcodes(op) =>
|
||||
case AssemblyLine0(op, AddrMode.Absolute | AddrMode.Relative | AddrMode.DoesNotExist, MemoryAddressConstant(Label(l))) if jumpingRelatedOpcodes(op) =>
|
||||
if (!localLabels.contains(l) && !l.startsWith(".")) {
|
||||
println("Bad jump " + l)
|
||||
// println("Bad jump " + l)
|
||||
true
|
||||
} else false
|
||||
case AssemblyLine(JSR, AddrMode.Absolute, MemoryAddressConstant(th:ExternFunction), _) =>
|
||||
case AssemblyLine0(JSR, AddrMode.Absolute, MemoryAddressConstant(th:ExternFunction)) =>
|
||||
false
|
||||
case AssemblyLine(JSR, AddrMode.Absolute, MemoryAddressConstant(th:NormalFunction), _) =>
|
||||
case AssemblyLine0(JSR, AddrMode.Absolute, MemoryAddressConstant(th:NormalFunction)) =>
|
||||
if(!functionsThatCanBeCalledFromInlinedFunctions(th.name)){
|
||||
println("Bad call " + th)
|
||||
// println("Bad call " + th)
|
||||
true
|
||||
} else false
|
||||
case AssemblyLine(op, _, _, _) if jumpingRelatedOpcodes(op) || badOpcodes(op) =>
|
||||
println("Bad opcode " + op)
|
||||
case AssemblyLine0(op, _, _) if jumpingRelatedOpcodes(op) || badOpcodes(op) =>
|
||||
// println("Bad opcode " + op)
|
||||
true
|
||||
case _ => false
|
||||
}) return None
|
||||
@ -63,18 +64,18 @@ object MosInliningCalculator extends AbstractInliningCalculator[AssemblyLine] {
|
||||
|
||||
def inline(code: List[AssemblyLine], inlinedFunctions: Map[String, List[AssemblyLine]], jobContext: JobContext): List[AssemblyLine] = {
|
||||
code.flatMap {
|
||||
case AssemblyLine(Opcode.JSR, AddrMode.Absolute | AddrMode.LongAbsolute, p, true) if inlinedFunctions.contains(p.toString) =>
|
||||
case AssemblyLine(Opcode.JSR, AddrMode.Absolute | AddrMode.LongAbsolute, p, Elidability.Elidable, _) if inlinedFunctions.contains(p.toString) =>
|
||||
val labelPrefix = jobContext.nextLabel("ai")
|
||||
inlinedFunctions(p.toString).map {
|
||||
case line@AssemblyLine(_, _, MemoryAddressConstant(Label(label)), _) =>
|
||||
case line@AssemblyLine0(_, _, MemoryAddressConstant(Label(label))) =>
|
||||
val newLabel = MemoryAddressConstant(Label(labelPrefix + label))
|
||||
line.copy(parameter = newLabel)
|
||||
case l => l
|
||||
}
|
||||
case AssemblyLine(Opcode.JMP, AddrMode.Absolute, p, true) if inlinedFunctions.contains(p.toString) =>
|
||||
case AssemblyLine(Opcode.JMP, AddrMode.Absolute, p, Elidability.Elidable, _) if inlinedFunctions.contains(p.toString) =>
|
||||
val labelPrefix = jobContext.nextLabel("ai")
|
||||
inlinedFunctions(p.toString).map {
|
||||
case line@AssemblyLine(_, _, MemoryAddressConstant(Label(label)), _) =>
|
||||
case line@AssemblyLine0(_, _, MemoryAddressConstant(Label(label))) =>
|
||||
val newLabel = MemoryAddressConstant(Label(labelPrefix + label))
|
||||
line.copy(parameter = newLabel)
|
||||
case l => l
|
||||
|
@ -68,24 +68,24 @@ class Z80Assembler(program: Program,
|
||||
}
|
||||
|
||||
try { instr match {
|
||||
case ZLine(LABEL, NoRegisters, MemoryAddressConstant(Label(labelName)), _) =>
|
||||
case ZLine0(LABEL, NoRegisters, MemoryAddressConstant(Label(labelName))) =>
|
||||
labelMap(labelName) = index
|
||||
index
|
||||
case ZLine(BYTE, NoRegisters, param, _) =>
|
||||
case ZLine0(BYTE, NoRegisters, param) =>
|
||||
writeByte(bank, index, param)
|
||||
index + 1
|
||||
case ZLine(DISCARD_F | DISCARD_HL | DISCARD_BC | DISCARD_DE | DISCARD_IX | DISCARD_IY | DISCARD_A, NoRegisters, _, _) =>
|
||||
case ZLine0(DISCARD_F | DISCARD_HL | DISCARD_BC | DISCARD_DE | DISCARD_IX | DISCARD_IY | DISCARD_A, NoRegisters, _) =>
|
||||
index
|
||||
case ZLine(LABEL | BYTE | DISCARD_F | DISCARD_HL | DISCARD_BC | DISCARD_DE | DISCARD_IX | DISCARD_IY | DISCARD_A, _, _, _) =>
|
||||
case ZLine0(LABEL | BYTE | DISCARD_F | DISCARD_HL | DISCARD_BC | DISCARD_DE | DISCARD_IX | DISCARD_IY | DISCARD_A, _, _) =>
|
||||
???
|
||||
case ZLine(RST, NoRegisters, param, _) =>
|
||||
case ZLine0(RST, NoRegisters, param) =>
|
||||
val opcode = param.quickSimplify match {
|
||||
case NumericConstant(n, _) if n >=0 && n <= 0x38 && n % 8 == 0 => 0xc7 + n.toInt
|
||||
case _ => log.error("Invalid param for RST"); 0xc7
|
||||
}
|
||||
writeByte(bank, index, opcode)
|
||||
index + 1
|
||||
case ZLine(IM, NoRegisters, param, _) =>
|
||||
case ZLine0(IM, NoRegisters, param) =>
|
||||
requireZ80()
|
||||
val opcode = param.quickSimplify match {
|
||||
case NumericConstant(0, _) => 0x46
|
||||
@ -96,23 +96,23 @@ class Z80Assembler(program: Program,
|
||||
writeByte(bank, index, 0xED)
|
||||
writeByte(bank, index + 1, opcode)
|
||||
index + 2
|
||||
case ZLine(op, OneRegister(reg), _, _) if ZOpcodeClasses.AllSingleBit(op) =>
|
||||
case ZLine0(op, OneRegister(reg), _) if ZOpcodeClasses.AllSingleBit(op) =>
|
||||
requireExtended80()
|
||||
writeByte(bank, index, 0xcb)
|
||||
writeByte(bank, index + 1, ZOpcodeClasses.singleBitOpcode(op) + internalRegisterIndex(reg))
|
||||
index + 2
|
||||
case ZLine(op, NoRegisters, _, _) if implieds.contains(op) =>
|
||||
case ZLine0(op, NoRegisters, _) if implieds.contains(op) =>
|
||||
writeByte(bank, index, implieds(op))
|
||||
index + 1
|
||||
case ZLine(EXX, NoRegisters, _, _)=>
|
||||
case ZLine0(EXX, NoRegisters, _)=>
|
||||
requireZ80()
|
||||
writeByte(bank, index, 0xd9)
|
||||
index + 1
|
||||
case ZLine(EX_AF_AF, NoRegisters, _, _)=>
|
||||
case ZLine0(EX_AF_AF, NoRegisters, _)=>
|
||||
requireZ80()
|
||||
writeByte(bank, index, 8)
|
||||
index + 1
|
||||
case ZLine(RETI, NoRegisters, _, _) =>
|
||||
case ZLine0(RETI, NoRegisters, _) =>
|
||||
requireExtended80()
|
||||
if (useSharpOpcodes()) {
|
||||
writeByte(bank, index, 0xd9)
|
||||
@ -122,15 +122,15 @@ class Z80Assembler(program: Program,
|
||||
writeByte(bank, index + 1, 0x4d)
|
||||
index + 2
|
||||
}
|
||||
case ZLine(op, NoRegisters, _, _) if edImplieds.contains(op) =>
|
||||
case ZLine0(op, NoRegisters, _) if edImplieds.contains(op) =>
|
||||
requireZ80()
|
||||
writeByte(bank, index, 0xed)
|
||||
writeByte(bank, index + 1, edImplieds(op))
|
||||
index + 2
|
||||
case ZLine(ADD_16, TwoRegisters(ZRegister.HL, source), _, _) =>
|
||||
case ZLine0(ADD_16, TwoRegisters(ZRegister.HL, source), _) =>
|
||||
writeByte(bank, index, 9 + 16 * internalRegisterIndex(source))
|
||||
index + 1
|
||||
case ZLine(ADD_16, TwoRegisters(ix@(ZRegister.IX | ZRegister.IY), source@(ZRegister.IX | ZRegister.IY)), _, _)=>
|
||||
case ZLine0(ADD_16, TwoRegisters(ix@(ZRegister.IX | ZRegister.IY), source@(ZRegister.IX | ZRegister.IY)), _)=>
|
||||
requireZ80()
|
||||
if (ix == source) {
|
||||
writeByte(bank, index, prefixByte(ix))
|
||||
@ -140,60 +140,60 @@ class Z80Assembler(program: Program,
|
||||
log.fatal("Cannot assemble " + instr)
|
||||
index
|
||||
}
|
||||
case ZLine(ADD_16, TwoRegisters(ix@(ZRegister.IX | ZRegister.IY), source), _, _) =>
|
||||
case ZLine0(ADD_16, TwoRegisters(ix@(ZRegister.IX | ZRegister.IY), source), _) =>
|
||||
requireZ80()
|
||||
writeByte(bank, index, prefixByte(ix))
|
||||
writeByte(bank, index + 1, 9 + 16 * internalRegisterIndex(source))
|
||||
index + 2
|
||||
case ZLine(ADC_16, TwoRegisters(ZRegister.HL, reg), _, _) =>
|
||||
case ZLine0(ADC_16, TwoRegisters(ZRegister.HL, reg), _) =>
|
||||
requireZ80()
|
||||
writeByte(bank, index, 0xed)
|
||||
writeByte(bank, index + 1, 0x4a + 0x10 * internalRegisterIndex(reg))
|
||||
index + 2
|
||||
case ZLine(SBC_16, TwoRegisters(ZRegister.HL, reg), _, _) =>
|
||||
case ZLine0(SBC_16, TwoRegisters(ZRegister.HL, reg), _) =>
|
||||
requireZ80()
|
||||
writeByte(bank, index, 0xed)
|
||||
writeByte(bank, index + 1, 0x42 + 0x10 * internalRegisterIndex(reg))
|
||||
index + 2
|
||||
case ZLine(LD_16, TwoRegisters(ix@(ZRegister.IX | ZRegister.IY), ZRegister.IMM_16), param, _) =>
|
||||
case ZLine0(LD_16, TwoRegisters(ix@(ZRegister.IX | ZRegister.IY), ZRegister.IMM_16), param) =>
|
||||
requireZ80()
|
||||
writeByte(bank, index, prefixByte(ix))
|
||||
writeByte(bank, index + 1, 0x21)
|
||||
writeWord(bank, index + 2, param)
|
||||
index + 4
|
||||
case ZLine(LD_16, TwoRegisters(target, ZRegister.IMM_16), param, _) =>
|
||||
case ZLine0(LD_16, TwoRegisters(target, ZRegister.IMM_16), param) =>
|
||||
writeByte(bank, index, 1 + 16 * internalRegisterIndex(target))
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(LD_16, TwoRegisters(ix@(ZRegister.IX | ZRegister.IY), ZRegister.MEM_ABS_16), param, _) =>
|
||||
case ZLine0(LD_16, TwoRegisters(ix@(ZRegister.IX | ZRegister.IY), ZRegister.MEM_ABS_16), param) =>
|
||||
requireZ80()
|
||||
writeByte(bank, index, prefixByte(ix))
|
||||
writeByte(bank, index + 1, 0x2a)
|
||||
writeWord(bank, index + 2, param)
|
||||
index + 4
|
||||
case ZLine(LD_16, TwoRegisters(ZRegister.MEM_ABS_16, ix@(ZRegister.IX | ZRegister.IY)), param, _) =>
|
||||
case ZLine0(LD_16, TwoRegisters(ZRegister.MEM_ABS_16, ix@(ZRegister.IX | ZRegister.IY)), param) =>
|
||||
requireZ80()
|
||||
writeByte(bank, index, prefixByte(ix))
|
||||
writeByte(bank, index + 1, 0x22)
|
||||
writeWord(bank, index + 2, param)
|
||||
index + 4
|
||||
case ZLine(LD_16, TwoRegisters(ZRegister.HL, ZRegister.MEM_ABS_16), param, _) =>
|
||||
case ZLine0(LD_16, TwoRegisters(ZRegister.HL, ZRegister.MEM_ABS_16), param) =>
|
||||
requireIntel8080()
|
||||
writeByte(bank, index, 0x2a)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(LD_16, TwoRegisters(ZRegister.MEM_ABS_16, ZRegister.HL), param, _) =>
|
||||
case ZLine0(LD_16, TwoRegisters(ZRegister.MEM_ABS_16, ZRegister.HL), param) =>
|
||||
requireIntel8080()
|
||||
writeByte(bank, index, 0x22)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(LD_16, TwoRegisters(reg@(ZRegister.BC | ZRegister.DE | ZRegister.SP), ZRegister.MEM_ABS_16), param, _) =>
|
||||
case ZLine0(LD_16, TwoRegisters(reg@(ZRegister.BC | ZRegister.DE | ZRegister.SP), ZRegister.MEM_ABS_16), param) =>
|
||||
requireZ80()
|
||||
writeByte(bank, index, 0xed)
|
||||
writeByte(bank, index+1, 0x4b + 0x10 * internalRegisterIndex(reg))
|
||||
writeWord(bank, index + 2, param)
|
||||
index + 4
|
||||
case ZLine(LD_16, TwoRegisters(ZRegister.MEM_ABS_16, ZRegister.SP), param, _) =>
|
||||
case ZLine0(LD_16, TwoRegisters(ZRegister.MEM_ABS_16, ZRegister.SP), param) =>
|
||||
requireExtended80()
|
||||
if (useSharpOpcodes()) {
|
||||
writeByte(bank, index, 8)
|
||||
@ -205,74 +205,74 @@ class Z80Assembler(program: Program,
|
||||
writeWord(bank, index + 2, param)
|
||||
index + 4
|
||||
}
|
||||
case ZLine(LD_16, TwoRegisters(ZRegister.MEM_ABS_16, reg@(ZRegister.BC | ZRegister.DE)), param, _) =>
|
||||
case ZLine0(LD_16, TwoRegisters(ZRegister.MEM_ABS_16, reg@(ZRegister.BC | ZRegister.DE)), param) =>
|
||||
requireZ80()
|
||||
writeByte(bank, index, 0xed)
|
||||
writeByte(bank, index+1, 0x43 + 0x10 * internalRegisterIndex(reg))
|
||||
writeWord(bank, index + 2, param)
|
||||
index + 4
|
||||
case ZLine(LD_16, TwoRegisters(ZRegister.SP, ZRegister.HL), _, _) =>
|
||||
case ZLine0(LD_16, TwoRegisters(ZRegister.SP, ZRegister.HL), _) =>
|
||||
writeByte(bank, index, 0xF9)
|
||||
index + 1
|
||||
case ZLine(LD_16, TwoRegisters(ZRegister.SP, ix@(ZRegister.IX | ZRegister.IY)), _, _) =>
|
||||
case ZLine0(LD_16, TwoRegisters(ZRegister.SP, ix@(ZRegister.IX | ZRegister.IY)), _) =>
|
||||
requireZ80()
|
||||
writeByte(bank, index, prefixByte(ix))
|
||||
writeByte(bank, index + 1, 0xF9)
|
||||
index + 2
|
||||
case ZLine(op, OneRegister(ZRegister.IMM_8), param, _) if immediates.contains(op) =>
|
||||
case ZLine0(op, OneRegister(ZRegister.IMM_8), param) if immediates.contains(op) =>
|
||||
val o = immediates(op)
|
||||
writeByte(bank, index, o)
|
||||
writeByte(bank, index + 1, param)
|
||||
index + 2
|
||||
case ZLine(op, OneRegisterOffset(ix@(ZRegister.MEM_IX_D | ZRegister.MEM_IY_D), offset), _, _) if ZOpcodeClasses.AllSingleBit(op) =>
|
||||
case ZLine0(op, OneRegisterOffset(ix@(ZRegister.MEM_IX_D | ZRegister.MEM_IY_D), offset), _) if ZOpcodeClasses.AllSingleBit(op) =>
|
||||
requireZ80()
|
||||
writeByte(bank, index, prefixByte(ix))
|
||||
writeByte(bank, index + 1, 0xcb)
|
||||
writeByte(bank, index + 2, offset)
|
||||
writeByte(bank, index + 3, ZOpcodeClasses.singleBitOpcode(op) + internalRegisterIndex(ZRegister.MEM_HL))
|
||||
index + 4
|
||||
case ZLine(op, OneRegisterOffset(ix@(ZRegister.MEM_IX_D | ZRegister.MEM_IY_D), offset), _, _) if oneRegister.contains(op) =>
|
||||
case ZLine0(op, OneRegisterOffset(ix@(ZRegister.MEM_IX_D | ZRegister.MEM_IY_D), offset), _) if oneRegister.contains(op) =>
|
||||
requireZ80()
|
||||
val o = oneRegister(op)
|
||||
writeByte(bank, index, prefixByte(ix))
|
||||
writeByte(bank, index + 1, o.opcode + internalRegisterIndex(ZRegister.MEM_HL) * o.multiplier)
|
||||
writeByte(bank, index + 2, offset)
|
||||
index + 3
|
||||
case ZLine(op, OneRegister(ix@(ZRegister.IX | ZRegister.IY)), _, _) if oneRegister.contains(op) =>
|
||||
case ZLine0(op, OneRegister(ix@(ZRegister.IX | ZRegister.IY)), _) if oneRegister.contains(op) =>
|
||||
requireZ80()
|
||||
val o = oneRegister(op)
|
||||
writeByte(bank, index, prefixByte(ix))
|
||||
writeByte(bank, index + 1, o.opcode + internalRegisterIndex(ZRegister.HL) * o.multiplier)
|
||||
writeByte(bank, index + 2, instr.parameter)
|
||||
index + 3
|
||||
case ZLine(op, OneRegister(reg), _, _) if reg != ZRegister.IMM_8 && oneRegister.contains(op) =>
|
||||
case ZLine0(op, OneRegister(reg), _) if reg != ZRegister.IMM_8 && oneRegister.contains(op) =>
|
||||
val o = oneRegister(op)
|
||||
writeByte(bank, index, o.opcode + internalRegisterIndex(reg) * o.multiplier)
|
||||
index + 1
|
||||
case ZLine(SLL, OneRegister(reg), _, _) =>
|
||||
case ZLine0(SLL, OneRegister(reg), _) =>
|
||||
requireZ80Illegals()
|
||||
writeByte(bank, index, 0xcb)
|
||||
writeByte(bank, index + 1, 0x30 + internalRegisterIndex(reg))
|
||||
index + 2
|
||||
case ZLine(SWAP, OneRegister(reg), _, _) =>
|
||||
case ZLine0(SWAP, OneRegister(reg), _) =>
|
||||
requireSharp()
|
||||
writeByte(bank, index, 0xcb)
|
||||
writeByte(bank, index + 1, 0x30 + internalRegisterIndex(reg))
|
||||
index + 2
|
||||
case ZLine(SLL, OneRegisterOffset(ix@(ZRegister.MEM_IX_D | ZRegister.MEM_IY_D), offset), _, _) =>
|
||||
case ZLine0(SLL, OneRegisterOffset(ix@(ZRegister.MEM_IX_D | ZRegister.MEM_IY_D), offset), _) =>
|
||||
requireZ80Illegals()
|
||||
writeByte(bank, index, prefixByte(ix))
|
||||
writeByte(bank, index + 1, 0xcb)
|
||||
writeByte(bank, index + 2, offset)
|
||||
writeByte(bank, index + 3, 0x30 + internalRegisterIndex(MEM_HL))
|
||||
index + 4
|
||||
case ZLine(op, OneRegister(reg), _, _) if cbOneRegister.contains(op) =>
|
||||
case ZLine0(op, OneRegister(reg), _) if cbOneRegister.contains(op) =>
|
||||
requireExtended80()
|
||||
val o = cbOneRegister(op)
|
||||
writeByte(bank, index, 0xcb)
|
||||
writeByte(bank, index + 1, o.opcode + internalRegisterIndex(reg) * o.multiplier)
|
||||
index + 2
|
||||
case ZLine(op, OneRegisterOffset(ix@(ZRegister.MEM_IX_D | ZRegister.MEM_IY_D), offset), _, _) if cbOneRegister.contains(op) =>
|
||||
case ZLine0(op, OneRegisterOffset(ix@(ZRegister.MEM_IX_D | ZRegister.MEM_IY_D), offset), _) if cbOneRegister.contains(op) =>
|
||||
requireZ80()
|
||||
val o = cbOneRegister(op)
|
||||
writeByte(bank, index, prefixByte(ix))
|
||||
@ -280,7 +280,7 @@ class Z80Assembler(program: Program,
|
||||
writeByte(bank, index + 2, offset)
|
||||
writeByte(bank, index + 3, o.opcode + internalRegisterIndex(MEM_HL) * o.multiplier)
|
||||
index + 4
|
||||
case ZLine(LD, registers, _, _) =>
|
||||
case ZLine0(LD, registers, _) =>
|
||||
registers match {
|
||||
case TwoRegisters(I, A) =>
|
||||
requireZ80()
|
||||
@ -363,254 +363,254 @@ class Z80Assembler(program: Program,
|
||||
writeByte(bank, index, 0x40 + internalRegisterIndex(source) + internalRegisterIndex(target) * 8)
|
||||
index + 1
|
||||
}
|
||||
case ZLine(IN_IMM, OneRegister(ZRegister.A), param, _) =>
|
||||
case ZLine0(IN_IMM, OneRegister(ZRegister.A), param) =>
|
||||
requireIntel8080()
|
||||
writeByte(bank, index, 0xdb)
|
||||
writeByte(bank, index + 1, param)
|
||||
index + 2
|
||||
case ZLine(IN_C, OneRegister(reg), param, _) =>
|
||||
case ZLine0(IN_C, OneRegister(reg), param) =>
|
||||
requireZ80()
|
||||
writeByte(bank, index, 0xed)
|
||||
writeByte(bank, index + 1, 0x40 + 8 * internalRegisterIndex(reg))
|
||||
index + 2
|
||||
case ZLine(OUT_IMM, OneRegister(ZRegister.A), param, _) =>
|
||||
case ZLine0(OUT_IMM, OneRegister(ZRegister.A), param) =>
|
||||
requireIntel8080()
|
||||
writeByte(bank, index, 0xd3)
|
||||
writeByte(bank, index + 1, param)
|
||||
index + 2
|
||||
case ZLine(OUT_C, OneRegister(reg), param, _) =>
|
||||
case ZLine0(OUT_C, OneRegister(reg), param) =>
|
||||
requireZ80()
|
||||
writeByte(bank, index, 0xed)
|
||||
writeByte(bank, index + 1, 0x41 + 8 * internalRegisterIndex(reg))
|
||||
index + 2
|
||||
|
||||
case ZLine(CALL, NoRegisters, param, _) =>
|
||||
case ZLine0(CALL, NoRegisters, param) =>
|
||||
writeByte(bank, index, 0xcd)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
|
||||
|
||||
|
||||
case ZLine(CALL, IfFlagClear(ZFlag.Z), param, _) =>
|
||||
case ZLine0(CALL, IfFlagClear(ZFlag.Z), param) =>
|
||||
writeByte(bank, index, 0xc4)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(CALL, IfFlagClear(ZFlag.C), param, _) =>
|
||||
case ZLine0(CALL, IfFlagClear(ZFlag.C), param) =>
|
||||
writeByte(bank, index, 0xd4)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(CALL, IfFlagClear(ZFlag.P), param, _) =>
|
||||
case ZLine0(CALL, IfFlagClear(ZFlag.P), param) =>
|
||||
requireIntel8080()
|
||||
writeByte(bank, index, 0xe4)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(CALL, IfFlagClear(ZFlag.S), param, _) =>
|
||||
case ZLine0(CALL, IfFlagClear(ZFlag.S), param) =>
|
||||
requireIntel8080()
|
||||
writeByte(bank, index, 0xf4)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
|
||||
case ZLine(CALL, IfFlagSet(ZFlag.Z), param, _) =>
|
||||
case ZLine0(CALL, IfFlagSet(ZFlag.Z), param) =>
|
||||
writeByte(bank, index, 0xcc)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(CALL, IfFlagSet(ZFlag.C), param, _) =>
|
||||
case ZLine0(CALL, IfFlagSet(ZFlag.C), param) =>
|
||||
writeByte(bank, index, 0xdc)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(CALL, IfFlagSet(ZFlag.P), param, _) =>
|
||||
case ZLine0(CALL, IfFlagSet(ZFlag.P), param) =>
|
||||
requireIntel8080()
|
||||
writeByte(bank, index, 0xec)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(CALL, IfFlagSet(ZFlag.S), param, _) =>
|
||||
case ZLine0(CALL, IfFlagSet(ZFlag.S), param) =>
|
||||
requireIntel8080()
|
||||
writeByte(bank, index, 0xfc)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
|
||||
case ZLine(JP, NoRegisters, param, _) =>
|
||||
case ZLine0(JP, NoRegisters, param) =>
|
||||
writeByte(bank, index, 0xc3)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
|
||||
case ZLine(JP, IfFlagClear(ZFlag.Z), param, _) =>
|
||||
case ZLine0(JP, IfFlagClear(ZFlag.Z), param) =>
|
||||
writeByte(bank, index, 0xc2)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(JP, IfFlagClear(ZFlag.C), param, _) =>
|
||||
case ZLine0(JP, IfFlagClear(ZFlag.C), param) =>
|
||||
writeByte(bank, index, 0xd2)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(JP, IfFlagClear(ZFlag.P), param, _) =>
|
||||
case ZLine0(JP, IfFlagClear(ZFlag.P), param) =>
|
||||
requireIntel8080()
|
||||
writeByte(bank, index, 0xe2)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(JP, IfFlagClear(ZFlag.S), param, _) =>
|
||||
case ZLine0(JP, IfFlagClear(ZFlag.S), param) =>
|
||||
requireIntel8080()
|
||||
writeByte(bank, index, 0xf2)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
|
||||
case ZLine(JP, IfFlagSet(ZFlag.Z), param, _) =>
|
||||
case ZLine0(JP, IfFlagSet(ZFlag.Z), param) =>
|
||||
writeByte(bank, index, 0xca)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(JP, IfFlagSet(ZFlag.C), param, _) =>
|
||||
case ZLine0(JP, IfFlagSet(ZFlag.C), param) =>
|
||||
writeByte(bank, index, 0xda)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(JP, IfFlagSet(ZFlag.P), param, _) =>
|
||||
case ZLine0(JP, IfFlagSet(ZFlag.P), param) =>
|
||||
requireIntel8080()
|
||||
writeByte(bank, index, 0xea)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(JP, IfFlagSet(ZFlag.S), param, _) =>
|
||||
case ZLine0(JP, IfFlagSet(ZFlag.S), param) =>
|
||||
requireIntel8080()
|
||||
writeByte(bank, index, 0xfa)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(JP, OneRegister(HL), _, _) =>
|
||||
case ZLine0(JP, OneRegister(HL), _) =>
|
||||
writeByte(bank, index, 0xe9)
|
||||
index + 1
|
||||
case ZLine(JP, OneRegister(IX), _, _) =>
|
||||
case ZLine0(JP, OneRegister(IX), _) =>
|
||||
requireZ80()
|
||||
writeByte(bank, index, 0xdd)
|
||||
writeByte(bank, index, 0xe9)
|
||||
index + 2
|
||||
case ZLine(JP, OneRegister(IY), _, _) =>
|
||||
case ZLine0(JP, OneRegister(IY), _) =>
|
||||
requireZ80()
|
||||
writeByte(bank, index, 0xfd)
|
||||
writeByte(bank, index, 0xe9)
|
||||
index + 2
|
||||
|
||||
case ZLine(RET, IfFlagClear(ZFlag.Z), _, _) =>
|
||||
case ZLine0(RET, IfFlagClear(ZFlag.Z), _) =>
|
||||
writeByte(bank, index, 0xc0)
|
||||
index + 1
|
||||
case ZLine(RET, IfFlagClear(ZFlag.C), _, _) =>
|
||||
case ZLine0(RET, IfFlagClear(ZFlag.C), _) =>
|
||||
writeByte(bank, index, 0xd0)
|
||||
index + 1
|
||||
case ZLine(RET, IfFlagClear(ZFlag.P), _, _) =>
|
||||
case ZLine0(RET, IfFlagClear(ZFlag.P), _) =>
|
||||
requireIntel8080()
|
||||
writeByte(bank, index, 0xe0)
|
||||
index + 1
|
||||
case ZLine(RET, IfFlagClear(ZFlag.S), _, _) =>
|
||||
case ZLine0(RET, IfFlagClear(ZFlag.S), _) =>
|
||||
requireIntel8080()
|
||||
writeByte(bank, index, 0xf0)
|
||||
index + 1
|
||||
|
||||
case ZLine(RET, IfFlagSet(ZFlag.Z), _, _) =>
|
||||
case ZLine0(RET, IfFlagSet(ZFlag.Z), _) =>
|
||||
writeByte(bank, index, 0xc8)
|
||||
index + 1
|
||||
case ZLine(RET, IfFlagSet(ZFlag.C), _, _) =>
|
||||
case ZLine0(RET, IfFlagSet(ZFlag.C), _) =>
|
||||
writeByte(bank, index, 0xd8)
|
||||
index + 1
|
||||
case ZLine(RET, IfFlagSet(ZFlag.P), _, _) =>
|
||||
case ZLine0(RET, IfFlagSet(ZFlag.P), _) =>
|
||||
requireIntel8080()
|
||||
writeByte(bank, index, 0xe8)
|
||||
index + 1
|
||||
case ZLine(RET, IfFlagSet(ZFlag.S), _, _) =>
|
||||
case ZLine0(RET, IfFlagSet(ZFlag.S), _) =>
|
||||
requireIntel8080()
|
||||
writeByte(bank, index, 0xf8)
|
||||
index + 1
|
||||
|
||||
case ZLine(JR, IfFlagClear(ZFlag.Z), param, _) =>
|
||||
case ZLine0(JR, IfFlagClear(ZFlag.Z), param) =>
|
||||
requireExtended80()
|
||||
writeByte(bank, index, 0x20)
|
||||
writeByte(bank, index + 1, AssertByte(param - index - 2))
|
||||
index + 2
|
||||
case ZLine(JR, IfFlagClear(ZFlag.C), param, _) =>
|
||||
case ZLine0(JR, IfFlagClear(ZFlag.C), param) =>
|
||||
requireExtended80()
|
||||
writeByte(bank, index, 0x30)
|
||||
writeByte(bank, index + 1, AssertByte(param - index - 2))
|
||||
index + 2
|
||||
|
||||
case ZLine(JR, IfFlagSet(ZFlag.Z), param, _) =>
|
||||
case ZLine0(JR, IfFlagSet(ZFlag.Z), param) =>
|
||||
requireExtended80()
|
||||
writeByte(bank, index, 0x28)
|
||||
writeByte(bank, index + 1, AssertByte(param - index - 2))
|
||||
index + 2
|
||||
case ZLine(JR, IfFlagSet(ZFlag.C), param, _) =>
|
||||
case ZLine0(JR, IfFlagSet(ZFlag.C), param) =>
|
||||
requireExtended80()
|
||||
writeByte(bank, index, 0x38)
|
||||
writeByte(bank, index + 1, AssertByte(param - index - 2))
|
||||
index + 2
|
||||
|
||||
case ZLine(JR, NoRegisters, param, _) =>
|
||||
case ZLine0(JR, NoRegisters, param) =>
|
||||
requireExtended80()
|
||||
writeByte(bank, index, 0x18)
|
||||
writeByte(bank, index + 1, AssertByte(param - index - 2))
|
||||
index + 2
|
||||
case ZLine(DJNZ, NoRegisters, param, _) =>
|
||||
case ZLine0(DJNZ, NoRegisters, param) =>
|
||||
requireZ80()
|
||||
writeByte(bank, index, 0x10)
|
||||
writeByte(bank, index + 1, AssertByte(param - index - 2))
|
||||
index + 2
|
||||
case ZLine(EX_SP, OneRegister(HL), _, _) =>
|
||||
case ZLine0(EX_SP, OneRegister(HL), _) =>
|
||||
requireIntel8080()
|
||||
writeByte(bank, index, 0xe3)
|
||||
index + 1
|
||||
case ZLine(EX_SP, OneRegister(IX), _, _) =>
|
||||
case ZLine0(EX_SP, OneRegister(IX), _) =>
|
||||
requireZ80()
|
||||
writeByte(bank, index, 0xdd)
|
||||
writeByte(bank, index + 1, 0xe3)
|
||||
index + 2
|
||||
case ZLine(EX_SP, OneRegister(IY), _, _) =>
|
||||
case ZLine0(EX_SP, OneRegister(IY), _) =>
|
||||
requireZ80()
|
||||
writeByte(bank, index, 0xfd)
|
||||
writeByte(bank, index + 1, 0xe3)
|
||||
index + 2
|
||||
case ZLine(EX_DE_HL, _, _, _) =>
|
||||
case ZLine0(EX_DE_HL, _, _) =>
|
||||
requireIntel8080()
|
||||
writeByte(bank, index, 0xeb)
|
||||
index + 1
|
||||
|
||||
case ZLine(ADD_SP, _, param, _) =>
|
||||
case ZLine0(ADD_SP, _, param) =>
|
||||
requireSharp()
|
||||
writeByte(bank, index, 0xe8)
|
||||
writeByte(bank, index + 1, param)
|
||||
index + 2
|
||||
case ZLine(LD_HLSP, _, param, _) =>
|
||||
case ZLine0(LD_HLSP, _, param) =>
|
||||
requireSharp()
|
||||
writeByte(bank, index, 0xf8)
|
||||
writeByte(bank, index + 1, param)
|
||||
index + 2
|
||||
case ZLine(LD_AHLI, _, _, _) =>
|
||||
case ZLine0(LD_AHLI, _, _) =>
|
||||
requireSharp()
|
||||
writeByte(bank, index, 0x2a)
|
||||
index + 1
|
||||
case ZLine(LD_AHLD, _, _, _) =>
|
||||
case ZLine0(LD_AHLD, _, _) =>
|
||||
requireSharp()
|
||||
writeByte(bank, index, 0x3a)
|
||||
index + 1
|
||||
case ZLine(LD_HLIA, _, _, _) =>
|
||||
case ZLine0(LD_HLIA, _, _) =>
|
||||
requireSharp()
|
||||
writeByte(bank, index, 0x22)
|
||||
index + 1
|
||||
case ZLine(LD_HLDA, _, _, _) =>
|
||||
case ZLine0(LD_HLDA, _, _) =>
|
||||
requireSharp()
|
||||
writeByte(bank, index, 0x32)
|
||||
index + 1
|
||||
case ZLine(LDH_AD, _, param, _) =>
|
||||
case ZLine0(LDH_AD, _, param) =>
|
||||
requireSharp()
|
||||
writeByte(bank, index, 0xf0)
|
||||
writeByte(bank, index + 1, param.loByte)
|
||||
index + 2
|
||||
case ZLine(LDH_DA, _, param, _) =>
|
||||
case ZLine0(LDH_DA, _, param) =>
|
||||
requireSharp()
|
||||
writeByte(bank, index, 0xe0)
|
||||
writeByte(bank, index + 1, param.loByte)
|
||||
index + 2
|
||||
case ZLine(LDH_AC, _, _, _) =>
|
||||
case ZLine0(LDH_AC, _, _) =>
|
||||
requireSharp()
|
||||
writeByte(bank, index, 0xf2)
|
||||
index + 1
|
||||
case ZLine(LDH_CA, _, _, _) =>
|
||||
case ZLine0(LDH_CA, _, _) =>
|
||||
requireSharp()
|
||||
writeByte(bank, index, 0xe2)
|
||||
index + 1
|
||||
case ZLine(STOP, _, _, _) =>
|
||||
case ZLine0(STOP, _, _) =>
|
||||
requireSharp()
|
||||
writeByte(bank, index, 0x10)
|
||||
index + 1
|
||||
|
@ -4,6 +4,7 @@ import millfork.CompilationOptions
|
||||
import millfork.assembly.z80.{ZOpcode, _}
|
||||
import millfork.env.{Environment, Label, MemoryAddressConstant}
|
||||
import ZOpcode._
|
||||
import millfork.assembly.Elidability
|
||||
import millfork.node.ZRegister.SP
|
||||
|
||||
import scala.collection.mutable
|
||||
@ -13,7 +14,7 @@ import scala.collection.mutable
|
||||
*/
|
||||
class Z80Deduplicate(env: Environment, options: CompilationOptions) extends Deduplicate[ZLine](env, options) {
|
||||
override def getJump(line: ZLine): Option[String] = line match {
|
||||
case ZLine(JP, NoRegisters, MemoryAddressConstant(thing), _) => Some(thing.name)
|
||||
case ZLine0(JP, NoRegisters, MemoryAddressConstant(thing)) => Some(thing.name)
|
||||
case _ => None
|
||||
}
|
||||
|
||||
@ -21,7 +22,7 @@ class Z80Deduplicate(env: Environment, options: CompilationOptions) extends Dedu
|
||||
|
||||
override def actualCode(FunctionName: String, functionCode: List[ZLine]): List[ZLine] = {
|
||||
functionCode match {
|
||||
case ZLine(LABEL, _, MemoryAddressConstant(Label(FunctionName)), _) :: xs => xs
|
||||
case ZLine0(LABEL, _, MemoryAddressConstant(Label(FunctionName))) :: xs => xs
|
||||
case xs => xs
|
||||
}
|
||||
}
|
||||
@ -65,20 +66,20 @@ class Z80Deduplicate(env: Environment, options: CompilationOptions) extends Dedu
|
||||
case _ => false
|
||||
}
|
||||
|
||||
override def createCall(functionName: String): ZLine = ZLine(CALL, NoRegisters, MemoryAddressConstant(Label(functionName)), elidable = false)
|
||||
override def createCall(functionName: String): ZLine = ZLine(CALL, NoRegisters, MemoryAddressConstant(Label(functionName)), elidability = Elidability.Fixed)
|
||||
|
||||
override def createReturn(): ZLine = ZLine.implied(RET)
|
||||
|
||||
def retPrecededByDiscards(xs: List[ZLine]): Option[List[ZLine]] = {
|
||||
xs match {
|
||||
case ZLine(op, _, _, _) :: xs if ZOpcodeClasses.NoopDiscards(op) => retPrecededByDiscards(xs)
|
||||
case ZLine(RET, _, _, _) :: xs => Some(xs)
|
||||
case ZLine0(op, _, _) :: ys if ZOpcodeClasses.NoopDiscards(op) => retPrecededByDiscards(ys)
|
||||
case ZLine0(RET, _, _) :: ys => Some(ys)
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
|
||||
override def tco(code: List[ZLine]): List[ZLine] = code match {
|
||||
case (call@ZLine(CALL, _, _, _)) :: xs => retPrecededByDiscards(xs) match {
|
||||
case (call@ZLine0(CALL, _, _)) :: xs => retPrecededByDiscards(xs) match {
|
||||
case Some(rest) =>call.copy(opcode = JP) :: tco(rest)
|
||||
case _ => call :: tco(xs)
|
||||
}
|
||||
@ -90,13 +91,13 @@ class Z80Deduplicate(env: Environment, options: CompilationOptions) extends Dedu
|
||||
val map = mutable.Map[String, String]()
|
||||
var counter = 0
|
||||
code.foreach{
|
||||
case ZLine(LABEL, _, MemoryAddressConstant(Label(x)), _) if x.startsWith(".") =>
|
||||
case ZLine0(LABEL, _, MemoryAddressConstant(Label(x))) if x.startsWith(".") =>
|
||||
map(x) = if (temporary) ".ddtmp__" + counter else env.nextLabel("dd")
|
||||
counter += 1
|
||||
case _ =>
|
||||
}
|
||||
code.map{
|
||||
case l@ZLine(_, _, MemoryAddressConstant(Label(x)), _) if map.contains(x) =>
|
||||
case l@ZLine0(_, _, MemoryAddressConstant(Label(x))) if map.contains(x) =>
|
||||
l.copy(parameter = MemoryAddressConstant(Label(map(x))))
|
||||
case l => l
|
||||
}
|
||||
@ -106,14 +107,14 @@ class Z80Deduplicate(env: Environment, options: CompilationOptions) extends Dedu
|
||||
val myLabels = mutable.Set[String]()
|
||||
val useCount = mutable.Map[String, Int]()
|
||||
snippet.foreach{
|
||||
case ZLine(LABEL, _, MemoryAddressConstant(Label(x)), _) =>
|
||||
case ZLine0(LABEL, _, MemoryAddressConstant(Label(x))) =>
|
||||
myLabels += x
|
||||
case ZLine(_, _, MemoryAddressConstant(Label(x)), _) =>
|
||||
case ZLine0(_, _, MemoryAddressConstant(Label(x))) =>
|
||||
useCount(x) = useCount.getOrElse(x, 0) - 1
|
||||
case _ =>
|
||||
}
|
||||
wholeCode.foreach {
|
||||
case ZLine(op, _, MemoryAddressConstant(Label(x)), _) if op != LABEL && myLabels(x) =>
|
||||
case ZLine0(op, _, MemoryAddressConstant(Label(x))) if op != LABEL && myLabels(x) =>
|
||||
useCount(x) = useCount.getOrElse(x, 0) + 1
|
||||
case _ =>
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package millfork.output
|
||||
|
||||
import millfork.JobContext
|
||||
import millfork.assembly.Elidability
|
||||
import millfork.assembly.z80._
|
||||
import millfork.compiler.AbstractCompiler
|
||||
import millfork.env._
|
||||
@ -20,7 +21,7 @@ object Z80InliningCalculator extends AbstractInliningCalculator[ZLine] {
|
||||
override def codeForInlining(fname: String, functionsThatCanBeCalledFromInlinedFunctions: Set[String], code: List[ZLine]): Option[List[ZLine]] = {
|
||||
if (code.isEmpty) return None
|
||||
code.last match {
|
||||
case ZLine(RET, NoRegisters, _, _) =>
|
||||
case ZLine0(RET, NoRegisters, _) =>
|
||||
case _ => return None
|
||||
}
|
||||
var result = code.init
|
||||
@ -29,14 +30,14 @@ object Z80InliningCalculator extends AbstractInliningCalculator[ZLine] {
|
||||
}
|
||||
if (result.head.opcode == LABEL && result.head.parameter == Label(fname).toAddress) result = result.tail
|
||||
if (result.exists {
|
||||
case ZLine(op, _, MemoryAddressConstant(Label(l)), _) if jumpingRelatedOpcodes(op) =>
|
||||
case ZLine0(op, _, MemoryAddressConstant(Label(l))) if jumpingRelatedOpcodes(op) =>
|
||||
!l.startsWith(".")
|
||||
case ZLine(CALL, _, MemoryAddressConstant(th: ExternFunction), _) => false
|
||||
case ZLine(CALL, _, NumericConstant(_, _), _) => false
|
||||
case ZLine(JP, OneRegister(_), _, _) => false
|
||||
case ZLine(CALL, _, MemoryAddressConstant(th: NormalFunction), _) =>
|
||||
case ZLine0(CALL, _, MemoryAddressConstant(th: ExternFunction)) => false
|
||||
case ZLine0(CALL, _, NumericConstant(_, _)) => false
|
||||
case ZLine0(JP, OneRegister(_), _) => false
|
||||
case ZLine0(CALL, _, MemoryAddressConstant(th: NormalFunction)) =>
|
||||
!functionsThatCanBeCalledFromInlinedFunctions(th.name)
|
||||
case ZLine(op, _, _, _) if jumpingRelatedOpcodes(op) || badOpcodes(op) => true
|
||||
case ZLine0(op, _, _) if jumpingRelatedOpcodes(op) || badOpcodes(op) => true
|
||||
case _ => false
|
||||
}) return None
|
||||
Some(result)
|
||||
@ -55,20 +56,20 @@ object Z80InliningCalculator extends AbstractInliningCalculator[ZLine] {
|
||||
|
||||
override def inline(code: List[ZLine], inlinedFunctions: Map[String, List[ZLine]], jobContext: JobContext): List[ZLine] = {
|
||||
code.flatMap {
|
||||
case ZLine(CALL, registers, p, true) if inlinedFunctions.contains(p.toString) =>
|
||||
case ZLine(CALL, registers, p, Elidability.Elidable, _) if inlinedFunctions.contains(p.toString) =>
|
||||
val labelPrefix = jobContext.nextLabel("ai")
|
||||
wrap(registers, jobContext,
|
||||
inlinedFunctions(p.toString).map {
|
||||
case line@ZLine(_, _, MemoryAddressConstant(Label(label)), _) =>
|
||||
case line@ZLine0(_, _, MemoryAddressConstant(Label(label))) =>
|
||||
val newLabel = MemoryAddressConstant(Label(labelPrefix + label))
|
||||
line.copy(parameter = newLabel)
|
||||
case l => l
|
||||
})
|
||||
case ZLine(JP | JR, registers, p, true) if inlinedFunctions.contains(p.toString) =>
|
||||
case ZLine(JP | JR, registers, p, Elidability.Elidable, _) if inlinedFunctions.contains(p.toString) =>
|
||||
val labelPrefix = jobContext.nextLabel("ai")
|
||||
wrap(registers, jobContext,
|
||||
inlinedFunctions(p.toString).map {
|
||||
case line@ZLine(_, _, MemoryAddressConstant(Label(label)), _) =>
|
||||
case line@ZLine0(_, _, MemoryAddressConstant(Label(label))) =>
|
||||
val newLabel = MemoryAddressConstant(Label(labelPrefix + label))
|
||||
line.copy(parameter = newLabel)
|
||||
case l => l
|
||||
|
@ -5,6 +5,7 @@ import java.nio.file.{Files, Paths}
|
||||
import java.util
|
||||
|
||||
import fastparse.all._
|
||||
import millfork.assembly.Elidability
|
||||
import millfork.env._
|
||||
import millfork.error.{ConsoleLogger, Logger}
|
||||
import millfork.node._
|
||||
@ -589,7 +590,10 @@ object MfParser {
|
||||
val nonStatementLevel = 1 // everything but not `=`
|
||||
val mathLevel = 4 // the `:` operator
|
||||
|
||||
val elidable: P[Boolean] = ("?".! ~/ HWS).?.map(_.isDefined)
|
||||
val elidable: P[Elidability.Value] = ("?".! ~/ HWS).?.map{
|
||||
case Some(_) => Elidability.Elidable
|
||||
case _ => Elidability.Fixed
|
||||
}
|
||||
|
||||
val externFunctionBody: P[Option[List[Statement]]] = P("extern" ~/ PassWith(None))
|
||||
|
||||
|
@ -6,6 +6,7 @@ import millfork.env._
|
||||
import millfork.error.ConsoleLogger
|
||||
import millfork.node._
|
||||
import millfork.CompilationOptions
|
||||
import millfork.assembly.Elidability
|
||||
import millfork.output.{MemoryAlignment, NoAlignment, WithinPageAlignment}
|
||||
|
||||
/**
|
||||
@ -21,7 +22,7 @@ case class MosParser(filename: String, input: String, currentDirectory: String,
|
||||
def fastAlignmentForFunctions: MemoryAlignment = WithinPageAlignment
|
||||
|
||||
// TODO: label and instruction in one line
|
||||
val asmLabel: P[ExecutableStatement] = (identifier ~ HWS ~ ":" ~/ HWS).map(l => MosAssemblyStatement(Opcode.LABEL, AddrMode.DoesNotExist, VariableExpression(l), elidable = true))
|
||||
val asmLabel: P[ExecutableStatement] = (identifier ~ HWS ~ ":" ~/ HWS).map(l => MosAssemblyStatement(Opcode.LABEL, AddrMode.DoesNotExist, VariableExpression(l), Elidability.Elidable))
|
||||
|
||||
// def zeropageAddrModeHint: P[Option[Boolean]] = Pass
|
||||
|
||||
@ -55,7 +56,7 @@ case class MosParser(filename: String, input: String, currentDirectory: String,
|
||||
}
|
||||
|
||||
val asmInstruction: P[ExecutableStatement] = {
|
||||
val lineParser: P[(Boolean, Opcode.Value, (AddrMode.Value, Expression))] = !"}" ~ elidable ~/ asmOpcode ~/ asmParameter
|
||||
val lineParser: P[(Elidability.Value, Opcode.Value, (AddrMode.Value, Expression))] = !"}" ~ elidable ~/ asmOpcode ~/ asmParameter
|
||||
lineParser.map { case (elid, op, param) =>
|
||||
(op, param._1) match {
|
||||
case (Opcode.SAX, AddrMode.Implied) => MosAssemblyStatement(Opcode.HuSAX, param._1, param._2, elid)
|
||||
|
@ -4,7 +4,7 @@ import java.util.Locale
|
||||
|
||||
import fastparse.all.{parserApi, _}
|
||||
import fastparse.core
|
||||
import millfork.assembly.z80
|
||||
import millfork.assembly.{Elidability, z80}
|
||||
import millfork.{CompilationFlag, CompilationOptions, node}
|
||||
import millfork.assembly.z80.{ZOpcode, _}
|
||||
import millfork.env.{ByZRegister, Constant, ParamPassingConvention}
|
||||
@ -52,7 +52,7 @@ case class Z80Parser(filename: String,
|
||||
} yield ParameterDeclaration(typ, appc).pos(p)
|
||||
|
||||
// TODO: label and instruction in one line
|
||||
val asmLabel: P[ExecutableStatement] = (identifier ~ HWS ~ ":" ~/ HWS).map(l => Z80AssemblyStatement(ZOpcode.LABEL, NoRegisters, None, VariableExpression(l), elidable = true))
|
||||
val asmLabel: P[ExecutableStatement] = (identifier ~ HWS ~ ":" ~/ HWS).map(l => Z80AssemblyStatement(ZOpcode.LABEL, NoRegisters, None, VariableExpression(l), elidability = Elidability.Elidable))
|
||||
|
||||
val asmMacro: P[ExecutableStatement] = ("+" ~/ HWS ~/ functionCall(false)).map(ExpressionStatement)
|
||||
|
||||
|
@ -1,9 +1,10 @@
|
||||
package millfork.test
|
||||
|
||||
import millfork.assembly.Elidability
|
||||
import millfork.{CompilationOptions, Cpu, CpuFamily, JobContext}
|
||||
import millfork.assembly.z80.{LocalVariableAddressViaIX, NoRegisters, ZLine}
|
||||
import millfork.compiler.LabelGenerator
|
||||
import millfork.env.{Constant, Environment, NumericConstant}
|
||||
import millfork.env.{Environment, NumericConstant}
|
||||
import millfork.output.Z80Assembler
|
||||
import millfork.test.emu._
|
||||
import org.scalatest.{FunSuite, Matchers}
|
||||
@ -43,7 +44,7 @@ class ZLineSizeSuite extends FunSuite with Matchers {
|
||||
runCase(ZLine.register(BIT0, E))
|
||||
runCase(ZLine.register(JP, IX))
|
||||
runCase(ZLine.register(JP, HL))
|
||||
runCase(ZLine(IM, NoRegisters, NumericConstant(1, 1), true))
|
||||
runCase(ZLine(IM, NoRegisters, NumericConstant(1, 1), Elidability.Elidable))
|
||||
runCase(ZLine.register(DEC, HL))
|
||||
runCase(ZLine.register(DEC, LocalVariableAddressViaIX(7)))
|
||||
runCase(ZLine.ld8(A, MEM_HL))
|
||||
|
Loading…
x
Reference in New Issue
Block a user