From 7ee777f405e617e87d3fc0dace7031c2b787769d Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Tue, 27 Dec 2022 18:12:41 +0100 Subject: [PATCH] vm/ir: for loop is now correctly skipped if loopvar>endvar this is different still in the 6502 codegen, where it wraps around $00! --- .../prog8/codegen/intermediate/IRCodeGen.kt | 7 ++++ compiler/res/version.txt | 2 +- docs/source/todo.rst | 9 +++--- .../src/prog8/intermediate/IRInstructions.kt | 32 +++++++++---------- 4 files changed, 29 insertions(+), 21 deletions(-) diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt index 005254b6c..3903a3813 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt @@ -542,12 +542,19 @@ class IRCodeGen( result += expressionEval.translateExpression(iterable.to, endvalueReg, -1) result += expressionEval.translateExpression(iterable.from, indexReg, -1) + + val labelAfterFor = createLabelName() + val greaterOpcode = if(loopvarDt in SignedDatatypes) Opcode.BGTS else Opcode.BGT + addInstr(result, IRInstruction(greaterOpcode, loopvarDtIr, indexReg, endvalueReg, labelSymbol=labelAfterFor), null) + addInstr(result, IRInstruction(Opcode.STOREM, loopvarDtIr, reg1=indexReg, labelSymbol=loopvarSymbol), null) result += labelFirstChunk(translateNode(forLoop.statements), loopLabel) result += addConstMem(loopvarDtIr, null, loopvarSymbol, step) addInstr(result, IRInstruction(Opcode.LOADM, loopvarDtIr, reg1 = indexReg, labelSymbol = loopvarSymbol), null) val branchOpcode = if(loopvarDt in SignedDatatypes) Opcode.BLES else Opcode.BLE addInstr(result, IRInstruction(branchOpcode, loopvarDtIr, reg1=indexReg, reg2=endvalueReg, labelSymbol=loopLabel), null) + + result += IRCodeChunk(labelAfterFor, null) return result } diff --git a/compiler/res/version.txt b/compiler/res/version.txt index eec6dacbd..f5c2c4b8e 100644 --- a/compiler/res/version.txt +++ b/compiler/res/version.txt @@ -1 +1 @@ -8.8.1 +8.9-dev diff --git a/docs/source/todo.rst b/docs/source/todo.rst index cb8df04b0..64f69f0b9 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,6 +3,7 @@ TODO For next release ^^^^^^^^^^^^^^^^ +- remove redundant branch opcodes in IR: BLT(S), BLE(S). Replace by swapped BGT(S), BGE(S). - make sure bool value is always 0 or 1 (all casts should convert), then: - rewrite bool=bool^1 into bool=not bool - should solve: bool bb = not bb -> larger code than bool bb ^= 1 @@ -33,10 +34,10 @@ Compiler: - ir peephole opt: reuse registers in chunks (but keep result registers in mind that pass values out!) - ir: add more optimizations in IRPeepholeOptimizer - vm: somehow be able to load a label address as value? (VmProgramLoader) -- see if we can let for loops skip the loop if end just 2 special cases in CodeGen. +- 6502 codegen: see if we can let for loops skip the loop if startvar>endvar, without adding a lot of code size/duplicating the loop condition. + It is documented behavior to now loop 'around' $00 but it's too easy to forget about! + Lot of work because of so many special cases in ForLoopsAsmgen..... (vm codegen already behaves like this) +- ir: can we determine for the loop variable in forloops if it could be kept in a (virtual) register instead of a real variable? Need to be able to check if the variable is used by another statement beside just the for loop. - createAssemblyAndAssemble(): make it possible to actually get rid of the VarDecl nodes by fixing the rest of the code mentioned there. but probably better to rewrite the 6502 codegen on top of the new Ast. - generate WASM to eventually run prog8 on a browser canvas? diff --git a/intermediate/src/prog8/intermediate/IRInstructions.kt b/intermediate/src/prog8/intermediate/IRInstructions.kt index 02f632d55..168234750 100644 --- a/intermediate/src/prog8/intermediate/IRInstructions.kt +++ b/intermediate/src/prog8/intermediate/IRInstructions.kt @@ -76,20 +76,20 @@ bz reg1, address - branch to location if reg1 is zero bnz reg1, address - branch to location if reg1 is not zero beq reg1, reg2, address - jump to location in program given by location, if reg1 == reg2 bne reg1, reg2, address - jump to location in program given by location, if reg1 != reg2 -blt reg1, reg2, address - jump to location in program given by location, if reg1 < reg2 (unsigned) -blts reg1, reg2, address - jump to location in program given by location, if reg1 < reg2 (signed) -ble reg1, reg2, address - jump to location in program given by location, if reg1 <= reg2 (unsigned) -bles reg1, reg2, address - jump to location in program given by location, if reg1 <= reg2 (signed) +blt reg1, reg2, address - jump to location in program given by location, if reg1 < reg2 (unsigned) TODO REMOVE +blts reg1, reg2, address - jump to location in program given by location, if reg1 < reg2 (signed) TODO REMOVE +ble reg1, reg2, address - jump to location in program given by location, if reg1 <= reg2 (unsigned) TODO REMOVE +bles reg1, reg2, address - jump to location in program given by location, if reg1 <= reg2 (signed) TODO REMOVE bgt reg1, reg2, address - jump to location in program given by location, if reg1 > reg2 (unsigned) bgts reg1, reg2, address - jump to location in program given by location, if reg1 > reg2 (signed) bge reg1, reg2, address - jump to location in program given by location, if reg1 >= reg2 (unsigned) bges reg1, reg2, address - jump to location in program given by location, if reg1 >= reg2 (signed) seq reg1, reg2 - set reg=1 if reg1 == reg2, otherwise set reg1=0 sne reg1, reg2 - set reg=1 if reg1 != reg2, otherwise set reg1=0 -slt reg1, reg2 - set reg=1 if reg1 < reg2 (unsigned), otherwise set reg1=0 -slts reg1, reg2 - set reg=1 if reg1 < reg2 (signed), otherwise set reg1=0 -sle reg1, reg2 - set reg=1 if reg1 <= reg2 (unsigned), otherwise set reg1=0 -sles reg1, reg2 - set reg=1 if reg1 <= reg2 (signed), otherwise set reg1=0 +slt reg1, reg2 - set reg=1 if reg1 < reg2 (unsigned), otherwise set reg1=0 TODO REMOVE +slts reg1, reg2 - set reg=1 if reg1 < reg2 (signed), otherwise set reg1=0 TODO REMOVE +sle reg1, reg2 - set reg=1 if reg1 <= reg2 (unsigned), otherwise set reg1=0 TODO REMOVE +sles reg1, reg2 - set reg=1 if reg1 <= reg2 (signed), otherwise set reg1=0 TODO REMOVE sgt reg1, reg2 - set reg=1 if reg1 > reg2 (unsigned), otherwise set reg1=0 sgts reg1, reg2 - set reg=1 if reg1 > reg2 (signed), otherwise set reg1=0 sge reg1, reg2 - set reg=1 if reg1 >= reg2 (unsigned), otherwise set reg1=0 @@ -244,22 +244,22 @@ enum class Opcode { BNZ, BEQ, BNE, - BLT, - BLTS, + BLT, // TODO REMOVE + BLTS, // TODO REMOVE BGT, BGTS, - BLE, - BLES, + BLE, // TODO REMOVE + BLES, // TODO REMOVE BGE, BGES, SEQ, SNE, - SLT, - SLTS, + SLT, // TODO REMOVE ? + SLTS, // TODO REMOVE ? SGT, SGTS, - SLE, - SLES, + SLE, // TODO REMOVE ? + SLES, // TODO REMOVE ? SGE, SGES,