mirror of
https://github.com/KarolS/millfork.git
synced 2024-09-10 11:54:30 +00:00
Using short jumps whenever possible
This commit is contained in:
parent
8d818f7624
commit
91acbfae2f
78
src/main/scala/millfork/assembly/opt/JumpShortening.scala
Normal file
78
src/main/scala/millfork/assembly/opt/JumpShortening.scala
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
package millfork.output
|
package millfork.output
|
||||||
|
|
||||||
import millfork.assembly.opt.AssemblyOptimization
|
import millfork.assembly.opt.{AssemblyOptimization, JumpShortening}
|
||||||
import millfork.assembly.{AddrMode, AssemblyLine, Opcode}
|
import millfork.assembly.{AddrMode, AssemblyLine, Opcode}
|
||||||
import millfork.compiler.{CompilationContext, MfCompiler}
|
import millfork.compiler.{CompilationContext, MfCompiler}
|
||||||
import millfork.env._
|
import millfork.env._
|
||||||
@ -305,7 +305,8 @@ class Assembler(private val program: Program, private val rootEnv: Environment)
|
|||||||
val code = optimizations.foldLeft(unoptimized) { (c, opt) =>
|
val code = optimizations.foldLeft(unoptimized) { (c, opt) =>
|
||||||
opt.optimize(f, c, options)
|
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 = {
|
private def outputFunction(code: List[AssemblyLine], startFrom: Int, assOut: mutable.ArrayBuffer[String], options: CompilationOptions): Int = {
|
||||||
|
Loading…
Reference in New Issue
Block a user