1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-05-31 18:41:30 +00:00

Various optimizations

This commit is contained in:
Karol Stasiak 2020-12-01 18:18:56 +01:00
parent 4a529b5ddc
commit 90a9538936
5 changed files with 200 additions and 33 deletions

View File

@ -36,6 +36,8 @@
* 8080: word negation now works.
* Various optimization improvements.
* Various other fixes.
* Improved some error messages.

View File

@ -1379,103 +1379,103 @@ object AlwaysGoodOptimizations {
needsFlowInfo = FlowInfoRequirement.BackwardFlow,
(HasOpcodeIn(LDA, STA) & HasAddrMode(Immediate) & MatchParameter(1)) ~
(Linear & Not(ChangesA) & Not(HasOpcode(DISCARD_AF))).* ~
(Linear & Not(ChangesA) & Not(HasOpcode(DISCARD_AF)) | HasOpcodeIn(OpcodeClasses.ShortConditionalBranching)).* ~
(Elidable & HasOpcode(LDA) & HasAddrMode(Immediate) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~~> (_.init),
(HasOpcodeIn(LDX, STX) & HasAddrMode(Immediate) & MatchParameter(1)) ~
(Linear & Not(ChangesX) & Not(HasOpcode(DISCARD_XF))).* ~
(Linear & Not(ChangesX) & Not(HasOpcode(DISCARD_XF)) | HasOpcodeIn(OpcodeClasses.ShortConditionalBranching)).* ~
(Elidable & HasOpcode(LDX) & HasAddrMode(Immediate) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~~> (_.init),
(HasOpcodeIn(LDY, STY) & HasAddrMode(Immediate) & MatchParameter(1)) ~
(Linear & Not(ChangesY) & Not(HasOpcode(DISCARD_YF))).* ~
(Linear & Not(ChangesY) & Not(HasOpcode(DISCARD_YF)) | HasOpcodeIn(OpcodeClasses.ShortConditionalBranching)).* ~
(Elidable & HasOpcode(LDY) & HasAddrMode(Immediate) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~~> (_.init),
(HasOpcodeIn(LDA, STA) & MatchAddrMode(0) & MatchParameter(1)) ~
(Linear & Not(ChangesA) & Not(HasOpcode(DISCARD_AF)) & DoesntChangeIndexingInAddrMode(0) & DoesntChangeMemoryAt(0, 1)).* ~
(Linear & Not(ChangesA) & Not(HasOpcode(DISCARD_AF)) & DoesntChangeIndexingInAddrMode(0) & DoesntChangeMemoryAt(0, 1) | HasOpcodeIn(OpcodeClasses.ShortConditionalBranching)).* ~
(Elidable & HasOpcode(LDA) & MatchAddrMode(0) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~~> (_.init),
(HasOpcodeIn(LDX, STX) & MatchAddrMode(0) & MatchParameter(1)) ~
(Linear & Not(ChangesX) & Not(HasOpcode(DISCARD_XF)) & DoesntChangeIndexingInAddrMode(0) & DoesntChangeMemoryAt(0, 1)).* ~
(Linear & Not(ChangesX) & Not(HasOpcode(DISCARD_XF)) & DoesntChangeIndexingInAddrMode(0) & DoesntChangeMemoryAt(0, 1) | HasOpcodeIn(OpcodeClasses.ShortConditionalBranching)).* ~
(Elidable & HasOpcode(LDX) & MatchAddrMode(0) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~~> (_.init),
(HasOpcodeIn(LDY, STY) & MatchAddrMode(0) & MatchParameter(1)) ~
(Linear & Not(ChangesY) & Not(HasOpcode(DISCARD_YF)) & DoesntChangeIndexingInAddrMode(0) & DoesntChangeMemoryAt(0, 1)).* ~
(Linear & Not(ChangesY) & Not(HasOpcode(DISCARD_YF)) & DoesntChangeIndexingInAddrMode(0) & DoesntChangeMemoryAt(0, 1) | HasOpcodeIn(OpcodeClasses.ShortConditionalBranching)).* ~
(Elidable & HasOpcode(LDY) & MatchAddrMode(0) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~~> (_.init),
(HasOpcode(LDA) & HasAddrMode(Immediate) & MatchParameter(1)) ~
(Linear & Not(ChangesA) & Not(ChangesNAndZ) & Not(HasOpcode(DISCARD_AF))).* ~
(Linear & Not(ChangesA) & Not(ChangesNAndZ) & Not(HasOpcode(DISCARD_AF)) | HasOpcodeIn(OpcodeClasses.ShortConditionalBranching)).* ~
(Elidable & HasOpcode(LDA) & HasAddrMode(Immediate) & MatchParameter(1)) ~~> (_.init),
(HasOpcode(LDX) & HasAddrMode(Immediate) & MatchParameter(1)) ~
(Linear & Not(ChangesX) & Not(ChangesNAndZ) & Not(HasOpcode(DISCARD_XF))).* ~
(Linear & Not(ChangesX) & Not(ChangesNAndZ) & Not(HasOpcode(DISCARD_XF)) | HasOpcodeIn(OpcodeClasses.ShortConditionalBranching)).* ~
(Elidable & HasOpcode(LDX) & HasAddrMode(Immediate) & MatchParameter(1)) ~~> (_.init),
(HasOpcode(LDY) & HasAddrMode(Immediate) & MatchParameter(1)) ~
(Linear & Not(ChangesY) & Not(ChangesNAndZ) & Not(HasOpcode(DISCARD_YF))).* ~
(Linear & Not(ChangesY) & Not(ChangesNAndZ) & Not(HasOpcode(DISCARD_YF)) | HasOpcodeIn(OpcodeClasses.ShortConditionalBranching)).* ~
(Elidable & HasOpcode(LDY) & HasAddrMode(Immediate) & MatchParameter(1)) ~~> (_.init),
(HasOpcode(LDA) & MatchAddrMode(0) & MatchParameter(1)) ~
(Linear & Not(ChangesA) & Not(ChangesNAndZ) & Not(HasOpcode(DISCARD_AF)) & DoesntChangeIndexingInAddrMode(0) & DoesntChangeMemoryAt(0, 1)).* ~
(Linear & Not(ChangesA) & Not(ChangesNAndZ) & Not(HasOpcode(DISCARD_AF)) & DoesntChangeIndexingInAddrMode(0) & DoesntChangeMemoryAt(0, 1) | HasOpcodeIn(OpcodeClasses.ShortConditionalBranching)).* ~
(Elidable & HasOpcode(LDA) & MatchAddrMode(0) & MatchParameter(1)) ~~> (_.init),
(HasOpcode(LDX) & MatchAddrMode(0) & MatchParameter(1)) ~
(Linear & Not(ChangesX) & Not(ChangesNAndZ) & Not(HasOpcode(DISCARD_XF)) & DoesntChangeIndexingInAddrMode(0) & DoesntChangeMemoryAt(0, 1)).* ~
(Linear & Not(ChangesX) & Not(ChangesNAndZ) & Not(HasOpcode(DISCARD_XF)) & DoesntChangeIndexingInAddrMode(0) & DoesntChangeMemoryAt(0, 1) | HasOpcodeIn(OpcodeClasses.ShortConditionalBranching)).* ~
(Elidable & HasOpcode(LDX) & MatchAddrMode(0) & MatchParameter(1)) ~~> (_.init),
(HasOpcode(LDY) & MatchAddrMode(0) & MatchParameter(1)) ~
(Linear & Not(ChangesY) & Not(ChangesNAndZ) & Not(HasOpcode(DISCARD_YF)) & DoesntChangeIndexingInAddrMode(0) & DoesntChangeMemoryAt(0, 1)).* ~
(Linear & Not(ChangesY) & Not(ChangesNAndZ) & Not(HasOpcode(DISCARD_YF)) & DoesntChangeIndexingInAddrMode(0) & DoesntChangeMemoryAt(0, 1) | HasOpcodeIn(OpcodeClasses.ShortConditionalBranching)).* ~
(Elidable & HasOpcode(LDY) & MatchAddrMode(0) & MatchParameter(1)) ~~> (_.init),
(HasOpcodeIn(LDA, STA) & MatchAddrMode(0) & MatchParameter(1)) ~
(ShortConditionalBranching & MatchParameter(2)) ~
(Linear & Not(ChangesA) & Not(HasOpcode(DISCARD_AF)) & DoesntChangeIndexingInAddrMode(0) & DoesntChangeMemoryAt(0, 1)).* ~
(Linear & Not(ChangesA) & Not(HasOpcode(DISCARD_AF)) & DoesntChangeIndexingInAddrMode(0) & DoesntChangeMemoryAt(0, 1) | HasOpcodeIn(OpcodeClasses.ShortConditionalBranching)).* ~
(HasOpcode(LABEL) & MatchParameter(2)) ~
(Elidable & HasOpcode(LDA) & MatchAddrMode(0) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~~> (_.init),
(HasOpcodeIn(LDX, STX) & MatchAddrMode(0) & MatchParameter(1)) ~
(ShortConditionalBranching & MatchParameter(2)) ~
(Linear & Not(ChangesX) & Not(HasOpcode(DISCARD_XF)) & DoesntChangeIndexingInAddrMode(0) & DoesntChangeMemoryAt(0, 1)).* ~
(Linear & Not(ChangesX) & Not(HasOpcode(DISCARD_XF)) & DoesntChangeIndexingInAddrMode(0) & DoesntChangeMemoryAt(0, 1) | HasOpcodeIn(OpcodeClasses.ShortConditionalBranching)).* ~
(HasOpcode(LABEL) & MatchParameter(2)) ~
(Elidable & HasOpcode(LDX) & MatchAddrMode(0) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~~> (_.init),
(HasOpcodeIn(LDY, STY) & MatchAddrMode(0) & MatchParameter(1)) ~
(ShortConditionalBranching & MatchParameter(2)) ~
(Linear & Not(ChangesY) & Not(HasOpcode(DISCARD_YF)) & DoesntChangeIndexingInAddrMode(0) & DoesntChangeMemoryAt(0, 1)).* ~
(Linear & Not(ChangesY) & Not(HasOpcode(DISCARD_YF)) & DoesntChangeIndexingInAddrMode(0) & DoesntChangeMemoryAt(0, 1) | HasOpcodeIn(OpcodeClasses.ShortConditionalBranching)).* ~
(HasOpcode(LABEL) & MatchParameter(2)) ~
(Elidable & HasOpcode(LDY) & MatchAddrMode(0) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~~> (_.init),
(HasOpcodeIn(LDA, STA) & MatchAddrMode(0) & MatchParameter(1)) ~
(ShortBranching & MatchParameter(3)) ~
(Linear & Not(ChangesA) & Not(HasOpcode(DISCARD_AF)) & DoesntChangeIndexingInAddrMode(0) & DoesntChangeMemoryAt(0, 1)).* ~
(Linear & Not(ChangesA) & Not(HasOpcode(DISCARD_AF)) & DoesntChangeIndexingInAddrMode(0) & DoesntChangeMemoryAt(0, 1) | HasOpcodeIn(OpcodeClasses.ShortConditionalBranching)).* ~
(HasOpcode(LABEL) & MatchParameter(3) & HasCallerCount(1)) ~
(Elidable & HasOpcode(LDA) & MatchAddrMode(0) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~~> (_.init),
HasOpcodeIn(TXA, TAX, LAX, LXA) ~
(Not(HasOpcodeIn(TXA, TAX)) & Linear & Not(ChangesA) & Not(ChangesX)).* ~
(Not(HasOpcodeIn(TXA, TAX)) & Linear & Not(ChangesA) & Not(ChangesX) | HasOpcodeIn(OpcodeClasses.ShortConditionalBranching)).* ~
(Elidable & HasOpcodeIn(TXA, TAX) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~~> (_.init),
HasOpcodeIn(TYA, TAY) ~
(Not(HasOpcodeIn(TYA, TAY)) & Linear & Not(ChangesA) & Not(ChangesY)).* ~
(Not(HasOpcodeIn(TYA, TAY)) & Linear & Not(ChangesA) & Not(ChangesY) | HasOpcodeIn(OpcodeClasses.ShortConditionalBranching)).* ~
(Elidable & HasOpcodeIn(TYA, TAY) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~~> (_.init),
(HasOpcodeIn(STA, LDA) & HasAddrModeIn(ZeroPage, Absolute) & MatchAddrMode(0) & MatchParameter(1)) ~
(Linear & Not(HasOpcode(TAX)) & Not(ChangesA) & DoesntChangeMemoryAt(0, 1)).* ~
(Linear & Not(HasOpcode(TAX)) & Not(ChangesA) & DoesntChangeMemoryAt(0, 1) | HasOpcodeIn(OpcodeClasses.ShortConditionalBranching)).* ~
HasOpcode(TAX) ~
(LinearOrBranch & Not(ChangesX) & DoesntChangeMemoryAt(0, 1)).* ~
(Elidable & HasOpcode(LDX) & HasAddrModeIn(ZeroPage, Absolute) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~~> (_.init),
(HasOpcodeIn(STA, LDA) & HasAddrModeIn(ZeroPage, Absolute) & MatchAddrMode(0) & MatchParameter(1)) ~
(Linear & Not(HasOpcode(TAY)) & Not(ChangesA) & DoesntChangeMemoryAt(0, 1)).* ~
(Linear & Not(HasOpcode(TAY)) & Not(ChangesA) & DoesntChangeMemoryAt(0, 1) | HasOpcodeIn(OpcodeClasses.ShortConditionalBranching)).* ~
HasOpcode(TAY) ~
(LinearOrBranch & Not(ChangesY) & DoesntChangeMemoryAt(0, 1)).* ~
(Elidable & HasOpcode(LDY) & HasAddrModeIn(ZeroPage, Absolute) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~~> (_.init),
(HasOpcodeIn(LDA, STA) & MatchAddrMode(0) & MatchParameter(1)) ~
(Linear & Not(ChangesA) & Not(HasOpcode(DISCARD_AF)) & DoesntChangeIndexingInAddrMode(0) & DoesNotConcernMemoryAt(0, 1)).* ~
(Linear & Not(ChangesA) & Not(HasOpcode(DISCARD_AF)) & DoesntChangeIndexingInAddrMode(0) & DoesNotConcernMemoryAt(0, 1) | HasOpcodeIn(OpcodeClasses.ShortConditionalBranching)).* ~
(Elidable & HasOpcode(LDX) & MatchAddrMode(0) & MatchParameter(1)) ~~> (code => code.init :+ AssemblyLine.implied(TAX)),
(HasOpcodeIn(LDA, STA) & MatchAddrMode(0) & MatchParameter(1)) ~
(Linear & Not(ChangesA) & Not(HasOpcode(DISCARD_AF)) & DoesntChangeIndexingInAddrMode(0) & DoesNotConcernMemoryAt(0, 1)).* ~
(Linear & Not(ChangesA) & Not(HasOpcode(DISCARD_AF)) & DoesntChangeIndexingInAddrMode(0) & DoesNotConcernMemoryAt(0, 1) | HasOpcodeIn(OpcodeClasses.ShortConditionalBranching)).* ~
(Elidable & HasOpcode(LDY) & MatchAddrMode(0) & MatchParameter(1)) ~~> (code => code.init :+ AssemblyLine.implied(TAY)),
)
@ -3046,6 +3046,66 @@ object AlwaysGoodOptimizations {
(Elidable & HasOpcode(LABEL) & MatchParameter(1) & IsNotALabelUsedManyTimes & DoesntMatterWhatItDoesWith(State.N, State.Z, State.C, State.V)) ~~> { code =>
List(code(1).copy(opcode = LDA), code.head.copy(opcode = AND))
},
(Elidable & HasOpcode(CMP) & HasAddrMode(Immediate)) ~
(Elidable & HasOpcodeIn(BEQ, BNE) & MatchParameter(1)) ~
(Elidable & HasAddrMode(Implied) & HasOpcodeIn(INC, DEC) & DoesntMatterWhatItDoesWith(State.N, State.Z, State.C, State.V)) ~
(Elidable & HasOpcode(JMP) & HasAddrModeIn(Absolute, LongAbsolute)) ~
(Elidable & HasOpcode(LABEL) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.N, State.Z, State.C, State.V, State.A)) ~~> { code =>
val delta = code(2).opcode match {
case INC => +1
case DEC => -1
}
val branch = code(1).opcode match {
case BEQ => BNE
case BNE => BEQ
}
List(
code(2),
code.head.copy(parameter = (code.head.parameter + delta).quickSimplify),
code(1).copy(opcode = branch, parameter = code(3).parameter),
code(4))
},
(Elidable & HasOpcode(CPX) & HasAddrMode(Immediate)) ~
(Elidable & HasOpcodeIn(BEQ, BNE) & MatchParameter(1)) ~
(Elidable & HasAddrMode(Implied) & HasOpcodeIn(INX, DEX) & DoesntMatterWhatItDoesWith(State.N, State.Z, State.C, State.V)) ~
(Elidable & HasOpcode(JMP) & HasAddrModeIn(Absolute, LongAbsolute)) ~
(Elidable & HasOpcode(LABEL) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.N, State.Z, State.C, State.V, State.X)) ~~> { code =>
val delta = code(2).opcode match {
case INX => +1
case DEX => -1
}
val branch = code(1).opcode match {
case BEQ => BNE
case BNE => BEQ
}
List(
code(2),
code.head.copy(parameter = (code.head.parameter + delta).quickSimplify),
code(1).copy(opcode = branch, parameter = code(3).parameter),
code(4))
},
(Elidable & HasOpcode(CPY) & HasAddrMode(Immediate)) ~
(Elidable & HasOpcodeIn(BEQ, BNE) & MatchParameter(1)) ~
(Elidable & HasAddrMode(Implied) & HasOpcodeIn(INY, DEY) & DoesntMatterWhatItDoesWith(State.N, State.Z, State.C, State.V)) ~
(Elidable & HasOpcode(JMP) & HasAddrModeIn(Absolute, LongAbsolute)) ~
(Elidable & HasOpcode(LABEL) & MatchParameter(1) & DoesntMatterWhatItDoesWith(State.N, State.Z, State.C, State.V, State.Y)) ~~> { code =>
val delta = code(2).opcode match {
case INY => +1
case DEY => -1
}
val branch = code(1).opcode match {
case BEQ => BNE
case BNE => BEQ
}
List(
code(2),
code.head.copy(parameter = (code.head.parameter + delta).quickSimplify),
code(1).copy(opcode = branch, parameter = code(3).parameter),
code(4))
},
)
private val powersOf2: List[(Int, Int)] = List(

View File

@ -94,55 +94,76 @@ object AlwaysGoodI80Optimizations {
needsFlowInfo = FlowInfoRequirement.ForwardFlow,
for7Registers(register =>
Is8BitLoad(ZRegister.MEM_HL, register) ~
(Linear & Not(Changes(ZRegister.H)) & Not(Changes(ZRegister.L)) & Not(ChangesMemory) & Not(Changes(register)) & Not(IsRegular8BitLoadFrom(ZRegister.MEM_HL))).* ~
(HasOpcodeIn(Set(JP,JR)) & Not(HasRegisters(NoRegisters)) |
Linear & Not(Changes(ZRegister.H)) & Not(Changes(ZRegister.L)) & Not(ChangesMemory) & Not(Changes(register)) & Not(IsRegular8BitLoadFrom(ZRegister.MEM_HL))).* ~
(Elidable & Is8BitLoad(register, ZRegister.MEM_HL)) ~~> { code => code.init }
),
for7Registers(register =>
Is8BitLoad(register, ZRegister.MEM_HL) ~
(HasOpcodeIn(Set(JP,JR)) & Not(HasRegisters(NoRegisters)) |
Linear & Not(Changes(ZRegister.H)) & Not(Changes(ZRegister.L)) & Not(ChangesMemory) & Not(Changes(register)) & Not(IsRegular8BitLoadFrom(ZRegister.MEM_HL))).* ~
(Elidable & Is8BitLoad(register, ZRegister.MEM_HL)) ~~> { code => code.init }
),
for7Registers(register =>
Is8BitLoad(ZRegister.MEM_HL, register) ~
(Linear & Not(Changes(ZRegister.H)) & Not(Changes(ZRegister.L)) & Not(ChangesMemory) & Not(Changes(register)) & Not(IsRegular8BitLoadFrom(ZRegister.MEM_HL))).* ~
(HasOpcodeIn(Set(JP, JR)) & Not(HasRegisters(NoRegisters)) |
Linear & Not(Changes(ZRegister.H)) & Not(Changes(ZRegister.L)) & Not(ChangesMemory) & Not(Changes(register)) & Not(IsRegular8BitLoadFrom(ZRegister.MEM_HL))).* ~
(Elidable & IsRegular8BitLoadFrom(ZRegister.MEM_HL)) ~~> { code =>
val last = code.last
code.init :+ last.copy(registers = TwoRegisters(last.registers.asInstanceOf[TwoRegisters].target, register))
}
),
(Is8BitLoad(ZRegister.MEM_ABS_8, ZRegister.A) & MatchParameter(0)).captureLine(1) ~
(Linear & DoesntChangeMemoryAt(1) & Not(Changes(ZRegister.A))).* ~
(HasOpcodeIn(Set(JP, JR)) & Not(HasRegisters(NoRegisters)) |
Linear & DoesntChangeMemoryAt(1) & Not(Changes(ZRegister.A))).* ~
(Elidable & Is8BitLoad(ZRegister.A, ZRegister.MEM_ABS_8) & MatchParameter(0)) ~~> { code => code.init },
(Is8BitLoad(ZRegister.A, ZRegister.MEM_ABS_8) & MatchParameter(0)).captureLine(1) ~
(HasOpcodeIn(Set(JP, JR)) & Not(HasRegisters(NoRegisters)) |
Linear & DoesntChangeMemoryAt(1) & Not(Changes(ZRegister.A))).* ~
(Elidable & Is8BitLoad(ZRegister.A, ZRegister.MEM_ABS_8) & MatchParameter(0)) ~~> { code => code.init },
(Is8BitLoad(ZRegister.MEM_HL, ZRegister.A) & MatchConstantInHL(0)).captureLine(1) ~
(Linear & DoesntChangeMemoryAt(1) & Not(Changes(ZRegister.A))).* ~
(HasOpcodeIn(Set(JP, JR)) & Not(HasRegisters(NoRegisters)) |
Linear & DoesntChangeMemoryAt(1) & Not(Changes(ZRegister.A))).* ~
(Elidable & Is8BitLoad(ZRegister.A, ZRegister.MEM_ABS_8) & MatchParameter(0)) ~~> { code => code.init },
(Is8BitLoad(ZRegister.MEM_ABS_8, ZRegister.A) & MatchParameter(0)).captureLine(1) ~
(Linear & DoesntChangeMemoryAt(1) & Not(Changes(ZRegister.A))).* ~
(HasOpcodeIn(Set(JP, JR)) & Not(HasRegisters(NoRegisters)) |
Linear & DoesntChangeMemoryAt(1) & Not(Changes(ZRegister.A))).* ~
(Elidable & Is8BitLoad(ZRegister.A, ZRegister.MEM_HL) & MatchConstantInHL(0)) ~~> { code => code.init },
(Is8BitLoad(ZRegister.MEM_HL, ZRegister.A) & MatchConstantInHL(0)).captureLine(1) ~
(Linear & DoesntChangeMemoryAt(1) & Not(Changes(ZRegister.A))).* ~
(HasOpcodeIn(Set(JP, JR)) & Not(HasRegisters(NoRegisters)) |
Linear & DoesntChangeMemoryAt(1) & Not(Changes(ZRegister.A))).* ~
(Elidable & Is8BitLoad(ZRegister.A, ZRegister.MEM_HL) & MatchConstantInHL(0)) ~~> { code => code.init },
(Is16BitLoad(ZRegister.MEM_ABS_16, ZRegister.HL) & MatchParameter(0)).captureLine(1) ~
(Linear & DoesntChangeMemoryAt(1) & Not(Changes(ZRegister.HL))).* ~
(HasOpcodeIn(Set(JP, JR)) & Not(HasRegisters(NoRegisters)) |
Linear & DoesntChangeMemoryAt(1) & Not(Changes(ZRegister.HL))).* ~
(Elidable & Is16BitLoad(ZRegister.HL, ZRegister.MEM_ABS_16) & MatchParameter(0)) ~~> { code => code.init },
(Is8BitLoad(ZRegister.MEM_ABS_8, ZRegister.A) & MatchParameter(0) & MatchRegister(ZRegister.A, 2)).captureLine(1) ~
(Linear & DoesntChangeMemoryAt(1) & Not(Is8BitLoad(ZRegister.A, ZRegister.MEM_ABS_8))).* ~
(HasOpcodeIn(Set(JP, JR)) & Not(HasRegisters(NoRegisters)) |
Linear & DoesntChangeMemoryAt(1) & Not(Is8BitLoad(ZRegister.A, ZRegister.MEM_ABS_8))).* ~
(Elidable & Is8BitLoad(ZRegister.A, ZRegister.MEM_ABS_8) & MatchParameter(0)) ~~> { (code, ctx) =>
code.init :+ ZLine.ldImm8(ZRegister.A, ctx.get[Int](2))
},
(Is16BitLoad(ZRegister.MEM_ABS_16, ZRegister.HL) & MatchParameter(0) & MatchConstantInHL(2)).captureLine(1) ~
(Linear & DoesntChangeMemoryAt(1) & Not(Is16BitLoad(ZRegister.HL, ZRegister.MEM_ABS_16))).* ~
(HasOpcodeIn(Set(JP, JR)) & Not(HasRegisters(NoRegisters)) |
Linear & DoesntChangeMemoryAt(1) & Not(Is16BitLoad(ZRegister.HL, ZRegister.MEM_ABS_16))).* ~
(Elidable & Is16BitLoad(ZRegister.HL, ZRegister.MEM_ABS_16) & MatchParameter(0)) ~~> { (code, ctx) =>
code.init :+ ZLine.ldImm16(ZRegister.HL, ctx.get[Constant](2))
},
for5LargeRegisters(register =>
(Is8BitLoad(MEM_ABS_8, ZRegister.A) & MatchParameter(0) & MatchRegister(A, 2)).captureLine(1) ~
(Linear & DoesntChangeMemoryAt(1) & Not(Is8BitLoad(MEM_ABS_8, ZRegister.A))).* ~
(HasOpcodeIn(Set(JP, JR)) & Not(HasRegisters(NoRegisters)) |
Linear & DoesntChangeMemoryAt(1) & Not(Is8BitLoad(MEM_ABS_8, ZRegister.A))).* ~
(Is8BitLoad(MEM_ABS_8, ZRegister.A) & MatchParameter(10) & MatchRegister(A, 12)).captureLine(11) ~
Where(ctx => ctx.get[Constant](0).succ == ctx.get[Constant](10)) ~
(Linear & DoesntChangeMemoryAt(1) & DoesntChangeMemoryAt(11)).* ~
(HasOpcodeIn(Set(JP, JR)) & Not(HasRegisters(NoRegisters)) |
Linear & DoesntChangeMemoryAt(1) & DoesntChangeMemoryAt(11)).* ~
(Elidable & Is16BitLoad(register, MEM_ABS_16) & MatchParameter(0) & MatchRegister(A, 12)) ~~> { (code, ctx) =>
val hi = ctx.get[Int](12)
val lo = ctx.get[Int](2)
@ -859,6 +880,50 @@ object AlwaysGoodI80Optimizations {
),
)
val SimplifiableComparison = new RuleBasedAssemblyOptimization("Simplifiable comparison",
needsFlowInfo = FlowInfoRequirement.BackwardFlow,
(Elidable & HasOpcode(CP) & HasRegisterParam(ZRegister.IMM_8)) ~
(Elidable & HasOpcodeIn(Set(JR, JP)) & MatchJumpTarget(1) & (HasRegisters(IfFlagSet(ZFlag.Z)) | HasRegisters(IfFlagClear(ZFlag.Z)))) ~
(Elidable & HasOpcodeIn(Set(INC, DEC)) & HasRegisterParam(ZRegister.A) & DoesntMatterWhatItDoesWithFlags) ~
(Elidable & HasOpcodeIn(Set(JR, JP)) & IsUnconditional) ~
(Elidable & HasOpcode(LABEL) & MatchJumpTarget(1) & IsUnconditional & DoesntMatterWhatItDoesWithFlags & DoesntMatterWhatItDoesWith(ZRegister.A)) ~~> { code =>
val delta = code(2).opcode match {
case INC => +1
case DEC => -1
}
val branch = code(1).registers.negate
List(
code(2),
code.head.copy(parameter = (code.head.parameter + delta).quickSimplify),
code(1).copy(opcode=JP, registers = branch, parameter = code(3).parameter),
code(4))
},
for6Registers(reg =>
(Elidable & Is8BitLoad(ZRegister.A, reg)) ~
(Elidable & HasOpcode(CP) & HasRegisterParam(ZRegister.IMM_8)) ~
(Elidable & HasOpcodeIn(Set(JR, JP)) & MatchJumpTarget(1) & DoesntMatterWhatItDoesWith(ZRegister.A) & (HasRegisters(IfFlagSet(ZFlag.Z)) | HasRegisters(IfFlagClear(ZFlag.Z)))) ~
(Elidable & HasOpcodeIn(Set(INC, DEC)) & HasRegisterParam(reg) & DoesntMatterWhatItDoesWithFlags) ~
(Elidable & HasOpcodeIn(Set(JR, JP)) & IsUnconditional) ~
(Elidable & HasOpcode(LABEL) & MatchJumpTarget(1) & IsUnconditional & DoesntMatterWhatItDoesWithFlags & DoesntMatterWhatItDoesWith(ZRegister.A, reg)) ~~> { code =>
val delta = code(3).opcode match {
case INC => +1
case DEC => -1
}
val branch = code(2).registers.negate
List(
code(3),
code.head,
code(1).copy(parameter = (code(1).parameter + delta).quickSimplify),
code(2).copy(opcode=JP, registers = branch, parameter = code(4).parameter),
code(5))
},
)
)
val FreeHL = new RuleBasedAssemblyOptimization("Free HL",
needsFlowInfo = FlowInfoRequirement.BackwardFlow,
// 0
@ -1218,6 +1283,14 @@ object AlwaysGoodI80Optimizations {
(HasOpcodeIn(Set(JP, JR)) & MatchJumpTarget(0) & Elidable) ~
HasOpcodeIn(ZOpcodeClasses.NoopDiscards).* ~
(HasOpcode(LABEL) & MatchJumpTarget(0)) ~~> (c => c.last :: Nil),
(HasOpcodeIn(Set(JP, JR)) & MatchJumpTarget(0) & IsConditional & Elidable) ~
(HasOpcodeIn(Set(JP, JR)) & Elidable & IsUnconditional) ~
(HasOpcode(LABEL) & MatchJumpTarget(0)) ~~> { code =>
List(
code(1).copy(opcode = JP, registers = code.head.registers.negate),
code(2)
)
},
)
val SimplifiableShifting = new RuleBasedAssemblyOptimization("Simplifiable shifting",
@ -1762,6 +1835,7 @@ object AlwaysGoodI80Optimizations {
PointlessStackUnstashing,
ReloadingKnownValueFromMemory,
ShiftingKnownValue,
SimplifiableComparison,
SimplifiableMaths,
SimplifiableShifting,
UnusedCodeRemoval,

View File

@ -719,6 +719,13 @@ case object IsUnconditional extends AssemblyLinePattern {
override def hitRate: Double = 0.212
}
case object IsConditional extends AssemblyLinePattern {
override def matchLineTo(ctx: AssemblyMatchingContext, flowInfo: FlowInfo, line: ZLine): Boolean =
line.registers.isInstanceOf[IfFlagSet] || line.registers.isInstanceOf[IfFlagClear]
override def hitRate: Double = 0.212
}
case class MatchConstantInHL(i: Int) extends AssemblyLinePattern {
override def validate(needsFlowInfo: FlowInfoRequirement.Value): Unit =
FlowInfoRequirement.assertForward(needsFlowInfo)

View File

@ -144,4 +144,28 @@ class SecondAssemblyOptimizationSuite extends FunSuite with Matchers {
}
}
test("Bubblesort") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
"""
|array sorttable [2540] @$C000
|
|void main() {
| byte t,i,n1,n2
| for t,25,downto,0{
| for i,0,to,25{
| n1 = sorttable[i]
| n2 = sorttable[i+1]
| if n1>n2 {
| sorttable[i] = n2
| sorttable[i+1] = n1
| }
| }
| }
|}
|
|""".stripMargin) { m =>
}
}
}