mirror of
https://github.com/irmen/prog8.git
synced 2025-01-12 04:30:03 +00:00
fix some optimizations of loops, added some conditional branch optimizations
This commit is contained in:
parent
c4a28b8502
commit
798c4d7902
@ -121,7 +121,7 @@ asmsub uword2bcd (uword value @ AY) -> clobbers(A,Y) -> () {
|
|||||||
dey ; and repeat for next bit
|
dey ; and repeat for next bit
|
||||||
bne -
|
bne -
|
||||||
cld ; back to binary
|
cld ; back to binary
|
||||||
cli ; enable interrupts again
|
cli ; enable interrupts again @todo don't re-enable if it wasn't enabled before
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
@ -72,6 +72,7 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
|
|||||||
optimizeVariableCopying()
|
optimizeVariableCopying()
|
||||||
optimizeMultipleSequentialLineInstrs()
|
optimizeMultipleSequentialLineInstrs()
|
||||||
optimizeCallReturnIntoJump()
|
optimizeCallReturnIntoJump()
|
||||||
|
optimizeConditionalBranches()
|
||||||
// todo: add more optimizations to stackvm code
|
// todo: add more optimizations to stackvm code
|
||||||
|
|
||||||
optimizeRemoveNops() // must be done as the last step
|
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
|
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() {
|
private fun optimizeRemoveNops() {
|
||||||
// remove nops (that are not a label)
|
// remove nops (that are not a label)
|
||||||
for (blk in blocks)
|
for (blk in blocks)
|
||||||
|
@ -16,6 +16,9 @@ import kotlin.math.abs
|
|||||||
class AssemblyError(msg: String) : RuntimeException(msg)
|
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) {
|
class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, val heap: HeapValues, val zeropage: Zeropage) {
|
||||||
private val globalFloatConsts = mutableMapOf<Double, String>()
|
private val globalFloatConsts = mutableMapOf<Double, String>()
|
||||||
private val assemblyLines = mutableListOf<String>()
|
private val assemblyLines = mutableListOf<String>()
|
||||||
|
@ -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) },
|
"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) },
|
"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) },
|
"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) },
|
"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) },
|
"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) },
|
"deg" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, n, h -> oneDoubleArg(a, p, n, h, Math::toDegrees) },
|
||||||
|
@ -285,10 +285,14 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
|
|||||||
val constvalue = repeatLoop.untilCondition.constValue(namespace, heap)
|
val constvalue = repeatLoop.untilCondition.constValue(namespace, heap)
|
||||||
if(constvalue!=null) {
|
if(constvalue!=null) {
|
||||||
return if(constvalue.asBooleanValue){
|
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)
|
printWarning("condition is always true", repeatLoop.position)
|
||||||
|
if(hasContinueOrBreak(repeatLoop.body))
|
||||||
|
repeatLoop
|
||||||
|
else {
|
||||||
optimizationsDone++
|
optimizationsDone++
|
||||||
repeatLoop.body
|
repeatLoop.body
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// always false -> print a warning, and optimize into body + jump (if there are no continue and break statements)
|
// 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)
|
printWarning("condition is always false", repeatLoop.position)
|
||||||
|
@ -40,3 +40,10 @@ Should use the zeropage for variables
|
|||||||
- Variables should be allocated in the zeropage as long as it has space.
|
- 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?
|
- 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
|
||||||
|
|
||||||
|
@ -1,44 +1,48 @@
|
|||||||
%import c64utils
|
%import c64utils
|
||||||
|
%import c64flt
|
||||||
|
%option enable_floats
|
||||||
|
|
||||||
~ main {
|
~ main {
|
||||||
|
|
||||||
ubyte xx=99
|
|
||||||
word yy=12345
|
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
c64scr.print_ub(xx)
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
c64scr.print_w(yy)
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
|
|
||||||
foo.derp()
|
ubyte ub
|
||||||
foo2.derp()
|
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 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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user