diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt index 770e09f15..35872c49f 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt @@ -458,6 +458,28 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { // special case, these should be inlined, or even use specialized instructions. Instead of doing a normal subroutine call. return translateStackFunctions(fcall, callTarget) } + when(callTarget.scopedName) { + "sys.clear_carry" -> { + val chunk = mutableListOf() + addInstr(chunk, IRInstruction(Opcode.CLC), null) + return ExpressionCodeResult(chunk, IRDataType.BYTE, -1, -1) + } + "sys.set_carry" -> { + val chunk = mutableListOf() + addInstr(chunk, IRInstruction(Opcode.SEC), null) + return ExpressionCodeResult(chunk, IRDataType.BYTE, -1, -1) + } + "sys.clear_irqd" -> { + val chunk = mutableListOf() + addInstr(chunk, IRInstruction(Opcode.CLI), null) + return ExpressionCodeResult(chunk, IRDataType.BYTE, -1, -1) + } + "sys.set_irqd" -> { + val chunk = mutableListOf() + addInstr(chunk, IRInstruction(Opcode.SEI), null) + return ExpressionCodeResult(chunk, IRDataType.BYTE, -1, -1) + } + } when (callTarget) { is StSub -> { diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt index f66793a7e..cca83b3a0 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt @@ -263,6 +263,24 @@ class IRPeepholeOptimizer(private val irprog: IRProgram) { } } } + + if(ins.opcode== Opcode.SEI || ins.opcode== Opcode.CLI) { + if(idx < chunk.instructions.size-1) { + val insAfter = chunk.instructions[idx+1] + if(insAfter.opcode == ins.opcode) { + chunk.instructions.removeAt(idx) + changed = true + } + else if(ins.opcode== Opcode.SEI && insAfter.opcode== Opcode.CLI) { + chunk.instructions.removeAt(idx) + changed = true + } + else if(ins.opcode== Opcode.CLI && insAfter.opcode== Opcode.SEI) { + chunk.instructions.removeAt(idx) + changed = true + } + } + } } return changed } diff --git a/codeGenIntermediate/test/TestIRPeepholeOpt.kt b/codeGenIntermediate/test/TestIRPeepholeOpt.kt index cb0691840..8546705aa 100644 --- a/codeGenIntermediate/test/TestIRPeepholeOpt.kt +++ b/codeGenIntermediate/test/TestIRPeepholeOpt.kt @@ -80,21 +80,52 @@ class TestIRPeepholeOpt: FunSpec({ instr[1].opcode shouldBe Opcode.INC } - test("remove double sec/clc") { + test("remove double sec/clc/sei/cli") { val irProg = makeIRProgram(listOf( IRInstruction(Opcode.SEC), IRInstruction(Opcode.SEC), IRInstruction(Opcode.SEC), IRInstruction(Opcode.CLC), IRInstruction(Opcode.CLC), - IRInstruction(Opcode.CLC) + IRInstruction(Opcode.CLC), + IRInstruction(Opcode.SEI), + IRInstruction(Opcode.SEI), + IRInstruction(Opcode.SEI), + IRInstruction(Opcode.CLI), + IRInstruction(Opcode.CLI), + IRInstruction(Opcode.CLI), )) - irProg.chunks().single().instructions.size shouldBe 6 + irProg.chunks().single().instructions.size shouldBe 12 val opt = IRPeepholeOptimizer(irProg) opt.optimize(true, ErrorReporterForTests()) val instr = irProg.chunks().single().instructions - instr.size shouldBe 1 + instr.size shouldBe 2 instr[0].opcode shouldBe Opcode.CLC + instr[1].opcode shouldBe Opcode.CLI + } + + test("remove double sec/clc/sei/cli reversed") { + val irProg = makeIRProgram(listOf( + IRInstruction(Opcode.CLC), + IRInstruction(Opcode.CLC), + IRInstruction(Opcode.CLC), + IRInstruction(Opcode.SEC), + IRInstruction(Opcode.SEC), + IRInstruction(Opcode.SEC), + IRInstruction(Opcode.CLI), + IRInstruction(Opcode.CLI), + IRInstruction(Opcode.CLI), + IRInstruction(Opcode.SEI), + IRInstruction(Opcode.SEI), + IRInstruction(Opcode.SEI), + )) + irProg.chunks().single().instructions.size shouldBe 12 + val opt = IRPeepholeOptimizer(irProg) + opt.optimize(true, ErrorReporterForTests()) + val instr = irProg.chunks().single().instructions + instr.size shouldBe 2 + instr[0].opcode shouldBe Opcode.SEC + instr[1].opcode shouldBe Opcode.SEI } test("push followed by pop") { diff --git a/compiler/res/prog8lib/virtual/syslib.p8 b/compiler/res/prog8lib/virtual/syslib.p8 index 7640ecfbd..cc3d3ee60 100644 --- a/compiler/res/prog8lib/virtual/syslib.p8 +++ b/compiler/res/prog8lib/virtual/syslib.p8 @@ -85,6 +85,18 @@ sys { }} } + sub set_irqd() { + %ir {{ + sei + }} + } + + sub clear_irqd() { + %ir {{ + cli + }} + } + sub disable_caseswitch() { ; no-op } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 62accb287..84c1baa73 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,9 +3,7 @@ TODO See open issues on github. -Re-generate the skeleons doc files. - -IR: add SEC and CLC instructions in place of call to sys.set_carry() and sys.clear_carry(). (check more inline sub calls that should be a single instruction?) +Re-generate the skeletons doc files. optimize signed byte/word division by powers of 2 (and shift right?), it's now using divmod routine. (also % ?) see inplacemodificationByteVariableWithLiteralval() and inplacemodificationSomeWordWithLiteralval() diff --git a/intermediate/src/prog8/intermediate/IRInstructions.kt b/intermediate/src/prog8/intermediate/IRInstructions.kt index e4139934e..86277809a 100644 --- a/intermediate/src/prog8/intermediate/IRInstructions.kt +++ b/intermediate/src/prog8/intermediate/IRInstructions.kt @@ -241,6 +241,8 @@ MISC clc - clear Carry status bit sec - set Carry status bit +cli - clear interrupt disable flag +sei - set interrupt disable flag nop - do nothing breakpoint - trigger a breakpoint msig [b, w] reg1, reg2 - reg1 becomes the most significant byte (or word) of the word (or int) in reg2 (.w not yet implemented; requires 32 bits regs) @@ -411,6 +413,8 @@ enum class Opcode { CLC, SEC, + CLI, + SEI, PUSH, POP, PUSHST, @@ -771,6 +775,8 @@ val instructionFormats = mutableMapOf( Opcode.CONCAT to InstructionFormat.from("BW,<>r1, InsBREAKPOINT() Opcode.CLC -> { statusCarry = false; nextPc() } Opcode.SEC -> { statusCarry = true; nextPc() } + Opcode.CLI, Opcode.SEI -> throw IllegalArgumentException("VM doesn't support interrupt status bit") Opcode.FFROMUB -> InsFFROMUB(ins) Opcode.FFROMSB -> InsFFROMSB(ins)