IR: make LSIG,MSIG,CONCAT instruction set flags to skip cmp #0 afterwards (if msb(x)>0)

This commit is contained in:
Irmen de Jong
2025-09-30 21:48:57 +02:00
parent 8d6f3301c8
commit 75da38224d
4 changed files with 28 additions and 34 deletions
+5 -6
View File
@@ -49,7 +49,6 @@ Future Things and Ideas
IR/VM
-----
- make MSIG instruction set flags and skip cmp #0 afterwards (if msb(x)>0)
- is it possible to use LOADFIELD/STOREFIELD instructions even more?
- make multiple classes of registers and maybe also categorize by life time , to prepare for better register allocation in the future
SYSCALL_ARGS, // Reserved for syscall arguments (r99000-99099, r99100-99199)
@@ -75,8 +74,8 @@ IR/VM
- change the instruction format so an indirect register (a pointer) can be used more often, at least for the inplace assignment operators that operate on pointer
- getting it in shape for code generation...: the IR file should be able to encode every detail about a prog8 program (the VM doesn't have to actually be able to run all of it though!)
- fix call() return value handling (... what's wrong with it again?)
- encode asmsub/extsub clobber info in the call , or maybe include these definitions in the p8ir file itself too. (return registers are already encoded in the CALL instruction)
- proper code gen for the CALLI instruction and that it (optionally) returns a word value that needs to be assigned to a reg
- encode asmsub/extsub clobber info in the call , or maybe include these definitions in the p8ir file itself too. (return registers are already encoded in the CALL instruction)
- implement fast code paths for TODO("inplace split....
- implement more TODOs in AssignmentGen
- do something with the 'split' tag on split word arrays
@@ -86,10 +85,10 @@ IR/VM
don't forget to take into account the data type of the register when it's going to be reused!
- idea: (but LLVM IR simply keeps the variables, so not a good idea then?...): replace all scalar variables by an allocated register. Keep a table of the variable to register mapping (including the datatype)
global initialization values are simply a list of LOAD instructions.
Variables replaced include all subroutine parameters! So the only variables that remain as variables are arrays and strings.
Variables replaced include all subroutine parameters? Or not? So the only variables that remain as variables are arrays and strings.
- the @split arrays are currently also split in _lsb/_msb arrays in the IR, and operations take multiple (byte) instructions that may lead to verbose and slow operation and machine code generation down the line.
maybe another representation is needed once actual codegeneration is done from the IR...?
- ExpressionCodeResult: get rid of the separation between single result register and multiple result registers? maybe not, this requires hundreds of lines to change
maybe another representation is needed once actual codegeneration is done from the IR...? Should array operations be encoded in a more high level form in the IR?
- ExpressionCodeResult: get rid of the separation between single result register and multiple result registers? maybe not, this requires hundreds of lines to change.. :(
- sometimes source lines end up missing in the output p8ir, for example the first assignment is gone in:
sub start() {
cx16.r0L = cx16.r1 as ubyte
@@ -170,4 +169,4 @@ Optimizations
- VariableAllocator: can we think of a smarter strategy for allocating variables into zeropage, rather than first-come-first-served?
for instance, vars used inside loops first, then loopvars, then uwords used as pointers (or these first??), then the rest
This will probably need the register categorization from the IR explained there, for the old 6502 codegen there is not enough information to act on
- various optimizers skip stuff if compTarget.name==VMTarget.NAME. Once 6502-codegen is done from IR code, those checks should probably be removed, or be made permanent
- various optimizers skip stuff if compTarget.name==VMTarget.NAME. Once 6502-codegen is done from IR code, those checks should probably all be removed, or be made permanent
+8 -21
View File
@@ -1,28 +1,15 @@
%import conv
%import textio
%zeropage basicsafe
main {
sub start() {
uword value
ubyte size
uword @shared value
value, size = conv.any2uword("123")
txt.print_uw(value)
txt.spc()
txt.print_ub(size)
txt.nl()
if msb(value)>0
cx16.r0++
value, size = conv.any2uword("$ea31")
txt.print_uw(value)
txt.spc()
txt.print_ub(size)
txt.nl()
if lsb(value)>0
cx16.r0++
value, size = conv.any2uword("%11111110")
txt.print_uw(value)
txt.spc()
txt.print_ub(size)
txt.nl()
value = mkword(cx16.r0L, cx16.r1L)
if_z
cx16.r0++
}
}
@@ -17,11 +17,12 @@ Program to execute is not stored in the system memory, it's just a separate list
100K virtual floating point registers (64 bits double precision) fr0-fr99999
65536 bytes of memory. Thus memory pointers (addresses) are limited to 16 bits.
Value stack, max 128 entries of 1 byte each.
Status flags: Carry, Zero, Negative. NOTE: status flags are only affected by the CMP instruction or explicit CLC/SEC,
LOAD instructions DO affect the Z and N flags.
INC/DEC/NEG instructions DO affect the Z and N flags,
other instructions only affect Z an N flags if the value in a result register is written.
See OpcodesThatSetStatusbits
Status flags: Carry, Zero, Negative, Overflow.
NOTE: status flags are only affected by the CMP instruction or explicit CLC/SEC,
LOAD instructions also DO affect the Z and N flags.
INC/DEC/NEG instructions also DO affect the Z and N flags,
other instructions also only affect Z an N flags if the value in a result register is written.
See OpcodesThatSetStatusbits.
Instruction set is mostly a load/store architecture, there are few instructions operating on memory directly.
@@ -500,7 +501,10 @@ val OpcodesThatSetStatusbitsButNotCarry = arrayOf(
Opcode.OR,
Opcode.XORM,
Opcode.XORR,
Opcode.XOR
Opcode.XOR,
Opcode.LSIG,
Opcode.MSIG,
Opcode.CONCAT
)
val OpcodesThatDependOnCarry = arrayOf(
@@ -2358,6 +2358,7 @@ class VirtualMachine(irProgram: IRProgram) {
IRDataType.BYTE -> {
val value = registers.getUW(i.reg2!!)
registers.setUB(i.reg1!!, value.toUByte())
statusbitsNZ(value.toInt(), i.type!!)
}
IRDataType.WORD -> throw IllegalArgumentException("lsig.w not yet supported, requires 32-bits registers")
IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
@@ -2370,6 +2371,7 @@ class VirtualMachine(irProgram: IRProgram) {
IRDataType.BYTE -> {
val value = registers.getUW(i.reg2!!)
val newValue = value.toInt() ushr 8
statusbitsNZ(newValue, i.type!!)
registers.setUB(i.reg1!!, newValue.toUByte())
}
IRDataType.WORD -> throw IllegalArgumentException("msig.w not yet supported, requires 32-bits registers")
@@ -2383,7 +2385,9 @@ class VirtualMachine(irProgram: IRProgram) {
IRDataType.BYTE -> {
val msb = registers.getUB(i.reg2!!)
val lsb = registers.getUB(i.reg3!!)
registers.setUW(i.reg1!!, ((msb.toInt() shl 8) or lsb.toInt()).toUShort())
val value = ((msb.toInt() shl 8) or lsb.toInt())
registers.setUW(i.reg1!!, value.toUShort())
statusbitsNZ(value.toInt(), i.type!!)
}
IRDataType.WORD -> throw IllegalArgumentException("concat.w not yet supported, requires 32-bits registers")
IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")