mirror of
https://github.com/KarolS/millfork.git
synced 2025-02-06 01:30:13 +00:00
Following jumps. Generating conditional returns/calls.
This commit is contained in:
parent
2d0f3a5a12
commit
9581891d66
62
src/main/scala/millfork/assembly/mos/opt/JumpFollowing.scala
Normal file
62
src/main/scala/millfork/assembly/mos/opt/JumpFollowing.scala
Normal file
@ -0,0 +1,62 @@
|
||||
package millfork.assembly.mos.opt
|
||||
|
||||
import millfork.CompilationOptions
|
||||
import millfork.assembly.mos.{AssemblyLine, OpcodeClasses}
|
||||
import millfork.env.{Label, MemoryAddressConstant}
|
||||
import millfork.assembly.mos.Opcode._
|
||||
import millfork.assembly.mos.AddrMode._
|
||||
|
||||
import scala.collection.mutable
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
*/
|
||||
object JumpFollowing {
|
||||
|
||||
def apply(options: CompilationOptions, code: List[AssemblyLine]): List[AssemblyLine] = {
|
||||
val labelsToRts = mutable.Set[String]()
|
||||
val labelsToRti = mutable.Set[String]()
|
||||
val labelsToRtl = mutable.Set[String]()
|
||||
val labelsToJumps = mutable.Map[String, String]()
|
||||
val currentLabels = mutable.Set[String]()
|
||||
for (line <- code) {
|
||||
line match {
|
||||
case AssemblyLine(LABEL, _, MemoryAddressConstant(Label(label)), _) =>
|
||||
currentLabels += label
|
||||
case AssemblyLine(op, _, _, _) if OpcodeClasses.NoopDiscardsFlags(op) =>
|
||||
case AssemblyLine(LABEL, _, _, _) =>
|
||||
case AssemblyLine(RTS, _, _, _) =>
|
||||
labelsToRts ++= currentLabels
|
||||
currentLabels.clear()
|
||||
case AssemblyLine(RTI, _, _, _) =>
|
||||
labelsToRti ++= currentLabels
|
||||
currentLabels.clear()
|
||||
case AssemblyLine(RTL, _, _, _) =>
|
||||
labelsToRtl ++= currentLabels
|
||||
currentLabels.clear()
|
||||
case AssemblyLine(JMP | BRA, Absolute | Relative, MemoryAddressConstant(Label(label)), _) =>
|
||||
labelsToJumps ++= currentLabels.map(_ -> label)
|
||||
currentLabels.clear()
|
||||
case _ =>
|
||||
currentLabels.clear()
|
||||
}
|
||||
}
|
||||
code.map {
|
||||
case jump@AssemblyLine(JMP | BRA, Absolute | Relative | LongRelative | LongAbsolute, MemoryAddressConstant(Label(label)), true) =>
|
||||
if (labelsToRts(label)) {
|
||||
options.log.debug(s"Optimizing ${jump.opcode} straight into RTS")
|
||||
AssemblyLine.implied(RTS)
|
||||
} else if (labelsToRti(label)) {
|
||||
options.log.debug(s"Optimizing ${jump.opcode} straight into RTI")
|
||||
AssemblyLine.implied(RTI)
|
||||
} else if (labelsToRtl(label)) {
|
||||
options.log.debug(s"Optimizing ${jump.opcode} straight into RTL")
|
||||
AssemblyLine.implied(RTL)
|
||||
} else if (labelsToJumps.contains(label)) {
|
||||
options.log.debug(s"Optimizing ${jump.opcode} straight into a jump")
|
||||
AssemblyLine.absolute(JMP, Label(labelsToJumps(label)))
|
||||
} else jump
|
||||
case x => x
|
||||
}
|
||||
}
|
||||
}
|
@ -17,13 +17,19 @@ object ZFlag extends Enumeration {
|
||||
val AllButZ: Seq[Value] = Seq(P, C, H, N, S)
|
||||
}
|
||||
|
||||
sealed trait ZRegisters
|
||||
sealed trait ZRegisters {
|
||||
def negate: ZRegisters = this
|
||||
}
|
||||
|
||||
case object NoRegisters extends ZRegisters
|
||||
|
||||
case class IfFlagSet(flag: ZFlag.Value) extends ZRegisters
|
||||
case class IfFlagSet(flag: ZFlag.Value) extends ZRegisters {
|
||||
override def negate: ZRegisters = IfFlagClear(flag)
|
||||
}
|
||||
|
||||
case class IfFlagClear(flag: ZFlag.Value) extends ZRegisters
|
||||
case class IfFlagClear(flag: ZFlag.Value) extends ZRegisters {
|
||||
override def negate: ZRegisters = IfFlagSet(flag)
|
||||
}
|
||||
|
||||
case class OneRegister(register: ZRegister.Value) extends ZRegisters {
|
||||
// if (register == ZRegister.MEM_IY_D || register == ZRegister.MEM_IX_D) ???
|
||||
|
@ -0,0 +1,52 @@
|
||||
package millfork.assembly.z80.opt
|
||||
|
||||
import millfork.assembly.z80.ZOpcode._
|
||||
import millfork.assembly.z80._
|
||||
import millfork.env.{Constant, Label, MemoryAddressConstant, NormalFunction}
|
||||
import millfork.parser.Preprocessor.IfContext
|
||||
import millfork.{CompilationFlag, CompilationOptions}
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
*/
|
||||
object ConditionalInstructions {
|
||||
|
||||
def apply(options: CompilationOptions, code: List[ZLine]): List[ZLine] = code match {
|
||||
case (jump@ZLine(JR | JP, IfFlagSet(_) | IfFlagClear(_), MemoryAddressConstant(Label(label)), true)) ::
|
||||
(call@ZLine(CALL, NoRegisters, _, _)) ::
|
||||
xs =>
|
||||
if (startsWithLabel(label, xs)) {
|
||||
val condCall = call.copy(registers = jump.registers.negate)
|
||||
options.log.debug(s"Replacing ${jump.toString.trim} ${call.toString.trim} with ${condCall.toString.trim}")
|
||||
condCall :: apply(options, xs)
|
||||
}else jump :: call :: apply(options, xs)
|
||||
case (jump@ZLine(JR | JP, IfFlagSet(_) | IfFlagClear(_), MemoryAddressConstant(Label(label)), true)) :: xs =>
|
||||
retPrecededByDiscards(xs) match {
|
||||
case Some(rest) if startsWithLabel(label, rest) =>
|
||||
val condRet = ZLine(RET, jump.registers.negate, Constant.Zero)
|
||||
options.log.debug(s"Replacing ${jump.toString.trim} RET with ${condRet.toString.trim}")
|
||||
condRet :: apply(options, rest)
|
||||
|
||||
case _ => jump :: apply(options, xs)
|
||||
}
|
||||
case x :: xs => x :: apply(options, xs)
|
||||
case Nil => Nil
|
||||
}
|
||||
|
||||
private def retPrecededByDiscards(code: List[ZLine]): Option[List[ZLine]] = {
|
||||
code match {
|
||||
case ZLine(op, _, _, _) :: xs if ZOpcodeClasses.NoopDiscards(op) => retPrecededByDiscards(xs)
|
||||
case ZLine(RET, NoRegisters, _, _) :: xs => Some(xs)
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
|
||||
private def startsWithLabel(LabelName: String, code: List[ZLine]): Boolean = {
|
||||
code match {
|
||||
case ZLine(LABEL, _, MemoryAddressConstant(Label(LabelName)), _) :: xs => true
|
||||
case ZLine(LABEL, _, _, _) :: xs => startsWithLabel(LabelName, xs)
|
||||
case ZLine(op, _, _, _) :: xs if ZOpcodeClasses.NoopDiscards(op) => startsWithLabel(LabelName, xs)
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
}
|
47
src/main/scala/millfork/assembly/z80/opt/JumpFollowing.scala
Normal file
47
src/main/scala/millfork/assembly/z80/opt/JumpFollowing.scala
Normal file
@ -0,0 +1,47 @@
|
||||
package millfork.assembly.z80.opt
|
||||
|
||||
import millfork.assembly.z80.ZOpcode._
|
||||
import millfork.assembly.z80._
|
||||
import millfork.env.{Constant, Label, MemoryAddressConstant}
|
||||
import millfork.{CompilationOptions}
|
||||
|
||||
import scala.collection.mutable
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
*/
|
||||
object JumpFollowing {
|
||||
|
||||
def apply(options: CompilationOptions, code: List[ZLine]): List[ZLine] = {
|
||||
val labelsToRet = mutable.Set[String]()
|
||||
val labelsToJumps = mutable.Map[String, String]()
|
||||
val currentLabels = mutable.Set[String]()
|
||||
for (line <- code) {
|
||||
line match {
|
||||
case ZLine(LABEL, _, MemoryAddressConstant(Label(label)), _) =>
|
||||
currentLabels += label
|
||||
case ZLine(op, _, _, _) if ZOpcodeClasses.NoopDiscards(op) =>
|
||||
case ZLine(LABEL, _, _, _) =>
|
||||
case ZLine(RET, NoRegisters, _, _) =>
|
||||
labelsToRet ++= currentLabels
|
||||
currentLabels.clear()
|
||||
case ZLine(JP | JR, NoRegisters, MemoryAddressConstant(Label(label)), _) =>
|
||||
labelsToJumps ++= currentLabels.map(_ -> label)
|
||||
currentLabels.clear()
|
||||
case _ =>
|
||||
currentLabels.clear()
|
||||
}
|
||||
}
|
||||
code.map {
|
||||
case jump@ZLine(JR | JP, cond, MemoryAddressConstant(Label(label)), true) =>
|
||||
if (labelsToRet(label)) {
|
||||
options.log.debug(s"Optimizing ${jump.opcode} straight into RET")
|
||||
ZLine(RET, cond, Constant.Zero)
|
||||
} else if (labelsToJumps.contains(label)) {
|
||||
options.log.debug(s"Optimizing ${jump.opcode} straight into a jump")
|
||||
ZLine.jump(labelsToJumps(label))
|
||||
} else jump
|
||||
case x => x
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
package millfork.output
|
||||
|
||||
import millfork.assembly.mos.opt.{HudsonOptimizations, JumpFixing, JumpShortening}
|
||||
import millfork.assembly.mos.opt.{HudsonOptimizations, JumpFixing, JumpFollowing, JumpShortening}
|
||||
import millfork.assembly._
|
||||
import millfork.env._
|
||||
import millfork.error.{ConsoleLogger, FatalErrorReporting}
|
||||
@ -24,7 +24,7 @@ class MosAssembler(program: Program,
|
||||
val optimizationContext = OptimizationContext(options, Map(), f.environment.maybeGet[ThingInMemory]("__reg"), Set())
|
||||
if (actuallyOptimize) {
|
||||
val finalCode = if (options.flag(CompilationFlag.EmitHudsonOpcodes)) HudsonOptimizations.removeLoadZero(f, code, optimizationContext) else code
|
||||
JumpShortening(f, JumpShortening(f, JumpFixing(f, finalCode, options), optimizationContext), optimizationContext)
|
||||
JumpShortening(f, JumpShortening(f, JumpFixing(f, JumpFollowing(options, finalCode), options), optimizationContext), optimizationContext)
|
||||
}
|
||||
else JumpFixing(f, code, options)
|
||||
}
|
||||
|
@ -2,10 +2,9 @@ package millfork.output
|
||||
|
||||
import millfork.{CompilationFlag, CompilationOptions, Cpu, Platform}
|
||||
import millfork.assembly.z80._
|
||||
import millfork.assembly.z80.opt.JumpShortening
|
||||
import millfork.assembly.z80.opt.{ConditionalInstructions, JumpFollowing, JumpShortening}
|
||||
import millfork.compiler.z80.Z80Compiler
|
||||
import millfork.env._
|
||||
import millfork.error.ConsoleLogger
|
||||
import millfork.node.{NiceFunctionProperty, Program, ZRegister}
|
||||
|
||||
import scala.collection.mutable
|
||||
@ -18,7 +17,7 @@ class Z80Assembler(program: Program,
|
||||
platform: Platform) extends AbstractAssembler[ZLine](program, rootEnv, platform, Z80InliningCalculator, Z80Compiler) {
|
||||
override def performFinalOptimizationPass(f: NormalFunction, actuallyOptimize: Boolean, options: CompilationOptions, code: List[ZLine]): List[ZLine] = {
|
||||
if (actuallyOptimize) {
|
||||
JumpShortening(f, code, options)
|
||||
JumpShortening(f, ConditionalInstructions(options, JumpFollowing(options, code)), options)
|
||||
} else code
|
||||
}
|
||||
|
||||
@ -393,12 +392,10 @@ class Z80Assembler(program: Program,
|
||||
|
||||
|
||||
case ZLine(CALL, IfFlagClear(ZFlag.Z), param, _) =>
|
||||
requireIntel8080()
|
||||
writeByte(bank, index, 0xc4)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(CALL, IfFlagClear(ZFlag.C), param, _) =>
|
||||
requireIntel8080()
|
||||
writeByte(bank, index, 0xd4)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
@ -414,12 +411,10 @@ class Z80Assembler(program: Program,
|
||||
index + 3
|
||||
|
||||
case ZLine(CALL, IfFlagSet(ZFlag.Z), param, _) =>
|
||||
requireIntel8080()
|
||||
writeByte(bank, index, 0xcc)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
case ZLine(CALL, IfFlagSet(ZFlag.C), param, _) =>
|
||||
requireIntel8080()
|
||||
writeByte(bank, index, 0xdc)
|
||||
writeWord(bank, index + 1, param)
|
||||
index + 3
|
||||
@ -491,11 +486,9 @@ class Z80Assembler(program: Program,
|
||||
index + 2
|
||||
|
||||
case ZLine(RET, IfFlagClear(ZFlag.Z), _, _) =>
|
||||
requireIntel8080()
|
||||
writeByte(bank, index, 0xc0)
|
||||
index + 1
|
||||
case ZLine(RET, IfFlagClear(ZFlag.C), _, _) =>
|
||||
requireIntel8080()
|
||||
writeByte(bank, index, 0xd0)
|
||||
index + 1
|
||||
case ZLine(RET, IfFlagClear(ZFlag.P), _, _) =>
|
||||
@ -508,11 +501,9 @@ class Z80Assembler(program: Program,
|
||||
index + 1
|
||||
|
||||
case ZLine(RET, IfFlagSet(ZFlag.Z), _, _) =>
|
||||
requireIntel8080()
|
||||
writeByte(bank, index, 0xc8)
|
||||
index + 1
|
||||
case ZLine(RET, IfFlagSet(ZFlag.C), _, _) =>
|
||||
requireIntel8080()
|
||||
writeByte(bank, index, 0xd8)
|
||||
index + 1
|
||||
case ZLine(RET, IfFlagSet(ZFlag.P), _, _) =>
|
||||
|
@ -1,7 +1,7 @@
|
||||
package millfork.test
|
||||
|
||||
import millfork.Cpu
|
||||
import millfork.test.emu.{EmuUnoptimizedCrossPlatformRun, ShouldNotCompile}
|
||||
import millfork.test.emu.{EmuCrossPlatformBenchmarkRun, EmuUnoptimizedCrossPlatformRun, ShouldNotCompile}
|
||||
import org.scalatest.{FunSuite, Matchers}
|
||||
|
||||
/**
|
||||
@ -40,7 +40,7 @@ class EnumSuite extends FunSuite with Matchers {
|
||||
}
|
||||
|
||||
test("Enum arrays") {
|
||||
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp)(
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp)(
|
||||
"""
|
||||
| enum ugly {
|
||||
| a
|
||||
@ -52,7 +52,7 @@ class EnumSuite extends FunSuite with Matchers {
|
||||
| void main () {
|
||||
| if a2[a] != 6 { crash() }
|
||||
| }
|
||||
| asm void crash() {
|
||||
| asm noinline void crash() {
|
||||
| #if ARCH_6502
|
||||
| sta $bfff
|
||||
| rts
|
||||
|
Loading…
x
Reference in New Issue
Block a user