IR: optimize pointer access

This commit is contained in:
Irmen de Jong 2024-02-04 07:34:16 +01:00
parent 8e00408e3e
commit 3c77f8a020
5 changed files with 137 additions and 48 deletions

View File

@ -383,18 +383,47 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
val tr = expressionEval.translateExpression(targetMemory.address)
val addressReg = tr.resultReg
addToResult(result, tr, tr.resultReg, -1)
result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREZI, targetDt, reg1=addressReg) }
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.STOREZI, targetDt, reg1=addressReg)
}
}
} else {
if(targetMemory.address is PtNumber) {
val chunk = IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREM, targetDt, reg1=valueRegister, address=(targetMemory.address as PtNumber).number.toInt()) }
result += chunk
} else {
val constAddress = targetMemory.address as? PtNumber
if(constAddress!=null) {
addInstr(result, IRInstruction(Opcode.STOREM, targetDt, reg1=valueRegister, address=constAddress.number.toInt()), null)
return result
}
val ptrWithOffset = targetMemory.address as? PtBinaryExpression
if(ptrWithOffset!=null && ptrWithOffset.operator=="+" && ptrWithOffset.left is PtIdentifier) {
if((ptrWithOffset.right as? PtNumber)?.number?.toInt() in 0..255) {
// STOREIX only works with byte index.
val ptrName = (ptrWithOffset.left as PtIdentifier).name
val offsetReg = codeGen.registers.nextFree()
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=offsetReg, immediate = ptrWithOffset.right.asConstInteger())
it += IRInstruction(Opcode.STOREIX, IRDataType.BYTE, reg1=valueRegister, reg2=offsetReg, labelSymbol = ptrName)
}
return result
}
}
val offsetTypecast = ptrWithOffset?.right as? PtTypeCast
if(ptrWithOffset!=null && ptrWithOffset.operator=="+" && ptrWithOffset.left is PtIdentifier
&& (ptrWithOffset.right.type in ByteDatatypes || offsetTypecast?.value?.type in ByteDatatypes)) {
// STOREIX only works with byte index.
val tr = if(offsetTypecast?.value?.type in ByteDatatypes)
expressionEval.translateExpression(offsetTypecast!!.value)
else
expressionEval.translateExpression(ptrWithOffset.right)
addToResult(result, tr, tr.resultReg, -1)
val ptrName = (ptrWithOffset.left as PtIdentifier).name
addInstr(result, IRInstruction(Opcode.STOREIX, IRDataType.BYTE, reg1=valueRegister, reg2=tr.resultReg, labelSymbol = ptrName), null)
return result
}
val tr = expressionEval.translateExpression(targetMemory.address)
val addressReg = tr.resultReg
addToResult(result, tr, tr.resultReg, -1)
result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREI, targetDt, reg1=valueRegister, reg2=addressReg) }
}
addInstr(result, IRInstruction(Opcode.STOREI, targetDt, reg1=valueRegister, reg2=addressReg), null)
return result
}
return result

View File

