1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-12-23 23:30:22 +00:00

Various fixes

This commit is contained in:
Karol Stasiak 2020-07-18 01:16:31 +02:00
parent a2c49a1f89
commit d0bf683657
8 changed files with 166 additions and 55 deletions

View File

@ -1002,7 +1002,7 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
case DE => changesRegister(D) || changesRegister(E)
case IX => changesRegister(IXH) || changesRegister(IXL)
case IY => changesRegister(IYH) || changesRegister(IYL)
case AF => ???
case AF => true
case IMM_8 | IMM_16 => false
case MEM_ABS_8 | MEM_ABS_16 | MEM_DE | MEM_HL | MEM_BC | MEM_IX_D | MEM_IY_D | SP => ???
case _ =>

View File

@ -496,6 +496,9 @@ object AlwaysGoodI80Optimizations {
shallowerStack(code.tail.init)
}
}),
//37
(Elidable & HasOpcode(PUSH) & HasRegisterParam(AF)) ~
(Elidable & HasOpcode(POP) & HasRegisterParam(AF)) ~~> (_.tail.init),
)
private def shallowerStack(lines: List[ZLine]): List[ZLine] = lines match {

View File

@ -974,6 +974,11 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
case sot: StackOffsetThing =>
List(calculateStackAddressToD(ctx, sot.offset), List(MLine.tfr(M6809Register.A, M6809Register.B)))
}
case e:DerefExpression =>
List.tabulate(targetSize)(i =>
if (i == 0) compileAddressToX(ctx, e) :+ MLine.indexedX(LDB, 0)
else List(MLine.indexedX(LDB, i))
)
case e:FunctionCallExpression =>
ctx.env.maybeGet[NormalFunction](e.functionName) match {
case Some(function) =>

View File

@ -446,7 +446,7 @@ object BuiltIns {
AssemblyLine.implied(TAX),
AssemblyLine.label(labelRepeat)) ++ singleShift ++ List(
AssemblyLine.implied(DEX),
AssemblyLine.relative(BEQ, labelRepeat))
AssemblyLine.relative(BNE, labelRepeat))
case _ =>
val labelSkip = ctx.nextLabel("ss")
val labelRepeat = ctx.nextLabel("sr")
@ -455,7 +455,7 @@ object BuiltIns {
AssemblyLine.relative(BEQ, labelSkip),
AssemblyLine.label(labelRepeat)) ++ singleShift ++ List(
AssemblyLine.implied(DEX),
AssemblyLine.relative(BEQ, labelRepeat),
AssemblyLine.relative(BNE, labelRepeat),
AssemblyLine.label(labelSkip))
}
}))

View File

