From 514e819ddffb1c59c6103cc1869a79430fff99b3 Mon Sep 17 00:00:00 2001 From: Karol Stasiak Date: Sat, 28 Jul 2018 00:02:57 +0200 Subject: [PATCH] =?UTF-8?q?Fix=20several=20things:=20=E2=80=93=20statement?= =?UTF-8?q?=20preprocessor=20=E2=80=93=20unused=20label=20removal=20?= =?UTF-8?q?=E2=80=93=20>>>>=20operator=20on=206502=20=E2=80=93=20constant?= =?UTF-8?q?=20byte=20comparison=20on=206502?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mos/opt/AlwaysGoodOptimizations.scala | 12 ++--- .../AbstractStatementPreprocessor.scala | 24 ++++++--- .../millfork/compiler/mos/BuiltIns.scala | 49 +++++++++++++++---- .../compiler/mos/MosExpressionCompiler.scala | 7 +-- 4 files changed, 65 insertions(+), 27 deletions(-) diff --git a/src/main/scala/millfork/assembly/mos/opt/AlwaysGoodOptimizations.scala b/src/main/scala/millfork/assembly/mos/opt/AlwaysGoodOptimizations.scala index a8b17d3e..9008a1e0 100644 --- a/src/main/scala/millfork/assembly/mos/opt/AlwaysGoodOptimizations.scala +++ b/src/main/scala/millfork/assembly/mos/opt/AlwaysGoodOptimizations.scala @@ -685,19 +685,19 @@ object AlwaysGoodOptimizations { needsFlowInfo = FlowInfoRequirement.NoRequirement, (Elidable & HasOpcode(JMP) & HasAddrMode(Absolute) & MatchParameter(0)) ~ (Elidable & LinearOrBranch).* ~ - (HasOpcode(LABEL) & MatchParameter(0)) ~~> (_ => Nil), + (HasOpcode(LABEL) & MatchParameter(0)) ~~> (code => List(code.last)), (Elidable & HasOpcode(BRA) & MatchParameter(0)) ~ (Elidable & LinearOrBranch).* ~ - (HasOpcode(LABEL) & MatchParameter(0)) ~~> (_ => Nil), + (HasOpcode(LABEL) & MatchParameter(0)) ~~> (code => List(code.last)), (Elidable & HasOpcode(JMP) & HasAddrMode(Absolute) & MatchParameter(0)) ~ (Not(HasOpcode(LABEL)) & Not(MatchParameter(0))).* ~ - (HasOpcode(LABEL) & MatchParameter(0)) ~ + ((HasOpcode(LABEL) & MatchParameter(0)) ~ (HasOpcode(LABEL) | NoopDiscardsFlags).* ~ - HasOpcode(RTS) ~~> (code => AssemblyLine.implied(RTS) :: code.tail), + HasOpcode(RTS)).capture(1) ~~> ((code, ctx) => ctx.get[List[AssemblyLine]](1) ++ code.tail), (Elidable & ShortBranching & MatchParameter(0)) ~ (NoopDiscardsFlags.* ~ - (Elidable & HasOpcode(RTS))).capture(1) ~ - (HasOpcode(LABEL) & MatchParameter(0)) ~ + (Elidable & HasOpcode(RTS)) ~ + (HasOpcode(LABEL) & MatchParameter(0))).capture(1) ~ NoopDiscardsFlags.* ~ (Elidable & HasOpcode(RTS)) ~~> ((code, ctx) => ctx.get[List[AssemblyLine]](1)), ) diff --git a/src/main/scala/millfork/compiler/AbstractStatementPreprocessor.scala b/src/main/scala/millfork/compiler/AbstractStatementPreprocessor.scala index 1299d27f..6daa46ec 100644 --- a/src/main/scala/millfork/compiler/AbstractStatementPreprocessor.scala +++ b/src/main/scala/millfork/compiler/AbstractStatementPreprocessor.scala @@ -19,7 +19,9 @@ abstract class AbstractStatementPreprocessor(ctx: CompilationContext, statements protected val localPrefix = ctx.function.name + "$" protected val usedIdentifiers = if (optimize) statements.flatMap(_.getAllExpressions).flatMap(_.getAllIdentifiers) else Set() protected val trackableVars: Set[String] = if (optimize) { - env.getAllLocalVariables.map(_.name.stripPrefix(localPrefix)) + env.getAllLocalVariables + .filterNot(_.typ.isSigned) // sadly, tracking loses signedness + .map(_.name.stripPrefix(localPrefix)) .filterNot(_.contains(".")) .filterNot(_.contains("$")) .filterNot { vname => @@ -61,22 +63,25 @@ abstract class AbstractStatementPreprocessor(ctx: CompilationContext, statements stmt match { case Assignment(ve@VariableExpression(v), arg) if trackableVars(v) => cv = search(arg, cv) - Assignment(ve, optimizeExpr(arg, cv)).pos(pos) -> (env.eval(arg, currentVarValues) match { case Some(c) => cv + (v -> c) case None => cv - v }) + case Assignment(ve, arg) => + cv = search(arg, cv) + cv = search(ve, cv) + Assignment(ve, optimizeExpr(arg, cv)).pos(pos) -> cv case ExpressionStatement(expr@FunctionCallExpression("+=", List(VariableExpression(v), arg))) if currentVarValues.contains(v) => cv = search(arg, cv) - ExpressionStatement(optimizeExpr(expr, cv)).pos(pos) -> (env.eval(expr, currentVarValues) match { + ExpressionStatement(optimizeExpr(expr, cv - v)).pos(pos) -> (env.eval(expr, currentVarValues) match { case Some(c) => if (cv.contains(v)) cv + (v -> (cv(v) + c)) else cv case None => cv - v }) case ExpressionStatement(expr@FunctionCallExpression(op, List(VariableExpression(v), arg))) if op.endsWith("=") && op != ">=" && op != "<=" && op != ":=" => cv = search(arg, cv) - ExpressionStatement(optimizeExpr(expr, cv)).pos(pos) -> (cv - v) + ExpressionStatement(optimizeExpr(expr, cv - v)).pos(pos) -> (cv - v) case ExpressionStatement(expr) => cv = search(expr, cv) ExpressionStatement(optimizeExpr(expr, cv)).pos(pos) -> cv @@ -88,7 +93,7 @@ abstract class AbstractStatementPreprocessor(ctx: CompilationContext, statements IfStatement(c, t, e).pos(pos) -> commonVV(vt, ve) case WhileStatement(cond, body, inc, labels) => cv = search(cond, cv) - val c = optimizeExpr(cond, cv) + val c = optimizeExpr(cond, Map()) val (b, _) = optimizeStmts(body, Map()) val (i, _) = optimizeStmts(inc, Map()) WhileStatement(c, b, i, labels).pos(pos) -> Map() @@ -161,13 +166,18 @@ abstract class AbstractStatementPreprocessor(ctx: CompilationContext, statements ErrorReporting.debug(s"Using node flow to replace $v with $constant", pos) GeneratedConstantExpression(constant, getExpressionType(ctx, expr)).pos(pos) case FunctionCallExpression(t1, List(FunctionCallExpression(t2, List(arg)))) - if optimize && pointlessDoubleCast(t1, t2, expr) => + if optimize && pointlessDoubleCast(t1, t2, arg) => ErrorReporting.debug(s"Pointless double cast $t1($t2(...))", pos) optimizeExpr(FunctionCallExpression(t1, List(arg)), currentVarValues) case FunctionCallExpression(t1, List(arg)) - if optimize && pointlessCast(t1, expr) => + if optimize && pointlessCast(t1, arg) => ErrorReporting.debug(s"Pointless cast $t1(...)", pos) optimizeExpr(arg, currentVarValues) + case FunctionCallExpression("nonet", args) => + // Eliminating variables may eliminate carry + FunctionCallExpression("nonet", args.map(arg => optimizeExpr(arg, Map()))).pos(pos) + case FunctionCallExpression(name, args) => + FunctionCallExpression(name, args.map(arg => optimizeExpr(arg, currentVarValues))).pos(pos) case _ => expr // TODO } } diff --git a/src/main/scala/millfork/compiler/mos/BuiltIns.scala b/src/main/scala/millfork/compiler/mos/BuiltIns.scala index 18659fb0..7b2ec806 100644 --- a/src/main/scala/millfork/compiler/mos/BuiltIns.scala +++ b/src/main/scala/millfork/compiler/mos/BuiltIns.scala @@ -214,17 +214,21 @@ object BuiltIns { } } - def compileNonetOps(ctx: CompilationContext, lhs: LhsExpression, rhs: Expression): List[AssemblyLine] = { + def compileNonetOps(ctx: CompilationContext, lhs: Expression, rhs: Expression): List[AssemblyLine] = { val env = ctx.env val b = env.get[Type]("byte") - val (ldaHi, ldaLo) = lhs match { - case v: VariableExpression => - val variable = env.get[Variable](v.name) - AssemblyLine.variable(ctx, LDA, variable, 1) -> AssemblyLine.variable(ctx, LDA, variable, 0) - case SeparateBytesExpression(h: VariableExpression, l: VariableExpression) => - AssemblyLine.variable(ctx, LDA, env.get[Variable](h.name), 0) -> AssemblyLine.variable(ctx, LDA, env.get[Variable](l.name), 0) - case _ => - ??? + val (ldaHi, ldaLo) = env.eval(lhs) match { + case Some(c) => + List(AssemblyLine.immediate(LDA, c.hiByte)) -> List(AssemblyLine.immediate(LDA, c.loByte)) + case _ => lhs match { + case v: VariableExpression => + val variable = env.get[Variable](v.name) + AssemblyLine.variable(ctx, LDA, variable, 1) -> AssemblyLine.variable(ctx, LDA, variable, 0) + case SeparateBytesExpression(h: VariableExpression, l: VariableExpression) => + AssemblyLine.variable(ctx, LDA, env.get[Variable](h.name), 0) -> AssemblyLine.variable(ctx, LDA, env.get[Variable](l.name), 0) + case _ => + ??? + } } env.eval(rhs) match { case Some(NumericConstant(0, _)) => @@ -394,6 +398,33 @@ object BuiltIns { case BranchIfTrue(l) => compType -> l case BranchIfFalse(l) => ComparisonType.negate(compType) -> l } + (env.eval(lhs), env.eval(rhs)) match { + case (Some(NumericConstant(lc, _)), Some(NumericConstant(rc, _))) => + return if (effectiveComparisonType match { + // TODO: those masks are probably wrong + case ComparisonType.Equal => + (lc & 0xff) == (rc & 0xff) + case ComparisonType.NotEqual => + (lc & 0xff) != (rc & 0xff) + case ComparisonType.LessOrEqualUnsigned => + (lc & 0xff) <= (rc & 0xff) + case ComparisonType.GreaterOrEqualUnsigned => + (lc & 0xff) >= (rc & 0xff) + case ComparisonType.GreaterUnsigned => + (lc & 0xff) > (rc & 0xff) + case ComparisonType.LessUnsigned => + (lc & 0xff) < (rc & 0xff) + case ComparisonType.LessOrEqualSigned => + lc.toByte <= rc.toByte + case ComparisonType.GreaterOrEqualSigned => + lc.toByte >= rc.toByte + case ComparisonType.GreaterSigned => + lc.toByte > rc.toByte + case ComparisonType.LessSigned => + lc.toByte < rc.toByte + }) List(AssemblyLine.absolute(JMP, Label(label))) else Nil + case _ => + } val branchingCompiled = effectiveComparisonType match { case ComparisonType.Equal => List(AssemblyLine.relative(BEQ, Label(label))) diff --git a/src/main/scala/millfork/compiler/mos/MosExpressionCompiler.scala b/src/main/scala/millfork/compiler/mos/MosExpressionCompiler.scala index 9435d2fd..fcc98ecc 100644 --- a/src/main/scala/millfork/compiler/mos/MosExpressionCompiler.scala +++ b/src/main/scala/millfork/compiler/mos/MosExpressionCompiler.scala @@ -777,11 +777,8 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] { } case ">>>>" => val (l, r, 2) = assertArithmeticBinary(ctx, params) - l match { - case v: LhsExpression => - zeroExtend = true - BuiltIns.compileNonetOps(ctx, v, r) - } + zeroExtend = true + BuiltIns.compileNonetOps(ctx, l, r) case "<<" => val (l, r, size) = assertArithmeticBinary(ctx, params) size match {