@ -93,21 +93,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
}
ExpressionCodeResult(result, vmDt, resultRegister, -1)
}
is PtMemoryByte -> {
val result = mutableListOf<IRCodeChunkBase>()
if(expr.address is PtNumber) {
val address = (expr.address as PtNumber).number.toInt()
val resultRegister = codeGen.registers.nextFree()
addInstr(result, IRInstruction(Opcode.LOADM, IRDataType.BYTE, reg1=resultRegister, address = address), null)
ExpressionCodeResult(result, IRDataType.BYTE, resultRegister, -1)
} else {
val tr = translateExpression(expr.address)
addToResult(result, tr, tr.resultReg, -1)
val resultReg = codeGen.registers.nextFree()
addInstr(result, IRInstruction(Opcode.LOADI, IRDataType.BYTE, reg1=resultReg, reg2=tr.resultReg), null)
ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1)
}
}
is PtMemoryByte -> translate(expr)
is PtTypeCast -> translate(expr)
is PtPrefix -> translate(expr)
is PtArrayIndexer -> translate(expr)
@ -122,6 +108,49 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
}
}
private fun translate(mem: PtMemoryByte): ExpressionCodeResult {
val result = mutableListOf<IRCodeChunkBase>()
val resultRegister = codeGen.registers.nextFree()
val constAddress = mem.address as? PtNumber
if(constAddress!=null) {
addInstr(result, IRInstruction(Opcode.LOADM, IRDataType.BYTE, reg1=resultRegister, address = constAddress.number.toInt()), null)
return ExpressionCodeResult(result, IRDataType.BYTE, resultRegister, -1)
}
val ptrWithOffset = mem.address as? PtBinaryExpression
if(ptrWithOffset!=null && ptrWithOffset.operator=="+" && ptrWithOffset.left is PtIdentifier) {
if((ptrWithOffset.right as? PtNumber)?.number?.toInt() in 0..255) {
// LOADIX only works with byte index.
val ptrName = (ptrWithOffset.left as PtIdentifier).name
val offsetReg = codeGen.registers.nextFree()
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=offsetReg, immediate = ptrWithOffset.right.asConstInteger())
it += IRInstruction(Opcode.LOADIX, IRDataType.BYTE, reg1=resultRegister, reg2=offsetReg, labelSymbol = ptrName)
}
return ExpressionCodeResult(result, IRDataType.BYTE, resultRegister, -1)
}
}
val offsetTypecast = ptrWithOffset?.right as? PtTypeCast
if(ptrWithOffset!=null && ptrWithOffset.operator=="+" && ptrWithOffset.left is PtIdentifier
&& (ptrWithOffset.right.type in ByteDatatypes || offsetTypecast?.value?.type in ByteDatatypes)) {
// LOADIX only works with byte index.
val tr = if(offsetTypecast?.value?.type in ByteDatatypes)
translateExpression(offsetTypecast!!.value)
else
translateExpression(ptrWithOffset.right)
addToResult(result, tr, tr.resultReg, -1)
val ptrName = (ptrWithOffset.left as PtIdentifier).name
addInstr(result, IRInstruction(Opcode.LOADIX, IRDataType.BYTE, reg1=resultRegister, reg2=tr.resultReg, labelSymbol = ptrName), null)
return ExpressionCodeResult(result, IRDataType.BYTE, resultRegister, -1)
}
val tr = translateExpression(mem.address)
addToResult(result, tr, tr.resultReg, -1)
addInstr(result, IRInstruction(Opcode.LOADI, IRDataType.BYTE, reg1=resultRegister, reg2=tr.resultReg), null)
return ExpressionCodeResult(result, IRDataType.BYTE, resultRegister, -1)
}
private fun translate(check: PtContainmentCheck): ExpressionCodeResult {
val result = mutableListOf<IRCodeChunkBase>()
when(check.iterable.type) {

View File

@ -1516,10 +1516,45 @@ class IRCodeGen(
if(ident!=null) {
addInstr(result, IRInstruction(operationMem, irDt, labelSymbol = ident.name), null)
} else if(memory!=null) {
if(memory.address is PtNumber) {
val address = (memory.address as PtNumber).number.toInt()
addInstr(result, IRInstruction(operationMem, irDt, address = address), null)
} else {
val constAddress = memory.address as? PtNumber
if(constAddress!=null) {
addInstr(result, IRInstruction(operationMem, irDt, address = constAddress.number.toInt()), null)
return result
}
val ptrWithOffset = memory.address as? PtBinaryExpression
if(ptrWithOffset!=null && ptrWithOffset.operator=="+" && ptrWithOffset.left is PtIdentifier) {
if((ptrWithOffset.right as? PtNumber)?.number?.toInt() in 0..255) {
// LOADIX only works with byte index.
val ptrName = (ptrWithOffset.left as PtIdentifier).name
val offsetReg = registers.nextFree()
val incReg = registers.nextFree()
result += IRCodeChunk(null, null).also {
it += IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=offsetReg, immediate = ptrWithOffset.right.asConstInteger())
it += IRInstruction(Opcode.LOADIX, IRDataType.BYTE, reg1=incReg, reg2=offsetReg, labelSymbol = ptrName)
it += IRInstruction(operationRegister, irDt, reg1 = incReg)
it += IRInstruction(Opcode.STOREIX, IRDataType.BYTE, reg1=incReg, reg2=offsetReg, labelSymbol = ptrName)
}
return result
}
}
val offsetTypecast = ptrWithOffset?.right as? PtTypeCast
if(ptrWithOffset!=null && ptrWithOffset.operator=="+" && ptrWithOffset.left is PtIdentifier
&& (ptrWithOffset.right.type in ByteDatatypes || offsetTypecast?.value?.type in ByteDatatypes)) {
// LOADIX only works with byte index.
val tr = if(offsetTypecast?.value?.type in ByteDatatypes)
expressionEval.translateExpression(offsetTypecast!!.value)
else
expressionEval.translateExpression(ptrWithOffset.right)
addToResult(result, tr, tr.resultReg, -1)
val ptrName = (ptrWithOffset.left as PtIdentifier).name
result += IRCodeChunk(null, null).also {
val incReg = registers.nextFree()
it += IRInstruction(Opcode.LOADIX, IRDataType.BYTE, reg1=incReg, reg2=tr.resultReg, labelSymbol = ptrName)
it += IRInstruction(operationRegister, irDt, reg1 = incReg)
it += IRInstruction(Opcode.STOREIX, IRDataType.BYTE, reg1=incReg, reg2=tr.resultReg, labelSymbol = ptrName)
}
return result
}
val tr = expressionEval.translateExpression(memory.address)
addToResult(result, tr, tr.resultReg, -1)
result += IRCodeChunk(null, null).also {
@ -1528,7 +1563,7 @@ class IRCodeGen(
it += IRInstruction(operationRegister, irDt, reg1 = incReg)
it += IRInstruction(Opcode.STOREI, irDt, reg1 = incReg, reg2 = tr.resultReg)
}
}
return result
} else if (array!=null) {
val variable = array.variable.name
val itemsize = program.memsizer.memorySize(array.type)

View File

@ -1,8 +1,6 @@
TODO
====
VM textelite is now a lot larger due to the ptr[i] -> @(ptr+i) rewrite. Fix this.
(after merge in boolean): move all "OperatorXinplace" from expressionGen to AssignmentGen, see if we can get rid of the Result return type.
...

View File

@ -11,9 +11,16 @@ main {
uword @shared az = $4000
ubyte @shared value = 22
cx16.r0H = value*4 + az[value]
cx16.r0L = az[value] + value*4
az[20] = 99
az[2000] = 99
az[value] = 99
az[cx16.r0] = 99
; cx16.r0L = az[200]
; cx16.r1L = az[2000]
; cx16.r0L = az[value]
; cx16.r0H = value*4 + az[value]
; cx16.r0L = az[value] + value*4
;
; @($4004) = 99
; az[4]--
; @(az + offset)--
@ -26,15 +33,6 @@ main {
; cx16.r0L = az[4] + value*5
; cx16.r1L = value*5 + az[4]
; ubyte @shared idx = 1
; txt.print_w(array[idx])
; txt.nl()
; txt.print_w(-array[idx])
; txt.nl()
; array[idx] = -array[idx]
; txt.print_w(array[idx])
; txt.nl()
;
; ubyte @shared xx
; ubyte[3] ubarr