mirror of
https://github.com/irmen/prog8.git
synced 2025-02-16 22:30:46 +00:00
ir: improve register type detection
This commit is contained in:
parent
7b4a82b91a
commit
942d3ee640
@ -403,10 +403,11 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
if(fixedIndex!=null) {
|
||||
val chunk = IRCodeChunk(null, null).also {
|
||||
if(targetArray.splitWords) {
|
||||
val msbReg = codeGen.registers.nextFree()
|
||||
it += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1 = valueRegister, immediate = arrayLength, labelSymbol = "${variable}_lsb", symbolOffset = fixedIndex)
|
||||
it += IRInstruction(Opcode.MSIG, IRDataType.BYTE, reg1 = msbReg, reg2 = valueRegister)
|
||||
it += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1 = msbReg, immediate = arrayLength, labelSymbol = "${variable}_msb", symbolOffset = fixedIndex)
|
||||
val lsbmsbReg = codeGen.registers.nextFree()
|
||||
it += IRInstruction(Opcode.LSIG, IRDataType.BYTE, reg1 = lsbmsbReg, reg2 = valueRegister)
|
||||
it += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1 = lsbmsbReg, immediate = arrayLength, labelSymbol = "${variable}_lsb", symbolOffset = fixedIndex)
|
||||
it += IRInstruction(Opcode.MSIG, IRDataType.BYTE, reg1 = lsbmsbReg, reg2 = valueRegister)
|
||||
it += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1 = lsbmsbReg, immediate = arrayLength, labelSymbol = "${variable}_msb", symbolOffset = fixedIndex)
|
||||
}
|
||||
else
|
||||
it += IRInstruction(Opcode.STOREM, targetDt, reg1 = valueRegister, labelSymbol = variable, symbolOffset = fixedIndex*itemsize)
|
||||
@ -417,10 +418,11 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
||||
result += code
|
||||
result += IRCodeChunk(null, null).also {
|
||||
if(targetArray.splitWords) {
|
||||
val msbReg = codeGen.registers.nextFree()
|
||||
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1 = valueRegister, reg2=indexReg, immediate = arrayLength, labelSymbol = "${variable}_lsb")
|
||||
it += IRInstruction(Opcode.MSIG, IRDataType.BYTE, reg1 = msbReg, reg2 = valueRegister)
|
||||
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1 = msbReg, reg2=indexReg, immediate = arrayLength, labelSymbol = "${variable}_msb")
|
||||
val lsbmsbReg = codeGen.registers.nextFree()
|
||||
it += IRInstruction(Opcode.LSIG, IRDataType.BYTE, reg1 = lsbmsbReg, reg2 = valueRegister)
|
||||
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1 = lsbmsbReg, reg2=indexReg, immediate = arrayLength, labelSymbol = "${variable}_lsb")
|
||||
it += IRInstruction(Opcode.MSIG, IRDataType.BYTE, reg1 = lsbmsbReg, reg2 = valueRegister)
|
||||
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1 = lsbmsbReg, reg2=indexReg, immediate = arrayLength, labelSymbol = "${variable}_msb")
|
||||
}
|
||||
else
|
||||
it += IRInstruction(Opcode.STOREX, targetDt, reg1 = valueRegister, reg2=indexReg, labelSymbol = variable)
|
||||
|
@ -148,8 +148,9 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
val right = exprGen.translateExpression(call.args[1])
|
||||
addToResult(result, left, left.resultReg, -1)
|
||||
addToResult(result, right, right.resultReg, -1)
|
||||
result += codeGen.makeSyscall(IMSyscall.COMPARE_STRINGS, listOf(IRDataType.WORD to left.resultReg, IRDataType.WORD to right.resultReg), IRDataType.BYTE to left.resultReg)
|
||||
return ExpressionCodeResult(result, IRDataType.BYTE, left.resultReg, -1)
|
||||
val resultReg = codeGen.registers.nextFree()
|
||||
result += codeGen.makeSyscall(IMSyscall.COMPARE_STRINGS, listOf(IRDataType.WORD to left.resultReg, IRDataType.WORD to right.resultReg), IRDataType.BYTE to resultReg)
|
||||
return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1)
|
||||
}
|
||||
|
||||
private fun funcCmp(call: PtBuiltinFunctionCall): ExpressionCodeResult {
|
||||
@ -501,9 +502,13 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
}
|
||||
|
||||
private fun funcLsb(call: PtBuiltinFunctionCall): ExpressionCodeResult {
|
||||
return exprGen.translateExpression(call.args.single())
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
val tr = exprGen.translateExpression(call.args.single())
|
||||
addToResult(result, tr, tr.resultReg, -1)
|
||||
val resultReg = codeGen.registers.nextFree()
|
||||
addInstr(result, IRInstruction(Opcode.LSIG, IRDataType.BYTE, reg1 = resultReg, reg2 = tr.resultReg), null)
|
||||
// note: if a word result is needed, the upper byte is cleared by the typecast that follows. No need to do it here.
|
||||
// ....To be more strict, maybe we should introduce a new result register that is of type .b?
|
||||
return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1)
|
||||
}
|
||||
|
||||
private fun funcMsb(call: PtBuiltinFunctionCall): ExpressionCodeResult {
|
||||
|
@ -55,11 +55,12 @@ Future Things and Ideas
|
||||
IR/VM
|
||||
-----
|
||||
- getting it in shape for code generation...: the IR file should be able to encode every detail about a prog8 program (the VM doesn't have to actually be able to run all of it though!)
|
||||
- addUsedRegistersCounts() doesn't always determine the datatype correctly. For instance with indirect instructions it thinks it still is a byte whereas it is a word (address)
|
||||
- addUsedRegistersCounts() doesn't always determine the datatype correctly. --> GET RID OF THE Sxxx OPCODES FOR NOW?
|
||||
- fix TODO("IR rol/ror on split words array")
|
||||
- fix "<< in array" / ">> in array"
|
||||
- implement missing operators in AssignmentGen (array shifts etc)
|
||||
- fix call() return value handling
|
||||
- try to get rid of LSIG opcode again (but this will introduce byte reads from word typed registers...)
|
||||
- proper code gen for the CALLI instruction and that it (optionally) returns a word value that needs to be assigned to a reg
|
||||
- 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.
|
||||
|
@ -2,25 +2,31 @@
|
||||
%zeropage basicsafe
|
||||
%option no_sysinit
|
||||
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
cx16.r0L = 0
|
||||
cx16.r9L = if cx16.r0L & $80 != 0 11 else 22
|
||||
cx16.r10L = if cx16.r0L & $40 == 0 11 else 22
|
||||
|
||||
txt.print_ub(cx16.r9L)
|
||||
txt.spc()
|
||||
txt.print_ub(cx16.r10L)
|
||||
cx16.r2 = $eeee
|
||||
txt.print_uwhex(cx16.r2, true)
|
||||
txt.nl()
|
||||
|
||||
cx16.r0L = 255
|
||||
cx16.r9L = if cx16.r0L & $80 != 0 11 else 22
|
||||
cx16.r10L = if cx16.r0L & $40 == 0 11 else 22
|
||||
|
||||
txt.print_ub(cx16.r9L)
|
||||
txt.spc()
|
||||
txt.print_ub(cx16.r10L)
|
||||
cx16.r2,void = thing2() ; TODO fix IR+6502 codegen missing an ext.b (it is present when thing only returns single returnvalue)
|
||||
txt.print_uwhex(cx16.r2, true)
|
||||
txt.nl()
|
||||
cx16.r2 = thing() ; codegen does ext.b correctly here
|
||||
txt.print_uwhex(cx16.r2, true)
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
asmsub thing() -> ubyte @A {
|
||||
%asm {{
|
||||
lda #$44
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
asmsub thing2() -> ubyte @A, bool @Pc {
|
||||
%asm {{
|
||||
lda #$aa
|
||||
clc
|
||||
rts
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
||||
regs.append(" r$regnum -> $types")
|
||||
if (types.size > 1) {
|
||||
regs.append(" !!!! more than one type !!!!\n")
|
||||
println("Detected multi-type register usage: $regnum->$types in ${chunk.label} at ${chunk.sourceLinesPositions.firstOrNull()}")
|
||||
println("IR: Detected multi-type register usage: $regnum->$types in ${chunk.label} at ${chunk.sourceLinesPositions.firstOrNull()}")
|
||||
}
|
||||
else
|
||||
regs.append("\n")
|
||||
|
@ -40,7 +40,7 @@ loadm reg1, address - load reg1 with value at memory address
|
||||
loadi reg1, reg2 - load reg1 with value at memory indirect, memory pointed to by reg2
|
||||
loadx reg1, reg2, address - load reg1 with value at memory address indexed by value in reg2 (only the lsb part used for indexing)
|
||||
loadix reg1, reg2, pointeraddr - load reg1 with value at memory indirect, pointed to by pointeraddr indexed by value in reg2 (only the lsb part used for indexing)
|
||||
loadr reg1, reg2 - load reg1 with value in register reg2
|
||||
loadr reg1, reg2 - load reg1 with value in register reg2, "reg1 = reg2"
|
||||
loadha reg1 - load cpu hardware register A into reg1.b
|
||||
loadhx reg1 - load cpu hardware register X into reg1.b
|
||||
loadhy reg1 - load cpu hardware register Y into reg1.b
|
||||
@ -69,7 +69,7 @@ storehfacone fpreg1 - store fpreg1.f into "cpu register" fac1
|
||||
CONTROL FLOW
|
||||
------------
|
||||
jump location - continue running at instruction at 'location' (label/memory address)
|
||||
jumpi rqg1 - continue running at memory address in reg1 (indirect jump)
|
||||
jumpi reg1 - 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]
|
||||
@ -252,6 +252,7 @@ sei - set interrupt disable flag
|
||||
nop - do nothing
|
||||
breakpoint - trigger a breakpoint
|
||||
align alignmentvalue - represents a memory alignment directive
|
||||
lsig [b, w] reg1, reg2 - reg1 becomes the least significant byte (or word) of the word (or int) in reg2 (.w not yet implemented; requires 32 bits regs)
|
||||
msig [b, w] reg1, reg2 - reg1 becomes the most significant byte (or word) of the word (or int) in reg2 (.w not yet implemented; requires 32 bits regs)
|
||||
concat [b, w] reg1, reg2, reg3 - reg1.w = 'concatenate' two registers: lsb/lsw of reg2 (as msb) and lsb/lsw of reg3 (as lsb) into word or int (int not yet implemented; requires 32bits regs)
|
||||
push [b, w, f] reg1 - push value in reg1 on the stack
|
||||
@ -432,6 +433,7 @@ enum class Opcode {
|
||||
POP,
|
||||
PUSHST,
|
||||
POPST,
|
||||
LSIG,
|
||||
MSIG,
|
||||
CONCAT,
|
||||
BREAKPOINT,
|
||||
@ -790,6 +792,7 @@ val instructionFormats = mutableMapOf(
|
||||
Opcode.FFLOOR to InstructionFormat.from("F,>fr1,<fr2"),
|
||||
Opcode.FCEIL to InstructionFormat.from("F,>fr1,<fr2"),
|
||||
|
||||
Opcode.LSIG to InstructionFormat.from("BW,>r1,<r2"),
|
||||
Opcode.MSIG to InstructionFormat.from("BW,>r1,<r2"),
|
||||
Opcode.PUSH to InstructionFormat.from("BW,<r1 | F,<fr1"),
|
||||
Opcode.POP to InstructionFormat.from("BW,>r1 | F,>fr1"),
|
||||
@ -926,35 +929,32 @@ data class IRInstruction(
|
||||
OperandDirection.UNUSED -> {}
|
||||
OperandDirection.READ -> {
|
||||
readRegsCounts[this.reg1!!] = readRegsCounts.getValue(this.reg1)+1
|
||||
if(type!=null) {
|
||||
val actualtype = determineReg1Type()
|
||||
if(actualtype!=null) {
|
||||
var types = regsTypes[this.reg1]
|
||||
if(types==null) types = mutableSetOf()
|
||||
types += type
|
||||
types += actualtype
|
||||
regsTypes[this.reg1] = types
|
||||
}
|
||||
}
|
||||
OperandDirection.WRITE -> {
|
||||
writeRegsCounts[this.reg1!!] = writeRegsCounts.getValue(this.reg1)+1
|
||||
if(type!=null) {
|
||||
val actualtype = determineReg1Type()
|
||||
if(actualtype!=null) {
|
||||
var types = regsTypes[this.reg1]
|
||||
if(types==null) types = mutableSetOf()
|
||||
types += type
|
||||
types += actualtype
|
||||
regsTypes[this.reg1] = types
|
||||
}
|
||||
}
|
||||
OperandDirection.READWRITE -> {
|
||||
readRegsCounts[this.reg1!!] = readRegsCounts.getValue(this.reg1)+1
|
||||
if(type!=null) {
|
||||
var types = regsTypes[this.reg1]
|
||||
if(types==null) types = mutableSetOf()
|
||||
types += type
|
||||
regsTypes[this.reg1] = types
|
||||
}
|
||||
writeRegsCounts[this.reg1] = writeRegsCounts.getValue(this.reg1)+1
|
||||
if(type!=null) {
|
||||
val actualtype = determineReg1Type()
|
||||
if(actualtype!=null) {
|
||||
var types = regsTypes[this.reg1]
|
||||
if(types==null) types = mutableSetOf()
|
||||
types += type
|
||||
types += actualtype
|
||||
regsTypes[this.reg1] = types
|
||||
}
|
||||
}
|
||||
@ -963,10 +963,11 @@ data class IRInstruction(
|
||||
OperandDirection.UNUSED -> {}
|
||||
OperandDirection.READ -> {
|
||||
writeRegsCounts[this.reg2!!] = writeRegsCounts.getValue(this.reg2)+1
|
||||
if(type!=null) {
|
||||
val actualtype = determineReg2Type()
|
||||
if(actualtype!=null) {
|
||||
var types = regsTypes[this.reg2]
|
||||
if(types==null) types = mutableSetOf()
|
||||
types += type
|
||||
types += actualtype
|
||||
regsTypes[this.reg2] = types
|
||||
}
|
||||
}
|
||||
@ -976,10 +977,11 @@ data class IRInstruction(
|
||||
OperandDirection.UNUSED -> {}
|
||||
OperandDirection.READ -> {
|
||||
writeRegsCounts[this.reg3!!] = writeRegsCounts.getValue(this.reg3)+1
|
||||
if(type!=null) {
|
||||
val actualtype = determineReg3Type()
|
||||
if(actualtype!=null) {
|
||||
var types = regsTypes[this.reg3]
|
||||
if(types==null) types = mutableSetOf()
|
||||
types += type
|
||||
types += actualtype
|
||||
regsTypes[this.reg3] = types
|
||||
}
|
||||
}
|
||||
@ -1034,6 +1036,44 @@ data class IRInstruction(
|
||||
}
|
||||
}
|
||||
|
||||
private fun determineReg1Type(): IRDataType? {
|
||||
if(opcode==Opcode.JUMPI || opcode==Opcode.CALLI || opcode==Opcode.STOREZI)
|
||||
return IRDataType.WORD
|
||||
if(opcode==Opcode.EXT || opcode==Opcode.EXTS)
|
||||
return when(type) {
|
||||
IRDataType.BYTE -> IRDataType.WORD
|
||||
IRDataType.WORD -> TODO("ext.w into long type")
|
||||
else -> null
|
||||
}
|
||||
if(opcode==Opcode.CONCAT)
|
||||
return when(type) {
|
||||
IRDataType.BYTE -> IRDataType.WORD
|
||||
IRDataType.WORD -> TODO("concat.w from long type")
|
||||
else -> null
|
||||
}
|
||||
if(opcode==Opcode.ASRNM || opcode==Opcode.LSRNM || opcode==Opcode.LSLNM)
|
||||
return IRDataType.BYTE
|
||||
return this.type
|
||||
}
|
||||
|
||||
private fun determineReg2Type(): IRDataType? {
|
||||
if(opcode==Opcode.LOADI || opcode==Opcode.STOREI)
|
||||
return IRDataType.WORD
|
||||
if(opcode==Opcode.MSIG || opcode==Opcode.LSIG)
|
||||
return when(type) {
|
||||
IRDataType.BYTE -> IRDataType.WORD
|
||||
IRDataType.WORD -> TODO("msig/lsig.w from long type")
|
||||
else -> null
|
||||
}
|
||||
if(opcode==Opcode.ASRN || opcode==Opcode.LSRN || opcode==Opcode.LSLN)
|
||||
return IRDataType.BYTE
|
||||
return this.type
|
||||
}
|
||||
|
||||
private fun determineReg3Type(): IRDataType? {
|
||||
return this.type
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
val result = mutableListOf(opcode.name.lowercase())
|
||||
|
||||
|
@ -313,6 +313,7 @@ class VirtualMachine(irProgram: IRProgram) {
|
||||
Opcode.ROLM -> InsROLM(ins, false)
|
||||
Opcode.ROXL -> InsROL(ins, true)
|
||||
Opcode.ROXLM -> InsROLM(ins, true)
|
||||
Opcode.LSIG -> InsLSIG(ins)
|
||||
Opcode.MSIG -> InsMSIG(ins)
|
||||
Opcode.CONCAT -> InsCONCAT(ins)
|
||||
Opcode.PUSH -> InsPUSH(ins)
|
||||
@ -2290,6 +2291,18 @@ class VirtualMachine(irProgram: IRProgram) {
|
||||
statusCarry = newStatusCarry
|
||||
}
|
||||
|
||||
private fun InsLSIG(i: IRInstruction) {
|
||||
when(i.type!!) {
|
||||
IRDataType.BYTE -> {
|
||||
val value = registers.getUW(i.reg2!!)
|
||||
registers.setUB(i.reg1!!, value.toUByte())
|
||||
}
|
||||
IRDataType.WORD -> throw IllegalArgumentException("lsig.w not yet supported, requires 32-bits registers")
|
||||
IRDataType.FLOAT -> throw IllegalArgumentException("invalid float type for this instruction $i")
|
||||
}
|
||||
nextPc()
|
||||
}
|
||||
|
||||
private fun InsMSIG(i: IRInstruction) {
|
||||
when(i.type!!) {
|
||||
IRDataType.BYTE -> {
|
||||
|
Loading…
x
Reference in New Issue
Block a user