1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-07-13 15:29:01 +00:00

Using short jumps whenever possible

This commit is contained in:
Karol Stasiak 2018-01-20 18:51:49 +01:00
parent 8d818f7624
commit 91acbfae2f
2 changed files with 81 additions and 2 deletions

View File

@ -0,0 +1,78 @@
package millfork.assembly.opt
import millfork.{CompilationFlag, CompilationOptions}
import millfork.assembly.{AddrMode, AssemblyLine, Opcode}
import millfork.assembly.Opcode._
import millfork.env.{Label, MemoryAddressConstant, NormalFunction}
import millfork.error.ErrorReporting
/**
* @author Karol Stasiak
*/
object JumpShortening {
def validShortJump(thisOffset: Int, labelOffset: Int): Boolean = {
val distance = labelOffset - (thisOffset + 2)
distance.toByte == distance
}
def apply(f: NormalFunction, code: List[AssemblyLine], options: CompilationOptions): List[AssemblyLine] = {
val offsets = new Array[Int](code.length)
var o = 0
code.zipWithIndex.foreach{
case (line, ix) =>
offsets(ix) = o
o += line.sizeInBytes
}
val labelOffsets = code.zipWithIndex.flatMap {
case (AssemblyLine(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) =>
labelOffsets.get(label).fold(line) { labelOffset =>
val thisOffset = offsets(ix)
if (validShortJump(thisOffset, labelOffset)) {
val result = line.copy(opcode = BRA, addrMode = AddrMode.Relative)
ErrorReporting.debug("Changing branch from long to short")
ErrorReporting.trace(line.toString)
ErrorReporting.trace(" ↓")
ErrorReporting.trace(result.toString)
result
} else line
}
case (line, _) => line
}
} else {
FlowAnalyzer.analyze(f, code, options, FlowInfoRequirement.ForwardFlow).zipWithIndex.map {
case ((info, line@AssemblyLine(JMP, AddrMode.Absolute, MemoryAddressConstant(Label(label)), _)), ix) =>
labelOffsets.get(label).fold(line) { labelOffset =>
val thisOffset = offsets(ix)
if (validShortJump(thisOffset, labelOffset)) {
val bra =
if (info.statusBefore.z.contains(true)) BEQ
else if (info.statusBefore.z.contains(false)) BNE
else if (info.statusBefore.n.contains(true)) BMI
else if (info.statusBefore.n.contains(false)) BPL
else if (info.statusBefore.v.contains(true)) BVS
else if (info.statusBefore.v.contains(false)) BVC
else if (info.statusBefore.c.contains(true)) BCS
else if (info.statusBefore.c.contains(false)) BCC
else JMP
if (bra != JMP) {
val result = line.copy(opcode = bra, addrMode = AddrMode.Relative)
ErrorReporting.debug("Changing branch from long to short")
ErrorReporting.trace(line.toString)
ErrorReporting.trace(" ↓")
ErrorReporting.trace(result.toString)
result
} else line
} else line
}
case ((_, line), _) => line
}
}
}
}

View File

@ -1,6 +1,6 @@
package millfork.output
import millfork.assembly.opt.AssemblyOptimization
import millfork.assembly.opt.{AssemblyOptimization, JumpShortening}
import millfork.assembly.{AddrMode, AssemblyLine, Opcode}
import millfork.compiler.{CompilationContext, MfCompiler}
import millfork.env._
@ -305,7 +305,8 @@ class Assembler(private val program: Program, private val rootEnv: Environment)
val code = optimizations.foldLeft(unoptimized) { (c, opt) =>
opt.optimize(f, c, options)
}
code
if (optimizations.nonEmpty) JumpShortening(f, JumpShortening(f, code, options), options)
else code
}
private def outputFunction(code: List[AssemblyLine], startFrom: Int, assOut: mutable.ArrayBuffer[String], options: CompilationOptions): Int = {