mirror of
https://github.com/irmen/prog8.git
synced 2024-11-22 15:33:02 +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
|
||||
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
|
||||
}}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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>()
|
||||
|
@ -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) },
|
||||
|
@ -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)
|
||||
optimizationsDone++
|
||||
repeatLoop.body
|
||||
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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user