From 08544159d41c3174f1f80ff057c95bea4fbb4d56 Mon Sep 17 00:00:00 2001 From: Karol Stasiak Date: Sun, 25 Mar 2018 16:18:19 +0200 Subject: [PATCH] Don't emit branching instructions with broken offsets --- .../millfork/compiler/StatementCompiler.scala | 84 ++++++++++++++----- src/main/scala/millfork/env/Constant.scala | 10 +++ .../scala/millfork/output/Assembler.scala | 8 +- 3 files changed, 81 insertions(+), 21 deletions(-) diff --git a/src/main/scala/millfork/compiler/StatementCompiler.scala b/src/main/scala/millfork/compiler/StatementCompiler.scala index fdfa8578..4e1beff0 100644 --- a/src/main/scala/millfork/compiler/StatementCompiler.scala +++ b/src/main/scala/millfork/compiler/StatementCompiler.scala @@ -209,11 +209,14 @@ object StatementCompiler { val largeThenBlock = thenBlock.map(_.sizeInBytes).sum > 100 val largeElseBlock = elseBlock.map(_.sizeInBytes).sum > 100 condType match { - case ConstantBooleanType(_, true) => thenBlock - case ConstantBooleanType(_, false) => elseBlock + case ConstantBooleanType(_, true) => + ExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching) ++ thenBlock + case ConstantBooleanType(_, false) => + ExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching) ++ elseBlock case FlagBooleanType(_, jumpIfTrue, jumpIfFalse) => (thenPart, elsePart) match { - case (Nil, Nil) => Nil + case (Nil, Nil) => + ExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching) case (Nil, _) => val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching) if (largeElseBlock) { @@ -229,35 +232,76 @@ object StatementCompiler { if (largeThenBlock) { val middle = MfCompiler.nextLabel("th") val end = MfCompiler.nextLabel("fi") - List(conditionBlock, branchChunk(jumpIfTrue, middle), jmpChunk(end), labelChunk(middle), elseBlock, labelChunk(end)).flatten + List(conditionBlock, branchChunk(jumpIfTrue, middle), jmpChunk(end), labelChunk(middle), thenBlock, labelChunk(end)).flatten } else { val end = MfCompiler.nextLabel("fi") List(conditionBlock, branchChunk(jumpIfFalse, end), thenBlock, labelChunk(end)).flatten } case _ => - // TODO: large blocks - if (largeElseBlock || largeThenBlock) ErrorReporting.error("Large blocks in if statement", statement.position) - val middle = MfCompiler.nextLabel("el") - val end = MfCompiler.nextLabel("fi") val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching) - List(conditionBlock, branchChunk(jumpIfFalse, middle), thenBlock, jmpChunk(end), labelChunk(middle), elseBlock, labelChunk(end)).flatten + if (largeThenBlock) { + if (largeElseBlock) { + val middleT = MfCompiler.nextLabel("th") + val middleE = MfCompiler.nextLabel("el") + val end = MfCompiler.nextLabel("fi") + List(conditionBlock, branchChunk(jumpIfTrue, middleT), jmpChunk(middleE), labelChunk(middleT), thenBlock, jmpChunk(end), labelChunk(middleE), elseBlock, labelChunk(end)).flatten + } else { + val middle = MfCompiler.nextLabel("th") + val end = MfCompiler.nextLabel("fi") + List(conditionBlock, branchChunk(jumpIfTrue, middle), elseBlock, jmpChunk(end), labelChunk(middle), thenBlock, labelChunk(end)).flatten + } + } else { + val middle = MfCompiler.nextLabel("el") + val end = MfCompiler.nextLabel("fi") + List(conditionBlock, branchChunk(jumpIfFalse, middle), thenBlock, jmpChunk(end), labelChunk(middle), elseBlock, labelChunk(end)).flatten + } } case BuiltInBooleanType => (thenPart, elsePart) match { - case (Nil, Nil) => Nil + case (Nil, Nil) => + ExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching) case (Nil, _) => - val end = MfCompiler.nextLabel("fi") - val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfTrue(end)) - List(conditionBlock, elseBlock, labelChunk(end)).flatten + if (largeElseBlock) { + val middle = MfCompiler.nextLabel("el") + val end = MfCompiler.nextLabel("fi") + val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfFalse(middle)) + List(conditionBlock, jmpChunk(end), labelChunk(middle), elseBlock, labelChunk(end)).flatten + } else { + val end = MfCompiler.nextLabel("fi") + val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfTrue(end)) + List(conditionBlock, elseBlock, labelChunk(end)).flatten + } case (_, Nil) => - val end = MfCompiler.nextLabel("fi") - val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfFalse(end)) - List(conditionBlock, thenBlock, labelChunk(end)).flatten + if (largeThenBlock) { + val middle = MfCompiler.nextLabel("th") + val end = MfCompiler.nextLabel("fi") + val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfTrue(middle)) + List(conditionBlock, jmpChunk(end), labelChunk(middle), thenBlock, labelChunk(end)).flatten + } else { + val end = MfCompiler.nextLabel("fi") + val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfFalse(end)) + List(conditionBlock, thenBlock, labelChunk(end)).flatten + } case _ => - val middle = MfCompiler.nextLabel("el") - val end = MfCompiler.nextLabel("fi") - val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfFalse(middle)) - List(conditionBlock, thenBlock, jmpChunk(end), labelChunk(middle), elseBlock, labelChunk(end)).flatten + if (largeThenBlock) { + if (largeElseBlock) { + val middleT = MfCompiler.nextLabel("th") + val middleE = MfCompiler.nextLabel("el") + val end = MfCompiler.nextLabel("fi") + val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfTrue(middleT)) + List(conditionBlock, jmpChunk(middleE), labelChunk(middleT), thenBlock, jmpChunk(end), labelChunk(middleE), elseBlock, labelChunk(end)).flatten + } else { + val middle = MfCompiler.nextLabel("th") + val end = MfCompiler.nextLabel("fi") + val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfTrue(middle)) + List(conditionBlock, elseBlock, jmpChunk(end), labelChunk(middle), thenBlock, labelChunk(end)).flatten + } + } else { + val middle = MfCompiler.nextLabel("el") + val end = MfCompiler.nextLabel("fi") + val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, BranchIfFalse(middle)) + List(conditionBlock, thenBlock, jmpChunk(end), labelChunk(middle), elseBlock, labelChunk(end)).flatten + } } case _ => ErrorReporting.error(s"Illegal type for a condition: `$condType`", condition.position) diff --git a/src/main/scala/millfork/env/Constant.scala b/src/main/scala/millfork/env/Constant.scala index de5b477c..d15c02f2 100644 --- a/src/main/scala/millfork/env/Constant.scala +++ b/src/main/scala/millfork/env/Constant.scala @@ -65,6 +65,16 @@ sealed trait Constant { def isRelatedTo(v: Variable): Boolean } +case class AssertByte(c: Constant) extends Constant { + override def isProvablyZero: Boolean = c.isProvablyZero + + override def requiredSize: Int = 1 + + override def isRelatedTo(v: Variable): Boolean = c.isRelatedTo(v) + + override def quickSimplify: Constant = AssertByte(c.quickSimplify) +} + case class UnexpandedConstant(name: String, requiredSize: Int) extends Constant { override def isRelatedTo(v: Variable): Boolean = false } diff --git a/src/main/scala/millfork/output/Assembler.scala b/src/main/scala/millfork/output/Assembler.scala index c168dd94..a79400d0 100644 --- a/src/main/scala/millfork/output/Assembler.scala +++ b/src/main/scala/millfork/output/Assembler.scala @@ -68,6 +68,12 @@ class Assembler(private val program: Program, private val rootEnv: Environment, def deepConstResolve(c: Constant): Long = { c match { case NumericConstant(v, _) => v + case AssertByte(inner) => + val value = deepConstResolve(inner) + if (value.toByte == value) value else { + ErrorReporting.error("Invalid relative jump: " + c) + -2 // spin + } case MemoryAddressConstant(th) => try { if (labelMap.contains(th.name)) return labelMap(th.name) @@ -421,7 +427,7 @@ class Assembler(private val program: Program, private val rootEnv: Environment, index += 1 case AssemblyLine(op, Relative, param, _) => writeByte(bank, index, Assembler.opcodeFor(op, Relative, options)) - writeByte(bank, index + 1, param - (index + 2)) + writeByte(bank, index + 1, AssertByte(param - (index + 2))) index += 2 case AssemblyLine(op, am@(Immediate | ZeroPage | ZeroPageX | ZeroPageY | IndexedY | IndexedX | IndexedZ | LongIndexedY | LongIndexedZ | Stack), param, _) => writeByte(bank, index, Assembler.opcodeFor(op, am, options))