1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-06-25 19:29:49 +00:00

Allowed more kinds of constants within variable and array initializers

This commit is contained in:
Karol Stasiak 2018-03-19 21:58:51 +01:00
parent 6f98af3eb7
commit c9c0c16e98
6 changed files with 78 additions and 39 deletions

View File

@ -6,6 +6,8 @@
* `-fzp-register` is now enabled by default, as the documentation has already been saying. * `-fzp-register` is now enabled by default, as the documentation has already been saying.
* Allowed more kinds of constants within variable and array initializers.
* Fixed several bugs. * Fixed several bugs.
* Other improvements. * Other improvements.

View File

@ -53,25 +53,23 @@ object ReturnDispatch {
} }
val returnType = ctx.function.returnType val returnType = ctx.function.returnType
val map = mutable.Map[Int, (Constant, List[Constant])]() val map: mutable.Map[Int, (String, List[Expression])] = mutable.Map()
var min = Option.empty[Int] var min = Option.empty[Int]
var max = Option.empty[Int] var max = Option.empty[Int]
var default = Option.empty[(Constant, List[Constant])] var default = Option.empty[(String, List[Expression])]
stmt.branches.foreach { branch => stmt.branches.foreach { branch =>
val function = ctx.env.evalForAsm(branch.function).getOrElse { val function: String = ctx.env.evalForAsm(branch.function) match {
ErrorReporting.error("Undefined function or Non-constant function address for dispatch branch", branch.function.position) case Some(MemoryAddressConstant(f: FunctionInMemory)) =>
Constant.Zero if (f.returnType.name != returnType.name) {
ErrorReporting.warn(s"Dispatching to a function of different return type: dispatcher return type: ${returnType.name}, dispatchee return type: ${f.returnType.name}", ctx.options, branch.function.position)
}
f.name
case _ =>
ErrorReporting.error("Undefined function or Non-constant function address for dispatch branch", branch.function.position)
""
} }
if (returnType.name != "void") { branch.params.foreach(toConstant)
function match { val params = branch.params
case MemoryAddressConstant(f: FunctionInMemory) =>
if (f.returnType.name != returnType.name) {
ErrorReporting.warn(s"Dispatching to a function of different return type: dispatcher return type: ${returnType.name}, dispatchee return type: ${f.returnType.name}", ctx.options, branch.function.position)
}
case _ => ()
}
}
val params = branch.params.map(toConstant)
if (params.length > stmt.params.length) { if (params.length > stmt.params.length) {
ErrorReporting.error("Too many parameters for dispatch branch", branch.params.head.position) ErrorReporting.error("Too many parameters for dispatch branch", branch.params.head.position)
} }
@ -102,7 +100,7 @@ object ReturnDispatch {
} }
val actualMin = defaultMin min nonDefaultMin.getOrElse(defaultMin) val actualMin = defaultMin min nonDefaultMin.getOrElse(defaultMin)
val actualMax = defaultMax max nonDefaultMax.getOrElse(defaultMax) val actualMax = defaultMax max nonDefaultMax.getOrElse(defaultMax)
val zeroes = Constant.Zero -> List[Constant]() val zeroes = "" -> List[Expression]()
for (i <- actualMin to actualMax) { for (i <- actualMin to actualMax) {
if (!map.contains(i)) map(i) = default.getOrElse { if (!map.contains(i)) map(i) = default.getOrElse {
// TODO: warning? // TODO: warning?
@ -125,7 +123,7 @@ object ReturnDispatch {
val label = MfCompiler.nextLabel("di") val label = MfCompiler.nextLabel("di")
val paramArrays = stmt.params.indices.map { ix => val paramArrays = stmt.params.indices.map { ix =>
val a = InitializedArray(label + "$" + ix + ".array", None, (paramMins(ix) to paramMaxes(ix)).map { key => val a = InitializedArray(label + "$" + ix + ".array", None, (paramMins(ix) to paramMaxes(ix)).map { key =>
map(key)._2.lift(ix).getOrElse(Constant.Zero) map(key)._2.lift(ix).getOrElse(LiteralExpression(0, 1))
}.toList, }.toList,
ctx.function.declaredBank) ctx.function.declaredBank)
env.registerUnnamedArray(a) env.registerUnnamedArray(a)
@ -147,7 +145,7 @@ object ReturnDispatch {
} }
if (useJmpaix) { if (useJmpaix) {
val jumpTable = InitializedArray(label + "$jt.array", None, (actualMin to actualMax).flatMap(i => List(map(i)._1.loByte, map(i)._1.hiByte)).toList, ctx.function.declaredBank) val jumpTable = InitializedArray(label + "$jt.array", None, (actualMin to actualMax).flatMap(i => List(lobyte0(map(i)._1), hibyte0(map(i)._1))).toList, ctx.function.declaredBank)
env.registerUnnamedArray(jumpTable) env.registerUnnamedArray(jumpTable)
if (copyParams.isEmpty) { if (copyParams.isEmpty) {
val loadIndex = ExpressionCompiler.compile(ctx, stmt.indexer, Some(b -> RegisterVariable(Register.A, b)), BranchSpec.None) val loadIndex = ExpressionCompiler.compile(ctx, stmt.indexer, Some(b -> RegisterVariable(Register.A, b)), BranchSpec.None)
@ -162,8 +160,8 @@ object ReturnDispatch {
} }
} else { } else {
val loadIndex = ExpressionCompiler.compile(ctx, stmt.indexer, Some(b -> RegisterVariable(Register.X, b)), BranchSpec.None) val loadIndex = ExpressionCompiler.compile(ctx, stmt.indexer, Some(b -> RegisterVariable(Register.X, b)), BranchSpec.None)
val jumpTableLo = InitializedArray(label + "$jl.array", None, (actualMin to actualMax).map(i => (map(i)._1 - 1).loByte).toList, ctx.function.declaredBank) val jumpTableLo = InitializedArray(label + "$jl.array", None, (actualMin to actualMax).map(i => lobyte1(map(i)._1)).toList, ctx.function.declaredBank)
val jumpTableHi = InitializedArray(label + "$jh.array", None, (actualMin to actualMax).map(i => (map(i)._1 - 1).hiByte).toList, ctx.function.declaredBank) val jumpTableHi = InitializedArray(label + "$jh.array", None, (actualMin to actualMax).map(i => hibyte1(map(i)._1)).toList, ctx.function.declaredBank)
env.registerUnnamedArray(jumpTableLo) env.registerUnnamedArray(jumpTableLo)
env.registerUnnamedArray(jumpTableHi) env.registerUnnamedArray(jumpTableHi)
loadIndex ++ copyParams ++ List( loadIndex ++ copyParams ++ List(
@ -174,4 +172,20 @@ object ReturnDispatch {
AssemblyLine.implied(RTS)) AssemblyLine.implied(RTS))
} }
} }
private def lobyte0(fname: String): Expression = if (fname == "") LiteralExpression(0, 1) else {
FunctionCallExpression("lo",List(VariableExpression(fname + ".addr")))
}
private def hibyte0(fname: String): Expression = if (fname == "") LiteralExpression(0, 1) else {
FunctionCallExpression("hi",List(VariableExpression(fname + ".addr")))
}
private def lobyte1(fname: String): Expression = if (fname == "") LiteralExpression(0, 1) else {
FunctionCallExpression("lo", List(SumExpression(List(false -> VariableExpression(fname + ".addr"), true -> LiteralExpression(1, 1)), decimal = false)))
}
private def hibyte1(fname: String): Expression = if (fname == "") LiteralExpression(0, 1) else {
FunctionCallExpression("hi", List(SumExpression(List(false -> VariableExpression(fname + ".addr"), true -> LiteralExpression(1, 1)), decimal = false)))
}
} }

View File

@ -348,6 +348,20 @@ class Environment(val parent: Option[Environment], val prefix: String) {
} yield hc.asl(8) + lc } yield hc.asl(8) + lc
case FunctionCallExpression(name, params) => case FunctionCallExpression(name, params) =>
name match { name match {
case "hi" =>
if (params.size == 1) {
eval(params.head).map(_.hiByte.quickSimplify)
} else {
ErrorReporting.error("Invalid number of parameters for `hi`", e.position)
None
}
case "lo" =>
if (params.size == 1) {
eval(params.head).map(_.loByte.quickSimplify)
} else {
ErrorReporting.error("Invalid number of parameters for `lo`", e.position)
None
}
case "nonet" => case "nonet" =>
params match { params match {
case List(FunctionCallExpression("<<", ps@List(_, _))) => case List(FunctionCallExpression("<<", ps@List(_, _))) =>
@ -358,7 +372,10 @@ class Environment(val parent: Option[Environment], val prefix: String) {
constantOperation(MathOperator.Plus9, ps.map(_._2)) constantOperation(MathOperator.Plus9, ps.map(_._2))
case List(SumExpression(ps@List((true,_),(true,_)), true)) => case List(SumExpression(ps@List((true,_),(true,_)), true)) =>
constantOperation(MathOperator.DecimalPlus9, ps.map(_._2)) constantOperation(MathOperator.DecimalPlus9, ps.map(_._2))
case List(_) =>
None
case _ => case _ =>
ErrorReporting.error("Invalid number of parameters for `nonet`", e.position)
None None
} }
case ">>'" => case ">>'" =>
@ -660,9 +677,7 @@ class Environment(val parent: Option[Environment], val prefix: String) {
val length = contents.length val length = contents.length
if (length > 0xffff || length < 0) ErrorReporting.error(s"Array `${stmt.name}` has invalid length", stmt.position) if (length > 0xffff || length < 0) ErrorReporting.error(s"Array `${stmt.name}` has invalid length", stmt.position)
val address = stmt.address.map(a => eval(a).getOrElse(Constant.error(s"Array `${stmt.name}` has non-constant address", stmt.position))) val address = stmt.address.map(a => eval(a).getOrElse(Constant.error(s"Array `${stmt.name}` has non-constant address", stmt.position)))
val data = contents.map(x => eval(x).getOrElse(Constant.error(s"Array `${stmt.name}` has non-constant contents", stmt.position))) val array = InitializedArray(stmt.name + ".array", address, contents, declaredBank = stmt.bank)
val array = InitializedArray(stmt.name + ".array", address, data,
declaredBank = stmt.bank)
addThing(array, stmt.position) addThing(array, stmt.position)
registerAddressConstant(UninitializedMemoryVariable(stmt.name, p, VariableAllocationMethod.None, registerAddressConstant(UninitializedMemoryVariable(stmt.name, p, VariableAllocationMethod.None,
declaredBank = stmt.bank), stmt.position) declaredBank = stmt.bank), stmt.position)
@ -748,9 +763,7 @@ class Environment(val parent: Option[Environment], val prefix: String) {
if (options.flags(CompilationFlag.ReadOnlyArrays)) { if (options.flags(CompilationFlag.ReadOnlyArrays)) {
ErrorReporting.warn("Initialized variable in read-only segment", options, position) ErrorReporting.warn("Initialized variable in read-only segment", options, position)
} }
val ivc = eval(ive).getOrElse(Constant.error(s"Initial value of `$name` is not a constant", position)) InitializedMemoryVariable(name, None, typ, ive, declaredBank = stmt.bank)
InitializedMemoryVariable(name, None, typ, ivc,
declaredBank = stmt.bank)
} }
registerAddressConstant(v, stmt.position) registerAddressConstant(v, stmt.position)
(v, v.toAddress) (v, v.toAddress)
@ -815,8 +828,7 @@ class Environment(val parent: Option[Environment], val prefix: String) {
def collectDeclarations(program: Program, options: CompilationOptions): Unit = { def collectDeclarations(program: Program, options: CompilationOptions): Unit = {
if (options.flag(CompilationFlag.OptimizeForSonicSpeed)) { if (options.flag(CompilationFlag.OptimizeForSonicSpeed)) {
addThing(InitializedArray("identity$", None, List.tabulate(256)(n => NumericConstant(n, 1)), addThing(InitializedArray("identity$", None, List.tabulate(256)(n => LiteralExpression(n, 1)), declaredBank = None), None)
declaredBank = None), None)
} }
program.declarations.foreach { program.declarations.foreach {
case f: FunctionDeclarationStatement => registerFunction(f, options) case f: FunctionDeclarationStatement => registerFunction(f, options)
@ -838,8 +850,7 @@ class Environment(val parent: Option[Environment], val prefix: String) {
address = None), options) address = None), options)
} }
if (!things.contains("__constant8")) { if (!things.contains("__constant8")) {
things("__constant8") = InitializedArray("__constant8", None, List(NumericConstant(8, 1)), things("__constant8") = InitializedArray("__constant8", None, List(LiteralExpression(8, 1)), declaredBank = None)
declaredBank = None)
} }
} }

View File

@ -155,7 +155,7 @@ case class UninitializedMemoryVariable(name: String, typ: Type, alloc: VariableA
override def toAddress: MemoryAddressConstant = MemoryAddressConstant(this) override def toAddress: MemoryAddressConstant = MemoryAddressConstant(this)
} }
case class InitializedMemoryVariable(name: String, address: Option[Constant], typ: Type, initialValue: Constant, declaredBank: Option[String]) extends MemoryVariable with PreallocableThing { case class InitializedMemoryVariable(name: String, address: Option[Constant], typ: Type, initialValue: Expression, declaredBank: Option[String]) extends MemoryVariable with PreallocableThing {
override def zeropage: Boolean = false override def zeropage: Boolean = false
override def toAddress: MemoryAddressConstant = MemoryAddressConstant(this) override def toAddress: MemoryAddressConstant = MemoryAddressConstant(this)
@ -185,7 +185,7 @@ case class RelativeArray(name: String, address: Constant, sizeInBytes: Int, decl
override def bank(compilationOptions: CompilationOptions): String = declaredBank.getOrElse("default") override def bank(compilationOptions: CompilationOptions): String = declaredBank.getOrElse("default")
} }
case class InitializedArray(name: String, address: Option[Constant], contents: List[Constant], declaredBank: Option[String]) extends MfArray with PreallocableThing { case class InitializedArray(name: String, address: Option[Constant], contents: List[Expression], declaredBank: Option[String]) extends MfArray with PreallocableThing {
override def shouldGenerate = true override def shouldGenerate = true
override def isFar(compilationOptions: CompilationOptions): Boolean = farFlag.getOrElse(false) override def isFar(compilationOptions: CompilationOptions): Boolean = farFlag.getOrElse(false)

View File

@ -1,7 +1,7 @@
package millfork.node package millfork.node
import millfork.assembly.{AddrMode, Opcode} import millfork.assembly.{AddrMode, Opcode}
import millfork.env.{Label, ParamPassingConvention} import millfork.env.{Constant, Label, ParamPassingConvention}
case class Position(filename: String, line: Int, column: Int, cursor: Int) case class Position(filename: String, line: Int, column: Int, cursor: Int)

View File

@ -215,7 +215,10 @@ class Assembler(private val program: Program, private val rootEnv: Environment,
assembly.append("* = $" + index.toHexString) assembly.append("* = $" + index.toHexString)
assembly.append(name) assembly.append(name)
for (item <- items) { for (item <- items) {
writeByte(bank, index, item) env.eval(item) match {
case Some(c) => writeByte(bank, index, c)
case None => ErrorReporting.error(s"Non-constant contents of array `$name`")
}
bank0.occupied(index) = true bank0.occupied(index) = true
bank0.initialized(index) = true bank0.initialized(index) = true
bank0.writeable(index) = true bank0.writeable(index) = true
@ -281,7 +284,10 @@ class Assembler(private val program: Program, private val rootEnv: Environment,
assembly.append("* = $" + index.toHexString) assembly.append("* = $" + index.toHexString)
assembly.append(name) assembly.append(name)
for (item <- items) { for (item <- items) {
writeByte(bank, index, item) env.eval(item) match {
case Some(c) => writeByte(bank, index, c)
case None => ErrorReporting.error(s"Non-constant contents of array `$name`")
}
index += 1 index += 1
} }
items.grouped(16).foreach {group => items.grouped(16).foreach {group =>
@ -298,10 +304,16 @@ class Assembler(private val program: Program, private val rootEnv: Environment,
env.things += altName -> ConstantThing(altName, NumericConstant(index, 2), env.get[Type]("pointer")) env.things += altName -> ConstantThing(altName, NumericConstant(index, 2), env.get[Type]("pointer"))
assembly.append("* = $" + index.toHexString) assembly.append("* = $" + index.toHexString)
assembly.append(name) assembly.append(name)
for (i <- 0 until typ.size) { env.eval(value) match {
writeByte(bank, index, value.subbyte(i)) case Some(c) =>
assembly.append(" !byte " + value.subbyte(i).quickSimplify) for (i <- 0 until typ.size) {
index += 1 writeByte(bank, index, c.subbyte(i))
assembly.append(" !byte " + c.subbyte(i).quickSimplify)
index += 1
}
case None =>
ErrorReporting.error(s"Non-constant initial value for variable `$name`")
index += typ.size
} }
initializedVariablesSize += typ.size initializedVariablesSize += typ.size
justAfterCode += bank -> index justAfterCode += bank -> index