From 54bffc91ae92e00b2718b254d331775d6c7d14d7 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Tue, 25 Jun 2024 22:39:20 +0200 Subject: [PATCH] properly generate PUSH and POP instructions for push() and pop() calls in IR. Also switch to a fork of shadowJar to avoid Gradle deprecation errors. --- .../codegen/intermediate/ExpressionGen.kt | 43 ++++++++++++++++++- compiler/build.gradle | 3 +- compiler/test/vm/TestCompilerVirtual.kt | 31 ++++++++++++- docs/source/todo.rst | 2 - 4 files changed, 74 insertions(+), 5 deletions(-) diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt index 985c1a7bc..770e09f15 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt @@ -1,5 +1,6 @@ package prog8.codegen.intermediate +import prog8.code.StNode import prog8.code.StRomSub import prog8.code.StSub import prog8.code.ast.* @@ -451,7 +452,14 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { } fun translate(fcall: PtFunctionCall): ExpressionCodeResult { - when (val callTarget = codeGen.symbolTable.flat.getValue(fcall.name)) { + val callTarget = codeGen.symbolTable.flat.getValue(fcall.name) + + if(callTarget.scopedName in listOf("sys.push", "sys.pushw", "sys.pop", "sys.popw")) { + // special case, these should be inlined, or even use specialized instructions. Instead of doing a normal subroutine call. + return translateStackFunctions(fcall, callTarget) + } + + when (callTarget) { is StSub -> { val result = mutableListOf() addInstr(result, IRInstruction(Opcode.PREPARECALL, immediate = callTarget.parameters.size), null) @@ -590,6 +598,39 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { } } + private fun translateStackFunctions(fcall: PtFunctionCall, callTarget: StNode): ExpressionCodeResult { + val chunk = mutableListOf() + when(callTarget.scopedName) { + "sys.push" -> { + // push byte + val tr = translateExpression(fcall.args.single()) + chunk += tr.chunks + addInstr(chunk, IRInstruction(Opcode.PUSH, IRDataType.BYTE, reg1=tr.resultReg), null) + return ExpressionCodeResult(chunk, IRDataType.BYTE, -1, -1) + } + "sys.pushw" -> { + // push word + val tr = translateExpression(fcall.args.single()) + chunk += tr.chunks + addInstr(chunk, IRInstruction(Opcode.PUSH, IRDataType.WORD, reg1=tr.resultReg), null) + return ExpressionCodeResult(chunk, IRDataType.WORD, -1, -1) + } + "sys.pop" -> { + // pop byte + val popReg = codeGen.registers.nextFree() + addInstr(chunk, IRInstruction(Opcode.POP, IRDataType.BYTE, reg1=popReg), null) + return ExpressionCodeResult(chunk, IRDataType.BYTE, popReg, -1) + } + "sys.popw" -> { + // pop word + val popReg = codeGen.registers.nextFree() + addInstr(chunk, IRInstruction(Opcode.POP, IRDataType.WORD, reg1=popReg), null) + return ExpressionCodeResult(chunk, IRDataType.WORD, popReg, -1) + } + else -> throw AssemblyError("unknown stack subroutine called") + } + } + private fun callRomSubWithMultipleReturnValues( callTarget: StRomSub, fcall: PtFunctionCall, diff --git a/compiler/build.gradle b/compiler/build.gradle index aee0be0af..5443b7712 100644 --- a/compiler/build.gradle +++ b/compiler/build.gradle @@ -2,7 +2,8 @@ plugins { id 'java' id 'application' id 'org.jetbrains.kotlin.jvm' - id 'com.github.johnrengelman.shadow' version '8.1.1' + // id 'com.github.johnrengelman.shadow' version '8.1.1' + id 'io.github.goooler.shadow' version '8.1.7' id 'com.peterabeles.gversion' version '1.10.2' } diff --git a/compiler/test/vm/TestCompilerVirtual.kt b/compiler/test/vm/TestCompilerVirtual.kt index 3d81e8298..f3da054ed 100644 --- a/compiler/test/vm/TestCompilerVirtual.kt +++ b/compiler/test/vm/TestCompilerVirtual.kt @@ -11,6 +11,7 @@ import prog8.ast.statements.Assignment import prog8.code.target.C64Target import prog8.code.target.Cx16Target import prog8.code.target.VMTarget +import prog8.intermediate.IRDataType import prog8.intermediate.IRFileReader import prog8.intermediate.IRSubroutine import prog8.intermediate.Opcode @@ -475,6 +476,34 @@ main { compileText(VMTarget(), true, src, writeAssembly = true) shouldNotBe null } - + test("push() and pop() generate correct IR instructions") { + val src=""" +main { + sub start() { + ubyte bb + uword ww + sys.push(42) + bb++ + bb=sys.pop() + sys.pushw(9999) + ww++ + ww=sys.popw() + } +}""" + val result = compileText(VMTarget(), true, src, writeAssembly = true)!! + val virtfile = result.compilationOptions.outputDir.resolve(result.compilerAst.name + ".p8ir") + val irProgram = IRFileReader().read(virtfile) + val start = irProgram.blocks[0].children[0] as IRSubroutine + val instructions = start.chunks.flatMap { c->c.instructions } + instructions.size shouldBe 13 + instructions[3].opcode shouldBe Opcode.PUSH + instructions[3].type shouldBe IRDataType.BYTE + instructions[5].opcode shouldBe Opcode.POP + instructions[5].type shouldBe IRDataType.BYTE + instructions[8].opcode shouldBe Opcode.PUSH + instructions[8].type shouldBe IRDataType.WORD + instructions[10].opcode shouldBe Opcode.POP + instructions[10].type shouldBe IRDataType.WORD + } }) \ No newline at end of file diff --git a/docs/source/todo.rst b/docs/source/todo.rst index b431240d5..0ed7e85be 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -7,8 +7,6 @@ https://github.com/irmen/prog8/issues/136 (string.find register order issue) optimization: for 65c02 sometimes clc adc #1 is generated, this can be optimized into inc a (always? or not? mind the carry flag!) -IR: sys.push() and sys.pop() etc should be translated into PUSH/POP instructions instead of subroutine calls - if-optimization: if row == NUMQUEENS { print_solution()