mirror of
https://github.com/irmen/prog8.git
synced 2025-04-05 03:37:25 +00:00
lower code: break -> goto after (simplifies codegen)
This commit is contained in:
parent
a090fe3834
commit
4da4f96669
@ -781,18 +781,14 @@ class AsmGen(private val program: Program,
|
||||
is BranchStatement -> translate(stmt)
|
||||
is IfStatement -> translate(stmt)
|
||||
is ForLoop -> forloopsAsmGen.translate(stmt)
|
||||
is Break -> {
|
||||
if(loopEndLabels.isEmpty())
|
||||
throw AssemblyError("break statement out of context ${stmt.position}")
|
||||
jmp(loopEndLabels.peek())
|
||||
}
|
||||
is WhileLoop -> translate(stmt)
|
||||
is RepeatLoop -> translate(stmt)
|
||||
is UntilLoop -> translate(stmt)
|
||||
is WhenStatement -> translate(stmt)
|
||||
is BuiltinFunctionStatementPlaceholder -> throw AssemblyError("builtin function should not have placeholder anymore?")
|
||||
is AnonymousScope -> translate(stmt)
|
||||
is BuiltinFunctionStatementPlaceholder -> throw AssemblyError("builtin function should not have placeholder anymore")
|
||||
is Block -> throw AssemblyError("block should have been handled elsewhere")
|
||||
is Break -> throw AssemblyError("break should have been replaced by goto")
|
||||
else -> throw AssemblyError("missing asm translation for $stmt")
|
||||
}
|
||||
}
|
||||
@ -1366,34 +1362,12 @@ $repeatLabel lda $counterVar
|
||||
out(" $instruction ${getJumpTarget(jump)}")
|
||||
translate(stmt.elsepart)
|
||||
} else {
|
||||
val truePartIsJustBreak = stmt.truepart.statements.firstOrNull() is Break
|
||||
val elsePartIsJustBreak = stmt.elsepart.statements.firstOrNull() is Break
|
||||
if(stmt.elsepart.isEmpty()) {
|
||||
if(truePartIsJustBreak) {
|
||||
// branch with just a break (jump out of loop)
|
||||
val instruction = branchInstruction(stmt.condition, false)
|
||||
val loopEndLabel = loopEndLabels.peek()
|
||||
out(" $instruction $loopEndLabel")
|
||||
} else {
|
||||
val instruction = branchInstruction(stmt.condition, true)
|
||||
val elseLabel = makeLabel("branch_else")
|
||||
out(" $instruction $elseLabel")
|
||||
translate(stmt.truepart)
|
||||
out(elseLabel)
|
||||
}
|
||||
}
|
||||
else if(truePartIsJustBreak) {
|
||||
// branch with just a break (jump out of loop)
|
||||
val instruction = branchInstruction(stmt.condition, false)
|
||||
val loopEndLabel = loopEndLabels.peek()
|
||||
out(" $instruction $loopEndLabel")
|
||||
translate(stmt.elsepart)
|
||||
} else if(elsePartIsJustBreak) {
|
||||
// branch with just a break (jump out of loop) but true/false inverted
|
||||
val instruction = branchInstruction(stmt.condition, true)
|
||||
val loopEndLabel = loopEndLabels.peek()
|
||||
out(" $instruction $loopEndLabel")
|
||||
val elseLabel = makeLabel("branch_else")
|
||||
out(" $instruction $elseLabel")
|
||||
translate(stmt.truepart)
|
||||
out(elseLabel)
|
||||
} else {
|
||||
val instruction = branchInstruction(stmt.condition, true)
|
||||
val elseLabel = makeLabel("branch_else")
|
||||
|
@ -6,7 +6,6 @@ import prog8.ast.expressions.*
|
||||
import prog8.ast.statements.*
|
||||
import prog8.ast.walk.AstWalker
|
||||
import prog8.ast.walk.IAstModification
|
||||
import prog8.ast.walk.IAstVisitor
|
||||
import prog8.compilerinterface.ICompilationTarget
|
||||
import prog8.compilerinterface.IErrorReporter
|
||||
import prog8.compilerinterface.size
|
||||
@ -228,15 +227,14 @@ class StatementOptimizer(private val program: Program,
|
||||
override fun before(untilLoop: UntilLoop, parent: Node): Iterable<IAstModification> {
|
||||
val constvalue = untilLoop.condition.constValue(program)
|
||||
if(constvalue!=null) {
|
||||
if(constvalue.asBooleanValue) {
|
||||
// always true -> keep only the statement block (if there are no break statements)
|
||||
return if(constvalue.asBooleanValue) {
|
||||
// always true -> keep only the statement block
|
||||
errors.warn("condition is always true", untilLoop.condition.position)
|
||||
if(!hasBreak(untilLoop.body))
|
||||
return listOf(IAstModification.ReplaceNode(untilLoop, untilLoop.body, parent))
|
||||
listOf(IAstModification.ReplaceNode(untilLoop, untilLoop.body, parent))
|
||||
} else {
|
||||
// always false
|
||||
val forever = RepeatLoop(null, untilLoop.body, untilLoop.position)
|
||||
return listOf(IAstModification.ReplaceNode(untilLoop, forever, parent))
|
||||
listOf(IAstModification.ReplaceNode(untilLoop, forever, parent))
|
||||
}
|
||||
}
|
||||
return noModifications
|
||||
@ -474,25 +472,4 @@ class StatementOptimizer(private val program: Program,
|
||||
|
||||
return noModifications
|
||||
}
|
||||
|
||||
private fun hasBreak(scope: IStatementContainer): Boolean {
|
||||
|
||||
class Searcher: IAstVisitor
|
||||
{
|
||||
var count=0
|
||||
|
||||
override fun visit(breakStmt: Break) {
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
val s=Searcher()
|
||||
for(stmt in scope.statements) {
|
||||
stmt.accept(s)
|
||||
if(s.count>0)
|
||||
return true
|
||||
}
|
||||
return s.count > 0
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -31,6 +31,10 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, private val o
|
||||
varsList.add(decl.name to decl)
|
||||
}
|
||||
|
||||
override fun before(breakStmt: Break, parent: Node): Iterable<IAstModification> {
|
||||
throw FatalAstException("break should have been replaced by goto $breakStmt")
|
||||
}
|
||||
|
||||
override fun before(block: Block, parent: Node): Iterable<IAstModification> {
|
||||
// move all subroutines to the bottom of the block
|
||||
val subs = block.statements.filterIsInstance<Subroutine>()
|
||||
|
@ -76,8 +76,8 @@ fun compileProgram(args: CompilerArguments): CompilationResult {
|
||||
)
|
||||
postprocessAst(program, args.errors, compilationOptions)
|
||||
|
||||
// println("*********** AST BEFORE ASSEMBLYGEN *************")
|
||||
// printProgram(program)
|
||||
println("*********** AST BEFORE ASSEMBLYGEN *************")
|
||||
printProgram(program)
|
||||
|
||||
if (args.writeAssembly) {
|
||||
when (val result = writeAssembly(program, args.errors, args.outputDir, args.quietAssembler, compilationOptions)) {
|
||||
@ -267,6 +267,8 @@ private fun processAst(program: Program, errors: IErrorReporter, compilerOptions
|
||||
errors.report()
|
||||
program.reorderStatements(errors, compilerOptions)
|
||||
errors.report()
|
||||
program.desugaring(errors)
|
||||
errors.report()
|
||||
program.addTypecasts(errors, compilerOptions)
|
||||
errors.report()
|
||||
program.variousCleanups(program, errors)
|
||||
@ -295,11 +297,11 @@ private fun optimizeAst(program: Program, compilerOptions: CompilationOptions, e
|
||||
if (optsDone1 + optsDone2 + optsDone3 == 0)
|
||||
break
|
||||
}
|
||||
|
||||
errors.report()
|
||||
}
|
||||
|
||||
private fun postprocessAst(program: Program, errors: IErrorReporter, compilerOptions: CompilationOptions) {
|
||||
program.desugaring(errors)
|
||||
program.addTypecasts(errors, compilerOptions)
|
||||
errors.report()
|
||||
program.variousCleanups(program, errors)
|
||||
|
@ -59,6 +59,12 @@ internal fun Program.addTypecasts(errors: IErrorReporter, options: CompilationOp
|
||||
caster.applyModifications()
|
||||
}
|
||||
|
||||
fun Program.desugaring(errors: IErrorReporter): Int {
|
||||
val desugar = CodeDesugarer(this, errors)
|
||||
desugar.visit(this)
|
||||
return desugar.applyModifications()
|
||||
}
|
||||
|
||||
internal fun Program.verifyFunctionArgTypes() {
|
||||
val fixer = VerifyFunctionArgTypes(this)
|
||||
fixer.visit(this)
|
||||
|
59
compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt
Normal file
59
compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt
Normal file
@ -0,0 +1,59 @@
|
||||
package prog8.compiler.astprocessing
|
||||
|
||||
import prog8.ast.IStatementContainer
|
||||
import prog8.ast.Node
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.ParentSentinel
|
||||
import prog8.ast.expressions.IdentifierReference
|
||||
import prog8.ast.statements.*
|
||||
import prog8.ast.walk.AstWalker
|
||||
import prog8.ast.walk.IAstModification
|
||||
import prog8.compilerinterface.*
|
||||
|
||||
|
||||
internal class CodeDesugarer(val program: Program, private val errors: IErrorReporter) : AstWalker() {
|
||||
|
||||
// Some more code shuffling to simplify the Ast that the codegenerator has to process.
|
||||
// Several changes have already been done by the StatementReorderer !
|
||||
// But the ones here are simpler and are repeated once again after all optimization steps
|
||||
// have been performed (because those could re-introduce nodes that have to be desugared)
|
||||
//
|
||||
// List of modifications:
|
||||
// - replace 'break' statements by a goto + generated after label.
|
||||
|
||||
|
||||
private var generatedLabelSequenceNumber: Int = 0
|
||||
private val generatedLabelPrefix = "prog8_label_"
|
||||
|
||||
private fun makeLabel(postfix: String): String {
|
||||
generatedLabelSequenceNumber++
|
||||
return "${generatedLabelPrefix}${generatedLabelSequenceNumber}_$postfix"
|
||||
}
|
||||
|
||||
override fun before(breakStmt: Break, parent: Node): Iterable<IAstModification> {
|
||||
fun jumpAfter(stmt: Statement): Iterable<IAstModification> {
|
||||
val labelName = makeLabel("after")
|
||||
val ident = IdentifierReference(listOf(labelName), breakStmt.position)
|
||||
return listOf(
|
||||
IAstModification.ReplaceNode(breakStmt, Jump(null, ident, null, breakStmt.position), parent),
|
||||
IAstModification.InsertAfter(stmt, Label(labelName, breakStmt.position), stmt.parent as IStatementContainer)
|
||||
)
|
||||
}
|
||||
|
||||
var partof = parent
|
||||
while(true) {
|
||||
when (partof) {
|
||||
is Subroutine, is Block, is ParentSentinel -> {
|
||||
errors.err("break in wrong scope", breakStmt.position)
|
||||
return noModifications
|
||||
}
|
||||
is ForLoop,
|
||||
is RepeatLoop,
|
||||
is UntilLoop,
|
||||
is WhileLoop -> return jumpAfter(partof as Statement)
|
||||
else -> partof = partof.parent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -8,10 +8,8 @@ import prog8.ast.walk.AstWalker
|
||||
import prog8.ast.walk.IAstModification
|
||||
import prog8.compilerinterface.BuiltinFunctions
|
||||
import prog8.compilerinterface.CompilationOptions
|
||||
import prog8.compilerinterface.ICompilationTarget
|
||||
import prog8.compilerinterface.IErrorReporter
|
||||
|
||||
|
||||
internal class StatementReorderer(val program: Program,
|
||||
val errors: IErrorReporter,
|
||||
private val options: CompilationOptions) : AstWalker() {
|
||||
|
@ -1,19 +1,38 @@
|
||||
|
||||
%import textio
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
||||
ubyte @shared joy_info
|
||||
|
||||
sub start() {
|
||||
void pushing_start()
|
||||
}
|
||||
ubyte @shared xx
|
||||
repeat {
|
||||
xx++
|
||||
if xx==10
|
||||
break
|
||||
}
|
||||
txt.print_ub(xx)
|
||||
txt.nl()
|
||||
|
||||
sub pushing_start() -> ubyte {
|
||||
joy_info++
|
||||
return not c64.READST()
|
||||
}
|
||||
while xx<50 {
|
||||
xx++
|
||||
if xx==40
|
||||
break
|
||||
}
|
||||
txt.print_ub(xx)
|
||||
txt.nl()
|
||||
|
||||
sub derp(ubyte aa) -> ubyte {
|
||||
aa++
|
||||
return aa*2
|
||||
do {
|
||||
xx++
|
||||
if xx==80
|
||||
break
|
||||
} until xx>100
|
||||
txt.print_ub(xx)
|
||||
txt.nl()
|
||||
|
||||
for xx in 0 to 25 {
|
||||
if xx==20
|
||||
break
|
||||
}
|
||||
txt.print_ub(xx)
|
||||
txt.nl()
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user