IR: implemented inplace prefix op on split array

VM: NEG instructions also set N and Z flags
This commit is contained in:
Irmen de Jong 2024-01-26 00:12:04 +01:00
parent 0800033b47
commit 39d2194d8f
4 changed files with 117 additions and 65 deletions

View File

@ -36,8 +36,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
else else
fallbackAssign(augAssign) fallbackAssign(augAssign)
} else if(array!=null) { } else if(array!=null) {
// TODO assignArrayAugmented(array, augAssign) assignArrayAugmented(array, augAssign)
fallbackAssign(augAssign)
} else { } else {
fallbackAssign(augAssign) fallbackAssign(augAssign)
} }
@ -157,27 +156,84 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
} }
private fun inplacePrefix(operator: String, array: PtArrayIndexer, eltSize: Int): Result<IRCodeChunks, NotImplementedError> { private fun inplacePrefix(operator: String, array: PtArrayIndexer, eltSize: Int): Result<IRCodeChunks, NotImplementedError> {
if(array.splitWords)
TODO("inplace prefix for split word array")
val result = mutableListOf<IRCodeChunkBase>() val result = mutableListOf<IRCodeChunkBase>()
val vmDt = irType(array.type) val vmDt = irType(array.type)
val constIndex = array.index.asConstInteger() val constIndex = array.index.asConstInteger()
fun loadIndex(): Int {
val tr = expressionEval.translateExpression(array.index)
addToResult(result, tr, tr.resultReg, -1)
if(!array.splitWords && eltSize>1)
result += codeGen.multiplyByConst(IRDataType.BYTE, tr.resultReg, eltSize)
return tr.resultReg
}
if(array.splitWords) {
// handle split LSB/MSB arrays
when(operator) {
"+" -> { }
"-" -> {
val skipCarryLabel = codeGen.createLabelName()
if(constIndex!=null) {
addInstr(result, IRInstruction(Opcode.NEGM, IRDataType.BYTE, labelSymbol = array.variable.name+"_lsb", symbolOffset = constIndex), null)
addInstr(result, IRInstruction(Opcode.BSTEQ, labelSymbol = skipCarryLabel), null)
addInstr(result, IRInstruction(Opcode.INCM, IRDataType.BYTE, labelSymbol = array.variable.name+"_msb", symbolOffset = constIndex), null)
addInstr(result, IRInstruction(Opcode.NEGM, IRDataType.BYTE, labelSymbol = array.variable.name+"_msb", symbolOffset = constIndex), skipCarryLabel)
} else {
val indexReg = loadIndex()
val registerLsb = codeGen.registers.nextFree()
val registerMsb = codeGen.registers.nextFree()
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1 = registerLsb, reg2 = indexReg, labelSymbol = array.variable.name+"_lsb")
it += IRInstruction(Opcode.NEG, IRDataType.BYTE, reg1 = registerLsb)
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1 = registerLsb, reg2 = indexReg, labelSymbol = array.variable.name+"_lsb")
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1 = registerMsb, reg2 = indexReg, labelSymbol = array.variable.name+"_msb")
it += IRInstruction(Opcode.NEG, IRDataType.BYTE, reg1 = registerMsb)
it += IRInstruction(Opcode.CMPI, IRDataType.BYTE, reg1 = registerLsb, immediate = 0)
it += IRInstruction(Opcode.BSTEQ, labelSymbol = skipCarryLabel)
it += IRInstruction(Opcode.DEC, IRDataType.BYTE, reg1 = registerMsb)
}
result += IRCodeChunk(skipCarryLabel, null).also {
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1 = registerMsb, reg2 = indexReg, labelSymbol = array.variable.name+"_msb")
}
}
}
"~" -> {
if(constIndex!=null) {
addInstr(result, IRInstruction(Opcode.INVM, IRDataType.BYTE, labelSymbol = array.variable.name+"_lsb", symbolOffset = constIndex), null)
addInstr(result, IRInstruction(Opcode.INVM, IRDataType.BYTE, labelSymbol = array.variable.name+"_msb", symbolOffset = constIndex), null)
} else {
val indexReg = loadIndex()
val register = codeGen.registers.nextFree()
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1 = register, reg2 = indexReg, labelSymbol = array.variable.name+"_lsb")
it += IRInstruction(Opcode.INV, IRDataType.BYTE, reg1 = register)
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1 = register, reg2 = indexReg, labelSymbol = array.variable.name+"_lsb")
it += IRInstruction(Opcode.LOADX, IRDataType.BYTE, reg1 = register, reg2 = indexReg, labelSymbol = array.variable.name+"_msb")
it += IRInstruction(Opcode.INV, IRDataType.BYTE, reg1 = register)
it += IRInstruction(Opcode.STOREX, IRDataType.BYTE, reg1 = register, reg2 = indexReg, labelSymbol = array.variable.name+"_msb")
}
}
}
else -> throw AssemblyError("weird prefix operator")
}
return Ok(result)
}
// normal array.
when(operator) { when(operator) {
"+" -> { } "+" -> { }
"-" -> { "-" -> {
if(constIndex!=null) { if(constIndex!=null) {
addInstr(result, IRInstruction(Opcode.NEGM, vmDt, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize), null) addInstr(result, IRInstruction(Opcode.NEGM, vmDt, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize), null)
} else { } else {
val indexReg = loadIndex()
val register = codeGen.registers.nextFree() val register = codeGen.registers.nextFree()
val tr = expressionEval.translateExpression(array.index)
addToResult(result, tr, tr.resultReg, -1)
if(eltSize>1)
result += codeGen.multiplyByConst(IRDataType.BYTE, tr.resultReg, eltSize)
result += IRCodeChunk(null, null).also { result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOADX, vmDt, reg1 = register, reg2 = tr.resultReg, labelSymbol = array.variable.name) it += IRInstruction(Opcode.LOADX, vmDt, reg1 = register, reg2 = indexReg, labelSymbol = array.variable.name)
it += IRInstruction(Opcode.NEG, vmDt, reg1 = register) it += IRInstruction(Opcode.NEG, vmDt, reg1 = register)
it += IRInstruction(Opcode.STOREX, vmDt, reg1 = register, reg2 = tr.resultReg, labelSymbol = array.variable.name) it += IRInstruction(Opcode.STOREX, vmDt, reg1 = register, reg2 = indexReg, labelSymbol = array.variable.name)
} }
} }
} }
@ -185,35 +241,29 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
if(constIndex!=null) { if(constIndex!=null) {
addInstr(result, IRInstruction(Opcode.INVM, vmDt, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize), null) addInstr(result, IRInstruction(Opcode.INVM, vmDt, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize), null)
} else { } else {
val indexReg = loadIndex()
val register = codeGen.registers.nextFree() val register = codeGen.registers.nextFree()
val tr = expressionEval.translateExpression(array.index)
addToResult(result, tr, tr.resultReg, -1)
if(eltSize>1)
result += codeGen.multiplyByConst(IRDataType.BYTE, tr.resultReg, eltSize)
result += IRCodeChunk(null, null).also { result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOADX, vmDt, reg1 = register, reg2 = tr.resultReg, labelSymbol = array.variable.name) it += IRInstruction(Opcode.LOADX, vmDt, reg1 = register, reg2 = indexReg, labelSymbol = array.variable.name)
it += IRInstruction(Opcode.INV, vmDt, reg1 = register) it += IRInstruction(Opcode.INV, vmDt, reg1 = register)
it += IRInstruction(Opcode.STOREX, vmDt, reg1 = register, reg2 = tr.resultReg, labelSymbol = array.variable.name) it += IRInstruction(Opcode.STOREX, vmDt, reg1 = register, reg2 = indexReg, labelSymbol = array.variable.name)
} }
} }
} }
"not" -> { "not" -> {
// TODO: in boolean branch, is 'not' handled ok like this?
val register = codeGen.registers.nextFree() val register = codeGen.registers.nextFree()
if(constIndex!=null) { if(constIndex!=null) {
// TODO: in boolean branch, is 'not' handled ok like this?
result += IRCodeChunk(null, null).also { result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOAD, vmDt, reg1=register, immediate = 1) it += IRInstruction(Opcode.LOAD, vmDt, reg1=register, immediate = 1)
it += IRInstruction(Opcode.XORM, vmDt, reg1=register, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize) it += IRInstruction(Opcode.XORM, vmDt, reg1=register, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize)
} }
} else { } else {
val tr = expressionEval.translateExpression(array.index) val indexReg = loadIndex()
addToResult(result, tr, tr.resultReg, -1)
if(eltSize>1)
result += codeGen.multiplyByConst(IRDataType.BYTE, tr.resultReg, eltSize)
result += IRCodeChunk(null, null).also { result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOADX, vmDt, reg1 = register, reg2 = tr.resultReg, labelSymbol = array.variable.name) it += IRInstruction(Opcode.LOADX, vmDt, reg1 = register, reg2 = indexReg, labelSymbol = array.variable.name)
it += IRInstruction(Opcode.XOR, vmDt, reg1 = register, immediate = 1) it += IRInstruction(Opcode.XOR, vmDt, reg1 = register, immediate = 1)
it += IRInstruction(Opcode.STOREX, vmDt, reg1 = register, reg2 = tr.resultReg, labelSymbol = array.variable.name) it += IRInstruction(Opcode.STOREX, vmDt, reg1 = register, reg2 = indexReg, labelSymbol = array.variable.name)
} }
} }
} }

