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.*
|
2022-08-27 11:06:44 +00:00
|
|
|
import prog8.code.core.AssemblyError
|
|
|
|
import prog8.code.core.DataType
|
2023-02-15 21:50:35 +00:00
|
|
|
import prog8.code.core.PrefixOperators
|
2022-08-27 11:06:44 +00:00
|
|
|
import prog8.code.core.SignedDatatypes
|
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")
|
|
|
|
|
2023-03-13 20:53:02 +00:00
|
|
|
val ident = augAssign.target.identifier
|
|
|
|
val memory = augAssign.target.memory
|
|
|
|
val array = augAssign.target.array
|
2022-08-21 15:21:29 +00:00
|
|
|
|
2023-08-02 19:26:40 +00:00
|
|
|
val chunks = if(ident!=null) {
|
2023-03-13 20:53:02 +00:00
|
|
|
assignVarAugmented(ident.name, augAssign)
|
2022-08-21 15:21:29 +00:00
|
|
|
} else if(memory != null) {
|
|
|
|
if(memory.address is PtNumber)
|
2023-03-13 20:53:02 +00:00
|
|
|
assignMemoryAugmented((memory.address as PtNumber).number.toInt(), augAssign)
|
2022-08-21 15:21:29 +00:00
|
|
|
else
|
2023-03-13 20:53:02 +00:00
|
|
|
fallbackAssign(augAssign)
|
2022-08-21 15:21:29 +00:00
|
|
|
} else if(array!=null) {
|
2024-01-22 23:56:06 +00:00
|
|
|
assignArrayAugmented(array, augAssign)
|
2022-08-21 15:21:29 +00:00
|
|
|
} else {
|
2023-03-13 20:53:02 +00:00
|
|
|
fallbackAssign(augAssign)
|
2022-08-21 15:21:29 +00:00
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
2024-01-22 23:56:06 +00:00
|
|
|
private fun assignMemoryAugmented(address: Int, assignment: PtAugmentedAssign): IRCodeChunks {
|
2023-02-15 21:50:35 +00:00
|
|
|
val value = assignment.value
|
2024-01-16 19:41:53 +00:00
|
|
|
val targetDt = irType(assignment.target.type)
|
|
|
|
val signed = assignment.target.type in SignedDatatypes
|
2023-02-15 21:50:35 +00:00
|
|
|
return when(assignment.operator) {
|
2024-01-16 19:41:53 +00:00
|
|
|
"+=" -> expressionEval.operatorPlusInplace(address, null, targetDt, value)
|
|
|
|
"-=" -> expressionEval.operatorMinusInplace(address, null, targetDt, value)
|
|
|
|
"*=" -> expressionEval.operatorMultiplyInplace(address, null, targetDt, value)
|
|
|
|
"/=" -> expressionEval.operatorDivideInplace(address, null, targetDt, signed, value)
|
|
|
|
"|=" -> expressionEval.operatorOrInplace(address, null, targetDt, value)
|
|
|
|
"&=" -> expressionEval.operatorAndInplace(address, null, targetDt, value)
|
|
|
|
"^=" -> expressionEval.operatorXorInplace(address, null, targetDt, value)
|
|
|
|
"<<=" -> expressionEval.operatorShiftLeftInplace(address, null, targetDt, value)
|
|
|
|
">>=" -> expressionEval.operatorShiftRightInplace(address, null, targetDt, signed, value)
|
|
|
|
"%=" -> expressionEval.operatorModuloInplace(address, null, targetDt, value)
|
2024-01-22 23:56:06 +00:00
|
|
|
"==" -> expressionEval.operatorEqualsNotEqualsInplace(address, null, targetDt, value)
|
2024-01-16 19:41:53 +00:00
|
|
|
"!=" -> expressionEval.operatorNotEqualsInplace(address, null, targetDt, value)
|
|
|
|
"<" -> expressionEval.operatorLessInplace(address, null, targetDt, signed, value)
|
|
|
|
">" -> expressionEval.operatorGreaterInplace(address, null, targetDt, signed, value)
|
|
|
|
"<=" -> expressionEval.operatorLessEqualInplace(address, null, targetDt, signed, value)
|
|
|
|
">=" -> expressionEval.operatorGreaterEqualInplace(address, null, targetDt, signed, value)
|
|
|
|
in PrefixOperators -> inplacePrefix(assignment.operator, targetDt, address, null)
|
2023-03-13 20:29:57 +00:00
|
|
|
|
2023-02-16 21:45:35 +00:00
|
|
|
else -> throw AssemblyError("invalid augmented assign operator ${assignment.operator}")
|
2022-08-21 15:21:29 +00:00
|
|
|
}
|
2022-09-14 23:32:48 +00:00
|
|
|
}
|
2022-08-21 15:21:29 +00:00
|
|
|
|
2023-02-15 21:50:35 +00:00
|
|
|
private fun assignVarAugmented(symbol: String, assignment: PtAugmentedAssign): IRCodeChunks {
|
|
|
|
val value = assignment.value
|
2024-01-16 19:41:53 +00:00
|
|
|
val signed = assignment.target.type in SignedDatatypes
|
2023-04-29 12:22:04 +00:00
|
|
|
val targetDt = irType(assignment.target.type)
|
2024-01-16 19:41:53 +00:00
|
|
|
return when(assignment.operator) {
|
2023-04-05 18:48:20 +00:00
|
|
|
"+=" -> expressionEval.operatorPlusInplace(null, symbol, targetDt, value)
|
|
|
|
"-=" -> expressionEval.operatorMinusInplace(null, symbol, targetDt, value)
|
|
|
|
"*=" -> expressionEval.operatorMultiplyInplace(null, symbol, targetDt, value)
|
2024-01-16 19:41:53 +00:00
|
|
|
"/=" -> expressionEval.operatorDivideInplace(null, symbol, targetDt, signed, value)
|
2023-04-05 18:48:20 +00:00
|
|
|
"|=" -> expressionEval.operatorOrInplace(null, symbol, targetDt, value)
|
2023-12-30 03:26:29 +00:00
|
|
|
"or=" -> expressionEval.operatorLogicalOrInplace(null, symbol, targetDt, value)
|
2023-04-05 18:48:20 +00:00
|
|
|
"&=" -> expressionEval.operatorAndInplace(null, symbol, targetDt, value)
|
2023-12-30 03:26:29 +00:00
|
|
|
"and=" -> expressionEval.operatorLogicalAndInplace(null, symbol, targetDt, value)
|
|
|
|
"^=", "xor=" -> expressionEval.operatorXorInplace(null, symbol, targetDt, value)
|
2023-04-05 18:48:20 +00:00
|
|
|
"<<=" -> expressionEval.operatorShiftLeftInplace(null, symbol, targetDt, value)
|
2024-01-16 19:41:53 +00:00
|
|
|
">>=" -> expressionEval.operatorShiftRightInplace(null, symbol, targetDt, signed, value)
|
2023-04-05 18:48:20 +00:00
|
|
|
"%=" -> expressionEval.operatorModuloInplace(null, symbol, targetDt, value)
|
2024-01-22 23:56:06 +00:00
|
|
|
"==" -> expressionEval.operatorEqualsNotEqualsInplace(null, symbol, targetDt, value)
|
2023-04-05 18:48:20 +00:00
|
|
|
"!=" -> expressionEval.operatorNotEqualsInplace(null, symbol, targetDt, value)
|
2024-01-16 19:41:53 +00:00
|
|
|
"<" -> expressionEval.operatorLessInplace(null, symbol, targetDt, signed, value)
|
|
|
|
">" -> expressionEval.operatorGreaterInplace(null, symbol, targetDt, signed, value)
|
|
|
|
"<=" -> expressionEval.operatorLessEqualInplace(null, symbol, targetDt, signed, value)
|
|
|
|
">=" -> expressionEval.operatorGreaterEqualInplace(null, symbol, targetDt, signed, value)
|
2023-04-05 18:48:20 +00:00
|
|
|
in PrefixOperators -> inplacePrefix(assignment.operator, targetDt, null, symbol)
|
2024-01-22 23:56:06 +00:00
|
|
|
|
|
|
|
else -> throw AssemblyError("invalid augmented assign operator ${assignment.operator}")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun assignArrayAugmented(array: PtArrayIndexer, assignment: PtAugmentedAssign): IRCodeChunks {
|
|
|
|
val eltSize = codeGen.program.memsizer.memorySize(array.type)
|
|
|
|
val value = assignment.value
|
|
|
|
val signed = assignment.target.type in SignedDatatypes
|
|
|
|
val result = when(assignment.operator) {
|
|
|
|
// TODO implement all of these:
|
|
|
|
// "+=" -> expressionEval.operatorPlusInplace(array, eltSize, value)
|
|
|
|
// "-=" -> expressionEval.operatorMinusInplace(array, eltSize, value)
|
|
|
|
// "*=" -> expressionEval.operatorMultiplyInplace(array, eltSize, value)
|
|
|
|
// "/=" -> expressionEval.operatorDivideInplace(array, eltSize, signed, value)
|
|
|
|
// "|=" -> expressionEval.operatorOrInplace(array, eltSize, value)
|
|
|
|
// "&=" -> expressionEval.operatorAndInplace(array, eltSize, value)
|
|
|
|
// "^=" -> expressionEval.operatorXorInplace(array, eltSize, value)
|
|
|
|
// "<<=" -> expressionEval.operatorShiftLeftInplace(array, eltSize, value)
|
|
|
|
// ">>=" -> expressionEval.operatorShiftRightInplace(array, eltSize, signed, value)
|
|
|
|
// "%=" -> expressionEval.operatorModuloInplace(array, eltSize, value)
|
|
|
|
"==" -> expressionEval.operatorEqualsNotEqualsInplace(array, eltSize, value, true)
|
|
|
|
"!=" -> expressionEval.operatorEqualsNotEqualsInplace(array, eltSize, value, false)
|
|
|
|
// "<" -> expressionEval.operatorLessInplace(array, eltSize, signed, value) // TODO reuse code from ==
|
|
|
|
// ">" -> expressionEval.operatorGreaterInplace(array, eltSize, signed, value) // TODO reuse code from ==
|
|
|
|
// "<=" -> expressionEval.operatorLessEqualInplace(array, eltSize, signed, value) // TODO reuse code from ==
|
|
|
|
// ">=" -> expressionEval.operatorGreaterEqualInplace(array, eltSize, signed, value) // TODO reuse code from ==
|
|
|
|
in PrefixOperators -> inplacePrefix(assignment.operator, array, eltSize)
|
|
|
|
|
|
|
|
// else -> Err(NotImplementedError("invalid augmented assign operator ${assignment.operator}"))
|
2023-02-16 21:45:35 +00:00
|
|
|
else -> throw AssemblyError("invalid augmented assign operator ${assignment.operator}")
|
2022-09-14 23:32:48 +00:00
|
|
|
}
|
2024-01-22 23:56:06 +00:00
|
|
|
|
|
|
|
return result.getOrElse { fallbackAssign(assignment) }
|
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-16 19:41:53 +00:00
|
|
|
value = PtPrefix(origAssign.operator, origAssign.target.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 {
|
2023-02-15 21:50:35 +00:00
|
|
|
require(origAssign.operator.endsWith('='))
|
2024-01-22 20:07:51 +00:00
|
|
|
val operator = if(origAssign.operator=="==") "==" else origAssign.operator.dropLast(1)
|
|
|
|
value = PtBinaryExpression(operator, origAssign.target.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-22 23:56:06 +00:00
|
|
|
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 vmDt = irType(array.type)
|
|
|
|
val constIndex = array.index.asConstInteger()
|
|
|
|
when(operator) {
|
|
|
|
"+" -> { }
|
|
|
|
"-" -> {
|
|
|
|
if(constIndex!=null) {
|
|
|
|
addInstr(result, IRInstruction(Opcode.NEGM, vmDt, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize), null)
|
|
|
|
} else {
|
|
|
|
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 {
|
|
|
|
it += IRInstruction(Opcode.LOADX, vmDt, reg1 = register, reg2 = tr.resultReg, labelSymbol = array.variable.name)
|
|
|
|
it += IRInstruction(Opcode.NEG, vmDt, reg1 = register)
|
|
|
|
it += IRInstruction(Opcode.STOREX, vmDt, reg1 = register, reg2 = tr.resultReg, labelSymbol = array.variable.name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"~" -> {
|
|
|
|
if(constIndex!=null) {
|
|
|
|
addInstr(result, IRInstruction(Opcode.INVM, vmDt, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize), null)
|
|
|
|
} else {
|
|
|
|
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 {
|
|
|
|
it += IRInstruction(Opcode.LOADX, vmDt, reg1 = register, reg2 = tr.resultReg, labelSymbol = array.variable.name)
|
|
|
|
it += IRInstruction(Opcode.INV, vmDt, reg1 = register)
|
|
|
|
it += IRInstruction(Opcode.STOREX, vmDt, reg1 = register, reg2 = tr.resultReg, labelSymbol = array.variable.name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"not" -> {
|
|
|
|
val register = codeGen.registers.nextFree()
|
|
|
|
if(constIndex!=null) {
|
|
|
|
// TODO: in boolean branch, is 'not' handled ok like this?
|
|
|
|
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 {
|
|
|
|
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 {
|
|
|
|
it += IRInstruction(Opcode.LOADX, vmDt, reg1 = register, reg2 = tr.resultReg, labelSymbol = array.variable.name)
|
|
|
|
it += IRInstruction(Opcode.XOR, vmDt, reg1 = register, immediate = 1)
|
|
|
|
it += IRInstruction(Opcode.STOREX, vmDt, reg1 = register, reg2 = tr.resultReg, labelSymbol = array.variable.name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else -> throw AssemblyError("weird prefix operator")
|
|
|
|
}
|
|
|
|
return Ok(result)
|
|
|
|
}
|
|
|
|
|
2023-02-15 21:50:35 +00:00
|
|
|
private fun inplacePrefix(operator: String, vmDt: IRDataType, address: Int?, symbol: String?): IRCodeChunks {
|
2022-11-02 21:12:42 +00:00
|
|
|
val code= IRCodeChunk(null, null)
|
2022-08-21 15:21:29 +00:00
|
|
|
when(operator) {
|
|
|
|
"+" -> { }
|
2024-01-22 21:47:09 +00:00
|
|
|
"-" -> code += IRInstruction(Opcode.NEGM, vmDt, address = address, labelSymbol = symbol)
|
|
|
|
"~" -> code += IRInstruction(Opcode.INVM, vmDt, address = address, labelSymbol = symbol)
|
2024-01-22 23:56:06 +00:00
|
|
|
// TODO: in boolean branch, how is 'not' handled here?
|
2022-08-21 15:21:29 +00:00
|
|
|
else -> throw AssemblyError("weird prefix operator")
|
|
|
|
}
|
2022-10-06 22:34:56 +00:00
|
|
|
return listOf(code)
|
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-07-31 17:35:57 +00:00
|
|
|
if(targetArray.usesPointerVariable) {
|
2022-08-21 15:21:29 +00:00
|
|
|
if(itemsize!=1)
|
|
|
|
throw AssemblyError("non-array var indexing requires bytes dt")
|
2023-03-13 20:53:02 +00:00
|
|
|
if(targetArray.index.type!=DataType.UBYTE)
|
2022-08-21 15:21:29 +00:00
|
|
|
throw AssemblyError("non-array var indexing requires bytes index")
|
2023-03-13 20:53:02 +00:00
|
|
|
val tr = expressionEval.translateExpression(targetArray.index)
|
|
|
|
val idxReg = tr.resultReg
|
|
|
|
addToResult(result, tr, tr.resultReg, -1)
|
2022-11-02 21:12:42 +00:00
|
|
|
val code = IRCodeChunk(null, null)
|
2022-08-21 15:21:29 +00:00
|
|
|
if(zero) {
|
|
|
|
// there's no STOREZIX instruction
|
2023-03-13 20:53:02 +00:00
|
|
|
valueRegister = codeGen.registers.nextFree()
|
2023-05-08 20:26:22 +00:00
|
|
|
code += IRInstruction(Opcode.LOAD, targetDt, reg1=valueRegister, immediate = 0)
|
2022-08-21 15:21:29 +00:00
|
|
|
}
|
2023-05-08 20:26:22 +00:00
|
|
|
code += IRInstruction(Opcode.STOREIX, targetDt, reg1=valueRegister, reg2=idxReg, labelSymbol = variable)
|
2022-10-06 22:34:56 +00:00
|
|
|
result += code
|
|
|
|
return result
|
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
|
|
|
}
|
|
|
|
}
|