mirror of
https://github.com/KarolS/millfork.git
synced 2025-07-16 06:24:08 +00:00
Compilation fixes
Separated bytes compilation fixes (although only preliminary, it's still a pretty broken feature) Better compilation of complex expressions (don't spill to the stack so often)
This commit is contained in:
@@ -143,19 +143,7 @@ object BuiltIns {
|
|||||||
val env = ctx.env
|
val env = ctx.env
|
||||||
val b = env.get[Type]("byte")
|
val b = env.get[Type]("byte")
|
||||||
val sortedParams = params.sortBy { case (subtract, expr) =>
|
val sortedParams = params.sortBy { case (subtract, expr) =>
|
||||||
val constPart = env.eval(expr) match {
|
simplicity(env, expr) + (if (subtract) "X" else "P")
|
||||||
case Some(NumericConstant(_, _)) => "Z"
|
|
||||||
case Some(_) => "Y"
|
|
||||||
case None => expr match {
|
|
||||||
case VariableExpression(_) => "V"
|
|
||||||
case IndexedExpression(_, LiteralExpression(_, _)) => "K"
|
|
||||||
case IndexedExpression(_, VariableExpression(_)) => "J"
|
|
||||||
case IndexedExpression(_, _) => "I"
|
|
||||||
case _ => "A"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val subtractPart = if (subtract) "X" else "P"
|
|
||||||
constPart + subtractPart
|
|
||||||
}
|
}
|
||||||
// TODO: merge constants
|
// TODO: merge constants
|
||||||
val normalizedParams = sortedParams
|
val normalizedParams = sortedParams
|
||||||
@@ -179,6 +167,21 @@ object BuiltIns {
|
|||||||
firstParamCompiled ++ firstParamSignCompiled ++ remainingParamsCompiled
|
firstParamCompiled ++ firstParamSignCompiled ++ remainingParamsCompiled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def simplicity(env: Environment, expr: Expression): Char = {
|
||||||
|
val constPart = env.eval(expr) match {
|
||||||
|
case Some(NumericConstant(_, _)) => 'Z'
|
||||||
|
case Some(_) => 'Y'
|
||||||
|
case None => expr match {
|
||||||
|
case VariableExpression(_) => 'V'
|
||||||
|
case IndexedExpression(_, LiteralExpression(_, _)) => 'K'
|
||||||
|
case IndexedExpression(_, VariableExpression(_)) => 'J'
|
||||||
|
case IndexedExpression(_, _) => 'I'
|
||||||
|
case _ => 'A'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
constPart
|
||||||
|
}
|
||||||
|
|
||||||
def compileBitOps(opcode: Opcode.Value, ctx: CompilationContext, params: List[Expression]): List[AssemblyLine] = {
|
def compileBitOps(opcode: Opcode.Value, ctx: CompilationContext, params: List[Expression]): List[AssemblyLine] = {
|
||||||
val b = ctx.env.get[Type]("byte")
|
val b = ctx.env.get[Type]("byte")
|
||||||
|
|
||||||
@@ -264,15 +267,7 @@ object BuiltIns {
|
|||||||
def compileInPlaceWordOrLongShiftOps(ctx: CompilationContext, lhs: LhsExpression, rhs: Expression, aslRatherThanLsr: Boolean): List[AssemblyLine] = {
|
def compileInPlaceWordOrLongShiftOps(ctx: CompilationContext, lhs: LhsExpression, rhs: Expression, aslRatherThanLsr: Boolean): List[AssemblyLine] = {
|
||||||
val env = ctx.env
|
val env = ctx.env
|
||||||
val b = env.get[Type]("byte")
|
val b = env.get[Type]("byte")
|
||||||
val targetBytes = lhs match {
|
val targetBytes = getStorageForEachByte(ctx, lhs)
|
||||||
case v: VariableExpression =>
|
|
||||||
val variable = env.get[Variable](v.name)
|
|
||||||
List.tabulate(variable.typ.size) { i => AssemblyLine.variable(ctx, STA, variable, i) }
|
|
||||||
case SeparateBytesExpression(h: VariableExpression, l: VariableExpression) =>
|
|
||||||
List(
|
|
||||||
AssemblyLine.variable(ctx, STA, env.get[Variable](l.name)),
|
|
||||||
AssemblyLine.variable(ctx, STA, env.get[Variable](h.name)))
|
|
||||||
}
|
|
||||||
val lo = targetBytes.head
|
val lo = targetBytes.head
|
||||||
val hi = targetBytes.last
|
val hi = targetBytes.last
|
||||||
env.eval(rhs) match {
|
env.eval(rhs) match {
|
||||||
@@ -578,6 +573,12 @@ object BuiltIns {
|
|||||||
simpleOperation(DEC, ctx, v, IndexChoice.RequireX, preserveA = false, commutative = true)
|
simpleOperation(DEC, ctx, v, IndexChoice.RequireX, preserveA = false, commutative = true)
|
||||||
}
|
}
|
||||||
case _ =>
|
case _ =>
|
||||||
|
if (!subtract && simplicity(env, v) > simplicity(env, addend)) {
|
||||||
|
val loadRhs = MlCompiler.compile(ctx, addend, Some(b -> RegisterVariable(Register.A, b)), NoBranching)
|
||||||
|
val modifyAcc = insertBeforeLast(AssemblyLine.implied(CLC), simpleOperation(ADC, ctx, v, IndexChoice.PreferY, preserveA = true, commutative = true, decimal = decimal))
|
||||||
|
val storeLhs = MlCompiler.compileByteStorage(ctx, Register.A, v)
|
||||||
|
loadRhs ++ modifyAcc ++ storeLhs
|
||||||
|
} else {
|
||||||
val loadLhs = MlCompiler.compile(ctx, v, Some(b -> RegisterVariable(Register.A, b)), NoBranching)
|
val loadLhs = MlCompiler.compile(ctx, v, Some(b -> RegisterVariable(Register.A, b)), NoBranching)
|
||||||
val modifyLhs = if (subtract) {
|
val modifyLhs = if (subtract) {
|
||||||
insertBeforeLast(AssemblyLine.implied(SEC), simpleOperation(SBC, ctx, addend, IndexChoice.PreferY, preserveA = true, commutative = false, decimal = decimal))
|
insertBeforeLast(AssemblyLine.implied(SEC), simpleOperation(SBC, ctx, addend, IndexChoice.PreferY, preserveA = true, commutative = false, decimal = decimal))
|
||||||
@@ -588,6 +589,7 @@ object BuiltIns {
|
|||||||
loadLhs ++ modifyLhs ++ storeLhs
|
loadLhs ++ modifyLhs ++ storeLhs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def compileInPlaceWordOrLongAddition(ctx: CompilationContext, lhs: LhsExpression, addend: Expression, subtract: Boolean, decimal: Boolean): List[AssemblyLine] = {
|
def compileInPlaceWordOrLongAddition(ctx: CompilationContext, lhs: LhsExpression, addend: Expression, subtract: Boolean, decimal: Boolean): List[AssemblyLine] = {
|
||||||
if (decimal && !ctx.options.flag(CompilationFlag.DecimalMode)) {
|
if (decimal && !ctx.options.flag(CompilationFlag.DecimalMode)) {
|
||||||
@@ -596,17 +598,7 @@ object BuiltIns {
|
|||||||
val env = ctx.env
|
val env = ctx.env
|
||||||
val b = env.get[Type]("byte")
|
val b = env.get[Type]("byte")
|
||||||
val w = env.get[Type]("word")
|
val w = env.get[Type]("word")
|
||||||
val targetBytes: List[List[AssemblyLine]] = lhs match {
|
val targetBytes: List[List[AssemblyLine]] = getStorageForEachByte(ctx, lhs)
|
||||||
case v: VariableExpression =>
|
|
||||||
val variable = env.get[Variable](v.name)
|
|
||||||
List.tabulate(variable.typ.size) { i => AssemblyLine.variable(ctx, STA, variable, i) }
|
|
||||||
case SeparateBytesExpression(h: VariableExpression, l: VariableExpression) =>
|
|
||||||
val lv = env.get[Variable](l.name)
|
|
||||||
val hv = env.get[Variable](h.name)
|
|
||||||
List(
|
|
||||||
AssemblyLine.variable(ctx, STA, lv),
|
|
||||||
AssemblyLine.variable(ctx, STA, hv))
|
|
||||||
}
|
|
||||||
val lhsIsStack = targetBytes.head.head.opcode == TSX
|
val lhsIsStack = targetBytes.head.head.opcode == TSX
|
||||||
val targetSize = targetBytes.size
|
val targetSize = targetBytes.size
|
||||||
val addendType = MlCompiler.getExpressionType(ctx, addend)
|
val addendType = MlCompiler.getExpressionType(ctx, addend)
|
||||||
@@ -775,31 +767,26 @@ object BuiltIns {
|
|||||||
| (AND, Some(NumericConstant(-1, _))) =>
|
| (AND, Some(NumericConstant(-1, _))) =>
|
||||||
Nil
|
Nil
|
||||||
case _ =>
|
case _ =>
|
||||||
|
if (simplicity(env, v) > simplicity(env, param)) {
|
||||||
|
val loadRhs = MlCompiler.compile(ctx, param, Some(b -> RegisterVariable(Register.A, b)), NoBranching)
|
||||||
|
val modifyAcc = simpleOperation(operation, ctx, v, IndexChoice.PreferY, preserveA = true, commutative = true)
|
||||||
|
val storeLhs = MlCompiler.compileByteStorage(ctx, Register.A, v)
|
||||||
|
loadRhs ++ modifyAcc ++ storeLhs
|
||||||
|
} else {
|
||||||
val loadLhs = MlCompiler.compile(ctx, v, Some(b -> RegisterVariable(Register.A, b)), NoBranching)
|
val loadLhs = MlCompiler.compile(ctx, v, Some(b -> RegisterVariable(Register.A, b)), NoBranching)
|
||||||
val modifyLhs = simpleOperation(operation, ctx, param, IndexChoice.PreferY, preserveA = true, commutative = true)
|
val modifyLhs = simpleOperation(operation, ctx, param, IndexChoice.PreferY, preserveA = true, commutative = true)
|
||||||
val storeLhs = MlCompiler.compileByteStorage(ctx, Register.A, v)
|
val storeLhs = MlCompiler.compileByteStorage(ctx, Register.A, v)
|
||||||
loadLhs ++ modifyLhs ++ storeLhs
|
loadLhs ++ modifyLhs ++ storeLhs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def compileInPlaceWordOrLongBitOp(ctx: CompilationContext, lhs: LhsExpression, param: Expression, operation: Opcode.Value): List[AssemblyLine] = {
|
def compileInPlaceWordOrLongBitOp(ctx: CompilationContext, lhs: LhsExpression, param: Expression, operation: Opcode.Value): List[AssemblyLine] = {
|
||||||
val env = ctx.env
|
val env = ctx.env
|
||||||
val b = env.get[Type]("byte")
|
val b = env.get[Type]("byte")
|
||||||
val w = env.get[Type]("word")
|
val w = env.get[Type]("word")
|
||||||
val targetBytes: List[List[AssemblyLine]] = lhs match {
|
val targetBytes: List[List[AssemblyLine]] = getStorageForEachByte(ctx, lhs)
|
||||||
case v: VariableExpression =>
|
|
||||||
val variable = env.get[Variable](v.name)
|
|
||||||
List.tabulate(variable.typ.size) { i => AssemblyLine.variable(ctx, STA, variable, i) }
|
|
||||||
case SeparateBytesExpression(h: VariableExpression, l: VariableExpression) =>
|
|
||||||
val lv = env.get[Variable](l.name)
|
|
||||||
val hv = env.get[Variable](h.name)
|
|
||||||
List(
|
|
||||||
AssemblyLine.variable(ctx, STA, lv),
|
|
||||||
AssemblyLine.variable(ctx, STA, hv))
|
|
||||||
case _ =>
|
|
||||||
???
|
|
||||||
}
|
|
||||||
val lo = targetBytes.head
|
val lo = targetBytes.head
|
||||||
val targetSize = targetBytes.size
|
val targetSize = targetBytes.size
|
||||||
val paramType = MlCompiler.getExpressionType(ctx, param)
|
val paramType = MlCompiler.getExpressionType(ctx, param)
|
||||||
@@ -866,4 +853,20 @@ object BuiltIns {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private def getStorageForEachByte(ctx: CompilationContext, lhs: LhsExpression): List[List[AssemblyLine]] = {
|
||||||
|
val env = ctx.env
|
||||||
|
lhs match {
|
||||||
|
case v: VariableExpression =>
|
||||||
|
val variable = env.get[Variable](v.name)
|
||||||
|
List.tabulate(variable.typ.size) { i => AssemblyLine.variable(ctx, STA, variable, i) }
|
||||||
|
case IndexedExpression(variable, index) =>
|
||||||
|
List(MlCompiler.compileByteStorage(ctx, Register.A, lhs))
|
||||||
|
case SeparateBytesExpression(h: LhsExpression, l: LhsExpression) =>
|
||||||
|
List(
|
||||||
|
getStorageForEachByte(ctx, l).head,
|
||||||
|
MlCompiler.preserveRegisterIfNeeded(ctx, Register.A, getStorageForEachByte(ctx, h).head))
|
||||||
|
case _ =>
|
||||||
|
???
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -797,13 +797,14 @@ object MlCompiler {
|
|||||||
} { case (exprType, target) =>
|
} { case (exprType, target) =>
|
||||||
assertCompatible(exprType, target.typ)
|
assertCompatible(exprType, target.typ)
|
||||||
target match {
|
target match {
|
||||||
|
// TODO: some more complex ones may not work correctly
|
||||||
case RegisterVariable(Register.A | Register.X | Register.Y, _) => compile(ctx, l, exprTypeAndVariable, branches)
|
case RegisterVariable(Register.A | Register.X | Register.Y, _) => compile(ctx, l, exprTypeAndVariable, branches)
|
||||||
case RegisterVariable(Register.AX, _) =>
|
case RegisterVariable(Register.AX, _) =>
|
||||||
compile(ctx, l, Some(b -> RegisterVariable(Register.A, b)), branches) ++
|
compile(ctx, l, Some(b -> RegisterVariable(Register.A, b)), branches) ++
|
||||||
compile(ctx, h, Some(b -> RegisterVariable(Register.X, b)), branches)
|
preserveRegisterIfNeeded(ctx, Register.A, compile(ctx, h, Some(b -> RegisterVariable(Register.X, b)), branches))
|
||||||
case RegisterVariable(Register.AY, _) =>
|
case RegisterVariable(Register.AY, _) =>
|
||||||
compile(ctx, l, Some(b -> RegisterVariable(Register.A, b)), branches) ++
|
compile(ctx, l, Some(b -> RegisterVariable(Register.A, b)), branches) ++
|
||||||
compile(ctx, h, Some(b -> RegisterVariable(Register.Y, b)), branches)
|
preserveRegisterIfNeeded(ctx, Register.A, compile(ctx, h, Some(b -> RegisterVariable(Register.Y, b)), branches))
|
||||||
case RegisterVariable(Register.XA, _) =>
|
case RegisterVariable(Register.XA, _) =>
|
||||||
compile(ctx, l, Some(b -> RegisterVariable(Register.X, b)), branches) ++
|
compile(ctx, l, Some(b -> RegisterVariable(Register.X, b)), branches) ++
|
||||||
compile(ctx, h, Some(b -> RegisterVariable(Register.A, b)), branches)
|
compile(ctx, h, Some(b -> RegisterVariable(Register.A, b)), branches)
|
||||||
|
@@ -134,4 +134,32 @@ class SeparateBytesSuite extends FunSuite with Matchers {
|
|||||||
| }
|
| }
|
||||||
""".stripMargin)(_.readWord(0xc000) should equal(0x707))
|
""".stripMargin)(_.readWord(0xc000) should equal(0x707))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ignore("Complex separate addition") {
|
||||||
|
EmuBenchmarkRun("""
|
||||||
|
| array hi [25] @$c000
|
||||||
|
| array lo [25] @$c080
|
||||||
|
| void main () {
|
||||||
|
| byte i
|
||||||
|
| hi[0] = 0
|
||||||
|
| lo[0] = 0
|
||||||
|
| hi[1] = 0
|
||||||
|
| lo[1] = 1
|
||||||
|
| for i,0,until,lo.length-2 {
|
||||||
|
| barrier()
|
||||||
|
| hi[addTwo(i)]:lo[i + (one() << 1)] = hi[i + one()]:lo[1+i]
|
||||||
|
| barrier()
|
||||||
|
| hi[addTwo(i)]:lo[i + (one() << 1)] += hi[i]:lo[i]
|
||||||
|
| barrier()
|
||||||
|
| }
|
||||||
|
| }
|
||||||
|
| byte one() { return 1 }
|
||||||
|
| byte addTwo(byte x) { return x + 2 }
|
||||||
|
| void barrier() {}
|
||||||
|
""".stripMargin){m =>
|
||||||
|
val h = m.readWord(0xc000 + 24)
|
||||||
|
val l = m.readWord(0xc080 + 24)
|
||||||
|
(h * 0x100 + l) should equal(46368)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user