@ -113,17 +113,17 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
def compileToHL(ctx: CompilationContext, expression: Expression): List[ZLine] = compile(ctx, expression, ZExpressionTarget.HL)
def compileDerefPointer(ctx: CompilationContext, expression: DerefExpression): List[ZLine] = {
def compileDerefPointer(ctx: CompilationContext, expression: DerefExpression, extraOffset: Int = 0): List[ZLine] = {
import ZRegister._
val innerPart = compileToHL(ctx, expression.inner)
innerPart match {
case List(ZLine0(LD_16, TwoRegisters(HL, IMM_16), c)) =>
List(ZLine(LD_16, TwoRegisters(HL, IMM_16), c + expression.offset))
List(ZLine(LD_16, TwoRegisters(HL, IMM_16), c + expression.offset + extraOffset))
case _ =>
innerPart ++ (expression.offset match {
innerPart ++ ((expression.offset + extraOffset) match {
case 0 => Nil
case i if i < 5 => List.fill(i)(ZLine.register(INC_16, ZRegister.HL)) // TODO: a better threshold
case _ => List(ZLine.ldImm8(ZRegister.C, expression.offset), ZLine.ldImm8(ZRegister.B, 0), ZLine.registers(ADD_16, ZRegister.HL, ZRegister.BC))
case i if i > 0 && i < 5 => List.fill(i)(ZLine.register(INC_16, ZRegister.HL)) // TODO: a better threshold
case n => List(ZLine.ldImm8(ZRegister.C, n & 0xff), ZLine.ldImm8(ZRegister.B, n >> 8), ZLine.registers(ADD_16, ZRegister.HL, ZRegister.BC))
})
}
}
@ -1355,12 +1355,12 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
}
}
def calculateAddressToAppropriatePointer(ctx: CompilationContext, expr: LhsExpression, forWriting: Boolean): Option[(LocalVariableAddressOperand, List[ZLine])] = {
def calculateAddressToAppropriatePointer(ctx: CompilationContext, expr: LhsExpression, forWriting: Boolean, extraOffset: Int = 0): Option[(LocalVariableAddressOperand, List[ZLine])] = {
val env = ctx.env
expr match {
case VariableExpression(name) =>
env.get[Variable](name) match {
case v:VariableInMemory => Some(LocalVariableAddressViaHL -> List(ZLine.ldImm16(ZRegister.HL, v.toAddress)))
case v:VariableInMemory => Some(LocalVariableAddressViaHL -> List(ZLine.ldImm16(ZRegister.HL, v.toAddress + extraOffset)))
case v:StackVariable =>
if (ctx.options.flag(CompilationFlag.UseIxForStack)){
Some(LocalVariableAddressViaIX(v.baseOffset) -> Nil)
@ -1370,8 +1370,8 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
Some(LocalVariableAddressViaHL -> calculateStackAddressToHL(ctx, v))
}
}
case i:IndexedExpression => Some(LocalVariableAddressViaHL -> calculateAddressToHL(ctx, i, forWriting))
case i:DerefExpression => Some(LocalVariableAddressViaHL -> compileDerefPointer(ctx, i))
case i:IndexedExpression => Some(LocalVariableAddressViaHL -> calculateAddressToHL(ctx, i, forWriting, extraOffset))
case i:DerefExpression => Some(LocalVariableAddressViaHL -> compileDerefPointer(ctx, i, extraOffset))
case _:SeparateBytesExpression => None
case _ => ???
}
@ -1391,11 +1391,11 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
}
}
def calculateAddressToHL(ctx: CompilationContext, i: IndexedExpression, forWriting: Boolean): List[ZLine] = {
def calculateAddressToHL(ctx: CompilationContext, i: IndexedExpression, forWriting: Boolean, extraOffset: Int = 0): List[ZLine] = {
val env = ctx.env
val pointy = env.getPointy(i.name)
AbstractExpressionCompiler.checkIndexType(ctx, pointy, i.index)
val elementSize = pointy.elementType.size
val elementSize = pointy.elementType.alignedSize
val logElemSize = elementSize match {
case 1 => 0
case 2 => 1
@ -1409,9 +1409,9 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
ctx.log.error("Writing to a constant array", i.position)
}
env.evalVariableAndConstantSubParts(i.index) match {
case (None, offset) => List(ZLine.ldImm16(ZRegister.HL, (baseAddr + offset * elementSize).quickSimplify))
case (None, offset) => List(ZLine.ldImm16(ZRegister.HL, (baseAddr + extraOffset + offset * elementSize).quickSimplify))
case (Some(index), offset) =>
val constantPart = (baseAddr + offset * elementSize).quickSimplify
val constantPart = (baseAddr + extraOffset + offset * elementSize).quickSimplify
if (getExpressionType(ctx, i.index).size == 1 && sizeInBytes.exists(_ < 256) && alignment == WithinPageAlignment) {
compileToA(ctx, i.index) ++ List.fill(logElemSize)(ZLine.register(ADD, ZRegister.A)) ++ List(
ZLine.imm8(ADD, constantPart.loByte),
@ -1426,7 +1426,7 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
}
case VariablePointy(varAddr, _, _, _) =>
env.eval(i.index) match {
case Some(NumericConstant(0, _)) =>
case Some(NumericConstant(0, _)) if extraOffset == 0 =>
if (ctx.options.flag(CompilationFlag.EmitIntel8080Opcodes)) {
List(ZLine.ldAbs16(ZRegister.HL, varAddr))
} else {
@ -1439,12 +1439,12 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
}
case _ =>
if (ctx.options.flag(CompilationFlag.EmitIntel8080Opcodes)) {
compileToBC(ctx, i.index) ++
compileToBC(ctx, i.index #*# elementSize #+# extraOffset) ++
List(ZLine.ldAbs16(ZRegister.HL, varAddr)) ++
List.fill(elementSize)(ZLine.registers(ADD_16, ZRegister.HL, ZRegister.BC))
} else {
// TODO: is this reasonable?
compileToBC(ctx, i.index) ++
compileToBC(ctx, i.index #*# elementSize #+# extraOffset) ++
List(
ZLine.ldAbs8(ZRegister.A, varAddr),
ZLine.ld8(ZRegister.L, ZRegister.A),
@ -1455,7 +1455,7 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
}
case _: StackVariablePointy =>
compileToHL(ctx, VariableExpression(i.name).pos(i.position)) ++
stashHLIfChanged(ctx, compileToBC(ctx, i.index)) ++
stashHLIfChanged(ctx, compileToBC(ctx, i.index #*# elementSize #+# extraOffset)) ++
List.fill(elementSize)(ZLine.registers(ADD_16, ZRegister.HL, ZRegister.BC))
}
}

View File

@ -1,13 +1,14 @@
package millfork.compiler.z80
import millfork.CompilationFlag
import millfork.assembly.z80.{NoRegisters, ZLine, ZOpcode}
import millfork.assembly.z80.{LocalVariableAddressViaHL, LocalVariableAddressViaIX, LocalVariableAddressViaIY, NoRegisters, ZLine, ZOpcode}
import millfork.compiler.CompilationContext
import millfork.env.NumericConstant
import millfork.error.ConsoleLogger
import millfork.node._
import scala.collection.GenTraversableOnce
import scala.collection.mutable.ListBuffer
/**
* @author Karol Stasiak
@ -244,44 +245,117 @@ object Z80Shifting {
}
def compileLongShiftInPlace(ctx: CompilationContext, lhs: LhsExpression, rhs: Expression, size: Int, left: Boolean): List[ZLine] = {
val extended = ctx.options.flag(CompilationFlag.EmitExtended80Opcodes)
val store = Z80ExpressionCompiler.compileByteStores(ctx, lhs, size, includeStep = false)
val loadLeft = Z80ExpressionCompiler.compileByteReads(ctx, lhs, size, ZExpressionTarget.HL)
val shiftOne = if (left) {
loadLeft.zip(store).zipWithIndex.flatMap {
case ((ld, st), ix) =>
import ZOpcode._
import ZRegister._
val shiftByte =
if (ix == 0) List(ZLine.register(ADD, A))
else List(ZLine.implied(RLA))
ld ++ shiftByte ++ st
val extended = ctx.options.flag(CompilationFlag.EmitExtended80Opcodes)
val intel8080 = ctx.options.flag(CompilationFlag.EmitIntel8080Opcodes)
val Some((loadRegisterOperand, loadSequence)) =
Z80ExpressionCompiler.calculateAddressToAppropriatePointer(ctx, lhs, forWriting = true, extraOffset = if (left) 0 else size-1)
val result = ListBuffer[ZLine]()
result ++= loadSequence
def appendShift(preserveHL: Boolean): Unit = {
if (loadRegisterOperand == LocalVariableAddressViaHL && preserveHL) {
result += ZLine.ld8(D, H)
result += ZLine.ld8(E, L)
}
if (left) {
for (ix <- 0 until size) {
val shiftedOperand = loadRegisterOperand match {
case LocalVariableAddressViaHL =>
LocalVariableAddressViaHL
case LocalVariableAddressViaIX(offset) =>
LocalVariableAddressViaIX(offset + ix)
case LocalVariableAddressViaIY(offset) =>
LocalVariableAddressViaIY(offset + ix)
}
if (ix == 0) {
if (extended) {
result += ZLine.register(SLA, shiftedOperand)
} else {
result += ZLine.ld8(A, shiftedOperand)
result += ZLine.register(ADD, A)
result += ZLine.ld8(shiftedOperand, A)
}
} else {
loadLeft.reverse.zip(store.reverse).zipWithIndex.flatMap {
case ((ld, st), ix) =>
import ZOpcode._
import ZRegister._
val shiftByte = if (ix == 0) {
if (extended) List(ZLine.register(SRL, A))
else List(ZLine.register(OR, A), ZLine.implied(RRA))
} else List(ZLine.implied(RRA))
ld ++ shiftByte ++ st
if (extended) {
result += ZLine.register(RL, shiftedOperand)
} else {
result += ZLine.ld8(A, shiftedOperand)
result += ZLine.implied(RLA)
result += ZLine.ld8(shiftedOperand, A)
}
}
if (loadRegisterOperand == LocalVariableAddressViaHL && ix != size - 1) {
result += ZLine.register(INC_16, HL)
}
}
} else {
for (ix <- (size - 1).to(0, -1)) {
val shiftedOperand = loadRegisterOperand match {
case LocalVariableAddressViaHL =>
LocalVariableAddressViaHL
case LocalVariableAddressViaIX(offset) =>
LocalVariableAddressViaIX(offset + ix)
case LocalVariableAddressViaIY(offset) =>
LocalVariableAddressViaIY(offset + ix)
}
if (ix == size - 1) {
if (extended) {
result += ZLine.register(SRL, shiftedOperand)
} else {
result += ZLine.ld8(A, shiftedOperand)
result += ZLine.register(OR, A)
result += ZLine.implied(RRA)
result += ZLine.ld8(shiftedOperand, A)
}
} else {
if (extended) {
result += ZLine.register(RR, shiftedOperand)
} else {
result += ZLine.ld8(A, shiftedOperand)
result += ZLine.implied(RRA)
result += ZLine.ld8(shiftedOperand, A)
}
}
if (loadRegisterOperand == LocalVariableAddressViaHL && ix != 0) {
result += ZLine.register(DEC_16, HL)
}
}
}
if (loadRegisterOperand == LocalVariableAddressViaHL && preserveHL) {
if (intel8080) {
result += ZLine.implied(EX_DE_HL)
} else {
result += ZLine.ld8(H, D)
result += ZLine.ld8(L, E)
}
}
}
ctx.env.eval(rhs) match {
case Some(NumericConstant(0, _)) => Nil
case Some(NumericConstant(0, _)) => ()
case Some(NumericConstant(n, _)) if n < 0 =>
ctx.log.error("Negative shift amount", rhs.position) // TODO
Nil
case Some(NumericConstant(n, _)) =>
List.fill(n.toInt)(shiftOne).flatten
()
case Some(NumericConstant(n, _)) if n < 3 => // TODO: more exact math on performance and size
for(i <- 0 until n.toInt) {
appendShift(i != n-1)
}
case _ =>
val calcCount = calculateIterationCountPlus1(ctx, rhs)
if (loadRegisterOperand == LocalVariableAddressViaHL) {
result ++= Z80ExpressionCompiler.stashHLIfChanged(ctx, calcCount)
} else {
result ++= calcCount
}
val labelL = ctx.nextLabel("sh")
val labelS = ctx.nextLabel("sh")
calcCount ++ List(ZLine.jumpR(ctx, labelS), ZLine.label(labelL)) ++ shiftOne ++ List(ZLine.label(labelS)) ++ ZLine.djnz(ctx, labelL)
result += ZLine.jumpR(ctx, labelS)
result += ZLine.label(labelL)
appendShift(true)
result += ZLine.label(labelS)
result ++= ZLine.djnz(ctx, labelL)
}
result.toList
}
}

View File

@ -9,6 +9,7 @@ import millfork.env._
import millfork.error.ConsoleLogger
import scala.collection.mutable
import scala.collection.mutable.ListBuffer
/**
* @author Karol Stasiak
@ -548,8 +549,35 @@ object ZBuiltIns {
}
}
} else {
ctx.log.error("Too complex left-hand-side expression", lhs.position)
return Z80ExpressionCompiler.compile(ctx, lhs, ZExpressionTarget.NOTHING) ++ Z80ExpressionCompiler.compile(ctx, rhs, ZExpressionTarget.NOTHING)
val target = Z80ExpressionCompiler.compileToHL(ctx, inner #+# offset)
val sourceBytes = Z80ExpressionCompiler.compileByteReads(ctx, rhs, size, ZExpressionTarget.BC).map(l => Z80ExpressionCompiler.stashHLIfChanged(ctx, l))
val result = ListBuffer[ZLine]()
result ++= target
if (opcodeFirst == SUB && decimal) {
???
} else if (opcodeFirst == SUB && !decimal) {
for (i <- 0 until size) {
if (i != 0) result += ZLine.register(PUSH, ZRegister.AF)
result ++= sourceBytes(i)
result += ZLine.ld8(ZRegister.E, ZRegister.A)
if (i != 0) result += ZLine.register(POP, ZRegister.AF)
result += ZLine.ld8(ZRegister.A, ZRegister.MEM_HL)
result += ZLine.register(if (i == 0) opcodeFirst else opcodeLater, ZRegister.E)
result += ZLine.ld8(ZRegister.MEM_HL, ZRegister.A)
if (i != size - 1) result += ZLine.register(INC_16, ZRegister.HL)
}
} else {
for (i <- 0 until size) {
result ++= sourceBytes(i)
result += ZLine.register(if (i==0) opcodeFirst else opcodeLater, ZRegister.MEM_HL)
if (decimal) result += ZLine.implied(DAA)
result += ZLine.ld8(ZRegister.MEM_HL, ZRegister.A)
if (i != size -1) result += ZLine.register(INC_16, ZRegister.HL)
}
}
return result.toList
// ctx.log.error("Too complex left-hand-side expression", lhs.position)
// return Z80ExpressionCompiler.compile(ctx, lhs, ZExpressionTarget.NOTHING) ++ Z80ExpressionCompiler.compile(ctx, rhs, ZExpressionTarget.NOTHING)
}
case _ =>
}

View File

@ -465,29 +465,30 @@ class ArraySuite extends FunSuite with Matchers with AppendedClues {
| a[0] = tmp
| a[0] += 2
| a[0] <<= 2
| a[0] -= 7
| }
| noinline int32 f() = 5
""".stripMargin) { m =>
m.readLong(0xc000) should equal(28)
m.readLong(0xc000) should equal(21)
}
}
test("Various large assignments involving arrays") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Intel8080, Cpu.Z80)(
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Intel8080, Cpu.Z80, Cpu.Motorola6809)(
"""
| array(int32) a[7] @$c000
| void main () {
| a[0] = 2
| }
""".stripMargin) { m => }
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Intel8080, Cpu.Z80)(
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Intel8080, Cpu.Z80, Cpu.Motorola6809)(
"""
| array(int32) a[7] @$c000
| int32 main () {
| return a[4]
| }
""".stripMargin) { m => }
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Intel8080, Cpu.Z80)(
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Intel8080, Cpu.Z80, Cpu.Motorola6809)(
"""
| array(int32) a[7] @$c000
| noinline void f(byte i) {