1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-06-25 19:29:49 +00:00

Fixing invalid short jumps

This commit is contained in:
Karol Stasiak 2018-06-11 00:04:24 +02:00
parent a16f662031
commit 70818cc3d2
3 changed files with 84 additions and 3 deletions

View File

@ -38,6 +38,8 @@ where `11111` is a sequential number and `xx` is the type:
* `is` optimized addition of carry using undocumented instructions
* `lj` extra labels generated when converting invalid short jumps to long jumps
* `no` nonet to word extension caused by the `nonet` operator
* `od` end of a `do-while` statement

View File

@ -0,0 +1,79 @@
package millfork.assembly.opt
import java.util.concurrent.atomic.AtomicInteger
import millfork.assembly.Opcode._
import millfork.assembly.{AddrMode, AssemblyLine, Opcode}
import millfork.compiler.MfCompiler
import millfork.env.{Label, MemoryAddressConstant, NormalFunction}
import millfork.error.ErrorReporting
import millfork.{CompilationFlag, CompilationOptions}
/**
* @author Karol Stasiak
*/
object JumpFixing {
val counter = new AtomicInteger(80000)
def generateNextLabel() = f".lj${counter.getAndIncrement()}%05d"
def invalidShortJump(thisOffset: Int, labelOffset: Int): Boolean = {
val distance = labelOffset - (thisOffset + 2)
distance.toByte != distance
}
private def negate(opcode: Opcode.Value) = opcode match {
case BEQ => BNE
case BNE => BEQ
case BCC => BCS
case BCS => BCC
case BVC => BVS
case BVS => BVC
case BMI => BPL
case BPL => BMI
}
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
var changed = false
val result = code.zipWithIndex.flatMap {
case (line@AssemblyLine(op, AddrMode.Relative, MemoryAddressConstant(Label(label)), true), ix) =>
labelOffsets.get(label).fold(List(line)) { labelOffset =>
val thisOffset = offsets(ix)
if (invalidShortJump(thisOffset, labelOffset)) {
changed = true
val long: List[AssemblyLine] = op match {
case BRA => List(line.copy(opcode = JMP, addrMode = AddrMode.Absolute))
case BSR => List(line.copy(opcode = JSR, addrMode = AddrMode.Absolute))
case _ =>
val label = generateNextLabel()
List(
AssemblyLine.relative(negate(op), label),
line.copy(opcode = JMP, addrMode = AddrMode.Absolute),
AssemblyLine.label(label)
)
}
ErrorReporting.debug("Changing branch from short to long")
ErrorReporting.trace(line.toString)
ErrorReporting.trace(" ↓")
long.foreach(l => ErrorReporting.trace(l.toString))
long
} else List(line)
}
case (line, _) => List(line)
}
if (changed) apply(f, result, options) else result
}
}

View File

@ -1,6 +1,6 @@
package millfork.output
import millfork.assembly.opt.{AssemblyOptimization, HudsonOptimizations, JumpShortening}
import millfork.assembly.opt.{AssemblyOptimization, HudsonOptimizations, JumpFixing, JumpShortening}
import millfork.assembly.{AddrMode, AssemblyLine, Opcode}
import millfork.compiler.{CompilationContext, MfCompiler}
import millfork.env._
@ -446,9 +446,9 @@ class Assembler(private val program: Program, private val rootEnv: Environment,
}
if (optimizations.nonEmpty) {
val finalCode = if (options.flag(CompilationFlag.EmitHudsonOpcodes)) HudsonOptimizations.removeLoadZero(code) else code
JumpShortening(f, JumpShortening(f, finalCode, options), options)
JumpShortening(f, JumpShortening(f, JumpFixing(f, finalCode, options), options), options)
}
else code
else JumpFixing(f, code, options)
}
private def outputFunction(bank: String, code: List[AssemblyLine], startFrom: Int, assOut: mutable.ArrayBuffer[String], options: CompilationOptions): Int = {