mirror of
https://github.com/KarolS/millfork.git
synced 2025-04-07 11:39:08 +00:00
Z80: Fix stack variable optimizations when addresses of stack variables are taken (2)
This commit is contained in:
parent
afa871abcf
commit
22cdd1c768
@ -35,6 +35,9 @@ object CompactStackFrame extends AssemblyOptimization[ZLine] {
|
||||
ZLine(ADD_16, TwoRegisters(Index, SP), _, Elidability.Elidable, s3) ::
|
||||
ZLine(LD_16, TwoRegisters(SP, Index), _, Elidability.Elidable, s4) :: tail =>
|
||||
val sourceSize = (-negativeSize).&(0xffff).toInt
|
||||
if (mayAccessStackViaPointers(tail)) {
|
||||
return None
|
||||
}
|
||||
val usedOffsets: Set[Int] = findUsedOffsets(tail, Index match {
|
||||
case IX => MEM_IX_D
|
||||
case IY => MEM_IY_D
|
||||
@ -56,29 +59,41 @@ object CompactStackFrame extends AssemblyOptimization[ZLine] {
|
||||
}
|
||||
}
|
||||
|
||||
def mayAccessStackViaPointers(code: List[ZLine]): Boolean = {
|
||||
import millfork.assembly.z80.ZOpcode._
|
||||
import millfork.node.ZRegister._
|
||||
val mayUsePointer = code.map {
|
||||
case ZLine0(_, TwoRegisters(HL, SP), _) => true
|
||||
case ZLine0(_, TwoRegisters(SP, HL), _) => true
|
||||
case ZLine0(LD_HLSP | LD_DESP, _, _) => true
|
||||
case ZLine0(_, TwoRegistersOffset(_, MEM_HL | MEM_BC | MEM_DE, offset), _) => true
|
||||
case ZLine0(_, TwoRegistersOffset(MEM_HL | MEM_BC | MEM_DE, _, offset), _) => true
|
||||
case ZLine0(CALL, _, _) => true
|
||||
case _ => false
|
||||
}.toArray
|
||||
val range = VariableLifetime.expandRangeToCoverLoops(code, mayUsePointer)
|
||||
if (range.nonEmpty) {
|
||||
val criticalCodeSlice = code.slice(range.start, range.end)
|
||||
if (criticalCodeSlice.exists {
|
||||
case ZLine0(_, TwoRegisters(_, SP), _) => true
|
||||
case ZLine0(_, TwoRegisters(SP, _), _) => true
|
||||
case ZLine0(LD_HLSP | LD_DESP, _, _) => true
|
||||
case ZLine0(EX_SP, _, _) => true
|
||||
case _ => false
|
||||
}) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
def findUsedOffsets(code: List[ZLine], Mem: ZRegister.Value): Set[Int] = {
|
||||
val used = code.flatMap {
|
||||
code.flatMap {
|
||||
case ZLine0(_, OneRegisterOffset(Mem, offset), _) => Some(offset)
|
||||
case ZLine0(_, TwoRegistersOffset(_, Mem, offset), _) => Some(offset)
|
||||
case ZLine0(_, TwoRegistersOffset(Mem, _, offset), _) => Some(offset)
|
||||
case _ => None
|
||||
}.toSet
|
||||
import ZOpcode._
|
||||
import ZRegister._
|
||||
if (used.isEmpty){
|
||||
used
|
||||
} else if (code.exists {
|
||||
case ZLine0(LD_16, TwoRegisters(_, SP), _) => true
|
||||
case ZLine0(LD_16, TwoRegisters(SP, _), _) => true
|
||||
case ZLine0(ADD_16 | SBC_16, TwoRegisters(_, SP), _) => true
|
||||
case ZLine0(LD_HLSP | LD_DESP, _, _) => true
|
||||
case ZLine0(EX_SP, _, _) => true
|
||||
case _ => false
|
||||
}){
|
||||
(0 to used.max).toSet
|
||||
} else used
|
||||
|
||||
}
|
||||
|
||||
def optimizeContinue(code: List[ZLine], Index: ZRegister.Value, sourceSize: Int, targetSize: Int, mapping: Map[Int, Int]): Option[List[ZLine]] = {
|
||||
|
@ -46,11 +46,16 @@ object VariableLifetime {
|
||||
pointerReadAt.foreach(i => flags(i) = true)
|
||||
}
|
||||
|
||||
val code = codeWithFlow.map(_._2)
|
||||
expandRangeToCoverLoops(code, flags)
|
||||
}
|
||||
|
||||
def expandRangeToCoverLoops(code: List[ZLine], flags: Array[Boolean]): Range = {
|
||||
if (flags.forall(!_)) return Range(0, 0)
|
||||
var min = flags.indexOf(true)
|
||||
var max = flags.lastIndexOf(true) + 1
|
||||
var changed = true
|
||||
val labelMap = codeWithFlow.zipWithIndex.flatMap(a => a._1._2.parameter match {
|
||||
val labelMap = code.zipWithIndex.flatMap(a => a._1.parameter match {
|
||||
case MemoryAddressConstant(Label(l)) => List(l -> a._2)
|
||||
case _ => Nil
|
||||
}).groupBy(_._1).mapValues(_.map(_._2).toSet)
|
||||
|
@ -49,14 +49,18 @@ object UnusedLocalVariables extends NodeOptimization {
|
||||
case _ => Nil
|
||||
}
|
||||
|
||||
def getAllReadVariables(expression: (String, Expression)): List[String] = {
|
||||
if (expression._2.isPure) getAllReadVariables(List(expression._2)).filter(_ != expression._1)
|
||||
else getAllReadVariables(List(expression._2))
|
||||
}
|
||||
|
||||
def optimizeVariables(log: Logger, statements: List[Statement]): List[Statement] = {
|
||||
val allLocals = getAllLocalVariables(statements)
|
||||
val allRead = getAllReadVariables(statements.flatMap {
|
||||
case Assignment(VariableExpression(_), expression) => List(expression)
|
||||
case ExpressionStatement(FunctionCallExpression(op, VariableExpression(_) :: params)) if op.endsWith("=") => params
|
||||
case x => x.getAllExpressions
|
||||
}).toSet
|
||||
val allRead = statements.flatMap {
|
||||
case Assignment(VariableExpression(v), expression) => List(v.takeWhile(_ != '.') -> expression)
|
||||
case ExpressionStatement(FunctionCallExpression(op, VariableExpression(_) :: params)) if op.endsWith("=") => params.map("```" -> _)
|
||||
case x => x.getAllExpressions.map("```" -> _)
|
||||
}.flatMap(getAllReadVariables(_)).toSet
|
||||
val localsToRemove = allLocals.filterNot(allRead).toSet
|
||||
if (localsToRemove.nonEmpty) {
|
||||
log.debug("Removing unused local variables: " + localsToRemove.mkString(", "))
|
||||
|
@ -123,12 +123,22 @@ class StackVarSuite extends FunSuite with Matchers {
|
||||
| }
|
||||
| word fib(byte i) {
|
||||
| stack byte j
|
||||
| stack word sum
|
||||
| stack word w
|
||||
| stack word v
|
||||
| j = i
|
||||
| if j < 2 {
|
||||
| return 1
|
||||
| }
|
||||
| stack word sum
|
||||
|
|
||||
| sum = fib(j-1)
|
||||
|
|
||||
| // see if optimizer cleans these off:
|
||||
| w = sum
|
||||
| sum = w
|
||||
| v = sum
|
||||
| sum = v
|
||||
|
|
||||
| sum += fib(j-2)
|
||||
| sum &= $0F3F
|
||||
| return sum
|
||||
@ -410,5 +420,39 @@ class StackVarSuite extends FunSuite with Matchers {
|
||||
""".stripMargin)
|
||||
}
|
||||
|
||||
test("Pointers to stack variables 4") {
|
||||
val m = EmuOptimizedZ80Run(
|
||||
"""
|
||||
| noinline word f() = 6
|
||||
| noinline void g(word x) {}
|
||||
| asm void __loop() {
|
||||
| nop
|
||||
| nop
|
||||
| nop
|
||||
| jp __loop
|
||||
| }
|
||||
| noinline void h (pointer.word p) {
|
||||
| p[0] = __loop.addr + 1
|
||||
| }
|
||||
| void main () {
|
||||
| stack word b
|
||||
| stack word a
|
||||
| stack word c
|
||||
| stack word d
|
||||
| h(a.pointer)
|
||||
| h(b.pointer)
|
||||
| h(c.pointer)
|
||||
| h(d.pointer)
|
||||
| a = f()
|
||||
| a += 5
|
||||
| a += a.addr.lo
|
||||
| g(a)
|
||||
| if f() == 0 { main() }
|
||||
| }
|
||||
""".stripMargin)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user