1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-07-05 09:28:54 +00:00

Z80: Jump shortening

This commit is contained in:
Karol Stasiak 2018-08-08 13:45:38 +02:00
parent 5c65af17d4
commit 8b09941cef
2 changed files with 64 additions and 1 deletions

View File

@ -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
}
}
}

View File

@ -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