1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-05-31 18:41:30 +00:00

6502: Fix arithmetic promotion bugs for function return values

This commit is contained in:
Karol Stasiak 2019-09-14 16:01:02 +02:00
parent 1d445ecdd1
commit a4f91eda03
4 changed files with 43 additions and 16 deletions

View File

@ -22,6 +22,8 @@
* Added `vectrex` text encoding.
* 6502: Fixed arithmetic promotion bugs for function return values.
* Fixed several serious bugs related to cartridge-based targets.
## 0.3.6

View File

@ -354,7 +354,7 @@ object MosBulkMemoryOperations {
val loadTarget = if (target.typ.size == 2) MosExpressionCompiler.compileToAX(ctx, targetExpression) else MosExpressionCompiler.compileToA(ctx, targetExpression)
val storeTarget =
if (target.typ.size == 2) MosExpressionCompiler.expressionStorageFromAX(ctx, Some(target.typ -> target), targetExpression.position)
else MosExpressionCompiler.expressionStorageFromA(ctx, Some(target.typ -> target), targetExpression.position)
else MosExpressionCompiler.expressionStorageFromA(ctx, Some(target.typ -> target), targetExpression.position, signedSource = false)
Some(loadTarget ++ frame._1 ++ body ++ frame._2 ++ storeTarget)
}

View File

