From cbe709a9cf7d09443edd5a308c0fb58789595f13 Mon Sep 17 00:00:00 2001 From: Karol Stasiak Date: Sat, 29 Dec 2018 20:01:17 +0100 Subject: [PATCH] 6502: fix optimizations using index registers --- .../opt/ChangeIndexRegisterOptimization.scala | 12 +++--- .../opt/VariableToRegisterOptimization.scala | 14 +++++++ .../SecondAssemblyOptimizationSuite.scala | 37 +++++++++++++++++++ 3 files changed, 58 insertions(+), 5 deletions(-) diff --git a/src/main/scala/millfork/assembly/mos/opt/ChangeIndexRegisterOptimization.scala b/src/main/scala/millfork/assembly/mos/opt/ChangeIndexRegisterOptimization.scala index 9930679a..0d5a33b8 100644 --- a/src/main/scala/millfork/assembly/mos/opt/ChangeIndexRegisterOptimization.scala +++ b/src/main/scala/millfork/assembly/mos/opt/ChangeIndexRegisterOptimization.scala @@ -100,6 +100,11 @@ class ChangeIndexRegisterOptimization(preferX2Y: Boolean) extends AssemblyOptimi //noinspection OptionEqualsSome private def canOptimize(code: List[AssemblyLine], dir: IndexDirection, loaded: Option[IndexReg]): Boolean = code match { + + case AssemblyLine0(INC | DEC | ASL | ROL | ROR | LSR | STZ | LDZ | BIT, AbsoluteX | ZeroPageX, _) :: xs if dir == X2Y => false + case AssemblyLine0(LDY | STY, AbsoluteX | ZeroPageX, _) :: xs => false + case AssemblyLine0(LDX | STX, AbsoluteY | ZeroPageY, _) :: xs => false + case AssemblyLine0(_, AbsoluteY, _) :: xs if loaded != Some(Y) => false case AssemblyLine0(_, ZeroPageY, _) :: xs if loaded != Some(Y) => false case AssemblyLine0(_, IndexedY, _) :: xs if dir == Y2X || loaded != Some(Y) => false @@ -118,18 +123,15 @@ class ChangeIndexRegisterOptimization(preferX2Y: Boolean) extends AssemblyOptimi canOptimize(xs, dir, None) case AssemblyLine0(LDX | TAX, _, _) :: AssemblyLine0(_, IndexedX, _) :: xs if dir == X2Y => canOptimize(xs, dir, None) - case AssemblyLine0(LDX | TAX, _, _) :: AssemblyLine0(INC | DEC | ASL | ROL | ROR | LSR | LDY | STY | STZ, AbsoluteX | ZeroPageX, _) :: xs if dir == X2Y => + case AssemblyLine0(LDX | TAX, _, _) :: AssemblyLine0(INC | DEC | ASL | ROL | ROR | LSR | STZ, AbsoluteX | ZeroPageX, _) :: xs if dir == X2Y => canOptimize(xs, dir, None) case AssemblyLine0(LDY | TAY, _, _) :: AssemblyLine0(INY | DEY, _, _) :: AssemblyLine0(_, IndexedY, _) :: xs if dir == Y2X => canOptimize(xs, dir, None) case AssemblyLine0(LDX | TAX, _, _) :: AssemblyLine0(INX | DEX, _, _) :: AssemblyLine0(_, IndexedX, _) :: xs if dir == X2Y => canOptimize(xs, dir, None) - case AssemblyLine0(LDX | TAX, _, _) :: AssemblyLine0(INX | DEX, _, _) :: AssemblyLine0(INC | DEC | ASL | ROL | ROR | LSR | LDY | STY | STZ, AbsoluteX | ZeroPageX, _) :: xs if dir == X2Y => + case AssemblyLine0(LDX | TAX, _, _) :: AssemblyLine0(INX | DEX, _, _) :: AssemblyLine0(INC | DEC | ASL | ROL | ROR | LSR | STZ, AbsoluteX | ZeroPageX, _) :: xs if dir == X2Y => canOptimize(xs, dir, None) - case AssemblyLine0(INC | DEC | ASL | ROL | ROR | LSR | STZ | LDZ | LDY | STY | BIT, AbsoluteX | ZeroPageX, _) :: xs if dir == X2Y => false - case AssemblyLine0(LDX | STX, AbsoluteY | ZeroPageY, _) :: xs if dir == Y2X => false - case AssemblyLine0(LAX, _, _) :: xs => false case AssemblyLine0(JSR | BSR, _, _) :: xs => false // TODO case AssemblyLine0(JMP, Absolute, _) :: xs => canOptimize(xs, dir, None) // TODO diff --git a/src/main/scala/millfork/assembly/mos/opt/VariableToRegisterOptimization.scala b/src/main/scala/millfork/assembly/mos/opt/VariableToRegisterOptimization.scala index 40d49b11..0da05e8b 100644 --- a/src/main/scala/millfork/assembly/mos/opt/VariableToRegisterOptimization.scala +++ b/src/main/scala/millfork/assembly/mos/opt/VariableToRegisterOptimization.scala @@ -379,11 +379,25 @@ object VariableToRegisterOptimization extends AssemblyOptimization[AssemblyLine] val vy = yCandidate.getOrElse("-") val vz = zCandidate.getOrElse("-") lines match { + case (AssemblyLine0(_, Immediate, MemoryAddressConstant(th)), _) :: xs + if th.name == vx || th.name == vy || th.name == vz => + // if an address of a variable is used, then that variable cannot be assigned to a register + None + case (AssemblyLine0(_, Immediate, SubbyteConstant(MemoryAddressConstant(th), _)), _) :: xs if th.name == vx || th.name == vy || th.name == vz => // if an address of a variable is used, then that variable cannot be assigned to a register None + case (AssemblyLine0(LDX | STX, AbsoluteY | ZeroPageY | IndexedY | IndexedSY | IndexedZ, _), _) :: xs if xCandidate.isDefined => + None + + case (AssemblyLine0(LDY | STY, AbsoluteX | ZeroPageX | IndexedX | LongAbsoluteX | IndexedZ, _), _) :: xs if yCandidate.isDefined => + None + + case (AssemblyLine0(LDZ | STZ, AbsoluteX | ZeroPageX | IndexedX | LongAbsoluteX | AbsoluteY | ZeroPageY | IndexedY | IndexedSY, _), _) :: xs if zCandidate.isDefined => + None + case (AssemblyLine0(_, AbsoluteX | AbsoluteY | LongAbsoluteX | ZeroPageX | ZeroPageY | IndexedY | IndexedX | IndexedZ | diff --git a/src/test/scala/millfork/test/SecondAssemblyOptimizationSuite.scala b/src/test/scala/millfork/test/SecondAssemblyOptimizationSuite.scala index 0101eeab..6b90557c 100644 --- a/src/test/scala/millfork/test/SecondAssemblyOptimizationSuite.scala +++ b/src/test/scala/millfork/test/SecondAssemblyOptimizationSuite.scala @@ -66,4 +66,41 @@ class SecondAssemblyOptimizationSuite extends FunSuite with Matchers { | } """.stripMargin) { m => m.readByte(0xc000) should equal(4) } } + + test("Index register usage") { + EmuBenchmarkRun( + """ + | array palette = [0, 2, 8, 7, 1] + | array reverse_palette [16] @$c000 + | array __screen[1000] + | array c64_color_ram[1000] + | void main () { + | byte i + | for i,0,paralleluntil,palette.length { + | reverse_palette[palette[i]] = i + | } + | for i,0,paralleluntil,250 { + | __screen[000+i] = 160 + | __screen[250+i] = 160 + | __screen[500+i] = 160 + | __screen[750+i] = 160 + | } + | for i,0,paralleluntil,250 { + | c64_color_ram[000+i] = 0 + | c64_color_ram[250+i] = 0 + | c64_color_ram[500+i] = 0 + | c64_color_ram[750+i] = 0 + | } + | for i,0,paralleluntil,40 { + | c64_color_ram[960+i] = 1 + | } + | } + """.stripMargin) { m => + m.readByte(0xc000) should equal(0) + m.readByte(0xc002) should equal(1) + m.readByte(0xc008) should equal(2) + m.readByte(0xc007) should equal(3) + m.readByte(0xc001) should equal(4) + } + } }