mirror of
https://github.com/irmen/prog8.git
synced 2024-12-24 16:29:21 +00:00
slight optimization of repeat loop (0-256 iters) code generation on 65c02 cpu
This commit is contained in:
parent
583e208c1e
commit
1e8d8e40a2
@ -1128,13 +1128,13 @@ class AsmGen(private val program: Program,
|
||||
}
|
||||
|
||||
private fun translate(stmt: RepeatLoop) {
|
||||
val repeatLabel = makeLabel("repeat")
|
||||
val endLabel = makeLabel("repeatend")
|
||||
loopEndLabels.push(endLabel)
|
||||
|
||||
when (stmt.iterations) {
|
||||
null -> {
|
||||
// endless loop
|
||||
val repeatLabel = makeLabel("repeat")
|
||||
out(repeatLabel)
|
||||
translate(stmt.body)
|
||||
jmp(repeatLabel)
|
||||
@ -1146,13 +1146,11 @@ class AsmGen(private val program: Program,
|
||||
throw AssemblyError("invalid number of iterations")
|
||||
when {
|
||||
iterations == 0 -> {}
|
||||
iterations <= 256 -> {
|
||||
out(" lda #${iterations and 255}")
|
||||
repeatByteCountInA(iterations, repeatLabel, endLabel, stmt)
|
||||
}
|
||||
iterations == 1 -> translate(stmt.body)
|
||||
iterations <= 256 -> repeatByteCount(iterations, stmt)
|
||||
else -> {
|
||||
out(" lda #<${iterations} | ldy #>${iterations}")
|
||||
repeatWordCountInAY(iterations, repeatLabel, endLabel, stmt)
|
||||
repeatWordCountInAY(iterations, endLabel, stmt)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1161,12 +1159,12 @@ class AsmGen(private val program: Program,
|
||||
val name = asmVariableName(stmt.iterations as IdentifierReference)
|
||||
when(vardecl.datatype) {
|
||||
DataType.UBYTE, DataType.BYTE -> {
|
||||
assignVariableToRegister(name, RegisterOrPair.A)
|
||||
repeatByteCountInA(null, repeatLabel, endLabel, stmt)
|
||||
assignVariableToRegister(name, RegisterOrPair.Y)
|
||||
repeatCountInY(stmt, endLabel)
|
||||
}
|
||||
DataType.UWORD, DataType.WORD -> {
|
||||
assignVariableToRegister(name, RegisterOrPair.AY)
|
||||
repeatWordCountInAY(null, repeatLabel, endLabel, stmt)
|
||||
repeatWordCountInAY(null, endLabel, stmt)
|
||||
}
|
||||
else -> throw AssemblyError("invalid loop variable datatype $vardecl")
|
||||
}
|
||||
@ -1177,12 +1175,12 @@ class AsmGen(private val program: Program,
|
||||
throw AssemblyError("unknown dt")
|
||||
when (dt.getOr(DataType.UNDEFINED)) {
|
||||
in ByteDatatypes -> {
|
||||
assignExpressionToRegister(stmt.iterations!!, RegisterOrPair.A)
|
||||
repeatByteCountInA(null, repeatLabel, endLabel, stmt)
|
||||
assignExpressionToRegister(stmt.iterations!!, RegisterOrPair.Y)
|
||||
repeatCountInY(stmt, endLabel)
|
||||
}
|
||||
in WordDatatypes -> {
|
||||
assignExpressionToRegister(stmt.iterations!!, RegisterOrPair.AY)
|
||||
repeatWordCountInAY(null, repeatLabel, endLabel, stmt)
|
||||
repeatWordCountInAY(null, endLabel, stmt)
|
||||
}
|
||||
else -> throw AssemblyError("invalid loop expression datatype $dt")
|
||||
}
|
||||
@ -1192,13 +1190,14 @@ class AsmGen(private val program: Program,
|
||||
loopEndLabels.pop()
|
||||
}
|
||||
|
||||
private fun repeatWordCountInAY(constIterations: Int?, repeatLabel: String, endLabel: String, stmt: RepeatLoop) {
|
||||
private fun repeatWordCountInAY(constIterations: Int?, endLabel: String, stmt: RepeatLoop) {
|
||||
// note: A/Y must have been loaded with the number of iterations!
|
||||
if(constIterations==0)
|
||||
return
|
||||
// no need to explicitly test for 0 iterations as this is done in the countdown logic below
|
||||
|
||||
val counterVar: String = createRepeatCounterVar(DataType.UWORD, constIterations, stmt)
|
||||
val repeatLabel = makeLabel("repeat")
|
||||
val counterVar = createRepeatCounterVar(DataType.UWORD, false, stmt)!!
|
||||
out("""
|
||||
sta $counterVar
|
||||
sty $counterVar+1
|
||||
@ -1216,23 +1215,58 @@ $repeatLabel lda $counterVar
|
||||
out(endLabel)
|
||||
}
|
||||
|
||||
private fun repeatByteCountInA(constIterations: Int?, repeatLabel: String, endLabel: String, stmt: RepeatLoop) {
|
||||
// note: A must be loaded with the number of iterations!
|
||||
if(constIterations==0)
|
||||
return
|
||||
|
||||
if(constIterations==null)
|
||||
out(" beq $endLabel ; skip loop if zero iters")
|
||||
val counterVar = createRepeatCounterVar(DataType.UBYTE, constIterations, stmt)
|
||||
out(" sta $counterVar")
|
||||
out(repeatLabel)
|
||||
translate(stmt.body)
|
||||
out(" dec $counterVar | bne $repeatLabel")
|
||||
if(constIterations==null)
|
||||
out(endLabel)
|
||||
private fun repeatByteCount(count: Int, stmt: RepeatLoop) {
|
||||
require(count in 2..256)
|
||||
val repeatLabel = makeLabel("repeat")
|
||||
if(isTargetCpu(CpuType.CPU65c02)) {
|
||||
val counterVar = createRepeatCounterVar(DataType.UBYTE, true, stmt)
|
||||
if(counterVar!=null) {
|
||||
out(" lda #${count and 255} | sta $counterVar")
|
||||
out(repeatLabel)
|
||||
translate(stmt.body)
|
||||
out(" dec $counterVar | bne $repeatLabel")
|
||||
} else {
|
||||
out(" ldy #${count and 255}")
|
||||
out("$repeatLabel phy")
|
||||
translate(stmt.body)
|
||||
out(" ply | dey | bne $repeatLabel")
|
||||
}
|
||||
} else {
|
||||
val counterVar = createRepeatCounterVar(DataType.UBYTE, false, stmt)
|
||||
out(" lda #${count and 255} | sta $counterVar")
|
||||
out(repeatLabel)
|
||||
translate(stmt.body)
|
||||
out(" dec $counterVar | bne $repeatLabel")
|
||||
}
|
||||
}
|
||||
|
||||
private fun createRepeatCounterVar(dt: DataType, constIterations: Int?, stmt: RepeatLoop): String {
|
||||
private fun repeatCountInY(stmt: RepeatLoop, endLabel: String) {
|
||||
// note: Y must just have been loaded with the (variable) number of loops to be performed!
|
||||
val repeatLabel = makeLabel("repeat")
|
||||
if(isTargetCpu(CpuType.CPU65c02)) {
|
||||
val counterVar = createRepeatCounterVar(DataType.UBYTE, true, stmt)
|
||||
if(counterVar!=null) {
|
||||
out(" beq $endLabel | sty $counterVar")
|
||||
out(repeatLabel)
|
||||
translate(stmt.body)
|
||||
out(" dec $counterVar | bne $repeatLabel")
|
||||
} else {
|
||||
out(" beq $endLabel")
|
||||
out("$repeatLabel phy")
|
||||
translate(stmt.body)
|
||||
out(" ply | dey | bne $repeatLabel")
|
||||
}
|
||||
} else {
|
||||
val counterVar = createRepeatCounterVar(DataType.UBYTE, false, stmt)!!
|
||||
out(" beq $endLabel | sty $counterVar")
|
||||
out(repeatLabel)
|
||||
translate(stmt.body)
|
||||
out(" dec $counterVar | bne $repeatLabel")
|
||||
}
|
||||
out(endLabel)
|
||||
}
|
||||
|
||||
private fun createRepeatCounterVar(dt: DataType, mustBeInZeropage: Boolean, stmt: RepeatLoop): String? {
|
||||
val asmInfo = stmt.definingSubroutine!!.asmGenInfo
|
||||
var parent = stmt.parent
|
||||
while(parent !is ParentSentinel) {
|
||||
@ -1245,27 +1279,33 @@ $repeatLabel lda $counterVar
|
||||
if(!isNested) {
|
||||
// we can re-use a counter var from the subroutine if it already has one for that datatype
|
||||
val existingVar = asmInfo.extraVars.firstOrNull { it.first==dt }
|
||||
if(existingVar!=null)
|
||||
return existingVar.second
|
||||
if(existingVar!=null) {
|
||||
if(!mustBeInZeropage || existingVar.third!=null)
|
||||
return existingVar.second
|
||||
}
|
||||
}
|
||||
|
||||
val counterVar = makeLabel("repeatcounter")
|
||||
val counterVar = makeLabel("counter")
|
||||
when(dt) {
|
||||
DataType.UBYTE -> {
|
||||
if(constIterations!=null && constIterations>=16 && zeropage.hasByteAvailable()) {
|
||||
if(zeropage.hasByteAvailable()) {
|
||||
// allocate count var on ZP
|
||||
val zpAddr = zeropage.allocate(counterVar, DataType.UBYTE, stmt.position, errors)
|
||||
asmInfo.extraVars.add(Triple(DataType.UBYTE, counterVar, zpAddr))
|
||||
} else {
|
||||
if(mustBeInZeropage)
|
||||
return null
|
||||
asmInfo.extraVars.add(Triple(DataType.UBYTE, counterVar, null))
|
||||
}
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
if(constIterations!=null && constIterations>=16 && zeropage.hasWordAvailable()) {
|
||||
if(zeropage.hasWordAvailable()) {
|
||||
// allocate count var on ZP
|
||||
val zpAddr = zeropage.allocate(counterVar, DataType.UWORD, stmt.position, errors)
|
||||
asmInfo.extraVars.add(Triple(DataType.UWORD, counterVar, zpAddr))
|
||||
} else {
|
||||
if(mustBeInZeropage)
|
||||
return null
|
||||
asmInfo.extraVars.add(Triple(DataType.UWORD, counterVar, null))
|
||||
}
|
||||
}
|
||||
|
@ -3,12 +3,14 @@ TODO
|
||||
|
||||
For next compiler release (7.6)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
...
|
||||
see if the 16 bit repeat code can be optimized on 65c02 a bit more as well, like the 8 bit
|
||||
|
||||
|
||||
Need help with
|
||||
^^^^^^^^^^^^^^
|
||||
- c128 target: various machine specific things (free zp locations, how banking works, getting the floating point routines working, ...)
|
||||
- other targets such as Atari 800XL: all required details about the machine, I have no clue whatsoever
|
||||
- see the Porting Guide in the documentation for this.
|
||||
|
||||
|
||||
Blocked by an official Commander-x16 r39 release
|
||||
@ -45,6 +47,7 @@ Future
|
||||
|
||||
More code optimization ideas
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
- if a for loop's loopvariable isn't referenced in the body, replace by a repeatloop
|
||||
- automatically convert if statements that test for multiple values (if X==1 or X==2..) to if X in [1,2,..] statements, instead of just a warning
|
||||
- byte typed expressions should be evaluated in the accumulator where possible, without (temp)var
|
||||
for instance value = otherbyte >> 1 --> lda otherbite ; lsr a; sta value
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
rm -f *.jar *.asm *.prg *.vm.txt *.vice-mon-list a.out
|
||||
rm -f *.jar *.asm *.prg *.vm.txt *.vice-mon-list *.list a.out imgui.ini
|
||||
rm -rf build out
|
||||
rm -rf compiler/build codeGeneration/build codeOptimizers/build compilerInterfaces/build compilerAst/build dbusCompilerService/build httpCompilerService/build parser/build
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user