1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-05-31 18:41:30 +00:00
millfork/src/main/scala/millfork/env/Constant.scala
2021-11-12 02:44:20 +01:00

809 lines
30 KiB
Scala

package millfork.env
import millfork.CompilationOptions
import millfork.DecimalUtils._
import millfork.node.{ResolvedFieldDesc, SumExpression}
import millfork.output.DivisibleAlignment
import scala.collection.GenTraversableOnce
object Constant {
val Zero: Constant = NumericConstant(0, 1)
val WordZero: Constant = NumericConstant(0, 2)
val One: Constant = NumericConstant(1, 1)
def apply(i: Long): Constant = NumericConstant(i, minimumSize(i))
def minimumSize(value: Long): Int = if (value < -128 || value > 255) 2 else 1 // TODO !!!
}
import millfork.env.Constant.minimumSize
import millfork.error.ConsoleLogger
import millfork.node.Position
sealed trait Constant {
def toIntelString: String
def isQuiteNegative: Boolean = false
def isProvablyZero: Boolean = false
def isProvably(value: Int): Boolean = false
def isProvablyInRange(startInclusive: Int, endInclusive: Int): Boolean = false
def isProvablyNonnegative: Boolean = false
def isProvablyNegative(asType: Type): Boolean = false
final def isProvablyGreaterOrEqualThan(other: Int): Boolean = isProvablyGreaterOrEqualThan(Constant(other))
def isProvablyGreaterOrEqualThan(other: Constant): Boolean = other match {
case NumericConstant(0, _) => true
case _ => false
}
def fitsProvablyIntoByte: Boolean = false
def isProvablyDivisibleBy256: Boolean = false
def asl(i: Constant): Constant = i match {
case NumericConstant(sa, _) => asl(sa.toInt)
case _ => CompoundConstant(MathOperator.Shl, this, i)
}
def asl(i: Int): Constant = CompoundConstant(MathOperator.Shl, this, NumericConstant(i, requiredSize + i/8))
def requiredSize: Int
def +(that: Constant): Constant = CompoundConstant(MathOperator.Plus, this, that)
def *(scale: Int): Constant = CompoundConstant(MathOperator.Times, this, NumericConstant(scale, Constant.minimumSize(scale) min 2)).quickSimplify
def -(that: Constant): Constant = CompoundConstant(MathOperator.Minus, this, that)
def +(that: Long): Constant = if (that == 0) this else this + NumericConstant(that, minimumSize(that))
def -(that: Long): Constant = if (that == 0) this else this - NumericConstant(that, minimumSize(that))
def loByte: Constant = {
if (requiredSize == 1) return this
if (isProvablyDivisibleBy256) Constant.Zero else SubbyteConstant(this, 0)
}
def hiByte: Constant = {
if (requiredSize == 1) Constant.Zero
else SubbyteConstant(this, 1)
}
def subbyte(index: Int): Constant = {
if (requiredSize > 0 && requiredSize <= index) Constant.Zero
else index match {
case 0 => if (isProvablyDivisibleBy256) Constant.Zero else loByte
case 1 => hiByte
case _ => SubbyteConstant(this, index)
}
}
def subbyteBe(index: Int, totalSize: Int): Constant = subbyte(totalSize - 1 - index)
def subword(index: Int): Constant = {
if (requiredSize <= index) Constant.Zero
else if (requiredSize == 2 && !this.isInstanceOf[StructureConstant]) this
else {
// TODO: check if ok
CompoundConstant(MathOperator.Or, CompoundConstant(MathOperator.Shl, subbyte(index + 1), NumericConstant(8, 2)), subbyte(index)).quickSimplify
}
}
def subwordReversed(index: Int): Constant = {
if (requiredSize <= index) Constant.Zero
else if (requiredSize == 2 && !this.isInstanceOf[StructureConstant]) this
else {
// TODO: check if ok
CompoundConstant(MathOperator.Or, CompoundConstant(MathOperator.Shl, subbyte(index), NumericConstant(8, 2)), subbyte(index + 1)).quickSimplify
}
}
def subconstant(options: CompilationOptions, offset: Int, length: Int): Constant = {
if (offset == 0 && length == requiredSize) {
this
} else if (options.platform.isBigEndian && length == 1) {
// TODO: is this ok?
subbyteBe(offset, requiredSize)
} else if (length == 1) {
subbyte(offset)
} else if (offset >= requiredSize) {
Constant.Zero
} else if (options.platform.isBigEndian) {
// TODO: is this ok?
(0 until length).map { i =>
val index = i + offset
val shift = 8 * (length - i)
CompoundConstant(MathOperator.Shl, subbyteBe(index, requiredSize), NumericConstant(shift, 1)).quickSimplify
}.reduceLeft((l, r) => CompoundConstant(MathOperator.Or, l, r).quickSimplify).quickSimplify
} else {
((length - 1) to 0 by (-1)).map { i =>
val index = i + offset
if (i == 0) subbyte(index) else CompoundConstant(MathOperator.Shl, subbyte(index), NumericConstant(8 * i, 1))
}.reduceLeft((l, r) => CompoundConstant(MathOperator.Or, l, r).quickSimplify).quickSimplify
}
}
def isLowestByteAlwaysEqual(i: Int) : Boolean = false
def quickSimplify: Constant = this
def isRelatedTo(v: Thing): Boolean
def refersTo(name: String): Boolean
def extractLabels: List[String]
def fitsInto(typ: Type): Boolean = true // TODO
def fitInto(typ: Type): Constant = {
// TODO:
typ.size match {
case 1 =>
loByte.quickSimplify match {
case NumericConstant(value, 1) =>
if (typ.isSigned) NumericConstant(value.toByte, 1)
else NumericConstant(value & 0xff, 1)
case CompoundConstant(MathOperator.Minus, NumericConstant(l, _), NumericConstant(r, _)) =>
val value = l - r
if (typ.isSigned) NumericConstant(value.toByte, 1)
else NumericConstant(value & 0xff, 1)
case b => b
}
case 2 =>
subword(0).quickSimplify match {
case NumericConstant(value, _) =>
if (typ.isSigned) NumericConstant(value.toShort, 2)
else NumericConstant(value & 0xffff, 2)
case CompoundConstant(MathOperator.Minus, NumericConstant(l, _), NumericConstant(r, _)) =>
val value = l - r
if (typ.isSigned) NumericConstant(value.toShort, 2)
else NumericConstant(value & 0xffff, 2)
case w => w
}
case _ => this
}
}
def fitInto(sourceType: Type, targetType: Type): Constant = {
val fit0 = fitInto(sourceType)
if (sourceType.size >= targetType.size) fit0 else {
fit0 match {
case NumericConstant(n, _) => NumericConstant(n, targetType.size)
case _ => fit0
}
}
}
final def succ: Constant = (this + 1).quickSimplify
def rootThingName: String
}
case class AssertByte(c: Constant) extends Constant {
override def isQuiteNegative: Boolean = c.isQuiteNegative
override def isProvablyGreaterOrEqualThan(other: Constant): Boolean = c.isProvablyGreaterOrEqualThan(other)
override def isProvablyZero: Boolean = c.isProvablyZero
override def isProvably(i: Int): Boolean = c.isProvably(i)
override def isProvablyNonnegative: Boolean = c.isProvablyNonnegative
override def isProvablyNegative(asType: Type): Boolean = c.isProvablyNegative(asType)
override def isProvablyInRange(startInclusive: Int, endInclusive: Int): Boolean = c.isProvablyInRange(startInclusive, endInclusive)
override def fitsProvablyIntoByte: Boolean = true
override def requiredSize: Int = 1
override def isRelatedTo(v: Thing): Boolean = c.isRelatedTo(v)
override def refersTo(name: String): Boolean = c.refersTo(name)
override def quickSimplify: Constant = AssertByte(c.quickSimplify)
override def fitsInto(typ: Type): Boolean = true
override def toIntelString: String = c.toIntelString
override def rootThingName: String = c.rootThingName
override def extractLabels: List[String] = c.extractLabels
}
case class StructureConstant(typ: StructType, fields: List[Constant]) extends Constant {
override def toIntelString: String = typ.name + fields.map(_.toIntelString).mkString("(",",",")")
override def toString: String = typ.name + fields.map(_.toString).mkString("(",",",")")
override def requiredSize: Int = typ.size
override def isRelatedTo(v: Thing): Boolean = fields.exists(_.isRelatedTo(v))
override def refersTo(name: String): Boolean = typ.name == name || fields.exists(_.refersTo(name))
override def loByte: Constant = subbyte(0)
override def hiByte: Constant = subbyte(1)
override def subbyte(index: Int): Constant = {
var offset = 0
for ((fv, ResolvedFieldDesc(ft, _, _, arrayIndexTypeAndSize)) <- fields.zip(typ.mutableFieldsWithTypes)) {
// TODO: handle array members?
val fs = ft.size
if (index < offset + fs) {
val indexInField = index - offset
return fv.subbyte(indexInField)
}
offset += fs * arrayIndexTypeAndSize.fold(1)(_._2)
}
Constant.Zero
}
override def subbyteBe(index: Int, totalSize: Int): Constant = {
var offset = 0
for ((fv, ResolvedFieldDesc(ft, _, _, arrayIndexTypeAndSize)) <- fields.zip(typ.mutableFieldsWithTypes)) {
// TODO: handle array members?
val fs = ft.size
if (index < offset + fs) {
val indexInField = index - offset
return fv.subbyteBe(indexInField, fs)
}
offset += fs * arrayIndexTypeAndSize.fold(1)(_._2)
}
Constant.Zero
}
override def rootThingName: String = "?"
override def extractLabels: List[String] = this.fields.flatMap(_.extractLabels)
}
case class UnexpandedConstant(name: String, requiredSize: Int) extends Constant {
override def isRelatedTo(v: Thing): Boolean = false
override def toString: String = name
override def toIntelString: String = name
override def refersTo(name: String): Boolean = name == this.name
override def rootThingName: String = "?"
override def extractLabels: List[String] = Nil
}
case class NumericConstant(value: Long, requiredSize: Int) extends Constant {
if (requiredSize == 1) {
if (value < -128 || value > 255) {
throw ConstantOverflowException(value, requiredSize)
}
}
override def isQuiteNegative: Boolean = value < 0
override def isProvablyGreaterOrEqualThan(other: Constant): Boolean = value >= 0 && (other match {
case NumericConstant(o, _) if o >= 0 => value >= o
case _ => false
})
override def isProvablyInRange(startInclusive: Int, endInclusive: Int): Boolean = value >= startInclusive && value <= endInclusive
override def isProvablyZero: Boolean = value == 0
override def isProvably(i: Int): Boolean = value == i
override def isProvablyNonnegative: Boolean = value >= 0
override def isProvablyNegative(asType: Type): Boolean = {
if (!asType.isSigned) return false
if (asType.size >= 8) return value < 0
value.&(0x1L.<<(8 * asType.size - 1)) != 0
}
override def fitsProvablyIntoByte: Boolean = requiredSize == 1
override def isProvablyDivisibleBy256: Boolean = (value & 0xff) == 0
override def isLowestByteAlwaysEqual(i: Int) : Boolean = (value & 0xff) == (i&0xff)
override def asl(i: Int): Constant = {
val newSize = requiredSize + i / 8
val mask = (1 << (8 * newSize)) - 1
NumericConstant((value << i) & mask, newSize)
}
override def +(that: Constant): Constant = that + value
override def +(that: Long) = NumericConstant(value + that, minimumSize(value + that))
override def -(that: Long) = NumericConstant(value - that, minimumSize(value - that))
override def toString: String = if (value > 9) value.formatted("$%X") else value.toString
override def toIntelString: String = if (value > 9) {
val tmp = value.formatted("%Xh")
if (tmp(0) > '9') "0" + tmp else tmp
} else value.toString
override def isRelatedTo(v: Thing): Boolean = false
override def refersTo(name: String): Boolean = false
override def fitsInto(typ: Type): Boolean = {
if (typ.isSigned) {
typ.size match {
case 1 => value == value.toByte
case 2 => value == value.toShort
case 3 => value == ((value.toInt << 8) >> 8)
case 4 => value == value.toInt
case _ => true
}
} else {
typ.size match {
case 1 => value == (value & 0xff)
case 2 => value == (value & 0xffff)
case 3 => value == (value & 0xffffff)
case 4 => value == (value & 0xffffffffL)
case _ => true
}
}
}
override def fitInto(typ: Type): Constant = {
if (typ.size >= 8) {
return NumericConstant(value, typ.size)
}
val actualBits = 1L.<<(8 * typ.size).-(1).&(value)
if (isProvablyNegative(typ)) {
val sx = (-1L).<<(8 * typ.size)
NumericConstant(sx | actualBits, typ.size)
} else {
NumericConstant(actualBits, typ.size)
}
}
override def rootThingName: String = ""
override def extractLabels: List[String] = Nil
}
case class MemoryAddressConstant(var thing: ThingInMemory) extends Constant {
override def isProvablyNonnegative: Boolean = true
override def isProvablyGreaterOrEqualThan(other: Constant): Boolean = other match {
case NumericConstant(0, _) => true
case MemoryAddressConstant(otherThing) => thing == otherThing
case CompoundConstant(MathOperator.Plus, MemoryAddressConstant(otherThing), c) =>
thing == otherThing && c.isProvablyNonnegative
case CompoundConstant(MathOperator.Plus, c, MemoryAddressConstant(otherThing)) =>
thing == otherThing && c.isProvablyNonnegative
case _ => false
}
override def isProvablyDivisibleBy256: Boolean = thing match {
case t: PreallocableThing => t.alignment match {
case DivisibleAlignment(divisor) => divisor.&(0xff) == 0
case _ => false
}
case t: UninitializedMemory => t.alignment match {
case DivisibleAlignment(divisor) => divisor.&(0xff) == 0
case _ => false
}
case _ => false
}
override def fitsProvablyIntoByte: Boolean = thing.zeropage // TODO: check if it's true only on 6502
override def requiredSize = 2
override def toString: String = thing.name
override def toIntelString: String = thing.name
override def isRelatedTo(v: Thing): Boolean = thing.name == v.name
override def refersTo(name: String): Boolean = name == thing.name
override def rootThingName: String = thing.rootName
override def extractLabels: List[String] = thing match {
case Label(n) => List(n)
case _ => Nil
}
}
case class SubbyteConstant(base: Constant, index: Int) extends Constant {
override def quickSimplify: Constant = {
val simplified = base.quickSimplify
simplified match {
case NumericConstant(x, size) => if (index != 0 && index >= size) {
Constant.Zero
} else {
NumericConstant((x >> (index * 8)) & 0xff, 1)
}
case _ =>
if (index == 0 && simplified.isProvablyDivisibleBy256) Constant.Zero
else SubbyteConstant(simplified, index)
}
}
override def requiredSize = 1
override def isProvablyNonnegative: Boolean = true
override def fitsProvablyIntoByte: Boolean = true
override def isProvablyDivisibleBy256: Boolean = index == 0 && base.isProvablyDivisibleBy256
override def toString: String = index match {
case 0 => s"lo($base)"
case 1 => s"hi($base)"
case i => s"b$i($base)"
}
override def toIntelString: String = index match {
case 0 => s"lo(${base.toIntelString})"
case 1 => s"hi(${base.toIntelString})"
case i => s"b$i(${base.toIntelString})"
}
override def isRelatedTo(v: Thing): Boolean = base.isRelatedTo(v)
override def refersTo(name: String): Boolean = base.refersTo(name)
override def rootThingName: String = base.rootThingName
override def extractLabels: List[String] = base.extractLabels
}
object MathOperator extends Enumeration {
val Plus, Minus, Times, Shl, Shr, Shl9, Shr9, Plus9, DecimalPlus9,
DecimalPlus, DecimalMinus, DecimalTimes, DecimalShl, DecimalShl9, DecimalShr,
Equal, NotEqual, Less, LessEqual, Greater, GreaterEqual,
Minimum, Maximum,
Divide, Modulo,
And, Or, Exor = Value
}
case class CompoundConstant(operator: MathOperator.Value, lhs: Constant, rhs: Constant) extends Constant {
override def isQuiteNegative: Boolean = operator match {
case MathOperator.Minus =>
lhs.isQuiteNegative || lhs.isInstanceOf[NumericConstant] && rhs.isInstanceOf[MemoryAddressConstant]
case _ =>
false
}
override def isProvablyNonnegative: Boolean = {
import MathOperator._
operator match {
case Plus | DecimalPlus |
Times | DecimalTimes |
Shl | DecimalShl |
Shl9 | DecimalShl9 |
Shr | DecimalShr |
Divide | Modulo |
And | Or | Exor => lhs.isProvablyNonnegative && rhs.isProvablyNonnegative
case _ => false
}
}
override def isProvablyDivisibleBy256: Boolean = operator match {
case MathOperator.And | MathOperator.Times =>
lhs.isProvablyDivisibleBy256 || rhs.isProvablyDivisibleBy256
case MathOperator.Or | MathOperator.Exor | MathOperator.Plus | MathOperator.Minus =>
lhs.isProvablyDivisibleBy256 && rhs.isProvablyDivisibleBy256
case MathOperator.Shl =>
rhs.isProvablyGreaterOrEqualThan(NumericConstant(8, 1)) || lhs.isProvablyDivisibleBy256
case _ => false
}
override def quickSimplify: Constant = {
val l = lhs.quickSimplify
val r = rhs.quickSimplify
(l, r) match {
case (MemoryAddressConstant(lt), MemoryAddressConstant(rt)) if operator == MathOperator.Minus && lt == rt => Constant.Zero
case (CompoundConstant(MathOperator.Plus, MemoryAddressConstant(lt), c), MemoryAddressConstant(rt)) if operator == MathOperator.Minus && lt == rt => c
case (CompoundConstant(MathOperator.Plus, a, ll@NumericConstant(lv, _)), rr@NumericConstant(rv, _)) if operator == MathOperator.Plus =>
CompoundConstant(MathOperator.Plus, a, ll + rr).quickSimplify
case (CompoundConstant(MathOperator.Minus, a, ll@NumericConstant(lv, _)), rr@NumericConstant(rv, _)) if operator == MathOperator.Minus =>
CompoundConstant(MathOperator.Minus, a, ll + rr).quickSimplify
case (CompoundConstant(MathOperator.Plus, a, ll@NumericConstant(lv, _)), rr@NumericConstant(rv, _)) if operator == MathOperator.Minus =>
if (lv >= rv) {
CompoundConstant(MathOperator.Plus, a, ll - rr).quickSimplify
} else {
CompoundConstant(MathOperator.Minus, a, rr - ll).quickSimplify
}
case (CompoundConstant(MathOperator.Plus, a, ll@NumericConstant(lv, _)), b) if operator == MathOperator.Minus && a == b =>
ll.quickSimplify
case (CompoundConstant(MathOperator.Minus, a, ll@NumericConstant(lv, _)), rr@NumericConstant(rv, _)) if operator == MathOperator.Plus =>
if (lv >= rv) {
CompoundConstant(MathOperator.Minus, a, ll - rr).quickSimplify
} else {
CompoundConstant(MathOperator.Plus, a, rr - ll).quickSimplify
}
case (_, CompoundConstant(MathOperator.Minus, a, b)) if operator == MathOperator.Minus =>
((l + b) - a).quickSimplify
case (_, CompoundConstant(MathOperator.Plus, a, b)) if operator == MathOperator.Minus =>
((l - a) - b).quickSimplify
case (CompoundConstant(MathOperator.Shl, SubbyteConstant(c1, 1), NumericConstant(8, _)), SubbyteConstant(c2, 0))
if operator == MathOperator.Or || operator == MathOperator.Plus && c1 == c2 && c1.requiredSize <= 2 => c1
case (CompoundConstant(MathOperator.Times, SubbyteConstant(c1, 1), NumericConstant(256, _)), SubbyteConstant(c2, 0))
if operator == MathOperator.Or || operator == MathOperator.Plus && c1 == c2 && c1.requiredSize <= 2 => c1
case (CompoundConstant(MathOperator.Times, NumericConstant(256, _), SubbyteConstant(c1, 1)), SubbyteConstant(c2, 0))
if operator == MathOperator.Or || operator == MathOperator.Plus && c1 == c2 && c1.requiredSize <= 2 => c1
case (_, CompoundConstant(MathOperator.DecimalMinus, a, b)) if operator == MathOperator.DecimalPlus =>
CompoundConstant(MathOperator.DecimalMinus, CompoundConstant(MathOperator.DecimalPlus, l, a), b).quickSimplify
case (NumericConstant(0, 1), c) =>
operator match {
case MathOperator.Plus => c
case MathOperator.Plus9 => c
case MathOperator.DecimalPlus => c
case MathOperator.DecimalPlus9 => c
case MathOperator.Minus => c match {
case NumericConstant(rv, rs) => NumericConstant(-rv, rs)
case _ => CompoundConstant(operator, l, r)
}
case MathOperator.Times => Constant.Zero
case MathOperator.Shl => Constant.Zero
case MathOperator.Shr => Constant.Zero
case MathOperator.Shl9 => Constant.Zero
case MathOperator.Shr9 => Constant.Zero
case MathOperator.Exor => c
case MathOperator.Or => c
case MathOperator.And => Constant.Zero
case MathOperator.Divide => Constant.Zero
case MathOperator.Modulo => Constant.Zero
case _ => quickSimplify2(l, r)
}
case (NumericConstant(0, _), c) =>
operator match {
case MathOperator.Shl => l
case MathOperator.Times => l
case _ => quickSimplify2(l, r)
}
case (c, NumericConstant(0, 1)) =>
operator match {
case MathOperator.Plus => c
case MathOperator.Plus9 => c
case MathOperator.DecimalPlus => c
case MathOperator.DecimalPlus9 => c
case MathOperator.Minus => c
case MathOperator.DecimalMinus => c
case MathOperator.Times => Constant.Zero
case MathOperator.Shl => c
case MathOperator.Shr => c
case MathOperator.Shl9 => c
case MathOperator.Shr9 => c
case MathOperator.Exor => c
case MathOperator.Or => c
case MathOperator.And => Constant.Zero
case _ => quickSimplify2(l, r)
}
case (c, NumericConstant(1, 1)) =>
operator match {
case MathOperator.Times => c
case MathOperator.Divide => c
case MathOperator.Modulo => Constant.Zero
case _ => quickSimplify2(l, r)
}
case (NumericConstant(1, 1), c) =>
operator match {
case MathOperator.Times => c
case _ => quickSimplify2(l, r)
}
case _ => quickSimplify2(l, r)
}
}
private def quickSimplify2(l: Constant, r: Constant): Constant = (l, r) match {
case (NumericConstant(lv, ls), NumericConstant(rv, rs)) =>
var size = ls max rs
val bitmask = (1L << (8*size)) - 1
val value = operator match {
case MathOperator.Minimum => lv min rv
case MathOperator.Maximum => lv max rv
case MathOperator.Plus => lv + rv
case MathOperator.Minus =>
val tmp = lv - rv
if (size == 1 && (tmp < -128 || tmp > 255) ) return l.quickSimplify - r.quickSimplify
tmp
case MathOperator.Times => lv * rv
case MathOperator.Shl => lv << rv
case MathOperator.Shr => lv >> rv
case MathOperator.Shl9 => (lv << rv) & 0x1ff
case MathOperator.Plus9 => (lv + rv) & 0x1ff
case MathOperator.Shr9 => (lv & 0x1ff) >> rv
case MathOperator.Exor => (lv ^ rv) & bitmask
case MathOperator.Or => lv | rv
case MathOperator.And => lv & rv & bitmask
case MathOperator.Divide if lv >= 0 && rv > 0 => lv / rv
case MathOperator.Modulo if lv >= 0 && rv >= 0 => lv % rv
case MathOperator.DecimalPlus if ls == 1 && rs == 1 =>
asDecimal(lv & 0xff, rv & 0xff, _ + _) & 0xff
case MathOperator.DecimalMinus if ls == 1 && rs == 1 && lv.&(0xff) >= rv.&(0xff) =>
asDecimal(lv & 0xff, rv & 0xff, _ - _) & 0xff
case _ => return this
}
operator match {
case MathOperator.Plus9 | MathOperator.DecimalPlus9 | MathOperator.Shl9 | MathOperator.DecimalShl9 =>
size = 2
case MathOperator.Times | MathOperator.Shl =>
val mask = (1 << (size * 8)) - 1
if (value != (value & mask)) {
size = ls + rs
}
case _ =>
}
NumericConstant(value, size)
case _ => CompoundConstant(operator, l, r)
}
import MathOperator._
override def +(that: Constant): Constant = {
that match {
case NumericConstant(n, _) => this + n
case _ => super.+(that)
}
}
override def -(that: Long): Constant = this + (-that)
override def +(that: Long): Constant = {
if (that == 0) {
return this
}
val That = that
val MinusThat = -that
this match {
case CompoundConstant(Plus, CompoundConstant(Shl, SubbyteConstant(c1, 1), NumericConstant(8, _)), SubbyteConstant(c2, 0)) if c1 == c2 => c1
case CompoundConstant(Plus, NumericConstant(MinusThat, _), r) => r
case CompoundConstant(Plus, l, NumericConstant(MinusThat, _)) => l
case CompoundConstant(Plus, NumericConstant(x, _), r) => CompoundConstant(Plus, r, NumericConstant(x + that, minimumSize(x + that)))
case CompoundConstant(Plus, l, NumericConstant(x, _)) => CompoundConstant(Plus, l, NumericConstant(x + that, minimumSize(x + that)))
case CompoundConstant(Minus, l, NumericConstant(That, _)) => l
case _ => CompoundConstant(Plus, this, NumericConstant(that, minimumSize(that)))
}
}
private def plhs: String = lhs match {
case _: NumericConstant | _: MemoryAddressConstant => lhs.toString
case _ => "(" + lhs + ')'
}
private def prhs: String = lhs match {
case _: NumericConstant | _: MemoryAddressConstant => rhs.toString
case _ => "(" + rhs + ')'
}
private def plhis: String = lhs match {
case _: NumericConstant | _: MemoryAddressConstant => lhs.toIntelString
case _ => "(" + lhs.toIntelString + ')'
}
private def prhis: String = lhs match {
case _: NumericConstant | _: MemoryAddressConstant => rhs.toIntelString
case _ => "(" + rhs.toIntelString + ')'
}
override def toString: String = {
operator match {
case Plus => s"$plhs + $prhs"
case Plus9 => s"nonet($plhs + $prhs)"
case Minus => s"$plhs - $prhs"
case Times => s"$plhs * $prhs"
case Shl => s"$plhs << $prhs"
case Shr => s"$plhs >> $prhs"
case Shl9 => s"nonet($plhs << $prhs)"
case Shr9 => s"$plhs >>>> $prhs"
case DecimalPlus => s"$plhs +' $prhs"
case DecimalPlus9 => s"nonet($plhs +' $prhs)"
case DecimalMinus => s"$plhs -' $prhs"
case DecimalTimes => s"$plhs *' $prhs"
case DecimalShl => s"$plhs <<' $prhs"
case DecimalShl9 => s"nonet($plhs <<' $prhs)"
case DecimalShr => s"$plhs >>' $prhs"
case And => s"$plhs & $prhs"
case Or => s"$plhs | $prhs"
case Exor => s"$plhs ^ $prhs"
case Divide => s"$plhs / $prhs"
case Modulo => s"$plhs %% $prhs"
case Equal => s"$plhs == $prhs"
case NotEqual => s"$plhs != $prhs"
case Greater => s"$plhs > $prhs"
case GreaterEqual => s"$plhs >= $prhs"
case Less=> s"$plhs < $prhs"
case LessEqual=> s"$plhs <= $prhs"
}
}
override def toIntelString: String = {
operator match {
case Plus => s"$plhis + $prhis"
case Plus9 => s"nonet($plhis + $prhis)"
case Minus => s"$plhis - $prhis"
case Times => s"$plhis * $prhis"
case Shl => s"$plhis << $prhis"
case Shr => s"$plhis >> $prhis"
case Shl9 => s"nonet($plhis << $prhis)"
case Shr9 => s"$plhis >>>> $prhis"
case DecimalPlus => s"$plhis +' $prhis"
case DecimalPlus9 => s"nonet($plhis +' $prhis)"
case DecimalMinus => s"$plhis -' $prhis"
case DecimalTimes => s"$plhis *' $prhis"
case DecimalShl => s"$plhis <<' $prhis"
case DecimalShl9 => s"nonet($plhis <<' $prhis)"
case DecimalShr => s"$plhis >>' $prhis"
case And => s"$plhis & $prhis"
case Or => s"$plhis | $prhis"
case Exor => s"$plhis ^ $prhis"
case Divide => s"$plhs / $prhs"
case Modulo => s"$plhs %% $prhs"
}
}
override def requiredSize: Int = {
import MathOperator._
operator match {
case Plus9 | DecimalPlus9 | Shl9 | DecimalShl9 => 2
case Times | Shl =>
// TODO
lhs.requiredSize max rhs.requiredSize
case _ => lhs.requiredSize max rhs.requiredSize
}
}
override def fitsProvablyIntoByte: Boolean = {
import MathOperator._
operator match {
case And => lhs.fitsProvablyIntoByte || rhs.fitsProvablyIntoByte
case Or | Exor => lhs.fitsProvablyIntoByte && rhs.fitsProvablyIntoByte
case Shr | Shr9 => lhs.fitsProvablyIntoByte
case Plus => (lhs, rhs) match {
case (MemoryAddressConstant(thing), offset) => thing.name == "__reg" && offset.fitsProvablyIntoByte
case (offset, MemoryAddressConstant(thing)) => thing.name == "__reg" && offset.fitsProvablyIntoByte
case _ => false
}
case Minus => (lhs, rhs) match {
case (MemoryAddressConstant(thing), offset) => thing.name == "__reg" && offset.fitsProvablyIntoByte
case _ => false
}
case _ => false
}
}
override def isRelatedTo(v: Thing): Boolean = lhs.isRelatedTo(v) || rhs.isRelatedTo(v)
override def refersTo(name: String): Boolean = lhs.refersTo(name) || rhs.refersTo(name)
override def subbyte(index: Int): Constant = {
if (index != 0) return super.subbyte(index)
operator match {
case MathOperator.Minus if lhs.isProvablyZero => ((lhs+256)-rhs).quickSimplify.subbyte(0).quickSimplify
case MathOperator.Shl if rhs.isProvablyGreaterOrEqualThan(8) => Constant.Zero
case _ => super.subbyte(index)
}
}
override def loByte: Constant = {
val result = operator match {
case MathOperator.Minus if lhs.isProvablyZero =>
((lhs+256)-rhs).quickSimplify.loByte.quickSimplify
case MathOperator.Shl if rhs.isProvablyGreaterOrEqualThan(8) => Constant.Zero
case _ => super.loByte
}
result
}
override def rootThingName: String = (lhs.rootThingName, rhs.rootThingName) match {
case ("?", _) => "?"
case (_, "?") => "?"
case ("", x) => x
case (x, "") => x
case _ => "?"
}
override def extractLabels: List[String] = lhs.extractLabels ++ rhs.extractLabels
}
case class IfConstant(cond: Constant, ifTrue: Constant, ifFalse: Constant) extends Constant {
override def toIntelString: String = s"if(${cond.toIntelString},${ifTrue.toIntelString},${ifFalse.toIntelString})"
override def toString: String = s"if(${cond.toString},${ifTrue.toString},${ifFalse.toString})"
override def requiredSize: Int = ifTrue.requiredSize max ifFalse.requiredSize
override def isRelatedTo(v: Thing): Boolean = cond.isRelatedTo(v) || ifTrue.isRelatedTo(v) || ifFalse.isRelatedTo(v)
override def refersTo(name: String): Boolean = cond.refersTo(name) || ifTrue.refersTo(name) || ifFalse.refersTo(name)
override def extractLabels: List[String] = cond.extractLabels ++ ifTrue.extractLabels ++ ifFalse.extractLabels
override def rootThingName: String = "?"
}