This commit is contained in:
Karol Stasiak 2018-01-08 01:17:25 +01:00
parent 309f12cf82
commit 502faa3694
22 changed files with 108 additions and 38 deletions

View File

@ -0,0 +1,3 @@
void main() {
panic()
}

View File

@ -1,6 +1,6 @@
[compilation]
arch=strict
modules=a8_kernel
modules=a8_kernel,default_panic
[allocation]

View File

@ -1,6 +1,6 @@
[compilation]
arch=nmos
modules=c128_hardware,loader_1c01,c128_kernal
modules=c128_hardware,loader_1c01,c128_kernal,default_panic
[allocation]

View File

@ -1,6 +1,6 @@
[compilation]
arch=nmos
modules=loader_1001,c264_kernal,c264_hardware
modules=loader_1001,c264_kernal,c264_hardware,default_panic
[allocation]

View File

@ -5,7 +5,7 @@
; CPU architecture: nmos, strictnmos, ricoh, strictricoh, cmos
arch=nmos
; modules to load
modules=c64_hardware,loader_0801,c64_kernal,stdlib
modules=c64_hardware,loader_0801,c64_kernal,c64_panic,stdlib
; optionally: default flags
emit_illegals=true

27
include/c64_panic.mfk Normal file
View File

@ -0,0 +1,27 @@
void _panic() {
asm {
SEI
PLA // status register
PLA
TAY
PLA
TAX
JSR hi_nibble_to_hex
JSR putchar
TXA
JSR lo_nibble_to_hex
JSR putchar
TYA
JSR hi_nibble_to_hex
JSR putchar
TYA
JSR lo_nibble_to_hex
JSR putchar
LDA #2
STA $D020
}
while(true){}
}

View File

@ -0,0 +1,3 @@
void _panic() {
while(true){}
}

View File

@ -1,6 +1,6 @@
[compilation]
arch=nmos
modules=loader_0401,pet_kernal
modules=loader_0401,pet_kernal,default_panic
[allocation]

View File

@ -1,6 +1,6 @@
[compilation]
arch=nmos
modules=c264_loader,c264_kernal,c264_hardware
modules=c264_loader,c264_kernal,c264_hardware,default_panic
[allocation]

View File

@ -21,3 +21,25 @@ inline asm void enable_irq() {
CLI
}
asm byte hi_nibble_to_hex(byte a) {
LSR
LSR
LSR
LSR
JMP lo_nibble_to_hex
}
asm byte lo_nibble_to_hex(byte a) {
AND #$F
CLC
ADC #$30
CMP #$3A
BCC _lo_nibble_to_hex_lbl
ADC #$6 // carry is set
_lo_nibble_to_hex_lbl:
RTS
}
inline asm void panic() {
JSR _panic
}

View File

@ -1,6 +1,6 @@
[compilation]
arch=nmos
modules=loader_1001,vic20_kernal
modules=loader_1001,vic20_kernal,default_panic
[allocation]

View File

@ -1,6 +1,6 @@
[compilation]
arch=nmos
modules=loader_0401,vic20_kernal
modules=loader_0401,vic20_kernal,default_panic
[allocation]

View File

@ -1,6 +1,6 @@
[compilation]
arch=nmos
modules=loader_1201,vic20_kernal
modules=loader_1201,vic20_kernal,default_panic
[allocation]

View File

@ -78,6 +78,8 @@ object CompilationFlag extends Enumeration {
DetailedFlowAnalysis, DangerousOptimizations, InlineFunctions,
// memory allocation options
VariableOverlap,
// runtime check options
CheckIndexOutOfBounds,
// warning options
ExtraComparisonWarnings,
RorWarning,

View File

@ -77,7 +77,7 @@ object Main {
options = options).run()
val program = if (optLevel > 0) {
OptimizationPresets.NodeOpt.foldLeft(unoptimized)((p, opt) => p.applyNodeOptimization(opt))
OptimizationPresets.NodeOpt.foldLeft(unoptimized)((p, opt) => p.applyNodeOptimization(opt, options))
} else {
unoptimized
}
@ -191,10 +191,13 @@ object Main {
}.description("Whether should prevent indirect JMP bug on page boundary.")
boolean("-fdecimal-mode", "-fno-decimal-mode").action { (c, v) =>
c.changeFlag(CompilationFlag.DecimalMode, v)
}.description("Whether should decimal mode be available.")
}.description("Whether decimal mode should be available.")
boolean("-fvariable-overlap", "-fno-variable-overlap").action { (c, v) =>
c.changeFlag(CompilationFlag.VariableOverlap, v)
}.description("Whether should variables overlap if their scopes do not intersect.")
}.description("Whether variables should overlap if their scopes do not intersect.")
boolean("-fbounds-checking", "-fno-bounds-checking").action { (c, v) =>
c.changeFlag(CompilationFlag.VariableOverlap, v)
}.description("Whether should insert bounds checking on array access.")
fluff("", "Optimization options:", "")