View File

@ -5,43 +5,27 @@
main { main {
sub start() { sub start() {
ubyte @shared index = 1 word[3] @split @shared array = [1111,$10ff,3333]
; @(2000) = 99 txt.print_w(array[1])
; uword @shared ptr = 2000 txt.nl()
; txt.print_ub(@(2000)) txt.print_w(-array[1])
; txt.nl() txt.nl()
; @(2000) ++ array[1] = -array[1]
; @(2000) ++ txt.print_w(array[1])
; @(2000) --
; txt.print_ub(@(2000))
; txt.nl()
uword[3] @split arr
arr[1] = 9999
txt.print_uw(arr[1])
txt.nl() txt.nl()
arr[1] = arr[1]*5
cx16.r0=2222
arr[1] *= cx16.r0
arr[1] -=5
arr[1] -=index
txt.print_uw(arr[1])
txt.nl() txt.nl()
; arr[index] = 9999 ubyte @shared idx = 1
; txt.print_uw(arr[index]) txt.print_w(array[idx])
; txt.nl() txt.nl()
; arr[index] += 5 txt.print_w(-array[idx])
; arr[index] += 5 txt.nl()
; arr[index] -= 5 array[idx] = -array[idx]
; txt.print_uw(arr[index]) txt.print_w(array[idx])
; txt.nl() txt.nl()
;
; ubyte @shared xx ; ubyte @shared xx
; uword[3] ubarr ; uword[3] ubarr
; bool[3] barr ; bool[3] barr
@ -52,20 +36,20 @@ main {
; ubarr[1] = ubarr[1] <= 2 ; ubarr[1] = ubarr[1] <= 2
; ubarr[1] = ubarr[1] > 3 ; ubarr[1] = ubarr[1] > 3
; ubarr[1] = ubarr[1] >= 3 ; ubarr[1] = ubarr[1] >= 3
;
; barr[1] = barr[0] and barr[2] ; barr[1] = barr[0] and barr[2]
; barr[1] = barr[0] or barr[2] ; barr[1] = barr[0] or barr[2]
; barr[1] = barr[0] xor barr[2] ; barr[1] = barr[0] xor barr[2]
; barr[1] = not barr[0] ; barr[1] = not barr[0]
;
; ubarr[1] = 999 ; ubarr[1] = 999
; ubarr[1] = ubarr[1]==999 ; ubarr[1] = ubarr[1]==999
; txt.print_uw(ubarr[1]) ; txt.print_uw(ubarr[1])
;
; barr[1] = barr[1] and bb ; barr[1] = barr[1] and bb
; barr[1] = barr[1] or bb ; barr[1] = barr[1] or bb
; barr[1] = barr[1] xor bb ; barr[1] = barr[1] xor bb
;
; bb = bb and barr[1] ; bb = bb and barr[1]
; bb = bb or barr[1] ; bb = bb or barr[1]
; bb = bb xor barr[1] ; bb = bb xor barr[1]

View File

@ -16,7 +16,7 @@ Program to execute is not stored in the system memory, it's just a separate list
Value stack, max 128 entries of 1 byte each. Value stack, max 128 entries of 1 byte each.
Status flags: Carry, Zero, Negative. NOTE: status flags are only affected by the CMP instruction or explicit CLC/SEC, Status flags: Carry, Zero, Negative. NOTE: status flags are only affected by the CMP instruction or explicit CLC/SEC,
LOAD instructions DO affect the Z and N flags. LOAD instructions DO affect the Z and N flags.
INC/DEC instructions DO affect the Z and N flags, INC/DEC/NEG instructions DO affect the Z and N flags,
other instructions only affect Z an N flags if the value in a result register is written. other instructions only affect Z an N flags if the value in a result register is written.
See OpcodesThatSetStatusbits See OpcodesThatSetStatusbits
@ -444,6 +444,8 @@ val OpcodesThatSetStatusbitsButNotCarry = arrayOf(
Opcode.LOADX, Opcode.LOADX,
Opcode.LOADIX, Opcode.LOADIX,
Opcode.LOADR, Opcode.LOADR,
Opcode.NEG,
Opcode.NEGM,
Opcode.INC, Opcode.INC,
Opcode.INCM, Opcode.INCM,
Opcode.DEC, Opcode.DEC,
@ -456,7 +458,7 @@ val OpcodesThatSetStatusbitsButNotCarry = arrayOf(
Opcode.OR, Opcode.OR,
Opcode.XORM, Opcode.XORM,
Opcode.XORR, Opcode.XORR,
Opcode.XOR Opcode.XOR,
) )
val OpcodesThatDependOnCarry = arrayOf( val OpcodesThatDependOnCarry = arrayOf(

View File

@ -974,8 +974,16 @@ class VirtualMachine(irProgram: IRProgram) {
private fun InsNEG(i: IRInstruction) { private fun InsNEG(i: IRInstruction) {
when(i.type!!) { when(i.type!!) {
IRDataType.BYTE -> registers.setUB(i.reg1!!, (-registers.getUB(i.reg1!!).toInt()).toUByte()) IRDataType.BYTE -> {
IRDataType.WORD -> registers.setUW(i.reg1!!, (-registers.getUW(i.reg1!!).toInt()).toUShort()) val value = -registers.getUB(i.reg1!!).toInt()
registers.setUB(i.reg1!!, value.toUByte())
statusbitsNZ(value, IRDataType.BYTE)
}
IRDataType.WORD -> {
val value = -registers.getUW(i.reg1!!).toInt()
registers.setUW(i.reg1!!, value.toUShort())
statusbitsNZ(value, IRDataType.WORD)
}
IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, -registers.getFloat(i.fpReg1!!)) IRDataType.FLOAT -> registers.setFloat(i.fpReg1!!, -registers.getFloat(i.fpReg1!!))
} }
nextPc() nextPc()
@ -984,8 +992,16 @@ class VirtualMachine(irProgram: IRProgram) {
private fun InsNEGM(i: IRInstruction) { private fun InsNEGM(i: IRInstruction) {
val address = i.address!! val address = i.address!!
when(i.type!!) { when(i.type!!) {
IRDataType.BYTE -> memory.setUB(address, (-memory.getUB(address).toInt()).toUByte()) IRDataType.BYTE -> {
IRDataType.WORD -> memory.setUW(address, (-memory.getUW(address).toInt()).toUShort()) val value = -memory.getUB(address).toInt()
memory.setUB(address, value.toUByte())
statusbitsNZ(value, IRDataType.BYTE)
}
IRDataType.WORD -> {
val value = -memory.getUW(address).toInt()
memory.setUW(address, value.toUShort())
statusbitsNZ(value, IRDataType.WORD)
}
IRDataType.FLOAT -> memory.setFloat(address, -memory.getFloat(address)) IRDataType.FLOAT -> memory.setFloat(address, -memory.getFloat(address))
} }
nextPc() nextPc()