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

Following jumps. Generating conditional returns/calls.

This commit is contained in:
Karol Stasiak 2018-08-08 23:12:20 +02:00
parent 2d0f3a5a12
commit 9581891d66
7 changed files with 177 additions and 19 deletions

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

View File

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

View File

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

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

View File

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

View File

@ -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), _, _) =>

View File

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