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:
parent
406d69c74a
commit
eb6b7d7769
@ -94,6 +94,18 @@ object AlwaysGoodOptimizations {
|
|||||||
HasOpcode(LSR) & HasAddrMode(Implied) & DoesntMatterWhatItDoesWith(State.C)) ~~> { (code, ctx) =>
|
HasOpcode(LSR) & HasAddrMode(Implied) & DoesntMatterWhatItDoesWith(State.C)) ~~> { (code, ctx) =>
|
||||||
AssemblyLine.immediate(LDA, (ctx.get[Int](0) & 0xff) >> 1) :: Nil
|
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) &
|
(Elidable & MatchA(0) &
|
||||||
HasClear(State.C) & HasOpcode(ROL) & HasAddrMode(Implied) & DoesntMatterWhatItDoesWith(State.C)) ~~> { (code, ctx) =>
|
HasClear(State.C) & HasOpcode(ROL) & HasAddrMode(Implied) & DoesntMatterWhatItDoesWith(State.C)) ~~> { (code, ctx) =>
|
||||||
AssemblyLine.immediate(LDA, ctx.get[Int](0) << 1) :: Nil
|
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) =>
|
HasSet(State.C) & HasOpcode(ROR) & HasAddrMode(Implied) & DoesntMatterWhatItDoesWith(State.C)) ~~> { (code, ctx) =>
|
||||||
AssemblyLine.immediate(LDA, 0x80 + (ctx.get[Int](0) & 0xff) / 2) :: Nil
|
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 &
|
(Elidable &
|
||||||
MatchA(0) & MatchParameter(1) &
|
MatchA(0) & MatchParameter(1) &
|
||||||
HasOpcode(ADC) & HasAddrMode(Immediate) &
|
HasOpcode(ADC) & HasAddrMode(Immediate) &
|
||||||
@ -535,6 +569,19 @@ object AlwaysGoodOptimizations {
|
|||||||
LAX, DoesntMatterWhatItDoesWith(State.N, State.Z),
|
LAX, DoesntMatterWhatItDoesWith(State.N, State.Z),
|
||||||
Not(ConcernsX) & Not(ConcernsA),
|
Not(ConcernsX) & Not(ConcernsA),
|
||||||
SAX, DoesntMatterWhatItDoesWith(State.A, State.X)),
|
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",
|
val PointlessStackStashing = new RuleBasedAssemblyOptimization("Pointless stack stashing",
|
||||||
|
@ -192,6 +192,10 @@ abstract class AbstractStatementPreprocessor(ctx: CompilationContext, statements
|
|||||||
FunctionCallExpression("nonet", args.map(arg => optimizeExpr(arg, Map()))).pos(pos)
|
FunctionCallExpression("nonet", args.map(arg => optimizeExpr(arg, Map()))).pos(pos)
|
||||||
case FunctionCallExpression(name, args) =>
|
case FunctionCallExpression(name, args) =>
|
||||||
FunctionCallExpression(name, args.map(arg => optimizeExpr(arg, currentVarValues))).pos(pos)
|
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
|
case _ => expr // TODO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -260,6 +260,18 @@ object BuiltIns {
|
|||||||
|
|
||||||
def compileNonetOps(ctx: CompilationContext, lhs: Expression, rhs: Expression): List[AssemblyLine] = {
|
def compileNonetOps(ctx: CompilationContext, lhs: Expression, rhs: Expression): List[AssemblyLine] = {
|
||||||
val env = ctx.env
|
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 b = env.get[Type]("byte")
|
||||||
val (ldaHi, ldaLo) = env.eval(lhs) match {
|
val (ldaHi, ldaLo) = env.eval(lhs) match {
|
||||||
case Some(c) =>
|
case Some(c) =>
|
||||||
|
2
src/main/scala/millfork/env/Constant.scala
vendored
2
src/main/scala/millfork/env/Constant.scala
vendored
@ -361,7 +361,7 @@ case class CompoundConstant(operator: MathOperator.Value, lhs: Constant, rhs: Co
|
|||||||
case _ => return this
|
case _ => return this
|
||||||
}
|
}
|
||||||
operator match {
|
operator match {
|
||||||
case MathOperator.Plus9 | MathOperator.DecimalPlus9 =>
|
case MathOperator.Plus9 | MathOperator.DecimalPlus9 | MathOperator.Shl9 | MathOperator.DecimalShl9 =>
|
||||||
size = 2
|
size = 2
|
||||||
case MathOperator.Times | MathOperator.Shl =>
|
case MathOperator.Times | MathOperator.Shl =>
|
||||||
val mask = (1 << (size * 8)) - 1
|
val mask = (1 << (size * 8)) - 1
|
||||||
|
@ -549,9 +549,9 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
|||||||
constantOperation(MathOperator.Shl9, ps)
|
constantOperation(MathOperator.Shl9, ps)
|
||||||
case List(FunctionCallExpression("<<'", ps@List(_, _))) =>
|
case List(FunctionCallExpression("<<'", ps@List(_, _))) =>
|
||||||
constantOperation(MathOperator.DecimalShl9, ps)
|
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))
|
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))
|
constantOperation(MathOperator.DecimalPlus9, ps.map(_._2))
|
||||||
case List(_) =>
|
case List(_) =>
|
||||||
None
|
None
|
||||||
|
@ -102,4 +102,45 @@ class NonetSuite extends FunSuite with Matchers {
|
|||||||
m.readWord(0xc006) should equal(0x8080)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user