diff --git a/compiler/examples/test.p8 b/compiler/examples/test.p8 index 174e99fac..a321bc392 100644 --- a/compiler/examples/test.p8 +++ b/compiler/examples/test.p8 @@ -17,6 +17,14 @@ word[len(zcoor)] rotatedz=-1 sub start() { + + + label1: + label2: + Y-- + if_mi goto label1 + if_mi goto label1 else goto label2 + uword anglex uword angley uword anglez diff --git a/compiler/examples/whizzine.p8 b/compiler/examples/whizzine.p8 index 128bb43ff..dd8d36b15 100644 --- a/compiler/examples/whizzine.p8 +++ b/compiler/examples/whizzine.p8 @@ -61,15 +61,18 @@ sub irq() { angle++ c64.MSIGX=0 - for ubyte i in 0 to 14 step 2 { - word x = (sin8(angle*2-i*8) as word)+190 ; @todo will/should be using shifts for faster multiplication - byte y = cos8(angle*3-i*8) // 2 ; @todo will/should be using shifts for faster multiplication - @(SP0X+i) = lsb(x) - @(SP0Y+i) = y+150 as ubyte + ubyte i=14 - lsr(c64.MSIGX) - if msb(x) c64.MSIGX |= %10000000 - } +nextsprite: ; @todo should be a for loop from 14 to 0 step -2 but this causes a value out of range error at the moment + word x = (sin8(angle*2-i*8) as word)+190 ; @todo will/should be using shifts for faster multiplication + byte y = cos8(angle*3-i*8) // 2 ; @todo will/should be using shifts for faster multiplication + @(SP0X+i) = lsb(x) + @(SP0Y+i) = y+150 as ubyte + + lsl(c64.MSIGX) + if msb(x) c64.MSIGX++ + i-=2 + if_pl goto nextsprite c64.EXTCOL++ } diff --git a/compiler/src/prog8/ast/AST.kt b/compiler/src/prog8/ast/AST.kt index fe275e327..0145fc1ff 100644 --- a/compiler/src/prog8/ast/AST.kt +++ b/compiler/src/prog8/ast/AST.kt @@ -270,9 +270,9 @@ interface IAstProcessor { return scope } - fun process(typecastExpression: TypecastExpression): IExpression { - typecastExpression.expression = typecastExpression.expression.process(this) - return typecastExpression + fun process(typecast: TypecastExpression): IExpression { + typecast.expression = typecast.expression.process(this) + return typecast } fun process(memread: DirectMemoryRead): IExpression { @@ -1934,7 +1934,7 @@ private fun prog8Parser.ReturnstmtContext.toAst() : Return { private fun prog8Parser.UnconditionaljumpContext.toAst(): Jump { val address = integerliteral()?.toAst()?.number?.toInt() - val identifier = scoped_identifier().toAst() + val identifier = scoped_identifier()?.toAst() return Jump(address, identifier, null, toPosition()) } diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 308b0dc0e..4bdc0c00e 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -195,7 +195,7 @@ private class StatementTranslator(private val prog: IntermediateProgram, is VariableInitializationAssignment -> translate(stmt) // for initializing vars in a scope is Assignment -> translate(stmt) // normal and augmented assignments is PostIncrDecr -> translate(stmt) - is Jump -> translate(stmt) + is Jump -> translate(stmt, null) is FunctionCallStatement -> translate(stmt) is IfStatement -> translate(stmt) is BranchStatement -> translate(stmt) @@ -399,35 +399,67 @@ private class StatementTranslator(private val prog: IntermediateProgram, * _stmt_999_end: * nop * - * @todo generate more efficient bytecode for the form with just jumps: if_xx goto .. [else goto ..] ? - * -> this should translate into just a single branch opcode per goto + * if the branch statement just contains jumps, more efficient code is generated. + * (just the appropriate branching instruction is outputted!) */ + if(branch.elsepart.isEmpty() && branch.truepart.isEmpty()) + return + + fun branchOpcode(branch: BranchStatement, complement: Boolean) = + if(complement) { + when (branch.condition) { + BranchCondition.CS -> Opcode.BCC + BranchCondition.CC -> Opcode.BCS + BranchCondition.EQ, BranchCondition.Z -> Opcode.BNZ + BranchCondition.NE, BranchCondition.NZ -> Opcode.BZ + BranchCondition.VS -> Opcode.BVC + BranchCondition.VC -> Opcode.BVS + BranchCondition.MI, BranchCondition.NEG -> Opcode.BPOS + BranchCondition.PL, BranchCondition.POS -> Opcode.BNEG + } + } else { + when (branch.condition) { + BranchCondition.CS -> Opcode.BCS + BranchCondition.CC -> Opcode.BCC + BranchCondition.EQ, BranchCondition.Z -> Opcode.BZ + BranchCondition.NE, BranchCondition.NZ -> Opcode.BNZ + BranchCondition.VS -> Opcode.BVS + BranchCondition.VC -> Opcode.BVC + BranchCondition.MI, BranchCondition.NEG -> Opcode.BNEG + BranchCondition.PL, BranchCondition.POS -> Opcode.BPOS + } + } + prog.line(branch.position) - val labelElse = makeLabel("else") - val labelEnd = makeLabel("end") - val opcode = when(branch.condition) { - BranchCondition.CS -> Opcode.BCC - BranchCondition.CC -> Opcode.BCS - BranchCondition.EQ, BranchCondition.Z -> Opcode.BNZ - BranchCondition.NE, BranchCondition.NZ -> Opcode.BZ - BranchCondition.VS -> Opcode.BVC - BranchCondition.VC -> Opcode.BVS - BranchCondition.MI, BranchCondition.NEG -> Opcode.BPOS - BranchCondition.PL, BranchCondition.POS -> Opcode.BNEG - } - if(branch.elsepart.isEmpty()) { - prog.instr(opcode, callLabel = labelEnd) - translate(branch.truepart) - prog.label(labelEnd) + val truejump = branch.truepart.statements.first() + val elsejump = branch.elsepart.statements.firstOrNull() + if(truejump is Jump && truejump.address==null && (elsejump ==null || (elsejump is Jump && elsejump.address==null))) { + // optimized code for just conditional jumping + val opcodeTrue = branchOpcode(branch, false) + translate(truejump, opcodeTrue) + if(elsejump is Jump) { + val opcodeFalse = branchOpcode(branch, true) + translate(elsejump, opcodeFalse) + } } else { - prog.instr(opcode, callLabel = labelElse) - translate(branch.truepart) - prog.instr(Opcode.JUMP, callLabel = labelEnd) - prog.label(labelElse) - translate(branch.elsepart) - prog.label(labelEnd) + // regular if..else branching + val labelElse = makeLabel("else") + val labelEnd = makeLabel("end") + val opcode = branchOpcode(branch, true) + if (branch.elsepart.isEmpty()) { + prog.instr(opcode, callLabel = labelEnd) + translate(branch.truepart) + prog.label(labelEnd) + } else { + prog.instr(opcode, callLabel = labelElse) + translate(branch.truepart) + prog.instr(Opcode.JUMP, callLabel = labelEnd) + prog.label(labelElse) + translate(branch.elsepart) + prog.label(labelEnd) + } + prog.instr(Opcode.NOP) } - prog.instr(Opcode.NOP) } private fun makeLabel(postfix: String): String { @@ -1235,13 +1267,17 @@ private class StatementTranslator(private val prog: IntermediateProgram, prog.instr(Opcode.SYSCALL, Value(DataType.UBYTE, callNr)) } - private fun translate(stmt: Jump) { + private fun translate(stmt: Jump, branchOpcode: Opcode?) { var jumpAddress: Value? = null var jumpLabel: String? = null when { stmt.generatedLabel!=null -> jumpLabel = stmt.generatedLabel - stmt.address!=null -> jumpAddress = Value(DataType.UWORD, stmt.address) + stmt.address!=null -> { + if(branchOpcode!=null) + throw CompilerException("cannot branch to address, should use absolute jump instead") + jumpAddress = Value(DataType.UWORD, stmt.address) + } else -> { val target = stmt.identifier!!.targetStatement(namespace)!! jumpLabel = when(target) { @@ -1252,7 +1288,7 @@ private class StatementTranslator(private val prog: IntermediateProgram, } } prog.line(stmt.position) - prog.instr(Opcode.JUMP, jumpAddress, jumpLabel) + prog.instr(branchOpcode ?: Opcode.JUMP, jumpAddress, jumpLabel) } private fun translate(stmt: PostIncrDecr) { diff --git a/compiler/src/prog8/compiler/target/c64/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/AsmGen.kt index 53bd9b816..b2d6960da 100644 --- a/compiler/src/prog8/compiler/target/c64/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/AsmGen.kt @@ -414,8 +414,18 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, Opcode.CLC -> " clc" Opcode.SEI -> " sei" Opcode.CLI -> " cli" - Opcode.JUMP -> " jmp ${ins.callLabel}" - Opcode.CALL -> " jsr ${ins.callLabel}" + Opcode.JUMP -> { + if(ins.callLabel!=null) + " jmp ${ins.callLabel}" + else + " jmp ${hexVal(ins)}" + } + Opcode.CALL -> { + if(ins.callLabel!=null) + " jsr ${ins.callLabel}" + else + " jsr ${hexVal(ins)}" + } Opcode.RETURN -> " rts" Opcode.RSAVE -> { // save cpu status flag and all registers A, X, Y.