fix some optimizations of loops, added some conditional branch optimizations

This commit is contained in:
Irmen de Jong 2019-01-27 19:14:58 +01:00
parent c4a28b8502
commit 798c4d7902
7 changed files with 107 additions and 36 deletions

View File

@ -121,7 +121,7 @@ asmsub uword2bcd (uword value @ AY) -> clobbers(A,Y) -> () {
dey ; and repeat for next bit
bne -
cld ; back to binary
cli ; enable interrupts again
cli ; enable interrupts again @todo don't re-enable if it wasn't enabled before
rts
}}
}

View File

@ -72,6 +72,7 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
optimizeVariableCopying()
optimizeMultipleSequentialLineInstrs()
optimizeCallReturnIntoJump()
optimizeConditionalBranches()
// todo: add more optimizations to stackvm code
optimizeRemoveNops() // must be done as the last step
@ -79,6 +80,57 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
optimizeRemoveNops() // once more
}
private fun optimizeConditionalBranches() {
// conditional branches that consume the value on the stack
// sometimes these are just constant values, so we can statically determine the branch
// or, they are preceded by a NOT instruction so we can simply remove that and flip the branch condition
val pushvalue = setOf(Opcode.PUSH_BYTE, Opcode.PUSH_WORD)
val notvalue = setOf(Opcode.NOT_BYTE, Opcode.NOT_WORD)
val branchOpcodes = setOf(Opcode.JZ, Opcode.JNZ, Opcode.JZW, Opcode.JNZW)
for(blk in blocks) {
val instructionsToReplace = mutableMapOf<Int, Instruction>()
blk.instructions.asSequence().withIndex().filter {it.value.opcode!=Opcode.LINE}.windowed(2).toList().forEach {
if (it[1].value.opcode in branchOpcodes) {
if (it[0].value.opcode in pushvalue) {
val value = it[0].value.arg!!.asBooleanValue
instructionsToReplace[it[0].index] = Instruction(Opcode.NOP)
val replacement: Instruction =
if (value) {
when (it[1].value.opcode) {
Opcode.JNZ -> Instruction(Opcode.JUMP, callLabel = it[1].value.callLabel)
Opcode.JNZW -> Instruction(Opcode.JUMP, callLabel = it[1].value.callLabel)
else -> Instruction(Opcode.NOP)
}
} else {
when (it[1].value.opcode) {
Opcode.JZ -> Instruction(Opcode.JUMP, callLabel = it[1].value.callLabel)
Opcode.JZW -> Instruction(Opcode.JUMP, callLabel = it[1].value.callLabel)
else -> Instruction(Opcode.NOP)
}
}
instructionsToReplace[it[1].index] = replacement
}
else if (it[0].value.opcode in notvalue) {
instructionsToReplace[it[0].index] = Instruction(Opcode.NOP)
val replacement: Instruction =
when (it[1].value.opcode) {
Opcode.JZ -> Instruction(Opcode.JNZ, callLabel = it[1].value.callLabel)
Opcode.JZW -> Instruction(Opcode.JNZW, callLabel = it[1].value.callLabel)
Opcode.JNZ -> Instruction(Opcode.JZ, callLabel = it[1].value.callLabel)
Opcode.JNZW -> Instruction(Opcode.JZW, callLabel = it[1].value.callLabel)
else -> Instruction(Opcode.NOP)
}
instructionsToReplace[it[1].index] = replacement
}
}
}
for (rins in instructionsToReplace) {
blk.instructions[rins.key] = rins.value
}
}
}
private fun optimizeRemoveNops() {
// remove nops (that are not a label)
for (blk in blocks)

View File

@ -16,6 +16,9 @@ import kotlin.math.abs
class AssemblyError(msg: String) : RuntimeException(msg)
// TODO: code generation for POW instruction
class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, val heap: HeapValues, val zeropage: Zeropage) {
private val globalFloatConsts = mutableMapOf<Double, String>()
private val assemblyLines = mutableListOf<String>()

View File

@ -45,6 +45,7 @@ val BuiltinFunctions = mapOf(
"atan" to FunctionSignature(true, listOf(BuiltinFunctionParam("rads", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, n, h -> oneDoubleArg(a, p, n, h, Math::atan) },
"ln" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, n, h -> oneDoubleArg(a, p, n, h, Math::log) },
"log2" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, n, h -> oneDoubleArg(a, p, n, h, ::log2) },
// TODO: sqrt() should have integer versions too
"sqrt" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, n, h -> oneDoubleArg(a, p, n, h, Math::sqrt) },
"rad" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, n, h -> oneDoubleArg(a, p, n, h, Math::toRadians) },
"deg" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, n, h -> oneDoubleArg(a, p, n, h, Math::toDegrees) },

View File

@ -285,10 +285,14 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
val constvalue = repeatLoop.untilCondition.constValue(namespace, heap)
if(constvalue!=null) {
return if(constvalue.asBooleanValue){
// always true -> keep only the statement block
// always true -> keep only the statement block (if there are no continue and break statements)
printWarning("condition is always true", repeatLoop.position)
if(hasContinueOrBreak(repeatLoop.body))
repeatLoop
else {
optimizationsDone++
repeatLoop.body
}
} else {
// always false -> print a warning, and optimize into body + jump (if there are no continue and break statements)
printWarning("condition is always false", repeatLoop.position)

View File

@ -40,3 +40,10 @@ Should use the zeropage for variables
- Variables should be allocated in the zeropage as long as it has space.
- add some sort of ``zp`` modifier keyword on vardecls to force them into zeropage?
Misc
^^^^
- sqrt() should have integer implementation as well, instead of relying on float SQRT for all argument types
- code generation for POW instruction

View File

@ -1,44 +1,48 @@
%import c64utils
%import c64flt
%option enable_floats
~ main {
ubyte xx=99
word yy=12345
sub start() {
c64scr.print_ub(xx)
c64.CHROUT('\n')
c64scr.print_w(yy)
c64.CHROUT('\n')
foo.derp()
foo2.derp()
ubyte ub
byte b
word w
uword uw
float f1
float f2
float f3
float f4
float f5
float f6
f1=sqrt(A)
f1=A**0.5
f2=ub**0.5
f3=b**0.5
f4=w**0.5
f5=uw**0.5
f6=f1**0.5
; A=A**5
; ub=ub**5
; b=b**5
; w=w**5
; uw=uw**5
; f=f**5
;
; A=A**Y
; ub=ub**Y
; b=b**Y
; w=w**Y
; uw=uw**Y
; f=f**Y
}
; @todo code for pow()
; @todo optimize code generation for "if blah ..." and "if not blah ..."
; @todo optimize vm
; push_byte ub:01
; jnz _prog8stmt_7_loop
}
~ foo {
ubyte woo=2
sub derp() {
A=woo
}
}
~ foo2 {
sub derp() {
ubyte woo=3
A=99
}
}