diff --git a/CHANGELOG.md b/CHANGELOG.md index 560350be..6f16dbd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,8 @@ * Minor improvements to inline assembly. +* Improvements to constant evaluation. + * Optimization improvements. ## 0.3.14 diff --git a/src/main/scala/millfork/compiler/mos/MosExpressionCompiler.scala b/src/main/scala/millfork/compiler/mos/MosExpressionCompiler.scala index 8bff6a64..ffe9620a 100644 --- a/src/main/scala/millfork/compiler/mos/MosExpressionCompiler.scala +++ b/src/main/scala/millfork/compiler/mos/MosExpressionCompiler.scala @@ -14,7 +14,8 @@ import millfork.output.NoAlignment */ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] { - def compileConstant(ctx: CompilationContext, expr: Constant, exprType: Type, target: Variable): List[AssemblyLine] = { + def compileConstant(ctx: CompilationContext, expr0: Constant, exprType: Type, target: Variable): List[AssemblyLine] = { + val expr = expr0.fitInto(exprType, target.typ) target match { case RegisterVariable(MosRegister.A, _) => List(AssemblyLine(LDA, Immediate, expr)) case RegisterVariable(MosRegister.AW, _) => diff --git a/src/main/scala/millfork/env/Constant.scala b/src/main/scala/millfork/env/Constant.scala index 6fc09c30..11a832df 100644 --- a/src/main/scala/millfork/env/Constant.scala +++ b/src/main/scala/millfork/env/Constant.scala @@ -1,7 +1,7 @@ package millfork.env import millfork.DecimalUtils._ -import millfork.node.ResolvedFieldDesc +import millfork.node.{ResolvedFieldDesc, SumExpression} import millfork.output.DivisibleAlignment object Constant { @@ -79,17 +79,19 @@ sealed trait Constant { def subword(index: Int): Constant = { if (requiredSize <= index) Constant.Zero + else if (requiredSize == 2 && !this.isInstanceOf[StructureConstant]) this else { // TODO: check if ok - CompoundConstant(MathOperator.Or, CompoundConstant(MathOperator.Shl, subbyte(index + 1), NumericConstant(8, 1)), subbyte(index)).quickSimplify + CompoundConstant(MathOperator.Or, CompoundConstant(MathOperator.Shl, subbyte(index + 1), NumericConstant(8, 2)), subbyte(index)).quickSimplify } } def subwordReversed(index: Int): Constant = { if (requiredSize <= index) Constant.Zero + else if (requiredSize == 2 && !this.isInstanceOf[StructureConstant]) this else { // TODO: check if ok - CompoundConstant(MathOperator.Or, CompoundConstant(MathOperator.Shl, subbyte(index), NumericConstant(8, 1)), subbyte(index + 1)).quickSimplify + CompoundConstant(MathOperator.Or, CompoundConstant(MathOperator.Shl, subbyte(index), NumericConstant(8, 2)), subbyte(index + 1)).quickSimplify } } @@ -126,6 +128,10 @@ sealed trait Constant { case NumericConstant(value, 1) => if (typ.isSigned) NumericConstant(value.toByte, 1) else NumericConstant(value & 0xff, 1) + case CompoundConstant(MathOperator.Minus, NumericConstant(l, _), NumericConstant(r, _)) => + val value = l - r + if (typ.isSigned) NumericConstant(value.toByte, 1) + else NumericConstant(value & 0xff, 1) case b => b } case 2 => @@ -133,12 +139,26 @@ sealed trait Constant { case NumericConstant(value, _) => if (typ.isSigned) NumericConstant(value.toShort, 2) else NumericConstant(value & 0xffff, 2) + case CompoundConstant(MathOperator.Minus, NumericConstant(l, _), NumericConstant(r, _)) => + val value = l - r + if (typ.isSigned) NumericConstant(value.toShort, 2) + else NumericConstant(value & 0xffff, 2) case w => w } case _ => this } } + def fitInto(sourceType: Type, targetType: Type): Constant = { + val fit0 = fitInto(sourceType) + if (sourceType.size >= targetType.size) fit0 else { + fit0 match { + case NumericConstant(n, _) => NumericConstant(n, targetType.size) + case _ => fit0 + } + } + } + final def succ: Constant = (this + 1).quickSimplify def rootThingName: String diff --git a/src/main/scala/millfork/output/AbstractAssembler.scala b/src/main/scala/millfork/output/AbstractAssembler.scala index a13c36f8..2b09381d 100644 --- a/src/main/scala/millfork/output/AbstractAssembler.scala +++ b/src/main/scala/millfork/output/AbstractAssembler.scala @@ -140,11 +140,16 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program else ??? case SubbyteConstant(cc, i) => deepConstResolve(cc).>>>(i * 8).&(0xff) case s: StructureConstant => - s.typ.size match { - case 0 => 0 - case 1 => deepConstResolve(s.subbyte(0)) - case 2 => if (platform.isBigEndian) deepConstResolve(s.subwordReversed(0)) else deepConstResolve(s.subword(0)) // TODO: endianness? - case _ => ??? + try { + s.typ.size match { + case 0 => 0 + case 1 => deepConstResolve(s.subbyte(0)) + case 2 => if (platform.isBigEndian) deepConstResolve(s.subwordReversed(0)) else deepConstResolve(s.subword(0)) // TODO: endianness? + case _ => ??? + } + } catch { + case _: StackOverflowError => + log.fatal("Stack overflow " + c) } case CompoundConstant(operator, lc, rc) => val l = deepConstResolve(lc) diff --git a/src/test/scala/millfork/test/StructSuite.scala b/src/test/scala/millfork/test/StructSuite.scala index f9dce740..083834bb 100644 --- a/src/test/scala/millfork/test/StructSuite.scala +++ b/src/test/scala/millfork/test/StructSuite.scala @@ -92,7 +92,7 @@ class StructSuite extends FunSuite with Matchers { } test("Optimize struct modifications") { - EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8086)(""" + EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8086, Cpu.Motorola6809)(""" | struct point { byte x, byte y } | enum direction { none, right } | direction last_direction @$c400 @@ -116,7 +116,7 @@ class StructSuite extends FunSuite with Matchers { } test("Struct literals") { - EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8086)(""" + EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8086, Cpu.Motorola6809)(""" | struct point { byte x, byte y } | const point origin = point(1,2) | noinline point move_right(point p) {