mirror of
https://github.com/KarolS/millfork.git
synced 2025-01-10 20:29:35 +00:00
Allow modifying large things via pointers
This commit is contained in:
parent
b9736f924c
commit
632bb0c994
@ -130,7 +130,6 @@ object M6809LargeBuiltins {
|
||||
case List(MLine(LEAX, _, _, _, _)) => None
|
||||
case xs =>
|
||||
result ++= xs
|
||||
ctx.log.error("Invalid left-hand-side expression", target.position)
|
||||
None
|
||||
}
|
||||
var firstNonzeroByte = 0
|
||||
|
@ -333,13 +333,14 @@ object BuiltIns {
|
||||
}
|
||||
|
||||
def compileInPlaceWordOrLongShiftOps(ctx: CompilationContext, lhs: LhsExpression, rhs: Expression, aslRatherThanLsr: Boolean): List[AssemblyLine] = {
|
||||
val reg = ctx.env.get[VariableInMemory]("__reg")
|
||||
lhs match {
|
||||
case dx: DerefExpression =>
|
||||
if (ctx.options.zpRegisterSize < 4) {
|
||||
ctx.log.error("Unsupported shift operation. Consider increasing the size of the zeropage register or simplifying the left hand side expression.", lhs.position)
|
||||
return MosExpressionCompiler.compileToAX(ctx, lhs) ++ MosExpressionCompiler.compileToAX(ctx, rhs)
|
||||
}
|
||||
return handleWordOrLongInPlaceModificationViaDeref(ctx, dx, rhs){ (ptr, reg, offset, r) =>
|
||||
return handleWordOrLongInPlaceModificationViaDeref(ctx, dx, rhs, fromMsb = !aslRatherThanLsr){ (ptr, reg, offset, r) =>
|
||||
val shiftAmount = r match {
|
||||
case List(AssemblyLine0(LDA, Immediate, NumericConstant(a, _)), AssemblyLine0(LDX, Immediate, _)) => Some(a.toInt)
|
||||
case _ => None
|
||||
@ -399,7 +400,65 @@ object BuiltIns {
|
||||
storeFromR2 ++ List(
|
||||
AssemblyLine.label(labelSkip))
|
||||
}
|
||||
}
|
||||
}(Left({ size =>
|
||||
val compiledRhs = MosExpressionCompiler.compileToA(ctx, rhs)
|
||||
val shiftAmount = compiledRhs match {
|
||||
case List(AssemblyLine0(LDA, Immediate, NumericConstant(a, _))) => Some(a.toInt)
|
||||
case _ => None
|
||||
}
|
||||
val innerLoopLabel = ctx.nextLabel("sr")
|
||||
val singleShift = if (aslRatherThanLsr) {
|
||||
List(
|
||||
AssemblyLine.implied(CLC),
|
||||
AssemblyLine.immediate(LDY, 0),
|
||||
AssemblyLine.label(innerLoopLabel),
|
||||
AssemblyLine.indexedY(LDA, reg),
|
||||
AssemblyLine.implied(ROL),
|
||||
AssemblyLine.indexedY(STA, reg),
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine.immediate(CPY, size),
|
||||
AssemblyLine.relative(BNE, innerLoopLabel))
|
||||
} else {
|
||||
List(
|
||||
AssemblyLine.implied(CLC),
|
||||
AssemblyLine.immediate(LDY, size - 1),
|
||||
AssemblyLine.label(innerLoopLabel),
|
||||
AssemblyLine.indexedY(LDA, reg),
|
||||
AssemblyLine.implied(ROR),
|
||||
AssemblyLine.indexedY(STA, reg),
|
||||
AssemblyLine.implied(DEY),
|
||||
AssemblyLine.relative(BPL, innerLoopLabel))
|
||||
}
|
||||
shiftAmount match {
|
||||
case Some(0) => Nil
|
||||
case Some(n) if n >= size * 8 =>
|
||||
List(
|
||||
AssemblyLine.immediate(LDY, size - 1),
|
||||
AssemblyLine.label(innerLoopLabel),
|
||||
AssemblyLine.immediate(LDA, 0),
|
||||
AssemblyLine.indexedY(STA, reg),
|
||||
AssemblyLine.implied(DEY),
|
||||
AssemblyLine.relative(BPL, innerLoopLabel))
|
||||
case Some(1) => singleShift
|
||||
case Some(n) if n > 0 =>
|
||||
val labelRepeat = ctx.nextLabel("sr")
|
||||
compiledRhs ++ List(
|
||||
AssemblyLine.implied(TAX),
|
||||
AssemblyLine.label(labelRepeat)) ++ singleShift ++ List(
|
||||
AssemblyLine.implied(DEX),
|
||||
AssemblyLine.relative(BEQ, labelRepeat))
|
||||
case _ =>
|
||||
val labelSkip = ctx.nextLabel("ss")
|
||||
val labelRepeat = ctx.nextLabel("sr")
|
||||
compiledRhs ++ List(
|
||||
AssemblyLine.implied(TAX),
|
||||
AssemblyLine.relative(BEQ, labelSkip),
|
||||
AssemblyLine.label(labelRepeat)) ++ singleShift ++ List(
|
||||
AssemblyLine.implied(DEX),
|
||||
AssemblyLine.relative(BEQ, labelRepeat),
|
||||
AssemblyLine.label(labelSkip))
|
||||
}
|
||||
}))
|
||||
case _ =>
|
||||
}
|
||||
val env = ctx.env
|
||||
@ -1137,7 +1196,7 @@ object BuiltIns {
|
||||
v match {
|
||||
case dx: DerefExpression =>
|
||||
// this is ugly, needs a rewrite
|
||||
return handleWordOrLongInPlaceModificationViaDeref(ctx, dx, addend){(ptr, reg, offset, r) =>
|
||||
return handleWordOrLongInPlaceModificationViaDeref(ctx, dx, addend, fromMsb = false){(ptr, reg, offset, r) =>
|
||||
val constR = r match {
|
||||
case List(AssemblyLine0(LDA, Immediate, l), AssemblyLine0(LDX, Immediate, h)) =>
|
||||
h.asl(8).+(l).quickSimplify match {
|
||||
@ -1211,7 +1270,7 @@ object BuiltIns {
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
)
|
||||
}
|
||||
}
|
||||
}(Left({size => ???}))
|
||||
case _ =>
|
||||
}
|
||||
val b = ctx.env.get[Type]("byte")
|
||||
@ -1466,15 +1525,17 @@ object BuiltIns {
|
||||
}
|
||||
|
||||
@inline
|
||||
private def handleWordOrLongInPlaceModificationViaDeref(ctx: CompilationContext, lhs: DerefExpression, rhs: Expression)(footer: (Constant, VariableInMemory, Int, List[AssemblyLine]) => List[AssemblyLine]): List[AssemblyLine] = {
|
||||
private def handleWordOrLongInPlaceModificationViaDeref(ctx: CompilationContext, lhs: DerefExpression, rhs: Expression, fromMsb: Boolean)
|
||||
(wordFooter: (Constant, VariableInMemory, Int, List[AssemblyLine]) => List[AssemblyLine])
|
||||
(eitherDoWholeThingOrMergeByte: Either[(Int) => List[AssemblyLine], (Int, List[AssemblyLine], Boolean) => List[AssemblyLine]]): List[AssemblyLine] = {
|
||||
if (ctx.options.zpRegisterSize < 2) {
|
||||
ctx.log.error("Unsupported operation. Consider increasing the size of the zeropage register.", lhs.position)
|
||||
return MosExpressionCompiler.compileToAX(ctx, lhs) ++ MosExpressionCompiler.compileToAX(ctx, rhs)
|
||||
}
|
||||
val env = ctx.env
|
||||
val targetType = MosExpressionCompiler.getExpressionType(ctx, lhs)
|
||||
val reg = env.get[VariableInMemory]("__reg")
|
||||
if (targetType.size == 2 ) {
|
||||
val reg = env.get[VariableInMemory]("__reg")
|
||||
var l = MosExpressionCompiler.compileToZReg(ctx, lhs.inner)
|
||||
val ptr = l match {
|
||||
case List(AssemblyLine0(LDA, ZeroPage, p), AssemblyLine0(STA, ZeroPage, _), AssemblyLine0(LDA, ZeroPage, q), AssemblyLine0(STA, ZeroPage, _)) if p.succ == q =>
|
||||
@ -1487,15 +1548,30 @@ object BuiltIns {
|
||||
reg.toAddress
|
||||
}
|
||||
val r = MosExpressionCompiler.compileToAX(ctx, rhs)
|
||||
val s = footer(ptr, reg, lhs.offset, r)
|
||||
val s = wordFooter(ptr, reg, lhs.offset, r)
|
||||
if (MosExpressionCompiler.changesZpreg(r, 0) || MosExpressionCompiler.changesZpreg(r, 1)) {
|
||||
r ++ MosExpressionCompiler.preserveRegisterIfNeeded(ctx, MosRegister.AX, l) ++ s
|
||||
} else {
|
||||
l ++ r ++ s
|
||||
}
|
||||
} else {
|
||||
ctx.log.error("Too complex left-hand-side expression", lhs.position)
|
||||
MosExpressionCompiler.compileToAX(ctx, lhs) ++ MosExpressionCompiler.compileToAX(ctx, rhs)
|
||||
val result = ListBuffer[AssemblyLine]()
|
||||
result ++= MosExpressionCompiler.compileToZReg(ctx, lhs.inner #+# lhs.offset)
|
||||
eitherDoWholeThingOrMergeByte match {
|
||||
case Left(wholeThing) => result ++= wholeThing(targetType.size)
|
||||
case Right(mergeByte) =>
|
||||
val loads = getLoadForEachByte(ctx, rhs, targetType.size).map(x => MosExpressionCompiler.preserve2ZpregIfNeededDestroyingAAndX(ctx, 0, 1, cmpTo(LDA, x)))
|
||||
if (fromMsb) {
|
||||
for(i <- targetType.size.-(1).to(0, -1)) {
|
||||
result ++= mergeByte(i, loads(i), i == targetType.size - 1)
|
||||
}
|
||||
} else {
|
||||
for(i <- 0 until targetType.size) {
|
||||
result ++= mergeByte(i, loads(i), i == targetType.size - 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
result.toList
|
||||
}
|
||||
}
|
||||
|
||||
@ -1510,7 +1586,7 @@ object BuiltIns {
|
||||
ctx.log.error("Too complex left hand side. Consider increasing the size of the zeropage register.", lhs.position)
|
||||
return compileInPlaceWordOrLongAddition(ctx, lhs, addend, subtract = false, decimal = false)
|
||||
}
|
||||
return if (subtract) handleWordOrLongInPlaceModificationViaDeref(ctx, dx, addend)((ptr, reg, offset, _) => wrapInSedCldIfNeeded(decimal, List(
|
||||
return if (subtract) handleWordOrLongInPlaceModificationViaDeref(ctx, dx, addend, fromMsb = false)((ptr, reg, offset, _) => wrapInSedCldIfNeeded(decimal, List(
|
||||
AssemblyLine.immediate(LDY, offset),
|
||||
AssemblyLine.implied(SEC),
|
||||
AssemblyLine.zeropage(STA, reg, 2),
|
||||
@ -1522,7 +1598,30 @@ object BuiltIns {
|
||||
AssemblyLine.indexedY(LDA, ptr),
|
||||
AssemblyLine.zeropage(SBC, reg, 2),
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
))) else handleWordOrLongInPlaceModificationViaDeref(ctx, dx, addend)((ptr, _, offset, _) => wrapInSedCldIfNeeded(decimal, List(
|
||||
)))(Right({(iy, r, last) =>
|
||||
val reg = ctx.env.get[VariableInMemory]("__reg")
|
||||
val result = ListBuffer[AssemblyLine]()
|
||||
if (iy != 0) {
|
||||
result ++= MosExpressionCompiler.preserveCarryIfNeeded(ctx, r)
|
||||
} else {
|
||||
result ++= r
|
||||
}
|
||||
result += AssemblyLine.immediate(LDY, iy)
|
||||
result += AssemblyLine.zeropage(STA, reg, 2)
|
||||
result += AssemblyLine.indexedY(LDA, reg)
|
||||
if (iy == 0) {
|
||||
result += AssemblyLine.implied(SEC)
|
||||
}
|
||||
if (decimal) {
|
||||
result += AssemblyLine.implied(SED)
|
||||
}
|
||||
result += AssemblyLine.zeropage(SBC, reg, 2)
|
||||
if (decimal) {
|
||||
result += AssemblyLine.implied(CLD)
|
||||
}
|
||||
result += AssemblyLine.indexedY(STA, reg)
|
||||
result.toList
|
||||
})) else handleWordOrLongInPlaceModificationViaDeref(ctx, dx, addend, fromMsb = false)((ptr, _, offset, _) => wrapInSedCldIfNeeded(decimal, List(
|
||||
AssemblyLine.immediate(LDY, offset),
|
||||
AssemblyLine.implied(CLC),
|
||||
AssemblyLine.indexedY(ADC, ptr),
|
||||
@ -1531,7 +1630,28 @@ object BuiltIns {
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine.indexedY(ADC, ptr),
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
)))
|
||||
)))(Right({(iy, r, last) =>
|
||||
val reg = ctx.env.get[VariableInMemory]("__reg")
|
||||
val result = ListBuffer[AssemblyLine]()
|
||||
if (iy != 0) {
|
||||
result ++= MosExpressionCompiler.preserveCarryIfNeeded(ctx, r)
|
||||
} else {
|
||||
result ++= r
|
||||
}
|
||||
result += AssemblyLine.immediate(LDY, iy)
|
||||
if (iy == 0) {
|
||||
result += AssemblyLine.implied(CLC)
|
||||
}
|
||||
if (decimal) {
|
||||
result += AssemblyLine.implied(SED)
|
||||
}
|
||||
result += AssemblyLine.indexedY(ADC, reg)
|
||||
if (decimal) {
|
||||
result += AssemblyLine.implied(CLD)
|
||||
}
|
||||
result += AssemblyLine.indexedY(STA, reg)
|
||||
result.toList
|
||||
}))
|
||||
case _ =>
|
||||
}
|
||||
val env = ctx.env
|
||||
@ -1881,7 +2001,7 @@ object BuiltIns {
|
||||
|
||||
def compileInPlaceWordOrLongBitOp(ctx: CompilationContext, lhs: LhsExpression, param: Expression, operation: Opcode.Value): List[AssemblyLine] = {
|
||||
lhs match {
|
||||
case dx: DerefExpression => return handleWordOrLongInPlaceModificationViaDeref(ctx, dx, param)((ptr, _, offset, _) => List(
|
||||
case dx: DerefExpression => return handleWordOrLongInPlaceModificationViaDeref(ctx, dx, param, fromMsb = false)((ptr, _, offset, _) => List(
|
||||
AssemblyLine.immediate(LDY, offset),
|
||||
AssemblyLine.indexedY(operation, ptr),
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
@ -1889,7 +2009,13 @@ object BuiltIns {
|
||||
AssemblyLine.implied(INY),
|
||||
AssemblyLine.indexedY(operation, ptr),
|
||||
AssemblyLine.indexedY(STA, ptr),
|
||||
))
|
||||
))(Right({ (iy, r, last) =>
|
||||
val reg = ctx.env.get[VariableInMemory]("__reg")
|
||||
r ++ List(
|
||||
AssemblyLine.immediate(LDY, iy),
|
||||
AssemblyLine.indexedY(operation, reg),
|
||||
AssemblyLine.indexedY(STA, reg))
|
||||
}))
|
||||
case _ =>
|
||||
}
|
||||
val env = ctx.env
|
||||
|
@ -104,6 +104,25 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
||||
} else code
|
||||
}
|
||||
|
||||
def preserve2ZpregIfNeededDestroyingAAndX(ctx: CompilationContext, Offset1: Int, Offset2: Int, code: List[AssemblyLine]): List[AssemblyLine] = {
|
||||
if (changesZpreg(code, Offset1) || changesZpreg(code, Offset2)) {
|
||||
val reg = ctx.env.get[VariableInMemory]("__reg")
|
||||
List(
|
||||
AssemblyLine.zeropage(LDA, reg, Offset1),
|
||||
AssemblyLine.implied(PHA),
|
||||
AssemblyLine.zeropage(LDA, reg, Offset2),
|
||||
AssemblyLine.implied(PHA)) ++
|
||||
code ++
|
||||
List(
|
||||
AssemblyLine.implied(TAX),
|
||||
AssemblyLine.implied(PLA),
|
||||
AssemblyLine.zeropage(STA, reg, Offset2),
|
||||
AssemblyLine.implied(PLA),
|
||||
AssemblyLine.zeropage(STA, reg, Offset1),
|
||||
AssemblyLine.implied(TXA))
|
||||
} else code
|
||||
}
|
||||
|
||||
def changesZpreg(code: List[AssemblyLine], Offset: Int): Boolean = {
|
||||
code.exists {
|
||||
case AssemblyLine0(op,
|
||||
@ -1500,11 +1519,8 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
||||
}
|
||||
case i if i > 2 =>
|
||||
l match {
|
||||
case v: VariableExpression =>
|
||||
case v: LhsExpression =>
|
||||
BuiltIns.compileInPlaceWordOrLongAddition(ctx, v, r, subtract = false, decimal = false)
|
||||
case _ =>
|
||||
ctx.log.error("Cannot modify large object accessed via such complex expression", l.position)
|
||||
compile(ctx, r, None, BranchSpec.None)
|
||||
}
|
||||
}
|
||||
case "-=" =>
|
||||
@ -1519,11 +1535,8 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
||||
}
|
||||
case i if i > 2 =>
|
||||
l match {
|
||||
case v: VariableExpression =>
|
||||
case v: LhsExpression =>
|
||||
BuiltIns.compileInPlaceWordOrLongAddition(ctx, v, r, subtract = true, decimal = false)
|
||||
case _ =>
|
||||
ctx.log.error("Cannot modify large object accessed via such complex expression", l.position)
|
||||
compile(ctx, r, None, BranchSpec.None)
|
||||
}
|
||||
}
|
||||
case "+'=" =>
|
||||
@ -1538,11 +1551,8 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
||||
}
|
||||
case i if i > 2 =>
|
||||
l match {
|
||||
case v: VariableExpression =>
|
||||
case v: LhsExpression =>
|
||||
BuiltIns.compileInPlaceWordOrLongAddition(ctx, v, r, subtract = false, decimal = true)
|
||||
case _ =>
|
||||
ctx.log.error("Cannot modify large object accessed via such complex expression", l.position)
|
||||
compile(ctx, r, None, BranchSpec.None)
|
||||
}
|
||||
}
|
||||
case "-'=" =>
|
||||
@ -1557,11 +1567,8 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
|
||||
}
|
||||
case i if i > 2 =>
|
||||
l match {
|
||||
case v: VariableExpression =>
|
||||
case v: LhsExpression =>
|
||||
BuiltIns.compileInPlaceWordOrLongAddition(ctx, v, r, subtract = true, decimal = true)
|
||||
case _ =>
|
||||
ctx.log.error("Cannot modify large object accessed via such complex expression", l.position)
|
||||
compile(ctx, r, None, BranchSpec.None)
|
||||
}
|
||||
}
|
||||
case "<<=" =>
|
||||
|
@ -456,13 +456,20 @@ class ArraySuite extends FunSuite with Matchers with AppendedClues {
|
||||
}
|
||||
|
||||
test("Invalid array things that will become valid in the future") {
|
||||
ShouldNotCompile(
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Intel8080, Cpu.Z80 , Cpu.Sharp, Cpu.Motorola6809)(
|
||||
"""
|
||||
| array(int32) a[7] @$c000
|
||||
| void main () {
|
||||
| int32 tmp
|
||||
| tmp = f()
|
||||
| a[0] = tmp
|
||||
| a[0] += 2
|
||||
| a[0] <<= 2
|
||||
| }
|
||||
""".stripMargin)
|
||||
| noinline int32 f() = 5
|
||||
""".stripMargin) { m =>
|
||||
m.readLong(0xc000) should equal(28)
|
||||
}
|
||||
}
|
||||
|
||||
test("Various large assignments involving arrays") {
|
||||
|
Loading…
x
Reference in New Issue
Block a user