1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-07-16 20:29:04 +00:00

Add struct literals

This commit is contained in:
Karol Stasiak 2019-06-25 00:45:49 +02:00
parent 978d97cd7d
commit e394fe15c3
6 changed files with 141 additions and 3 deletions

View File

@ -147,6 +147,12 @@ Offsets are available as `structname.fieldname.offset`:
// alternatively: // alternatively:
ptr = p.y.addr ptr = p.y.addr
You can create constant expressions of struct types using so-called struct constructors, e.g.:
point(5,6)
All arguments to the constructor must be constant.
## Unions ## Unions
union <name> { <field definitions (type and name), separated by commas or newlines>} union <name> { <field definitions (type and name), separated by commas or newlines>}
@ -163,3 +169,5 @@ start at the same point in memory and therefore overlap each other.
if u.w == 0 { ok() } if u.w == 0 { ok() }
Offset constants are also available, but they're obviously all zero. Offset constants are also available, but they're obviously all zero.
Unions currently do not have an equivalent of struct constructors. This may be improved on in the future.

View File

@ -124,6 +124,34 @@ case class AssertByte(c: Constant) extends Constant {
override def toIntelString: String = c.toIntelString override def toIntelString: String = c.toIntelString
} }
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, (ft, _)) <- fields.zip(typ.mutableFieldsWithTypes)) {
val fs = ft.size
if (index < offset + fs) {
return fv.subbyte(index - offset)
}
offset += fs
}
Constant.Zero
}
}
case class UnexpandedConstant(name: String, requiredSize: Int) extends Constant { case class UnexpandedConstant(name: String, requiredSize: Int) extends Constant {
override def isRelatedTo(v: Thing): Boolean = false override def isRelatedTo(v: Thing): Boolean = false

View File

@ -552,6 +552,12 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
case Some(ff: MangledFunction) => case Some(ff: MangledFunction) =>
if (ff.returnType.isSigned) Some(e) -> Constant.Zero if (ff.returnType.isSigned) Some(e) -> Constant.Zero
else variable -> constant else variable -> constant
case Some(t: StructType) =>
// dunno what to do
variable -> constant
case Some(t: UnionType) =>
// dunno what to do
None -> Constant.Zero
case Some(t: Type) => case Some(t: Type) =>
if (t.isSigned) Some(e) -> Constant.Zero if (t.isSigned) Some(e) -> Constant.Zero
else variable -> constant else variable -> constant
@ -745,10 +751,19 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
case "||" | "|" => case "||" | "|" =>
constantOperation(MathOperator.Or, params) constantOperation(MathOperator.Or, params)
case _ => case _ =>
if (params.size == 1) { maybeGet[Type](name) match {
return maybeGet[Type](name).flatMap(_ => eval(params.head)) case Some(t: StructType) =>
if (params.size == t.fields.size) {
sequence(params.map(eval)).map(fields => StructureConstant(t, fields))
} else None
case Some(_: UnionType) =>
None
case Some(_) =>
if (params.size == 1) {
eval(params.head)
} else None
case _ => None
} }
None
} }
} }
}.map(_.quickSimplify) }.map(_.quickSimplify)
@ -1699,6 +1714,21 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
log.error("Cycles in struct definitions found") log.error("Cycles in struct definitions found")
} }
def fixStructFields(): Unit = {
things.values.foreach {
case st@StructType(_, fields) =>
st.mutableFieldsWithTypes = fields.map {
case (tn, name) => get[Type](tn) -> name
}
case ut@UnionType(_, fields) =>
ut.mutableFieldsWithTypes = fields.map {
case (tn, name) => get[Type](tn) -> name
}
case _ => ()
}
}
def collectDeclarations(program: Program, options: CompilationOptions): Unit = { def collectDeclarations(program: Program, options: CompilationOptions): Unit = {
val b = get[VariableType]("byte") val b = get[VariableType]("byte")
val v = get[Type]("void") val v = get[Type]("void")
@ -1719,6 +1749,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
case _ => case _ =>
} }
fixStructSizes() fixStructSizes()
fixStructFields()
val pointies = collectPointies(program.declarations) val pointies = collectPointies(program.declarations)
pointiesUsed("") = pointies pointiesUsed("") = pointies
program.declarations.foreach { program.declarations.foreach {

View File

@ -107,12 +107,14 @@ sealed trait CompoundVariableType extends VariableType
case class StructType(name: String, fields: List[(String, String)]) extends CompoundVariableType { case class StructType(name: String, fields: List[(String, String)]) extends CompoundVariableType {
override def size: Int = mutableSize override def size: Int = mutableSize
var mutableSize: Int = -1 var mutableSize: Int = -1
var mutableFieldsWithTypes: List[(Type, String)] = Nil
override def isSigned: Boolean = false override def isSigned: Boolean = false
} }
case class UnionType(name: String, fields: List[(String, String)]) extends CompoundVariableType { case class UnionType(name: String, fields: List[(String, String)]) extends CompoundVariableType {
override def size: Int = mutableSize override def size: Int = mutableSize
var mutableSize: Int = -1 var mutableSize: Int = -1
var mutableFieldsWithTypes: List[(Type, String)] = Nil
override def isSigned: Boolean = false override def isSigned: Boolean = false
} }

View File

@ -124,6 +124,13 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
if (labelMap.contains(name)) labelMap(name)._2 if (labelMap.contains(name)) labelMap(name)._2
else ??? else ???
case SubbyteConstant(cc, i) => deepConstResolve(cc).>>>(i * 8).&(0xff) case SubbyteConstant(cc, i) => deepConstResolve(cc).>>>(i * 8).&(0xff)
case s: StructureConstant =>
s.typ.size match {
case 0 => 0
case 1 => deepConstResolve(s.subbyte(0))
case 2 => deepConstResolve(s.subword(0))
case _ => ???
}
case CompoundConstant(operator, lc, rc) => case CompoundConstant(operator, lc, rc) =>
val l = deepConstResolve(lc) val l = deepConstResolve(lc)
val r = deepConstResolve(rc) val r = deepConstResolve(rc)

View File

@ -107,4 +107,66 @@ class StructSuite extends FunSuite with Matchers {
m.readByte(0xc400) should equal(1) m.readByte(0xc400) should equal(1)
} }
} }
test("Struct literals") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8086)("""
| struct point { byte x, byte y }
| const point origin = point(1,2)
| noinline point move_right(point p) {
| p.x += 1
| return p
| }
| byte output @$c000
| void main () {
| point p
| p = move_right(origin)
| p = move_right(point(1,2))
| output = p.x
| }
""".stripMargin) { m =>
m.readByte(0xc000) should equal(2)
}
}
test("Struct literals 2") {
val code = """
| struct point { word x, word y }
| const point origin = point(6, 8)
| noinline point move_right(point p) {
| p.x += 1
| return p
| }
| noinline point move_up(point p) {
| p.y += 1
| return p
| }
| word outputX @$c000
| word outputY @$c002
| void main () {
| point p
| p = point(0,0)
| p = move_up(point(0,0))
| p = origin
| p = move_up(p) //
| p = move_right(p) //
| p = move_right(p) //
| p = move_up(p) //
| p = move_right(p) //
| p = move_right(p) //
| p = move_up(p) //
| p = move_up(p) //
| p = move_up(p) //
| p = move_right(p) //
| p = move_up(p) //
| p = move_up(p) //
| p = move_up(p) //
| outputX = p.x
| outputY = p.y
| }
""".stripMargin
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8086)(code){ m =>
m.readWord(0xc000) should equal(code.count(_ == '→') + 6)
m.readWord(0xc002) should equal(code.count(_ == '↑') + 8)
}
}
} }