1
0
mirror of https://github.com/KarolS/millfork.git synced 2025-04-10 16:39:59 +00:00

6502: Few minor boolean conversion optimizations

This commit is contained in:
Karol Stasiak 2019-10-01 00:47:09 +02:00
parent 1185b1c0bb
commit f251292dd0
2 changed files with 88 additions and 0 deletions

View File

@ -52,6 +52,11 @@ object AlwaysGoodOptimizations {
(HasOpcodeIn(ORA, EOR) & HasImmediate(1) & Elidable & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~
(Linear & Not(ConcernsA)).* ~
(HasOpcodeIn(LSR, ROR) & HasAddrMode(Implied) & DoesntMatterWhatItDoesWith(State.C)) ~~> (_.tail),
(HasOpcode(LDA) & Elidable & MatchParameter(0)) ~
(HasOpcode(SEC) & Elidable) ~
(HasOpcode(SBC) & Elidable & MatchParameter(0) & DoesntMatterWhatItDoesWith(State.C, State.V)) ~~> { code =>
List(AssemblyLine.immediate(LDA, 0).mergePos(code.map(_.source)))
},
))
val PointlessAccumulatorShifting = new RuleBasedAssemblyOptimization("Pointless accumulator shifting",
@ -2920,6 +2925,57 @@ object AlwaysGoodOptimizations {
List(code.last.copy(opcode = CPY))
},
(Elidable & HasOpcode(EOR) & MatchImmediate(0)) ~
(Elidable & HasOpcode(CMP) & MatchImmediate(1) & DoesntMatterWhatItDoesWith(State.A, State.N, State.C)) ~~> { (code, ctx) =>
List(code.last.copy(parameter = CompoundConstant(MathOperator.Exor, ctx.get[Constant](0), ctx.get[Constant](1))))
},
MultipleAssemblyRules(for {
cmpZero <- Seq(false, true)
rts <- Seq(false, true)
beq <- Seq(false, true)
nonzeroFirst <- Seq(false, true)
} yield {
(Elidable & HasOpcode(AND) & MatchNumericImmediate(0)) ~
Where(ctx => {
val mask = ctx.get[Int](0)
(mask == 1 || mask == 2 || mask == 4)
}) ~
(if (cmpZero) Elidable & HasOpcode(CMP) & HasImmediate(0) else Elidable & HasOpcode(CMP) & MatchNumericImmediate(0)) ~
(Elidable & HasOpcode(if (beq) BEQ else BNE) & MatchParameter(5)) ~
(Elidable & HasOpcode(LDA) & (if (nonzeroFirst) MatchNumericImmediate(1) else HasImmediate(0))) ~
(if (rts) Elidable & HasOpcode(RTS) else Elidable & HasOpcodeIn(JMP, BRA, if (nonzeroFirst) BNE else BEQ) & MatchParameter(6)) ~
(Elidable & HasOpcode(LABEL) & MatchParameter(5) & IsNotALabelUsedManyTimes) ~
(Elidable & HasOpcode(LDA) & (if (nonzeroFirst) HasImmediate(0) else MatchNumericImmediate(1))) ~
Where(ctx => {
val mask = ctx.get[Int](1)
(mask == 1 || mask == 2 || mask == 4)
}) ~
(Elidable & (if (rts) HasOpcode(RTS) else HasOpcode(LABEL) & MatchParameter(6) & IsNotALabelUsedManyTimes) & DoesntMatterWhatItDoesWith(State.C, State.Z, State.N)) ~~> { (code, ctx) =>
val inverted = cmpZero ^ beq ^ nonzeroFirst
val andMask = ctx.get[Int](0)
val positiveResult = ctx.get[Int](1)
val prepare = if (inverted) {
List(code.head, AssemblyLine.immediate(EOR, andMask))
} else {
List(code.head)
}
val shifts = (andMask, positiveResult) match {
case (1, 1) | (2, 2) | (4, 4) => Nil
case (1, 2) | (2, 4) => List(AssemblyLine.implied(ASL))
case (2, 1) | (4, 2) => List(AssemblyLine.implied(LSR))
case (1, 4) => List(AssemblyLine.implied(ASL), AssemblyLine.implied(ASL))
case (4, 1) => List(AssemblyLine.implied(LSR), AssemblyLine.implied(LSR))
case _ => ???
}
if (rts) {
prepare ++ shifts ++ List(code(4))
} else {
prepare ++ shifts
}
}
}),
)
private val powersOf2: List[(Int, Int)] = List(

View File

@ -0,0 +1,32 @@
package millfork.test
import millfork.Cpu
import millfork.test.emu.EmuCrossPlatformBenchmarkRun
import org.scalatest.{FunSuite, Matchers}
/**
* @author Karol Stasiak
*/
class BooleanOptimizationSuite extends FunSuite with Matchers {
test("Cases") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos)(
"""
| noinline bool f1(byte a) = a & 1 != 0
| noinline bool f2(byte a) = a & 4 != 4
| noinline bool f3(byte a) = a ^ 5 == 6
| noinline bool f4(byte a) = a == 0
| noinline bool f5(byte a) = a == 1
| void main() {
| f1(0)
| f2(0)
| f3(0)
| f4(0)
| f5(0)
| }
""".stripMargin){ m =>
}
}
}