mirror of
https://github.com/irmen/prog8.git
synced 2025-11-02 13:16:07 +00:00
multi value returns with longs
This commit is contained in:
@@ -806,6 +806,7 @@ class AsmGen6502Internal (
|
||||
RegisterOrPair.AY,
|
||||
RegisterOrPair.XY -> assignmentAsmGen.assignRegisterpairWord(target, reg)
|
||||
in Cx16VirtualRegisters -> assignmentAsmGen.assignVirtualRegister(target, reg)
|
||||
in combinedLongRegisters -> assignmentAsmGen.assignVirtualRegister(target, reg)
|
||||
RegisterOrPair.FAC1 -> assignmentAsmGen.assignFAC1float(target)
|
||||
RegisterOrPair.FAC2 -> assignmentAsmGen.assignFAC2float(target)
|
||||
else -> throw AssemblyError("invalid register")
|
||||
@@ -1306,7 +1307,7 @@ $repeatLabel""")
|
||||
assignExpressionTo(it.first as PtExpression, tgt)
|
||||
}
|
||||
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")
|
||||
|
||||
@@ -114,39 +114,17 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
|
||||
RegisterOrPair.FAC2 -> {
|
||||
AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.FLOAT, scope, pos, register = registers)
|
||||
}
|
||||
RegisterOrPair.R0,
|
||||
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 -> {
|
||||
in Cx16VirtualRegisters -> {
|
||||
val dt = if(signed) DataType.WORD else DataType.UWORD
|
||||
AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, dt, scope, pos, register = registers)
|
||||
}
|
||||
|
||||
RegisterOrPair.R0R1_32,
|
||||
RegisterOrPair.R2R3_32,
|
||||
RegisterOrPair.R4R5_32,
|
||||
RegisterOrPair.R6R7_32,
|
||||
RegisterOrPair.R8R9_32,
|
||||
RegisterOrPair.R10R11_32,
|
||||
RegisterOrPair.R12R13_32,
|
||||
RegisterOrPair.R14R15_32 -> {
|
||||
in combinedLongRegisters -> {
|
||||
val dt = if(signed) DataType.LONG
|
||||
else
|
||||
TODO("unsigned long")
|
||||
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.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 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.FAC2 -> addInstr(result, IRInstruction(Opcode.LOADHFACONE, IRDataType.FLOAT, fpReg1 = regNum), null)
|
||||
null -> if(returns.register.statusflag!=null)
|
||||
|
||||
@@ -1976,12 +1976,17 @@ class IRCodeGen(
|
||||
in Cx16VirtualRegisters -> {
|
||||
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) {
|
||||
// TODO: do the statusflag argument as last
|
||||
Statusflag.Pc -> chunk += IRInstruction(Opcode.LSR, paramDt, reg1=resultReg)
|
||||
else -> throw AssemblyError("unsupported statusflag as param")
|
||||
}
|
||||
else -> throw AssemblyError("unsupported register arg")
|
||||
else -> throw AssemblyError("unsupported register arg $registerOrFlag")
|
||||
}
|
||||
return chunk
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ Regular subroutines
|
||||
|
||||
**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
|
||||
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
|
||||
@@ -179,7 +179,7 @@ Single word parameter: ``sub foo(uword 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
|
||||
|
||||
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*
|
||||
|
||||
Other: ``sub foo(ubyte bar, ubyte baz, ubyte zoo) { ... }``
|
||||
|
||||
@@ -3,7 +3,6 @@ TODO
|
||||
|
||||
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?
|
||||
- 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?
|
||||
@@ -32,6 +31,9 @@ STRUCTS and TYPED POINTERS
|
||||
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)
|
||||
- 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
|
||||
|
||||
@@ -4,17 +4,20 @@
|
||||
main {
|
||||
sub start() {
|
||||
long lv = 99887766
|
||||
lv = func(lv)
|
||||
lv, cx16.r0, cx16.r2L = func(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
|
||||
txt.print("func: ")
|
||||
txt.print_l(arg)
|
||||
txt.nl()
|
||||
return arg
|
||||
return arg, 9999, 42
|
||||
}
|
||||
|
||||
; TODO multi-value returns
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user