@ -582,7 +582,7 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
case 2 => List(tsx, AssemblyLine.implied(TXA), AssemblyLine.implied(INX), AssemblyLine.implied(INX))
case _ => List(tsx, AssemblyLine.implied(TXA), AssemblyLine.implied(CLC), AssemblyLine.immediate(ADC, actualOffset))
}
loadA ++ expressionStorageFromA(ctx, Some(b -> target), None)
loadA ++ expressionStorageFromA(ctx, Some(b -> target), None, signedSource = false)
}
case None =>
val loadA = actualOffset match {
@ -1036,9 +1036,9 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
val (prepare, addr, am) = getPhysicalPointerForDeref(ctx, inner)
(targetType.size, am) match {
case (1, AbsoluteY) =>
prepare ++ List(AssemblyLine.absolute(LDA, addr + offset)) ++ expressionStorageFromA(ctx, exprTypeAndVariable, expr.position)
prepare ++ List(AssemblyLine.absolute(LDA, addr + offset)) ++ expressionStorageFromA(ctx, exprTypeAndVariable, expr.position, exprType.isSigned)
case (1, _) =>
prepare ++ List(AssemblyLine.immediate(LDY, offset), AssemblyLine(LDA, am, addr)) ++ expressionStorageFromA(ctx, exprTypeAndVariable, expr.position)
prepare ++ List(AssemblyLine.immediate(LDY, offset), AssemblyLine(LDA, am, addr)) ++ expressionStorageFromA(ctx, exprTypeAndVariable, expr.position, exprType.isSigned)
case (2, AbsoluteY) =>
prepare ++
List(
@ -1176,6 +1176,7 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
case f@FunctionCallExpression(name, params) =>
var zeroExtend = false
var signExtend = false
var resultVariable = ""
val calculate: List[AssemblyLine] = name match {
case "call" =>
@ -1659,6 +1660,10 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
if (function.returnType.size > 2) {
resultVariable = function.name + ".return"
}
if (function.returnType.size == 1) {
zeroExtend = !function.returnType.isSigned
signExtend = function.returnType.isSigned
}
function match {
case nf: NormalFunction =>
if (nf.interrupt) {
@ -1708,12 +1713,12 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
}
}
if (resultVariable == "") {
val store: List[AssemblyLine] = expressionStorageFromAX(ctx, exprTypeAndVariable, expr.position)
if (zeroExtend && exprTypeAndVariable.exists(_._1.size >= 2)) {
calculate ++ List(AssemblyLine.immediate(LDX, 0)) ++ store
val store: List[AssemblyLine] = if (zeroExtend || signExtend) {
expressionStorageFromA(ctx, exprTypeAndVariable, expr.position, signExtend)
} else {
calculate ++ store
expressionStorageFromAX(ctx, exprTypeAndVariable, expr.position)
}
calculate ++ store
} else {
calculate ++ compile(ctx, VariableExpression(resultVariable), exprTypeAndVariable, branches)
}
@ -1864,17 +1869,17 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
}
}
def expressionStorageFromA(ctx: CompilationContext, exprTypeAndVariable: Option[(Type, Variable)], position: Option[Position]): List[AssemblyLine] = {
def expressionStorageFromA(ctx: CompilationContext, exprTypeAndVariable: Option[(Type, Variable)], position: Option[Position], signedSource: Boolean): List[AssemblyLine] = {
exprTypeAndVariable.fold(noop) {
case (VoidType, _) => ctx.log.fatal("Cannot assign word to void", position)
case (_, RegisterVariable(MosRegister.A, _)) => noop
case (typ, RegisterVariable(MosRegister.AW, _)) =>
if (typ.isSigned) List(AssemblyLine.implied(TAX)) ++ signExtendA(ctx) ++ List(AssemblyLine.implied(XBA), AssemblyLine.implied(TXA))
if (signedSource) List(AssemblyLine.implied(TAX)) ++ signExtendA(ctx) ++ List(AssemblyLine.implied(XBA), AssemblyLine.implied(TXA))
else List(AssemblyLine.implied(XBA), AssemblyLine.immediate(LDA, 0), AssemblyLine.implied(XBA))
case (_, RegisterVariable(MosRegister.X, _)) => List(AssemblyLine.implied(TAX))
case (_, RegisterVariable(MosRegister.Y, _)) => List(AssemblyLine.implied(TAY))
case (typ, RegisterVariable(MosRegister.AX, _)) =>
if (typ.isSigned) {
if (signedSource) {
if (ctx.options.flag(CompilationFlag.EmitHudsonOpcodes)) {
List(AssemblyLine.implied(TAX)) ++ signExtendA(ctx) ++ List(AssemblyLine.implied(HuSAX))
} else {
@ -1882,19 +1887,19 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
}
} else List(AssemblyLine.immediate(LDX, 0))
case (typ, RegisterVariable(MosRegister.XA, _)) =>
if (typ.isSigned) {
if (signedSource) {
List(AssemblyLine.implied(TAX)) ++ signExtendA(ctx)
} else {
List(AssemblyLine.implied(TAX), AssemblyLine.immediate(LDA, 0))
}
case (typ, RegisterVariable(MosRegister.YA, _)) =>
if (typ.isSigned) {
if (signedSource) {
List(AssemblyLine.implied(TAY)) ++ signExtendA(ctx)
} else {
List(AssemblyLine.implied(TAY), AssemblyLine.immediate(LDA, 0))
}
case (typ, RegisterVariable(MosRegister.AY, _)) =>
if (typ.isSigned) {
if (signedSource) {
if (ctx.options.flag(CompilationFlag.EmitHudsonOpcodes)) {
List(AssemblyLine.implied(TAY)) ++ signExtendA(ctx) ++ List(AssemblyLine.implied(SAY))
} else {
@ -1906,7 +1911,7 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
case 1 =>
AssemblyLine.variable(ctx, STA, v)
case s if s > 1 =>
if (t.isSigned) {
if (signedSource) {
AssemblyLine.variable(ctx, STA, v) ++ signExtendA(ctx) ++ List.tabulate(s - 1)(i => AssemblyLine.variable(ctx, STA, v, i + 1)).flatten
} else {
AssemblyLine.variable(ctx, STA, v) ++ List(AssemblyLine.immediate(LDA, 0)) ++
@ -1918,7 +1923,7 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
case 1 =>
AssemblyLine.tsx(ctx) :+ AssemblyLine.dataStackX(ctx, STA, v)
case s if s > 1 =>
AssemblyLine.tsx(ctx) ++ (if (t.isSigned) {
AssemblyLine.tsx(ctx) ++ (if (signedSource) {
List(
AssemblyLine.dataStackX(ctx, STA, v.baseOffset)) ++
signExtendA(ctx) ++

View File

@ -302,4 +302,24 @@ class PointerSuite extends FunSuite with Matchers with AppendedClues {
m.readWord(0xc000) should equal(0x203)
}
}
test("Word pointers and byte-to-word promotions") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080) (
"""
|pointer.word p
|word output @$c000
|void main () {
| p = output.pointer
| p[0] = f()
|}
|noinline word g() = $100
|noinline byte f() {
| g()
| return 5
|}
""".stripMargin
){ m =>
m.readWord(0xc000) should equal(5)
}
}
}