diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt index 9d5ee7f6e..462a8f447 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt @@ -78,22 +78,20 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) { } private fun joinChunks(sub: IRSubroutine) { - /* - Subroutine contains a list of chunks. - Some can be joined into one. - TODO: this has to be changed later... - */ + // Subroutine contains a list of chunks. Some can be joined into one. if(sub.chunks.isEmpty()) return -/* fun mayJoin(previous: IRCodeChunkBase, chunk: IRCodeChunkBase): Boolean { + if(chunk.label!=null) + return false if(previous is IRCodeChunk && chunk is IRCodeChunk) { + // if the previous chunk doesn't end in a jump or a return, flow continues into the next chunk + val lastInstruction = previous.instructions.lastOrNull() + if(lastInstruction!=null) + return lastInstruction.opcode !in OpcodesThatJump return true - - // TODO: only if all instructions are non-branching, allow it to join? - // return !chunk.lines.filterIsInstance().any {it.opcode in OpcodesThatBranch } } return false } @@ -107,7 +105,7 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) { chunks += sub.chunks[ix] } sub.chunks.clear() - sub.chunks += chunks*/ + sub.chunks += chunks } private fun cleanupPushPop(chunk: IRCodeChunk, indexedInstructions: List>): Boolean { @@ -174,7 +172,7 @@ internal class IRPeepholeOptimizer(private val irprog: IRProgram) { // remove useless RETURN if(ins.opcode == Opcode.RETURN && idx>0) { val previous = chunk.instructions[idx-1] as? IRInstruction - if(previous?.opcode in setOf(Opcode.JUMP, Opcode.JUMPA, Opcode.RETURN)) { + if(previous?.opcode in OpcodesThatJump) { chunk.instructions.removeAt(idx) changed = true } diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 0aeb80c5d..327e5a201 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -252,16 +252,8 @@ internal class AstChecker(private val program: Program, } override fun visit(inlineAssembly: InlineAssembly) { - val assembly = inlineAssembly.assembly - if(compilerOptions.compTarget.name!=VMTarget.NAME) { - if (" rti" in assembly || "\trti" in assembly || " rts" in assembly || "\trts" in assembly || - " jmp" in assembly || "\tjmp" in assembly || " bra" in assembly || "\tbra" in assembly - ) - count++ - } else { - if(" return" in assembly || "\treturn" in assembly || " jump" in assembly || "\tjump" in assembly) - count++ - } + if(inlineAssembly.hasReturnOrRts(compilerOptions.compTarget)) + count++ } } diff --git a/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt b/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt index e95729e24..e9d77f945 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt @@ -12,7 +12,6 @@ import prog8.ast.statements.VarDeclOrigin import prog8.ast.walk.AstWalker import prog8.ast.walk.IAstModification import prog8.code.core.* -import prog8.code.target.VMTarget internal fun Program.checkValid(errors: IErrorReporter, compilerOptions: CompilationOptions) { @@ -170,15 +169,8 @@ internal fun IdentifierReference.isSubroutineParameter(program: Program): Boolea } internal fun Subroutine.hasRtsInAsm(compTarget: ICompilationTarget): Boolean { - val instructions = - if(compTarget.name == VMTarget.NAME) - listOf(" return", "\treturn", " jump", "\tjump") - else - listOf(" rti", "\trti", " rts", "\trts", " jmp", "\tjmp", " bra", "\tbra") return statements .asSequence() .filterIsInstance() - .any { - instructions.any { instr->instr in it.assembly } - } + .any { it.hasReturnOrRts(compTarget) } } \ No newline at end of file diff --git a/compilerAst/src/prog8/ast/statements/AstStatements.kt b/compilerAst/src/prog8/ast/statements/AstStatements.kt index a59d26941..ac2e43217 100644 --- a/compilerAst/src/prog8/ast/statements/AstStatements.kt +++ b/compilerAst/src/prog8/ast/statements/AstStatements.kt @@ -7,6 +7,7 @@ import prog8.ast.expressions.* import prog8.ast.walk.AstWalker import prog8.ast.walk.IAstVisitor import prog8.code.core.* +import prog8.code.target.VMTarget interface INamedStatement { @@ -629,6 +630,15 @@ class InlineAssembly(val assembly: String, val isIR: Boolean, override val posit override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) + fun hasReturnOrRts(target: ICompilationTarget): Boolean { + return if(target.name!= VMTarget.NAME) { + " rti" in assembly || "\trti" in assembly || " rts" in assembly || "\trts" in assembly || + " jmp" in assembly || "\tjmp" in assembly || " bra" in assembly || "\tbra" in assembly + } else { + " return" in assembly || "\treturn" in assembly || " jump" in assembly || "\tjump" in assembly || " jumpa" in assembly || "\tjumpa" in assembly + } + } + val names: Set by lazy { // A cache of all the words (identifiers) present in this block of assembly code diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 61b48fccd..b8102ae04 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,14 +3,12 @@ TODO For next release ^^^^^^^^^^^^^^^^ +- ir: fix linkChunks() in IRProgram and addAssemblyToProgram() next pointer tracking - vm: program is list of chunks, fix dispatcher -- maybe?: make sure last %ir chunk in a subroutine ends with a jump or a return instruction - ir: fix unit tests -- ir: fix joinChunks() in the IR optimizer - there are WAY too many chunks with 1 instruction in them only - ir: fix removeWeirdBranches in IR optimizer - ir: next in IRCodeChunk can also be a Asm Chunk which can have next as well -- add cx16diskio.vload_raw() to load headerless files into vram -- mention the syntax highlighting files in the readme and the docs, and add note to the IDEA one that it can also be used in Rider +- update diagram in technical.rst? ... diff --git a/examples/test.p8 b/examples/test.p8 index 90e99e5f1..0b5ffa868 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,11 +1,16 @@ -%import textio +; %import textio main { sub start() { - ubyte aa = 42 - ubyte bb = 99 - aa += bb - txt.print_ub(aa) + ; should get a return after the nop + %ir {{ + nop + }} + +; ubyte aa = 42 +; ubyte bb = 99 +; aa += bb +; txt.print_ub(aa) } } diff --git a/intermediate/src/prog8/intermediate/IRInstructions.kt b/intermediate/src/prog8/intermediate/IRInstructions.kt index ebd3514bf..8bb7d8d7e 100644 --- a/intermediate/src/prog8/intermediate/IRInstructions.kt +++ b/intermediate/src/prog8/intermediate/IRInstructions.kt @@ -353,6 +353,12 @@ enum class Opcode { BINARYDATA } +val OpcodesThatJump = setOf( + Opcode.JUMP, + Opcode.JUMPA, + Opcode.RETURN +) + val OpcodesThatBranch = setOf( Opcode.JUMP, Opcode.JUMPA, diff --git a/intermediate/src/prog8/intermediate/IRProgram.kt b/intermediate/src/prog8/intermediate/IRProgram.kt index dce3ece7c..4fb7897c3 100644 --- a/intermediate/src/prog8/intermediate/IRProgram.kt +++ b/intermediate/src/prog8/intermediate/IRProgram.kt @@ -93,18 +93,22 @@ class IRProgram(val name: String, } blocks.asSequence().flatMap { it.subroutines }.forEach { sub -> + + sub.chunks.withIndex().forEach { (index, chunk) -> + fun nextChunk(): IRCodeChunkBase? = if(index { // link sequential chunks val jump = chunk.instructions.lastOrNull()?.opcode - if (jump == null || jump !in setOf(Opcode.JUMP, Opcode.JUMPA, Opcode.RETURN)) { + if (jump == null || jump !in OpcodesThatJump) { // no jump at the end, so link to next chunk (if it exists) - if(index { - // TODO("link next of asm chunk") + val next = nextChunk() + if(next!=null) { + // TODO if chunk doesn't end in a jump or return statement, flow continues into the next chunk + } } is IRInlineBinaryChunk -> { // TODO("link next of binary chunk") diff --git a/virtualmachine/src/prog8/vm/VirtualMachine.kt b/virtualmachine/src/prog8/vm/VirtualMachine.kt index 858cb18bf..b505dacc7 100644 --- a/virtualmachine/src/prog8/vm/VirtualMachine.kt +++ b/virtualmachine/src/prog8/vm/VirtualMachine.kt @@ -136,7 +136,7 @@ class VirtualMachine(irProgram: IRProgram) { private fun dispatch(ins: IRInstruction) { when(ins.opcode) { - Opcode.NOP -> { nextPc() } + Opcode.NOP -> nextPc() Opcode.LOAD -> InsLOAD(ins) Opcode.LOADM -> InsLOADM(ins) Opcode.LOADX -> InsLOADX(ins) diff --git a/virtualmachine/src/prog8/vm/VmProgramLoader.kt b/virtualmachine/src/prog8/vm/VmProgramLoader.kt index ad9fa02d4..0d87aa776 100644 --- a/virtualmachine/src/prog8/vm/VmProgramLoader.kt +++ b/virtualmachine/src/prog8/vm/VmProgramLoader.kt @@ -272,7 +272,7 @@ class VmProgramLoader { symbolAddresses: MutableMap, ): Pair { if(asmChunk.isIR) { - val chunk = IRCodeChunk(asmChunk.label, asmChunk.position, null) + val chunk = IRCodeChunk(asmChunk.label, asmChunk.position, null) // TODO keep track of the chunk's next pointer asmChunk.assembly.lineSequence().forEach { val parsed = parseIRCodeLine(it.trim(), Pair(chunk, chunk.instructions.size), placeholders) parsed.fold(