mirror of
https://github.com/KarolS/millfork.git
synced 2025-01-11 12:29:46 +00:00
Compiler performance improvements
This commit is contained in:
parent
0e5d79f222
commit
badd7ef1d8
@ -3,7 +3,7 @@ package millfork.assembly.mos.opt
|
||||
import millfork.assembly.OptimizationContext
|
||||
import millfork.{CompilationFlag, CompilationOptions}
|
||||
import millfork.assembly.mos.{AssemblyLine, AssemblyLine0, OpcodeClasses}
|
||||
import millfork.assembly.opt.AnyStatus
|
||||
import millfork.assembly.opt.{AnyStatus, FlowCache}
|
||||
import millfork.env._
|
||||
|
||||
/**
|
||||
@ -11,7 +11,10 @@ import millfork.env._
|
||||
*/
|
||||
object CoarseFlowAnalyzer {
|
||||
|
||||
val cache = new FlowCache[AssemblyLine, CpuStatus]("mos forward")
|
||||
|
||||
def analyze(f: NormalFunction, code: List[AssemblyLine], optimizationContext: OptimizationContext): List[CpuStatus] = {
|
||||
cache.get(code).foreach(return _)
|
||||
val compilationOptions = optimizationContext.options
|
||||
val niceFunctionProperties = optimizationContext.niceFunctionProperties
|
||||
val ceFlag = compilationOptions.flag(CompilationFlag.Emit65CE02Opcodes)
|
||||
@ -124,6 +127,6 @@ object CoarseFlowAnalyzer {
|
||||
// println("---------------------")
|
||||
}
|
||||
|
||||
flagArray.toList
|
||||
cache.put(code, flagArray.toList)
|
||||
}
|
||||
}
|
||||
|
@ -15,11 +15,11 @@ import scala.collection.mutable
|
||||
object JumpFollowing {
|
||||
|
||||
def apply(options: CompilationOptions, code: List[AssemblyLine]): List[AssemblyLine] = {
|
||||
val labelsToRts = mutable.Set[String]()
|
||||
val labelsToRti = mutable.Set[String]()
|
||||
val labelsToRtl = mutable.Set[String]()
|
||||
val labelsToJumps = mutable.Map[String, String]()
|
||||
val currentLabels = mutable.Set[String]()
|
||||
val labelsToRts = new mutable.HashSet[String]()
|
||||
val labelsToRti = new mutable.HashSet[String]()
|
||||
val labelsToRtl = new mutable.HashSet[String]()
|
||||
val labelsToJumps = new mutable.HashMap[String, String]()
|
||||
val currentLabels = new mutable.HashSet[String]()
|
||||
for (line <- code) {
|
||||
line match {
|
||||
case AssemblyLine0(LABEL, _, MemoryAddressConstant(Label(label))) =>
|
||||
|
@ -1,14 +1,11 @@
|
||||
package millfork.assembly.mos.opt
|
||||
|
||||
import millfork.CompilationOptions
|
||||
import millfork.assembly._
|
||||
import millfork.assembly.mos._
|
||||
import millfork.assembly.opt.FlowCache
|
||||
import millfork.env._
|
||||
import millfork.error.ConsoleLogger
|
||||
import millfork.node.MosRegister
|
||||
|
||||
import scala.collection.immutable
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
*/
|
||||
@ -51,6 +48,22 @@ case class CpuImportance(a: Importance = UnknownImportance,
|
||||
r2: Importance = UnknownImportance,
|
||||
r3: Importance = UnknownImportance,
|
||||
) {
|
||||
|
||||
def setPseudoRegister(regOffset: Int, importance: Importance): CpuImportance = regOffset match {
|
||||
case 0 => this.copy(r0 = importance)
|
||||
case 1 => this.copy(r1 = importance)
|
||||
case 2 => this.copy(r2 = importance)
|
||||
case 3 => this.copy(r3 = importance)
|
||||
case _ => this
|
||||
}
|
||||
def setPseudoRegisterWord(regOffset: Int, importance: Importance): CpuImportance = regOffset match {
|
||||
case 0 => this.copy(r0 = importance, r1 = importance)
|
||||
case 1 => this.copy(r1 = importance, r2 = importance)
|
||||
case 2 => this.copy(r2 = importance, r3 = importance)
|
||||
case 3 => this.copy(r3 = importance)
|
||||
case _ => this
|
||||
}
|
||||
|
||||
override def toString: String = s"A=$a,B=$ah,X=$x,Y=$y,Z=$iz; Z=$z,N=$n,C=$c,V=$v,D=$d,M=$m,X=$w; R0=$r0,R1=$r1,R2=$r2,R3=$r3"
|
||||
|
||||
def ~(that: CpuImportance) = new CpuImportance(
|
||||
@ -98,9 +111,11 @@ case class CpuImportance(a: Importance = UnknownImportance,
|
||||
|
||||
object ReverseFlowAnalyzer {
|
||||
|
||||
val cache = new FlowCache[AssemblyLine, CpuImportance]("mos reverse")
|
||||
|
||||
val functionsThatReadC = Set("__adc_decimal", "__sbc_decimal")
|
||||
private val aluAdders = Set(Opcode.ADC, Opcode.SBC, Opcode.ISC, Opcode.DCP, Opcode.ADC_W, Opcode.SBC_W)
|
||||
private val actuallyRead = Set(AddrMode.IndexedZ, AddrMode.IndexedSY, AddrMode.IndexedY, AddrMode.LongIndexedY, AddrMode.LongIndexedZ, AddrMode.IndexedX, AddrMode.Indirect, AddrMode.AbsoluteIndexedX)
|
||||
private val readAsPointer = Set(AddrMode.IndexedZ, AddrMode.IndexedSY, AddrMode.IndexedY, AddrMode.LongIndexedY, AddrMode.LongIndexedZ, AddrMode.IndexedX, AddrMode.Indirect, AddrMode.AbsoluteIndexedX)
|
||||
private val absoluteLike = Set(AddrMode.ZeroPage, AddrMode.Absolute, AddrMode.LongAbsolute)
|
||||
private val importanceBeforeJsr: CpuImportance = CpuImportance(
|
||||
a = Unimportant,
|
||||
@ -128,6 +143,7 @@ object ReverseFlowAnalyzer {
|
||||
|
||||
//noinspection RedundantNewCaseClass
|
||||
def analyze(f: NormalFunction, code: List[AssemblyLine], optimizationContext: OptimizationContext): List[CpuImportance] = {
|
||||
cache.get(code).foreach(return _)
|
||||
val niceFunctionProperties = optimizationContext.niceFunctionProperties
|
||||
val importanceArray = Array.fill[CpuImportance](code.length)(new CpuImportance())
|
||||
val codeArray = code.toArray
|
||||
@ -297,65 +313,38 @@ object ReverseFlowAnalyzer {
|
||||
else if (addrMode == IndexedZ /*|| addrMode == LongIndexedZ*/ )
|
||||
currentImportance = currentImportance.copy(iz = Important)
|
||||
}
|
||||
if (absoluteLike(currentLine.addrMode)) {
|
||||
if (OpcodeClasses.StoresByte(currentLine.opcode)) {
|
||||
currentLine.parameter match {
|
||||
case MemoryAddressConstant(th: Thing)
|
||||
if th.name == "__reg" => currentImportance = currentImportance.copy(r0 = Unimportant)
|
||||
case CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th: Thing), NumericConstant(1, _))
|
||||
if th.name == "__reg" => currentImportance = currentImportance.copy(r1 = Unimportant)
|
||||
case CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th: Thing), NumericConstant(2, _))
|
||||
if th.name == "__reg" => currentImportance = currentImportance.copy(r2 = Unimportant)
|
||||
case CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th: Thing), NumericConstant(3, _))
|
||||
if th.name == "__reg" => currentImportance = currentImportance.copy(r3 = Unimportant)
|
||||
case _ => ()
|
||||
}
|
||||
}
|
||||
if (OpcodeClasses.StoresWord(currentLine.opcode)) {
|
||||
currentLine.parameter match {
|
||||
case MemoryAddressConstant(th: Thing)
|
||||
if th.name == "__reg" => currentImportance = currentImportance.copy(r0 = Unimportant, r1 = Unimportant)
|
||||
case CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th: Thing), NumericConstant(1, _))
|
||||
if th.name == "__reg" => currentImportance = currentImportance.copy(r1 = Unimportant, r2 = Unimportant)
|
||||
case CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th: Thing), NumericConstant(2, _))
|
||||
if th.name == "__reg" => currentImportance = currentImportance.copy(r2 = Unimportant, r3 = Unimportant)
|
||||
case _ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
if (actuallyRead(currentLine.addrMode)) {
|
||||
currentLine.parameter match {
|
||||
val isAbsoluteLike = absoluteLike(currentLine.addrMode)
|
||||
val isReadAsPointer = readAsPointer(currentLine.addrMode)
|
||||
if (isAbsoluteLike || isReadAsPointer) {
|
||||
(currentLine.parameter match {
|
||||
case MemoryAddressConstant(th: Thing)
|
||||
if th.name == "__reg" => currentImportance = currentImportance.copy(r0 = Important, r1 = Important)
|
||||
case CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th: Thing), NumericConstant(1, _))
|
||||
if th.name == "__reg" => currentImportance = currentImportance.copy(r1 = Important, r2 = Important)
|
||||
case CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th: Thing), NumericConstant(2, _))
|
||||
if th.name == "__reg" => currentImportance = currentImportance.copy(r2 = Important, r3 = Important)
|
||||
case _ => ()
|
||||
}
|
||||
} else if (OpcodeClasses.ReadsMemoryIfNotImpliedOrImmediate(currentLine.opcode)) {
|
||||
if (OpcodeClasses.AccessesWordInMemory(currentLine.opcode)) {
|
||||
currentLine.parameter match {
|
||||
case MemoryAddressConstant(th: Thing)
|
||||
if th.name == "__reg" => currentImportance = currentImportance.copy(r0 = Important, r1 = Important)
|
||||
case CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th: Thing), NumericConstant(1, _))
|
||||
if th.name == "__reg" => currentImportance = currentImportance.copy(r1 = Important, r2 = Important)
|
||||
case CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th: Thing), NumericConstant(2, _))
|
||||
if th.name == "__reg" => currentImportance = currentImportance.copy(r2 = Important, r3 = Important)
|
||||
case _ => ()
|
||||
}
|
||||
} else {
|
||||
currentLine.parameter match {
|
||||
case MemoryAddressConstant(th: Thing)
|
||||
if th.name == "__reg" => currentImportance = currentImportance.copy(r0 = Important)
|
||||
case CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th: Thing), NumericConstant(1, _))
|
||||
if th.name == "__reg" => currentImportance = currentImportance.copy(r1 = Important)
|
||||
case CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th: Thing), NumericConstant(2, _))
|
||||
if th.name == "__reg" => currentImportance = currentImportance.copy(r2 = Important)
|
||||
case CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th: Thing), NumericConstant(3, _))
|
||||
if th.name == "__reg" => currentImportance = currentImportance.copy(r3 = Important)
|
||||
case _ => ()
|
||||
}
|
||||
if th.name == "__reg" =>
|
||||
Some(0)
|
||||
case CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th: Thing), NumericConstant(n, _))
|
||||
if th.name == "__reg" =>
|
||||
Some(n.toInt)
|
||||
case _ =>
|
||||
None
|
||||
}) match {
|
||||
case None =>
|
||||
case Some(regOffset) =>
|
||||
if (isAbsoluteLike) {
|
||||
if (OpcodeClasses.StoresByte(currentLine.opcode)) {
|
||||
currentImportance = currentImportance.setPseudoRegister(regOffset, Unimportant)
|
||||
} else if (OpcodeClasses.StoresWord(currentLine.opcode)) {
|
||||
currentImportance = currentImportance.setPseudoRegisterWord(regOffset, Unimportant)
|
||||
}
|
||||
if (OpcodeClasses.ReadsMemoryIfNotImpliedOrImmediate(currentLine.opcode)) {
|
||||
if (OpcodeClasses.AccessesWordInMemory(currentLine.opcode)) {
|
||||
currentImportance = currentImportance.setPseudoRegisterWord(regOffset, Important)
|
||||
} else {
|
||||
currentImportance = currentImportance.setPseudoRegister(regOffset, Important)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isReadAsPointer) {
|
||||
currentImportance = currentImportance.setPseudoRegisterWord(regOffset, Important)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -365,6 +354,6 @@ object ReverseFlowAnalyzer {
|
||||
// }
|
||||
// println("---------------------")
|
||||
|
||||
importanceArray.toList
|
||||
cache.put(code, importanceArray.toList)
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
package millfork.assembly.mos.opt
|
||||
|
||||
import millfork.CompilationOptions
|
||||
import millfork.{CompilationFlag, CompilationOptions}
|
||||
import millfork.assembly._
|
||||
import millfork.assembly.mos._
|
||||
import millfork.assembly.opt.SingleStatus
|
||||
@ -41,15 +41,15 @@ class RuleBasedAssemblyOptimization(val name: String, val needsFlowInfo: FlowInf
|
||||
|
||||
|
||||
override def optimize(f: NormalFunction, code: List[AssemblyLine], optimizationContext: OptimizationContext): List[AssemblyLine] = {
|
||||
val effectiveCode = code.map(a => a.copy(parameter = a.parameter.quickSimplify))
|
||||
val taggedCode = FlowAnalyzer.analyze(f, effectiveCode, optimizationContext, needsFlowInfo)
|
||||
optimizeImpl(f, taggedCode, optimizationContext)
|
||||
val taggedCode = FlowAnalyzer.analyze(f, code, optimizationContext, needsFlowInfo)
|
||||
val (changed, optimized) = optimizeImpl(f, taggedCode, optimizationContext)
|
||||
if (changed) optimized else code
|
||||
}
|
||||
|
||||
def optimizeImpl(f: NormalFunction, code: List[(FlowInfo, AssemblyLine)], optimizationContext: OptimizationContext): List[AssemblyLine] = {
|
||||
def optimizeImpl(f: NormalFunction, code: List[(FlowInfo, AssemblyLine)], optimizationContext: OptimizationContext): (Boolean, List[AssemblyLine]) = {
|
||||
val log = optimizationContext.log
|
||||
code match {
|
||||
case Nil => Nil
|
||||
case Nil => false -> Nil
|
||||
case head :: tail =>
|
||||
for ((rule, index) <- actualRules.zipWithIndex) {
|
||||
val ctx = new AssemblyMatchingContext(
|
||||
@ -64,7 +64,8 @@ class RuleBasedAssemblyOptimization(val name: String, val needsFlowInfo: FlowInf
|
||||
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
|
||||
if (!ctx.compilationOptions.flag(CompilationFlag.LineNumbersInAssembly)) optimizedChunk
|
||||
else 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))))
|
||||
@ -82,14 +83,15 @@ class RuleBasedAssemblyOptimization(val name: String, val needsFlowInfo: FlowInf
|
||||
optimizedChunkWithSource.filter(_.isPrintable).foreach(l => log.trace(l.toString))
|
||||
}
|
||||
if (needsFlowInfo != FlowInfoRequirement.NoRequirement) {
|
||||
return optimizedChunkWithSource ++ optimizeImpl(f, rest, optimizationContext)
|
||||
return true -> (optimizedChunkWithSource ++ optimizeImpl(f, rest, optimizationContext)._2)
|
||||
} else {
|
||||
return optimize(f, optimizedChunkWithSource ++ rest.map(_._2), optimizationContext)
|
||||
return true -> optimize(f, optimizedChunkWithSource ++ rest.map(_._2), optimizationContext)
|
||||
}
|
||||
case None => ()
|
||||
}
|
||||
}
|
||||
head._2 :: optimizeImpl(f, tail, optimizationContext)
|
||||
val (changedTail, optimizedTail) = optimizeImpl(f, tail, optimizationContext)
|
||||
(changedTail, head._2 :: optimizedTail)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -124,7 +126,7 @@ class AssemblyMatchingContext(val compilationOptions: CompilationOptions,
|
||||
|
||||
def functionReadsMemory(name: String): Boolean = !niceFunctionProperties(NiceFunctionProperty.DoesntReadMemory -> name)
|
||||
|
||||
private val map = mutable.Map[Int, Any]()
|
||||
private val map = new mutable.HashMap[Int, Any]()
|
||||
|
||||
override def toString: String = if (map.isEmpty) "<empty context>" else map.mkString(", ")
|
||||
|
||||
@ -722,6 +724,8 @@ case class Both(l: AssemblyLinePattern, r: AssemblyLinePattern) extends Assembly
|
||||
l.matchLineTo(ctx, flowInfo, line) && r.matchLineTo(ctx, flowInfo, line)
|
||||
|
||||
override def toString: String = l + " ∧ " + r
|
||||
|
||||
override def &(x: AssemblyLinePattern): AssemblyLinePattern = Both(l, Both(r, x))
|
||||
}
|
||||
|
||||
case class EitherPattern(l: AssemblyLinePattern, r: AssemblyLinePattern) extends AssemblyLinePattern {
|
||||
@ -734,6 +738,8 @@ case class EitherPattern(l: AssemblyLinePattern, r: AssemblyLinePattern) extends
|
||||
l.matchLineTo(ctx, flowInfo, line) || r.matchLineTo(ctx, flowInfo, line)
|
||||
|
||||
override def toString: String = s"($l ∨ $r)"
|
||||
|
||||
override def |(x: AssemblyLinePattern): AssemblyLinePattern = EitherPattern(l, EitherPattern(r, x))
|
||||
}
|
||||
|
||||
case object Elidable extends AssemblyLinePattern {
|
||||
|
37
src/main/scala/millfork/assembly/opt/FlowCache.scala
Normal file
37
src/main/scala/millfork/assembly/opt/FlowCache.scala
Normal file
@ -0,0 +1,37 @@
|
||||
package millfork.assembly.opt
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
*/
|
||||
class FlowCache[L, F](val name: String) {
|
||||
private val lastL = new Array[List[L]](1)
|
||||
private val lastF = new Array[List[F]](1)
|
||||
private var hits = 0L
|
||||
private var misses = 0L
|
||||
|
||||
private def index(lines: List[L]): Int = 0
|
||||
|
||||
private def dumpStats(): Unit = println(s"Cache for $name: $hits hits, $misses misses")
|
||||
|
||||
def get(lines: List[L]): Option[List[F]] = synchronized {
|
||||
val i = index(lines)
|
||||
if (lastL.indices.contains(i) && (lastL(i) eq lines)) {
|
||||
hits += 1
|
||||
// dumpStats()
|
||||
Some(lastF(i))
|
||||
} else {
|
||||
misses += 1
|
||||
// dumpStats()
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
def put(lines: List[L], flow: List[F]): List[F] = synchronized {
|
||||
val i = index(lines)
|
||||
if (lastL.indices.contains(i)) {
|
||||
lastL(i) = lines
|
||||
lastF(i) = flow
|
||||
}
|
||||
flow
|
||||
}
|
||||
}
|
@ -79,7 +79,7 @@ object Status {
|
||||
val SingleFF: Status[Int] = SingleStatus(0xff)
|
||||
|
||||
@inline
|
||||
private def wrapBool(b: Boolean) = if (b) SingleTrue else SingleFalse
|
||||
private def wrapBool(b: Boolean): Status[Boolean] = if (b) SingleTrue else SingleFalse
|
||||
|
||||
def flatMap2[T, U, R](a: Status[T], b: Status[U])(f: (T, U) => Status[R]): Status[R] = (a, b) match {
|
||||
case (SingleStatus(t), SingleStatus(u)) => f(t, u)
|
||||
@ -205,6 +205,23 @@ object Status {
|
||||
case _ => AnyStatus -> AnyStatus
|
||||
}
|
||||
|
||||
def adc(value: Status[Int], carry: Status[Boolean]): (Status[Int], Status[Boolean]) = (inner, value, carry) match {
|
||||
case (SingleStatus(x), SingleStatus(y), SingleStatus(false)) =>
|
||||
SingleStatus((x + y) & 0xff) -> SingleStatus((x.&(0xff) + y.&(0xff)) > 0xff)
|
||||
case (SingleStatus(x), SingleStatus(y), SingleStatus(true)) =>
|
||||
SingleStatus((x + y + 1) & 0xff) -> SingleStatus((x.&(0xff) + y.&(0xff) + 1) > 0xff)
|
||||
case (SingleStatus(x), SingleStatus(y), AnyStatus) => x + y match {
|
||||
case 255 => AnyStatus -> AnyStatus
|
||||
case z if z < 255 => AnyStatus -> SingleFalse
|
||||
case z if z > 255 => AnyStatus -> SingleTrue
|
||||
}
|
||||
case (SingleStatus(0), AnyStatus, SingleStatus(false))
|
||||
| (AnyStatus, SingleStatus(0), SingleStatus(false)) => AnyStatus -> SingleFalse
|
||||
case (SingleStatus(0xff), AnyStatus, SingleStatus(true))
|
||||
| (AnyStatus, SingleStatus(0xff), SingleStatus(true)) => AnyStatus -> SingleTrue
|
||||
case _ => AnyStatus -> AnyStatus
|
||||
}
|
||||
|
||||
def sbc(value: Int, carry: Status[Boolean], decimal: Status[Boolean]): (Status[Int], Status[Boolean]) = inner match {
|
||||
case SingleStatus(x) => decimal match {
|
||||
case SingleStatus(false) => carry match {
|
||||
|
@ -1,6 +1,6 @@
|
||||
package millfork.assembly.z80.opt
|
||||
|
||||
import millfork.assembly.opt.{AnyStatus, SingleStatus, Status}
|
||||
import millfork.assembly.opt.{AnyStatus, FlowCache, SingleStatus, Status}
|
||||
import millfork.assembly.z80._
|
||||
import millfork.env._
|
||||
import millfork.node.ZRegister
|
||||
@ -11,7 +11,10 @@ import millfork.{CompilationFlag, CompilationOptions, Cpu}
|
||||
*/
|
||||
object CoarseFlowAnalyzer {
|
||||
|
||||
val cache = new FlowCache[ZLine, CpuStatus]("z80 forward")
|
||||
|
||||
def analyze(f: NormalFunction, code: List[ZLine], compilationOptions: CompilationOptions): List[CpuStatus] = {
|
||||
cache.get(code).foreach(return _)
|
||||
val initialStatus = CpuStatus()
|
||||
val functionStartStatus = CpuStatus()
|
||||
val emptyStatus = CpuStatus()
|
||||
@ -45,45 +48,84 @@ object CoarseFlowAnalyzer {
|
||||
case _ => None
|
||||
}).fold(currentStatus)(_ ~ _)
|
||||
|
||||
case ZLine0(CALL, _, MemoryAddressConstant(fun: FunctionInMemory)) =>
|
||||
case ZLine0(CALL, reg, MemoryAddressConstant(fun: FunctionInMemory)) =>
|
||||
val n = fun.name
|
||||
val result = initialStatus.copy(memIx = currentStatus.memIx)
|
||||
currentStatus = result.copy(
|
||||
b = if (preservesB(n)) currentStatus.b else result.b,
|
||||
c = if (preservesC(n)) currentStatus.c else result.c,
|
||||
d = if (preservesD(n)) currentStatus.d else result.d,
|
||||
e = if (preservesE(n)) currentStatus.e else result.e,
|
||||
h = if (preservesH(n)) currentStatus.h else result.h,
|
||||
l = if (preservesL(n)) currentStatus.l else result.l
|
||||
)
|
||||
val mayBeCalled = reg match {
|
||||
case IfFlagSet(f) => !currentStatus.getFlag(f).contains(false)
|
||||
case IfFlagClear(f) => !currentStatus.getFlag(f).contains(true)
|
||||
case _ => true
|
||||
}
|
||||
if (mayBeCalled) {
|
||||
val result = initialStatus.copy(memIx = currentStatus.memIx)
|
||||
currentStatus = result.copy(
|
||||
b = if (preservesB(n)) currentStatus.b else result.b,
|
||||
c = if (preservesC(n)) currentStatus.c else result.c,
|
||||
d = if (preservesD(n)) currentStatus.d else result.d,
|
||||
e = if (preservesE(n)) currentStatus.e else result.e,
|
||||
h = if (preservesH(n)) currentStatus.h else result.h,
|
||||
l = if (preservesL(n)) currentStatus.l else result.l
|
||||
)
|
||||
}
|
||||
|
||||
case ZLine0(CALL, _, _) =>
|
||||
case ZLine0(NOP | DISCARD_A | DISCARD_BC | DISCARD_DE | DISCARD_HL | DISCARD_F, _, _) =>
|
||||
()
|
||||
case ZLine0(PUSH, _, _) =>
|
||||
()
|
||||
case ZLine0(POP, OneRegister(r), _) =>
|
||||
currentStatus = currentStatus.setRegister(r, AnyStatus)
|
||||
|
||||
case ZLine0(JR | JP | RET, IfFlagSet(flag), _) =>
|
||||
currentStatus = currentStatus.setFlag(flag, newStatus = false)
|
||||
|
||||
case ZLine0(JR | JP | RET, IfFlagClear(flag), _) =>
|
||||
currentStatus = currentStatus.setFlag(flag, newStatus = true)
|
||||
|
||||
case ZLine0(JR | JP | RET, NoRegisters | OneRegister(_), _) =>
|
||||
currentStatus = initialStatus.copy(memIx = currentStatus.memIx)
|
||||
|
||||
case ZLine0(DJNZ, _, _) =>
|
||||
// TODO
|
||||
currentStatus = currentStatus.copy(
|
||||
b = Status.SingleZero,
|
||||
zf = Status.SingleTrue,
|
||||
nf = AnyStatus,
|
||||
cf = AnyStatus,
|
||||
hf = AnyStatus,
|
||||
sf = AnyStatus)
|
||||
|
||||
case ZLine0(BYTE, _, _) =>
|
||||
currentStatus = initialStatus
|
||||
|
||||
case ZLine0(ADD, OneRegister(ZRegister.IMM_8), NumericConstant(0, _)) =>
|
||||
currentStatus = currentStatus.copy(
|
||||
nf = Status.SingleFalse,
|
||||
cf = Status.SingleFalse,
|
||||
zf = currentStatus.a.map(_.&(0xff) == 0),
|
||||
sf = currentStatus.a.map(_.&(0x80) == 0),
|
||||
pf = if (z80) Status.SingleFalse else AnyStatus,
|
||||
hf = Status.SingleFalse)
|
||||
case ZLine0(SUB, OneRegister(ZRegister.IMM_8), NumericConstant(0, _)) =>
|
||||
currentStatus = currentStatus.copy(
|
||||
nf = Status.SingleTrue,
|
||||
cf = Status.SingleFalse,
|
||||
zf = currentStatus.a.map(_.&(0xff) == 0),
|
||||
sf = currentStatus.a.map(_.&(0x80) == 0),
|
||||
zf = currentStatus.a.z(),
|
||||
sf = currentStatus.a.n(),
|
||||
pf = if (z80) Status.SingleFalse else AnyStatus,
|
||||
hf = Status.SingleFalse)
|
||||
|
||||
case l@ZLine0(ADD, OneRegister(ZRegister.IMM_8), NumericConstant(n, _)) =>
|
||||
val (newA, newC) = currentStatus.a.adc(n.toInt, currentStatus.cf, Status.SingleFalse)
|
||||
currentStatus = currentStatus.copy(a = newA,
|
||||
nf = Status.SingleFalse, cf = newC, zf = newA.z(), sf = newA.n(), pf = AnyStatus, hf = AnyStatus)
|
||||
case l@ZLine0(ADC, OneRegister(ZRegister.IMM_8), NumericConstant(n, _)) =>
|
||||
val (newA, newC) = currentStatus.a.adc(n.toInt, currentStatus.cf, Status.SingleFalse)
|
||||
currentStatus = currentStatus.copy(a = newA,
|
||||
nf = Status.SingleFalse, cf = newC, zf = newA.z(), sf = newA.n(), pf = AnyStatus, hf = AnyStatus)
|
||||
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)
|
||||
val (newA, newC) = currentStatus.a.adc(currentStatus.getRegister(s), Status.SingleFalse)
|
||||
currentStatus = currentStatus.copy(a = newA,
|
||||
nf = Status.SingleFalse, cf = newC, zf = newA.z(), sf = newA.n(), pf = AnyStatus, hf = AnyStatus)
|
||||
case l@ZLine0(ADC, OneRegister(s), _) =>
|
||||
val (newA, newC) = currentStatus.a.adc(currentStatus.getRegister(s), currentStatus.cf)
|
||||
currentStatus = currentStatus.copy(a = newA,
|
||||
nf = Status.SingleFalse, cf = newC, zf = newA.z(), sf = newA.n(), pf = AnyStatus, hf = AnyStatus)
|
||||
|
||||
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 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)
|
||||
@ -99,21 +141,50 @@ object CoarseFlowAnalyzer {
|
||||
nf = Status.SingleFalse, cf = Status.SingleFalse, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
|
||||
|
||||
case ZLine0(INC, OneRegister(r), _) =>
|
||||
val newV = currentStatus.getRegister(r).map(i => i.+(1).&(0xff))
|
||||
currentStatus = currentStatus.
|
||||
copy(cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus).
|
||||
setRegister(r, currentStatus.getRegister(r).map(i => i.+(1).&(0xff)))
|
||||
setRegister(r, newV)
|
||||
case ZLine0(DEC, OneRegister(r), _) =>
|
||||
val newV = currentStatus.getRegister(r).map(i => i.-(1).&(0xff))
|
||||
currentStatus = currentStatus.
|
||||
copy(cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus).
|
||||
setRegister(r, currentStatus.getRegister(r).map(i => i.-(1).&(0xff)))
|
||||
setRegister(r, newV)
|
||||
case ZLine0(INC, OneRegisterOffset(r, o), _) =>
|
||||
val newV = currentStatus.getRegister(r, o).map(i => i.+(1).&(0xff))
|
||||
currentStatus = currentStatus.
|
||||
copy(cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus).
|
||||
setRegister(r, newV, o)
|
||||
case ZLine0(DEC, OneRegisterOffset(r, o), _) =>
|
||||
val newV = currentStatus.getRegister(r, o).map(i => i.-(1).&(0xff))
|
||||
currentStatus = currentStatus.
|
||||
copy(cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus).
|
||||
setRegister(r, newV, o)
|
||||
|
||||
case ZLine0(INC_16, OneRegister(r), _) =>
|
||||
val newV = currentStatus.getRegister(r).map(i => i.+(1).&(0xffff))
|
||||
currentStatus = currentStatus.
|
||||
copy(cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus).
|
||||
setRegister(r, newV)
|
||||
case ZLine0(DEC_16, OneRegister(r), _) =>
|
||||
val newV = currentStatus.getRegister(r).map(i => i.-(1).&(0xffff))
|
||||
currentStatus = currentStatus.
|
||||
copy(cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus).
|
||||
setRegister(r, newV)
|
||||
|
||||
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 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 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 l@ZLine0(ADD, OneRegisterOffset(s, o), _) =>
|
||||
val (newA, newC) = currentStatus.a.adc(currentStatus.getRegister(s, o), Status.SingleFalse)
|
||||
currentStatus = currentStatus.copy(a = newA,
|
||||
nf = Status.SingleFalse, cf = newC, zf = newA.z(), sf = newA.n(), pf = AnyStatus, hf = AnyStatus)
|
||||
case l@ZLine0(ADC, OneRegisterOffset(s, o), _) =>
|
||||
val (newA, newC) = currentStatus.a.adc(currentStatus.getRegister(s, o), currentStatus.cf)
|
||||
currentStatus = currentStatus.copy(a = newA,
|
||||
nf = Status.SingleFalse, cf = newC, zf = newA.z(), sf = newA.n(), pf = AnyStatus, hf = AnyStatus)
|
||||
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)
|
||||
@ -167,6 +238,43 @@ object CoarseFlowAnalyzer {
|
||||
case ZLine0(CCF, _, _) =>
|
||||
currentStatus = currentStatus.copy(cf = currentStatus.cf.negate, hf = AnyStatus, nf = AnyStatus)
|
||||
|
||||
case ZLine0(CPL, _, _) =>
|
||||
currentStatus = currentStatus.copy(a = currentStatus.a.map(_ ^ 0xff), hf = AnyStatus, nf = Status.SingleTrue)
|
||||
case ZLine0(NEG, _, _) =>
|
||||
currentStatus = currentStatus.copy(
|
||||
a = currentStatus.a.map(x => (-x)&0xff),
|
||||
hf = AnyStatus,
|
||||
zf = currentStatus.a.z(),
|
||||
sf = AnyStatus,
|
||||
cf = AnyStatus,
|
||||
pf = AnyStatus,
|
||||
nf = Status.SingleTrue)
|
||||
case ZLine0(DAA, _, _) =>
|
||||
// TODO: full algorithm?
|
||||
currentStatus = currentStatus.copy(
|
||||
a = if (currentStatus.h.contains(false)) currentStatus.a else AnyStatus,
|
||||
hf = AnyStatus,
|
||||
zf = AnyStatus,
|
||||
sf = AnyStatus,
|
||||
cf = AnyStatus,
|
||||
pf = AnyStatus)
|
||||
|
||||
case ZLine0(BIT7, OneRegister(r), _) =>
|
||||
currentStatus = currentStatus.copy(
|
||||
zf = currentStatus.getRegister(r).bit7.negate,
|
||||
hf = Status.SingleTrue,
|
||||
sf = AnyStatus,
|
||||
pf = AnyStatus,
|
||||
nf = Status.SingleFalse)
|
||||
case ZLine0(BIT0, OneRegister(r), _) =>
|
||||
currentStatus = currentStatus.copy(
|
||||
zf = currentStatus.getRegister(r).bit0.negate,
|
||||
hf = Status.SingleTrue,
|
||||
sf = AnyStatus,
|
||||
pf = AnyStatus,
|
||||
nf = Status.SingleFalse)
|
||||
|
||||
|
||||
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)
|
||||
@ -187,6 +295,6 @@ object CoarseFlowAnalyzer {
|
||||
// println("---------------------")
|
||||
}
|
||||
|
||||
flagArray.toList
|
||||
cache.put(code, flagArray.toList)
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ case class CpuStatus(a: Status[Int] = UnknownStatus,
|
||||
case ZRegister.BC => this.copy(b = value.hi, c = value.lo)
|
||||
case ZRegister.DE => this.copy(d = value.hi, e = value.lo)
|
||||
case ZRegister.HL => this.copy(h = value.hi, l = value.lo, hl = value.map(NumericConstant(_, 2)))
|
||||
case ZRegister.IX => this.copy(ixh = value.hi, ixl = value.lo)
|
||||
case ZRegister.IX => this.copy(ixh = value.hi, ixl = value.lo, memIx = Map())
|
||||
case ZRegister.IY => this.copy(iyh = value.hi, iyl = value.lo)
|
||||
case ZRegister.AF => this.copy(a = value.hi, cf = AnyStatus, zf = AnyStatus, hf = AnyStatus, pf = AnyStatus, sf = AnyStatus)
|
||||
}
|
||||
@ -104,6 +104,18 @@ case class CpuStatus(a: Status[Int] = UnknownStatus,
|
||||
case ZFlag.S => sf
|
||||
case ZFlag.N => nf
|
||||
}
|
||||
|
||||
def setFlag(register: ZFlag.Value, newStatus: Boolean): CpuStatus = {
|
||||
val st = if (newStatus) Status.SingleTrue else Status.SingleFalse
|
||||
register match {
|
||||
case ZFlag.C => copy(cf = st)
|
||||
case ZFlag.H => copy(hf = st)
|
||||
case ZFlag.P => copy(pf = st)
|
||||
case ZFlag.Z => copy(zf = st)
|
||||
case ZFlag.S => copy(sf = st)
|
||||
case ZFlag.N => copy(nf = st)
|
||||
}
|
||||
}
|
||||
def ~(that: CpuStatus) = new CpuStatus(
|
||||
a = this.a ~ that.a,
|
||||
b = this.b ~ that.b,
|
||||
|
@ -14,9 +14,9 @@ import scala.collection.mutable
|
||||
object JumpFollowing {
|
||||
|
||||
def apply(options: CompilationOptions, code: List[ZLine]): List[ZLine] = {
|
||||
val labelsToRet = mutable.Set[String]()
|
||||
val labelsToJumps = mutable.Map[String, String]()
|
||||
val currentLabels = mutable.Set[String]()
|
||||
val labelsToRet = new mutable.HashSet[String]()
|
||||
val labelsToJumps = new mutable.HashMap[String, String]()
|
||||
val currentLabels = new mutable.HashSet[String]()
|
||||
for (line <- code) {
|
||||
line match {
|
||||
case ZLine0(LABEL, _, MemoryAddressConstant(Label(label))) =>
|
||||
|
@ -1,5 +1,6 @@
|
||||
package millfork.assembly.z80.opt
|
||||
|
||||
import millfork.assembly.opt.FlowCache
|
||||
import millfork.assembly.z80._
|
||||
import millfork.env._
|
||||
import millfork.node.ZRegister
|
||||
@ -175,6 +176,8 @@ case class CpuImportance(a: Importance = UnknownImportance,
|
||||
|
||||
object ReverseFlowAnalyzer {
|
||||
|
||||
val cache = new FlowCache[ZLine, CpuImportance]("z80 reverse")
|
||||
|
||||
val readsA = Set("__mul_u8u8u8", "__mul_u16u8u16")
|
||||
val readsB = Set("")
|
||||
val readsC = Set("")
|
||||
@ -185,6 +188,7 @@ object ReverseFlowAnalyzer {
|
||||
|
||||
//noinspection RedundantNewCaseClass
|
||||
def analyze(f: NormalFunction, code: List[ZLine]): List[CpuImportance] = {
|
||||
cache.get(code).foreach(return _)
|
||||
val importanceArray = Array.fill[CpuImportance](code.length)(new CpuImportance())
|
||||
val codeArray = code.toArray
|
||||
|
||||
@ -460,7 +464,7 @@ object ReverseFlowAnalyzer {
|
||||
// }
|
||||
// println("---------------------")
|
||||
|
||||
importanceArray.toList
|
||||
cache.put(code, importanceArray.toList)
|
||||
}
|
||||
|
||||
private def getLabelIndex(codeArray: Array[ZLine], L: String) = {
|
||||
|
@ -1,6 +1,6 @@
|
||||
package millfork.assembly.z80.opt
|
||||
|
||||
import millfork.CompilationOptions
|
||||
import millfork.{CompilationFlag, CompilationOptions}
|
||||
import millfork.assembly._
|
||||
import millfork.assembly.opt.{AnyStatus, SingleStatus}
|
||||
import millfork.assembly.z80._
|
||||
@ -39,15 +39,15 @@ class RuleBasedAssemblyOptimization(val name: String, val needsFlowInfo: FlowInf
|
||||
actualRules.foreach(_.pattern.validate(needsFlowInfo))
|
||||
|
||||
override def optimize(f: NormalFunction, code: List[ZLine], optimizationContext: OptimizationContext): List[ZLine] = {
|
||||
val effectiveCode = code.map(a => a.copy(parameter = a.parameter.quickSimplify))
|
||||
val taggedCode = FlowAnalyzer.analyze(f, effectiveCode, optimizationContext.options, needsFlowInfo)
|
||||
optimizeImpl(f, taggedCode, optimizationContext)
|
||||
val taggedCode = FlowAnalyzer.analyze(f, code, optimizationContext.options, needsFlowInfo)
|
||||
val (changed, optimized) = optimizeImpl(f, taggedCode, optimizationContext)
|
||||
if (changed) optimized else code
|
||||
}
|
||||
|
||||
def optimizeImpl(f: NormalFunction, code: List[(FlowInfo, ZLine)], optimizationContext: OptimizationContext): List[ZLine] = {
|
||||
def optimizeImpl(f: NormalFunction, code: List[(FlowInfo, ZLine)], optimizationContext: OptimizationContext): (Boolean, List[ZLine]) = {
|
||||
val log = optimizationContext.log
|
||||
code match {
|
||||
case Nil => Nil
|
||||
case Nil => (false, Nil)
|
||||
case head :: tail =>
|
||||
for ((rule, index) <- actualRules.zipWithIndex) {
|
||||
val ctx = new AssemblyMatchingContext(optimizationContext.options)
|
||||
@ -56,8 +56,9 @@ class RuleBasedAssemblyOptimization(val name: String, val needsFlowInfo: FlowInf
|
||||
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))
|
||||
if (!ctx.compilationOptions.flag(CompilationFlag.LineNumbersInAssembly)) optimizedChunk
|
||||
else 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
|
||||
@ -76,20 +77,21 @@ class RuleBasedAssemblyOptimization(val name: String, val needsFlowInfo: FlowInf
|
||||
optimizedChunkWithSource.filter(_.isPrintable).foreach(l => log.trace(l.toString))
|
||||
}
|
||||
if (needsFlowInfo != FlowInfoRequirement.NoRequirement) {
|
||||
return optimizedChunkWithSource ++ optimizeImpl(f, rest, optimizationContext)
|
||||
return true -> (optimizedChunkWithSource ++ optimizeImpl(f, rest, optimizationContext)._2)
|
||||
} else {
|
||||
return optimize(f, optimizedChunkWithSource ++ rest.map(_._2), optimizationContext)
|
||||
return true -> optimize(f, optimizedChunkWithSource ++ rest.map(_._2), optimizationContext)
|
||||
}
|
||||
case None => ()
|
||||
}
|
||||
}
|
||||
head._2 :: optimizeImpl(f, tail, optimizationContext)
|
||||
val (changedTail, optimizedTail) = optimizeImpl(f, tail, optimizationContext)
|
||||
(changedTail, head._2 :: optimizedTail)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AssemblyMatchingContext(val compilationOptions: CompilationOptions) {
|
||||
private val map = mutable.Map[Int, Any]()
|
||||
private val map = new mutable.HashMap[Int, Any]()
|
||||
|
||||
def log: Logger = compilationOptions.log
|
||||
|
||||
@ -697,6 +699,8 @@ case class Both(l: AssemblyLinePattern, r: AssemblyLinePattern) extends Assembly
|
||||
l.matchLineTo(ctx, flowInfo, line) && r.matchLineTo(ctx, flowInfo, line)
|
||||
|
||||
override def toString: String = l + " ∧ " + r
|
||||
|
||||
override def &(x: AssemblyLinePattern): AssemblyLinePattern = Both(l, Both(r, x))
|
||||
}
|
||||
|
||||
case class EitherPattern(l: AssemblyLinePattern, r: AssemblyLinePattern) extends AssemblyLinePattern {
|
||||
@ -709,6 +713,8 @@ case class EitherPattern(l: AssemblyLinePattern, r: AssemblyLinePattern) extends
|
||||
l.matchLineTo(ctx, flowInfo, line) || r.matchLineTo(ctx, flowInfo, line)
|
||||
|
||||
override def toString: String = s"($l ∨ $r)"
|
||||
|
||||
override def |(x: AssemblyLinePattern): AssemblyLinePattern = EitherPattern(l, EitherPattern(r, x))
|
||||
}
|
||||
|
||||
case object Elidable extends AssemblyLinePattern {
|
||||
|
@ -465,12 +465,15 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
|
||||
inlinedFunctions,
|
||||
options.jobContext))
|
||||
unoptimizedCodeSize += unoptimized.map(_.sizeInBytes).sum
|
||||
val code = optimizations.foldLeft(unoptimized) { (c, opt) =>
|
||||
opt.optimize(f, c, OptimizationContext(options, labelMap, env.maybeGet[ThingInMemory]("__reg"), niceFunctionProperties))
|
||||
val code = optimizations.foldLeft(quickSimplify(unoptimized)) { (c, opt) =>
|
||||
val code = opt.optimize(f, c, OptimizationContext(options, labelMap, env.maybeGet[ThingInMemory]("__reg"), niceFunctionProperties))
|
||||
if (code eq c) code else quickSimplify(code)
|
||||
}
|
||||
performFinalOptimizationPass(f, optimizations.nonEmpty, options, code)
|
||||
}
|
||||
|
||||
def quickSimplify(code: List[T]): List[T]
|
||||
|
||||
def gatherNiceFunctionProperties(niceFunctionProperties: mutable.Set[(NiceFunctionProperty, String)], functionName: String, code: List[T]): Unit
|
||||
|
||||
def performFinalOptimizationPass(f: NormalFunction, actuallyOptimize: Boolean, options: CompilationOptions, code: List[T]): List[T]
|
||||
|
@ -102,6 +102,8 @@ class MosAssembler(program: Program,
|
||||
}
|
||||
}
|
||||
|
||||
override def quickSimplify(code: List[AssemblyLine]): List[AssemblyLine] = code.map(a => a.copy(parameter = a.parameter.quickSimplify))
|
||||
|
||||
override def gatherNiceFunctionProperties(niceFunctionProperties: mutable.Set[(NiceFunctionProperty, String)], functionName: String, code: List[AssemblyLine]): Unit = {
|
||||
import Opcode._
|
||||
import AddrMode._
|
||||
|
@ -626,6 +626,8 @@ class Z80Assembler(program: Program,
|
||||
|
||||
override def injectLabels(labelMap: Map[String, Int], code: List[ZLine]): List[ZLine] = code // TODO
|
||||
|
||||
override def quickSimplify(code: List[ZLine]): List[ZLine] = code.map(a => a.copy(parameter = a.parameter.quickSimplify))
|
||||
|
||||
override def gatherNiceFunctionProperties(niceFunctionProperties: mutable.Set[(NiceFunctionProperty, String)], functionName: String, code: List[ZLine]): Unit = {
|
||||
// do nothing yet
|
||||
}
|
||||
|
@ -12,6 +12,8 @@ import millfork.node._
|
||||
import millfork.output.{DivisibleAlignment, MemoryAlignment, NoAlignment}
|
||||
import millfork.{CompilationFlag, CompilationOptions, SeparatedList}
|
||||
|
||||
import scala.collection.immutable.BitSet
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
*/
|
||||
@ -90,13 +92,13 @@ abstract class MfParser[T](fileId: String, input: String, currentDirectory: Stri
|
||||
|
||||
val textLiteralAtom: P[TextLiteralExpression] = textLiteral.map(TextLiteralExpression)
|
||||
|
||||
val literalAtom: P[LiteralExpression] = charAtom | binaryAtom | hexAtom | octalAtom | quaternaryAtom | decimalAtom
|
||||
val literalAtom: P[LiteralExpression] = binaryAtom | hexAtom | octalAtom | quaternaryAtom | decimalAtom | charAtom
|
||||
|
||||
val literalAtomWithIntel: P[LiteralExpression] = charAtom | binaryAtom | hexAtom | octalAtom | quaternaryAtom | intelHexAtom | decimalAtom
|
||||
val literalAtomWithIntel: P[LiteralExpression] = binaryAtom | hexAtom | octalAtom | quaternaryAtom | intelHexAtom | decimalAtom | charAtom
|
||||
|
||||
val atom: P[Expression] = P(position() ~ (literalAtom | variableAtom | textLiteralAtom)).map{case (p,a) => a.pos(p)}
|
||||
val atom: P[Expression] = P(position() ~ (variableAtom | literalAtom | textLiteralAtom)).map{case (p,a) => a.pos(p)}
|
||||
|
||||
val atomWithIntel: P[Expression] = P(position() ~ (literalAtomWithIntel | variableAtom | textLiteralAtom)).map{case (p,a) => a.pos(p)}
|
||||
val atomWithIntel: P[Expression] = P(position() ~ (variableAtom | literalAtomWithIntel | textLiteralAtom)).map{case (p,a) => a.pos(p)}
|
||||
|
||||
val globalVariableDefinition: P[Seq[DeclarationStatement]] = variableDefinition(true)
|
||||
val localVariableDefinition: P[Seq[DeclarationStatement]] = variableDefinition(false)
|
||||
@ -500,7 +502,7 @@ object MfParser {
|
||||
|
||||
def sign(abs: Long, minus: Boolean): Long = if (minus) -abs else abs
|
||||
|
||||
val invalidCharLiteralTypes: Set[Int] = Set[Int](
|
||||
val invalidCharLiteralTypes: BitSet = BitSet(
|
||||
Character.LINE_SEPARATOR,
|
||||
Character.PARAGRAPH_SEPARATOR,
|
||||
Character.CONTROL,
|
||||
|
Loading…
x
Reference in New Issue
Block a user