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:
parent
49d126ffa0
commit
ac51bcaf6c
|
@ -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,
|
||||
|
|
|
@ -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) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user