1
0
mirror of https://github.com/KarolS/millfork.git synced 2025-01-11 12:29:46 +00:00

Fix and improve nonet operations

This commit is contained in:
Karol Stasiak 2018-12-14 15:43:12 +01:00
parent 406d69c74a
commit eb6b7d7769
6 changed files with 107 additions and 3 deletions

View File

@ -94,6 +94,18 @@ object AlwaysGoodOptimizations {
HasOpcode(LSR) & HasAddrMode(Implied) & DoesntMatterWhatItDoesWith(State.C)) ~~> { (code, ctx) =>
AssemblyLine.immediate(LDA, (ctx.get[Int](0) & 0xff) >> 1) :: Nil
},
(Elidable & MatchA(0) &
HasOpcode(ASL) & HasAddrMode(Implied)) ~~> { (code, ctx) =>
val v = ctx.get[Int](0)
AssemblyLine.immediate(LDA, (v << 1) & 0xff) :: AssemblyLine.implied(if(v.&(0x80) != 0) SEC else CLC) :: Nil
},
(Elidable & MatchA(0) &
HasOpcode(LSR) & HasAddrMode(Implied)) ~~> { (code, ctx) =>
val v = ctx.get[Int](0)
AssemblyLine.immediate(LDA, (v & 0xff) >> 1) :: AssemblyLine.implied(if(v.&(1) != 0) SEC else CLC) :: Nil
},
(Elidable & MatchA(0) &
HasClear(State.C) & HasOpcode(ROL) & HasAddrMode(Implied) & DoesntMatterWhatItDoesWith(State.C)) ~~> { (code, ctx) =>
AssemblyLine.immediate(LDA, ctx.get[Int](0) << 1) :: Nil
@ -110,6 +122,28 @@ object AlwaysGoodOptimizations {
HasSet(State.C) & HasOpcode(ROR) & HasAddrMode(Implied) & DoesntMatterWhatItDoesWith(State.C)) ~~> { (code, ctx) =>
AssemblyLine.immediate(LDA, 0x80 + (ctx.get[Int](0) & 0xff) / 2) :: Nil
},
(Elidable & MatchA(0) &
HasClear(State.C) & HasOpcode(ROL) & HasAddrMode(Implied)) ~~> { (code, ctx) =>
val v = ctx.get[Int](0)
AssemblyLine.immediate(LDA, v << 1) :: AssemblyLine.implied(if(v.&(0x80) != 0) SEC else CLC) :: Nil
},
(Elidable & MatchA(0) &
HasClear(State.C) & HasOpcode(ROR) & HasAddrMode(Implied)) ~~> { (code, ctx) =>
val v = ctx.get[Int](0)
AssemblyLine.immediate(LDA, (ctx.get[Int](0) & 0xff) >> 1) :: AssemblyLine.implied(if(v.&(1) != 0) SEC else CLC) :: Nil
},
(Elidable & MatchA(0) &
HasSet(State.C) & HasOpcode(ROL) & HasAddrMode(Implied)) ~~> { (code, ctx) =>
val v = ctx.get[Int](0)
AssemblyLine.immediate(LDA, (v * 2 + 1) & 0xff) :: AssemblyLine.implied(if(v.&(0x80) != 0) SEC else CLC) :: Nil
},
(Elidable & MatchA(0) &
HasSet(State.C) & HasOpcode(ROR) & HasAddrMode(Implied)) ~~> { (code, ctx) =>
val v = ctx.get[Int](0)
AssemblyLine.immediate(LDA, 0x80 + (v & 0xff) / 2) :: AssemblyLine.implied(if(v.&(1) != 0) SEC else CLC) :: Nil
},
(Elidable &
MatchA(0) & MatchParameter(1) &
HasOpcode(ADC) & HasAddrMode(Immediate) &
@ -535,6 +569,19 @@ object AlwaysGoodOptimizations {
LAX, DoesntMatterWhatItDoesWith(State.N, State.Z),
Not(ConcernsX) & Not(ConcernsA),
SAX, DoesntMatterWhatItDoesWith(State.A, State.X)),
(Elidable & HasOpcode(ASL) & HasAddrMode(Implied)) ~
(Linear & Not(ConcernsA) & Not(ConcernsC) & Not(ReadsNOrZ)).* ~
(Elidable & HasOpcode(ROR) & HasAddrMode(Implied) & DoesntMatterWhatItDoesWith(State.C, State.N, State.Z)) ~~> (_.init.tail),
(Elidable & HasOpcode(LSR) & HasAddrMode(Implied)) ~
(Linear & Not(ConcernsA) & Not(ConcernsC) & Not(ReadsNOrZ)).* ~
(Elidable & HasOpcode(ROL) & HasAddrMode(Implied) & DoesntMatterWhatItDoesWith(State.C, State.N, State.Z)) ~~> (_.init.tail),
(Elidable & HasOpcode(ROL) & HasAddrMode(Implied)) ~
(Linear & Not(ConcernsA) & Not(ConcernsC) & Not(ReadsNOrZ)).* ~
(Elidable & HasOpcode(ROR) & HasAddrMode(Implied) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~~> (_.init.tail),
(Elidable & HasOpcode(ROR) & HasAddrMode(Implied)) ~
(Linear & Not(ConcernsA) & Not(ConcernsC) & Not(ReadsNOrZ)).* ~
(Elidable & HasOpcode(ROL) & HasAddrMode(Implied) & DoesntMatterWhatItDoesWith(State.N, State.Z)) ~~> (_.init.tail),
)
val PointlessStackStashing = new RuleBasedAssemblyOptimization("Pointless stack stashing",

View File

@ -192,6 +192,10 @@ abstract class AbstractStatementPreprocessor(ctx: CompilationContext, statements
FunctionCallExpression("nonet", args.map(arg => optimizeExpr(arg, Map()))).pos(pos)
case FunctionCallExpression(name, args) =>
FunctionCallExpression(name, args.map(arg => optimizeExpr(arg, currentVarValues))).pos(pos)
case SumExpression(expressions, decimal) =>
// don't collapse additions, let the later stages deal with it
// expecially important when inside a nonet operation
SumExpression(expressions.map{case (minus, arg) => minus -> optimizeExpr(arg, currentVarValues)}, decimal)
case _ => expr // TODO
}
}

View File

@ -260,6 +260,18 @@ object BuiltIns {
def compileNonetOps(ctx: CompilationContext, lhs: Expression, rhs: Expression): List[AssemblyLine] = {
val env = ctx.env
lhs match {
case FunctionCallExpression("nonet", List(lparam)) =>
(env.eval(lhs), env.eval(rhs)) match {
case (None, Some(NumericConstant(0, _))) =>
return MosExpressionCompiler.compile(ctx, lparam, None, NoBranching)
case (None, Some(NumericConstant(n, _))) if n > 0 =>
return MosExpressionCompiler.compile(ctx, lparam, None, NoBranching) ++
(AssemblyLine.implied(ROR) :: List.fill(n.toInt - 1)(AssemblyLine.implied(LSR)))
case _ =>
}
case _ =>
}
val b = env.get[Type]("byte")
val (ldaHi, ldaLo) = env.eval(lhs) match {
case Some(c) =>

View File

@ -361,7 +361,7 @@ case class CompoundConstant(operator: MathOperator.Value, lhs: Constant, rhs: Co
case _ => return this
}
operator match {
case MathOperator.Plus9 | MathOperator.DecimalPlus9 =>
case MathOperator.Plus9 | MathOperator.DecimalPlus9 | MathOperator.Shl9 | MathOperator.DecimalShl9 =>
size = 2
case MathOperator.Times | MathOperator.Shl =>
val mask = (1 << (size * 8)) - 1

View File

@ -549,9 +549,9 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
constantOperation(MathOperator.Shl9, ps)
case List(FunctionCallExpression("<<'", ps@List(_, _))) =>
constantOperation(MathOperator.DecimalShl9, ps)
case List(SumExpression(ps@List((true,_),(true,_)), false)) =>
case List(SumExpression(ps@List((false,_),(false,_)), false)) =>
constantOperation(MathOperator.Plus9, ps.map(_._2))
case List(SumExpression(ps@List((true,_),(true,_)), true)) =>
case List(SumExpression(ps@List((false,_),(false,_)), true)) =>
constantOperation(MathOperator.DecimalPlus9, ps.map(_._2))
case List(_) =>
None

View File

@ -102,4 +102,45 @@ class NonetSuite extends FunSuite with Matchers {
m.readWord(0xc006) should equal(0x8080)
}
}
test("Nonet shift right") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
"""
| byte output0 @$c000
| byte output1 @$c002
| byte output2 @$c004
| noinline void perform(byte x) {
| output0 = nonet(150+160) >>>> 1
| output1 = nonet(153+output0) >>>> 1
| output2 = nonet(150+x) >>>> 1
| }
| void main () {
| perform(200)
| }
| noinline byte three() { return 3 }
""".stripMargin) { m =>
m.readByte(0xc000) should equal(155)
m.readByte(0xc002) should equal(154)
m.readByte(0xc004) should equal(175)
}
}
test("Nonet shift right 2") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(
"""
| byte output0 @$c000
| byte output1 @$c002
| noinline void perform(byte x) {
| output0 = nonet(180 << 1) >>>> 1
| output1 = nonet(output0 << 1) >>>> 1
| }
| void main () {
| perform(200)
| }
| noinline byte three() { return 3 }
""".stripMargin) { m =>
m.readByte(0xc000) should equal(180)
m.readByte(0xc002) should equal(180)
}
}
}