From 2b7c09e6ee646e582b431d86494852bdfe207f60 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Tue, 5 Apr 2022 00:08:38 +0200 Subject: [PATCH] vm: more optimal code for loops ending on 0 --- .../prog8/codegen/virtual/AssemblyProgram.kt | 16 +++++++ .../src/prog8/codegen/virtual/CodeGen.kt | 42 +++++++++++-------- docs/source/todo.rst | 1 - examples/test.p8 | 12 +++--- virtualmachine/src/prog8/vm/Assembler.kt | 13 ++++++ 5 files changed, 60 insertions(+), 24 deletions(-) diff --git a/codeGenVirtual/src/prog8/codegen/virtual/AssemblyProgram.kt b/codeGenVirtual/src/prog8/codegen/virtual/AssemblyProgram.kt index 7c4449b17..c082a7ec3 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/AssemblyProgram.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/AssemblyProgram.kt @@ -64,6 +64,22 @@ internal class VmCodeInstruction( symbol: List?=null // alternative to value ): VmCodeLine() { val ins = Instruction(opcode, type, reg1, reg2, reg3, value, symbol) + + init { + if(value!=null) { + when (type) { + VmDataType.BYTE -> { + if (value < -128 || value > 255) + throw IllegalArgumentException("value out of range for byte: $value") + } + VmDataType.WORD -> { + if (value < -32768 || value > 65535) + throw IllegalArgumentException("value out of range for word: $value") + } + null -> {} + } + } + } } internal class VmCodeLabel(val name: List): VmCodeLine() internal class VmCodeComment(val comment: String): VmCodeLine() diff --git a/codeGenVirtual/src/prog8/codegen/virtual/CodeGen.kt b/codeGenVirtual/src/prog8/codegen/virtual/CodeGen.kt index 63a041be3..ca30f18e0 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/CodeGen.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/CodeGen.kt @@ -231,36 +231,44 @@ class CodeGen(internal val program: PtProgram, } private fun translateForInConstantRange(forLoop: PtForLoop, loopvar: StStaticVariable): VmCodeChunk { - val iterable = forLoop.iterable as PtRange - val step = iterable.step.number.toInt() - val range = IntProgression.fromClosedRange( - (iterable.from as PtNumber).number.toInt(), - (iterable.to as PtNumber).number.toInt() + step, - step) - if (range.isEmpty() || range.step==0) - throw AssemblyError("empty range or step 0") - val loopLabel = createLabelName() val loopvarAddress = allocations.get(loopvar.scopedName) val indexReg = vmRegisters.nextFree() - val endvalueReg = vmRegisters.nextFree() val loopvarDt = vmType(loopvar.dt) + val iterable = forLoop.iterable as PtRange + val step = iterable.step.number.toInt() + val rangeStart = (iterable.from as PtNumber).number.toInt() + val rangeEndUntyped = (iterable.to as PtNumber).number.toInt() + step + if(step==0) + throw AssemblyError("step 0") + if(step>0 && rangeEndUntypedrangeStart) + throw AssemblyError("empty range") + val rangeEndWrapped = if(loopvarDt==VmDataType.BYTE) rangeEndUntyped and 255 else rangeEndUntyped and 65535 val code = VmCodeChunk() - code += VmCodeInstruction(Opcode.LOAD, loopvarDt, reg1=endvalueReg, value=range.last) - code += VmCodeInstruction(Opcode.LOAD, loopvarDt, reg1=indexReg, value=range.first) + val endvalueReg: Int + if(rangeEndWrapped!=0) { + endvalueReg = vmRegisters.nextFree() + code += VmCodeInstruction(Opcode.LOAD, loopvarDt, reg1 = endvalueReg, value = rangeEndWrapped) + } else { + endvalueReg = 0 + } + code += VmCodeInstruction(Opcode.LOAD, loopvarDt, reg1=indexReg, value=rangeStart) code += VmCodeInstruction(Opcode.STOREM, loopvarDt, reg1=indexReg, value=loopvarAddress) code += VmCodeLabel(loopLabel) code += translateNode(forLoop.statements) - if(range.step<3) { - code += addConstMem(loopvarDt, loopvarAddress.toUInt(), range.step) + if(step<3) { + code += addConstMem(loopvarDt, loopvarAddress.toUInt(), step) code += VmCodeInstruction(Opcode.LOADM, loopvarDt, reg1 = indexReg, value = loopvarAddress) } else { code += VmCodeInstruction(Opcode.LOADM, loopvarDt, reg1 = indexReg, value = loopvarAddress) - code += addConstReg(loopvarDt, indexReg, range.step) + code += addConstReg(loopvarDt, indexReg, step) code += VmCodeInstruction(Opcode.STOREM, loopvarDt, reg1 = indexReg, value = loopvarAddress) } - // TODO more optimal loop instruction for loops ending on 0 (BNZ?) - code += VmCodeInstruction(Opcode.BNE, loopvarDt, reg1=indexReg, reg2=endvalueReg, symbol=loopLabel) + code += if(rangeEndWrapped==0) { + VmCodeInstruction(Opcode.BNZ, loopvarDt, reg1 = indexReg, symbol = loopLabel) + } else { + VmCodeInstruction(Opcode.BNE, loopvarDt, reg1 = indexReg, reg2 = endvalueReg, symbol = loopLabel) + } return code } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 69bd9c84e..017e3d5c0 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,7 +3,6 @@ TODO For next release ^^^^^^^^^^^^^^^^ -- vm: codegen: more optimal code for loops ending on 0 (BNZ?) - pipe operator: allow non-unary function calls in the pipe that specify the other argument(s) in the calls. - writeAssembly(): make it possible to actually get rid of the VarDecl nodes by fixing the rest of the code mentioned there. - allow "xxx" * constexpr (where constexpr is not a number literal), now gives expression error not same type diff --git a/examples/test.p8 b/examples/test.p8 index 62858f3ad..5ddbf8757 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -7,13 +7,13 @@ main { sub start() { - ubyte value1 = 99 - ubyte value2 = 222 + ubyte counter - uword @shared result = $ffff - result = value1 != value2 - - txt.print_uwhex(result, true) + repeat 256 { + txt.print_ub(counter) + txt.spc() + counter ++ + } txt.nl() ; a "pixelshader": diff --git a/virtualmachine/src/prog8/vm/Assembler.kt b/virtualmachine/src/prog8/vm/Assembler.kt index ae6ee81d5..f83034720 100644 --- a/virtualmachine/src/prog8/vm/Assembler.kt +++ b/virtualmachine/src/prog8/vm/Assembler.kt @@ -132,6 +132,19 @@ class Assembler { throw IllegalArgumentException("invalid reg3 for $line") if(!format.value && value!=null) throw IllegalArgumentException("invalid value for $line") + if(value!=null) { + when (type) { + VmDataType.BYTE -> { + if (value < -128 || value > 255) + throw IllegalArgumentException("value out of range for byte: $value") + } + VmDataType.WORD -> { + if (value < -32768 || value > 65535) + throw IllegalArgumentException("value out of range for word: $value") + } + null -> {} + } + } program.add(Instruction(opcode, type, reg1, reg2, reg3, value)) } }