mirror of
https://github.com/KarolS/millfork.git
synced 2025-01-11 12:29:46 +00:00
6809: various optimizations
This commit is contained in:
parent
947a84833a
commit
ca5fe5cdb0
@ -40,6 +40,8 @@ object MOpcode extends Enumeration {
|
||||
val PrefixedBy10: Set[MOpcode.Value] = Set(CMPD, CMPY, LDS, LDY, SWI2, STS, STY) // TODO: branches
|
||||
val PrefixedBy11: Set[MOpcode.Value] = Set(CMPS, CMPU, SWI3)
|
||||
val Prefixed: Set[MOpcode.Value] = PrefixedBy10 ++ PrefixedBy11
|
||||
val CanHaveImmediateAndIndexedByte: Set[MOpcode.Value] = Set(ADCA, ADCB, ADDA, ADDB, ANDA, ANDB, BITA, BITB, CMPA, CMPB, EORA, EORB, LDA, LDB, ORA, ORB, SBCA, SBCB, SUBA, SUBB)
|
||||
val CanHaveImmediateAndIndexedWord: Set[MOpcode.Value] = Set(ADDD, CMPD, CMPS, CMPU, CMPX, CMPY, LDD, LDS, LDU, LDX, LDY, SUBD)
|
||||
val CanHaveInherentAccumulator: Set[MOpcode.Value] = Set(ASL, ASR, CLR, COM, DEC, INC, LSR, NEG, ROL, ROR, TST)
|
||||
val Branching: Set[MOpcode.Value] = Set(BRA, BRN, BHI, BLS, BCC, BCS, BNE, BEQ, BVC, BVS, BPL, BMI, BGE, BLT, BGT, BLE)
|
||||
val ConditionalBranching: Set[MOpcode.Value] = Set(BHI, BLS, BCC, BCS, BNE, BEQ, BVC, BVS, BPL, BMI, BGE, BLT, BGT, BLE)
|
||||
@ -146,4 +148,26 @@ object MOpcode extends Enumeration {
|
||||
NOP -> None
|
||||
}
|
||||
}
|
||||
|
||||
def invertBranching(opcode: Value): Value = {
|
||||
opcode match {
|
||||
case BCC => BCS
|
||||
case BCS => BCC
|
||||
case BEQ => BNE
|
||||
case BNE => BEQ
|
||||
case BGE => BLT
|
||||
case BLT => BGE
|
||||
case BGT => BLE
|
||||
case BLE => BGT
|
||||
case BHI => BLS
|
||||
case BLS => BHI
|
||||
case BPL => BMI
|
||||
case BMI => BPL
|
||||
case BVC => BVS
|
||||
case BVS => BVC
|
||||
case BRA => BRN
|
||||
case BRN => BRA
|
||||
case _ => opcode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ package millfork.assembly.m6809.opt
|
||||
|
||||
import millfork.assembly.AssemblyOptimization
|
||||
import millfork.assembly.m6809.MOpcode._
|
||||
import millfork.assembly.m6809.{MLine, MState}
|
||||
import millfork.assembly.m6809.{Absolute, DAccumulatorIndexed, Immediate, LongRelative, MAddrMode, MLine, MState, PostIncremented, RegisterSet}
|
||||
import millfork.node.M6809Register
|
||||
|
||||
/**
|
||||
@ -18,6 +18,14 @@ object AlwaysGoodMOptimizations {
|
||||
(Elidable & HasOpcode(LDD) & DoesntMatterWhatItDoesWith(MState.A, MState.B, MState.NF, MState.ZF, MState.VF)) ~~> (_ => Nil),
|
||||
(Elidable & HasOpcodeIn(LDX, LEAX) & DoesntMatterWhatItDoesWith(MState.X, MState.NF, MState.ZF, MState.VF)) ~~> (_ => Nil),
|
||||
(Elidable & HasOpcodeIn(LDY, LEAY) & DoesntMatterWhatItDoesWith(MState.Y, MState.NF, MState.ZF, MState.VF)) ~~> (_ => Nil),
|
||||
(Elidable & HasOpcode(STB) & MatchAddrMode(0) & MatchParameter(1)) ~
|
||||
(Linear & Not(ChangesB) & DoesntChangeIndexingInAddrMode(0)).* ~
|
||||
(Elidable & HasOpcode(LDB) & MatchAddrMode(0) & MatchParameter(1)
|
||||
& DoesntMatterWhatItDoesWith(MState.NF, MState.ZF, MState.VF)) ~~> (_.init),
|
||||
(Elidable & HasOpcode(STD) & MatchAddrMode(0) & MatchParameter(1)) ~
|
||||
(Linear & Not(ChangesB) & DoesntChangeIndexingInAddrMode(0)).* ~
|
||||
(Elidable & HasOpcode(LDD) & MatchAddrMode(0) & MatchParameter(1)
|
||||
& DoesntMatterWhatItDoesWith(MState.NF, MState.ZF, MState.VF)) ~~> (_.init),
|
||||
)
|
||||
|
||||
val SimplifiableZeroStore = new RuleBasedAssemblyOptimization("Simplifiable zero store",
|
||||
@ -54,9 +62,96 @@ object AlwaysGoodMOptimizations {
|
||||
(Elidable & IsTfrTo(M6809Register.X) & DoesntMatterWhatItDoesWith(MState.X)) ~~> (_ => Nil),
|
||||
)
|
||||
|
||||
private val PullByte: MAddrMode = PostIncremented(M6809Register.S, 1, indirect = false)
|
||||
private val PullWord: MAddrMode = PostIncremented(M6809Register.S, 2, indirect = false)
|
||||
|
||||
import M6809Register._
|
||||
|
||||
val PointlessStashing = new RuleBasedAssemblyOptimization("Pointless stashing",
|
||||
needsFlowInfo = FlowInfoRequirement.BackwardFlow,
|
||||
|
||||
(Elidable & HasOpcode(LDB) & HasAddrMode(Immediate)) ~
|
||||
(Elidable & HasOpcode(PSHS) & HasAddrMode(RegisterSet(Set(B))) & DoesntMatterWhatItDoesWith(MState.NF, MState.ZF, MState.VF, MState.B)) ~
|
||||
(Linear & Not(ConcernsS)).* ~
|
||||
(Elidable & HasOpcodeIn(CanHaveImmediateAndIndexedByte) & HasAddrMode(PullByte)) ~~> { code =>
|
||||
code.drop(2).init :+ code.last.copy(addrMode = Immediate, parameter = code.head.parameter)
|
||||
},
|
||||
(Elidable & HasOpcode(LDD) & HasAddrMode(Immediate)) ~
|
||||
(Elidable & HasOpcode(PSHS) & HasAddrMode(RegisterSet(Set(D))) & DoesntMatterWhatItDoesWith(MState.NF, MState.ZF, MState.VF, MState.B, MState.A)) ~
|
||||
(Linear & Not(ConcernsS)).* ~
|
||||
(Elidable & HasOpcodeIn(CanHaveImmediateAndIndexedWord) & HasAddrMode(PullWord)) ~~> { code =>
|
||||
code.drop(2).init :+ code.last.copy(addrMode = Immediate, parameter = code.head.parameter)
|
||||
},
|
||||
|
||||
(Elidable & HasOpcode(LDB) & HasAddrMode(Immediate)) ~
|
||||
(Elidable & HasOpcode(PSHS) & HasAddrMode(RegisterSet(Set(B))) & DoesntMatterWhatItDoesWith(MState.NF, MState.ZF, MState.VF, MState.B)) ~
|
||||
(Linear & Not(ConcernsS)).* ~
|
||||
(Elidable & HasOpcode(PULS) & HasAddrMode(RegisterSet(Set(B))) & DoesntMatterWhatItDoesWith(MState.NF, MState.ZF, MState.VF)) ~~> { code =>
|
||||
code.drop(2).init :+ code.head
|
||||
},
|
||||
(Elidable & HasOpcode(LDB) & HasAddrMode(Immediate)) ~
|
||||
(Elidable & HasOpcode(PSHS) & HasAddrMode(RegisterSet(Set(B))) & DoesntMatterWhatItDoesWith(MState.NF, MState.ZF, MState.VF, MState.B)) ~
|
||||
(Linear & Not(ConcernsS)).* ~
|
||||
(Elidable & HasOpcode(PULS) & HasAddrMode(RegisterSet(Set(A))) & DoesntMatterWhatItDoesWith(MState.NF, MState.ZF, MState.VF)) ~~> { code =>
|
||||
code.drop(2).init :+ code.head.copy(opcode = LDA)
|
||||
},
|
||||
(Elidable & HasOpcode(LDD) & HasAddrMode(Immediate)) ~
|
||||
(Elidable & HasOpcode(PSHS) & HasAddrMode(RegisterSet(Set(D))) & DoesntMatterWhatItDoesWith(MState.NF, MState.ZF, MState.VF, MState.B, MState.A)) ~
|
||||
(Linear & Not(ConcernsS)).* ~
|
||||
(Elidable & HasOpcode(PULS) & HasAddrMode(RegisterSet(Set(D))) & DoesntMatterWhatItDoesWith(MState.NF, MState.ZF, MState.VF)) ~~> { code =>
|
||||
code.drop(2).init :+ code.head
|
||||
},
|
||||
(Elidable & HasOpcode(LDD) & HasAddrMode(Immediate)) ~
|
||||
(Elidable & HasOpcode(PSHS) & HasAddrMode(RegisterSet(Set(D))) & DoesntMatterWhatItDoesWith(MState.NF, MState.ZF, MState.VF, MState.B, MState.A)) ~
|
||||
(Linear & Not(ConcernsS)).* ~
|
||||
(Elidable & HasOpcode(PULS) & HasAddrMode(RegisterSet(Set(X))) & DoesntMatterWhatItDoesWith(MState.NF, MState.ZF, MState.VF)) ~~> { code =>
|
||||
code.drop(2).init :+ code.head.copy(opcode = LDX)
|
||||
},
|
||||
)
|
||||
|
||||
val SimplifiableJumps = new RuleBasedAssemblyOptimization("Simplifiable jumps",
|
||||
needsFlowInfo = FlowInfoRequirement.JustLabels,
|
||||
(Elidable & HasOpcodeIn(ConditionalBranching) & MatchParameter(0)) ~
|
||||
(Elidable & HasOpcodeIn(BRA, JMP)) ~
|
||||
(Elidable & HasOpcodeIn(LABEL) & MatchParameter(0) & IsNotALabelUsedManyTimes) ~~> {code =>
|
||||
List(code(1).copy(opcode = invertBranching(code.head.opcode), addrMode = LongRelative))
|
||||
},
|
||||
(Elidable & HasOpcodeIn(ConditionalBranching) & MatchParameter(0)) ~
|
||||
(Elidable & HasOpcodeIn(BRA, JMP)) ~
|
||||
(Elidable & HasOpcodeIn(LABEL) & MatchParameter(0)) ~~> {code =>
|
||||
List(code(1).copy(opcode = invertBranching(code.head.opcode), addrMode = LongRelative), code(2))
|
||||
}
|
||||
)
|
||||
|
||||
val SimplifiableArithmetics = new RuleBasedAssemblyOptimization("Simplifiable arithmetics",
|
||||
needsFlowInfo = FlowInfoRequirement.BothFlows,
|
||||
|
||||
(Elidable & HasOpcode(LEAX)
|
||||
& HasAddrMode(DAccumulatorIndexed(X, indirect = false))
|
||||
& HasA(0)
|
||||
& DoesntMatterWhatItDoesWith(MState.VF, MState.ZF, MState.NF)) ~~>
|
||||
(_ => List(MLine.inherent(ABX))),
|
||||
|
||||
(NotFixed & HasB(0) & HasOpcodeIn(ORB, EORB, ADDB) & DoesntMatterWhatItDoesWith(MState.VF, MState.ZF, MState.NF, MState.CF, MState.HF)) ~~>
|
||||
(_.map(_.copy(opcode = LDB))),
|
||||
(NotFixed & HasB(0xff) & HasOpcode(ANDB) & DoesntMatterWhatItDoesWith(MState.VF, MState.ZF, MState.NF, MState.CF, MState.HF)) ~~>
|
||||
(_.map(_.copy(opcode = LDB))),
|
||||
(NotFixed & HasA(0) & HasOpcodeIn(ORA, EORA, ADDA) & DoesntMatterWhatItDoesWith(MState.VF, MState.ZF, MState.NF, MState.CF, MState.HF)) ~~>
|
||||
(_.map(_.copy(opcode = LDA))),
|
||||
(NotFixed & HasA(0xff) & HasOpcode(ANDA) & DoesntMatterWhatItDoesWith(MState.VF, MState.ZF, MState.NF, MState.CF, MState.HF)) ~~>
|
||||
(_.map(_.copy(opcode = LDA))),
|
||||
(NotFixed & HasA(0) & HasB(0) & HasOpcodeIn(ADDD) & DoesntMatterWhatItDoesWith(MState.VF, MState.ZF, MState.NF, MState.CF, MState.HF)) ~~>
|
||||
(_.map(_.copy(opcode = LDD))),
|
||||
(Elidable & HasImmediate(0) & HasOpcodeIn(ORB, EORB, ADDB, ORA, EORA, ADDA, ADDD) & DoesntMatterWhatItDoesWith(MState.VF, MState.ZF, MState.NF, MState.CF, MState.HF)) ~~>
|
||||
(_ => Nil),
|
||||
|
||||
)
|
||||
|
||||
val All: Seq[AssemblyOptimization[MLine]] = Seq(
|
||||
PointlessLoad,
|
||||
PointlessRegisterTransfers,
|
||||
SimplifiableArithmetics,
|
||||
SimplifiableJumps,
|
||||
SimplifiableZeroStore
|
||||
)
|
||||
}
|
||||
|
81
src/main/scala/millfork/assembly/m6809/opt/JumpFixing.scala
Normal file
81
src/main/scala/millfork/assembly/m6809/opt/JumpFixing.scala
Normal file
@ -0,0 +1,81 @@
|
||||
package millfork.assembly.m6809.opt
|
||||
|
||||
import millfork.CompilationOptions
|
||||
import millfork.assembly.m6809.{LongRelative, MLine, MLine0, Relative}
|
||||
import millfork.env.{Label, MemoryAddressConstant, NormalFunction, ThingInMemory}
|
||||
import millfork.assembly.m6809.MOpcode._
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
*/
|
||||
object JumpFixing {
|
||||
|
||||
def validShortJump(thisOffset: Int, labelOffset: Int): Boolean = {
|
||||
// TODO
|
||||
val distance = labelOffset - (thisOffset + 2)
|
||||
distance.toByte == distance
|
||||
}
|
||||
|
||||
def apply(f: NormalFunction, code: List[MLine], options: CompilationOptions): List[MLine] = {
|
||||
val offsets = new Array[Int](code.length)
|
||||
var o = 0
|
||||
code.zipWithIndex.foreach{
|
||||
case (line, ix) =>
|
||||
offsets(ix) = o
|
||||
o += line.sizeInBytes
|
||||
}
|
||||
val labelOffsets = code.zipWithIndex.flatMap {
|
||||
case (MLine0(LABEL, _, MemoryAddressConstant(Label(label))), ix) => Some(label -> offsets(ix))
|
||||
case _ => None
|
||||
}.toMap
|
||||
var changed = false
|
||||
|
||||
def makeLong(line: MLine): MLine = {
|
||||
changed = true
|
||||
val newLine = line.copy(addrMode = LongRelative)
|
||||
options.log.debug("Changing branch from short to long")
|
||||
if (options.log.traceEnabled) {
|
||||
options.log.trace(line.toString)
|
||||
options.log.trace(" ↓")
|
||||
options.log.trace(newLine.toString)
|
||||
}
|
||||
newLine
|
||||
}
|
||||
def makeShort(line: MLine): MLine = {
|
||||
changed = true
|
||||
val newLine = line.copy(addrMode = Relative)
|
||||
options.log.debug("Changing branch from long to short")
|
||||
if (options.log.traceEnabled) {
|
||||
options.log.trace(line.toString)
|
||||
options.log.trace(" ↓")
|
||||
options.log.trace(newLine.toString)
|
||||
}
|
||||
newLine
|
||||
}
|
||||
|
||||
import millfork.assembly.Elidability.Elidable
|
||||
import millfork.assembly.Elidability.Volatile
|
||||
val result = code.zipWithIndex.map {
|
||||
case (line@MLine(_, Relative, MemoryAddressConstant(th: ThingInMemory), Elidable | Volatile, _), ix) =>
|
||||
labelOffsets.get(th.name) match {
|
||||
case None =>
|
||||
changed = true
|
||||
line.copy(addrMode = LongRelative)
|
||||
case Some(labelOffset) =>
|
||||
val thisOffset = offsets(ix)
|
||||
if (!validShortJump(thisOffset, labelOffset)) makeLong(line) else line
|
||||
}
|
||||
case (line@MLine(_, Relative, _, Elidable | Volatile, _), _) =>
|
||||
makeLong(line)
|
||||
case (line@MLine(_, LongRelative, MemoryAddressConstant(th: ThingInMemory), Elidable | Volatile, _), ix) =>
|
||||
labelOffsets.get(th.name) match {
|
||||
case None => line
|
||||
case Some(labelOffset) =>
|
||||
val thisOffset = offsets(ix)
|
||||
if (validShortJump(thisOffset, labelOffset)) makeShort(line) else line
|
||||
}
|
||||
case (line, _) => line
|
||||
}
|
||||
if (changed) apply(f, result, options) else result
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@ package millfork.assembly.m6809.opt
|
||||
|
||||
import millfork.{CompilationFlag, CompilationOptions}
|
||||
import millfork.assembly._
|
||||
import millfork.assembly.m6809.{Absolute, Immediate, Inherent, InherentA, InherentB, LongRelative, MAddrMode, MLine, MLine0, MOpcode, MState, Relative, TwoRegisters}
|
||||
import millfork.assembly.m6809.{Absolute, DAccumulatorIndexed, Immediate, Indexed, Inherent, InherentA, InherentB, LongRelative, MAddrMode, MLine, MLine0, MOpcode, MState, NonExistent, PostIncremented, PreDecremented, Relative, TwoRegisters}
|
||||
import millfork.assembly.opt.SingleStatus
|
||||
import millfork.compiler.LabelGenerator
|
||||
import millfork.env._
|
||||
@ -989,6 +989,25 @@ case class DoesntChangeMemoryAtAssumingNonchangingIndices(addrMode1: Int, param1
|
||||
override def hitRate: Double = 0.973
|
||||
}
|
||||
|
||||
case class DoesntChangeIndexingInAddrMode(i: Int) extends MLinePattern {
|
||||
override def matchLineTo(ctx: AssemblyMatchingContext, flowInfo: FlowInfo, line: MLine): Boolean = {
|
||||
import M6809Register._
|
||||
ctx.get[MAddrMode](i) match {
|
||||
case Indexed(S, false) => !ConcernsS.matchLineTo(ctx, flowInfo, line)
|
||||
case Indexed(X, false) => !ChangesX.matchLineTo(ctx, flowInfo, line)
|
||||
case Indexed(Y, false) => !ChangesY.matchLineTo(ctx, flowInfo, line)
|
||||
case Absolute(true) => !ChangesMemory.matchLineTo(ctx, flowInfo, line)
|
||||
case Absolute(false) | Inherent | InherentA | InherentB | Immediate => true
|
||||
case _ => false // let's ignore rarer addressing modes
|
||||
}
|
||||
}
|
||||
|
||||
override def toString: String = s"¬(?<$i>AddrMode)"
|
||||
|
||||
override def hitRate: Double = 0.99
|
||||
}
|
||||
|
||||
|
||||
case object ConcernsMemory extends MLinePattern {
|
||||
override def matchLineTo(ctx: AssemblyMatchingContext, flowInfo: FlowInfo, line: MLine): Boolean =
|
||||
ReadsMemory.matchLineTo(ctx, flowInfo, line) || ChangesMemory.matchLineTo(ctx, flowInfo, line)
|
||||
|
@ -1,6 +1,7 @@
|
||||
package millfork.output
|
||||
|
||||
import millfork.assembly.SourceLine
|
||||
import millfork.assembly.m6809.opt.JumpFixing
|
||||
import millfork.{CompilationOptions, Platform}
|
||||
import millfork.assembly.m6809.{MOpcode, _}
|
||||
import millfork.compiler.m6809.M6809Compiler
|
||||
@ -25,7 +26,9 @@ class M6809Assembler(program: Program,
|
||||
|
||||
override def gatherNiceFunctionProperties(options: CompilationOptions, niceFunctionProperties: mutable.Set[(NiceFunctionProperty, String)], function: NormalFunction, code: List[MLine]): Unit = ()
|
||||
|
||||
override def performFinalOptimizationPass(f: NormalFunction, actuallyOptimize: Boolean, options: CompilationOptions, code: List[MLine]): List[MLine] = code
|
||||
override def performFinalOptimizationPass(f: NormalFunction, actuallyOptimize: Boolean, options: CompilationOptions, code: List[MLine]): List[MLine] = {
|
||||
JumpFixing(f, code, options)
|
||||
}
|
||||
|
||||
private def registerCode(register: M6809Register.Value): Int = {
|
||||
import M6809Register._
|
||||
|
Loading…
x
Reference in New Issue
Block a user