View File

@ -1,11 +1,12 @@
package millfork.node
import millfork.CompilationOptions
import millfork.node.opt.NodeOptimization
/**
* @author Karol Stasiak
*/
case class Program(declarations: List[DeclarationStatement]) {
def applyNodeOptimization(o: NodeOptimization) = Program(o.optimize(declarations).asInstanceOf[List[DeclarationStatement]])
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

@ -1,16 +1,17 @@
package millfork.node.opt
import millfork.CompilationOptions
import millfork.node.{ExecutableStatement, Expression, Node, Statement}
/**
* @author Karol Stasiak
*/
trait NodeOptimization {
def optimize(nodes: List[Node]): List[Node]
def optimize(nodes: List[Node], options: CompilationOptions): List[Node]
def optimizeExecutableStatements(nodes: List[ExecutableStatement]): List[ExecutableStatement] =
optimize(nodes).asInstanceOf[List[ExecutableStatement]]
def optimizeExecutableStatements(nodes: List[ExecutableStatement], options: CompilationOptions): List[ExecutableStatement] =
optimize(nodes, options).asInstanceOf[List[ExecutableStatement]]
def optimizeStatements(nodes: List[Statement]): List[Statement] =
optimize(nodes).asInstanceOf[List[Statement]]
def optimizeStatements(nodes: List[Statement], options: CompilationOptions): List[Statement] =
optimize(nodes, options).asInstanceOf[List[Statement]]
}

View File

@ -1,5 +1,6 @@
package millfork.node.opt
import millfork.CompilationOptions
import millfork.node._
/**
@ -7,21 +8,21 @@ import millfork.node._
*/
object UnreachableCode extends NodeOptimization {
override def optimize(nodes: List[Node]): List[Node] = nodes match {
override def optimize(nodes: List[Node], options: CompilationOptions): List[Node] = nodes match {
case (x:FunctionDeclarationStatement)::xs =>
x.copy(statements = x.statements.map(optimizeStatements)) :: optimize(xs)
x.copy(statements = x.statements.map(optimizeStatements(_, options))) :: optimize(xs, options)
case (x:IfStatement)::xs =>
x.copy(
thenBranch = optimizeExecutableStatements(x.thenBranch),
elseBranch = optimizeExecutableStatements(x.elseBranch)) :: optimize(xs)
thenBranch = optimizeExecutableStatements(x.thenBranch, options),
elseBranch = optimizeExecutableStatements(x.elseBranch, options)) :: optimize(xs, options)
case (x:WhileStatement)::xs =>
x.copy(body = optimizeExecutableStatements(x.body)) :: optimize(xs)
x.copy(body = optimizeExecutableStatements(x.body, options)) :: optimize(xs, options)
case (x:DoWhileStatement)::xs =>
x.copy(body = optimizeExecutableStatements(x.body)) :: optimize(xs)
x.copy(body = optimizeExecutableStatements(x.body, options)) :: optimize(xs, options)
case (x:ReturnStatement) :: xs =>
x :: Nil
case x :: xs =>
x :: optimize(xs)
x :: optimize(xs, options)
case Nil =>
Nil
}

View File

@ -1,5 +1,6 @@
package millfork.node.opt
import millfork.{CompilationFlag, CompilationOptions}
import millfork.env._
import millfork.error.ErrorReporting
import millfork.node._
@ -9,25 +10,28 @@ import millfork.node._
*/
object UnusedFunctions extends NodeOptimization {
override def optimize(nodes: List[Node]): List[Node] = {
override def optimize(nodes: List[Node], options: CompilationOptions): List[Node] = {
val panicRequired = options.flags(CompilationFlag.CheckIndexOutOfBounds)
val allNormalFunctions = nodes.flatMap {
case v: FunctionDeclarationStatement => if (v.address.isDefined || v.interrupt || v.name == "main") Nil else List(v.name)
case v: FunctionDeclarationStatement => if (v.address.isDefined || v.interrupt || v.name == "main" || panicRequired && v.name == "_panic") Nil else List(v.name)
case _ => Nil
}.toSet
val allCalledFunctions = getAllCalledFunctions(nodes).toSet
val unusedFunctions = allNormalFunctions -- allCalledFunctions
if (unusedFunctions.nonEmpty) {
ErrorReporting.debug("Removing unused functions: " + unusedFunctions.mkString(", "))
optimize(removeFunctionsFromProgram(nodes, unusedFunctions), options)
} else {
nodes
}
removeFunctionsFromProgram(nodes, unusedFunctions)
}
private def removeFunctionsFromProgram(nodes: List[Node], unusedVariables: Set[String]): List[Node] = {
private def removeFunctionsFromProgram(nodes: List[Node], unusedFunctions: Set[String]): List[Node] = {
nodes match {
case (x: FunctionDeclarationStatement) :: xs if unusedVariables(x.name) =>
removeFunctionsFromProgram(xs, unusedVariables)
case (x: FunctionDeclarationStatement) :: xs if unusedFunctions(x.name) =>
removeFunctionsFromProgram(xs, unusedFunctions)
case x :: xs =>
x :: removeFunctionsFromProgram(xs, unusedVariables)
x :: removeFunctionsFromProgram(xs, unusedFunctions)
case Nil =>
Nil
}

View File

@ -1,5 +1,6 @@
package millfork.node.opt
import millfork.CompilationOptions
import millfork.env._
import millfork.error.ErrorReporting
import millfork.node._
@ -9,7 +10,7 @@ import millfork.node._
*/
object UnusedGlobalVariables extends NodeOptimization {
override def optimize(nodes: List[Node]): List[Node] = {
override def optimize(nodes: List[Node], options: CompilationOptions): List[Node] = {
// TODO: volatile
val allNonvolatileGlobalVariables = nodes.flatMap {

View File

@ -1,5 +1,6 @@
package millfork.node.opt
import millfork.CompilationOptions
import millfork.assembly.AssemblyLine
import millfork.env._
import millfork.error.ErrorReporting
@ -10,11 +11,11 @@ import millfork.node._
*/
object UnusedLocalVariables extends NodeOptimization {
override def optimize(nodes: List[Node]): List[Node] = nodes match {
override def optimize(nodes: List[Node], options: CompilationOptions): List[Node] = nodes match {
case (x: FunctionDeclarationStatement) :: xs =>
x.copy(statements = x.statements.map(optimizeVariables)) :: optimize(xs)
x.copy(statements = x.statements.map(optimizeVariables)) :: optimize(xs, options)
case x :: xs =>
x :: optimize(xs)
x :: optimize(xs, options)
case Nil =>
Nil
}

View File

@ -94,17 +94,18 @@ class EmuRun(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimization],
CompilationFlag.EmitIllegals -> this.emitIllegals,
CompilationFlag.DetailedFlowAnalysis -> quantum,
CompilationFlag.InlineFunctions -> this.inline,
// CompilationFlag.CheckIndexOutOfBounds -> true,
))
ErrorReporting.hasErrors = false
ErrorReporting.verbosity = 999
val parserF = MfParser("", source, "", options)
val parserF = MfParser("", source + "\n void _panic(){while(true){}}", "", options)
parserF.toAst match {
case Success(unoptimized, _) =>
ErrorReporting.assertNoErrors("Parse failed")
// prepare
val program = nodeOptimizations.foldLeft(unoptimized)((p, opt) => p.applyNodeOptimization(opt))
val program = nodeOptimizations.foldLeft(unoptimized)((p, opt) => p.applyNodeOptimization(opt, options))
val callGraph = new StandardCallGraph(program)
val env = new Environment(None, "")
env.collectDeclarations(program, options)