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

Optimizing pointless sign extensions

This commit is contained in:
Karol Stasiak 2018-01-30 17:37:03 +01:00
parent 49d126ffa0
commit ac51bcaf6c
4 changed files with 87 additions and 1 deletions

View File

@ -14,6 +14,7 @@ object OptimizationPresets {
UnusedGlobalVariables,
)
val AssOpt: List[AssemblyOptimization] = List[AssemblyOptimization](
AlwaysGoodOptimizations.PointlessSignCheck,
AlwaysGoodOptimizations.PoinlessLoadBeforeAnotherLoad,
AlwaysGoodOptimizations.PointlessLoadAfterLoadOrStore,
LaterOptimizations.PointessLoadingForShifting,
@ -148,6 +149,7 @@ object OptimizationPresets {
AlwaysGoodOptimizations.PointlessRegisterTransfers,
AlwaysGoodOptimizations.PointlessRegisterTransfersBeforeCompare,
AlwaysGoodOptimizations.PointlessRegisterTransfersBeforeReturn,
AlwaysGoodOptimizations.PointlessSignCheck,
AlwaysGoodOptimizations.PointlessStackStashing,
AlwaysGoodOptimizations.PointlessStashingToIndexOverShortSafeBranch,
AlwaysGoodOptimizations.PoinlessStoreBeforeStore,

View File

@ -1128,4 +1128,55 @@ object AlwaysGoodOptimizations {
List(code(1).copy(opcode = LDA), remapZ2N(code(2)))
},
)
val PointlessSignCheck: RuleBasedAssemblyOptimization = {
def loadOldSignedVariable: AssemblyPattern = (
(HasOpcodeIn(Set(AND, ANC)) & HasImmediateWhere(i => (i & 0x80) == 0)) ~
(HasOpcode(STA) & HasAddrModeIn(Set(Absolute, ZeroPage)) & MatchAddrMode(0) & MatchParameter(1)) ~
DoesNotConcernMemoryAt(0, 1).* ~
(HasOpcode(LDA) & HasAddrModeIn(Set(Absolute, ZeroPage)) & MatchParameter(1))
).capture(10) ~ Where(_.isExternallyLinearBlock(10))
val isNonnegative: Int => Boolean = i => (i & 0x80) == 0
new RuleBasedAssemblyOptimization("Pointless sign check",
needsFlowInfo = FlowInfoRequirement.NoRequirement,
(HasOpcode(AND) & HasImmediateWhere(isNonnegative)) ~
(Elidable & HasOpcode(BMI)) ~~> (_.take(1)),
loadOldSignedVariable ~
(Elidable & HasOpcode(BMI)) ~~> { (code, ctx) => ctx.get[List[AssemblyLine]](10) },
loadOldSignedVariable ~
(Elidable & HasOpcodeIn(Set(ORA, EOR)) & HasImmediateWhere(isNonnegative)) ~
(Elidable & HasOpcode(BMI)) ~
OverwritesA ~~> { (code, ctx) => ctx.get[List[AssemblyLine]](10) :+ code.last },
loadOldSignedVariable ~
(Elidable & HasOpcodeIn(Set(ORA, EOR)) & HasImmediateWhere(isNonnegative)) ~
(Elidable & HasOpcode(BMI)) ~~> { code => code.init },
loadOldSignedVariable ~
(Elidable & HasOpcodeIn(Set(ORA, EOR)) & HasImmediateWhere(isNonnegative)).? ~
(Elidable & HasOpcode(BPL)) ~~> { code => code.init :+ code.last.copy(opcode = JMP, addrMode = Absolute) },
loadOldSignedVariable ~
((Linear & Not(ConcernsX) & Not(ChangesA)).* ~
HasOpcode(TAX) ~
(Linear & Not(ConcernsX)).*).capture(11) ~
(Elidable & HasOpcode(TXA)) ~
(Elidable & HasOpcodeIn(Set(ORA, EOR)) & HasImmediateWhere(isNonnegative)).? ~
(Elidable & HasOpcode(BMI)) ~
OverwritesA ~~> { (code, ctx) => ctx.get[List[AssemblyLine]](10) ++ ctx.get[List[AssemblyLine]](11) :+ code.last },
loadOldSignedVariable ~
(Linear & Not(ConcernsX) & Not(ChangesA)).* ~
HasOpcode(TAX) ~
(Linear & Not(ConcernsX)).* ~
HasOpcode(TXA) ~
(HasOpcodeIn(Set(ORA, EOR)) & HasImmediateWhere(isNonnegative)).? ~
(Elidable & HasOpcode(BMI)) ~~> { code => code.init },
loadOldSignedVariable ~
(Linear & Not(ConcernsX) & Not(ChangesA)).* ~
HasOpcode(TAX) ~
(Linear & Not(ConcernsX)).* ~
HasOpcode(TXA) ~
(HasOpcodeIn(Set(ORA, EOR)) & HasImmediateWhere(isNonnegative)).? ~
(Elidable & HasOpcode(BPL)) ~~> { code => code.init :+ code.last.copy(opcode = JMP, addrMode = Absolute) },
)
}
}

View File

@ -696,6 +696,14 @@ case class HasImmediate(i: Int) extends TrivialAssemblyLinePattern {
override def toString: String = "#" + i
}
case class HasImmediateWhere(predicate: Int => Boolean) extends TrivialAssemblyLinePattern {
override def apply(line: AssemblyLine): Boolean =
line.addrMode == AddrMode.Immediate && (line.parameter.quickSimplify match {
case NumericConstant(j, _) => predicate(j.toInt & 0xff)
case _ => false
})
}
case class MatchObject(i: Int, f: Function[AssemblyLine, Any]) extends AssemblyLinePattern {
override def matchLineTo(ctx: AssemblyMatchingContext, flowInfo: FlowInfo, line: AssemblyLine): Boolean =
ctx.addObject(i, f(line))

View File

@ -1,6 +1,6 @@
package millfork.test
import millfork.test.emu.EmuUnoptimizedRun
import millfork.test.emu.{EmuBenchmarkRun, EmuUnoptimizedRun}
import org.scalatest.{FunSuite, Matchers}
/**
@ -41,4 +41,29 @@ class SignExtensionSuite extends FunSuite with Matchers {
| }
""".stripMargin).readLong(0xc000) should equal(420)
}
test("Optimize pointless sign extension") {
EmuBenchmarkRun("""
| array output [10] @$c000
| word w
| void main () {
| byte i
| sbyte b
| w = 435
| b = five()
| b &= $7f
| for i,0,paralleluntil,output.length {
| output[i] = i
| }
| w += b
| output[0] = w.lo
| output[1] = w.hi
| }
| sbyte five() {
| return 5
| }
""".stripMargin){m =>
m.readWord(0xc000) should equal(440)
}
}
}