1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-12-25 06:29:17 +00:00

Don't emit branching instructions with broken offsets

This commit is contained in:
Karol Stasiak 2018-03-25 16:18:19 +02:00
parent 0355495aff
commit 08544159d4
3 changed files with 81 additions and 21 deletions

View File

@ -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,36 +232,77 @@ 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 conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
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")
val conditionBlock = ExpressionCompiler.compile(ctx, condition, someRegisterA, NoBranching)
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, _) =>
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) =>
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 _ =>
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)
Nil

View File

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

View File

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