mirror of
https://github.com/KarolS/millfork.git
synced 2024-06-12 22:29:33 +00:00
Optimize the optimizer
This commit is contained in:
parent
7b205a2754
commit
6af84d1628
|
@ -30,7 +30,7 @@ object FlowInfoRequirement extends Enumeration {
|
||||||
}
|
}
|
||||||
|
|
||||||
def assertLabels(x: FlowInfoRequirement.Value): Unit = x match {
|
def assertLabels(x: FlowInfoRequirement.Value): Unit = x match {
|
||||||
case NoRequirement => FatalErrorReporting.reportFlyingPig("Backward flow info required")
|
case NoRequirement => FatalErrorReporting.reportFlyingPig("Label info required")
|
||||||
case _ => ()
|
case _ => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,29 +43,30 @@ class RuleBasedAssemblyOptimization(val name: String, val needsFlowInfo: FlowInf
|
||||||
|
|
||||||
private val actualRules = rules.flatMap(_.flatten)
|
private val actualRules = rules.flatMap(_.flatten)
|
||||||
actualRules.foreach(_.pattern.validate(needsFlowInfo))
|
actualRules.foreach(_.pattern.validate(needsFlowInfo))
|
||||||
|
private val actualRulesWithIndex = actualRules.zipWithIndex
|
||||||
|
|
||||||
|
|
||||||
override def optimize(f: NormalFunction, code: List[MLine], optimizationContext: OptimizationContext): List[MLine] = {
|
override def optimize(f: NormalFunction, code: List[MLine], optimizationContext: OptimizationContext): List[MLine] = {
|
||||||
val taggedCode = FlowAnalyzer.analyze(f, code, optimizationContext, needsFlowInfo)
|
val taggedCode = FlowAnalyzer.analyze(f, code, optimizationContext, needsFlowInfo)
|
||||||
val (changed, optimized) = optimizeImpl(f, taggedCode, optimizationContext)
|
optimizeImpl(f, code, taggedCode, optimizationContext)
|
||||||
if (changed) optimized else code
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def optimizeImpl(f: NormalFunction, code: List[(FlowInfo, MLine)], optimizationContext: OptimizationContext): (Boolean, List[MLine]) = {
|
final def optimizeImpl(f: NormalFunction, code: List[MLine], taggedCode: List[(FlowInfo, MLine)], optimizationContext: OptimizationContext): List[MLine] = {
|
||||||
val log = optimizationContext.log
|
val log = optimizationContext.log
|
||||||
code match {
|
taggedCode match {
|
||||||
case Nil => false -> Nil
|
case Nil => code
|
||||||
case head :: tail =>
|
case head :: tail =>
|
||||||
for ((rule, index) <- actualRules.zipWithIndex) {
|
for ((rule, index) <- actualRulesWithIndex) {
|
||||||
val ctx = new AssemblyMatchingContext(
|
val ctx = new AssemblyMatchingContext(
|
||||||
optimizationContext.options,
|
optimizationContext.options,
|
||||||
optimizationContext.labelMap,
|
optimizationContext.labelMap,
|
||||||
optimizationContext.niceFunctionProperties,
|
optimizationContext.niceFunctionProperties,
|
||||||
head._1.labelUseCount(_)
|
head._1.labelUseCount(_)
|
||||||
)
|
)
|
||||||
rule.pattern.matchTo(ctx, code) match {
|
rule.pattern.matchTo(ctx, taggedCode) match {
|
||||||
case Some(rest: List[(FlowInfo, MLine)]) =>
|
case Some(rest: List[(FlowInfo, MLine)]) =>
|
||||||
val matchedChunkToOptimize: List[MLine] = code.take(code.length - rest.length).map(_._2)
|
val optimizedChunkLengthBefore = taggedCode.length - rest.length
|
||||||
|
val (matchedChunkToOptimize, restOfCode) = code.splitAt(optimizedChunkLengthBefore)
|
||||||
val optimizedChunk: List[MLine] = rule.result(matchedChunkToOptimize, ctx)
|
val optimizedChunk: List[MLine] = rule.result(matchedChunkToOptimize, ctx)
|
||||||
val optimizedChunkWithSource =
|
val optimizedChunkWithSource =
|
||||||
if (!ctx.compilationOptions.flag(CompilationFlag.LineNumbersInAssembly)) optimizedChunk
|
if (!ctx.compilationOptions.flag(CompilationFlag.LineNumbersInAssembly)) optimizedChunk
|
||||||
|
@ -74,28 +75,34 @@ class RuleBasedAssemblyOptimization(val name: String, val needsFlowInfo: FlowInf
|
||||||
else if (optimizedChunk.size == 1) optimizedChunk.map(_.pos(SourceLine.merge(matchedChunkToOptimize.map(_.source))))
|
else if (optimizedChunk.size == 1) optimizedChunk.map(_.pos(SourceLine.merge(matchedChunkToOptimize.map(_.source))))
|
||||||
else if (matchedChunkToOptimize.flatMap(_.source).toSet.size == 1) optimizedChunk.map(_.pos(SourceLine.merge(matchedChunkToOptimize.map(_.source))))
|
else if (matchedChunkToOptimize.flatMap(_.source).toSet.size == 1) optimizedChunk.map(_.pos(SourceLine.merge(matchedChunkToOptimize.map(_.source))))
|
||||||
else optimizedChunk
|
else optimizedChunk
|
||||||
log.debug(s"Applied $name ($index)")
|
if (log.debugEnabled) {
|
||||||
if (needsFlowInfo != FlowInfoRequirement.NoRequirement) {
|
log.debug(s"Applied $name ($index)")
|
||||||
val before = code.head._1.statusBefore
|
|
||||||
val after = code(matchedChunkToOptimize.length - 1)._1.importanceAfter
|
|
||||||
log.trace(s"Before: $before")
|
|
||||||
log.trace(s"After: $after")
|
|
||||||
}
|
}
|
||||||
if (log.traceEnabled) {
|
if (log.traceEnabled) {
|
||||||
|
if (needsFlowInfo != FlowInfoRequirement.NoRequirement) {
|
||||||
|
val before = head._1.statusBefore
|
||||||
|
val after = taggedCode(matchedChunkToOptimize.length - 1)._1.importanceAfter
|
||||||
|
log.trace(s"Before: $before")
|
||||||
|
log.trace(s"After: $after")
|
||||||
|
}
|
||||||
matchedChunkToOptimize.filter(_.isPrintable).foreach(l => log.trace(l.toString))
|
matchedChunkToOptimize.filter(_.isPrintable).foreach(l => log.trace(l.toString))
|
||||||
log.trace(" ↓")
|
log.trace(" ↓")
|
||||||
optimizedChunkWithSource.filter(_.isPrintable).foreach(l => log.trace(l.toString))
|
optimizedChunkWithSource.filter(_.isPrintable).foreach(l => log.trace(l.toString))
|
||||||
}
|
}
|
||||||
if (needsFlowInfo != FlowInfoRequirement.NoRequirement) {
|
if (needsFlowInfo != FlowInfoRequirement.NoRequirement) {
|
||||||
return true -> (optimizedChunkWithSource ++ optimizeImpl(f, rest, optimizationContext)._2)
|
return optimizedChunkWithSource ++ optimizeImpl(f, restOfCode, rest, optimizationContext)
|
||||||
} else {
|
} else {
|
||||||
return true -> optimize(f, optimizedChunkWithSource ++ rest.map(_._2), optimizationContext)
|
return optimize(f, optimizedChunkWithSource ++ restOfCode, optimizationContext)
|
||||||
}
|
}
|
||||||
case None => ()
|
case None => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val (changedTail, optimizedTail) = optimizeImpl(f, tail, optimizationContext)
|
val optimizedTail = optimizeImpl(f, code.tail, tail, optimizationContext)
|
||||||
(changedTail, head._2 :: optimizedTail)
|
if (optimizedTail eq code.tail) {
|
||||||
|
code
|
||||||
|
} else {
|
||||||
|
code.head :: optimizedTail
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@ import millfork.assembly.{AssemblyOptimization, Elidability, OptimizationContext
|
||||||
import millfork.env._
|
import millfork.env._
|
||||||
import millfork.error.ConsoleLogger
|
import millfork.error.ConsoleLogger
|
||||||
|
|
||||||
|
import scala.collection.mutable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Karol Stasiak
|
* @author Karol Stasiak
|
||||||
*/
|
*/
|
||||||
|
@ -23,48 +25,52 @@ object EmptyParameterStoreRemoval extends AssemblyOptimization[AssemblyLine] {
|
||||||
case AssemblyLine0(JSR | BSR | JMP, _, NumericConstant(addr, _)) => Some("$" + addr.toHexString)
|
case AssemblyLine0(JSR | BSR | JMP, _, NumericConstant(addr, _)) => Some("$" + addr.toHexString)
|
||||||
case _ => None
|
case _ => None
|
||||||
}.toSet
|
}.toSet
|
||||||
val foreignVariables = f.environment.root.things.values.flatMap {
|
val foreignVariables = mutable.Set[String]()
|
||||||
|
f.environment.root.things.values.foreach {
|
||||||
case other: NormalFunction if !other.name.endsWith(".trampoline") =>
|
case other: NormalFunction if !other.name.endsWith(".trampoline") =>
|
||||||
val address = other.address match {
|
val address = other.address match {
|
||||||
case Some(NumericConstant(addr, _)) => "$" + addr.toHexString
|
case Some(NumericConstant(addr, _)) => "$" + addr.toHexString
|
||||||
case _ => ""
|
case _ => ""
|
||||||
}
|
}
|
||||||
if (other.name == f.name || usedFunctions(other.name) || usedFunctions(address)) {
|
if (other.name == f.name || usedFunctions(other.name) || usedFunctions(address)) {
|
||||||
Nil
|
// do nothing
|
||||||
} else {
|
} else {
|
||||||
val params = other.params match {
|
other.params match {
|
||||||
case NormalParamSignature(ps) => ps.map(_.name)
|
case NormalParamSignature(ps) =>
|
||||||
case _ => Nil
|
ps.foreach(p => foreignVariables += p.name)
|
||||||
|
case _ =>
|
||||||
}
|
}
|
||||||
val locals = other.environment.things.values.flatMap{
|
other.environment.things.values.foreach {
|
||||||
case th: MemoryVariable if th.alloc == VariableAllocationMethod.Auto => Some(th.name)
|
case th: MemoryVariable if th.alloc == VariableAllocationMethod.Auto =>
|
||||||
case th: MemoryVariable if th.alloc == VariableAllocationMethod.Zeropage => Some(th.name) // TODO: ???
|
foreignVariables += th.name
|
||||||
case _ => None
|
case th: MemoryVariable if th.alloc == VariableAllocationMethod.Zeropage =>
|
||||||
|
foreignVariables += th.name // TODO: ???
|
||||||
|
case _ =>
|
||||||
}
|
}
|
||||||
if (other.returnType.size > Cpu.getMaxSizeReturnableViaRegisters(optimizationContext.options.platform.cpu, optimizationContext.options)) {
|
if (other.returnType.size > Cpu.getMaxSizeReturnableViaRegisters(optimizationContext.options.platform.cpu, optimizationContext.options)) {
|
||||||
other.name + ".return" :: (params ++ locals)
|
foreignVariables += other.name + ".return"
|
||||||
} else {
|
|
||||||
params ++ locals
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case _ => Nil
|
case _ =>
|
||||||
}.toSet
|
}
|
||||||
val stillReadOrStoredVariables = code.flatMap {
|
val stillReadOrStoredVariables = mutable.Set[String]()
|
||||||
case AssemblyLine0(_, _, MemoryAddressConstant(th)) => Some(th.name)
|
code.foreach {
|
||||||
case AssemblyLine0(_, _, CompoundConstant(_, MemoryAddressConstant(th), _)) => Some(th.name)
|
case AssemblyLine0(_, _, MemoryAddressConstant(th)) => stillReadOrStoredVariables += th.name
|
||||||
case AssemblyLine0(_, Immediate, SubbyteConstant(MemoryAddressConstant(th), _)) => Some(th.name)
|
case AssemblyLine0(_, _, CompoundConstant(_, MemoryAddressConstant(th), _)) => stillReadOrStoredVariables += th.name
|
||||||
case _ => None
|
case AssemblyLine0(_, Immediate, SubbyteConstant(MemoryAddressConstant(th), _)) => stillReadOrStoredVariables += th.name
|
||||||
}.toSet
|
case _ =>
|
||||||
val stillReadVariables = code.flatMap {
|
}
|
||||||
|
val stillReadVariables = mutable.Set[String]()
|
||||||
|
code.foreach {
|
||||||
case AssemblyLine(op, am, MemoryAddressConstant(th), Elidability.Elidable, _)
|
case AssemblyLine(op, am, MemoryAddressConstant(th), Elidability.Elidable, _)
|
||||||
if storeInstructions(op) && storeAddrModes(am) => Nil
|
if storeInstructions(op) && storeAddrModes(am) =>
|
||||||
case AssemblyLine(op, am, CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(_, _)), Elidability.Elidable, _)
|
case AssemblyLine(op, am, CompoundConstant(MathOperator.Plus, MemoryAddressConstant(th), NumericConstant(_, _)), Elidability.Elidable, _)
|
||||||
if storeInstructions(op) && storeAddrModes(am) => Nil
|
if storeInstructions(op) && storeAddrModes(am) =>
|
||||||
case AssemblyLine0(_, _, MemoryAddressConstant(th)) => Some(th.name)
|
case AssemblyLine0(_, _, MemoryAddressConstant(th)) => stillReadVariables += th.name
|
||||||
case AssemblyLine0(_, _, CompoundConstant(_, MemoryAddressConstant(th), _)) => Some(th.name)
|
case AssemblyLine0(_, _, CompoundConstant(_, MemoryAddressConstant(th), _)) => stillReadVariables += th.name
|
||||||
case AssemblyLine0(_, Immediate, SubbyteConstant(MemoryAddressConstant(th), _)) => Some(th.name)
|
case AssemblyLine0(_, Immediate, SubbyteConstant(MemoryAddressConstant(th), _)) => stillReadVariables += th.name
|
||||||
case _ => None
|
case _ =>
|
||||||
}.toSet
|
}
|
||||||
|
|
||||||
val unusedForeignVariables = (foreignVariables & stillReadOrStoredVariables) -- stillReadVariables
|
val unusedForeignVariables = (foreignVariables & stillReadOrStoredVariables) -- stillReadVariables
|
||||||
if (unusedForeignVariables.isEmpty) {
|
if (unusedForeignVariables.isEmpty) {
|
||||||
|
|
|
@ -30,7 +30,7 @@ object FlowInfoRequirement extends Enumeration {
|
||||||
}
|
}
|
||||||
|
|
||||||
def assertLabels(x: FlowInfoRequirement.Value): Unit = x match {
|
def assertLabels(x: FlowInfoRequirement.Value): Unit = x match {
|
||||||
case NoRequirement => FatalErrorReporting.reportFlyingPig("Backward flow info required")
|
case NoRequirement => FatalErrorReporting.reportFlyingPig("Label info required")
|
||||||
case _ => ()
|
case _ => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,20 +43,20 @@ class RuleBasedAssemblyOptimization(val name: String, val needsFlowInfo: FlowInf
|
||||||
|
|
||||||
private val actualRules = rules.flatMap(_.flatten)
|
private val actualRules = rules.flatMap(_.flatten)
|
||||||
actualRules.foreach(_.pattern.validate(needsFlowInfo))
|
actualRules.foreach(_.pattern.validate(needsFlowInfo))
|
||||||
|
private val actualRulesWithIndex = actualRules.zipWithIndex
|
||||||
|
|
||||||
|
|
||||||
override def optimize(f: NormalFunction, code: List[AssemblyLine], optimizationContext: OptimizationContext): List[AssemblyLine] = {
|
override def optimize(f: NormalFunction, code: List[AssemblyLine], optimizationContext: OptimizationContext): List[AssemblyLine] = {
|
||||||
val taggedCode = FlowAnalyzer.analyze(f, code, optimizationContext, needsFlowInfo)
|
val taggedCode = FlowAnalyzer.analyze(f, code, optimizationContext, needsFlowInfo)
|
||||||
val (changed, optimized) = optimizeImpl(f, taggedCode, optimizationContext)
|
optimizeImpl(f, code, taggedCode, optimizationContext)
|
||||||
if (changed) optimized else code
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def optimizeImpl(f: NormalFunction, code: List[(FlowInfo, AssemblyLine)], optimizationContext: OptimizationContext): (Boolean, List[AssemblyLine]) = {
|
final def optimizeImpl(f: NormalFunction, code: List[AssemblyLine], taggedCode: List[(FlowInfo, AssemblyLine)], optimizationContext: OptimizationContext): List[AssemblyLine] = {
|
||||||
val log = optimizationContext.log
|
val log = optimizationContext.log
|
||||||
code match {
|
taggedCode match {
|
||||||
case Nil => false -> Nil
|
case Nil => code
|
||||||
case head :: tail =>
|
case head :: tail =>
|
||||||
for ((rule, index) <- actualRules.zipWithIndex) {
|
for ((rule, index) <- actualRulesWithIndex) {
|
||||||
val ctx = new AssemblyMatchingContext(
|
val ctx = new AssemblyMatchingContext(
|
||||||
optimizationContext.options,
|
optimizationContext.options,
|
||||||
optimizationContext.labelMap,
|
optimizationContext.labelMap,
|
||||||
|
@ -64,9 +64,10 @@ class RuleBasedAssemblyOptimization(val name: String, val needsFlowInfo: FlowInf
|
||||||
optimizationContext.niceFunctionProperties,
|
optimizationContext.niceFunctionProperties,
|
||||||
head._1.labelUseCount(_)
|
head._1.labelUseCount(_)
|
||||||
)
|
)
|
||||||
rule.pattern.matchTo(ctx, code) match {
|
rule.pattern.matchTo(ctx, taggedCode) match {
|
||||||
case Some(rest: List[(FlowInfo, AssemblyLine)]) =>
|
case Some(rest: List[(FlowInfo, AssemblyLine)]) =>
|
||||||
val matchedChunkToOptimize: List[AssemblyLine] = code.take(code.length - rest.length).map(_._2)
|
val optimizedChunkLengthBefore = taggedCode.length - rest.length
|
||||||
|
val (matchedChunkToOptimize, restOfCode) = code.splitAt(optimizedChunkLengthBefore)
|
||||||
val optimizedChunk: List[AssemblyLine] = rule.result(matchedChunkToOptimize, ctx)
|
val optimizedChunk: List[AssemblyLine] = rule.result(matchedChunkToOptimize, ctx)
|
||||||
val optimizedChunkWithSource =
|
val optimizedChunkWithSource =
|
||||||
if (!ctx.compilationOptions.flag(CompilationFlag.LineNumbersInAssembly)) optimizedChunk
|
if (!ctx.compilationOptions.flag(CompilationFlag.LineNumbersInAssembly)) optimizedChunk
|
||||||
|
@ -75,28 +76,34 @@ class RuleBasedAssemblyOptimization(val name: String, val needsFlowInfo: FlowInf
|
||||||
else if (optimizedChunk.size == 1) optimizedChunk.map(_.pos(SourceLine.merge(matchedChunkToOptimize.map(_.source))))
|
else if (optimizedChunk.size == 1) optimizedChunk.map(_.pos(SourceLine.merge(matchedChunkToOptimize.map(_.source))))
|
||||||
else if (matchedChunkToOptimize.flatMap(_.source).toSet.size == 1) optimizedChunk.map(_.pos(SourceLine.merge(matchedChunkToOptimize.map(_.source))))
|
else if (matchedChunkToOptimize.flatMap(_.source).toSet.size == 1) optimizedChunk.map(_.pos(SourceLine.merge(matchedChunkToOptimize.map(_.source))))
|
||||||
else optimizedChunk
|
else optimizedChunk
|
||||||
log.debug(s"Applied $name ($index)")
|
if (log.debugEnabled) {
|
||||||
if (needsFlowInfo != FlowInfoRequirement.NoRequirement) {
|
log.debug(s"Applied $name ($index)")
|
||||||
val before = code.head._1.statusBefore
|
|
||||||
val after = code(matchedChunkToOptimize.length - 1)._1.importanceAfter
|
|
||||||
log.trace(s"Before: $before")
|
|
||||||
log.trace(s"After: $after")
|
|
||||||
}
|
}
|
||||||
if (log.traceEnabled) {
|
if (log.traceEnabled) {
|
||||||
|
if (needsFlowInfo != FlowInfoRequirement.NoRequirement) {
|
||||||
|
val before = head._1.statusBefore
|
||||||
|
val after = taggedCode(matchedChunkToOptimize.length - 1)._1.importanceAfter
|
||||||
|
log.trace(s"Before: $before")
|
||||||
|
log.trace(s"After: $after")
|
||||||
|
}
|
||||||
matchedChunkToOptimize.filter(_.isPrintable).foreach(l => log.trace(l.toString))
|
matchedChunkToOptimize.filter(_.isPrintable).foreach(l => log.trace(l.toString))
|
||||||
log.trace(" ↓")
|
log.trace(" ↓")
|
||||||
optimizedChunkWithSource.filter(_.isPrintable).foreach(l => log.trace(l.toString))
|
optimizedChunkWithSource.filter(_.isPrintable).foreach(l => log.trace(l.toString))
|
||||||
}
|
}
|
||||||
if (needsFlowInfo != FlowInfoRequirement.NoRequirement) {
|
if (needsFlowInfo != FlowInfoRequirement.NoRequirement) {
|
||||||
return true -> (optimizedChunkWithSource ++ optimizeImpl(f, rest, optimizationContext)._2)
|
return optimizedChunkWithSource ++ optimizeImpl(f, restOfCode, rest, optimizationContext)
|
||||||
} else {
|
} else {
|
||||||
return true -> optimize(f, optimizedChunkWithSource ++ rest.map(_._2), optimizationContext)
|
return optimize(f, optimizedChunkWithSource ++ restOfCode, optimizationContext)
|
||||||
}
|
}
|
||||||
case None => ()
|
case None => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val (changedTail, optimizedTail) = optimizeImpl(f, tail, optimizationContext)
|
val optimizedTail = optimizeImpl(f, code.tail, tail, optimizationContext)
|
||||||
(changedTail, head._2 :: optimizedTail)
|
if (optimizedTail eq code.tail) {
|
||||||
|
code
|
||||||
|
} else {
|
||||||
|
code.head :: optimizedTail
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import millfork.env._
|
||||||
import millfork.error.Logger
|
import millfork.error.Logger
|
||||||
import millfork.node.MosNiceFunctionProperty
|
import millfork.node.MosNiceFunctionProperty
|
||||||
|
|
||||||
|
import scala.collection.mutable
|
||||||
import scala.collection.mutable.ListBuffer
|
import scala.collection.mutable.ListBuffer
|
||||||
import scala.util.control.TailCalls.{TailRec, done, tailcall}
|
import scala.util.control.TailCalls.{TailRec, done, tailcall}
|
||||||
|
|
||||||
|
@ -147,24 +148,26 @@ object VariableToRegisterOptimization extends AssemblyOptimization[AssemblyLine]
|
||||||
// assembly functions do not get this optimization
|
// assembly functions do not get this optimization
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
val stillUsedVariables = code.flatMap {
|
val stillUsedVariables = mutable.Set[String]()
|
||||||
case AssemblyLine0(_, _, MemoryAddressConstant(th)) => Some(th.name)
|
val variablesWithAddressesTaken = mutable.Set[String]()
|
||||||
|
code.foreach {
|
||||||
|
case AssemblyLine0(_, _, MemoryAddressConstant(th)) => stillUsedVariables += th.name
|
||||||
|
case AssemblyLine0(_, _, SubbyteConstant(MemoryAddressConstant(th), _)) => variablesWithAddressesTaken += th.name
|
||||||
case _ => None
|
case _ => None
|
||||||
}.toSet
|
}
|
||||||
val variablesWithAddressesTaken = code.flatMap {
|
val localVariables = mutable.Set[Variable]()
|
||||||
case AssemblyLine0(_, _, SubbyteConstant(MemoryAddressConstant(th), _)) => Some(th.name)
|
val variablesWithRegisterHint = mutable.Set[String]()
|
||||||
case _ => None
|
|
||||||
}.toSet
|
f.environment.getAllLocalVariables.foreach {
|
||||||
val localVariables = f.environment.getAllLocalVariables.filter {
|
case v@MemoryVariable(name, typ, alloc@(VariableAllocationMethod.Auto | VariableAllocationMethod.Register)) =>
|
||||||
case v@MemoryVariable(name, typ, VariableAllocationMethod.Auto | VariableAllocationMethod.Register) =>
|
if (typ.size == 1 && !paramVariables(name) && stillUsedVariables(name) && !variablesWithAddressesTaken(name) && !v.isVolatile){
|
||||||
typ.size == 1 && !paramVariables(name) && stillUsedVariables(name) && !variablesWithAddressesTaken(name) && !v.isVolatile
|
localVariables += v
|
||||||
|
if (alloc == VariableAllocationMethod.Register) {
|
||||||
|
variablesWithRegisterHint += v.name
|
||||||
|
}
|
||||||
|
}
|
||||||
case _ => false
|
case _ => false
|
||||||
}
|
}
|
||||||
val variablesWithRegisterHint = f.environment.getAllLocalVariables.filter {
|
|
||||||
case v@MemoryVariable(name, typ, VariableAllocationMethod.Register) =>
|
|
||||||
typ.size == 1 && !paramVariables(name) && stillUsedVariables(name) && !variablesWithAddressesTaken(name) && !v.isVolatile
|
|
||||||
case _ => false
|
|
||||||
}.map(_.name).toSet
|
|
||||||
|
|
||||||
val variablesWithLifetimes = localVariables.map(v =>
|
val variablesWithLifetimes = localVariables.map(v =>
|
||||||
v.name -> VariableLifetime.apply(v.name, code)
|
v.name -> VariableLifetime.apply(v.name, code)
|
||||||
|
@ -187,10 +190,12 @@ object VariableToRegisterOptimization extends AssemblyOptimization[AssemblyLine]
|
||||||
log = log
|
log = log
|
||||||
)
|
)
|
||||||
|
|
||||||
val labelsUsedOnce: Set[String] = code.flatMap {
|
val tmpUsedLabelList = mutable.ListBuffer[String]()
|
||||||
case AssemblyLine0(op, _, MemoryAddressConstant(Label(l))) if op != Opcode.LABEL => Some(l)
|
code.foreach{
|
||||||
case _ => None
|
case AssemblyLine0(op, _, MemoryAddressConstant(Label(l))) if op != Opcode.LABEL => tmpUsedLabelList += l
|
||||||
}.groupBy(identity).filter(_._2.size == 1).keySet
|
case _ =>
|
||||||
|
}
|
||||||
|
val labelsUsedOnce: Set[String] = tmpUsedLabelList.groupBy(identity).filter(_._2.size == 1).keySet
|
||||||
|
|
||||||
val featuresForAcc = FeaturesForAccumulator(
|
val featuresForAcc = FeaturesForAccumulator(
|
||||||
cmos = options.flag(CompilationFlag.EmitCmosOpcodes),
|
cmos = options.flag(CompilationFlag.EmitCmosOpcodes),
|
||||||
|
|
|
@ -30,7 +30,7 @@ object FlowInfoRequirement extends Enumeration {
|
||||||
}
|
}
|
||||||
|
|
||||||
def assertLabels(x: FlowInfoRequirement.Value): Unit = x match {
|
def assertLabels(x: FlowInfoRequirement.Value): Unit = x match {
|
||||||
case NoRequirement => FatalErrorReporting.reportFlyingPig("Backward flow info required")
|
case NoRequirement => FatalErrorReporting.reportFlyingPig("Label info required")
|
||||||
case _ => ()
|
case _ => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,23 +43,24 @@ class RuleBasedAssemblyOptimization(val name: String, val needsFlowInfo: FlowInf
|
||||||
|
|
||||||
private val actualRules = rules.flatMap(_.flatten)
|
private val actualRules = rules.flatMap(_.flatten)
|
||||||
actualRules.foreach(_.pattern.validate(needsFlowInfo))
|
actualRules.foreach(_.pattern.validate(needsFlowInfo))
|
||||||
|
private val actualRulesWithIndex = actualRules.zipWithIndex
|
||||||
|
|
||||||
override def optimize(f: NormalFunction, code: List[ZLine], optimizationContext: OptimizationContext): List[ZLine] = {
|
override def optimize(f: NormalFunction, code: List[ZLine], optimizationContext: OptimizationContext): List[ZLine] = {
|
||||||
val taggedCode = FlowAnalyzer.analyze(f, code, optimizationContext, needsFlowInfo)
|
val taggedCode = FlowAnalyzer.analyze(f, code, optimizationContext, needsFlowInfo)
|
||||||
val (changed, optimized) = optimizeImpl(f, taggedCode, optimizationContext)
|
optimizeImpl(f, code, taggedCode, optimizationContext)
|
||||||
if (changed) optimized else code
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def optimizeImpl(f: NormalFunction, code: List[(FlowInfo, ZLine)], optimizationContext: OptimizationContext): (Boolean, List[ZLine]) = {
|
final def optimizeImpl(f: NormalFunction, code:List[ZLine], taggedCode: List[(FlowInfo, ZLine)], optimizationContext: OptimizationContext): List[ZLine] = {
|
||||||
val log = optimizationContext.log
|
val log = optimizationContext.log
|
||||||
code match {
|
taggedCode match {
|
||||||
case Nil => (false, Nil)
|
case Nil => code
|
||||||
case head :: tail =>
|
case head :: tail =>
|
||||||
for ((rule, index) <- actualRules.zipWithIndex) {
|
for ((rule, index) <- actualRulesWithIndex) {
|
||||||
val ctx = new AssemblyMatchingContext(optimizationContext.options)
|
val ctx = new AssemblyMatchingContext(optimizationContext.options)
|
||||||
rule.pattern.matchTo(ctx, code) match {
|
rule.pattern.matchTo(ctx, taggedCode) match {
|
||||||
case Some(rest: List[(FlowInfo, ZLine)]) =>
|
case Some(rest: List[(FlowInfo, ZLine)]) =>
|
||||||
val matchedChunkToOptimize: List[ZLine] = code.take(code.length - rest.length).map(_._2)
|
val optimizedChunkLengthBefore = taggedCode.length - rest.length
|
||||||
|
val (matchedChunkToOptimize, restOfCode) = code.splitAt(optimizedChunkLengthBefore)
|
||||||
val optimizedChunk: List[ZLine] = rule.result(matchedChunkToOptimize, ctx)
|
val optimizedChunk: List[ZLine] = rule.result(matchedChunkToOptimize, ctx)
|
||||||
val optimizedChunkWithSource =
|
val optimizedChunkWithSource =
|
||||||
if (!ctx.compilationOptions.flag(CompilationFlag.LineNumbersInAssembly)) optimizedChunk
|
if (!ctx.compilationOptions.flag(CompilationFlag.LineNumbersInAssembly)) optimizedChunk
|
||||||
|
@ -68,30 +69,34 @@ class RuleBasedAssemblyOptimization(val name: String, val needsFlowInfo: FlowInf
|
||||||
else if (optimizedChunk.size == 1) optimizedChunk.map(_.pos(SourceLine.merge(matchedChunkToOptimize.map(_.source))))
|
else if (optimizedChunk.size == 1) optimizedChunk.map(_.pos(SourceLine.merge(matchedChunkToOptimize.map(_.source))))
|
||||||
else if (matchedChunkToOptimize.flatMap(_.source).toSet.size == 1) optimizedChunk.map(_.pos(SourceLine.merge(matchedChunkToOptimize.map(_.source))))
|
else if (matchedChunkToOptimize.flatMap(_.source).toSet.size == 1) optimizedChunk.map(_.pos(SourceLine.merge(matchedChunkToOptimize.map(_.source))))
|
||||||
else optimizedChunk
|
else optimizedChunk
|
||||||
log.debug(s"Applied $name ($index)")
|
if (log.debugEnabled) {
|
||||||
if (needsFlowInfo != FlowInfoRequirement.NoRequirement) {
|
log.debug(s"Applied $name ($index)")
|
||||||
val before = code.head._1.statusBefore
|
}
|
||||||
val after = code(matchedChunkToOptimize.length - 1)._1.importanceAfter
|
if (log.traceEnabled) {
|
||||||
if (log.traceEnabled) {
|
if (needsFlowInfo != FlowInfoRequirement.NoRequirement) {
|
||||||
|
val before = head._1.statusBefore
|
||||||
|
val after = taggedCode(matchedChunkToOptimize.length - 1)._1.importanceAfter
|
||||||
log.trace(s"Before: $before")
|
log.trace(s"Before: $before")
|
||||||
log.trace(s"After: $after")
|
log.trace(s"After: $after")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (log.traceEnabled) {
|
|
||||||
matchedChunkToOptimize.filter(_.isPrintable).foreach(l => log.trace(l.toString))
|
matchedChunkToOptimize.filter(_.isPrintable).foreach(l => log.trace(l.toString))
|
||||||
log.trace(" ↓")
|
log.trace(" ↓")
|
||||||
optimizedChunkWithSource.filter(_.isPrintable).foreach(l => log.trace(l.toString))
|
optimizedChunkWithSource.filter(_.isPrintable).foreach(l => log.trace(l.toString))
|
||||||
}
|
}
|
||||||
if (needsFlowInfo != FlowInfoRequirement.NoRequirement) {
|
if (needsFlowInfo != FlowInfoRequirement.NoRequirement) {
|
||||||
return true -> (optimizedChunkWithSource ++ optimizeImpl(f, rest, optimizationContext)._2)
|
return optimizedChunkWithSource ++ optimizeImpl(f, restOfCode, rest, optimizationContext)
|
||||||
} else {
|
} else {
|
||||||
return true -> optimize(f, optimizedChunkWithSource ++ rest.map(_._2), optimizationContext)
|
return optimize(f, optimizedChunkWithSource ++ restOfCode, optimizationContext)
|
||||||
}
|
}
|
||||||
case None => ()
|
case None => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val (changedTail, optimizedTail) = optimizeImpl(f, tail, optimizationContext)
|
val optimizedTail = optimizeImpl(f, code.tail, tail, optimizationContext)
|
||||||
(changedTail, head._2 :: optimizedTail)
|
if (optimizedTail eq code.tail) {
|
||||||
|
code
|
||||||
|
} else {
|
||||||
|
code.head :: optimizedTail
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user