2022-09-19 16:09:56 +00:00
|
|
|
package prog8.codegen.intermediate
|
2022-08-21 15:21:29 +00:00
|
|
|
|
2024-01-22 23:56:06 +00:00
|
|
|
import com.github.michaelbull.result.Ok
|
|
|
|
import com.github.michaelbull.result.Result
|
|
|
|
import com.github.michaelbull.result.getOrElse
|
2022-08-21 15:21:29 +00:00
|
|
|
import prog8.code.ast.*
|
2024-01-24 21:36:04 +00:00
|
|
|
import prog8.code.core.*
|
2022-10-06 22:34:56 +00:00
|
|
|
import prog8.intermediate.*
|
2022-08-21 15:21:29 +00:00
|
|
|
|
2024-01-22 23:56:06 +00:00
|
|
|
|
2022-09-19 17:41:43 +00:00
|
|
|
internal class AssignmentGen(private val codeGen: IRCodeGen, private val expressionEval: ExpressionGen) {
|
2022-08-21 15:21:29 +00:00
|
|
|
|
2022-10-06 22:34:56 +00:00
|
|
|
internal fun translate(assignment: PtAssignment): IRCodeChunks {
|
2022-08-21 15:21:29 +00:00
|
|
|
if(assignment.target.children.single() is PtMachineRegister)
|
|
|
|
throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister")
|
|
|
|
|
2023-08-02 19:26:40 +00:00
|
|
|
val chunks = translateRegularAssign(assignment)
|
|
|
|
chunks.filterIsInstance<IRCodeChunk>().firstOrNull()?.appendSrcPosition(assignment.position)
|
|
|
|
return chunks
|
2022-08-21 15:21:29 +00:00
|
|
|
}
|
|
|
|
|
2023-03-13 20:53:02 +00:00
|
|
|
internal fun translate(augAssign: PtAugmentedAssign): IRCodeChunks {
|
|
|
|
if(augAssign.target.children.single() is PtMachineRegister)
|
2023-02-15 21:50:35 +00:00
|
|
|
throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister")
|
|
|
|
|
2024-01-26 22:14:12 +00:00
|
|
|
val target = augAssign.target
|
|
|
|
val targetDt = irType(target.type)
|
|
|
|
val memTarget = target.memory
|
|
|
|
val constAddress = (memTarget?.address as? PtNumber)?.number?.toInt()
|
|
|
|
val symbol = target.identifier?.name
|
|
|
|
val array = target.array
|
|
|
|
val value = augAssign.value
|
|
|
|
val signed = target.type in SignedDatatypes
|
|
|
|
val result: Result<IRCodeChunks, NotImplementedError> = when(augAssign.operator) {
|
|
|
|
"+=" -> expressionEval.operatorPlusInplace(symbol, array, constAddress, memTarget, targetDt, value)
|
|
|
|
"-=" -> expressionEval.operatorMinusInplace(symbol, array, constAddress, memTarget, targetDt, value)
|
|
|
|
"*=" -> expressionEval.operatorMultiplyInplace(symbol, array, constAddress, memTarget, targetDt, value)
|
|
|
|
"/=" -> expressionEval.operatorDivideInplace(symbol, array, constAddress, memTarget, targetDt, value, signed)
|
|
|
|
"|=" -> expressionEval.operatorOrInplace(symbol, array, constAddress, memTarget, targetDt, value)
|
|
|
|
"or=" -> expressionEval.operatorLogicalOrInplace(symbol, array, constAddress, memTarget, targetDt, value)
|
|
|
|
"&=" -> expressionEval.operatorAndInplace(symbol, array, constAddress, memTarget, targetDt, value)
|
|
|
|
"and=" -> expressionEval.operatorLogicalAndInplace(symbol, array, constAddress, memTarget, targetDt, value)
|
|
|
|
"^=", "xor=" -> expressionEval.operatorXorInplace(symbol, array, constAddress, memTarget, targetDt, value)
|
|
|
|
"<<=" -> expressionEval.operatorShiftLeftInplace(symbol, array, constAddress, memTarget, targetDt, value)
|
|
|
|
">>=" -> expressionEval.operatorShiftRightInplace(symbol, array, constAddress, memTarget, targetDt, value, signed)
|
|
|
|
"%=" -> expressionEval.operatorModuloInplace(symbol, array, constAddress, memTarget, targetDt, value)
|
|
|
|
"==" -> expressionEval.operatorEqualsInplace(symbol, array, constAddress, memTarget, targetDt, value)
|
|
|
|
"!=" -> expressionEval.operatorNotEqualsInplace(symbol, array, constAddress, memTarget, targetDt, value)
|
|
|
|
"<" -> expressionEval.operatorLessInplace(symbol, array, constAddress, memTarget, targetDt, value, signed)
|
|
|
|
">" -> expressionEval.operatorGreaterInplace(symbol, array, constAddress, memTarget, targetDt, value, signed)
|
|
|
|
"<=" -> expressionEval.operatorLessEqualInplace(symbol, array, constAddress, memTarget, targetDt, value, signed)
|
|
|
|
">=" -> expressionEval.operatorGreaterEqualInplace(symbol, array, constAddress, memTarget, targetDt, value, signed)
|
|
|
|
in PrefixOperators -> inplacePrefix(augAssign.operator, symbol, array, constAddress, memTarget, targetDt)
|
|
|
|
|
|
|
|
else -> throw AssemblyError("invalid augmented assign operator ${augAssign.operator}")
|
2022-08-21 15:21:29 +00:00
|
|
|
}
|
2024-01-26 22:14:12 +00:00
|
|
|
|
|
|
|
val chunks = result.getOrElse { fallbackAssign(augAssign) }
|
2023-08-02 19:26:40 +00:00
|
|
|
chunks.filterIsInstance<IRCodeChunk>().firstOrNull()?.appendSrcPosition(augAssign.position)
|
|
|
|
return chunks
|
2022-08-21 15:21:29 +00:00
|
|
|
}
|
|
|
|
|
2023-02-15 21:50:35 +00:00
|
|
|
private fun fallbackAssign(origAssign: PtAugmentedAssign): IRCodeChunks {
|
|
|
|
val value: PtExpression
|
|
|
|
if(origAssign.operator in PrefixOperators) {
|
2024-01-24 21:36:04 +00:00
|
|
|
value = PtPrefix(origAssign.operator, origAssign.value.type, origAssign.value.position)
|
2023-02-15 21:50:35 +00:00
|
|
|
value.add(origAssign.value)
|
2022-09-14 23:32:48 +00:00
|
|
|
} else {
|
2024-01-24 21:36:04 +00:00
|
|
|
val operator = when(origAssign.operator) {
|
|
|
|
in ComparisonOperators -> origAssign.operator
|
|
|
|
else -> {
|
|
|
|
require(origAssign.operator.endsWith('='))
|
|
|
|
origAssign.operator.dropLast(1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
value = PtBinaryExpression(operator, origAssign.value.type, origAssign.value.position)
|
2023-07-02 13:26:04 +00:00
|
|
|
val left: PtExpression = origAssign.target.children.single() as PtExpression
|
|
|
|
value.add(left)
|
|
|
|
value.add(origAssign.value)
|
2022-08-21 15:21:29 +00:00
|
|
|
}
|
2023-03-31 21:55:24 +00:00
|
|
|
val normalAssign = PtAssignment(origAssign.position)
|
|
|
|
normalAssign.add(origAssign.target)
|
2023-02-15 21:50:35 +00:00
|
|
|
normalAssign.add(value)
|
|
|
|
return translateRegularAssign(normalAssign)
|
2022-08-21 15:21:29 +00:00
|
|
|
}
|
|
|
|
|
2024-01-26 22:14:12 +00:00
|
|
|
private fun inplacePrefix(operator: String, symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType): Result<IRCodeChunks, NotImplementedError> {
|
|
|
|
if(operator=="+")
|
|
|
|
return Ok(emptyList())
|
|
|
|
|
|
|
|
if(array!=null)
|
|
|
|
return Ok(inplacePrefixArray(operator, array))
|
|
|
|
|
|
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
|
|
if(constAddress==null && memory!=null) {
|
|
|
|
val register = codeGen.registers.nextFree()
|
|
|
|
val tr = expressionEval.translateExpression(memory.address)
|
|
|
|
addToResult(result, tr, tr.resultReg, -1)
|
|
|
|
when(operator) {
|
|
|
|
"-" -> {
|
|
|
|
result += IRCodeChunk(null, null).also {
|
|
|
|
it += IRInstruction(Opcode.LOADI, vmDt, reg1=register, reg2=tr.resultReg)
|
|
|
|
it += IRInstruction(Opcode.NEG, vmDt, reg1=register)
|
|
|
|
it += IRInstruction(Opcode.STOREI, vmDt, reg1=register, reg2=tr.resultReg)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"~" -> {
|
|
|
|
result += IRCodeChunk(null, null).also {
|
|
|
|
it += IRInstruction(Opcode.LOADI, vmDt, reg1=register, reg2=tr.resultReg)
|
|
|
|
it += IRInstruction(Opcode.INV, vmDt, reg1=register)
|
|
|
|
it += IRInstruction(Opcode.STOREI, vmDt, reg1=register, reg2=tr.resultReg)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
when (operator) {
|
|
|
|
"-" -> addInstr(result, IRInstruction(Opcode.NEGM, vmDt, address = constAddress, labelSymbol = symbol), null)
|
|
|
|
"~" -> addInstr(result, IRInstruction(Opcode.INVM, vmDt, address = constAddress, labelSymbol = symbol), null)
|
|
|
|
// TODO: in boolean branch, how is 'not' handled here?
|
|
|
|
else -> throw AssemblyError("weird prefix operator")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Ok(result)
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun inplacePrefixArray(operator: String, array: PtArrayIndexer): IRCodeChunks {
|
|
|
|
val eltSize = codeGen.program.memsizer.memorySize(array.type)
|
2024-01-22 23:56:06 +00:00
|
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
|
|
|
val vmDt = irType(array.type)
|
|
|
|
val constIndex = array.index.asConstInteger()
|
2024-01-25 23:12:04 +00:00
|
|
|
|
|
|
|
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")
|
|
|
|
}
|
2024-01-26 22:14:12 +00:00
|
|
|
return result
|
2024-01-25 23:12:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// normal array.
|
|
|
|
|
2024-01-22 23:56:06 +00:00
|
|
|
when(operator) {
|
|
|
|
"+" -> { }
|
|
|
|
"-" -> {
|
|
|
|
if(constIndex!=null) {
|
|
|
|
addInstr(result, IRInstruction(Opcode.NEGM, vmDt, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize), null)
|
|
|
|
} else {
|
2024-01-25 23:12:04 +00:00
|
|
|
val indexReg = loadIndex()
|
2024-01-22 23:56:06 +00:00
|
|
|
val register = codeGen.registers.nextFree()
|
|
|
|
result += IRCodeChunk(null, null).also {
|
2024-01-25 23:12:04 +00:00
|
|
|
it += IRInstruction(Opcode.LOADX, vmDt, reg1 = register, reg2 = indexReg, labelSymbol = array.variable.name)
|
2024-01-22 23:56:06 +00:00
|
|
|
it += IRInstruction(Opcode.NEG, vmDt, reg1 = register)
|
2024-01-25 23:12:04 +00:00
|
|
|
it += IRInstruction(Opcode.STOREX, vmDt, reg1 = register, reg2 = indexReg, labelSymbol = array.variable.name)
|
2024-01-22 23:56:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"~" -> {
|
|
|
|
if(constIndex!=null) {
|
|
|
|
addInstr(result, IRInstruction(Opcode.INVM, vmDt, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize), null)
|
|
|
|
} else {
|
2024-01-25 23:12:04 +00:00
|
|
|
val indexReg = loadIndex()
|
2024-01-22 23:56:06 +00:00
|
|
|
val register = codeGen.registers.nextFree()
|
|
|
|
result += IRCodeChunk(null, null).also {
|
2024-01-25 23:12:04 +00:00
|
|
|
it += IRInstruction(Opcode.LOADX, vmDt, reg1 = register, reg2 = indexReg, labelSymbol = array.variable.name)
|
2024-01-22 23:56:06 +00:00
|
|
|
it += IRInstruction(Opcode.INV, vmDt, reg1 = register)
|
2024-01-25 23:12:04 +00:00
|
|
|
it += IRInstruction(Opcode.STOREX, vmDt, reg1 = register, reg2 = indexReg, labelSymbol = array.variable.name)
|
2024-01-22 23:56:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"not" -> {
|
2024-01-25 23:12:04 +00:00
|
|
|
// TODO: in boolean branch, is 'not' handled ok like this?
|
2024-01-22 23:56:06 +00:00
|
|
|
val register = codeGen.registers.nextFree()
|
|
|
|
if(constIndex!=null) {
|
|
|
|
result += IRCodeChunk(null, null).also {
|
|
|
|
it += IRInstruction(Opcode.LOAD, vmDt, reg1=register, immediate = 1)
|
|
|
|
it += IRInstruction(Opcode.XORM, vmDt, reg1=register, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize)
|
|
|
|
}
|
|
|
|
} else {
|
2024-01-25 23:12:04 +00:00
|
|
|
val indexReg = loadIndex()
|
2024-01-22 23:56:06 +00:00
|
|
|
result += IRCodeChunk(null, null).also {
|
2024-01-25 23:12:04 +00:00
|
|
|
it += IRInstruction(Opcode.LOADX, vmDt, reg1 = register, reg2 = indexReg, labelSymbol = array.variable.name)
|
2024-01-22 23:56:06 +00:00
|
|
|
it += IRInstruction(Opcode.XOR, vmDt, reg1 = register, immediate = 1)
|
2024-01-25 23:12:04 +00:00
|
|
|
it += IRInstruction(Opcode.STOREX, vmDt, reg1 = register, reg2 = indexReg, labelSymbol = array.variable.name)
|
2024-01-22 23:56:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else -> throw AssemblyError("weird prefix operator")
|
|
|
|
}
|
2024-01-26 22:14:12 +00:00
|
|
|
return result
|
2022-08-21 15:21:29 +00:00
|
|
|
}
|
|
|
|
|
2022-10-06 22:34:56 +00:00
|
|
|
private fun translateRegularAssign(assignment: PtAssignment): IRCodeChunks {
|
2022-08-21 15:21:29 +00:00
|
|
|
// note: assigning array and string values is done via an explicit memcopy/stringcopy function call.
|
2023-03-13 20:53:02 +00:00
|
|
|
val targetIdent = assignment.target.identifier
|
|
|
|
val targetMemory = assignment.target.memory
|
|
|
|
val targetArray = assignment.target.array
|
2023-05-08 21:15:30 +00:00
|
|
|
val valueDt = irType(assignment.value.type)
|
|
|
|
val targetDt = irType(assignment.target.type)
|
2022-10-06 22:34:56 +00:00
|
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
2023-03-13 20:53:02 +00:00
|
|
|
|
|
|
|
var valueRegister = -1
|
|
|
|
var valueFpRegister = -1
|
2022-08-21 15:21:29 +00:00
|
|
|
val zero = codeGen.isZero(assignment.value)
|
|
|
|
if(!zero) {
|
|
|
|
// calculate the assignment value
|
2023-05-08 20:26:22 +00:00
|
|
|
if (valueDt == IRDataType.FLOAT) {
|
2023-03-13 01:21:58 +00:00
|
|
|
val tr = expressionEval.translateExpression(assignment.value)
|
2023-03-13 20:53:02 +00:00
|
|
|
valueFpRegister = tr.resultFpReg
|
|
|
|
addToResult(result, tr, -1, valueFpRegister)
|
2022-08-21 15:21:29 +00:00
|
|
|
} else {
|
2023-05-08 20:26:22 +00:00
|
|
|
val extendByteToWord = if(targetDt != valueDt) {
|
|
|
|
// usually an error EXCEPT when a byte is assigned to a word.
|
|
|
|
if(targetDt==IRDataType.WORD && valueDt==IRDataType.BYTE)
|
|
|
|
true
|
|
|
|
else
|
|
|
|
throw AssemblyError("assignment value and target dt mismatch")
|
|
|
|
} else false
|
2023-03-13 20:53:02 +00:00
|
|
|
if (assignment.value is PtMachineRegister) {
|
|
|
|
valueRegister = (assignment.value as PtMachineRegister).register
|
2023-07-08 20:42:11 +00:00
|
|
|
if(extendByteToWord) {
|
|
|
|
valueRegister = codeGen.registers.nextFree()
|
|
|
|
addInstr(result, IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1=valueRegister, reg2=(assignment.value as PtMachineRegister).register), null)
|
|
|
|
}
|
2022-08-21 15:21:29 +00:00
|
|
|
} else {
|
2023-03-13 01:21:58 +00:00
|
|
|
val tr = expressionEval.translateExpression(assignment.value)
|
2023-03-13 20:53:02 +00:00
|
|
|
valueRegister = tr.resultReg
|
|
|
|
addToResult(result, tr, valueRegister, -1)
|
2023-05-08 20:26:22 +00:00
|
|
|
if(extendByteToWord) {
|
2023-07-08 20:42:11 +00:00
|
|
|
valueRegister = codeGen.registers.nextFree()
|
2023-05-08 20:26:22 +00:00
|
|
|
val opcode = if(assignment.value.type in SignedDatatypes) Opcode.EXTS else Opcode.EXT
|
2023-07-08 20:42:11 +00:00
|
|
|
addInstr(result, IRInstruction(opcode, IRDataType.BYTE, reg1=valueRegister, reg2=tr.resultReg), null)
|
2023-05-08 20:26:22 +00:00
|
|
|
}
|
2022-08-21 15:21:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-03-13 20:53:02 +00:00
|
|
|
|
|
|
|
if(targetIdent!=null) {
|
2022-10-06 22:34:56 +00:00
|
|
|
val instruction = if(zero) {
|
2023-05-08 20:26:22 +00:00
|
|
|
IRInstruction(Opcode.STOREZM, targetDt, labelSymbol = targetIdent.name)
|
2022-08-21 15:21:29 +00:00
|
|
|
} else {
|
2023-05-08 20:26:22 +00:00
|
|
|
if (targetDt == IRDataType.FLOAT)
|
|
|
|
IRInstruction(Opcode.STOREM, targetDt, fpReg1 = valueFpRegister, labelSymbol = targetIdent.name)
|
2022-08-21 15:21:29 +00:00
|
|
|
else
|
2023-05-08 20:26:22 +00:00
|
|
|
IRInstruction(Opcode.STOREM, targetDt, reg1 = valueRegister, labelSymbol = targetIdent.name)
|
2022-08-21 15:21:29 +00:00
|
|
|
}
|
2022-11-02 21:12:42 +00:00
|
|
|
result += IRCodeChunk(null, null).also { it += instruction }
|
2022-10-06 22:34:56 +00:00
|
|
|
return result
|
2022-08-21 15:21:29 +00:00
|
|
|
}
|
2023-03-13 20:53:02 +00:00
|
|
|
else if(targetArray!=null) {
|
|
|
|
val variable = targetArray.variable.name
|
|
|
|
val itemsize = codeGen.program.memsizer.memorySize(targetArray.type)
|
2022-08-21 15:21:29 +00:00
|
|
|
|
2023-03-13 20:53:02 +00:00
|
|
|
val fixedIndex = constIntValue(targetArray.index)
|
2023-07-07 13:43:09 +00:00
|
|
|
val arrayLength = codeGen.symbolTable.getLength(targetArray.variable.name)
|
2022-08-21 15:21:29 +00:00
|
|
|
if(zero) {
|
|
|
|
if(fixedIndex!=null) {
|
2023-05-26 20:56:12 +00:00
|
|
|
val chunk = IRCodeChunk(null, null).also {
|
2023-06-02 21:39:57 +00:00
|
|
|
if(targetArray.splitWords) {
|
2024-01-13 12:55:16 +00:00
|
|
|
it += IRInstruction(Opcode.STOREZM, IRDataType.BYTE, immediate = arrayLength, labelSymbol = "${variable}_lsb", symbolOffset = fixedIndex)
|
|
|
|
it += IRInstruction(Opcode.STOREZM, IRDataType.BYTE, immediate = arrayLength, labelSymbol = "${variable}_msb", symbolOffset = fixedIndex)
|
2023-06-02 21:39:57 +00:00
|
|
|
}
|
2023-05-26 20:56:12 +00:00
|
|
|
else
|
2024-01-13 12:55:16 +00:00
|
|
|
it += IRInstruction(Opcode.STOREZM, targetDt, labelSymbol = variable, symbolOffset = fixedIndex*itemsize)
|
2023-05-26 20:56:12 +00:00
|
|
|
}
|
2022-10-06 22:34:56 +00:00
|
|
|
result += chunk
|
2022-08-21 15:21:29 +00:00
|
|
|
} else {
|
2023-03-14 00:12:52 +00:00
|
|
|
val (code, indexReg) = loadIndexReg(targetArray, itemsize)
|
|
|
|
result += code
|
2023-05-26 20:56:12 +00:00
|
|
|
result += IRCodeChunk(null, null).also {
|
2023-06-02 21:39:57 +00:00
|
|
|
if(targetArray.splitWords) {
|
|
|
|
it += IRInstruction(Opcode.STOREZX, IRDataType.BYTE, reg1 = indexReg, immediate = arrayLength, labelSymbol = variable+"_lsb")
|
|
|
|
it += IRInstruction(Opcode.STOREZX, IRDataType.BYTE, reg1 = indexReg, immediate = arrayLength, labelSymbol = variable+"_msb")
|
|
|
|
}
|
2023-05-26 20:56:12 +00:00
|
|
|
else
|
2023-06-02 21:39:57 +00:00
|
|
|
it += IRInstruction(Opcode.STOREZX, targetDt, reg1=indexReg, labelSymbol = variable)
|
2023-05-26 20:56:12 +00:00
|
|
|
}
|
2022-08-21 15:21:29 +00:00
|
|
|
}
|
|
|
|
} else {
|
2023-05-08 20:26:22 +00:00
|
|
|
if(targetDt== IRDataType.FLOAT) {
|
2022-08-21 15:21:29 +00:00
|
|
|
if(fixedIndex!=null) {
|
2022-09-14 23:32:48 +00:00
|
|
|
val offset = fixedIndex*itemsize
|
2023-05-26 20:56:12 +00:00
|
|
|
val chunk = IRCodeChunk(null, null).also {
|
2024-01-13 12:55:16 +00:00
|
|
|
it += IRInstruction(Opcode.STOREM, targetDt, fpReg1 = valueFpRegister, labelSymbol = variable, symbolOffset = offset)
|
2023-05-26 20:56:12 +00:00
|
|
|
}
|
2022-10-06 22:34:56 +00:00
|
|
|
result += chunk
|
2022-08-21 15:21:29 +00:00
|
|
|
} else {
|
2023-03-14 00:12:52 +00:00
|
|
|
val (code, indexReg) = loadIndexReg(targetArray, itemsize)
|
|
|
|
result += code
|
2023-05-26 20:56:12 +00:00
|
|
|
result += IRCodeChunk(null, null).also {
|
|
|
|
it += IRInstruction(Opcode.STOREX, targetDt, reg1 = indexReg, fpReg1 = valueFpRegister, labelSymbol = variable)
|
|
|
|
}
|
2022-08-21 15:21:29 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if(fixedIndex!=null) {
|
2023-05-26 20:56:12 +00:00
|
|
|
val chunk = IRCodeChunk(null, null).also {
|
2023-06-02 21:39:57 +00:00
|
|
|
if(targetArray.splitWords) {
|
|
|
|
val msbReg = codeGen.registers.nextFree()
|
2024-01-13 12:55:16 +00:00
|
|
|
it += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1 = valueRegister, immediate = arrayLength, labelSymbol = "${variable}_lsb", symbolOffset = fixedIndex)
|
2023-06-02 21:39:57 +00:00
|
|
|
it += IRInstruction(Opcode.MSIG, IRDataType.BYTE, reg1 = msbReg, reg2 = valueRegister)
|
2024-01-13 12:55:16 +00:00
|
|
|
it += IRInstruction(Opcode.STOREM, IRDataType.BYTE, reg1 = msbReg, immediate = arrayLength, labelSymbol = "${variable}_msb", symbolOffset = fixedIndex)
|
2023-06-02 21:39:57 +00:00
|
|
|
}
|
2023-05-26 20:56:12 +00:00
|
|
|
else
|
2024-01-13 12:55:16 +00:00
|
|
|
it += IRInstruction(Opcode.STOREM, targetDt, reg1 = valueRegister, labelSymbol = variable, symbolOffset = fixedIndex*itemsize)
|
2023-05-26 20:56:12 +00:00
|
|
|
}
|
2022-10-06 22:34:56 +00:00
|
|
|
result += chunk
|
2022-08-21 15:21:29 +00:00
|
|
|
} else {
|
2023-03-14 00:12:52 +00:00
|
|
|
val (code, indexReg) = loadIndexReg(targetArray, itemsize)
|
|
|
|
result += code
|
2023-05-26 20:56:12 +00:00
|
|
|
result += IRCodeChunk(null, null).also {
|
2023-06-02 21:39:57 +00:00
|
|
|
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")
|
|
|
|
}
|
2023-05-26 20:56:12 +00:00
|
|
|
else
|
2023-06-02 21:39:57 +00:00
|
|
|
it += IRInstruction(Opcode.STOREX, targetDt, reg1 = valueRegister, reg2=indexReg, labelSymbol = variable)
|
2023-05-26 20:56:12 +00:00
|
|
|
}
|
2022-08-21 15:21:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-10-06 22:34:56 +00:00
|
|
|
return result
|
2022-08-21 15:21:29 +00:00
|
|
|
}
|
2023-03-13 20:53:02 +00:00
|
|
|
else if(targetMemory!=null) {
|
2023-05-08 20:26:22 +00:00
|
|
|
require(targetDt == IRDataType.BYTE) { "must be byte type ${targetMemory.position}"}
|
2022-08-21 15:21:29 +00:00
|
|
|
if(zero) {
|
2023-03-13 20:53:02 +00:00
|
|
|
if(targetMemory.address is PtNumber) {
|
2023-05-08 20:26:22 +00:00
|
|
|
val chunk = IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREZM, targetDt, address = (targetMemory.address as PtNumber).number.toInt()) }
|
2022-10-06 22:34:56 +00:00
|
|
|
result += chunk
|
2022-08-21 15:21:29 +00:00
|
|
|
} else {
|
2023-03-13 20:53:02 +00:00
|
|
|
val tr = expressionEval.translateExpression(targetMemory.address)
|
|
|
|
val addressReg = tr.resultReg
|
2023-03-13 03:16:50 +00:00
|
|
|
addToResult(result, tr, tr.resultReg, -1)
|
2023-05-08 20:26:22 +00:00
|
|
|
result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREZI, targetDt, reg1=addressReg) }
|
2022-08-21 15:21:29 +00:00
|
|
|
}
|
|
|
|
} else {
|
2023-03-13 20:53:02 +00:00
|
|
|
if(targetMemory.address is PtNumber) {
|
2023-05-08 20:26:22 +00:00
|
|
|
val chunk = IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREM, targetDt, reg1=valueRegister, address=(targetMemory.address as PtNumber).number.toInt()) }
|
2022-10-06 22:34:56 +00:00
|
|
|
result += chunk
|
2022-08-21 15:21:29 +00:00
|
|
|
} else {
|
2023-03-13 20:53:02 +00:00
|
|
|
val tr = expressionEval.translateExpression(targetMemory.address)
|
|
|
|
val addressReg = tr.resultReg
|
2023-03-13 03:16:50 +00:00
|
|
|
addToResult(result, tr, tr.resultReg, -1)
|
2023-05-08 20:26:22 +00:00
|
|
|
result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREI, targetDt, reg1=valueRegister, reg2=addressReg) }
|
2022-08-21 15:21:29 +00:00
|
|
|
}
|
|
|
|
}
|
2022-10-06 22:34:56 +00:00
|
|
|
|
|
|
|
return result
|
2022-08-21 15:21:29 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
throw AssemblyError("weird assigntarget")
|
|
|
|
}
|
|
|
|
|
2023-03-14 00:12:52 +00:00
|
|
|
private fun loadIndexReg(array: PtArrayIndexer, itemsize: Int): Pair<IRCodeChunks, Int> {
|
2023-05-26 20:56:12 +00:00
|
|
|
// returns the code to load the Index into the register, which is also returned.
|
2023-03-31 21:55:24 +00:00
|
|
|
|
2023-04-03 01:13:35 +00:00
|
|
|
val result = mutableListOf<IRCodeChunkBase>()
|
2023-05-26 20:56:12 +00:00
|
|
|
if(itemsize==1 || array.splitWords) {
|
2023-04-03 01:13:35 +00:00
|
|
|
val tr = expressionEval.translateExpression(array.index)
|
|
|
|
addToResult(result, tr, tr.resultReg, -1)
|
|
|
|
return Pair(result, tr.resultReg)
|
2023-03-31 21:55:24 +00:00
|
|
|
}
|
|
|
|
|
2023-07-02 13:26:04 +00:00
|
|
|
val mult: PtExpression
|
|
|
|
mult = PtBinaryExpression("*", DataType.UBYTE, array.position)
|
|
|
|
mult.children += array.index
|
|
|
|
mult.children += PtNumber(DataType.UBYTE, itemsize.toDouble(), array.position)
|
|
|
|
val tr = expressionEval.translateExpression(mult)
|
|
|
|
addToResult(result, tr, tr.resultReg, -1)
|
|
|
|
return Pair(result, tr.resultReg)
|
2022-08-21 15:21:29 +00:00
|
|
|
}
|
|
|
|
}
|