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

Alias improvements:

– aliases can now override other objects
– take aliases into account when ordering functions for optimizations and inlining
This commit is contained in:
Karol Stasiak 2018-12-19 17:33:51 +01:00
parent 49ee0fd3a2
commit fc10746522
12 changed files with 65 additions and 10 deletions

View File

@ -66,7 +66,7 @@ TODO
### Alias definitions
`alias <alias> = <name>`
`alias <alias> = <name> [!]`
Sets an alias for a global name.
Unless shadowed by a local name, the alias will point to the given global object:
@ -86,6 +86,14 @@ Unless shadowed by a local name, the alias will point to the given global object
Aliases can be used for variables, arrays, constants, functions, and types,
but not for text encodings, array formats or keywords.
If the alias definition is followed by a `!`, then the alias overrides any other definition of that name.
This allows for overriding definitions of library functions by another library:
void f() {}
void g() {}
alias f = g!
// now the original f is removed and all calls to f will call g instead
### Array declarations
An array is a continuous sequence of bytes in memory.

View File

@ -1331,6 +1331,24 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
}
nameCheck(params)
}
def getBooleanConstant(literal: String): Option[Boolean] =
maybeGet[TypedThing](literal).flatMap(_.typ match {
case ConstantBooleanType(_, x) => Some(x)
case _ => None
})
def isAlias(name: String): Boolean = {
things.get(name).map(_.isInstanceOf[Alias]).orElse(parent.map(_.isAlias(name))).getOrElse(false)
}
def getAliases: Map[String, String] = {
things.values.flatMap {
case Alias(a, b, _) => Some(a -> b)
case _ => None
}.toMap ++ parent.map(_.getAliases).getOrElse(Map.empty)
}
}
object Environment {

View File

@ -33,14 +33,18 @@ abstract class CallGraph(program: Program, log: Logger) {
protected val multiaccessibleFunctions = mutable.Set[String]()
protected val everCalledFunctions = mutable.Set[String]()
protected val allFunctions = mutable.Set[String]()
protected val aliases = mutable.Map[String, String]()
entryPoints += "main"
program.declarations.foreach(s => add(None, Nil, s))
everCalledFunctions ++= everCalledFunctions.flatMap(aliases.get)
everCalledFunctions.retain(allFunctions)
fillOut()
def add(currentFunction: Option[String], callingFunctions: List[String], node: Node): Unit = {
node match {
case AliasDefinitionStatement(name, target, _) =>
aliases += name -> target
case f: FunctionDeclarationStatement =>
allFunctions += f.name
if (f.address.isDefined || f.interrupt) entryPoints += f.name
@ -67,6 +71,14 @@ abstract class CallGraph(program: Program, log: Logger) {
def fillOut(): Unit = {
callEdges ++= callEdges.flatMap {
case (a,b) => aliases.get(b).map(a -> _)
}
paramEdges ++= paramEdges.flatMap {
case (a,b) => aliases.get(b).map(a -> _)
}
var changed = true
while (changed) {
changed = false

View File

@ -192,7 +192,9 @@ sealed trait Statement extends Node {
def getAllExpressions: List[Expression]
}
sealed trait DeclarationStatement extends Statement
sealed trait DeclarationStatement extends Statement {
def name: String
}
case class TypeDefinitionStatement(name: String, parent: String) extends DeclarationStatement {
override def getAllExpressions: List[Expression] = Nil
@ -261,7 +263,7 @@ case class ProcessedContents(processor: String, values: ArrayContents) extends A
ProcessedContents(processor, values.replaceVariable(variableToReplace, expression))
}
case class AliasDefinitionStatement(name: String, target: String) extends DeclarationStatement {
case class AliasDefinitionStatement(name: String, target: String, important: Boolean) extends DeclarationStatement {
override def getAllExpressions: List[Expression] = Nil
}
@ -283,6 +285,8 @@ case class ParameterDeclaration(typ: String,
case class ImportStatement(filename: String) extends DeclarationStatement {
override def getAllExpressions: List[Expression] = Nil
override def name: String = ""
}
case class FunctionDeclarationStatement(name: String,

View File

@ -7,6 +7,17 @@ import millfork.node.opt.NodeOptimization
* @author Karol Stasiak
*/
case class Program(declarations: List[DeclarationStatement]) {
def applyImportantAliases: Program = {
val importantAliases = declarations.flatMap{
case AliasDefinitionStatement(name, _, true) => Some(name)
case _ => None
}.toSet
Program(declarations.filter{
case AliasDefinitionStatement(_, _, true) => true
case d => !importantAliases(d.name)
})
}
def applyNodeOptimization(o: NodeOptimization, options: CompilationOptions) = Program(o.optimize(declarations, options).asInstanceOf[List[DeclarationStatement]])
def +(p:Program): Program = Program(this.declarations ++ p.declarations)
}

View File

@ -29,7 +29,7 @@ object UnusedFunctions extends NodeOptimization {
override def optimize(nodes: List[Node], options: CompilationOptions): List[Node] = {
val aliases = nodes.flatMap{
case AliasDefinitionStatement(source, target) => Some(source -> target)
case AliasDefinitionStatement(source, target, _) => Some(source -> target)
case _ => None
}.toMap
val panicRequired = options.flags(CompilationFlag.CheckIndexOutOfBounds)

View File

@ -12,7 +12,7 @@ object UnusedGlobalVariables extends NodeOptimization {
override def optimize(nodes: List[Node], options: CompilationOptions): List[Node] = {
val aliases = nodes.flatMap{
case AliasDefinitionStatement(source, target) => Some(source -> target)
case AliasDefinitionStatement(source, target, _) => Some(source -> target)
case _ => None
}.toMap
// TODO: volatile

View File

@ -197,8 +197,9 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program
val compiledFunctions = mutable.Map[String, CompiledFunction[T]]()
val recommendedCompilationOrder = callGraph.recommendedCompilationOrder
val niceFunctionProperties = mutable.Set[(NiceFunctionProperty, String)]()
val aliases = env.getAliases
recommendedCompilationOrder.foreach { f =>
env.maybeGet[NormalFunction](f).foreach { function =>
if (!env.isAlias(f)) env.maybeGet[NormalFunction](f).foreach { function =>
val code = compileFunction(function, optimizations, options, inlinedFunctions, labelMap.toMap, niceFunctionProperties.toSet)
val strippedCodeForInlining = for {
limit <- potentiallyInlineable.get(f)

View File

@ -37,7 +37,7 @@ abstract class AbstractSourceLoadingQueue[T](val initialFilenames: List[String],
}
}
options.log.assertNoErrors("Parse failed")
parsedModules.values.reduce(_ + _)
parsedModules.values.reduce(_ + _).applyImportantAliases
}
def lookupModuleFile(includePath: List[String], moduleName: String, position: Option[Position]): String = {

View File

@ -213,7 +213,8 @@ abstract class MfParser[T](fileId: String, input: String, currentDirectory: Stri
p <- position()
name <- "alias" ~ !letterOrDigit ~/ SWS ~ identifier ~ HWS
target <- "=" ~/ HWS ~/ identifier ~/ HWS
} yield Seq(AliasDefinitionStatement(name, target).pos(p))
important <- "!".!.? ~/ HWS
} yield Seq(AliasDefinitionStatement(name, target, important.isDefined).pos(p))
def fastAlignmentForArrays: MemoryAlignment
def fastAlignmentForFunctions: MemoryAlignment

View File

@ -176,7 +176,7 @@ class EmuRun(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimization],
tmp += EmuRun.cachedBcd
tmp
}
val program = nodeOptimizations.foldLeft(withLibraries)((p, opt) => p.applyNodeOptimization(opt, options))
val program = nodeOptimizations.foldLeft(withLibraries.applyImportantAliases)((p, opt) => p.applyNodeOptimization(opt, options))
val callGraph = new StandardCallGraph(program, log)
val env = new Environment(None, "", CpuFamily.M6502, options.jobContext)
env.collectDeclarations(program, options)

View File

@ -98,7 +98,7 @@ class EmuZ80Run(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimizatio
tmp += EmuZ80Run.cachedMath(cpu)
tmp
}
val program = nodeOptimizations.foldLeft(withLibraries)((p, opt) => p.applyNodeOptimization(opt, options))
val program = nodeOptimizations.foldLeft(withLibraries.applyImportantAliases)((p, opt) => p.applyNodeOptimization(opt, options))
val callGraph = new StandardCallGraph(program, log)
val env = new Environment(None, "", CpuFamily.I80, options.jobContext)
env.collectDeclarations(program, options)