mirror of
https://github.com/KarolS/millfork.git
synced 2025-01-01 06:29:53 +00:00
6809: Improve booleans
This commit is contained in:
parent
f247516187
commit
d6fd1e8b77
@ -1,10 +1,10 @@
|
||||
package millfork.compiler.m6809
|
||||
|
||||
import millfork.assembly.m6809.{DAccumulatorIndexed, Immediate, Indexed, MLine, MLine0, MOpcode, TwoRegisters}
|
||||
import millfork.assembly.m6809.{DAccumulatorIndexed, Immediate, Indexed, InherentB, MLine, MLine0, MOpcode, RegisterSet, TwoRegisters}
|
||||
import millfork.compiler.{AbstractExpressionCompiler, BranchIfFalse, BranchIfTrue, BranchSpec, ComparisonType, CompilationContext, NoBranching}
|
||||
import millfork.node.{DerefExpression, Expression, FunctionCallExpression, GeneratedConstantExpression, IndexedExpression, LhsExpression, LiteralExpression, M6809Register, SumExpression, VariableExpression}
|
||||
import millfork.assembly.m6809.MOpcode._
|
||||
import millfork.env.{AssemblyParamSignature, BuiltInBooleanType, Constant, ConstantBooleanType, ConstantPointy, ExternFunction, FatBooleanType, FlagBooleanType, FunctionInMemory, FunctionPointerType, M6809RegisterVariable, MacroFunction, MathOperator, MemoryVariable, NonFatalCompilationException, NormalFunction, NormalParamSignature, NumericConstant, StackVariablePointy, ThingInMemory, Type, Variable, VariableInMemory, VariablePointy}
|
||||
import millfork.env.{AssemblyParamSignature, BuiltInBooleanType, Constant, ConstantBooleanType, ConstantPointy, ExternFunction, FatBooleanType, FlagBooleanType, FunctionInMemory, FunctionPointerType, Label, M6809RegisterVariable, MacroFunction, MathOperator, MemoryAddressConstant, MemoryVariable, NonFatalCompilationException, NormalFunction, NormalParamSignature, NumericConstant, StackVariablePointy, ThingInMemory, Type, Variable, VariableInMemory, VariablePointy}
|
||||
|
||||
import scala.collection.GenTraversableOnce
|
||||
|
||||
@ -140,7 +140,9 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
|
||||
}
|
||||
case fce@FunctionCallExpression(functionName, params) =>
|
||||
functionName match {
|
||||
case "not" => ???
|
||||
case "not" =>
|
||||
assertBool(ctx, "not", params, 1)
|
||||
compile(ctx, params.head, target, branches.flip)
|
||||
case "nonet" =>
|
||||
if (params.length != 1) {
|
||||
ctx.log.error("Invalid number of parameters", fce.position)
|
||||
@ -486,6 +488,22 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
|
||||
val label = ctx.env.nextLabel("bo")
|
||||
val condition = compile(ctx, expr, MExpressionTarget.NOTHING, BranchIfFalse(label))
|
||||
val conditionWithoutJump = condition.init
|
||||
|
||||
if (conditionWithoutJump.exists(l => l.parameter match {
|
||||
case MemoryAddressConstant(Label(l)) if l == label => true
|
||||
case _ => false
|
||||
})){
|
||||
val label2 = ctx.env.nextLabel("bo")
|
||||
return condition ++ List(
|
||||
MLine.immediate(LDB, 1),
|
||||
MLine.shortBranch(BRA, label2),
|
||||
MLine.label(label),
|
||||
MLine.immediate(LDB, 0),
|
||||
MLine.label(label2),
|
||||
MLine.inherentB(ROL)
|
||||
)
|
||||
}
|
||||
|
||||
condition.last.opcode match {
|
||||
case BCC =>
|
||||
conditionWithoutJump ++ List(MLine.immediate(LDB, 0), MLine.inherentB(ROL))
|
||||
@ -697,4 +715,24 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
|
||||
compile(ctx, conjunction, target, branches)
|
||||
}
|
||||
}
|
||||
|
||||
def areNZFlagsBasedOnB(code: List[MLine]): Boolean = {
|
||||
for (line <- code.reverse) {
|
||||
line.opcode match {
|
||||
case ADDB | ADCB | SUBB | SBCB | ANDB | ORB => return true
|
||||
case CLR | ASL | LSR | ASR | ROL | ROR | INC | DEC | NEG => return line.addrMode == InherentB
|
||||
case CMPB => return line.addrMode == Immediate && line.parameter.isProvablyZero
|
||||
case PULS | PULU =>
|
||||
line.addrMode match {
|
||||
case r: RegisterSet =>
|
||||
if (r.contains(M6809Register.B)) return false
|
||||
if (r.contains(M6809Register.CC)) return false
|
||||
case _ =>
|
||||
}
|
||||
case LEAS | LEAU | PSHS | PSHU | TFR | NOP | ABX => // loop
|
||||
case _ => return false
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
@ -3,9 +3,9 @@ package millfork.compiler.m6809
|
||||
import millfork.assembly.BranchingOpcodeMapping
|
||||
import millfork.assembly.m6809.{MLine, NonExistent}
|
||||
import millfork.compiler.{AbstractCompiler, AbstractExpressionCompiler, AbstractStatementCompiler, BranchSpec, CompilationContext}
|
||||
import millfork.node.{Assignment, BlackHoleExpression, BreakStatement, ContinueStatement, DoWhileStatement, ExecutableStatement, Expression, ExpressionStatement, ForEachStatement, ForStatement, IfStatement, M6809AssemblyStatement, ReturnDispatchStatement, ReturnStatement, VariableExpression, WhileStatement}
|
||||
import millfork.node.{Assignment, BlackHoleExpression, BreakStatement, ContinueStatement, DoWhileStatement, ExecutableStatement, Expression, ExpressionStatement, ForEachStatement, ForStatement, FunctionCallExpression, IfStatement, M6809AssemblyStatement, ReturnDispatchStatement, ReturnStatement, VariableExpression, WhileStatement}
|
||||
import millfork.assembly.m6809.MOpcode._
|
||||
import millfork.env.{FatBooleanType, Label, ThingInMemory}
|
||||
import millfork.env.{BooleanType, ConstantBooleanType, FatBooleanType, Label, ThingInMemory}
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
@ -45,11 +45,26 @@ object M6809StatementCompiler extends AbstractStatementCompiler[MLine] {
|
||||
case Assignment(destination, source) =>
|
||||
if (destination == BlackHoleExpression) return M6809ExpressionCompiler.compile(ctx, source, MExpressionTarget.NOTHING, BranchSpec.None) -> Nil
|
||||
val destinationType = AbstractExpressionCompiler.getExpressionType(ctx, destination)
|
||||
val sourceType = AbstractExpressionCompiler.getExpressionType(ctx, source)
|
||||
AbstractExpressionCompiler.checkAssignmentType(ctx, source, destinationType)
|
||||
destinationType.size match {
|
||||
case 1 => (M6809ExpressionCompiler.compileToB(ctx, source) ++ M6809ExpressionCompiler.storeB(ctx, destination)) -> Nil
|
||||
case 2 => (M6809ExpressionCompiler.compileToD(ctx, source) ++ M6809ExpressionCompiler.storeD(ctx, destination)) -> Nil
|
||||
}
|
||||
(destinationType.size match {
|
||||
case 0 => sourceType match {
|
||||
case _: ConstantBooleanType =>
|
||||
M6809ExpressionCompiler.compileToB(ctx, source) ++ M6809ExpressionCompiler.storeB(ctx, destination)
|
||||
case _: BooleanType =>
|
||||
M6809ExpressionCompiler.compileToFatBooleanInB(ctx, source) ++ M6809ExpressionCompiler.storeB(ctx, destination)
|
||||
case _ =>
|
||||
ctx.log.error("Cannot assign a void expression", statement.position)
|
||||
M6809ExpressionCompiler.compile(ctx, source, MExpressionTarget.NOTHING, BranchSpec.None) ++
|
||||
M6809ExpressionCompiler.compile(ctx, destination, MExpressionTarget.NOTHING, BranchSpec.None)
|
||||
}
|
||||
case 1 => sourceType match {
|
||||
case _: BooleanType =>
|
||||
M6809ExpressionCompiler.compileToFatBooleanInB(ctx, source) ++ M6809ExpressionCompiler.storeB(ctx, destination)
|
||||
case _ => M6809ExpressionCompiler.compileToB(ctx, source) ++ M6809ExpressionCompiler.storeB(ctx, destination)
|
||||
}
|
||||
case 2 => M6809ExpressionCompiler.compileToD(ctx, source) ++ M6809ExpressionCompiler.storeD(ctx, destination)
|
||||
}) -> Nil
|
||||
case ExpressionStatement(expression) =>
|
||||
M6809ExpressionCompiler.compile(ctx, expression, MExpressionTarget.NOTHING) -> Nil
|
||||
case s:IfStatement =>
|
||||
@ -86,10 +101,17 @@ object M6809StatementCompiler extends AbstractStatementCompiler[MLine] {
|
||||
|
||||
override def jmpChunk(label: Label): List[MLine] = List(MLine.absolute(JMP, label.toAddress))
|
||||
|
||||
override def branchChunk(opcode: BranchingOpcodeMapping, labelName: String): List[MLine] = ???
|
||||
override def branchChunk(opcode: BranchingOpcodeMapping, labelName: String): List[MLine] =
|
||||
List(MLine.shortBranch(opcode.m6809, labelName)) // TODO: ???
|
||||
|
||||
override def compileExpressionForBranching(ctx: CompilationContext, expr: Expression, branching: BranchSpec): List[MLine] =
|
||||
M6809ExpressionCompiler.compile(ctx, expr, MExpressionTarget.NOTHING, branching)
|
||||
if (AbstractExpressionCompiler.getExpressionType(ctx, expr) == FatBooleanType) {
|
||||
val prepareB = M6809ExpressionCompiler.compile(ctx, expr, MExpressionTarget.B, branching)
|
||||
if (M6809ExpressionCompiler.areNZFlagsBasedOnB(prepareB)) prepareB
|
||||
else prepareB :+ MLine.immediate(CMPB, 0)
|
||||
} else {
|
||||
M6809ExpressionCompiler.compile(ctx, expr, MExpressionTarget.NOTHING, branching)
|
||||
}
|
||||
|
||||
override def replaceLabel(ctx: CompilationContext, line: MLine, from: String, to: String): MLine = ???
|
||||
|
||||
|
@ -10,7 +10,7 @@ import org.scalatest.{FunSuite, Matchers}
|
||||
class BooleanSuite extends FunSuite with Matchers {
|
||||
|
||||
test("Not") {
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
|
||||
"""
|
||||
| byte output @$c000
|
||||
| array input = [5,6,7]
|
||||
@ -28,7 +28,7 @@ class BooleanSuite extends FunSuite with Matchers {
|
||||
|
||||
|
||||
test("And") {
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
|
||||
"""
|
||||
| byte output @$c000
|
||||
| array input = [5,6,7]
|
||||
@ -47,7 +47,7 @@ class BooleanSuite extends FunSuite with Matchers {
|
||||
|
||||
|
||||
test("Or") {
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
|
||||
"""
|
||||
| byte output @$c000
|
||||
| array input = [5,6,7]
|
||||
@ -89,7 +89,7 @@ class BooleanSuite extends FunSuite with Matchers {
|
||||
| inline void pass() { output += 1 }
|
||||
| noinline void fail() { outside[0] = 0 }
|
||||
""".stripMargin
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(code)(_.readByte(0xc000) should equal(code.sliding(4).count(_ == "pass")))
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(code)(_.readByte(0xc000) should equal(code.sliding(4).count(_ == "pass")))
|
||||
}
|
||||
|
||||
test("Fat boolean") {
|
||||
@ -136,7 +136,7 @@ class BooleanSuite extends FunSuite with Matchers {
|
||||
| bool never() = false
|
||||
|
|
||||
""".stripMargin
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(code)(_.readByte(0xc000) should equal(code.sliding(4).count(_ == "pass")))
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(code)(_.readByte(0xc000) should equal(code.sliding(4).count(_ == "pass")))
|
||||
}
|
||||
|
||||
test("Fat boolean optimization") {
|
||||
@ -153,7 +153,7 @@ class BooleanSuite extends FunSuite with Matchers {
|
||||
| }
|
||||
|
|
||||
""".stripMargin
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(code)(_.readByte(0xc000) should equal(7))
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(code)(_.readByte(0xc000) should equal(7))
|
||||
}
|
||||
|
||||
test("Constant booleans") {
|
||||
@ -183,7 +183,7 @@ class BooleanSuite extends FunSuite with Matchers {
|
||||
| }
|
||||
|
|
||||
""".stripMargin
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80)(code)(_.readWord(0xc000) should equal(13))
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(code)(_.readWord(0xc000) should equal(13))
|
||||
}
|
||||
|
||||
test("Constant booleans mini") {
|
||||
@ -224,7 +224,7 @@ class BooleanSuite extends FunSuite with Matchers {
|
||||
| }
|
||||
|
|
||||
""".stripMargin
|
||||
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80)(code){ m =>
|
||||
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(code){ m =>
|
||||
m.readByte(0xc000) should equal(1)
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ class M6809Memory(memoryBank: MemoryBank, resetVector: Int) extends MemorySegmen
|
||||
|
||||
override def store(addr: Int, `val`: Int): Unit = {
|
||||
if (!memoryBank.writeable(addr)) {
|
||||
println(s"Accessing memory for write at $$${addr.toHexString}")
|
||||
println(s"Accessing memory for write at $$${addr.toHexString}, writing $$${`val`.toHexString}")
|
||||
???
|
||||
}
|
||||
memoryBank.output(addr) = `val`.toByte
|
||||
|
Loading…
Reference in New Issue
Block a user