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

8080: Fixed inlining of byte-sized variables into registers

This commit is contained in:
Karol Stasiak 2019-06-26 01:45:34 +02:00
parent 2ad43cf3b3
commit f90d6afc43
3 changed files with 65 additions and 4 deletions

View File

@ -74,6 +74,8 @@
* Fixed for-each loops with non-constant arrays.
* 8080 and LR35902: Fixed inlining of byte-sized variables into registers.
* 8080 and LR35902: fixed large stack variables.
* Other bug fixes.

View File

@ -270,6 +270,25 @@ object ByteVariableToRegisterOptimization extends AssemblyOptimization[ZLine] {
if (target == D || target == E) fail(61) else
canBeInlined(vname, synced, target, addressInHl, addressInBc, addressInDe = Some(true), xs).map(add(CyclesAndBytes(10, 3)))
// TODO: other combinations:
case (_, ZLine0(LD, TwoRegisters(L, C), _)) :: (_, ZLine0(LD, TwoRegisters(H, B), _)) :: xs if addressInBc.contains(true) =>
canBeInlined(vname, synced, target, addressInHl = Some(true), addressInBc, addressInDe, xs).map(add(CyclesAndBytes(8, 2)))
case (_, ZLine0(LD, TwoRegisters(H, B), _)) :: (_, ZLine0(LD, TwoRegisters(L, C), _)) :: xs if addressInBc.contains(true) =>
canBeInlined(vname, synced, target, addressInHl = Some(true), addressInBc, addressInDe, xs).map(add(CyclesAndBytes(8, 2)))
case (_, ZLine0(LD, TwoRegisters(L, E), _)) :: (_, ZLine0(LD, TwoRegisters(H, D), _)) :: xs if addressInDe.contains(true) =>
canBeInlined(vname, synced, target, addressInHl = Some(true), addressInBc, addressInDe, xs).map(add(CyclesAndBytes(8, 2)))
case (_, ZLine0(LD, TwoRegisters(H, D), _)) :: (_, ZLine0(LD, TwoRegisters(L, E), _)) :: xs if addressInDe.contains(true) =>
canBeInlined(vname, synced, target, addressInHl = Some(true), addressInBc, addressInDe, xs).map(add(CyclesAndBytes(8, 2)))
case (_, ZLine0(LD, TwoRegisters(C, L), _)) :: (_, ZLine0(LD, TwoRegisters(B, H), _)) :: xs if addressInHl.contains(true) =>
canBeInlined(vname, synced, target, addressInHl, addressInBc = Some(true), addressInDe, xs).map(add(CyclesAndBytes(8, 2)))
case (_, ZLine0(LD, TwoRegisters(B, H), _)) :: (_, ZLine0(LD, TwoRegisters(C, L), _)) :: xs if addressInHl.contains(true) =>
canBeInlined(vname, synced, target, addressInHl, addressInBc = Some(true), addressInDe, xs).map(add(CyclesAndBytes(8, 2)))
case (_, ZLine0(LD, TwoRegisters(E, L), _)) :: (_, ZLine0(LD, TwoRegisters(D, H), _)) :: xs if addressInHl.contains(true) =>
canBeInlined(vname, synced, target, addressInHl, addressInBc, addressInDe = Some(true), xs).map(add(CyclesAndBytes(8, 2)))
case (_, ZLine0(LD, TwoRegisters(D, H), _)) :: (_, ZLine0(LD, TwoRegisters(E, L), _)) :: xs if addressInHl.contains(true) =>
canBeInlined(vname, synced, target, addressInHl, addressInBc, addressInDe = Some(true), xs).map(add(CyclesAndBytes(8, 2)))
case (_, ZLine0(_, OneRegister(MEM_HL), _)) :: xs => addressInHl match {
case Some(true) => canBeInlined(vname, synced, target, addressInHl, addressInBc, addressInDe, xs).map(add(CyclesAndBytes(3, 0)))
case Some(false) => canBeInlined(vname, synced, target, addressInHl, addressInBc, addressInDe, xs)
@ -388,15 +407,34 @@ object ByteVariableToRegisterOptimization extends AssemblyOptimization[ZLine] {
x.copy(registers = TwoRegisters(reg, target), parameter = p) ::
inlineVars(vname, target, addressInHl, addressInBc, addressInDe, xs)
// TODO: other combinations
case ZLine0(LD, TwoRegisters(L, C), _) :: ZLine0(LD, TwoRegisters(H, B), _) :: xs if addressInBc =>
inlineVars(vname, target, addressInHl = true, addressInBc = true, addressInDe = addressInDe, xs)
case ZLine0(LD, TwoRegisters(H, B), _) :: ZLine0(LD, TwoRegisters(L, C), _) :: xs if addressInBc =>
inlineVars(vname, target, addressInHl = true, addressInBc = true, addressInDe = addressInDe, xs)
case ZLine0(LD, TwoRegisters(L, E), _) :: ZLine0(LD, TwoRegisters(H, D), _) :: xs if addressInDe =>
inlineVars(vname, target, addressInHl = true, addressInBc = addressInBc, addressInDe = true, xs)
case ZLine0(LD, TwoRegisters(H, D), _) :: ZLine0(LD, TwoRegisters(L, E), _) :: xs if addressInDe =>
inlineVars(vname, target, addressInHl = true, addressInBc = addressInBc, addressInDe = true, xs)
case ZLine0(LD, TwoRegisters(C, L), _) :: ZLine0(LD, TwoRegisters(B, H), _) :: xs if addressInHl =>
inlineVars(vname, target, addressInHl = true, addressInBc = true, addressInDe = addressInDe, xs)
case ZLine0(LD, TwoRegisters(B, H), _) :: ZLine0(LD, TwoRegisters(C, L), _) :: xs if addressInHl =>
inlineVars(vname, target, addressInHl = true, addressInBc = true, addressInDe = addressInDe, xs)
case ZLine0(LD, TwoRegisters(E, L), _) :: ZLine0(LD, TwoRegisters(D, H), _) :: xs if addressInHl =>
inlineVars(vname, target, addressInHl = true, addressInBc = addressInBc, addressInDe = true, xs)
case ZLine0(LD, TwoRegisters(D, H), _) :: ZLine0(LD, TwoRegisters(E, L), _) :: xs if addressInHl =>
inlineVars(vname, target, addressInHl = true, addressInBc = addressInBc, addressInDe = true, xs)
case (x@ZLine(CALL,_,_,_,s))::xs =>
// TODO: this push/pull pair shouldn't prevent the inlining to the other register in the pair
target match {
case ZRegister.B | ZRegister.C =>
ZLine.register(PUSH, BC).pos(s) :: x :: ZLine.register(POP, BC).pos(s) ::
inlineVars(vname, target, addressInHl, addressInBc, addressInDe, xs)
inlineVars(vname, target, addressInHl = false, addressInBc, addressInDe = false, xs)
case ZRegister.D | ZRegister.E =>
ZLine.register(PUSH, DE).pos(s) :: x :: ZLine.register(POP, DE).pos(s) ::
inlineVars(vname, target, addressInHl, addressInBc, addressInDe, xs)
inlineVars(vname, target, addressInHl = false, addressInBc = false, addressInDe, xs)
}
case x :: xs if x.changesRegister(HL) =>

View File

@ -1,7 +1,7 @@
package millfork.assembly.z80.opt
import millfork.assembly.opt.SingleStatus
import millfork.assembly.z80.{OneRegister, TwoRegisters, ZLine, ZLine0}
import millfork.assembly.z80.{OneRegister, TwoRegisters, ZLine, ZLine0, ZOpcode}
import millfork.env._
import millfork.error.ConsoleLogger
import millfork.node.ZRegister
@ -14,17 +14,38 @@ object VariableLifetime {
// This only works for non-stack variables.
// TODO: this is also probably very wrong
def apply(variableName: String, codeWithFlow: List[(FlowInfo, ZLine)]): Range = {
import ZRegister._
import ZOpcode._
val pointerLoadedAt = codeWithFlow.zipWithIndex.filter{
case ((_, ZLine0(ZOpcode.LD_16, TwoRegisters(_, IMM_16), MemoryAddressConstant(MemoryVariable(n, _, _)))), _) => n == variableName
case _ => false
}.map(_._2)
val pointerReadAt = codeWithFlow.zipWithIndex.filter{
case ((_, ZLine0(_, TwoRegisters(MEM_HL | MEM_DE | MEM_BC, _), _)), _) => true
case ((_, ZLine0(_, TwoRegisters(_, MEM_HL | MEM_DE | MEM_BC), _)), _) => true
case ((_, ZLine0(_, OneRegister(MEM_HL | MEM_DE | MEM_BC), _)), _) => true
case ((_, ZLine0(CALL, _, _)), _) => true
case _ => false
}.map(_._2)
val flags = codeWithFlow.map {
case (_, ZLine0(_, _, MemoryAddressConstant(MemoryVariable(n, _, _)))) => n == variableName
case (_, ZLine0(_, _, CompoundConstant(MathOperator.Plus, MemoryAddressConstant(MemoryVariable(n, _, _)), NumericConstant(_, 1)))) => n == variableName
case (i, ZLine0(_, TwoRegisters(ZRegister.MEM_HL, _) | TwoRegisters(_, ZRegister.MEM_HL) | OneRegister(ZRegister.MEM_HL), _)) =>
case (i, ZLine0(_, TwoRegisters(MEM_HL, _) | TwoRegisters(_, MEM_HL) | OneRegister(MEM_HL), _)) =>
i.statusBefore.hl match {
case SingleStatus(MemoryAddressConstant(MemoryVariable(n, _, _))) => n == variableName
case SingleStatus(CompoundConstant(MathOperator.Plus, MemoryAddressConstant(MemoryVariable(n, _, _)), NumericConstant(_, 1))) => n == variableName
case _ => false
}
case _ => false
}.toArray
if(pointerLoadedAt.nonEmpty) {
pointerReadAt.foreach(i => flags(i) = true)
}
if (flags.forall(!_)) return Range(0, 0)
var min = flags.indexOf(true)
var max = flags.lastIndexOf(true) + 1