From 802cd7d86af7124c4b57afecadb513391c2a83a5 Mon Sep 17 00:00:00 2001 From: Karol Stasiak Date: Sun, 3 Nov 2019 22:26:41 +0100 Subject: [PATCH] Conversions from bool to byte --- .../compiler/AbstractExpressionCompiler.scala | 2 +- .../m6809/M6809ExpressionCompiler.scala | 32 ++++++++++++++++++- .../compiler/mos/MosExpressionCompiler.scala | 3 ++ .../compiler/z80/Z80ExpressionCompiler.scala | 3 ++ src/main/scala/millfork/env/Thing.scala | 12 +++++++ .../scala/millfork/test/BooleanSuite.scala | 18 +++++++++++ 6 files changed, 68 insertions(+), 2 deletions(-) diff --git a/src/main/scala/millfork/compiler/AbstractExpressionCompiler.scala b/src/main/scala/millfork/compiler/AbstractExpressionCompiler.scala index c637a0f1..9f9e402a 100644 --- a/src/main/scala/millfork/compiler/AbstractExpressionCompiler.scala +++ b/src/main/scala/millfork/compiler/AbstractExpressionCompiler.scala @@ -203,7 +203,7 @@ class AbstractExpressionCompiler[T <: AbstractCode] { failed = true } val sourceType = getExpressionType(ctx, params.head) - if (typ.size != sourceType.size && !sourceType.isAssignableTo(typ)) { + if (typ.size != sourceType.size && !sourceType.isExplicitlyCastableTo(typ)) { ctx.log.error(s"Cannot cast a type ${sourceType.name} to an incompatible type ${typ.name} of different size", params.head.position) failed = true } diff --git a/src/main/scala/millfork/compiler/m6809/M6809ExpressionCompiler.scala b/src/main/scala/millfork/compiler/m6809/M6809ExpressionCompiler.scala index 685ac7e8..3347971a 100644 --- a/src/main/scala/millfork/compiler/m6809/M6809ExpressionCompiler.scala +++ b/src/main/scala/millfork/compiler/m6809/M6809ExpressionCompiler.scala @@ -4,7 +4,7 @@ import millfork.assembly.m6809.{DAccumulatorIndexed, Indexed, MLine, MOpcode, Tw 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, Constant, ConstantBooleanType, ConstantPointy, ExternFunction, FatBooleanType, 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, M6809RegisterVariable, MacroFunction, MathOperator, MemoryVariable, NonFatalCompilationException, NormalFunction, NormalParamSignature, NumericConstant, StackVariablePointy, ThingInMemory, Type, Variable, VariableInMemory, VariablePointy} import scala.collection.GenTraversableOnce @@ -388,6 +388,9 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] { env.maybeGet[Type](fce.functionName) match { case Some(typ) => val sourceType = validateTypeCastAndGetSourceExpressionType(ctx, typ, params) + if (sourceType.isBoollike) { + return compileToFatBooleanInB(ctx, params.head) ++ targetifyB(ctx, target, isSigned = false) + } return typ.size match { // TODO: alternating signedness? case 1 => compileToB(ctx, params.head) ++ targetifyB(ctx, target, isSigned = typ.isSigned) @@ -482,8 +485,35 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] { case FatBooleanType => compileToB(ctx, expr) case t: ConstantBooleanType => List(MLine.immediate(MOpcode.LDB, if (t.value) 1 else 0)) + case BuiltInBooleanType | _: FlagBooleanType => + val label = ctx.env.nextLabel("bo") + val condition = compile(ctx, expr, MExpressionTarget.NOTHING, BranchIfFalse(label)) + val conditionWithoutJump = condition.init + condition.last.opcode match { + case BCC => + conditionWithoutJump ++ List(MLine.immediate(LDB, 0), MLine.inherentB(ROL)) + case BCS => + conditionWithoutJump ++ List(MLine.immediate(LDB, 0), MLine.inherentB(ROL), MLine.immediate(EORB, 1)) + case BVC | BVS => + conditionWithoutJump ++ List( + MLine.immediate(LDB, 0), + condition.last, + MLine.inherentB(INC), + MLine.label(label) + ) + case _ => + conditionWithoutJump ++ List( + MLine.immediate(ANDCC, 0xfe), + condition.last, + MLine.immediate(ORCC, 1), + MLine.label(label), + MLine.immediate(LDB, 0), + MLine.inherentB(ROL) + ) + } case _ => println(sourceType) + println(expr) ??? } } diff --git a/src/main/scala/millfork/compiler/mos/MosExpressionCompiler.scala b/src/main/scala/millfork/compiler/mos/MosExpressionCompiler.scala index 066dbdb6..657ab8a4 100644 --- a/src/main/scala/millfork/compiler/mos/MosExpressionCompiler.scala +++ b/src/main/scala/millfork/compiler/mos/MosExpressionCompiler.scala @@ -1676,6 +1676,9 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] { env.maybeGet[Type](f.functionName) match { case Some(typ) => val sourceType = validateTypeCastAndGetSourceExpressionType(ctx, typ, params) + if (sourceType.isBoollike) { + return compileToFatBooleanInA(ctx, params.head) ++ expressionStorageFromA(ctx, exprTypeAndVariable, position = expr.position, signedSource = false) + } exprTypeAndVariable match { case None => return compile(ctx, params.head, None, branches) diff --git a/src/main/scala/millfork/compiler/z80/Z80ExpressionCompiler.scala b/src/main/scala/millfork/compiler/z80/Z80ExpressionCompiler.scala index b1307298..961eb33a 100644 --- a/src/main/scala/millfork/compiler/z80/Z80ExpressionCompiler.scala +++ b/src/main/scala/millfork/compiler/z80/Z80ExpressionCompiler.scala @@ -1202,6 +1202,9 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] { env.maybeGet[Type](f.functionName) match { case Some(typ) => val sourceType = validateTypeCastAndGetSourceExpressionType(ctx, typ, params) + if (sourceType.isBoollike) { + return targetifyA(ctx, target, compileToFatBooleanInA(ctx, params.head), isSigned = false) + } return typ.size match { // TODO: alternating signedness? case 1 => targetifyA(ctx, target, compileToA(ctx, params.head), isSigned = typ.isSigned) diff --git a/src/main/scala/millfork/env/Thing.scala b/src/main/scala/millfork/env/Thing.scala index b0d0d362..d053ab3f 100644 --- a/src/main/scala/millfork/env/Thing.scala +++ b/src/main/scala/millfork/env/Thing.scala @@ -23,12 +23,16 @@ sealed trait Type extends CallableThing { def isSigned: Boolean + def isBoollike: Boolean = false + def isSubtypeOf(other: Type): Boolean = this == other def isCompatible(other: Type): Boolean = this == other override def toString: String = name + def isExplicitlyCastableTo(targetType: Type): Boolean = isAssignableTo(targetType) + def isAssignableTo(targetType: Type): Boolean = isCompatible(targetType) def isArithmetic = false @@ -131,6 +135,8 @@ case object FatBooleanType extends VariableType { override def isSigned: Boolean = false + override def isBoollike: Boolean = true + override def name: String = "bool" override def isPointy: Boolean = false @@ -138,6 +144,8 @@ case object FatBooleanType extends VariableType { override def isSubtypeOf(other: Type): Boolean = this == other override def isAssignableTo(targetType: Type): Boolean = this == targetType + + override def isExplicitlyCastableTo(targetType: Type): Boolean = targetType.isArithmetic || isAssignableTo(targetType) } sealed trait BooleanType extends Type { @@ -145,7 +153,11 @@ sealed trait BooleanType extends Type { def isSigned = false + override def isBoollike: Boolean = true + override def isAssignableTo(targetType: Type): Boolean = isCompatible(targetType) || targetType == FatBooleanType + + override def isExplicitlyCastableTo(targetType: Type): Boolean = targetType.isArithmetic || isAssignableTo(targetType) } case class ConstantBooleanType(name: String, value: Boolean) extends BooleanType diff --git a/src/test/scala/millfork/test/BooleanSuite.scala b/src/test/scala/millfork/test/BooleanSuite.scala index 486e538a..2fda054b 100644 --- a/src/test/scala/millfork/test/BooleanSuite.scala +++ b/src/test/scala/millfork/test/BooleanSuite.scala @@ -246,4 +246,22 @@ class BooleanSuite extends FunSuite with Matchers { m.readByte(0xc001) should equal(1) } } + + test("Boolean to number conversions") { + val code = + """ + |byte output @$c000 + |void main () { + |output = 0 + |output += byte(output == 0) // ↑ + |output += byte(output == 0) + |output += byte(output != 2) // ↑ + |output += byte(output != 2) + |output += byte(2 > 1) // ↑ + |} + |""".stripMargin + EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(code){ m => + m.readByte(0xc000) should equal(code.count(_ == '↑')) + } + } }