mirror of
https://github.com/KarolS/millfork.git
synced 2025-01-12 19:29:51 +00:00
Fixing invalid short jumps
This commit is contained in:
parent
a16f662031
commit
70818cc3d2
@ -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
|
||||
|
79
src/main/scala/millfork/assembly/opt/JumpFixing.scala
Normal file
79
src/main/scala/millfork/assembly/opt/JumpFixing.scala
Normal 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
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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 = {
|
||||
|
Loading…
x
Reference in New Issue
Block a user