mirror of
https://github.com/KarolS/millfork.git
synced 2025-01-19 19:30:08 +00:00
6502: Faster accesses to small arrays
This commit is contained in:
parent
d36b83421c
commit
b7300616d1
@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
* Optimized certain byte comparisons.
|
* Optimized certain byte comparisons.
|
||||||
|
|
||||||
* 6502: Optimized certain boolean conversions.
|
* 6502: Optimized certain boolean conversions and some small array accesses.
|
||||||
|
|
||||||
* Unused built-in functions are now removed more accurately.
|
* Unused built-in functions are now removed more accurately.
|
||||||
|
|
||||||
|
@ -408,7 +408,14 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
|||||||
Nil
|
Nil
|
||||||
}
|
}
|
||||||
case DerefExpression(inner, offset, targetType) =>
|
case DerefExpression(inner, offset, targetType) =>
|
||||||
val (prepare, addr, am) = getPhysicalPointerForDeref(ctx, inner)
|
val (prepare, addr, am, fast) = getPhysicalPointerForDeref(ctx, inner)
|
||||||
|
if (targetType.size == 1) {
|
||||||
|
fast match {
|
||||||
|
case Some((fastBase, fastIndex)) =>
|
||||||
|
return preserveRegisterIfNeeded(ctx, MosRegister.A, fastIndex(offset)) ++ List(AssemblyLine.absoluteY(STA, fastBase))
|
||||||
|
case _ =>
|
||||||
|
}
|
||||||
|
}
|
||||||
val lo = preserveRegisterIfNeeded(ctx, MosRegister.A, prepare) ++ List(AssemblyLine.immediate(LDY, offset), AssemblyLine(STA, am, addr))
|
val lo = preserveRegisterIfNeeded(ctx, MosRegister.A, prepare) ++ List(AssemblyLine.immediate(LDY, offset), AssemblyLine(STA, am, addr))
|
||||||
if (targetType.size == 1) {
|
if (targetType.size == 1) {
|
||||||
lo
|
lo
|
||||||
@ -523,17 +530,42 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
|||||||
compile(ctx, expr, Some(p -> env.get[Variable]("__reg.b2b3")), BranchSpec.None)
|
compile(ctx, expr, Some(p -> env.get[Variable]("__reg.b2b3")), BranchSpec.None)
|
||||||
}
|
}
|
||||||
|
|
||||||
def getPhysicalPointerForDeref(ctx: CompilationContext, pointerExpression: Expression): (List[AssemblyLine], Constant, AddrMode.Value) = {
|
def getPhysicalPointerForDeref(ctx: CompilationContext, pointerExpression: Expression): (List[AssemblyLine], Constant, AddrMode.Value, Option[(Constant, Int => List[AssemblyLine])]) = {
|
||||||
pointerExpression match {
|
pointerExpression match {
|
||||||
case VariableExpression(name) =>
|
case VariableExpression(name) =>
|
||||||
val p = ctx.env.get[ThingInMemory](name)
|
val p = ctx.env.get[ThingInMemory](name)
|
||||||
if (p.isInstanceOf[MfArray]) return (Nil, p.toAddress, AddrMode.AbsoluteY)
|
p match {
|
||||||
if (p.zeropage) return (Nil, p.toAddress, AddrMode.IndexedY)
|
case array: MfArray => return (Nil, p.toAddress, AddrMode.AbsoluteY,
|
||||||
|
if (array.sizeInBytes <= 256) Some(p.toAddress, (i: Int) => List(AssemblyLine.immediate(LDY, i))) else None)
|
||||||
|
case _ =>
|
||||||
|
}
|
||||||
|
if (p.zeropage) return (Nil, p.toAddress, AddrMode.IndexedY, None)
|
||||||
case _ =>
|
case _ =>
|
||||||
}
|
}
|
||||||
ctx.env.eval(pointerExpression) match {
|
ctx.env.eval(pointerExpression) match {
|
||||||
case Some(addr) => (Nil, addr, AddrMode.AbsoluteY)
|
case Some(addr) => (Nil, addr, AddrMode.AbsoluteY, None)
|
||||||
case _ => (compileToZReg(ctx, pointerExpression), ctx.env.get[ThingInMemory]("__reg.loword").toAddress, AddrMode.IndexedY)
|
case _ =>
|
||||||
|
val baseAndIndex: Option[(Expression, Expression)] = pointerExpression match {
|
||||||
|
case SumExpression(List((false, base), (false, index)), false) => Some(base -> index)
|
||||||
|
case FunctionCallExpression(pointerType, List(SumExpression(List((false, base), (false, index)), false))) if pointerType.startsWith("pointer.") =>
|
||||||
|
Some(base -> index)
|
||||||
|
case _ => None
|
||||||
|
}
|
||||||
|
(compileToZReg(ctx, pointerExpression), ctx.env.get[ThingInMemory]("__reg.loword").toAddress, AddrMode.IndexedY, baseAndIndex match {
|
||||||
|
case Some((base, index)) =>
|
||||||
|
val itype = AbstractExpressionCompiler.getExpressionType(ctx, index)
|
||||||
|
if (itype.size != 1 || itype.isSigned) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
ctx.env.eval(base).map { baseConst =>
|
||||||
|
baseConst -> { (i: Int) =>
|
||||||
|
val b = ctx.env.get[Type]("byte")
|
||||||
|
compile(ctx, index #+# i, Some(b -> RegisterVariable(MosRegister.Y, b)), BranchSpec.None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case _ => None
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1035,19 +1067,27 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case DerefExpression(inner, offset, targetType) =>
|
case DerefExpression(inner, offset, targetType) =>
|
||||||
val (prepare, addr, am) = getPhysicalPointerForDeref(ctx, inner)
|
val (prepare, addr, am, fast) = getPhysicalPointerForDeref(ctx, inner)
|
||||||
(targetType.size, am) match {
|
(fast, targetType.size, am) match {
|
||||||
case (1, AbsoluteY) =>
|
case (Some((fastBase, fastIndex)), 1, _) =>
|
||||||
|
fastIndex(offset) ++ List(AssemblyLine.absoluteY(LDA, fastBase)) ++ expressionStorageFromA(ctx, exprTypeAndVariable, expr.position, exprType.isSigned)
|
||||||
|
case (_, 1, AbsoluteY) =>
|
||||||
prepare ++ List(AssemblyLine.absolute(LDA, addr + offset)) ++ expressionStorageFromA(ctx, exprTypeAndVariable, expr.position, exprType.isSigned)
|
prepare ++ List(AssemblyLine.absolute(LDA, addr + offset)) ++ expressionStorageFromA(ctx, exprTypeAndVariable, expr.position, exprType.isSigned)
|
||||||
case (1, _) =>
|
case (_, 1, _) =>
|
||||||
prepare ++ List(AssemblyLine.immediate(LDY, offset), AssemblyLine(LDA, am, addr)) ++ expressionStorageFromA(ctx, exprTypeAndVariable, expr.position, exprType.isSigned)
|
prepare ++ List(AssemblyLine.immediate(LDY, offset), AssemblyLine(LDA, am, addr)) ++ expressionStorageFromA(ctx, exprTypeAndVariable, expr.position, exprType.isSigned)
|
||||||
case (2, AbsoluteY) =>
|
case (Some((fastBase, fastIndex)), 2, _) =>
|
||||||
|
fastIndex(offset) ++ List(
|
||||||
|
AssemblyLine.absoluteY(LDA, fastBase),
|
||||||
|
AssemblyLine.implied(INY),
|
||||||
|
AssemblyLine.absoluteY(LDX, fastBase)) ++
|
||||||
|
expressionStorageFromAX(ctx, exprTypeAndVariable, expr.position)
|
||||||
|
case (_, 2, AbsoluteY) =>
|
||||||
prepare ++
|
prepare ++
|
||||||
List(
|
List(
|
||||||
AssemblyLine.absolute(LDA, addr + offset),
|
AssemblyLine.absolute(LDA, addr + offset),
|
||||||
AssemblyLine.absolute(LDX, addr + offset + 1)) ++
|
AssemblyLine.absolute(LDX, addr + offset + 1)) ++
|
||||||
expressionStorageFromAX(ctx, exprTypeAndVariable, expr.position)
|
expressionStorageFromAX(ctx, exprTypeAndVariable, expr.position)
|
||||||
case (2, _) =>
|
case (_, 2, _) =>
|
||||||
prepare ++
|
prepare ++
|
||||||
List(
|
List(
|
||||||
AssemblyLine.immediate(LDY, offset+1),
|
AssemblyLine.immediate(LDY, offset+1),
|
||||||
@ -2058,7 +2098,7 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
|||||||
ctx.log.error("Invalid left-hand-side use of `:`")
|
ctx.log.error("Invalid left-hand-side use of `:`")
|
||||||
Nil
|
Nil
|
||||||
case DerefExpression(inner, offset, targetType) =>
|
case DerefExpression(inner, offset, targetType) =>
|
||||||
val (prepare, addr, am) = getPhysicalPointerForDeref(ctx, inner)
|
val (prepare, addr, am, fastTarget) = getPhysicalPointerForDeref(ctx, inner)
|
||||||
env.eval(source) match {
|
env.eval(source) match {
|
||||||
case Some(constant) =>
|
case Some(constant) =>
|
||||||
am match {
|
am match {
|
||||||
@ -2104,7 +2144,7 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
|||||||
Nil
|
Nil
|
||||||
}
|
}
|
||||||
case DerefExpression(innerSource, sourceOffset, _) =>
|
case DerefExpression(innerSource, sourceOffset, _) =>
|
||||||
val (prepareSource, addrSource, amSource) = getPhysicalPointerForDeref(ctx, innerSource)
|
val (prepareSource, addrSource, amSource, fastSource) = getPhysicalPointerForDeref(ctx, innerSource)
|
||||||
(am, amSource) match {
|
(am, amSource) match {
|
||||||
case (AbsoluteY, AbsoluteY) =>
|
case (AbsoluteY, AbsoluteY) =>
|
||||||
prepare ++ prepareSource ++ (0 until targetType.size).flatMap { i =>
|
prepare ++ prepareSource ++ (0 until targetType.size).flatMap { i =>
|
||||||
|
@ -39,14 +39,14 @@ sealed trait Expression extends Node {
|
|||||||
def isPure: Boolean
|
def isPure: Boolean
|
||||||
def getAllIdentifiers: Set[String]
|
def getAllIdentifiers: Set[String]
|
||||||
|
|
||||||
def #+#(smallInt: Int): Expression = (this #+# LiteralExpression(smallInt, 1).pos(this.position)).pos(this.position)
|
def #+#(smallInt: Int): Expression = if (smallInt == 0) this else (this #+# LiteralExpression(smallInt, 1).pos(this.position)).pos(this.position)
|
||||||
def #+#(that: Expression): Expression = that match {
|
def #+#(that: Expression): Expression = that match {
|
||||||
case SumExpression(params, false) => SumExpression((false -> this) :: params, decimal = false)
|
case SumExpression(params, false) => SumExpression((false -> this) :: params, decimal = false)
|
||||||
case _ => SumExpression(List(false -> this, false -> that), decimal = false)
|
case _ => SumExpression(List(false -> this, false -> that), decimal = false)
|
||||||
}
|
}
|
||||||
def #*#(smallInt: Int): Expression =
|
def #*#(smallInt: Int): Expression =
|
||||||
if (smallInt == 1) this else FunctionCallExpression("*", List(this, LiteralExpression(smallInt, 1).pos(this.position))).pos(this.position)
|
if (smallInt == 1) this else FunctionCallExpression("*", List(this, LiteralExpression(smallInt, 1).pos(this.position))).pos(this.position)
|
||||||
def #-#(smallInt: Int): Expression = (this #-# LiteralExpression(smallInt, 1).pos(this.position)).pos(this.position)
|
def #-#(smallInt: Int): Expression = if (smallInt == 0) this else (this #-# LiteralExpression(smallInt, 1).pos(this.position)).pos(this.position)
|
||||||
def #-#(that: Expression): Expression = SumExpression(List(false -> this, true -> that), decimal = false)
|
def #-#(that: Expression): Expression = SumExpression(List(false -> this, true -> that), decimal = false)
|
||||||
|
|
||||||
@transient var typeCache: Type = _
|
@transient var typeCache: Type = _
|
||||||
|
@ -610,4 +610,19 @@ class ArraySuite extends FunSuite with Matchers with AppendedClues {
|
|||||||
m.readLong(0xc024) should equal(0) withClue "b4..b7 of a[4] initted from stack int40"
|
m.readLong(0xc024) should equal(0) withClue "b4..b7 of a[4] initted from stack int40"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
test("Fast small array indexing") {
|
||||||
|
EmuBenchmarkRun(
|
||||||
|
"""
|
||||||
|
| array(word) words[10] @$c000
|
||||||
|
| noinline byte getLo(byte i) = words[i].lo
|
||||||
|
| noinline byte getHi(byte i) = words[i].hi
|
||||||
|
| noinline word get(byte i) = words[i]
|
||||||
|
| void main () {
|
||||||
|
| get(5)
|
||||||
|
| }
|
||||||
|
""".stripMargin){ m =>
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user