mirror of
				https://github.com/irmen/prog8.git
				synced 2025-11-03 19:16:13 +00:00 
			
		
		
		
	multi value returns with longs
This commit is contained in:
		@@ -806,6 +806,7 @@ class AsmGen6502Internal (
 | 
				
			|||||||
            RegisterOrPair.AY,
 | 
					            RegisterOrPair.AY,
 | 
				
			||||||
            RegisterOrPair.XY -> assignmentAsmGen.assignRegisterpairWord(target, reg)
 | 
					            RegisterOrPair.XY -> assignmentAsmGen.assignRegisterpairWord(target, reg)
 | 
				
			||||||
            in Cx16VirtualRegisters -> assignmentAsmGen.assignVirtualRegister(target, reg)
 | 
					            in Cx16VirtualRegisters -> assignmentAsmGen.assignVirtualRegister(target, reg)
 | 
				
			||||||
 | 
					            in combinedLongRegisters -> assignmentAsmGen.assignVirtualRegister(target, reg)
 | 
				
			||||||
            RegisterOrPair.FAC1 -> assignmentAsmGen.assignFAC1float(target)
 | 
					            RegisterOrPair.FAC1 -> assignmentAsmGen.assignFAC1float(target)
 | 
				
			||||||
            RegisterOrPair.FAC2 -> assignmentAsmGen.assignFAC2float(target)
 | 
					            RegisterOrPair.FAC2 -> assignmentAsmGen.assignFAC2float(target)
 | 
				
			||||||
            else -> throw AssemblyError("invalid register")
 | 
					            else -> throw AssemblyError("invalid register")
 | 
				
			||||||
@@ -1306,7 +1307,7 @@ $repeatLabel""")
 | 
				
			|||||||
                assignExpressionTo(it.first as PtExpression, tgt)
 | 
					                assignExpressionTo(it.first as PtExpression, tgt)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            assigns.first().also {
 | 
					            assigns.first().also {
 | 
				
			||||||
                assignExpressionToRegister(it.first as PtExpression, it.second.first.registerOrPair!!)
 | 
					                assignExpressionToRegister(it.first as PtExpression, it.second.first.registerOrPair!!, (it.first as PtExpression).type.isSigned)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        out("  rts")
 | 
					        out("  rts")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -114,39 +114,17 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
 | 
				
			|||||||
                    RegisterOrPair.FAC2 -> {
 | 
					                    RegisterOrPair.FAC2 -> {
 | 
				
			||||||
                        AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.FLOAT, scope, pos, register = registers)
 | 
					                        AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.FLOAT, scope, pos, register = registers)
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    RegisterOrPair.R0,
 | 
					                    in Cx16VirtualRegisters -> {
 | 
				
			||||||
                    RegisterOrPair.R1,
 | 
					 | 
				
			||||||
                    RegisterOrPair.R2,
 | 
					 | 
				
			||||||
                    RegisterOrPair.R3,
 | 
					 | 
				
			||||||
                    RegisterOrPair.R4,
 | 
					 | 
				
			||||||
                    RegisterOrPair.R5,
 | 
					 | 
				
			||||||
                    RegisterOrPair.R6,
 | 
					 | 
				
			||||||
                    RegisterOrPair.R7,
 | 
					 | 
				
			||||||
                    RegisterOrPair.R8,
 | 
					 | 
				
			||||||
                    RegisterOrPair.R9,
 | 
					 | 
				
			||||||
                    RegisterOrPair.R10,
 | 
					 | 
				
			||||||
                    RegisterOrPair.R11,
 | 
					 | 
				
			||||||
                    RegisterOrPair.R12,
 | 
					 | 
				
			||||||
                    RegisterOrPair.R13,
 | 
					 | 
				
			||||||
                    RegisterOrPair.R14,
 | 
					 | 
				
			||||||
                    RegisterOrPair.R15 -> {
 | 
					 | 
				
			||||||
                        val dt = if(signed) DataType.WORD else DataType.UWORD
 | 
					                        val dt = if(signed) DataType.WORD else DataType.UWORD
 | 
				
			||||||
                        AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, dt, scope, pos, register = registers)
 | 
					                        AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, dt, scope, pos, register = registers)
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					                    in combinedLongRegisters -> {
 | 
				
			||||||
                    RegisterOrPair.R0R1_32,
 | 
					 | 
				
			||||||
                    RegisterOrPair.R2R3_32,
 | 
					 | 
				
			||||||
                    RegisterOrPair.R4R5_32,
 | 
					 | 
				
			||||||
                    RegisterOrPair.R6R7_32,
 | 
					 | 
				
			||||||
                    RegisterOrPair.R8R9_32,
 | 
					 | 
				
			||||||
                    RegisterOrPair.R10R11_32,
 | 
					 | 
				
			||||||
                    RegisterOrPair.R12R13_32,
 | 
					 | 
				
			||||||
                    RegisterOrPair.R14R15_32 -> {
 | 
					 | 
				
			||||||
                        val dt = if(signed) DataType.LONG
 | 
					                        val dt = if(signed) DataType.LONG
 | 
				
			||||||
                            else
 | 
					                            else
 | 
				
			||||||
                                TODO("unsigned long")
 | 
					                                TODO("unsigned long")
 | 
				
			||||||
                        AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, dt, scope, pos, register = registers)
 | 
					                        AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, dt, scope, pos, register = registers)
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					                    else -> throw AssemblyError("weird register $registers")
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -76,6 +76,11 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
 | 
				
			|||||||
            RegisterOrPair.AY -> addInstr(result, IRInstruction(Opcode.LOADHAY, IRDataType.WORD, reg1=regNum), null)
 | 
					            RegisterOrPair.AY -> addInstr(result, IRInstruction(Opcode.LOADHAY, IRDataType.WORD, reg1=regNum), null)
 | 
				
			||||||
            RegisterOrPair.XY -> addInstr(result, IRInstruction(Opcode.LOADHXY, IRDataType.WORD, reg1=regNum), null)
 | 
					            RegisterOrPair.XY -> addInstr(result, IRInstruction(Opcode.LOADHXY, IRDataType.WORD, reg1=regNum), null)
 | 
				
			||||||
            in Cx16VirtualRegisters -> addInstr(result, IRInstruction(Opcode.LOADM, irType(returns.type), reg1=regNum, labelSymbol = "cx16.${returns.register.registerOrPair.toString().lowercase()}"), null)
 | 
					            in Cx16VirtualRegisters -> addInstr(result, IRInstruction(Opcode.LOADM, irType(returns.type), reg1=regNum, labelSymbol = "cx16.${returns.register.registerOrPair.toString().lowercase()}"), null)
 | 
				
			||||||
 | 
					            in combinedLongRegisters -> {
 | 
				
			||||||
 | 
					                require(returns.type.isLong)
 | 
				
			||||||
 | 
					                val startreg = returns.register.registerOrPair!!.name.take(2).lowercase()
 | 
				
			||||||
 | 
					                addInstr(result, IRInstruction(Opcode.LOADM, IRDataType.LONG, reg1=regNum, labelSymbol = "cx16.${startreg}"), null)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            RegisterOrPair.FAC1 -> addInstr(result, IRInstruction(Opcode.LOADHFACZERO, IRDataType.FLOAT, fpReg1 = regNum), null)
 | 
					            RegisterOrPair.FAC1 -> addInstr(result, IRInstruction(Opcode.LOADHFACZERO, IRDataType.FLOAT, fpReg1 = regNum), null)
 | 
				
			||||||
            RegisterOrPair.FAC2 -> addInstr(result, IRInstruction(Opcode.LOADHFACONE, IRDataType.FLOAT, fpReg1 = regNum), null)
 | 
					            RegisterOrPair.FAC2 -> addInstr(result, IRInstruction(Opcode.LOADHFACONE, IRDataType.FLOAT, fpReg1 = regNum), null)
 | 
				
			||||||
            null -> if(returns.register.statusflag!=null)
 | 
					            null -> if(returns.register.statusflag!=null)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1976,12 +1976,17 @@ class IRCodeGen(
 | 
				
			|||||||
            in Cx16VirtualRegisters -> {
 | 
					            in Cx16VirtualRegisters -> {
 | 
				
			||||||
                chunk += IRInstruction(Opcode.STOREM, paramDt, reg1=resultReg, labelSymbol = "cx16.${registerOrFlag.registerOrPair.toString().lowercase()}")
 | 
					                chunk += IRInstruction(Opcode.STOREM, paramDt, reg1=resultReg, labelSymbol = "cx16.${registerOrFlag.registerOrPair.toString().lowercase()}")
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            in combinedLongRegisters -> {
 | 
				
			||||||
 | 
					                require(paramDt==IRDataType.LONG)
 | 
				
			||||||
 | 
					                val startreg = registerOrFlag.registerOrPair!!.name.take(2).lowercase()
 | 
				
			||||||
 | 
					                chunk += IRInstruction(Opcode.STOREM, paramDt, reg1=resultReg, labelSymbol = "cx16.${startreg}")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            null -> when(registerOrFlag.statusflag) {
 | 
					            null -> when(registerOrFlag.statusflag) {
 | 
				
			||||||
                // TODO: do the statusflag argument as last
 | 
					                // TODO: do the statusflag argument as last
 | 
				
			||||||
                Statusflag.Pc -> chunk += IRInstruction(Opcode.LSR, paramDt, reg1=resultReg)
 | 
					                Statusflag.Pc -> chunk += IRInstruction(Opcode.LSR, paramDt, reg1=resultReg)
 | 
				
			||||||
                else -> throw AssemblyError("unsupported statusflag as param")
 | 
					                else -> throw AssemblyError("unsupported statusflag as param")
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else -> throw AssemblyError("unsupported register arg")
 | 
					            else -> throw AssemblyError("unsupported register arg $registerOrFlag")
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return chunk
 | 
					        return chunk
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -160,7 +160,7 @@ Regular subroutines
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
**Single arguments will often be passed in registers:**
 | 
					**Single arguments will often be passed in registers:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
For *single* byte, word, long, and pointer arguments, the values are simply loaded in cpu registers by the caller before calling the subroutine.
 | 
					For *single* byte, word, and pointer arguments (not long or float), the values are simply loaded in cpu registers by the caller before calling the subroutine.
 | 
				
			||||||
*The subroutine itself will take care of putting the values into the parameter variables.* This saves on code size because
 | 
					*The subroutine itself will take care of putting the values into the parameter variables.* This saves on code size because
 | 
				
			||||||
otherwise all callers would have to store the values in those variables themselves.
 | 
					otherwise all callers would have to store the values in those variables themselves.
 | 
				
			||||||
Note that his convention is also still used for subroutines that specify parameters to be put into
 | 
					Note that his convention is also still used for subroutines that specify parameters to be put into
 | 
				
			||||||
@@ -179,7 +179,7 @@ Single word parameter: ``sub foo(uword bar) { ... }``
 | 
				
			|||||||
Single pointer parameter: ``sub foo(^^ubyte bar) { ... }``
 | 
					Single pointer parameter: ``sub foo(^^ubyte bar) { ... }``
 | 
				
			||||||
    gets bar in the register pair A + Y (lsb in A, msb in Y), *subroutine* stores it into parameter variable
 | 
					    gets bar in the register pair A + Y (lsb in A, msb in Y), *subroutine* stores it into parameter variable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Floating point parameter: ``sub foo(float bar) { ... }``
 | 
					Long or Floating point parameter: ``sub foo(long bar) { ... }``, ``sub foo(float bar) { ... }``
 | 
				
			||||||
    value for bar gets stored into the parameter variable *by the caller*
 | 
					    value for bar gets stored into the parameter variable *by the caller*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Other: ``sub foo(ubyte bar, ubyte baz, ubyte zoo) { ... }``
 | 
					Other: ``sub foo(ubyte bar, ubyte baz, ubyte zoo) { ... }``
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,6 @@ TODO
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
LONG TYPE
 | 
					LONG TYPE
 | 
				
			||||||
---------
 | 
					---------
 | 
				
			||||||
- call convention: NEVER put LONG parameter into R0:R1 just use parameter variable (also fix convention doc)
 | 
					 | 
				
			||||||
- call convention for asmsubs:  asmsubs don't have syntax for passing a long value so use explicit separate msw() and lsw() arguments...  Or introduce new syntax for R0+R1 combo's?
 | 
					- call convention for asmsubs:  asmsubs don't have syntax for passing a long value so use explicit separate msw() and lsw() arguments...  Or introduce new syntax for R0+R1 combo's?
 | 
				
			||||||
- make sure == and != work with longs against byte and words as well signed and unsigned
 | 
					- make sure == and != work with longs against byte and words as well signed and unsigned
 | 
				
			||||||
- how hard is it to also implement the other comparison operators on longs?
 | 
					- how hard is it to also implement the other comparison operators on longs?
 | 
				
			||||||
@@ -32,6 +31,9 @@ STRUCTS and TYPED POINTERS
 | 
				
			|||||||
Future Things and Ideas
 | 
					Future Things and Ideas
 | 
				
			||||||
^^^^^^^^^^^^^^^^^^^^^^^
 | 
					^^^^^^^^^^^^^^^^^^^^^^^
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- After long variable type is completed: make all constants long by default (remove type name altogether), reduce to target type implictly if the actual value fits.
 | 
				
			||||||
 | 
					  This will break some existing programs that depend on value wrap arounds, but gives more intuitive constant number handling.
 | 
				
			||||||
 | 
					  Can give descriptive error message for old syntax that still includes the type name?
 | 
				
			||||||
- improve ANTLR grammar with better error handling (as suggested by Qwen AI)
 | 
					- improve ANTLR grammar with better error handling (as suggested by Qwen AI)
 | 
				
			||||||
- allow memory() to occur in array initializer
 | 
					- allow memory() to occur in array initializer
 | 
				
			||||||
- when a complete block is removed because unused, suppress all info messages about everything in the block being removed
 | 
					- when a complete block is removed because unused, suppress all info messages about everything in the block being removed
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,17 +4,20 @@
 | 
				
			|||||||
main {
 | 
					main {
 | 
				
			||||||
    sub start() {
 | 
					    sub start() {
 | 
				
			||||||
        long lv = 99887766
 | 
					        long lv = 99887766
 | 
				
			||||||
        lv = func(lv)
 | 
					        lv, cx16.r0, cx16.r2L = func(lv)
 | 
				
			||||||
        txt.print_l(lv)
 | 
					        txt.print_l(lv)
 | 
				
			||||||
 | 
					        txt.spc()
 | 
				
			||||||
 | 
					        txt.print_uw(cx16.r0)
 | 
				
			||||||
 | 
					        txt.spc()
 | 
				
			||||||
 | 
					        txt.print_ub(cx16.r2L)
 | 
				
			||||||
 | 
					        txt.nl()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sub func(long arg) -> long {
 | 
					    sub func(long arg) -> long, uword, ubyte {
 | 
				
			||||||
         arg -= 1234567
 | 
					         arg -= 1234567
 | 
				
			||||||
         txt.print("func: ")
 | 
					         txt.print("func: ")
 | 
				
			||||||
         txt.print_l(arg)
 | 
					         txt.print_l(arg)
 | 
				
			||||||
         txt.nl()
 | 
					         txt.nl()
 | 
				
			||||||
         return arg
 | 
					         return arg, 9999, 42
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    ; TODO multi-value returns
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user