1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-10-30 06:24:09 +00:00

References to variables in assembly should always refer to their addresses

This commit is contained in:
Karol Stasiak 2018-01-01 22:13:05 +01:00
parent 566631fc5e
commit 3e0d1d4978
3 changed files with 81 additions and 11 deletions

View File

@ -1090,14 +1090,10 @@ object MlCompiler {
case function: InlinedFunction => case function: InlinedFunction =>
inlineFunction(function, params, Some(ctx)).map { inlineFunction(function, params, Some(ctx)).map {
case AssemblyStatement(opcode, addrMode, expression, elidable) => case AssemblyStatement(opcode, addrMode, expression, elidable) =>
val param = env.eval(expression).getOrElse { val param = env.evalForAsm(expression).getOrElse {
expression match {
case VariableExpression(name) => env.get[ThingInMemory](name).toAddress
case _ =>
ErrorReporting.error("Inlining failed due to non-constant things", expression.position) ErrorReporting.error("Inlining failed due to non-constant things", expression.position)
Constant.Zero Constant.Zero
} }
}
AssemblyLine(opcode, addrMode, param, elidable) AssemblyLine(opcode, addrMode, param, elidable)
} }
@ -1427,12 +1423,17 @@ object MlCompiler {
if (OpcodeClasses.ShortBranching(o) || o == JMP || o == LABEL) { if (OpcodeClasses.ShortBranching(o) || o == JMP || o == LABEL) {
MemoryAddressConstant(Label(name)) MemoryAddressConstant(Label(name))
} else{ } else{
env.eval(x).getOrElse(env.get[ThingInMemory](name, x.position).toAddress) env.evalForAsm(x).getOrElse(env.get[ThingInMemory](name, x.position).toAddress)
} }
case _ => case _ =>
env.eval(x).getOrElse(Constant.error(s"`$x` is not a constant", x.position)) env.evalForAsm(x).getOrElse(Constant.error(s"`$x` is not a constant", x.position))
}
val actualAddrMode = a match {
case Absolute if OpcodeClasses.ShortBranching(o) => Relative
case IndexedX if o == JMP => AbsoluteIndexedX
case Indirect if o != JMP => ZeroPageIndirect
case _ => a
} }
val actualAddrMode = if (OpcodeClasses.ShortBranching(o) && a == Absolute) Relative else a
LinearChunk(List(AssemblyLine(o, actualAddrMode, c, e))) LinearChunk(List(AssemblyLine(o, actualAddrMode, c, e)))
case Assignment(dest, source) => case Assignment(dest, source) =>
LinearChunk(compileAssignment(ctx, source, dest)) LinearChunk(compileAssignment(ctx, source, dest))

View File

@ -285,7 +285,62 @@ class Environment(val parent: Option[Environment], val prefix: String) {
} }
private def constantOperation(op: MathOperator.Value, params: List[Expression]) = { private def constantOperation(op: MathOperator.Value, params: List[Expression]) = {
params.map(eval(_)).reduceLeft[Option[Constant]] { (oc, om) => params.map(eval).reduceLeft[Option[Constant]] { (oc, om) =>
for {
c <- oc
m <- om
} yield CompoundConstant(op, c, m)
}
}
def evalForAsm(e: Expression): Option[Constant] = {
e match {
case LiteralExpression(value, size) => Some(NumericConstant(value, size))
case VariableExpression(name) =>
maybeGet[ConstantThing](name).map(_.value).orElse(maybeGet[ThingInMemory](name).map(_.toAddress))
case IndexedExpression(name, index) => (evalForAsm(VariableExpression(name)), evalForAsm(index)) match {
case (Some(a), Some(b)) => Some(CompoundConstant(MathOperator.Plus, a, b).quickSimplify)
}
case HalfWordExpression(param, hi) => evalForAsm(e).map(c => if (hi) c.hiByte else c.loByte)
case SumExpression(params, decimal) =>
params.map {
case (minus, param) => (minus, evalForAsm(param))
}.foldLeft(Some(Constant.Zero).asInstanceOf[Option[Constant]]) { (oc, pair) =>
oc.flatMap { c =>
pair match {
case (_, None) => None
case (minus, Some(addend)) =>
val op = if (decimal) {
if (minus) MathOperator.DecimalMinus else MathOperator.DecimalPlus
} else {
if (minus) MathOperator.Minus else MathOperator.Plus
}
Some(CompoundConstant(op, c, addend))
}
}
}
case SeparateBytesExpression(h, l) => for {
lc <- evalForAsm(l)
hc <- evalForAsm(h)
} yield hc.asl(8) + lc
case FunctionCallExpression(name, params) =>
name match {
case "*" =>
constantOperationForAsm(MathOperator.Times, params)
case "&&" | "&" =>
constantOperationForAsm(MathOperator.And, params)
case "^" =>
constantOperationForAsm(MathOperator.Exor, params)
case "||" | "|" =>
constantOperationForAsm(MathOperator.Or, params)
case _ =>
None
}
}
}
private def constantOperationForAsm(op: MathOperator.Value, params: List[Expression]) = {
params.map(evalForAsm).reduceLeft[Option[Constant]] { (oc, om) =>
for { for {
c <- oc c <- oc
m <- om m <- om

View File

@ -96,4 +96,18 @@ class AssemblySuite extends FunSuite with Matchers {
""".stripMargin)(_.readByte(0xc000) should equal(5)) """.stripMargin)(_.readByte(0xc000) should equal(5))
} }
test("Adresses in asm") {
EmuBenchmarkRun(
"""
| word output @$c000
| void main () {
| output = 0
| add256(output)
| }
| inline asm void add256(word ref v) {
| inc v+1
| }
""".stripMargin)(_.readWord(0xc000) should equal(0x100))
}
} }