mirror of
https://github.com/irmen/prog8.git
synced 2024-11-28 10:51:14 +00:00
fix IR if expression sometimes lacking a cmpi after calculation of the condition value
VM/IR: add a returni immediate value return instruction to replace certain returnr's
This commit is contained in:
parent
09cbdf410a
commit
4a47e15b1c
@ -1395,12 +1395,14 @@ class IRCodeGen(
|
||||
private fun ifWithElse_IntegerCond(ifElse: PtIfElse): List<IRCodeChunkBase> {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
|
||||
fun translateSimple(condition: PtExpression, jumpFalseOpcode: Opcode) {
|
||||
fun translateSimple(condition: PtExpression, jumpFalseOpcode: Opcode, addCmpiZero: Boolean) {
|
||||
|
||||
if(condition is PtBuiltinFunctionCall && condition.name.startsWith("prog8_ifelse_bittest_"))
|
||||
throw AssemblyError("IR codegen doesn't have special instructions for dedicated BIT tests and should just still use normal AND")
|
||||
|
||||
val tr = expressionEval.translateExpression(condition)
|
||||
if(addCmpiZero)
|
||||
tr.chunks.last().instructions.add(IRInstruction(Opcode.CMPI, tr.dt, reg1 = tr.resultReg, immediate = 0))
|
||||
result += tr.chunks
|
||||
if(ifElse.hasElse()) {
|
||||
val elseLabel = createLabelName()
|
||||
@ -1420,7 +1422,7 @@ class IRCodeGen(
|
||||
|
||||
fun translateBinExpr(condition: PtBinaryExpression) {
|
||||
if(condition.operator in LogicalOperators)
|
||||
return translateSimple(condition, Opcode.BSTEQ)
|
||||
return translateSimple(condition, Opcode.BSTEQ, false)
|
||||
|
||||
val signed = condition.left.type in SignedDatatypes
|
||||
val elseBranchFirstReg: Int
|
||||
@ -1559,18 +1561,21 @@ class IRCodeGen(
|
||||
when(val cond=ifElse.condition) {
|
||||
is PtBool -> {
|
||||
// normally this will be optimized away, but not with -noopt
|
||||
translateSimple(cond, Opcode.BSTEQ)
|
||||
translateSimple(cond, Opcode.BSTEQ, false)
|
||||
}
|
||||
is PtTypeCast -> {
|
||||
require(cond.type==DataType.BOOL && cond.value.type in NumericDatatypes)
|
||||
translateSimple(cond, Opcode.BSTEQ)
|
||||
translateSimple(cond, Opcode.BSTEQ, false)
|
||||
}
|
||||
is PtIdentifier, is PtArrayIndexer, is PtBuiltinFunctionCall, is PtFunctionCall, is PtContainmentCheck -> {
|
||||
translateSimple(cond, Opcode.BSTEQ)
|
||||
is PtIdentifier, is PtArrayIndexer, is PtContainmentCheck -> {
|
||||
translateSimple(cond, Opcode.BSTEQ, false)
|
||||
}
|
||||
is PtBuiltinFunctionCall, is PtFunctionCall -> {
|
||||
translateSimple(cond, Opcode.BSTEQ, true)
|
||||
}
|
||||
is PtPrefix -> {
|
||||
require(cond.operator=="not")
|
||||
translateSimple(cond.value, Opcode.BSTNE)
|
||||
translateSimple(cond.value, Opcode.BSTNE, false)
|
||||
}
|
||||
is PtBinaryExpression -> {
|
||||
translateBinExpr(cond)
|
||||
@ -1648,14 +1653,22 @@ class IRCodeGen(
|
||||
addInstr(result, IRInstruction(Opcode.RETURN), null)
|
||||
} else {
|
||||
if(value.type==DataType.FLOAT) {
|
||||
val tr = expressionEval.translateExpression(value)
|
||||
addToResult(result, tr, -1, tr.resultFpReg)
|
||||
addInstr(result, IRInstruction(Opcode.RETURNR, IRDataType.FLOAT, fpReg1 = tr.resultFpReg), null)
|
||||
if(value is PtNumber) {
|
||||
addInstr(result, IRInstruction(Opcode.RETURNI, IRDataType.FLOAT, immediateFp = value.number), null)
|
||||
} else {
|
||||
val tr = expressionEval.translateExpression(value)
|
||||
addToResult(result, tr, -1, tr.resultFpReg)
|
||||
addInstr(result, IRInstruction(Opcode.RETURNR, IRDataType.FLOAT, fpReg1 = tr.resultFpReg), null)
|
||||
}
|
||||
}
|
||||
else {
|
||||
val tr = expressionEval.translateExpression(value)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
addInstr(result, IRInstruction(Opcode.RETURNR, irType(value.type) , reg1=tr.resultReg), null)
|
||||
if(value.asConstInteger()!=null) {
|
||||
addInstr(result, IRInstruction(Opcode.RETURNI, irType(value.type), immediate = value.asConstInteger()), null)
|
||||
} else {
|
||||
val tr = expressionEval.translateExpression(value)
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
addInstr(result, IRInstruction(Opcode.RETURNR, irType(value.type), reg1 = tr.resultReg), null)
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
|
@ -299,7 +299,7 @@ class IRPeepholeOptimizer(private val irprog: IRProgram) {
|
||||
}
|
||||
|
||||
// remove useless RETURN
|
||||
if(idx>0 && (ins.opcode == Opcode.RETURN || ins.opcode==Opcode.RETURNR)) {
|
||||
if(idx>0 && (ins.opcode == Opcode.RETURN || ins.opcode==Opcode.RETURNR || ins.opcode==Opcode.RETURNI)) {
|
||||
val previous = chunk.instructions[idx-1]
|
||||
if(previous.opcode in OpcodesThatJump) {
|
||||
chunk.instructions.removeAt(idx)
|
||||
|
@ -1,9 +1,8 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
VM/IR: fix return value passing from %ir routines? (diskio.exists routine always returns true)
|
||||
|
||||
make better zsmkit example
|
||||
replace zsound example by a zsmkit example
|
||||
contribute a short how-to to the zsmkit repo for building a suitable blob
|
||||
write a howto for integrating third party library code like zsmkit and vtui
|
||||
|
||||
Improve register load order in subroutine call args assignments:
|
||||
|
@ -1,30 +1,60 @@
|
||||
%import diskio
|
||||
%import textio
|
||||
;%import gfx_hires4
|
||||
%import diskio
|
||||
%option no_sysinit
|
||||
%zeropage basicsafe
|
||||
|
||||
main {
|
||||
|
||||
sub start() {
|
||||
txt.print_bool(diskio.exists("doesntexist.prg"))
|
||||
txt.print_ub(exists_byte("test.prg"))
|
||||
txt.spc()
|
||||
txt.print_ub(exists_byte("doesntexist.xxx"))
|
||||
txt.nl()
|
||||
txt.print_bool(diskio.exists("test.prg"))
|
||||
txt.print_bool(exists_bool("test.prg"))
|
||||
txt.spc()
|
||||
txt.print_bool(exists_bool("doesntexist.xxx"))
|
||||
txt.nl()
|
||||
txt.print_bool(exists1("test.prg"))
|
||||
txt.spc()
|
||||
txt.print_bool(exists1("doesntexist.xxx"))
|
||||
txt.nl()
|
||||
txt.print_bool(exists2("test.prg"))
|
||||
txt.spc()
|
||||
txt.print_bool(exists2("doesntexist.xxx"))
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
diskio.f_open_w("dump.bin")
|
||||
diskio.f_close_w()
|
||||
diskio.f_close_w()
|
||||
diskio.f_close_w()
|
||||
diskio.f_close_w()
|
||||
sub exists1(str filename) -> bool {
|
||||
; -- returns true if the given file exists on the disk, otherwise false
|
||||
if exists_byte(filename)!=0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
; gfx_hires4.graphics_mode()
|
||||
; gfx_hires4.circle(300, 250, 200, 3)
|
||||
; gfx_hires4.rect(320, 10, 20, 200, 3)
|
||||
; gfx_hires4.fill(310, 310, 2)
|
||||
;
|
||||
; repeat {
|
||||
; }
|
||||
sub exists2(str filename) -> bool {
|
||||
; -- returns true if the given file exists on the disk, otherwise false
|
||||
if exists_bool(filename) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
sub exists_bool(str name) -> bool {
|
||||
%ir {{
|
||||
loadm.w r65535,main.exists_bool.name
|
||||
syscall 52 (r65535.w): r0.b
|
||||
returnr.b r0
|
||||
}}
|
||||
}
|
||||
|
||||
sub exists_byte(str name) -> ubyte {
|
||||
%ir {{
|
||||
loadm.w r65535,main.exists_byte.name
|
||||
syscall 52 (r65535.w): r0.b
|
||||
returnr.b r0
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,6 +82,7 @@ syscall number (argument register list) [: resultreg.type]
|
||||
Always preceded by parameter setup and preparecall instructions
|
||||
return - restore last saved instruction location and continue at that instruction. No return value.
|
||||
returnr reg1 - like return, but also returns the value in reg1 to the caller
|
||||
returni number - like return, but also returns the immediate value to the caller
|
||||
|
||||
|
||||
|
||||
@ -289,6 +290,7 @@ enum class Opcode {
|
||||
SYSCALL,
|
||||
RETURN,
|
||||
RETURNR,
|
||||
RETURNI,
|
||||
|
||||
BSTCC,
|
||||
BSTCS,
|
||||
@ -428,7 +430,8 @@ val OpcodesThatJump = arrayOf(
|
||||
Opcode.JUMP,
|
||||
Opcode.JUMPI,
|
||||
Opcode.RETURN,
|
||||
Opcode.RETURNR
|
||||
Opcode.RETURNR,
|
||||
Opcode.RETURNI
|
||||
)
|
||||
|
||||
val OpcodesThatBranch = arrayOf(
|
||||
@ -436,6 +439,7 @@ val OpcodesThatBranch = arrayOf(
|
||||
Opcode.JUMPI,
|
||||
Opcode.RETURN,
|
||||
Opcode.RETURNR,
|
||||
Opcode.RETURNI,
|
||||
Opcode.CALLI,
|
||||
Opcode.CALL,
|
||||
Opcode.SYSCALL,
|
||||
@ -647,7 +651,8 @@ val instructionFormats = mutableMapOf(
|
||||
Opcode.CALL to InstructionFormat.from("N,call"),
|
||||
Opcode.SYSCALL to InstructionFormat.from("N,syscall"),
|
||||
Opcode.RETURN to InstructionFormat.from("N"),
|
||||
Opcode.RETURNR to InstructionFormat.from("BW,>r1 | F,>fr1"),
|
||||
Opcode.RETURNR to InstructionFormat.from("BW,<r1 | F,<fr1"),
|
||||
Opcode.RETURNI to InstructionFormat.from("BW,<i | F,<i"),
|
||||
Opcode.BSTCC to InstructionFormat.from("N,<a"),
|
||||
Opcode.BSTCS to InstructionFormat.from("N,<a"),
|
||||
Opcode.BSTEQ to InstructionFormat.from("N,<a"),
|
||||
|
@ -145,7 +145,7 @@ class IRProgram(val name: String,
|
||||
|
||||
// link all jump and branching instructions to their target
|
||||
chunk.instructions.forEach {
|
||||
if(it.opcode in OpcodesThatBranch && it.opcode!=Opcode.JUMPI && it.opcode!=Opcode.RETURN && it.opcode!=Opcode.RETURNR && it.labelSymbol!=null) {
|
||||
if(it.opcode in OpcodesThatBranch && it.opcode!=Opcode.JUMPI && it.opcode!=Opcode.RETURN && it.opcode!=Opcode.RETURNR && it.opcode!=Opcode.RETURNI && it.labelSymbol!=null) {
|
||||
if(it.labelSymbol.startsWith('$') || it.labelSymbol.first().isDigit()) {
|
||||
// it's a call to an address (romsub most likely)
|
||||
requireNotNull(it.address)
|
||||
|
@ -213,6 +213,7 @@ class VirtualMachine(irProgram: IRProgram) {
|
||||
Opcode.SYSCALL -> InsSYSCALL(ins)
|
||||
Opcode.RETURN -> InsRETURN()
|
||||
Opcode.RETURNR -> InsRETURNR(ins)
|
||||
Opcode.RETURNI -> InsRETURNI(ins)
|
||||
Opcode.BSTCC -> InsBSTCC(ins)
|
||||
Opcode.BSTCS -> InsBSTCS(ins)
|
||||
Opcode.BSTEQ -> InsBSTEQ(ins)
|
||||
@ -656,6 +657,46 @@ class VirtualMachine(irProgram: IRProgram) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun InsRETURNI(i: IRInstruction) {
|
||||
if(callStack.isEmpty())
|
||||
exit(0)
|
||||
else {
|
||||
val context = callStack.removeLast()
|
||||
val returns = context.fcallSpec.returns
|
||||
when (i.type!!) {
|
||||
IRDataType.BYTE -> {
|
||||
if(returns.isNotEmpty())
|
||||
registers.setUB(returns.single().registerNum, i.immediate!!.toUByte())
|
||||
else {
|
||||
val callInstr = context.returnChunk.instructions[context.returnIndex-1]
|
||||
if(callInstr.opcode!=Opcode.CALL)
|
||||
throw IllegalArgumentException("missing return value reg")
|
||||
}
|
||||
}
|
||||
IRDataType.WORD -> {
|
||||
if(returns.isNotEmpty())
|
||||
registers.setUW(returns.single().registerNum, i.immediate!!.toUShort())
|
||||
else {
|
||||
val callInstr = context.returnChunk.instructions[context.returnIndex-1]
|
||||
if(callInstr.opcode!=Opcode.CALL)
|
||||
throw IllegalArgumentException("missing return value reg")
|
||||
}
|
||||
}
|
||||
IRDataType.FLOAT -> {
|
||||
if(returns.isNotEmpty())
|
||||
registers.setFloat(returns.single().registerNum, i.immediateFp!!)
|
||||
else {
|
||||
val callInstr = context.returnChunk.instructions[context.returnIndex-1]
|
||||
if(callInstr.opcode!=Opcode.CALL)
|
||||
throw IllegalArgumentException("missing return value reg")
|
||||
}
|
||||
}
|
||||
}
|
||||
pcChunk = context.returnChunk
|
||||
pcIndex = context.returnIndex
|
||||
}
|
||||
}
|
||||
|
||||
private fun InsRETURNR(i: IRInstruction) {
|
||||
if(callStack.isEmpty())
|
||||
exit(0)
|
||||
|
Loading…
Reference in New Issue
Block a user