mirror of
https://github.com/KarolS/millfork.git
synced 2024-09-10 11:54:30 +00:00
Z80: Jump shortening
This commit is contained in:
parent
5c65af17d4
commit
8b09941cef
@ -0,0 +1,58 @@
|
||||
package millfork.assembly.z80.opt
|
||||
|
||||
import millfork.{CompilationFlag, CompilationOptions}
|
||||
import millfork.assembly.OptimizationContext
|
||||
import millfork.assembly.z80.ZOpcode._
|
||||
import millfork.assembly.z80._
|
||||
import millfork.env.{Label, MemoryAddressConstant, NormalFunction}
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
*/
|
||||
object JumpShortening {
|
||||
|
||||
def validShortJump(thisOffset: Int, labelOffset: Int): Boolean = {
|
||||
val distance = labelOffset - (thisOffset + 2)
|
||||
// TODO: I don't trust the instruction size calculations
|
||||
// distance.toByte == distance
|
||||
distance.abs < 100
|
||||
}
|
||||
|
||||
def apply(f: NormalFunction, code: List[ZLine], options: CompilationOptions): List[ZLine] = {
|
||||
if (!options.flags(CompilationFlag.EmitExtended80Opcodes)) return code
|
||||
val shouldOptimizeAlways = options.flag(CompilationFlag.EmitSharpOpcodes) || options.flag(CompilationFlag.OptimizeForSize)
|
||||
val bePessimistic = options.flag(CompilationFlag.OptimizeForSpeed)
|
||||
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 (ZLine(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) =>
|
||||
labelOffsets.get(label).fold(line) { labelOffset =>
|
||||
val thisOffset = offsets(ix)
|
||||
val willBeTaken = line.registers == NoRegisters ||
|
||||
labelOffset < thisOffset || // jumping back means a loopty-loop TODO: better heuristics
|
||||
bePessimistic // assume jump forward will happen if compiling with -Of
|
||||
val willBeBetter = shouldOptimizeAlways || !willBeTaken
|
||||
if (willBeBetter && validShortJump(thisOffset, labelOffset)) {
|
||||
val result = line.copy(opcode = JR)
|
||||
options.log.debug("Changing branch from long to short")
|
||||
if (options.log.traceEnabled) {
|
||||
options.log.trace(line.toString)
|
||||
options.log.trace(" ↓")
|
||||
options.log.trace(result.toString)
|
||||
}
|
||||
result
|
||||
} else line
|
||||
}
|
||||
case (line, _) => line
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ package millfork.output
|
||||
|
||||
import millfork.{CompilationFlag, CompilationOptions, Cpu, Platform}
|
||||
import millfork.assembly.z80._
|
||||
import millfork.assembly.z80.opt.JumpShortening
|
||||
import millfork.compiler.z80.Z80Compiler
|
||||
import millfork.env._
|
||||
import millfork.error.ConsoleLogger
|
||||
@ -15,7 +16,11 @@ import scala.collection.mutable
|
||||
class Z80Assembler(program: Program,
|
||||
rootEnv: Environment,
|
||||
platform: Platform) extends AbstractAssembler[ZLine](program, rootEnv, platform, Z80InliningCalculator, Z80Compiler) {
|
||||
override def performFinalOptimizationPass(f: NormalFunction, actuallyOptimize: Boolean, options: CompilationOptions, code: List[ZLine]): List[ZLine] = code
|
||||
override def performFinalOptimizationPass(f: NormalFunction, actuallyOptimize: Boolean, options: CompilationOptions, code: List[ZLine]): List[ZLine] = {
|
||||
if (actuallyOptimize) {
|
||||
JumpShortening(f, code, options)
|
||||
} else code
|
||||
}
|
||||
|
||||
private def internalRegisterIndex(reg: ZRegister.Value): Int = reg match {
|
||||
case ZRegister.B => 0
|
||||
|
Loading…
Reference in New Issue
Block a user