1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-08-16 20:28:54 +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:
Karol Stasiak 2018-01-07 23:30:43 +01:00
parent 2bc27fba75
commit 9ea3823bfd
3 changed files with 90 additions and 58 deletions

View File

@ -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 _ =>
???
}
}
} }

View File

@ -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)

View File

@ -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)
}
}
} }