mirror of
https://github.com/irmen/prog8.git
synced 2025-02-22 16:29:05 +00:00
fixed and optimized branches and gotos in if statements
This commit is contained in:
parent
209b50ddf7
commit
dd02d97db4
@ -5,13 +5,11 @@ import prog8.ast.RegisterOrPair.*
|
|||||||
import prog8.compiler.intermediate.IntermediateProgram
|
import prog8.compiler.intermediate.IntermediateProgram
|
||||||
import prog8.compiler.intermediate.Opcode
|
import prog8.compiler.intermediate.Opcode
|
||||||
import prog8.compiler.intermediate.Value
|
import prog8.compiler.intermediate.Value
|
||||||
|
import prog8.compiler.intermediate.branchOpcodes
|
||||||
import prog8.optimizing.same
|
import prog8.optimizing.same
|
||||||
import prog8.parser.tryGetEmbeddedResource
|
import prog8.parser.tryGetEmbeddedResource
|
||||||
import prog8.stackvm.Syscall
|
import prog8.stackvm.Syscall
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.InputStream
|
|
||||||
import java.io.InputStreamReader
|
|
||||||
import java.nio.file.Paths
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
@ -514,10 +512,24 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
|||||||
* _stmt_999_end:
|
* _stmt_999_end:
|
||||||
* nop
|
* nop
|
||||||
*
|
*
|
||||||
* @todo generate more efficient bytecode for the form with just jumps: if(..) goto .. [else goto ..]
|
* For if statements with goto's, more efficient code is generated.
|
||||||
*/
|
*/
|
||||||
prog.line(stmt.position)
|
prog.line(stmt.position)
|
||||||
translate(stmt.condition)
|
translate(stmt.condition)
|
||||||
|
|
||||||
|
val trueGoto = stmt.truepart.statements.singleOrNull() as? Jump
|
||||||
|
if(trueGoto!=null) {
|
||||||
|
// optimization for if (condition) goto ....
|
||||||
|
val conditionJumpOpcode = when(stmt.condition.resultingDatatype(namespace, heap)) {
|
||||||
|
DataType.UBYTE, DataType.BYTE -> Opcode.JNZ
|
||||||
|
DataType.UWORD, DataType.WORD -> Opcode.JNZW
|
||||||
|
else -> throw CompilerException("invalid condition datatype (expected byte or word) $stmt")
|
||||||
|
}
|
||||||
|
translate(trueGoto, conditionJumpOpcode)
|
||||||
|
translate(stmt.elsepart)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val conditionJumpOpcode = when(stmt.condition.resultingDatatype(namespace, heap)) {
|
val conditionJumpOpcode = when(stmt.condition.resultingDatatype(namespace, heap)) {
|
||||||
DataType.UBYTE, DataType.BYTE -> Opcode.JZ
|
DataType.UBYTE, DataType.BYTE -> Opcode.JZ
|
||||||
DataType.UWORD, DataType.WORD -> Opcode.JZW
|
DataType.UWORD, DataType.WORD -> Opcode.JZW
|
||||||
@ -1388,7 +1400,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
|||||||
when {
|
when {
|
||||||
stmt.generatedLabel!=null -> jumpLabel = stmt.generatedLabel
|
stmt.generatedLabel!=null -> jumpLabel = stmt.generatedLabel
|
||||||
stmt.address!=null -> {
|
stmt.address!=null -> {
|
||||||
if(branchOpcode!=null)
|
if(branchOpcode in branchOpcodes)
|
||||||
throw CompilerException("cannot branch to address, should use absolute jump instead")
|
throw CompilerException("cannot branch to address, should use absolute jump instead")
|
||||||
jumpAddress = Value(DataType.UWORD, stmt.address)
|
jumpAddress = Value(DataType.UWORD, stmt.address)
|
||||||
}
|
}
|
||||||
|
@ -285,3 +285,8 @@ val opcodesWithVarArgument = setOf(
|
|||||||
Opcode.DEC_INDEXED_VAR_UB, Opcode.DEC_INDEXED_VAR_B, Opcode.DEC_INDEXED_VAR_UW,
|
Opcode.DEC_INDEXED_VAR_UB, Opcode.DEC_INDEXED_VAR_B, Opcode.DEC_INDEXED_VAR_UW,
|
||||||
Opcode.DEC_INDEXED_VAR_W, Opcode.DEC_INDEXED_VAR_FLOAT
|
Opcode.DEC_INDEXED_VAR_W, Opcode.DEC_INDEXED_VAR_FLOAT
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val branchOpcodes = setOf(
|
||||||
|
Opcode.BCS, Opcode.BCC, Opcode.BZ, Opcode.BNZ,
|
||||||
|
Opcode.BNEG, Opcode.BPOS, Opcode.BVS, Opcode.BVC
|
||||||
|
)
|
||||||
|
@ -700,44 +700,72 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
|||||||
Opcode.INV_WORD -> " jsr prog8_lib.inv_word"
|
Opcode.INV_WORD -> " jsr prog8_lib.inv_word"
|
||||||
Opcode.NOT_BYTE -> " jsr prog8_lib.not_byte"
|
Opcode.NOT_BYTE -> " jsr prog8_lib.not_byte"
|
||||||
Opcode.NOT_WORD -> " jsr prog8_lib.not_word"
|
Opcode.NOT_WORD -> " jsr prog8_lib.not_word"
|
||||||
Opcode.BCS -> " bcs ${ins.callLabel}"
|
Opcode.BCS -> {
|
||||||
Opcode.BCC -> " bcc ${ins.callLabel}"
|
val label = ins.callLabel ?: hexVal(ins)
|
||||||
Opcode.BNEG -> " bmi ${ins.callLabel}"
|
" bcs $label"
|
||||||
Opcode.BPOS -> " bpl ${ins.callLabel}"
|
}
|
||||||
Opcode.BVC -> " bvc ${ins.callLabel}"
|
Opcode.BCC -> {
|
||||||
Opcode.BVS -> " bvs ${ins.callLabel}"
|
val label = ins.callLabel ?: hexVal(ins)
|
||||||
Opcode.BZ -> " beq ${ins.callLabel}"
|
" bcc $label"
|
||||||
Opcode.BNZ -> " bne ${ins.callLabel}"
|
}
|
||||||
|
Opcode.BNEG -> {
|
||||||
|
val label = ins.callLabel ?: hexVal(ins)
|
||||||
|
" bmi $label"
|
||||||
|
}
|
||||||
|
Opcode.BPOS -> {
|
||||||
|
val label = ins.callLabel ?: hexVal(ins)
|
||||||
|
" bpl $label"
|
||||||
|
}
|
||||||
|
Opcode.BVC -> {
|
||||||
|
val label = ins.callLabel ?: hexVal(ins)
|
||||||
|
" bvc $label"
|
||||||
|
}
|
||||||
|
Opcode.BVS -> {
|
||||||
|
val label = ins.callLabel ?: hexVal(ins)
|
||||||
|
" bvs $label"
|
||||||
|
}
|
||||||
|
Opcode.BZ -> {
|
||||||
|
val label = ins.callLabel ?: hexVal(ins)
|
||||||
|
" beq $label"
|
||||||
|
}
|
||||||
|
Opcode.BNZ -> {
|
||||||
|
val label = ins.callLabel ?: hexVal(ins)
|
||||||
|
" bne $label"
|
||||||
|
}
|
||||||
Opcode.JZ -> {
|
Opcode.JZ -> {
|
||||||
|
val label = ins.callLabel ?: hexVal(ins)
|
||||||
"""
|
"""
|
||||||
inx
|
inx
|
||||||
lda ${(ESTACK_LO).toHex()},x
|
lda ${(ESTACK_LO).toHex()},x
|
||||||
beq ${ins.callLabel}
|
beq $label
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
Opcode.JZW -> {
|
Opcode.JZW -> {
|
||||||
|
val label = ins.callLabel ?: hexVal(ins)
|
||||||
"""
|
"""
|
||||||
inx
|
inx
|
||||||
lda ${(ESTACK_LO).toHex()},x
|
lda ${(ESTACK_LO).toHex()},x
|
||||||
beq ${ins.callLabel}
|
beq $label
|
||||||
lda ${(ESTACK_HI).toHex()},x
|
lda ${(ESTACK_HI).toHex()},x
|
||||||
beq ${ins.callLabel}
|
beq $label
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
Opcode.JNZ -> {
|
Opcode.JNZ -> {
|
||||||
|
val label = ins.callLabel ?: hexVal(ins)
|
||||||
"""
|
"""
|
||||||
inx
|
inx
|
||||||
lda ${(ESTACK_LO).toHex()},x
|
lda ${(ESTACK_LO).toHex()},x
|
||||||
bne ${ins.callLabel}
|
bne $label
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
Opcode.JNZW -> {
|
Opcode.JNZW -> {
|
||||||
|
val label = ins.callLabel ?: hexVal(ins)
|
||||||
"""
|
"""
|
||||||
inx
|
inx
|
||||||
lda ${(ESTACK_LO).toHex()},x
|
lda ${(ESTACK_LO).toHex()},x
|
||||||
bne ${ins.callLabel}
|
bne $label
|
||||||
lda ${(ESTACK_HI).toHex()},x
|
lda ${(ESTACK_HI).toHex()},x
|
||||||
bne ${ins.callLabel}
|
bne $label
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
Opcode.CAST_B_TO_UB -> "" // is a no-op, just carry on with the byte as-is
|
Opcode.CAST_B_TO_UB -> "" // is a no-op, just carry on with the byte as-is
|
||||||
|
@ -368,7 +368,6 @@ class SimplifyExpressions(private val namespace: INameScope, private val heap: H
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// todo: get rid of this?
|
|
||||||
private data class ReorderedAssociativeBinaryExpr(val expr: BinaryExpression, val leftVal: LiteralValue?, val rightVal: LiteralValue?)
|
private data class ReorderedAssociativeBinaryExpr(val expr: BinaryExpression, val leftVal: LiteralValue?, val rightVal: LiteralValue?)
|
||||||
|
|
||||||
private fun reorderAssociative(expr: BinaryExpression, leftVal: LiteralValue?): ReorderedAssociativeBinaryExpr {
|
private fun reorderAssociative(expr: BinaryExpression, leftVal: LiteralValue?): ReorderedAssociativeBinaryExpr {
|
||||||
|
@ -18,43 +18,4 @@ Memory Block Operations
|
|||||||
these should call (or emit inline) optimized pieces of assembly code, so they run as fast as possible
|
these should call (or emit inline) optimized pieces of assembly code, so they run as fast as possible
|
||||||
|
|
||||||
At least we have memcopy() already and some screen related routines in asm
|
At least we have memcopy() already and some screen related routines in asm
|
||||||
|
@todo add memset() to easily set a part of memory to a specific byte value
|
||||||
|
|
||||||
Bitmap Definition (for Sprites and Characters)
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
to define CHARACTERS (8x8 monochrome or 4x8 multicolor = 8 bytes)
|
|
||||||
--> PLACE in memory on correct address (???k aligned)
|
|
||||||
|
|
||||||
and SPRITES (24x21 monochrome or 12x21 multicolor = 63 bytes)
|
|
||||||
--> PLACE in memory on correct address (base+sprite pointer, 64-byte aligned)
|
|
||||||
--> actually not needed because a block at the correct address, and an array using 3x21 binary values, more or less does exactly this already::
|
|
||||||
|
|
||||||
~ spritedata $0a00 {
|
|
||||||
; this memory block contains the sprite data
|
|
||||||
; it must start on an address aligned to 64 bytes.
|
|
||||||
%option force_output ; make sure the data in this block appears in the resulting program
|
|
||||||
|
|
||||||
ubyte[63] balloonsprite = [ %00000000,%01111111,%00000000,
|
|
||||||
%00000001,%11111111,%11000000,
|
|
||||||
%00000011,%11111111,%11100000,
|
|
||||||
%00000011,%11100011,%11100000,
|
|
||||||
%00000111,%11011100,%11110000,
|
|
||||||
%00000111,%11011101,%11110000,
|
|
||||||
%00000111,%11011100,%11110000,
|
|
||||||
%00000011,%11100011,%11100000,
|
|
||||||
%00000011,%11111111,%11100000,
|
|
||||||
%00000011,%11111111,%11100000,
|
|
||||||
%00000010,%11111111,%10100000,
|
|
||||||
%00000001,%01111111,%01000000,
|
|
||||||
%00000001,%00111110,%01000000,
|
|
||||||
%00000000,%10011100,%10000000,
|
|
||||||
%00000000,%10011100,%10000000,
|
|
||||||
%00000000,%01001001,%00000000,
|
|
||||||
%00000000,%01001001,%00000000,
|
|
||||||
%00000000,%00111110,%00000000,
|
|
||||||
%00000000,%00111110,%00000000,
|
|
||||||
%00000000,%00111110,%00000000,
|
|
||||||
%00000000,%00011100,%00000000 ]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -1,11 +1,33 @@
|
|||||||
%output raw
|
%import c64lib
|
||||||
%launcher none
|
|
||||||
|
|
||||||
|
|
||||||
~ main {
|
~ main {
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
|
|
||||||
|
; memset($0400, $0400+40, 81)
|
||||||
|
|
||||||
|
A=99
|
||||||
|
if(A<99) goto first else goto second
|
||||||
|
|
||||||
|
first:
|
||||||
|
c64scr.print("a<99 !\n")
|
||||||
|
goto next
|
||||||
|
second:
|
||||||
|
c64scr.print("wrong: a>=99 ?!\n")
|
||||||
|
|
||||||
|
next:
|
||||||
|
A=99
|
||||||
|
if(A<99) goto first2 else {
|
||||||
|
c64scr.print("wrong: a>=99 ?!\n")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
|
||||||
|
first2:
|
||||||
|
c64scr.print("a<99 !\n")
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
ubyte ub1
|
ubyte ub1
|
||||||
ubyte ub2
|
ubyte ub2
|
||||||
byte b1
|
byte b1
|
||||||
|
Loading…
x
Reference in New Issue
Block a user