mirror of
https://github.com/irmen/prog8.git
synced 2025-02-23 07:29:12 +00:00
removed 'continue' statement to be able to generate more optimized loop assembly code. started with for loop optimizations
This commit is contained in:
parent
f14dda4eca
commit
c0887b5f08
@ -305,10 +305,6 @@ class AstToSourceCode(val output: (text: String) -> Unit, val program: Program):
|
||||
output(postIncrDecr.operator)
|
||||
}
|
||||
|
||||
override fun visit(contStmt: Continue) {
|
||||
output("continue")
|
||||
}
|
||||
|
||||
override fun visit(breakStmt: Break) {
|
||||
output("break")
|
||||
}
|
||||
|
@ -217,9 +217,6 @@ private fun prog8Parser.StatementContext.toAst() : Statement {
|
||||
val breakstmt = breakstmt()?.toAst()
|
||||
if(breakstmt!=null) return breakstmt
|
||||
|
||||
val continuestmt = continuestmt()?.toAst()
|
||||
if(continuestmt!=null) return continuestmt
|
||||
|
||||
val whenstmt = whenstmt()?.toAst()
|
||||
if(whenstmt!=null) return whenstmt
|
||||
|
||||
@ -593,8 +590,6 @@ private fun prog8Parser.ForloopContext.toAst(): ForLoop {
|
||||
return ForLoop(loopvar, iterable, scope, toPosition())
|
||||
}
|
||||
|
||||
private fun prog8Parser.ContinuestmtContext.toAst() = Continue(toPosition())
|
||||
|
||||
private fun prog8Parser.BreakstmtContext.toAst() = Break(toPosition())
|
||||
|
||||
private fun prog8Parser.WhileloopContext.toAst(): WhileLoop {
|
||||
|
@ -88,7 +88,6 @@ abstract class AstWalker {
|
||||
open fun before(branchStatement: BranchStatement, parent: Node): Iterable<IAstModification> = emptyList()
|
||||
open fun before(breakStmt: Break, parent: Node): Iterable<IAstModification> = emptyList()
|
||||
open fun before(builtinFunctionStatementPlaceholder: BuiltinFunctionStatementPlaceholder, parent: Node): Iterable<IAstModification> = emptyList()
|
||||
open fun before(contStmt: Continue, parent: Node): Iterable<IAstModification> = emptyList()
|
||||
open fun before(decl: VarDecl, parent: Node): Iterable<IAstModification> = emptyList()
|
||||
open fun before(directive: Directive, parent: Node): Iterable<IAstModification> = emptyList()
|
||||
open fun before(expr: BinaryExpression, parent: Node): Iterable<IAstModification> = emptyList()
|
||||
@ -130,7 +129,6 @@ abstract class AstWalker {
|
||||
open fun after(branchStatement: BranchStatement, parent: Node): Iterable<IAstModification> = emptyList()
|
||||
open fun after(breakStmt: Break, parent: Node): Iterable<IAstModification> = emptyList()
|
||||
open fun after(builtinFunctionStatementPlaceholder: BuiltinFunctionStatementPlaceholder, parent: Node): Iterable<IAstModification> = emptyList()
|
||||
open fun after(contStmt: Continue, parent: Node): Iterable<IAstModification> = emptyList()
|
||||
open fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> = emptyList()
|
||||
open fun after(directive: Directive, parent: Node): Iterable<IAstModification> = emptyList()
|
||||
open fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> = emptyList()
|
||||
@ -309,11 +307,6 @@ abstract class AstWalker {
|
||||
track(after(postIncrDecr, parent), postIncrDecr, parent)
|
||||
}
|
||||
|
||||
fun visit(contStmt: Continue, parent: Node) {
|
||||
track(before(contStmt, parent), contStmt, parent)
|
||||
track(after(contStmt, parent), contStmt, parent)
|
||||
}
|
||||
|
||||
fun visit(breakStmt: Break, parent: Node) {
|
||||
track(before(breakStmt, parent), breakStmt, parent)
|
||||
track(after(breakStmt, parent), breakStmt, parent)
|
||||
|
@ -95,9 +95,6 @@ interface IAstVisitor {
|
||||
postIncrDecr.target.accept(this)
|
||||
}
|
||||
|
||||
fun visit(contStmt: Continue) {
|
||||
}
|
||||
|
||||
fun visit(breakStmt: Break) {
|
||||
}
|
||||
|
||||
|
@ -148,18 +148,6 @@ class ReturnFromIrq(override val position: Position) : Return(null, position) {
|
||||
override fun replaceChildNode(node: Node, replacement: Node) = throw FatalAstException("can't replace here")
|
||||
}
|
||||
|
||||
class Continue(override val position: Position) : Statement() {
|
||||
override lateinit var parent: Node
|
||||
|
||||
override fun linkParents(parent: Node) {
|
||||
this.parent=parent
|
||||
}
|
||||
|
||||
override fun replaceChildNode(node: Node, replacement: Node) = throw FatalAstException("can't replace here")
|
||||
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
|
||||
}
|
||||
|
||||
class Break(override val position: Position) : Statement() {
|
||||
override lateinit var parent: Node
|
||||
|
||||
|
@ -43,13 +43,11 @@ internal class AsmGen(private val program: Program,
|
||||
private val assignmentAsmGen = AssignmentAsmGen(program, errors, this)
|
||||
private val expressionsAsmGen = ExpressionsAsmGen(program, this)
|
||||
internal val loopEndLabels = ArrayDeque<String>()
|
||||
internal val loopContinueLabels = ArrayDeque<String>()
|
||||
internal val blockLevelVarInits = mutableMapOf<Block, MutableSet<VarDecl>>()
|
||||
|
||||
override fun compileToAssembly(optimize: Boolean): IAssemblyProgram {
|
||||
assemblyLines.clear()
|
||||
loopEndLabels.clear()
|
||||
loopContinueLabels.clear()
|
||||
|
||||
println("Generating assembly code... ")
|
||||
|
||||
@ -638,7 +636,6 @@ internal class AsmGen(private val program: Program,
|
||||
is BranchStatement -> translate(stmt)
|
||||
is IfStatement -> translate(stmt)
|
||||
is ForLoop -> forloopsAsmGen.translate(stmt)
|
||||
is Continue -> out(" jmp ${loopContinueLabels.peek()}")
|
||||
is Break -> out(" jmp ${loopEndLabels.peek()}")
|
||||
is WhileLoop -> translate(stmt)
|
||||
is RepeatLoop -> translate(stmt)
|
||||
@ -674,11 +671,11 @@ internal class AsmGen(private val program: Program,
|
||||
}
|
||||
|
||||
private fun translate(stmt: RepeatLoop) {
|
||||
// TODO more optimized code possible now that continue is gone?
|
||||
val repeatLabel = makeLabel("repeat")
|
||||
val endLabel = makeLabel("repeatend")
|
||||
val counterLabel = makeLabel("repeatcounter")
|
||||
loopEndLabels.push(endLabel)
|
||||
loopContinueLabels.push(repeatLabel)
|
||||
|
||||
when (stmt.iterations) {
|
||||
null -> {
|
||||
@ -737,7 +734,6 @@ internal class AsmGen(private val program: Program,
|
||||
}
|
||||
|
||||
loopEndLabels.pop()
|
||||
loopContinueLabels.pop()
|
||||
}
|
||||
|
||||
private fun repeatWordCountInAY(counterVar: String, repeatLabel: String, endLabel: String, body: AnonymousScope) {
|
||||
@ -778,10 +774,10 @@ $endLabel""")
|
||||
}
|
||||
|
||||
private fun translate(stmt: WhileLoop) {
|
||||
// TODO more optimized code possible now that continue is gone?
|
||||
val whileLabel = makeLabel("while")
|
||||
val endLabel = makeLabel("whileend")
|
||||
loopEndLabels.push(endLabel)
|
||||
loopContinueLabels.push(whileLabel)
|
||||
out(whileLabel)
|
||||
expressionsAsmGen.translateExpression(stmt.condition)
|
||||
val conditionDt = stmt.condition.inferType(program)
|
||||
@ -802,14 +798,13 @@ $endLabel""")
|
||||
out(" jmp $whileLabel")
|
||||
out(endLabel)
|
||||
loopEndLabels.pop()
|
||||
loopContinueLabels.pop()
|
||||
}
|
||||
|
||||
private fun translate(stmt: UntilLoop) {
|
||||
// TODO more optimized code possible now that continue is gone?
|
||||
val repeatLabel = makeLabel("repeat")
|
||||
val endLabel = makeLabel("repeatend")
|
||||
loopEndLabels.push(endLabel)
|
||||
loopContinueLabels.push(repeatLabel)
|
||||
out(repeatLabel)
|
||||
translate(stmt.body)
|
||||
expressionsAsmGen.translateExpression(stmt.untilCondition)
|
||||
@ -829,7 +824,6 @@ $endLabel""")
|
||||
}
|
||||
out(endLabel)
|
||||
loopEndLabels.pop()
|
||||
loopContinueLabels.pop()
|
||||
}
|
||||
|
||||
private fun translate(stmt: WhenStatement) {
|
||||
|
@ -14,9 +14,8 @@ import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_LO_PLUS1_HEX
|
||||
import prog8.compiler.toHex
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
// todo optimized loop code for common simple cases 0..N, N..0, >=1..N , N..>=1 where N<=255
|
||||
// todo choose more efficient comparisons to avoid needless lda's
|
||||
// todo optimize common case when step == 2 or -2
|
||||
// todo optimized code for step == 2 or -2
|
||||
// todo allocate loop counter variable dynamically, preferrably on zeropage
|
||||
|
||||
internal class ForLoopsAsmGen(private val program: Program, private val asmgen: AsmGen) {
|
||||
@ -42,11 +41,11 @@ internal class ForLoopsAsmGen(private val program: Program, private val asmgen:
|
||||
}
|
||||
|
||||
private fun translateForOverNonconstRange(stmt: ForLoop, iterableDt: DataType, range: RangeExpr) {
|
||||
// TODO more optimized code possible now that continue is gone?
|
||||
|
||||
val loopLabel = asmgen.makeLabel("for_loop")
|
||||
val endLabel = asmgen.makeLabel("for_end")
|
||||
val continueLabel = asmgen.makeLabel("for_continue")
|
||||
asmgen.loopEndLabels.push(endLabel)
|
||||
asmgen.loopContinueLabels.push(continueLabel)
|
||||
val stepsize=range.step.constValue(program)!!.number.toInt()
|
||||
when(iterableDt) {
|
||||
DataType.ARRAY_B, DataType.ARRAY_UB -> {
|
||||
@ -66,7 +65,7 @@ internal class ForLoopsAsmGen(private val program: Program, private val asmgen:
|
||||
$loopLabel""")
|
||||
asmgen.translate(stmt.body)
|
||||
asmgen.out("""
|
||||
$continueLabel lda $varname
|
||||
lda $varname
|
||||
cmp $ESTACK_LO_PLUS1_HEX,x
|
||||
beq $endLabel
|
||||
$incdec $varname
|
||||
@ -88,7 +87,7 @@ $endLabel inx""")
|
||||
$loopLabel""")
|
||||
asmgen.translate(stmt.body)
|
||||
asmgen.out("""
|
||||
$continueLabel lda $varname""")
|
||||
lda $varname""")
|
||||
if(stepsize>0) {
|
||||
asmgen.out("""
|
||||
clc
|
||||
@ -248,15 +247,13 @@ $endLabel inx""")
|
||||
}
|
||||
|
||||
asmgen.loopEndLabels.pop()
|
||||
asmgen.loopContinueLabels.pop()
|
||||
}
|
||||
|
||||
private fun translateForOverIterableVar(stmt: ForLoop, iterableDt: DataType, ident: IdentifierReference) {
|
||||
// TODO more optimized code possible now that continue is gone?
|
||||
val loopLabel = asmgen.makeLabel("for_loop")
|
||||
val endLabel = asmgen.makeLabel("for_end")
|
||||
val continueLabel = asmgen.makeLabel("for_continue")
|
||||
asmgen.loopEndLabels.push(endLabel)
|
||||
asmgen.loopContinueLabels.push(continueLabel)
|
||||
val iterableName = asmgen.asmIdentifierName(ident)
|
||||
val decl = ident.targetVarDecl(program.namespace)!!
|
||||
when(iterableDt) {
|
||||
@ -271,7 +268,7 @@ $loopLabel lda ${65535.toHex()} ; modified
|
||||
asmgen.out(" sta ${asmgen.asmIdentifierName(stmt.loopVar)}")
|
||||
asmgen.translate(stmt.body)
|
||||
asmgen.out("""
|
||||
$continueLabel inc $loopLabel+1
|
||||
inc $loopLabel+1
|
||||
bne $loopLabel
|
||||
inc $loopLabel+2
|
||||
bne $loopLabel
|
||||
@ -293,7 +290,7 @@ $modifiedLabel lda ${65535.toHex()},y ; modified""")
|
||||
asmgen.out(" sta ${asmgen.asmIdentifierName(stmt.loopVar)}")
|
||||
asmgen.translate(stmt.body)
|
||||
asmgen.out("""
|
||||
$continueLabel ldy $counterLabel
|
||||
ldy $counterLabel
|
||||
iny
|
||||
cpy #${length and 255}
|
||||
beq $endLabel
|
||||
@ -325,7 +322,7 @@ $modifiedLabel2 lda ${65535.toHex()},y ; modified
|
||||
sta $loopvarName+1""")
|
||||
asmgen.translate(stmt.body)
|
||||
asmgen.out("""
|
||||
$continueLabel ldy $counterLabel
|
||||
ldy $counterLabel
|
||||
iny
|
||||
iny
|
||||
cpy #${length and 255}
|
||||
@ -340,57 +337,34 @@ $endLabel""")
|
||||
else -> throw AssemblyError("can't iterate over $iterableDt")
|
||||
}
|
||||
asmgen.loopEndLabels.pop()
|
||||
asmgen.loopContinueLabels.pop()
|
||||
}
|
||||
|
||||
private fun translateForOverConstRange(stmt: ForLoop, iterableDt: DataType, range: IntProgression) {
|
||||
// TODO: optimize loop code when the range is < 256 iterations
|
||||
if (range.isEmpty())
|
||||
throw AssemblyError("empty range")
|
||||
if (range.isEmpty() || range.step==0)
|
||||
throw AssemblyError("empty range or step 0")
|
||||
if(iterableDt==DataType.ARRAY_B || iterableDt==DataType.ARRAY_UB) {
|
||||
if(range.step==1 && range.first>=0 && range.last <= 255 && range.last>range.first) return translateForSimpleByteRangeAsc(stmt, range)
|
||||
if(range.step==-1 && range.first<=255 && range.first >=0 && range.last<range.first) return translateForSimpleByteRangeDesc(stmt, range)
|
||||
}
|
||||
if(iterableDt==DataType.ARRAY_W || iterableDt==DataType.ARRAY_UW) {
|
||||
if(range.step==1 && range.first>=0 && range.last <= 255 && range.last>range.first) return translateForSimpleWordRange255Asc(stmt, range)
|
||||
if(range.step==-1 && range.first<=255 && range.first >=0 && range.last<range.first) return translateForSimpleWordRange255Desc(stmt, range)
|
||||
if(range.step==1 && range.first>=0 && range.last <= 65535 && range.last>range.first) return translateForSimpleWordRange65535Asc(stmt, range)
|
||||
if(range.step==-1 && range.first<=65535 && range.first >=0 && range.last<range.first) return translateForSimpleWordRange65535Desc(stmt, range)
|
||||
}
|
||||
|
||||
val loopLabel = asmgen.makeLabel("for_loop")
|
||||
val endLabel = asmgen.makeLabel("for_end")
|
||||
val continueLabel = asmgen.makeLabel("for_continue")
|
||||
asmgen.loopEndLabels.push(endLabel)
|
||||
asmgen.loopContinueLabels.push(continueLabel)
|
||||
// TODO more optimized code possible now that continue is gone?
|
||||
when(iterableDt) {
|
||||
DataType.ARRAY_B, DataType.ARRAY_UB -> {
|
||||
// loop over byte range via loopvar, step > 1 or < -1
|
||||
val counterLabel = asmgen.makeLabel("for_counter")
|
||||
// loop over byte range via loopvar
|
||||
val varname = asmgen.asmIdentifierName(stmt.loopVar)
|
||||
when {
|
||||
range.step==1 -> {
|
||||
// step = 1
|
||||
asmgen.out("""
|
||||
lda #${range.first}
|
||||
sta $varname
|
||||
lda #${range.last-range.first+1 and 255}
|
||||
sta $counterLabel
|
||||
$loopLabel""")
|
||||
asmgen.translate(stmt.body)
|
||||
asmgen.out("""
|
||||
$continueLabel dec $counterLabel
|
||||
beq $endLabel
|
||||
inc $varname
|
||||
jmp $loopLabel
|
||||
$counterLabel .byte 0
|
||||
$endLabel""")
|
||||
}
|
||||
range.step==-1 -> {
|
||||
// step = -1
|
||||
asmgen.out("""
|
||||
lda #${range.first}
|
||||
sta $varname
|
||||
lda #${range.first-range.last+1 and 255}
|
||||
sta $counterLabel
|
||||
$loopLabel""")
|
||||
asmgen.translate(stmt.body)
|
||||
asmgen.out("""
|
||||
$continueLabel dec $counterLabel
|
||||
beq $endLabel
|
||||
dec $varname
|
||||
jmp $loopLabel
|
||||
$counterLabel .byte 0
|
||||
$endLabel""")
|
||||
range.step==1 || range.step==-1 -> {
|
||||
throw AssemblyError("step 1 and -1 should have been handled specifically")
|
||||
}
|
||||
range.step >= 2 -> {
|
||||
// step >= 2
|
||||
@ -402,7 +376,7 @@ $endLabel""")
|
||||
$loopLabel""")
|
||||
asmgen.translate(stmt.body)
|
||||
asmgen.out("""
|
||||
$continueLabel dec $counterLabel
|
||||
dec $counterLabel
|
||||
beq $endLabel
|
||||
lda $varname
|
||||
clc
|
||||
@ -422,7 +396,7 @@ $endLabel""")
|
||||
$loopLabel""")
|
||||
asmgen.translate(stmt.body)
|
||||
asmgen.out("""
|
||||
$continueLabel dec $counterLabel
|
||||
dec $counterLabel
|
||||
beq $endLabel
|
||||
lda $varname
|
||||
sec
|
||||
@ -435,56 +409,59 @@ $endLabel""")
|
||||
}
|
||||
}
|
||||
DataType.ARRAY_W, DataType.ARRAY_UW -> {
|
||||
// loop over word range via loopvar
|
||||
// loop over word range via loopvar, step > 1 or < -1
|
||||
val varname = asmgen.asmIdentifierName(stmt.loopVar)
|
||||
when {
|
||||
range.step == 1 -> {
|
||||
// word, step = 1
|
||||
val lastValue = range.last+1
|
||||
asmgen.out("""
|
||||
lda #<${range.first}
|
||||
ldy #>${range.first}
|
||||
sta $varname
|
||||
sty $varname+1
|
||||
$loopLabel""")
|
||||
asmgen.translate(stmt.body)
|
||||
asmgen.out("""
|
||||
$continueLabel inc $varname
|
||||
bne +
|
||||
inc $varname+1
|
||||
+ lda $varname
|
||||
cmp #<$lastValue
|
||||
bne +
|
||||
lda $varname+1
|
||||
cmp #>$lastValue
|
||||
beq $endLabel
|
||||
+ jmp $loopLabel
|
||||
$endLabel""")
|
||||
}
|
||||
range.step == -1 -> {
|
||||
// word, step = 1
|
||||
val lastValue = range.last-1
|
||||
asmgen.out("""
|
||||
lda #<${range.first}
|
||||
ldy #>${range.first}
|
||||
sta $varname
|
||||
sty $varname+1
|
||||
$loopLabel""")
|
||||
asmgen.translate(stmt.body)
|
||||
asmgen.out("""
|
||||
$continueLabel lda $varname
|
||||
bne +
|
||||
dec $varname+1
|
||||
+ dec $varname
|
||||
lda $varname
|
||||
cmp #<$lastValue
|
||||
bne +
|
||||
lda $varname+1
|
||||
cmp #>$lastValue
|
||||
beq $endLabel
|
||||
+ jmp $loopLabel
|
||||
$endLabel""")
|
||||
range.step==1 || range.step==-1 -> {
|
||||
throw AssemblyError("step 1 and -1 should have been handled specifically")
|
||||
}
|
||||
// range.step == 1 -> {
|
||||
// // word, step = 1
|
||||
// val lastValue = range.last+1
|
||||
// asmgen.out("""
|
||||
// lda #<${range.first}
|
||||
// ldy #>${range.first}
|
||||
// sta $varname
|
||||
// sty $varname+1
|
||||
//$loopLabel""")
|
||||
// asmgen.translate(stmt.body)
|
||||
// asmgen.out("""
|
||||
// inc $varname
|
||||
// bne +
|
||||
// inc $varname+1
|
||||
//+ lda $varname
|
||||
// cmp #<$lastValue
|
||||
// bne +
|
||||
// lda $varname+1
|
||||
// cmp #>$lastValue
|
||||
// beq $endLabel
|
||||
//+ jmp $loopLabel
|
||||
//$endLabel""")
|
||||
// }
|
||||
// range.step == -1 -> {
|
||||
// // word, step = 1
|
||||
// val lastValue = range.last-1
|
||||
// asmgen.out("""
|
||||
// lda #<${range.first}
|
||||
// ldy #>${range.first}
|
||||
// sta $varname
|
||||
// sty $varname+1
|
||||
//$loopLabel""")
|
||||
// asmgen.translate(stmt.body)
|
||||
// asmgen.out("""
|
||||
// lda $varname
|
||||
// bne +
|
||||
// dec $varname+1
|
||||
//+ dec $varname
|
||||
// lda $varname
|
||||
// cmp #<$lastValue
|
||||
// bne +
|
||||
// lda $varname+1
|
||||
// cmp #>$lastValue
|
||||
// beq $endLabel
|
||||
//+ jmp $loopLabel
|
||||
//$endLabel""")
|
||||
// }
|
||||
range.step >= 2 -> {
|
||||
// word, step >= 2
|
||||
// note: range.last has already been adjusted by kotlin itself to actually be the last value of the sequence
|
||||
@ -497,7 +474,7 @@ $endLabel""")
|
||||
$loopLabel""")
|
||||
asmgen.translate(stmt.body)
|
||||
asmgen.out("""
|
||||
$continueLabel clc
|
||||
clc
|
||||
lda $varname
|
||||
adc #<${range.step}
|
||||
sta $varname
|
||||
@ -525,7 +502,7 @@ $endLabel""")
|
||||
$loopLabel""")
|
||||
asmgen.translate(stmt.body)
|
||||
asmgen.out("""
|
||||
$continueLabel sec
|
||||
sec
|
||||
lda $varname
|
||||
sbc #<${range.step.absoluteValue}
|
||||
sta $varname
|
||||
@ -546,7 +523,102 @@ $endLabel""")
|
||||
else -> throw AssemblyError("range expression can only be byte or word")
|
||||
}
|
||||
asmgen.loopEndLabels.pop()
|
||||
asmgen.loopContinueLabels.pop()
|
||||
}
|
||||
|
||||
private fun translateForSimpleByteRangeAsc(stmt: ForLoop, range: IntProgression) {
|
||||
val loopLabel = asmgen.makeLabel("for_loop")
|
||||
val endLabel = asmgen.makeLabel("for_end")
|
||||
asmgen.loopEndLabels.push(endLabel)
|
||||
val varname = asmgen.asmIdentifierName(stmt.loopVar)
|
||||
if (range.last == 255) {
|
||||
asmgen.out("""
|
||||
lda #${range.first}
|
||||
sta $varname
|
||||
$loopLabel""")
|
||||
asmgen.translate(stmt.body)
|
||||
asmgen.out("""
|
||||
inc $varname
|
||||
bne $loopLabel
|
||||
$endLabel""")
|
||||
} else {
|
||||
asmgen.out("""
|
||||
lda #${range.first}
|
||||
sta $varname
|
||||
$loopLabel""")
|
||||
asmgen.translate(stmt.body)
|
||||
asmgen.out("""
|
||||
lda $varname
|
||||
cmp #${range.last}
|
||||
beq $endLabel
|
||||
inc $varname
|
||||
bne $loopLabel
|
||||
$endLabel""")
|
||||
}
|
||||
asmgen.loopEndLabels.pop()
|
||||
}
|
||||
|
||||
private fun translateForSimpleByteRangeDesc(stmt: ForLoop, range: IntProgression) {
|
||||
val loopLabel = asmgen.makeLabel("for_loop")
|
||||
val endLabel = asmgen.makeLabel("for_end")
|
||||
asmgen.loopEndLabels.push(endLabel)
|
||||
val varname = asmgen.asmIdentifierName(stmt.loopVar)
|
||||
when (range.last) {
|
||||
0 -> {
|
||||
asmgen.out("""
|
||||
lda #${range.first}
|
||||
sta $varname
|
||||
$loopLabel""")
|
||||
asmgen.translate(stmt.body)
|
||||
asmgen.out("""
|
||||
lda $varname
|
||||
beq $endLabel
|
||||
dec $varname
|
||||
jmp $loopLabel
|
||||
$endLabel""")
|
||||
}
|
||||
1 -> {
|
||||
asmgen.out("""
|
||||
lda #${range.first}
|
||||
sta $varname
|
||||
$loopLabel""")
|
||||
asmgen.translate(stmt.body)
|
||||
asmgen.out("""
|
||||
dec $varname
|
||||
bne $loopLabel
|
||||
$endLabel""")
|
||||
}
|
||||
else -> {
|
||||
asmgen.out("""
|
||||
lda #${range.first}
|
||||
sta $varname
|
||||
$loopLabel""")
|
||||
asmgen.translate(stmt.body)
|
||||
asmgen.out("""
|
||||
lda $varname
|
||||
cmp #${range.last}
|
||||
beq $endLabel
|
||||
dec $varname
|
||||
bne $loopLabel
|
||||
$endLabel""")
|
||||
}
|
||||
}
|
||||
asmgen.loopEndLabels.pop()
|
||||
}
|
||||
|
||||
private fun translateForSimpleWordRange255Asc(stmt: ForLoop, range: IntProgression) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
private fun translateForSimpleWordRange255Desc(stmt: ForLoop, range: IntProgression) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
private fun translateForSimpleWordRange65535Asc(stmt: ForLoop, range: IntProgression) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
private fun translateForSimpleWordRange65535Desc(stmt: ForLoop, range: IntProgression) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -14,11 +14,6 @@ import prog8.functions.BuiltinFunctions
|
||||
import kotlin.math.floor
|
||||
|
||||
|
||||
/*
|
||||
TODO: remove unreachable code after return and exit()
|
||||
*/
|
||||
|
||||
|
||||
internal class StatementOptimizer(private val program: Program,
|
||||
private val errors: ErrorReporter) : AstWalker() {
|
||||
|
||||
@ -257,9 +252,9 @@ internal class StatementOptimizer(private val program: Program,
|
||||
val constvalue = untilLoop.untilCondition.constValue(program)
|
||||
if(constvalue!=null) {
|
||||
if(constvalue.asBooleanValue) {
|
||||
// always true -> keep only the statement block (if there are no continue and break statements)
|
||||
// always true -> keep only the statement block (if there are no break statements)
|
||||
errors.warn("condition is always true", untilLoop.untilCondition.position)
|
||||
if(!hasContinueOrBreak(untilLoop.body))
|
||||
if(!hasBreak(untilLoop.body))
|
||||
return listOf(IAstModification.ReplaceNode(untilLoop, untilLoop.body, parent))
|
||||
} else {
|
||||
// always false
|
||||
@ -495,7 +490,7 @@ internal class StatementOptimizer(private val program: Program,
|
||||
return linesToRemove
|
||||
}
|
||||
|
||||
private fun hasContinueOrBreak(scope: INameScope): Boolean {
|
||||
private fun hasBreak(scope: INameScope): Boolean {
|
||||
|
||||
class Searcher: IAstVisitor
|
||||
{
|
||||
@ -504,10 +499,6 @@ internal class StatementOptimizer(private val program: Program,
|
||||
override fun visit(breakStmt: Break) {
|
||||
count++
|
||||
}
|
||||
|
||||
override fun visit(contStmt: Continue) {
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
val s=Searcher()
|
||||
|
@ -6,6 +6,9 @@ import prog8.ast.processing.AstWalker
|
||||
import prog8.ast.processing.IAstModification
|
||||
import prog8.ast.statements.Block
|
||||
|
||||
/*
|
||||
TODO: remove unreachable code after return and exit()
|
||||
*/
|
||||
|
||||
internal class UnusedCodeRemover: AstWalker() {
|
||||
|
||||
|
@ -397,6 +397,8 @@ The *repeat* loop is used as a short notation of a for loop where the loop varia
|
||||
|
||||
You can also create loops by using the ``goto`` statement, but this should usually be avoided.
|
||||
|
||||
Breaking out of a loop prematurely is possible with the ``break`` statement.
|
||||
|
||||
.. attention::
|
||||
The value of the loop variable after executing the loop *is undefined*. Don't use it immediately
|
||||
after the loop without first assigning a new value to it!
|
||||
|
@ -559,7 +559,6 @@ You can use a single statement, or a statement block like in the example below::
|
||||
for <loopvar> in <expression> [ step <amount> ] {
|
||||
; do something...
|
||||
break ; break out of the loop
|
||||
continue ; immediately enter next iteration
|
||||
}
|
||||
|
||||
For example, this is a for loop using a byte variable ``i``, defined before, to loop over a certain range of numbers::
|
||||
@ -592,7 +591,6 @@ You can use a single statement, or a statement block like in the example below::
|
||||
while <condition> {
|
||||
; do something...
|
||||
break ; break out of the loop
|
||||
continue ; immediately enter next iteration
|
||||
}
|
||||
|
||||
|
||||
@ -605,7 +603,6 @@ You can use a single statement, or a statement block like in the example below::
|
||||
do {
|
||||
; do something...
|
||||
break ; break out of the loop
|
||||
continue ; immediately enter next iteration
|
||||
} until <condition>
|
||||
|
||||
|
||||
|
@ -2,9 +2,10 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
- finalize (most) of the still missing "new" assignment asm code generation
|
||||
- aliases for imported symbols for example perhaps '%alias print = c64scr.print'
|
||||
- option to load library files from a directory instead of the embedded ones (easier library development/debugging)
|
||||
- get rid of all TODO's ;-)
|
||||
- allow declaring arrays on specific memory location and page-aligned
|
||||
- option to load the built-inlibrary files from a directory instead of the embedded ones (for easier library development/debugging)
|
||||
- aliases for imported symbols for example perhaps '%alias print = c64scr.print' ?
|
||||
- investigate support for 8bitguy's Commander X16 platform https://www.commanderx16.com and https://github.com/commanderx16/x16-docs
|
||||
- see if we can group some errors together for instance the (now single) errors about unidentified symbols
|
||||
|
||||
|
74
examples/mfbench/romsum-p8.p8
Normal file
74
examples/mfbench/romsum-p8.p8
Normal file
@ -0,0 +1,74 @@
|
||||
%import c64utils
|
||||
|
||||
main {
|
||||
|
||||
const uword rom = $e000
|
||||
|
||||
sub sumrom() -> uword {
|
||||
uword p = rom
|
||||
uword s = 0
|
||||
ubyte i
|
||||
repeat $20 {
|
||||
for i in 0 to $ff {
|
||||
s += @(p+i)
|
||||
}
|
||||
p += $100
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
sub start() {
|
||||
benchcommon.begin()
|
||||
ubyte i
|
||||
for i in 0 to 5 {
|
||||
c64scr.print_uw(sumrom())
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
benchcommon.end()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
benchcommon {
|
||||
ubyte last_time0 = 0
|
||||
ubyte last_time1 = 0
|
||||
ubyte last_time2 = 0
|
||||
ubyte time_start0 = 0
|
||||
ubyte time_start1 = 0
|
||||
ubyte time_start2 = 0
|
||||
|
||||
|
||||
asmsub read_time () clobbers(A,X,Y) {
|
||||
%asm {{
|
||||
jsr $FFDE
|
||||
sta last_time0
|
||||
stx last_time1
|
||||
sty last_time2
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
sub begin() {
|
||||
benchcommon.read_time()
|
||||
benchcommon.time_start0 = benchcommon.last_time0
|
||||
benchcommon.time_start1 = benchcommon.last_time1
|
||||
benchcommon.time_start2 = benchcommon.last_time2
|
||||
}
|
||||
|
||||
sub end() {
|
||||
benchcommon.read_time()
|
||||
|
||||
c64scr.print_ubhex(benchcommon.time_start2, false)
|
||||
c64scr.print_ubhex(benchcommon.time_start1, false)
|
||||
c64scr.print_ubhex(benchcommon.time_start0, false)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
c64scr.print_ubhex(benchcommon.last_time2, false)
|
||||
c64scr.print_ubhex(benchcommon.last_time1, false)
|
||||
c64scr.print_ubhex(benchcommon.last_time0, false)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
void c64scr.input_chars($c000)
|
||||
}
|
||||
}
|
||||
|
88
examples/mfbench/sieve-p8.p8
Normal file
88
examples/mfbench/sieve-p8.p8
Normal file
@ -0,0 +1,88 @@
|
||||
%import c64utils
|
||||
|
||||
main {
|
||||
|
||||
const uword COUNT = 16384
|
||||
const uword SQRT_COUNT = 128
|
||||
const uword Sieve = $4000
|
||||
|
||||
sub sieve_round() {
|
||||
uword S
|
||||
ubyte I = 2
|
||||
memset(Sieve, COUNT, 0)
|
||||
while I < SQRT_COUNT {
|
||||
if @(Sieve + I) == 0 {
|
||||
S = Sieve + (I << 1)
|
||||
while S < Sieve + COUNT {
|
||||
@(S) = 1
|
||||
S += I
|
||||
}
|
||||
}
|
||||
I ++
|
||||
}
|
||||
}
|
||||
|
||||
sub start() {
|
||||
benchcommon.begin()
|
||||
|
||||
sieve_round()
|
||||
sieve_round()
|
||||
sieve_round()
|
||||
sieve_round()
|
||||
sieve_round()
|
||||
|
||||
sieve_round()
|
||||
sieve_round()
|
||||
sieve_round()
|
||||
sieve_round()
|
||||
sieve_round()
|
||||
|
||||
benchcommon.end()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
benchcommon {
|
||||
ubyte last_time0 = 0
|
||||
ubyte last_time1 = 0
|
||||
ubyte last_time2 = 0
|
||||
ubyte time_start0 = 0
|
||||
ubyte time_start1 = 0
|
||||
ubyte time_start2 = 0
|
||||
|
||||
|
||||
asmsub read_time () clobbers(A,X,Y) {
|
||||
%asm {{
|
||||
jsr $FFDE
|
||||
sta last_time0
|
||||
stx last_time1
|
||||
sty last_time2
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
sub begin() {
|
||||
benchcommon.read_time()
|
||||
benchcommon.time_start0 = benchcommon.last_time0
|
||||
benchcommon.time_start1 = benchcommon.last_time1
|
||||
benchcommon.time_start2 = benchcommon.last_time2
|
||||
}
|
||||
|
||||
sub end() {
|
||||
benchcommon.read_time()
|
||||
|
||||
c64scr.print_ubhex(benchcommon.time_start2, false)
|
||||
c64scr.print_ubhex(benchcommon.time_start1, false)
|
||||
c64scr.print_ubhex(benchcommon.time_start0, false)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
c64scr.print_ubhex(benchcommon.last_time2, false)
|
||||
c64scr.print_ubhex(benchcommon.last_time1, false)
|
||||
c64scr.print_ubhex(benchcommon.last_time0, false)
|
||||
c64.CHROUT('\n')
|
||||
|
||||
void c64scr.input_chars($c000)
|
||||
}
|
||||
}
|
||||
|
120
examples/test.p8
120
examples/test.p8
@ -2,49 +2,97 @@
|
||||
%import c64utils
|
||||
%import c64flt
|
||||
%zeropage basicsafe
|
||||
%option enable_floats
|
||||
|
||||
main {
|
||||
|
||||
sub start() {
|
||||
ubyte counterb
|
||||
uword counterw
|
||||
|
||||
ubyte wv
|
||||
ubyte wv2
|
||||
|
||||
wv = wv + wv + wv
|
||||
for counterb in 0 to 10 {
|
||||
c64scr.print_ub(counterb)
|
||||
c64.CHROUT(',')
|
||||
}
|
||||
c64.CHROUT('\n')
|
||||
|
||||
; wv *= wv2
|
||||
;
|
||||
; wv += 10
|
||||
; wv += 20
|
||||
; wv += 30
|
||||
;
|
||||
; wv += 1 + wv2
|
||||
; wv += 2 + wv2
|
||||
; wv += 3 + wv2
|
||||
;
|
||||
; wv += wv2 + 1
|
||||
; wv += wv2 + 2
|
||||
; wv += wv2 + 3
|
||||
;
|
||||
; wv = wv + 1 + wv2
|
||||
; wv = wv + 2 + wv2
|
||||
; wv = wv + 3 + wv2
|
||||
;
|
||||
; wv = 1 + wv2 + wv
|
||||
; wv = 2 + wv2 + wv
|
||||
; wv = 3 + wv2 + wv
|
||||
;
|
||||
; wv = wv + wv2 + 1
|
||||
; wv = wv + wv2 + 2
|
||||
; wv = wv + wv2 + 3
|
||||
;
|
||||
; wv = wv2 + 1 + wv
|
||||
; wv = wv2 + 2 + wv
|
||||
; wv = wv2 + 3 + wv
|
||||
for counterb in 10 to 30 {
|
||||
c64scr.print_ub(counterb)
|
||||
c64.CHROUT(',')
|
||||
}
|
||||
c64.CHROUT('\n')
|
||||
|
||||
wv = wv2 + wv + 1
|
||||
wv = wv2 + wv + 2
|
||||
wv = wv2 + wv + 3
|
||||
for counterb in 250 to 255 {
|
||||
c64scr.print_ub(counterb)
|
||||
c64.CHROUT(',')
|
||||
}
|
||||
c64.CHROUT('\n')
|
||||
|
||||
for counterb in 10 to 0 step -1 {
|
||||
c64scr.print_ub(counterb)
|
||||
c64.CHROUT(',')
|
||||
}
|
||||
c64.CHROUT('\n')
|
||||
|
||||
for counterb in 10 to 1 step -1 {
|
||||
c64scr.print_ub(counterb)
|
||||
c64.CHROUT(',')
|
||||
}
|
||||
c64.CHROUT('\n')
|
||||
|
||||
for counterb in 30 to 10 step -1 {
|
||||
c64scr.print_ub(counterb)
|
||||
c64.CHROUT(',')
|
||||
}
|
||||
c64.CHROUT('\n')
|
||||
|
||||
for counterb in 255 to 250 step -1 {
|
||||
c64scr.print_ub(counterb)
|
||||
c64.CHROUT(',')
|
||||
}
|
||||
c64.CHROUT('\n')
|
||||
c64.CHROUT('\n')
|
||||
|
||||
for counterw in 0 to 10 {
|
||||
c64scr.print_uw(counterw)
|
||||
c64.CHROUT(',')
|
||||
}
|
||||
c64.CHROUT('\n')
|
||||
|
||||
for counterw in 10 to 30 {
|
||||
c64scr.print_uw(counterw)
|
||||
c64.CHROUT(',')
|
||||
}
|
||||
c64.CHROUT('\n')
|
||||
|
||||
for counterw in 250 to 255 {
|
||||
c64scr.print_uw(counterw)
|
||||
c64.CHROUT(',')
|
||||
}
|
||||
c64.CHROUT('\n')
|
||||
|
||||
for counterw in 10 to 0 step -1 {
|
||||
c64scr.print_uw(counterw)
|
||||
c64.CHROUT(',')
|
||||
}
|
||||
c64.CHROUT('\n')
|
||||
|
||||
for counterw in 10 to 1 step -1 {
|
||||
c64scr.print_uw(counterw)
|
||||
c64.CHROUT(',')
|
||||
}
|
||||
c64.CHROUT('\n')
|
||||
|
||||
for counterw in 30 to 10 step -1 {
|
||||
c64scr.print_uw(counterw)
|
||||
c64.CHROUT(',')
|
||||
}
|
||||
c64.CHROUT('\n')
|
||||
|
||||
for counterw in 255 to 250 step -1 {
|
||||
c64scr.print_uw(counterw)
|
||||
c64.CHROUT(',')
|
||||
}
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
}
|
||||
|
@ -98,7 +98,6 @@ statement :
|
||||
| repeatloop
|
||||
| whenstmt
|
||||
| breakstmt
|
||||
| continuestmt
|
||||
| labeldef
|
||||
;
|
||||
|
||||
@ -214,8 +213,6 @@ returnstmt : 'return' expression? ;
|
||||
|
||||
breakstmt : 'break';
|
||||
|
||||
continuestmt: 'continue';
|
||||
|
||||
identifier : NAME ;
|
||||
|
||||
scoped_identifier : NAME ('.' NAME)* ;
|
||||
|
Loading…
x
Reference in New Issue
Block a user