mirror of
https://github.com/KarolS/millfork.git
synced 2024-12-22 16:31:02 +00:00
Signed multiplication
This commit is contained in:
parent
02031da61a
commit
7c60a89776
@ -62,16 +62,19 @@ class AbstractExpressionCompiler[T <: AbstractCode] {
|
||||
ctx.log.error("Long multiplication not supported", params.head.position)
|
||||
}
|
||||
if (inPlace) {
|
||||
if (lSize == 2 && rSize == 1 && rType.isSigned) {
|
||||
ctx.log.error("Signed multiplication not supported", params.head.position)
|
||||
if (params.size > 2) {
|
||||
ctx.log.error("Too many arguments for *=", params.head.position)
|
||||
}
|
||||
// if (lSize == 2 && rSize == 1 && rType.isSigned) {
|
||||
// ctx.log.error("Signed multiplication not supported", params.head.position)
|
||||
// }
|
||||
} else {
|
||||
if (lSize == 2 && rSize == 1 && rType.isSigned) {
|
||||
ctx.log.error("Signed multiplication not supported", params.head.position)
|
||||
}
|
||||
if (rSize == 2 && lSize == 1 && lType.isSigned) {
|
||||
ctx.log.error("Signed multiplication not supported", params.head.position)
|
||||
}
|
||||
// if (lSize == 2 && rSize == 1 && rType.isSigned) {
|
||||
// ctx.log.error("Signed multiplication not supported", params.head.position)
|
||||
// }
|
||||
// if (rSize == 2 && lSize == 1 && lType.isSigned) {
|
||||
// ctx.log.error("Signed multiplication not supported", params.head.position)
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@ -503,7 +506,23 @@ object AbstractExpressionCompiler {
|
||||
case List(n, _) if n >= 3 => env.get[Type]("int" + n * 8)
|
||||
case _ => log.error(s"Invalid parameters to %%", expr.position); w
|
||||
}
|
||||
case FunctionCallExpression(op@("*" | "|" | "&" | "^" | "/"), params) => params.map { e => getExpressionTypeImpl(env, log, e, loosely).size }.max match {
|
||||
case FunctionCallExpression(op@("*"), params) =>
|
||||
val paramTypes = params.map { e => getExpressionTypeImpl(env, log, e, loosely) }
|
||||
val signed = paramTypes.exists(_.isSigned)
|
||||
val unsigned = paramTypes.exists{
|
||||
case t: DerivedPlainType => !t.isSigned
|
||||
case _ => false
|
||||
}
|
||||
if (signed && unsigned) {
|
||||
log.error("Mixing signed and explicitly unsigned types in multiplication", expr.position)
|
||||
}
|
||||
paramTypes.map(_.size).max match {
|
||||
case 0 | 1 => if (signed) env.get[Type]("sbyte") else b
|
||||
case 2 => if (signed) env.get[Type]("signed16") else w
|
||||
case n if n >= 3 => env.get[Type]("int" + n * 8)
|
||||
case _ => log.error(s"Invalid parameters to " + op, expr.position); w
|
||||
}
|
||||
case FunctionCallExpression(op@("|" | "&" | "^" | "/"), params) => params.map { e => getExpressionTypeImpl(env, log, e, loosely).size }.max match {
|
||||
case 0 | 1 => b
|
||||
case 2 => w
|
||||
case n if n >= 3 => env.get[Type]("int" + n * 8)
|
||||
|
@ -270,6 +270,7 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
|
||||
Nil
|
||||
}
|
||||
case "*" =>
|
||||
assertSizesForMultiplication(ctx, params, inPlace = false)
|
||||
getArithmeticParamMaxSize(ctx, params) match {
|
||||
case 1 => M6809MulDiv.compileByteMultiplication(ctx, params, updateDerefX = false) ++ targetifyB(ctx, target, isSigned = false)
|
||||
case 2 => M6809MulDiv.compileWordMultiplication(ctx, params, updateDerefX = false) ++ targetifyD(ctx, target)
|
||||
@ -474,6 +475,7 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
|
||||
case _ => M6809LargeBuiltins.modifyInPlaceViaX(ctx, l, r, SUBA)
|
||||
}
|
||||
case "*=" =>
|
||||
assertSizesForMultiplication(ctx, params, inPlace = true)
|
||||
val (l, r, size) = assertArithmeticAssignmentLike(ctx, params)
|
||||
size match {
|
||||
case 1 => compileAddressToX(ctx, l) ++ M6809MulDiv.compileByteMultiplication(ctx, List(r), updateDerefX = true)
|
||||
|
@ -718,11 +718,16 @@ object PseudoregisterBuiltIns {
|
||||
ctx.log.error("Variable word-byte multiplication requires the zeropage pseudoregister of size at least 3", param1OrRegister.flatMap(_.position))
|
||||
return Nil
|
||||
}
|
||||
(param1OrRegister.fold(2)(e => AbstractExpressionCompiler.getExpressionType(ctx, e).size),
|
||||
AbstractExpressionCompiler.getExpressionType(ctx, param2).size) match {
|
||||
val lType = param1OrRegister.map(e => AbstractExpressionCompiler.getExpressionType(ctx, e))
|
||||
val rType = AbstractExpressionCompiler.getExpressionType(ctx, param2)
|
||||
(lType.fold(2)(_.size), rType.size) match {
|
||||
case (2, 2) => return compileWordWordMultiplication(ctx, param1OrRegister, param2)
|
||||
case (1, 2) => return compileWordMultiplication(ctx, Some(param2), param1OrRegister.get, storeInRegLo)
|
||||
case (2 | 1, 1) => // ok
|
||||
case (2, 1) =>
|
||||
if (rType.isSigned) {
|
||||
return compileWordWordMultiplication(ctx, param1OrRegister, param2)
|
||||
}
|
||||
case (1, 1) => // ok
|
||||
case _ => ctx.log.fatal("Invalid code path", param2.position)
|
||||
}
|
||||
if (!storeInRegLo && param1OrRegister.isDefined) {
|
||||
|
@ -317,11 +317,13 @@ object Z80Multiply {
|
||||
* Calculate HL = l * r
|
||||
*/
|
||||
def compile16BitMultiplyToHL(ctx: CompilationContext, l: Expression, r: Expression): List[ZLine] = {
|
||||
(AbstractExpressionCompiler.getExpressionType(ctx, l).size,
|
||||
AbstractExpressionCompiler.getExpressionType(ctx, r).size) match {
|
||||
val lType = AbstractExpressionCompiler.getExpressionType(ctx, l)
|
||||
val rType = AbstractExpressionCompiler.getExpressionType(ctx, r)
|
||||
(lType.size, rType.size) match {
|
||||
case (2, 2) => return compile16x16BitMultiplyToHL(ctx, l, r)
|
||||
case (1, 2) => return compile16BitMultiplyToHL(ctx, r, l)
|
||||
case (2 | 1, 1) => // ok
|
||||
case (2, 1) => if (rType.isSigned) return compile16x16BitMultiplyToHL(ctx, l, r)
|
||||
case (1, 1) => // ok
|
||||
case _ => ctx.log.fatal("Invalid code path", l.position)
|
||||
}
|
||||
ctx.env.eval(r) match {
|
||||
|
@ -814,4 +814,56 @@ class WordMathSuite extends FunSuite with Matchers with AppendedClues {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test("Signed multiplication with type promotion") {
|
||||
for {
|
||||
(t1, t2) <- Seq("sbyte" -> "word", "sbyte" -> "signed16", "byte" -> "signed16", "signed16" -> "word")
|
||||
x <- Seq(0, -1, 1, 120, -120)
|
||||
x2 <- Seq(0, -1, 1, 120, -120)
|
||||
} {
|
||||
val x1 = if (t1 == "byte") x & 0xff else x
|
||||
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(
|
||||
s"""
|
||||
| import zp_reg
|
||||
| signed16 output @$$c000
|
||||
| bool typeOk @$$c002
|
||||
| void main () {
|
||||
| $t1 v1
|
||||
| v1 = $x1
|
||||
| $t2 v2
|
||||
| v2 = $x2
|
||||
| memory_barrier()
|
||||
| output = v1 * v2
|
||||
| typeOk = typeof(v1 * v2) == typeof(signed16)
|
||||
| }""".
|
||||
stripMargin) { m =>
|
||||
m.readWord(0xc000).toShort should equal((x1 * x2).toShort) withClue s"= $t1($x1) * $t2($x2)"
|
||||
m.readByte(0xc002) should equal(1) withClue s"= typeof($t1 * $t2)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test("Signed multiplication with type promotion 2") {
|
||||
for {
|
||||
t2 <- Seq("sbyte", "signed16", "byte", "word")
|
||||
x1 <- Seq(0, -1, 1, 120, -120)
|
||||
x <- Seq(0, -1, 1, 120, -120)
|
||||
} {
|
||||
val x2 = if (t2.startsWith("s")) x else if (t2.startsWith("w")) x & 0xffff else x & 0xff
|
||||
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(
|
||||
s"""
|
||||
| import zp_reg
|
||||
| signed16 output @$$c000
|
||||
| void main () {
|
||||
| output = $x1
|
||||
| $t2 v2
|
||||
| v2 = $x2
|
||||
| memory_barrier()
|
||||
| output *= v2
|
||||
| }""".
|
||||
stripMargin) { m =>
|
||||
m.readWord(0xc000).toShort should equal((x1 * x2).toShort) withClue s"= signed16($x1) * $t2($x2)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user