mirror of
https://github.com/irmen/prog8.git
synced 2024-12-29 19:31:40 +00:00
changed IR JUMPI instruction to support more indirect jump cases
This commit is contained in:
parent
73baaeff1f
commit
f93b7e3303
@ -291,7 +291,7 @@ class IRCodeGen(
|
||||
BranchCondition.VS -> IRInstruction(Opcode.BSTVS, address = address)
|
||||
}
|
||||
addInstr(result, branchIns, null)
|
||||
} else if(label!=null) {
|
||||
} else if(label!=null && !isIndirectJump(goto)) {
|
||||
val branchIns = when(branch.condition) {
|
||||
BranchCondition.CS -> IRInstruction(Opcode.BSTCS, labelSymbol = label)
|
||||
BranchCondition.CC -> IRInstruction(Opcode.BSTCC, labelSymbol = label)
|
||||
@ -304,7 +304,7 @@ class IRCodeGen(
|
||||
}
|
||||
addInstr(result, branchIns, null)
|
||||
} else {
|
||||
TODO("JUMP to expression address ${goto.target}")
|
||||
TODO("JUMP to expression address ${goto.target}") // keep in mind the branch insruction that may need to precede this!
|
||||
}
|
||||
if(branch.falseScope.children.isNotEmpty())
|
||||
result += translateNode(branch.falseScope)
|
||||
@ -1027,12 +1027,12 @@ class IRCodeGen(
|
||||
it += IRInstruction(gotoOpcode, IRDataType.BYTE, reg1 = compResultReg, immediate = 0, labelSymbol = afterIfLabel)
|
||||
}
|
||||
}
|
||||
val identifier = goto.target as? PtIdentifier
|
||||
if(identifier!=null) {
|
||||
it += IRInstruction(Opcode.JUMPI, labelSymbol = identifier.name)
|
||||
} else {
|
||||
TODO("JUMP to expression address ${goto.target}")
|
||||
// evaluate jump address expression into a register and jump indirectly to it
|
||||
val tr = expressionEval.translateExpression(goto.target)
|
||||
for(i in tr.chunks.flatMap { it.instructions }) {
|
||||
it += i
|
||||
}
|
||||
it += IRInstruction(Opcode.JUMPI, reg1 = tr.resultReg)
|
||||
} else {
|
||||
// normal jump, directly to target with branch opcode
|
||||
when(condition.operator) {
|
||||
@ -1054,10 +1054,10 @@ class IRCodeGen(
|
||||
}
|
||||
it += if (goto.target.asConstInteger() != null)
|
||||
IRInstruction(gotoOpcode, IRDataType.BYTE, reg1 = compResultReg, immediate = 0, address = goto.target.asConstInteger())
|
||||
else if(goto.target is PtIdentifier)
|
||||
else if(goto.target is PtIdentifier && !isIndirectJump(goto))
|
||||
IRInstruction(gotoOpcode, IRDataType.BYTE, reg1 = compResultReg, immediate = 0, labelSymbol = (goto.target as PtIdentifier).name)
|
||||
else
|
||||
TODO("JUMP to expression address ${goto.target}")
|
||||
TODO("JUMP to expression address ${goto.target}") // keep in mind the branch insruction that may need to precede this!
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1073,10 +1073,10 @@ class IRCodeGen(
|
||||
else {
|
||||
require(!isIndirectJump(goto)) { "indirect jumps cannot be expressed using a branch opcode"}
|
||||
val identifier = goto.target as? PtIdentifier
|
||||
if(identifier!=null)
|
||||
if(identifier!=null && !isIndirectJump(goto))
|
||||
IRInstruction(branchOpcode, labelSymbol = identifier.name)
|
||||
else
|
||||
TODO("JUMP to expression address ${goto.target}")
|
||||
TODO("JUMP to expression address ${goto.target}") // keep in mind the branch insruction that may need to precede this!
|
||||
}
|
||||
}
|
||||
|
||||
@ -1084,11 +1084,6 @@ class IRCodeGen(
|
||||
// indirect jump to target so the if has to jump past it instead
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val afterIfLabel = createLabelName()
|
||||
val identifier = goto.target as? PtIdentifier
|
||||
if(identifier==null) {
|
||||
TODO("JUMP to expression address ${goto.target}")
|
||||
}
|
||||
val gotoSymbol = identifier.name
|
||||
|
||||
fun ifNonZeroIntThenJump_BinExpr(condition: PtBinaryExpression) {
|
||||
if(condition.operator in LogicalOperators) {
|
||||
@ -1210,7 +1205,10 @@ class IRCodeGen(
|
||||
else -> throw AssemblyError("weird if condition ${ifElse.condition}")
|
||||
}
|
||||
|
||||
addInstr(result, IRInstruction(Opcode.JUMPI, labelSymbol = gotoSymbol), null)
|
||||
// indirect jump to some computed address
|
||||
val tr = expressionEval.translateExpression(goto.target)
|
||||
result += tr.chunks
|
||||
addInstr(result, IRInstruction(Opcode.JUMPI, reg1 = tr.resultReg), null)
|
||||
result += IRCodeChunk(afterIfLabel, null)
|
||||
return result
|
||||
}
|
||||
@ -1254,10 +1252,10 @@ class IRCodeGen(
|
||||
}
|
||||
if (goto.target.asConstInteger() != null)
|
||||
addInstr(result, IRInstruction(opcode, irDt, reg1 = firstReg, immediate = number, address = goto.target.asConstInteger()), null)
|
||||
else if(goto.target is PtIdentifier)
|
||||
else if(goto.target is PtIdentifier && !isIndirectJump(goto))
|
||||
addInstr(result, IRInstruction(opcode, irDt, reg1 = firstReg, immediate = number, labelSymbol = (goto.target as PtIdentifier).name), null)
|
||||
else
|
||||
TODO("JUMP to expression address ${goto.target}")
|
||||
TODO("JUMP to expression address ${goto.target}") // keep in mind the branch insruction that may need to precede this!
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -1313,10 +1311,10 @@ class IRCodeGen(
|
||||
} else {
|
||||
if (goto.target.asConstInteger() != null)
|
||||
addInstr(result, IRInstruction(opcode, irDt, reg1 = firstReg, reg2 = secondReg, address = goto.target.asConstInteger()), null)
|
||||
else if(goto.target is PtIdentifier)
|
||||
else if(goto.target is PtIdentifier && !isIndirectJump(goto))
|
||||
addInstr(result, IRInstruction(opcode, irDt, reg1 = firstReg, reg2 = secondReg, labelSymbol = (goto.target as PtIdentifier).name), null)
|
||||
else
|
||||
TODO("JUMP to expression address ${goto.target}")
|
||||
TODO("JUMP to expression address ${goto.target}") // keep in mind the branch insruction that may need to precede this!
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1649,23 +1647,26 @@ class IRCodeGen(
|
||||
private fun translate(jump: PtJump): IRCodeChunks {
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val chunk = IRCodeChunk(null, null)
|
||||
chunk += if(jump.target.asConstInteger()!=null) {
|
||||
IRInstruction(Opcode.JUMP, address = jump.target.asConstInteger())
|
||||
} else {
|
||||
val identifier = jump.target as? PtIdentifier
|
||||
if (identifier != null) {
|
||||
if(isIndirectJump(jump)) {
|
||||
IRInstruction(Opcode.JUMPI, labelSymbol = identifier.name)
|
||||
} else {
|
||||
IRInstruction(Opcode.JUMP, labelSymbol = identifier.name)
|
||||
}
|
||||
} else {
|
||||
// val tr = expressionEval.translateExpression(jump.target)
|
||||
TODO("JUMP to expression address ${jump.target}")
|
||||
}
|
||||
}
|
||||
if(jump.target.asConstInteger()!=null) {
|
||||
chunk += IRInstruction(Opcode.JUMP, address = jump.target.asConstInteger())
|
||||
result += chunk
|
||||
return result
|
||||
} else {
|
||||
val identifier = jump.target as? PtIdentifier
|
||||
if (identifier != null && !isIndirectJump(jump)) {
|
||||
// jump to label
|
||||
chunk += IRInstruction(Opcode.JUMP, labelSymbol = identifier.name)
|
||||
result += chunk
|
||||
return result
|
||||
}
|
||||
// evaluate jump address expression into a register and jump indirectly to it
|
||||
val tr = expressionEval.translateExpression(jump.target)
|
||||
result += tr.chunks
|
||||
result += IRCodeChunk(null, null).also {
|
||||
it += IRInstruction(Opcode.JUMPI, reg1=tr.resultReg)
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
private fun isIndirectJump(jump: PtJump): Boolean {
|
||||
|
@ -397,7 +397,7 @@ cx16 {
|
||||
extsub $ff4a = CLOSE_ALL(ubyte device @A) clobbers(A,X,Y)
|
||||
extsub $ff59 = LKUPLA(ubyte la @A) clobbers(A,X,Y)
|
||||
extsub $ff5c = LKUPSA(ubyte sa @Y) clobbers(A,X,Y)
|
||||
extsub $ff5f = screen_mode(ubyte mode @A, bool getCurrent @Pc) -> ubyte @A, ubyte @X, ubyte @Y, bool @Pc ; also see SCREEN or get_screen_mode()
|
||||
extsub $ff5f = screen_mode(ubyte mode @A, bool getCurrent @Pc) -> ubyte @A, ubyte @X, ubyte @Y, bool @Pc ; also see SCREEN or get/set_screen_mode()
|
||||
extsub $ff62 = screen_set_charset(ubyte charset @A, uword charsetptr @XY) clobbers(A,X,Y)
|
||||
extsub $ff6e = JSRFAR() ; following word = address to call, byte after that=rom/ram bank it is in
|
||||
extsub $ff74 = fetch(ubyte zp_startaddr @A, ubyte bank @X, ubyte index @Y) clobbers(X) -> ubyte @A
|
||||
|
@ -24,6 +24,9 @@ Future Things and Ideas
|
||||
Need to add some way to generate a stable jump table at a given address.
|
||||
Need library to not call init_system AND init_system_phase2 not either.
|
||||
Library must not include prog8_program_start stuff either.
|
||||
- Add a LZSA decompressor to the compression library to be able to decompress lzsa when you don't have it in ROM or when the ROM is banked out or unavailable
|
||||
Problem is: on the X16, it should replicate the Kernal's behavior with decompressing to Vram / not incrementing the output address
|
||||
- Add TSCrunch or ZX0 decruncher to compression lib. Same requirement on X16 again to be able to decompress into vram.
|
||||
- Fix missing cases where regular & has to return the start of the split array in memory whatever byte comes first. Search TODO("address of split word array")
|
||||
- Add a syntax to access specific bits in a variable, to avoid manually shifts&ands, something like variable[4:8] ? (or something else this may be too similar to regular array indexing)
|
||||
- something to reduce the need to use fully qualified names all the time. 'with' ? Or 'using <prefix>'?
|
||||
@ -56,7 +59,7 @@ IR/VM
|
||||
- fix call() return value handling
|
||||
- fix float register parameters (FAC1,FAC2) for extsubs, search for TODO("floating point register parameters not supported")
|
||||
- proper code gen for the CALLI instruction and that it (optionally) returns a word value that needs to be assigned to a reg
|
||||
- make it possible to jump and branch to a computed address (expression), see TODO("JUMP to expression address" . This needs a change in the JUMPI instruction: it has to take a register instead (like CALLI)
|
||||
- make it possible to jump and branch to a computed address (expression) in all cases, see TODO("JUMP to expression address"
|
||||
- idea: (but LLVM IR simply keeps the variables, so not a good idea then?...): replace all scalar variables by an allocated register. Keep a table of the variable to register mapping (including the datatype)
|
||||
global initialization values are simply a list of LOAD instructions.
|
||||
Variables replaced include all subroutine parameters! So the only variables that remain as variables are arrays and strings.
|
||||
|
@ -1,7 +1,8 @@
|
||||
main {
|
||||
sub start() {
|
||||
;str test = '?' * 10
|
||||
str name = "foo"
|
||||
cx16.r0 = name+2
|
||||
cx16.r0 = $aabb
|
||||
cx16.r1 = $1122
|
||||
|
||||
goto cx16.r1+256
|
||||
}
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ storehxy reg1 - store reg1.w into cpu hardware register
|
||||
CONTROL FLOW
|
||||
------------
|
||||
jump location - continue running at instruction at 'location' (label/memory address)
|
||||
jumpi pointervar - continue running at memory address contained in the pointer variable (indirect jump)
|
||||
jumpi rqg1 - continue running at memory address in reg1 (indirect jump)
|
||||
preparecall numparams - indicator that the next instructions are the param setup and function call/syscall with <numparams> parameters
|
||||
calli reg1 - calls a subroutine (without arguments and without return valus) at memory addres in reg1 (indirect jsr)
|
||||
call label(argument register list) [: resultreg.type]
|
||||
@ -645,7 +645,7 @@ val instructionFormats = mutableMapOf(
|
||||
Opcode.STOREHAY to InstructionFormat.from("W,<r1"),
|
||||
Opcode.STOREHXY to InstructionFormat.from("W,<r1"),
|
||||
Opcode.JUMP to InstructionFormat.from("N,<a"),
|
||||
Opcode.JUMPI to InstructionFormat.from("N,<a"),
|
||||
Opcode.JUMPI to InstructionFormat.from("N,<r1"),
|
||||
Opcode.PREPARECALL to InstructionFormat.from("N,<i"),
|
||||
Opcode.CALLI to InstructionFormat.from("N,<r1"),
|
||||
Opcode.CALL to InstructionFormat.from("N,call"),
|
||||
|
@ -624,7 +624,9 @@ class VirtualMachine(irProgram: IRProgram) {
|
||||
}
|
||||
|
||||
private fun InsJUMPI(i: IRInstruction) {
|
||||
val artificialAddress = memory.getUW(i.address!!).toInt()
|
||||
val artificialAddress = registers.getUW(i.reg1!!).toInt()
|
||||
if(!artificialLabelAddresses.contains(artificialAddress))
|
||||
throw IllegalArgumentException("vm program can't jump to system memory address (${i.opcode} ${artificialAddress.toHex()})")
|
||||
pcChunk = artificialLabelAddresses.getValue(artificialAddress)
|
||||
pcIndex = 0
|
||||
}
|
||||
|
@ -123,7 +123,7 @@ class VmProgramLoader {
|
||||
}
|
||||
|
||||
val label = ins.labelSymbol
|
||||
if (label != null && (ins.opcode !in OpcodesThatBranch || ins.opcode==Opcode.JUMPI)) {
|
||||
if (label != null && (ins.opcode !in OpcodesThatBranch)) {
|
||||
placeholders[Pair(chunk, index)] = label
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user