mirror of
https://github.com/irmen/prog8.git
synced 2025-11-23 14:17:51 +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