fixed and optimized branches and gotos in if statements

This commit is contained in:
Irmen de Jong 2019-01-22 22:52:43 +01:00
parent 209b50ddf7
commit dd02d97db4
6 changed files with 89 additions and 62 deletions

View File

@ -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)
} }

View File

@ -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
)

View File

@ -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

View File

@ -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 {

View File

@ -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 ]
}

View File

@ -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