mirror of
https://github.com/irmen/prog8.git
synced 2025-02-25 04:29:36 +00:00
IR: fix codegen for routines returning in CPU Status register flag
This commit is contained in:
parent
332ba8ed7e
commit
b24df31c2b
@ -430,6 +430,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
result += tr.chunks
|
||||
}
|
||||
// return value
|
||||
var statusFlagResult: Statusflag? = null
|
||||
val returnRegSpec = if(fcall.void) null else {
|
||||
if(callTarget.returns.isEmpty())
|
||||
null
|
||||
@ -438,8 +439,11 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
val returnIrType = irType(returns.type)
|
||||
if(returnIrType==IRDataType.FLOAT)
|
||||
FunctionCallArgs.RegSpec(returnIrType, codeGen.registers.nextFreeFloat(), returns.register)
|
||||
else
|
||||
FunctionCallArgs.RegSpec(returnIrType, codeGen.registers.nextFree(), returns.register)
|
||||
else {
|
||||
statusFlagResult = returns.register.statusflag
|
||||
val returnRegister = if(statusFlagResult==null) codeGen.registers.nextFree() else -1
|
||||
FunctionCallArgs.RegSpec(returnIrType, returnRegister, returns.register)
|
||||
}
|
||||
} else {
|
||||
// multiple return values: take the first *register* (not status flag) return value and ignore the rest.
|
||||
val returns = callTarget.returns.first { it.register.registerOrPair!=null }
|
||||
@ -457,12 +461,49 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||
else
|
||||
IRInstruction(Opcode.CALL, address = callTarget.address!!.toInt(), fcallArgs = FunctionCallArgs(argRegisters, returnRegSpec))
|
||||
addInstr(result, call, null)
|
||||
|
||||
var finalReturnRegister = returnRegSpec?.registerNum ?: -1
|
||||
|
||||
if(fcall.parent is PtAssignment) {
|
||||
// look if the status flag bit should actually be returned as a 0/1 byte value in a result register (so it can be assigned)
|
||||
if(statusFlagResult!=null && returnRegSpec!=null) {
|
||||
// assign status flag bit to the return value register
|
||||
finalReturnRegister = codeGen.registers.nextFree()
|
||||
when(statusFlagResult) {
|
||||
Statusflag.Pc -> {
|
||||
result += IRCodeChunk(null, null).also {
|
||||
it += IRInstruction(Opcode.LOAD, returnRegSpec.dt, reg1=finalReturnRegister, immediate = 0)
|
||||
it += IRInstruction(Opcode.ROXL, returnRegSpec.dt, reg1=finalReturnRegister)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
val branchOpcode = when(statusFlagResult) {
|
||||
Statusflag.Pc -> Opcode.BSTCS
|
||||
Statusflag.Pz -> Opcode.BSTEQ
|
||||
Statusflag.Pv -> Opcode.BSTVS
|
||||
Statusflag.Pn -> Opcode.BSTNEG
|
||||
}
|
||||
val setLabel = codeGen.createLabelName()
|
||||
val endLabel = codeGen.createLabelName()
|
||||
result += IRCodeChunk(null, null).also {
|
||||
it += IRInstruction(branchOpcode, labelSymbol = setLabel)
|
||||
it += IRInstruction(Opcode.LOAD, returnRegSpec.dt, reg1=finalReturnRegister, immediate = 0)
|
||||
it += IRInstruction(Opcode.JUMP, labelSymbol = endLabel)
|
||||
}
|
||||
result += IRCodeChunk(setLabel, null).also {
|
||||
it += IRInstruction(Opcode.LOAD, returnRegSpec.dt, reg1=finalReturnRegister, immediate = 1)
|
||||
}
|
||||
result += IRCodeChunk(endLabel, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return if(fcall.void)
|
||||
ExpressionCodeResult(result, IRDataType.BYTE, -1, -1)
|
||||
else if(fcall.type==DataType.FLOAT)
|
||||
ExpressionCodeResult(result, returnRegSpec!!.dt, -1, returnRegSpec.registerNum)
|
||||
ExpressionCodeResult(result, returnRegSpec!!.dt, -1, finalReturnRegister)
|
||||
else
|
||||
ExpressionCodeResult(result, returnRegSpec!!.dt, returnRegSpec.registerNum, -1)
|
||||
ExpressionCodeResult(result, returnRegSpec!!.dt, finalReturnRegister, -1)
|
||||
}
|
||||
else -> throw AssemblyError("invalid node type")
|
||||
}
|
||||
|
@ -2,8 +2,6 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
- IR (expericodegen): fix code for calling routines that return a boolean in a status register such as Carry flag, it has to store the flag value somewhere
|
||||
|
||||
- merge branch optimize-st for some optimizations regarding SymbolTable use
|
||||
|
||||
- [on branch: call-pointers] allow calling a subroutine via a pointer variable (indirect JSR, optimized form of callfar())
|
||||
@ -18,6 +16,8 @@ Future Things and Ideas
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Compiler:
|
||||
|
||||
- What happens when subs return a boolean not in A, but in Carry flag?
|
||||
- What happens when we keep the BOOL type around until in codegen? (so, get rid of Boolean->ubyte and boolean remover)
|
||||
- Multidimensional arrays and chained indexing, purely as syntactic sugar over regular arrays.
|
||||
- make a form of "manual generics" possible like: varsub routine(T arg)->T where T is expanded to a specific type
|
||||
(this is already done hardcoded for several of the builtin functions)
|
||||
|
@ -4,54 +4,33 @@
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
if test_c_set()
|
||||
txt.print("yes1\n")
|
||||
else
|
||||
goto skip1
|
||||
bool @shared statusc = test_carry_set()
|
||||
bool @shared statusv = test_v_set()
|
||||
bool @shared statusz = test_z_set()
|
||||
bool @shared statusn = test_n_set()
|
||||
|
||||
txt.print("no1\n")
|
||||
|
||||
skip1:
|
||||
if test_c_clear()
|
||||
txt.print("yes2\n")
|
||||
else
|
||||
goto skip2
|
||||
|
||||
txt.print("no1\n")
|
||||
|
||||
skip2:
|
||||
txt.print("done\n")
|
||||
if test_carry_set() {
|
||||
txt.print("set!\n")
|
||||
}
|
||||
if test_v_set() {
|
||||
txt.print("set!\n")
|
||||
}
|
||||
if test_z_set() {
|
||||
txt.print("set!\n")
|
||||
}
|
||||
if test_n_set() {
|
||||
txt.print("set!\n")
|
||||
}
|
||||
}
|
||||
|
||||
asmsub test_c_clear() -> bool @Pc {
|
||||
asmsub test_carry_set() -> bool @Pc {
|
||||
%asm {{
|
||||
clc
|
||||
sec
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub test_z_clear() -> bool @Pz {
|
||||
%asm {{
|
||||
lda #1
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub test_n_clear() -> bool @Pn {
|
||||
%asm {{
|
||||
lda #1
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub test_v_clear() -> bool @Pv {
|
||||
%asm {{
|
||||
clv
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub test_c_set() -> bool @Pc {
|
||||
asmsub test_v_set() -> bool @Pv {
|
||||
%asm {{
|
||||
sec
|
||||
rts
|
||||
@ -60,22 +39,15 @@ skip2:
|
||||
|
||||
asmsub test_z_set() -> bool @Pz {
|
||||
%asm {{
|
||||
lda #0
|
||||
sec
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub test_n_set() -> bool @Pn {
|
||||
%asm {{
|
||||
lda #-1
|
||||
sec
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub test_v_set() -> bool @Pv {
|
||||
%asm {{
|
||||
bit +
|
||||
+ rts
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
@ -928,18 +928,27 @@ data class IRInstruction(
|
||||
val returns = fcallArgs.returns
|
||||
if(returns!=null) {
|
||||
result.add(":")
|
||||
val cpuReg = if(returns.cpuRegister==null) "" else {
|
||||
if(returns.cpuRegister.registerOrPair!=null)
|
||||
returns.cpuRegister.registerOrPair.toString()
|
||||
else
|
||||
returns.cpuRegister.statusflag.toString()
|
||||
}
|
||||
if(cpuReg.isEmpty()) {
|
||||
when (returns.dt) {
|
||||
IRDataType.BYTE -> result.add("r${returns.registerNum}.b")
|
||||
IRDataType.WORD -> result.add("r${returns.registerNum}.w")
|
||||
IRDataType.FLOAT -> result.add("fr${returns.registerNum}.f")
|
||||
}
|
||||
if(returns.cpuRegister!=null) {
|
||||
val cpuReg =
|
||||
if(returns.cpuRegister.registerOrPair!=null)
|
||||
returns.cpuRegister.registerOrPair.toString()
|
||||
else
|
||||
returns.cpuRegister.statusflag.toString()
|
||||
} else {
|
||||
result.add("@" + cpuReg)
|
||||
if(returns.cpuRegister?.statusflag==null) {
|
||||
when (returns.dt) {
|
||||
IRDataType.BYTE -> result.add(".b")
|
||||
IRDataType.WORD -> result.add(".w")
|
||||
IRDataType.FLOAT -> result.add(".f")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -254,6 +254,14 @@ private fun parseCall(rest: String): ParsedCall {
|
||||
return FunctionCallArgs.RegSpec(type, num, cpuRegister)
|
||||
}
|
||||
|
||||
fun parseReturnRegspec(reg: String): FunctionCallArgs.RegSpec {
|
||||
return if(reg.startsWith('@')) {
|
||||
FunctionCallArgs.RegSpec(IRDataType.BYTE, -1, parseRegisterOrStatusflag(reg.drop(1)))
|
||||
} else {
|
||||
parseRegspec(reg)
|
||||
}
|
||||
}
|
||||
|
||||
fun parseArgs(args: String): List<FunctionCallArgs.ArgumentSpec> {
|
||||
if(args.isBlank())
|
||||
return emptyList()
|
||||
@ -285,7 +293,7 @@ private fun parseCall(rest: String): ParsedCall {
|
||||
actualTarget,
|
||||
address,
|
||||
arguments,
|
||||
if(returns==null) null else parseRegspec(returns)
|
||||
if(returns==null) null else parseReturnRegspec(returns)
|
||||
)
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user